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/chromeos/profiles/profile_helper.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 "chrome/grit/generated_resources.h" 15 #include "chromeos/network/client_cert_util.h" 16 #include "chromeos/network/managed_network_configuration_handler.h" 17 #include "chromeos/network/network_event_log.h" 18 #include "chromeos/network/network_state.h" 19 #include "chromeos/network/network_state_handler.h" 20 #include "extensions/browser/extension_host.h" 21 #include "extensions/common/constants.h" 22 #include "ui/base/l10n/l10n_util.h" 23 #include "ui/base/page_transition_types.h" 24 #include "ui/views/controls/label.h" 25 #include "ui/views/layout/grid_layout.h" 26 #include "ui/views/layout/layout_constants.h" 27 #include "ui/views/widget/widget.h" 28 #include "ui/views/window/dialog_delegate.h" 29 30 namespace chromeos { 31 32 namespace { 33 34 // Default width/height of the dialog. 35 const int kDefaultWidth = 350; 36 const int kDefaultHeight = 100; 37 38 //////////////////////////////////////////////////////////////////////////////// 39 // Dialog for certificate enrollment. This displays the content from the 40 // certificate enrollment URI. 41 class EnrollmentDialogView : public views::DialogDelegateView { 42 public: 43 virtual ~EnrollmentDialogView(); 44 45 static void ShowDialog(gfx::NativeWindow owning_window, 46 const std::string& network_name, 47 Profile* profile, 48 const GURL& target_uri, 49 const base::Closure& connect); 50 51 // views::DialogDelegateView overrides 52 virtual int GetDialogButtons() const OVERRIDE; 53 virtual bool Accept() OVERRIDE; 54 virtual void OnClosed() OVERRIDE; 55 virtual base::string16 GetDialogButtonLabel( 56 ui::DialogButton button) const OVERRIDE; 57 58 // views::WidgetDelegate overrides 59 virtual ui::ModalType GetModalType() const OVERRIDE; 60 virtual base::string16 GetWindowTitle() const OVERRIDE; 61 62 // views::View overrides 63 virtual gfx::Size GetPreferredSize() const OVERRIDE; 64 65 private: 66 EnrollmentDialogView(const std::string& network_name, 67 Profile* profile, 68 const GURL& target_uri, 69 const base::Closure& connect); 70 void InitDialog(); 71 72 bool accepted_; 73 std::string network_name_; 74 Profile* profile_; 75 GURL target_uri_; 76 base::Closure connect_; 77 bool added_cert_; 78 }; 79 80 //////////////////////////////////////////////////////////////////////////////// 81 // EnrollmentDialogView implementation. 82 83 EnrollmentDialogView::EnrollmentDialogView(const std::string& network_name, 84 Profile* profile, 85 const GURL& target_uri, 86 const base::Closure& connect) 87 : accepted_(false), 88 network_name_(network_name), 89 profile_(profile), 90 target_uri_(target_uri), 91 connect_(connect), 92 added_cert_(false) { 93 } 94 95 EnrollmentDialogView::~EnrollmentDialogView() { 96 } 97 98 // static 99 void EnrollmentDialogView::ShowDialog(gfx::NativeWindow owning_window, 100 const std::string& network_name, 101 Profile* profile, 102 const GURL& target_uri, 103 const base::Closure& connect) { 104 EnrollmentDialogView* dialog_view = 105 new EnrollmentDialogView(network_name, profile, target_uri, connect); 106 views::DialogDelegate::CreateDialogWidget(dialog_view, NULL, owning_window); 107 dialog_view->InitDialog(); 108 views::Widget* widget = dialog_view->GetWidget(); 109 DCHECK(widget); 110 widget->Show(); 111 } 112 113 int EnrollmentDialogView::GetDialogButtons() const { 114 return ui::DIALOG_BUTTON_CANCEL | ui::DIALOG_BUTTON_OK; 115 } 116 117 bool EnrollmentDialogView::Accept() { 118 accepted_ = true; 119 return true; 120 } 121 122 void EnrollmentDialogView::OnClosed() { 123 if (!accepted_) 124 return; 125 chrome::NavigateParams params(profile_, 126 GURL(target_uri_), 127 ui::PAGE_TRANSITION_LINK); 128 params.disposition = NEW_FOREGROUND_TAB; 129 params.window_action = chrome::NavigateParams::SHOW_WINDOW; 130 chrome::Navigate(¶ms); 131 } 132 133 base::string16 EnrollmentDialogView::GetDialogButtonLabel( 134 ui::DialogButton button) const { 135 if (button == ui::DIALOG_BUTTON_OK) 136 return l10n_util::GetStringUTF16(IDS_NETWORK_ENROLLMENT_HANDLER_BUTTON); 137 return views::DialogDelegateView::GetDialogButtonLabel(button); 138 } 139 140 ui::ModalType EnrollmentDialogView::GetModalType() const { 141 return ui::MODAL_TYPE_SYSTEM; 142 } 143 144 base::string16 EnrollmentDialogView::GetWindowTitle() const { 145 return l10n_util::GetStringUTF16(IDS_NETWORK_ENROLLMENT_HANDLER_TITLE); 146 } 147 148 gfx::Size EnrollmentDialogView::GetPreferredSize() const { 149 return gfx::Size(kDefaultWidth, kDefaultHeight); 150 } 151 152 void EnrollmentDialogView::InitDialog() { 153 added_cert_ = false; 154 // Create the views and layout manager and set them up. 155 views::Label* label = new views::Label( 156 l10n_util::GetStringFUTF16(IDS_NETWORK_ENROLLMENT_HANDLER_INSTRUCTIONS, 157 base::UTF8ToUTF16(network_name_))); 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 // Keep the closure for later activation if we notice that 223 // a certificate has been added. 224 225 // TODO(gspencer): Do something smart with the closure. At the moment it is 226 // being ignored because we don't know when the enrollment tab is closed. 227 // http://crosbug.com/30422 228 for (std::vector<std::string>::const_iterator iter = uri_list.begin(); 229 iter != uri_list.end(); ++iter) { 230 GURL uri(*iter); 231 if (uri.IsStandard() || uri.scheme() == extensions::kExtensionScheme) { 232 // If this is a "standard" scheme, like http, ftp, etc., then open that in 233 // the enrollment dialog. 234 NET_LOG_EVENT("Showing enrollment dialog", network_name_); 235 EnrollmentDialogView::ShowDialog(owning_window_, 236 network_name_, 237 profile_, 238 uri, post_action); 239 return true; 240 } 241 NET_LOG_DEBUG("Nonstandard URI: " + uri.spec(), network_name_); 242 } 243 244 // No appropriate scheme was found. 245 NET_LOG_ERROR("No usable enrollment URI", network_name_); 246 return false; 247 } 248 249 void EnrollmentComplete(const std::string& service_path) { 250 NET_LOG_USER("Enrollment Complete", service_path); 251 } 252 253 } // namespace 254 255 //////////////////////////////////////////////////////////////////////////////// 256 // Factory function. 257 258 namespace enrollment { 259 260 bool CreateDialog(const std::string& service_path, 261 gfx::NativeWindow owning_window) { 262 const NetworkState* network = NetworkHandler::Get()->network_state_handler()-> 263 GetNetworkState(service_path); 264 if (!network) { 265 NET_LOG_ERROR("Enrolling Unknown network", service_path); 266 return false; 267 } 268 Browser* browser = chrome::FindBrowserWithWindow(owning_window); 269 Profile* profile = 270 browser ? browser->profile() : ProfileManager::GetPrimaryUserProfile(); 271 std::string username_hash = ProfileHelper::GetUserIdHashFromProfile(profile); 272 273 onc::ONCSource onc_source = onc::ONC_SOURCE_NONE; 274 const base::DictionaryValue* policy = 275 NetworkHandler::Get() 276 ->managed_network_configuration_handler() 277 ->FindPolicyByGUID(username_hash, network->guid(), &onc_source); 278 279 // We skip certificate patterns for device policy ONC so that an unmanaged 280 // user can't get to the place where a cert is presented for them 281 // involuntarily. 282 if (!policy || onc_source == onc::ONC_SOURCE_DEVICE_POLICY) 283 return false; 284 285 client_cert::ClientCertConfig cert_config; 286 OncToClientCertConfig(*policy, &cert_config); 287 288 if (cert_config.client_cert_type != onc::client_cert::kPattern) 289 return false; 290 291 if (cert_config.pattern.Empty()) 292 NET_LOG_ERROR("Certificate pattern is empty", service_path); 293 294 if (cert_config.pattern.enrollment_uri_list().empty()) { 295 NET_LOG_EVENT("No enrollment URIs", service_path); 296 return false; 297 } 298 299 NET_LOG_USER("Enrolling", service_path); 300 301 DialogEnrollmentDelegate* enrollment = 302 new DialogEnrollmentDelegate(owning_window, network->name(), profile); 303 return enrollment->Enroll(cert_config.pattern.enrollment_uri_list(), 304 base::Bind(&EnrollmentComplete, service_path)); 305 } 306 307 } // namespace enrollment 308 309 } // namespace chromeos 310