1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/chromeos/enrollment_dialog_view.h" 6 7 #include "base/bind.h" 8 #include "base/strings/utf_string_conversions.h" 9 #include "chrome/browser/extensions/extension_host.h" 10 #include "chrome/browser/profiles/profile.h" 11 #include "chrome/browser/profiles/profile_manager.h" 12 #include "chrome/browser/ui/browser_finder.h" 13 #include "chrome/browser/ui/browser_navigator.h" 14 #include "chromeos/network/network_event_log.h" 15 #include "chromeos/network/network_state.h" 16 #include "chromeos/network/network_state_handler.h" 17 #include "content/public/common/page_transition_types.h" 18 #include "extensions/common/constants.h" 19 #include "grit/generated_resources.h" 20 #include "ui/base/l10n/l10n_util.h" 21 #include "ui/base/resource/resource_bundle.h" 22 #include "ui/views/controls/label.h" 23 #include "ui/views/layout/grid_layout.h" 24 #include "ui/views/layout/layout_constants.h" 25 #include "ui/views/widget/widget.h" 26 #include "ui/views/window/dialog_delegate.h" 27 28 namespace chromeos { 29 30 namespace { 31 32 // Default width/height of the dialog. 33 const int kDefaultWidth = 350; 34 const int kDefaultHeight = 100; 35 36 //////////////////////////////////////////////////////////////////////////////// 37 // Dialog for certificate enrollment. This displays the content from the 38 // certificate enrollment URI. 39 class EnrollmentDialogView : public views::DialogDelegateView { 40 public: 41 virtual ~EnrollmentDialogView(); 42 43 static void ShowDialog(gfx::NativeWindow owning_window, 44 const std::string& network_name, 45 Profile* profile, 46 const GURL& target_uri, 47 const base::Closure& connect); 48 49 // views::DialogDelegateView overrides 50 virtual int GetDialogButtons() const OVERRIDE; 51 virtual bool Accept() OVERRIDE; 52 virtual void OnClosed() OVERRIDE; 53 virtual base::string16 GetDialogButtonLabel( 54 ui::DialogButton button) const OVERRIDE; 55 56 // views::WidgetDelegate overrides 57 virtual ui::ModalType GetModalType() const OVERRIDE; 58 virtual base::string16 GetWindowTitle() const OVERRIDE; 59 60 // views::View overrides 61 virtual gfx::Size GetPreferredSize() OVERRIDE; 62 63 private: 64 EnrollmentDialogView(const std::string& network_name, 65 Profile* profile, 66 const GURL& target_uri, 67 const base::Closure& connect); 68 void InitDialog(); 69 70 bool accepted_; 71 std::string network_name_; 72 Profile* profile_; 73 GURL target_uri_; 74 base::Closure connect_; 75 bool added_cert_; 76 }; 77 78 //////////////////////////////////////////////////////////////////////////////// 79 // EnrollmentDialogView implementation. 80 81 EnrollmentDialogView::EnrollmentDialogView(const std::string& network_name, 82 Profile* profile, 83 const GURL& target_uri, 84 const base::Closure& connect) 85 : accepted_(false), 86 network_name_(network_name), 87 profile_(profile), 88 target_uri_(target_uri), 89 connect_(connect), 90 added_cert_(false) { 91 } 92 93 EnrollmentDialogView::~EnrollmentDialogView() { 94 } 95 96 // static 97 void EnrollmentDialogView::ShowDialog(gfx::NativeWindow owning_window, 98 const std::string& network_name, 99 Profile* profile, 100 const GURL& target_uri, 101 const base::Closure& connect) { 102 EnrollmentDialogView* dialog_view = 103 new EnrollmentDialogView(network_name, profile, target_uri, connect); 104 views::DialogDelegate::CreateDialogWidget(dialog_view, NULL, owning_window); 105 dialog_view->InitDialog(); 106 views::Widget* widget = dialog_view->GetWidget(); 107 DCHECK(widget); 108 widget->Show(); 109 } 110 111 int EnrollmentDialogView::GetDialogButtons() const { 112 return ui::DIALOG_BUTTON_CANCEL | ui::DIALOG_BUTTON_OK; 113 } 114 115 bool EnrollmentDialogView::Accept() { 116 accepted_ = true; 117 return true; 118 } 119 120 void EnrollmentDialogView::OnClosed() { 121 if (!accepted_) 122 return; 123 chrome::NavigateParams params(profile_, 124 GURL(target_uri_), 125 content::PAGE_TRANSITION_LINK); 126 params.disposition = NEW_FOREGROUND_TAB; 127 params.window_action = chrome::NavigateParams::SHOW_WINDOW; 128 chrome::Navigate(¶ms); 129 } 130 131 base::string16 EnrollmentDialogView::GetDialogButtonLabel( 132 ui::DialogButton button) const { 133 if (button == ui::DIALOG_BUTTON_OK) 134 return l10n_util::GetStringUTF16(IDS_NETWORK_ENROLLMENT_HANDLER_BUTTON); 135 return views::DialogDelegateView::GetDialogButtonLabel(button); 136 } 137 138 ui::ModalType EnrollmentDialogView::GetModalType() const { 139 return ui::MODAL_TYPE_SYSTEM; 140 } 141 142 base::string16 EnrollmentDialogView::GetWindowTitle() const { 143 return l10n_util::GetStringUTF16(IDS_NETWORK_ENROLLMENT_HANDLER_TITLE); 144 } 145 146 gfx::Size EnrollmentDialogView::GetPreferredSize() { 147 return gfx::Size(kDefaultWidth, kDefaultHeight); 148 } 149 150 void EnrollmentDialogView::InitDialog() { 151 added_cert_ = false; 152 // Create the views and layout manager and set them up. 153 views::Label* label = new views::Label( 154 l10n_util::GetStringFUTF16(IDS_NETWORK_ENROLLMENT_HANDLER_INSTRUCTIONS, 155 UTF8ToUTF16(network_name_))); 156 label->SetFont(ui::ResourceBundle::GetSharedInstance().GetFont( 157 ui::ResourceBundle::BaseFont)); 158 label->SetHorizontalAlignment(gfx::ALIGN_LEFT); 159 label->SetMultiLine(true); 160 label->SetAllowCharacterBreak(true); 161 162 views::GridLayout* grid_layout = views::GridLayout::CreatePanel(this); 163 SetLayoutManager(grid_layout); 164 165 views::ColumnSet* columns = grid_layout->AddColumnSet(0); 166 columns->AddColumn(views::GridLayout::FILL, // Horizontal resize. 167 views::GridLayout::FILL, // Vertical resize. 168 1, // Resize weight. 169 views::GridLayout::USE_PREF, // Size type. 170 0, // Ignored for USE_PREF. 171 0); // Minimum size. 172 columns = grid_layout->AddColumnSet(1); 173 columns->AddPaddingColumn( 174 0, views::kUnrelatedControlHorizontalSpacing); 175 columns->AddColumn(views::GridLayout::LEADING, // Horizontal leading. 176 views::GridLayout::FILL, // Vertical resize. 177 1, // Resize weight. 178 views::GridLayout::USE_PREF, // Size type. 179 0, // Ignored for USE_PREF. 180 0); // Minimum size. 181 182 grid_layout->StartRow(0, 0); 183 grid_layout->AddView(label); 184 grid_layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); 185 grid_layout->Layout(this); 186 } 187 188 //////////////////////////////////////////////////////////////////////////////// 189 // Handler for certificate enrollment. 190 191 class DialogEnrollmentDelegate { 192 public: 193 // |owning_window| is the window that will own the dialog. 194 DialogEnrollmentDelegate(gfx::NativeWindow owning_window, 195 const std::string& network_name, 196 Profile* profile); 197 ~DialogEnrollmentDelegate(); 198 199 // EnrollmentDelegate overrides 200 bool Enroll(const std::vector<std::string>& uri_list, 201 const base::Closure& connect); 202 203 private: 204 gfx::NativeWindow owning_window_; 205 std::string network_name_; 206 Profile* profile_; 207 208 DISALLOW_COPY_AND_ASSIGN(DialogEnrollmentDelegate); 209 }; 210 211 DialogEnrollmentDelegate::DialogEnrollmentDelegate( 212 gfx::NativeWindow owning_window, 213 const std::string& network_name, 214 Profile* profile) : owning_window_(owning_window), 215 network_name_(network_name), 216 profile_(profile) {} 217 218 DialogEnrollmentDelegate::~DialogEnrollmentDelegate() {} 219 220 bool DialogEnrollmentDelegate::Enroll(const std::vector<std::string>& uri_list, 221 const base::Closure& post_action) { 222 if (uri_list.empty()) { 223 NET_LOG_EVENT("No enrollment URIs", network_name_); 224 return false; 225 } 226 227 // Keep the closure for later activation if we notice that 228 // a certificate has been added. 229 230 // TODO(gspencer): Do something smart with the closure. At the moment it is 231 // being ignored because we don't know when the enrollment tab is closed. 232 // http://crosbug.com/30422 233 for (std::vector<std::string>::const_iterator iter = uri_list.begin(); 234 iter != uri_list.end(); ++iter) { 235 GURL uri(*iter); 236 if (uri.IsStandard() || uri.scheme() == extensions::kExtensionScheme) { 237 // If this is a "standard" scheme, like http, ftp, etc., then open that in 238 // the enrollment dialog. 239 NET_LOG_EVENT("Showing enrollment dialog", network_name_); 240 EnrollmentDialogView::ShowDialog(owning_window_, 241 network_name_, 242 profile_, 243 uri, post_action); 244 return true; 245 } 246 NET_LOG_DEBUG("Nonstandard URI: " + uri.spec(), network_name_); 247 } 248 249 // No appropriate scheme was found. 250 NET_LOG_ERROR("No usable enrollment URI", network_name_); 251 return false; 252 } 253 254 void EnrollmentComplete(const std::string& service_path) { 255 NET_LOG_USER("Enrollment Complete", service_path); 256 } 257 258 } // namespace 259 260 //////////////////////////////////////////////////////////////////////////////// 261 // Factory function. 262 263 namespace enrollment { 264 265 bool CreateDialog(const std::string& service_path, 266 gfx::NativeWindow owning_window) { 267 const NetworkState* network = NetworkHandler::Get()->network_state_handler()-> 268 GetNetworkState(service_path); 269 if (!network) { 270 NET_LOG_ERROR("Enrolling Unknown network", service_path); 271 return false; 272 } 273 // We skip certificate patterns for device policy ONC so that an unmanaged 274 // user can't get to the place where a cert is presented for them 275 // involuntarily. 276 if (network->ui_data().onc_source() == onc::ONC_SOURCE_DEVICE_POLICY) 277 return false; 278 279 const CertificatePattern& certificate_pattern = 280 network->ui_data().certificate_pattern(); 281 if (certificate_pattern.Empty()) { 282 NET_LOG_EVENT("No certificate pattern found", service_path); 283 return false; 284 } 285 286 NET_LOG_USER("Enrolling", service_path); 287 288 Browser* browser = chrome::FindBrowserWithWindow(owning_window); 289 Profile* profile = browser ? browser->profile() : 290 ProfileManager::GetPrimaryUserProfileOrOffTheRecord(); 291 DialogEnrollmentDelegate* enrollment = 292 new DialogEnrollmentDelegate(owning_window, network->name(), profile); 293 return enrollment->Enroll(certificate_pattern.enrollment_uri_list(), 294 base::Bind(&EnrollmentComplete, service_path)); 295 } 296 297 } // namespace enrollment 298 299 } // namespace chromeos 300