Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / chromeos / options / vpn_config_view.cc
blobde4648c262706d3c8ee0203dff44b0ae6cead725
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.
5 #include "chrome/browser/chromeos/options/vpn_config_view.h"
7 #include "base/bind.h"
8 #include "base/strings/string_util.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/strings/utf_string_conversions.h"
11 #include "chrome/browser/chromeos/enrollment_dialog_view.h"
12 #include "chrome/browser/chromeos/net/onc_utils.h"
13 #include "chrome/browser/profiles/profile_manager.h"
14 #include "chrome/common/net/x509_certificate_model.h"
15 #include "chrome/grit/generated_resources.h"
16 #include "chromeos/login/login_state.h"
17 #include "chromeos/network/network_configuration_handler.h"
18 #include "chromeos/network/network_event_log.h"
19 #include "chromeos/network/network_state.h"
20 #include "chromeos/network/network_state_handler.h"
21 #include "chromeos/network/network_ui_data.h"
22 #include "components/onc/onc_constants.h"
23 #include "third_party/cros_system_api/dbus/service_constants.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/base/models/combobox_model.h"
26 #include "ui/chromeos/network/network_connect.h"
27 #include "ui/events/event.h"
28 #include "ui/views/controls/button/checkbox.h"
29 #include "ui/views/controls/combobox/combobox.h"
30 #include "ui/views/controls/label.h"
31 #include "ui/views/controls/textfield/textfield.h"
32 #include "ui/views/layout/grid_layout.h"
33 #include "ui/views/layout/layout_constants.h"
34 #include "ui/views/widget/widget.h"
35 #include "ui/views/window/dialog_client_view.h"
37 namespace {
39 enum ProviderTypeIndex {
40 PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK = 0,
41 PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT = 1,
42 PROVIDER_TYPE_INDEX_OPEN_VPN = 2,
43 PROVIDER_TYPE_INDEX_MAX = 3,
46 base::string16 ProviderTypeIndexToString(int index) {
47 switch (index) {
48 case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK:
49 return l10n_util::GetStringUTF16(
50 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_PSK);
51 case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT:
52 return l10n_util::GetStringUTF16(
53 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_L2TP_IPSEC_USER_CERT);
54 case PROVIDER_TYPE_INDEX_OPEN_VPN:
55 return l10n_util::GetStringUTF16(
56 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_OPEN_VPN);
58 NOTREACHED();
59 return base::string16();
62 int ProviderTypeToIndex(const std::string& provider_type,
63 const std::string& client_cert_id) {
64 if (provider_type == shill::kProviderL2tpIpsec) {
65 if (!client_cert_id.empty())
66 return PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT;
67 else
68 return PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK;
69 } else {
70 DCHECK(provider_type == shill::kProviderOpenVpn);
71 return PROVIDER_TYPE_INDEX_OPEN_VPN;
75 // Translates the provider type to the name of the respective ONC dictionary
76 // containing configuration data for the type.
77 std::string ProviderTypeIndexToONCDictKey(int provider_type_index) {
78 switch (provider_type_index) {
79 case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK:
80 case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT:
81 return onc::vpn::kIPsec;
82 case PROVIDER_TYPE_INDEX_OPEN_VPN:
83 return onc::vpn::kOpenVPN;
85 NOTREACHED() << "Unhandled provider type index " << provider_type_index;
86 return std::string();
89 std::string GetPemFromDictionary(
90 const base::DictionaryValue* provider_properties,
91 const std::string& key) {
92 const base::ListValue* pems = NULL;
93 if (!provider_properties->GetListWithoutPathExpansion(key, &pems))
94 return std::string();
95 std::string pem;
96 pems->GetString(0, &pem);
97 return pem;
100 } // namespace
102 namespace chromeos {
104 namespace internal {
106 class ProviderTypeComboboxModel : public ui::ComboboxModel {
107 public:
108 ProviderTypeComboboxModel();
109 ~ProviderTypeComboboxModel() override;
111 // Overridden from ui::ComboboxModel:
112 int GetItemCount() const override;
113 base::string16 GetItemAt(int index) override;
115 private:
116 DISALLOW_COPY_AND_ASSIGN(ProviderTypeComboboxModel);
119 class VpnServerCACertComboboxModel : public ui::ComboboxModel {
120 public:
121 VpnServerCACertComboboxModel();
122 ~VpnServerCACertComboboxModel() override;
124 // Overridden from ui::ComboboxModel:
125 int GetItemCount() const override;
126 base::string16 GetItemAt(int index) override;
128 private:
129 DISALLOW_COPY_AND_ASSIGN(VpnServerCACertComboboxModel);
132 class VpnUserCertComboboxModel : public ui::ComboboxModel {
133 public:
134 VpnUserCertComboboxModel();
135 ~VpnUserCertComboboxModel() override;
137 // Overridden from ui::ComboboxModel:
138 int GetItemCount() const override;
139 base::string16 GetItemAt(int index) override;
141 private:
142 DISALLOW_COPY_AND_ASSIGN(VpnUserCertComboboxModel);
145 // ProviderTypeComboboxModel ---------------------------------------------------
147 ProviderTypeComboboxModel::ProviderTypeComboboxModel() {
150 ProviderTypeComboboxModel::~ProviderTypeComboboxModel() {
153 int ProviderTypeComboboxModel::GetItemCount() const {
154 return PROVIDER_TYPE_INDEX_MAX;
157 base::string16 ProviderTypeComboboxModel::GetItemAt(int index) {
158 return ProviderTypeIndexToString(index);
161 // VpnServerCACertComboboxModel ------------------------------------------------
163 VpnServerCACertComboboxModel::VpnServerCACertComboboxModel() {
166 VpnServerCACertComboboxModel::~VpnServerCACertComboboxModel() {
169 int VpnServerCACertComboboxModel::GetItemCount() const {
170 if (CertLibrary::Get()->CertificatesLoading())
171 return 1; // "Loading"
172 // "Default" + certs.
173 return CertLibrary::Get()->NumCertificates(
174 CertLibrary::CERT_TYPE_SERVER_CA) + 1;
177 base::string16 VpnServerCACertComboboxModel::GetItemAt(int index) {
178 if (CertLibrary::Get()->CertificatesLoading())
179 return l10n_util::GetStringUTF16(
180 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_LOADING);
181 if (index == 0)
182 return l10n_util::GetStringUTF16(
183 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA_DEFAULT);
184 int cert_index = index - 1;
185 return CertLibrary::Get()->GetCertDisplayStringAt(
186 CertLibrary::CERT_TYPE_SERVER_CA, cert_index);
189 // VpnUserCertComboboxModel ----------------------------------------------------
191 VpnUserCertComboboxModel::VpnUserCertComboboxModel() {
194 VpnUserCertComboboxModel::~VpnUserCertComboboxModel() {
197 int VpnUserCertComboboxModel::GetItemCount() const {
198 if (CertLibrary::Get()->CertificatesLoading())
199 return 1; // "Loading"
200 int num_certs =
201 CertLibrary::Get()->NumCertificates(CertLibrary::CERT_TYPE_USER);
202 if (num_certs == 0)
203 return 1; // "None installed"
204 return num_certs;
207 base::string16 VpnUserCertComboboxModel::GetItemAt(int index) {
208 if (CertLibrary::Get()->CertificatesLoading()) {
209 return l10n_util::GetStringUTF16(
210 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_LOADING);
212 if (CertLibrary::Get()->NumCertificates(CertLibrary::CERT_TYPE_USER) == 0) {
213 return l10n_util::GetStringUTF16(
214 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_USER_CERT_NONE_INSTALLED);
216 return CertLibrary::Get()->GetCertDisplayStringAt(
217 CertLibrary::CERT_TYPE_USER, index);
220 } // namespace internal
222 VPNConfigView::VPNConfigView(NetworkConfigView* parent,
223 const std::string& service_path)
224 : ChildNetworkConfigView(parent, service_path),
225 service_text_modified_(false),
226 enable_psk_passphrase_(false),
227 enable_user_cert_(false),
228 enable_server_ca_cert_(false),
229 enable_otp_(false),
230 enable_group_name_(false),
231 user_passphrase_required_(false),
232 title_(0),
233 layout_(NULL),
234 server_textfield_(NULL),
235 service_text_(NULL),
236 service_textfield_(NULL),
237 provider_type_combobox_(NULL),
238 provider_type_text_label_(NULL),
239 psk_passphrase_label_(NULL),
240 psk_passphrase_textfield_(NULL),
241 user_cert_label_(NULL),
242 user_cert_combobox_(NULL),
243 server_ca_cert_label_(NULL),
244 server_ca_cert_combobox_(NULL),
245 username_textfield_(NULL),
246 user_passphrase_textfield_(NULL),
247 otp_label_(NULL),
248 otp_textfield_(NULL),
249 group_name_label_(NULL),
250 group_name_textfield_(NULL),
251 save_credentials_checkbox_(NULL),
252 error_label_(NULL),
253 provider_type_index_(PROVIDER_TYPE_INDEX_MAX),
254 weak_ptr_factory_(this) {
255 Init();
258 VPNConfigView::~VPNConfigView() {
259 RemoveAllChildViews(true); // Destroy children before models
260 CertLibrary::Get()->RemoveObserver(this);
263 base::string16 VPNConfigView::GetTitle() const {
264 DCHECK_NE(title_, 0);
265 return l10n_util::GetStringUTF16(title_);
268 views::View* VPNConfigView::GetInitiallyFocusedView() {
269 if (service_path_.empty()) {
270 // Put focus in the first editable field.
271 if (server_textfield_)
272 return server_textfield_;
273 else if (service_textfield_)
274 return service_textfield_;
275 else if (provider_type_combobox_)
276 return provider_type_combobox_;
277 else if (psk_passphrase_textfield_ && psk_passphrase_textfield_->enabled())
278 return psk_passphrase_textfield_;
279 else if (user_cert_combobox_ && user_cert_combobox_->enabled())
280 return user_cert_combobox_;
281 else if (server_ca_cert_combobox_ && server_ca_cert_combobox_->enabled())
282 return server_ca_cert_combobox_;
284 if (user_passphrase_textfield_ && user_passphrase_required_)
285 return user_passphrase_textfield_;
286 else if (otp_textfield_)
287 return otp_textfield_;
288 return NULL;
291 bool VPNConfigView::CanLogin() {
292 // Username is always required.
293 if (GetUsername().empty())
294 return false;
296 // TODO(stevenjb): min kMinPassphraseLen length?
297 if (service_path_.empty() &&
298 (GetService().empty() || GetServer().empty()))
299 return false;
301 // Block login if certs are required but user has none.
302 bool cert_required =
303 GetProviderTypeIndex() == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT;
304 if (cert_required && (!HaveUserCerts() || !IsUserCertValid()))
305 return false;
307 return true;
310 void VPNConfigView::ContentsChanged(views::Textfield* sender,
311 const base::string16& new_contents) {
312 if (sender == server_textfield_ && !service_text_modified_) {
313 // Set the service name to the server name up to '.', unless it has
314 // been explicitly set by the user.
315 base::string16 server = server_textfield_->text();
316 base::string16::size_type n = server.find_first_of(L'.');
317 service_name_from_server_ = server.substr(0, n);
318 service_textfield_->SetText(service_name_from_server_);
320 if (sender == service_textfield_) {
321 if (new_contents.empty())
322 service_text_modified_ = false;
323 else if (new_contents != service_name_from_server_)
324 service_text_modified_ = true;
326 UpdateCanLogin();
329 bool VPNConfigView::HandleKeyEvent(views::Textfield* sender,
330 const ui::KeyEvent& key_event) {
331 if ((sender == psk_passphrase_textfield_ ||
332 sender == user_passphrase_textfield_) &&
333 key_event.key_code() == ui::VKEY_RETURN) {
334 parent_->GetDialogClientView()->AcceptWindow();
336 return false;
339 void VPNConfigView::ButtonPressed(views::Button* sender,
340 const ui::Event& event) {
343 void VPNConfigView::OnPerformAction(views::Combobox* combobox) {
344 UpdateControls();
345 UpdateErrorLabel();
346 UpdateCanLogin();
349 void VPNConfigView::OnCertificatesLoaded(bool initial_load) {
350 Refresh();
353 bool VPNConfigView::Login() {
354 if (service_path_.empty()) {
355 base::DictionaryValue properties;
356 // Identifying properties
357 properties.SetStringWithoutPathExpansion(
358 shill::kTypeProperty, shill::kTypeVPN);
359 properties.SetStringWithoutPathExpansion(
360 shill::kNameProperty, GetService());
361 properties.SetStringWithoutPathExpansion(
362 shill::kProviderHostProperty, GetServer());
363 properties.SetStringWithoutPathExpansion(
364 shill::kProviderTypeProperty, GetProviderTypeString());
366 SetConfigProperties(&properties);
367 bool shared = false;
368 bool modifiable = false;
369 ChildNetworkConfigView::GetShareStateForLoginState(&shared, &modifiable);
371 bool only_policy_autoconnect =
372 onc::PolicyAllowsOnlyPolicyNetworksToAutoconnect(!shared);
373 if (only_policy_autoconnect) {
374 properties.SetBooleanWithoutPathExpansion(shill::kAutoConnectProperty,
375 false);
378 ui::NetworkConnect::Get()->CreateConfigurationAndConnect(&properties,
379 shared);
380 } else {
381 const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
382 GetNetworkState(service_path_);
383 if (!vpn) {
384 // Shill no longer knows about this network (edge case).
385 // TODO(stevenjb): Add notification for this.
386 NET_LOG_ERROR("Network not found", service_path_);
387 return true; // Close dialog
389 base::DictionaryValue properties;
390 SetConfigProperties(&properties);
391 ui::NetworkConnect::Get()->ConfigureNetworkAndConnect(
392 service_path_, properties, false /* not shared */);
394 return true; // Close dialog.
397 void VPNConfigView::Cancel() {
400 void VPNConfigView::InitFocus() {
401 views::View* view_to_focus = GetInitiallyFocusedView();
402 if (view_to_focus)
403 view_to_focus->RequestFocus();
406 const std::string VPNConfigView::GetService() const {
407 if (service_textfield_ != NULL)
408 return GetTextFromField(service_textfield_, true);
409 return service_path_;
412 const std::string VPNConfigView::GetServer() const {
413 if (server_textfield_ != NULL)
414 return GetTextFromField(server_textfield_, true);
415 return std::string();
418 const std::string VPNConfigView::GetPSKPassphrase() const {
419 if (psk_passphrase_textfield_ &&
420 enable_psk_passphrase_ &&
421 psk_passphrase_textfield_->visible())
422 return GetPassphraseFromField(psk_passphrase_textfield_);
423 return std::string();
426 const std::string VPNConfigView::GetUsername() const {
427 return GetTextFromField(username_textfield_, true);
430 const std::string VPNConfigView::GetUserPassphrase() const {
431 return GetPassphraseFromField(user_passphrase_textfield_);
434 const std::string VPNConfigView::GetGroupName() const {
435 return GetTextFromField(group_name_textfield_, false);
438 const std::string VPNConfigView::GetOTP() const {
439 return GetTextFromField(otp_textfield_, true);
442 const std::string VPNConfigView::GetServerCACertPEM() const {
443 int index = server_ca_cert_combobox_ ?
444 server_ca_cert_combobox_->selected_index() : 0;
445 if (index == 0) {
446 // First item is "Default".
447 return std::string();
448 } else {
449 int cert_index = index - 1;
450 return CertLibrary::Get()->GetServerCACertPEMAt(cert_index);
454 void VPNConfigView::SetUserCertProperties(
455 chromeos::client_cert::ConfigType client_cert_type,
456 base::DictionaryValue* properties) const {
457 if (!HaveUserCerts()) {
458 // No certificate selected or not required.
459 chromeos::client_cert::SetEmptyShillProperties(client_cert_type,
460 properties);
461 } else {
462 // Certificates are listed in the order they appear in the model.
463 int index = user_cert_combobox_ ? user_cert_combobox_->selected_index() : 0;
464 int slot_id = -1;
465 const std::string pkcs11_id =
466 CertLibrary::Get()->GetUserCertPkcs11IdAt(index, &slot_id);
467 chromeos::client_cert::SetShillProperties(
468 client_cert_type, slot_id, pkcs11_id, properties);
472 bool VPNConfigView::GetSaveCredentials() const {
473 return save_credentials_checkbox_->checked();
476 int VPNConfigView::GetProviderTypeIndex() const {
477 if (provider_type_combobox_)
478 return provider_type_combobox_->selected_index();
479 return provider_type_index_;
482 std::string VPNConfigView::GetProviderTypeString() const {
483 int index = GetProviderTypeIndex();
484 switch (index) {
485 case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK:
486 case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT:
487 return shill::kProviderL2tpIpsec;
488 case PROVIDER_TYPE_INDEX_OPEN_VPN:
489 return shill::kProviderOpenVpn;
491 NOTREACHED();
492 return std::string();
495 void VPNConfigView::Init() {
496 const NetworkState* vpn = NULL;
497 if (!service_path_.empty()) {
498 vpn = NetworkHandler::Get()->network_state_handler()->
499 GetNetworkState(service_path_);
500 DCHECK(vpn && vpn->type() == shill::kTypeVPN);
502 layout_ = views::GridLayout::CreatePanel(this);
503 SetLayoutManager(layout_);
505 // Observer any changes to the certificate list.
506 CertLibrary::Get()->AddObserver(this);
508 views::ColumnSet* column_set = layout_->AddColumnSet(0);
509 // Label.
510 column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
511 views::GridLayout::USE_PREF, 0, 0);
512 column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing);
513 // Textfield, combobox.
514 column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
515 views::GridLayout::USE_PREF, 0,
516 ChildNetworkConfigView::kInputFieldMinWidth);
517 column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing);
518 // Policy indicator.
519 column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0,
520 views::GridLayout::USE_PREF, 0, 0);
522 // Initialize members.
523 service_text_modified_ = false;
524 title_ = vpn ? IDS_OPTIONS_SETTINGS_JOIN_VPN : IDS_OPTIONS_SETTINGS_ADD_VPN;
526 // By default enable all controls.
527 enable_psk_passphrase_ = true;
528 enable_user_cert_ = true;
529 enable_server_ca_cert_ = true;
530 enable_otp_ = true;
531 enable_group_name_ = true;
533 // Server label and input.
534 layout_->StartRow(0, 0);
535 views::View* server_label =
536 new views::Label(l10n_util::GetStringUTF16(
537 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVER_HOSTNAME));
538 layout_->AddView(server_label);
539 server_textfield_ = new views::Textfield();
540 server_textfield_->set_controller(this);
541 layout_->AddView(server_textfield_);
542 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
543 if (!service_path_.empty()) {
544 server_label->SetEnabled(false);
545 server_textfield_->SetEnabled(false);
548 // Service label and name or input.
549 layout_->StartRow(0, 0);
550 layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
551 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVICE_NAME)));
552 if (service_path_.empty()) {
553 service_textfield_ = new views::Textfield();
554 service_textfield_->set_controller(this);
555 layout_->AddView(service_textfield_);
556 service_text_ = NULL;
557 } else {
558 service_text_ = new views::Label();
559 service_text_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
560 layout_->AddView(service_text_);
561 service_textfield_ = NULL;
563 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
565 // Provider type label and select.
566 layout_->StartRow(0, 0);
567 layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
568 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PROVIDER_TYPE)));
569 if (service_path_.empty()) {
570 provider_type_combobox_model_.reset(
571 new internal::ProviderTypeComboboxModel);
572 provider_type_combobox_ = new views::Combobox(
573 provider_type_combobox_model_.get());
574 provider_type_combobox_->set_listener(this);
575 layout_->AddView(provider_type_combobox_);
576 provider_type_text_label_ = NULL;
577 } else {
578 provider_type_text_label_ = new views::Label();
579 provider_type_text_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
580 layout_->AddView(provider_type_text_label_);
581 provider_type_combobox_ = NULL;
583 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
585 // PSK passphrase label, input and visible button.
586 layout_->StartRow(0, 0);
587 psk_passphrase_label_ = new views::Label(l10n_util::GetStringUTF16(
588 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PSK_PASSPHRASE));
589 layout_->AddView(psk_passphrase_label_);
590 psk_passphrase_textfield_ = new PassphraseTextfield();
591 psk_passphrase_textfield_->set_controller(this);
592 layout_->AddView(psk_passphrase_textfield_);
593 layout_->AddView(
594 new ControlledSettingIndicatorView(psk_passphrase_ui_data_));
595 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
597 // Server CA certificate
598 if (service_path_.empty()) {
599 layout_->StartRow(0, 0);
600 server_ca_cert_label_ = new views::Label(l10n_util::GetStringUTF16(
601 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA));
602 layout_->AddView(server_ca_cert_label_);
603 server_ca_cert_combobox_model_.reset(
604 new internal::VpnServerCACertComboboxModel());
605 server_ca_cert_combobox_ = new views::Combobox(
606 server_ca_cert_combobox_model_.get());
607 layout_->AddView(server_ca_cert_combobox_);
608 layout_->AddView(new ControlledSettingIndicatorView(ca_cert_ui_data_));
609 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
610 } else {
611 server_ca_cert_label_ = NULL;
612 server_ca_cert_combobox_ = NULL;
615 // User certificate label and input.
616 layout_->StartRow(0, 0);
617 user_cert_label_ = new views::Label(l10n_util::GetStringUTF16(
618 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_CERT));
619 layout_->AddView(user_cert_label_);
620 user_cert_combobox_model_.reset(
621 new internal::VpnUserCertComboboxModel());
622 user_cert_combobox_ = new views::Combobox(user_cert_combobox_model_.get());
623 user_cert_combobox_->set_listener(this);
624 layout_->AddView(user_cert_combobox_);
625 layout_->AddView(new ControlledSettingIndicatorView(user_cert_ui_data_));
626 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
628 // Username label and input.
629 layout_->StartRow(0, 0);
630 layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
631 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USERNAME)));
632 username_textfield_ = new views::Textfield();
633 username_textfield_->set_controller(this);
634 username_textfield_->SetEnabled(username_ui_data_.IsEditable());
635 layout_->AddView(username_textfield_);
636 layout_->AddView(new ControlledSettingIndicatorView(username_ui_data_));
637 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
639 // User passphrase label, input and visble button.
640 layout_->StartRow(0, 0);
641 layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
642 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_PASSPHRASE)));
643 user_passphrase_textfield_ = new PassphraseTextfield();
644 user_passphrase_textfield_->set_controller(this);
645 user_passphrase_textfield_->SetEnabled(user_passphrase_ui_data_.IsEditable());
646 layout_->AddView(user_passphrase_textfield_);
647 layout_->AddView(
648 new ControlledSettingIndicatorView(user_passphrase_ui_data_));
649 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
651 // OTP label and input.
652 layout_->StartRow(0, 0);
653 otp_label_ = new views::Label(l10n_util::GetStringUTF16(
654 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_OTP));
655 layout_->AddView(otp_label_);
656 otp_textfield_ = new views::Textfield();
657 otp_textfield_->set_controller(this);
658 layout_->AddView(otp_textfield_);
659 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
661 // Group Name label and input.
662 layout_->StartRow(0, 0);
663 group_name_label_ = new views::Label(l10n_util::GetStringUTF16(
664 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_GROUP_NAME));
665 layout_->AddView(group_name_label_);
666 group_name_textfield_ =
667 new views::Textfield();
668 group_name_textfield_->set_controller(this);
669 layout_->AddView(group_name_textfield_);
670 layout_->AddView(new ControlledSettingIndicatorView(group_name_ui_data_));
671 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
673 // Save credentials
674 layout_->StartRow(0, 0);
675 save_credentials_checkbox_ = new views::Checkbox(
676 l10n_util::GetStringUTF16(
677 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SAVE_CREDENTIALS));
678 save_credentials_checkbox_->SetEnabled(
679 save_credentials_ui_data_.IsEditable());
680 layout_->SkipColumns(1);
681 layout_->AddView(save_credentials_checkbox_);
682 layout_->AddView(
683 new ControlledSettingIndicatorView(save_credentials_ui_data_));
685 // Error label.
686 layout_->StartRow(0, 0);
687 layout_->SkipColumns(1);
688 error_label_ = new views::Label();
689 error_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
690 error_label_->SetEnabledColor(SK_ColorRED);
691 layout_->AddView(error_label_);
693 // Set or hide the UI, update comboboxes and error labels.
694 Refresh();
696 if (vpn) {
697 NetworkHandler::Get()->network_configuration_handler()->GetShillProperties(
698 service_path_, base::Bind(&VPNConfigView::InitFromProperties,
699 weak_ptr_factory_.GetWeakPtr()),
700 base::Bind(&VPNConfigView::GetPropertiesError,
701 weak_ptr_factory_.GetWeakPtr()));
705 void VPNConfigView::InitFromProperties(
706 const std::string& service_path,
707 const base::DictionaryValue& service_properties) {
708 const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
709 GetNetworkState(service_path);
710 if (!vpn) {
711 NET_LOG_ERROR("Shill Error getting properties VpnConfigView", service_path);
712 return;
715 std::string provider_type, server_hostname, username, group_name;
716 bool psk_passphrase_required = false;
717 user_passphrase_required_ = true;
718 const base::DictionaryValue* provider_properties;
719 if (service_properties.GetDictionaryWithoutPathExpansion(
720 shill::kProviderProperty, &provider_properties)) {
721 provider_properties->GetStringWithoutPathExpansion(
722 shill::kTypeProperty, &provider_type);
723 provider_properties->GetStringWithoutPathExpansion(
724 shill::kHostProperty, &server_hostname);
725 if (provider_type == shill::kProviderL2tpIpsec) {
726 provider_properties->GetStringWithoutPathExpansion(
727 shill::kL2tpIpsecClientCertIdProperty, &client_cert_id_);
728 ca_cert_pem_ = GetPemFromDictionary(
729 provider_properties, shill::kL2tpIpsecCaCertPemProperty);
730 provider_properties->GetBooleanWithoutPathExpansion(
731 shill::kL2tpIpsecPskRequiredProperty, &psk_passphrase_required);
732 provider_properties->GetStringWithoutPathExpansion(
733 shill::kL2tpIpsecUserProperty, &username);
734 provider_properties->GetStringWithoutPathExpansion(
735 shill::kL2tpIpsecTunnelGroupProperty, &group_name);
736 } else if (provider_type == shill::kProviderOpenVpn) {
737 provider_properties->GetStringWithoutPathExpansion(
738 shill::kOpenVPNClientCertIdProperty, &client_cert_id_);
739 ca_cert_pem_ = GetPemFromDictionary(
740 provider_properties, shill::kOpenVPNCaCertPemProperty);
741 provider_properties->GetStringWithoutPathExpansion(
742 shill::kOpenVPNUserProperty, &username);
743 provider_properties->GetBooleanWithoutPathExpansion(
744 shill::kPassphraseRequiredProperty, &user_passphrase_required_);
747 bool save_credentials = false;
748 service_properties.GetBooleanWithoutPathExpansion(
749 shill::kSaveCredentialsProperty, &save_credentials);
751 provider_type_index_ = ProviderTypeToIndex(provider_type, client_cert_id_);
753 if (service_text_)
754 service_text_->SetText(base::ASCIIToUTF16(vpn->name()));
755 if (provider_type_text_label_)
756 provider_type_text_label_->SetText(
757 ProviderTypeIndexToString(provider_type_index_));
759 if (server_textfield_ && !server_hostname.empty())
760 server_textfield_->SetText(base::UTF8ToUTF16(server_hostname));
761 if (username_textfield_ && !username.empty())
762 username_textfield_->SetText(base::UTF8ToUTF16(username));
763 if (group_name_textfield_ && !group_name.empty())
764 group_name_textfield_->SetText(base::UTF8ToUTF16(group_name));
765 if (psk_passphrase_textfield_)
766 psk_passphrase_textfield_->SetShowFake(!psk_passphrase_required);
767 if (user_passphrase_textfield_)
768 user_passphrase_textfield_->SetShowFake(!user_passphrase_required_);
769 if (save_credentials_checkbox_)
770 save_credentials_checkbox_->SetChecked(save_credentials);
772 Refresh();
773 UpdateCanLogin();
776 void VPNConfigView::ParseUIProperties(const NetworkState* vpn) {
777 std::string type_dict_name =
778 ProviderTypeIndexToONCDictKey(provider_type_index_);
779 if (provider_type_index_ == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK) {
780 ParseVPNUIProperty(vpn, type_dict_name, ::onc::ipsec::kServerCARef,
781 &ca_cert_ui_data_);
782 ParseVPNUIProperty(vpn, type_dict_name, ::onc::ipsec::kPSK,
783 &psk_passphrase_ui_data_);
784 ParseVPNUIProperty(vpn, type_dict_name, ::onc::ipsec::kGroup,
785 &group_name_ui_data_);
786 } else if (provider_type_index_ == PROVIDER_TYPE_INDEX_OPEN_VPN) {
787 ParseVPNUIProperty(vpn, type_dict_name, ::onc::openvpn::kServerCARef,
788 &ca_cert_ui_data_);
790 ParseVPNUIProperty(vpn, type_dict_name, ::onc::client_cert::kClientCertRef,
791 &user_cert_ui_data_);
793 const std::string credentials_dict_name(
794 provider_type_index_ == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK ?
795 ::onc::vpn::kL2TP : type_dict_name);
796 ParseVPNUIProperty(vpn, credentials_dict_name, ::onc::vpn::kUsername,
797 &username_ui_data_);
798 ParseVPNUIProperty(vpn, credentials_dict_name, ::onc::vpn::kPassword,
799 &user_passphrase_ui_data_);
800 ParseVPNUIProperty(vpn, credentials_dict_name, ::onc::vpn::kSaveCredentials,
801 &save_credentials_ui_data_);
804 void VPNConfigView::GetPropertiesError(
805 const std::string& error_name,
806 scoped_ptr<base::DictionaryValue> error_data) {
807 NET_LOG_ERROR("Shill Error from VpnConfigView: " + error_name, "");
810 void VPNConfigView::SetConfigProperties(
811 base::DictionaryValue* properties) {
812 int provider_type_index = GetProviderTypeIndex();
813 std::string user_passphrase = GetUserPassphrase();
814 std::string user_name = GetUsername();
815 std::string group_name = GetGroupName();
816 switch (provider_type_index) {
817 case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK: {
818 std::string psk_passphrase = GetPSKPassphrase();
819 if (!psk_passphrase.empty()) {
820 properties->SetStringWithoutPathExpansion(
821 shill::kL2tpIpsecPskProperty, GetPSKPassphrase());
823 if (!group_name.empty()) {
824 properties->SetStringWithoutPathExpansion(
825 shill::kL2tpIpsecTunnelGroupProperty, group_name);
827 if (!user_name.empty()) {
828 properties->SetStringWithoutPathExpansion(
829 shill::kL2tpIpsecUserProperty, user_name);
831 if (!user_passphrase.empty()) {
832 properties->SetStringWithoutPathExpansion(
833 shill::kL2tpIpsecPasswordProperty, user_passphrase);
835 break;
837 case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT: {
838 if (server_ca_cert_combobox_) {
839 std::string ca_cert_pem = GetServerCACertPEM();
840 base::ListValue* pem_list = new base::ListValue;
841 if (!ca_cert_pem.empty())
842 pem_list->AppendString(ca_cert_pem);
843 properties->SetWithoutPathExpansion(shill::kL2tpIpsecCaCertPemProperty,
844 pem_list);
846 SetUserCertProperties(client_cert::CONFIG_TYPE_IPSEC, properties);
847 if (!group_name.empty()) {
848 properties->SetStringWithoutPathExpansion(
849 shill::kL2tpIpsecTunnelGroupProperty, GetGroupName());
851 if (!user_name.empty()) {
852 properties->SetStringWithoutPathExpansion(
853 shill::kL2tpIpsecUserProperty, user_name);
855 if (!user_passphrase.empty()) {
856 properties->SetStringWithoutPathExpansion(
857 shill::kL2tpIpsecPasswordProperty, user_passphrase);
859 break;
861 case PROVIDER_TYPE_INDEX_OPEN_VPN: {
862 if (server_ca_cert_combobox_) {
863 std::string ca_cert_pem = GetServerCACertPEM();
864 base::ListValue* pem_list = new base::ListValue;
865 if (!ca_cert_pem.empty())
866 pem_list->AppendString(ca_cert_pem);
867 properties->SetWithoutPathExpansion(shill::kOpenVPNCaCertPemProperty,
868 pem_list);
870 SetUserCertProperties(client_cert::CONFIG_TYPE_OPENVPN, properties);
871 properties->SetStringWithoutPathExpansion(
872 shill::kOpenVPNUserProperty, GetUsername());
873 if (!user_passphrase.empty()) {
874 properties->SetStringWithoutPathExpansion(
875 shill::kOpenVPNPasswordProperty, user_passphrase);
877 std::string otp = GetOTP();
878 if (!otp.empty()) {
879 properties->SetStringWithoutPathExpansion(
880 shill::kOpenVPNOTPProperty, otp);
882 break;
884 case PROVIDER_TYPE_INDEX_MAX:
885 NOTREACHED();
886 break;
888 properties->SetBooleanWithoutPathExpansion(
889 shill::kSaveCredentialsProperty, GetSaveCredentials());
892 void VPNConfigView::Refresh() {
893 UpdateControls();
895 // Set certificate combo boxes.
896 if (server_ca_cert_combobox_) {
897 server_ca_cert_combobox_->ModelChanged();
898 if (enable_server_ca_cert_ && !ca_cert_pem_.empty()) {
899 // Select the current server CA certificate in the combobox.
900 int cert_index =
901 CertLibrary::Get()->GetServerCACertIndexByPEM(ca_cert_pem_);
902 if (cert_index >= 0) {
903 // Skip item for "Default"
904 server_ca_cert_combobox_->SetSelectedIndex(1 + cert_index);
905 } else {
906 server_ca_cert_combobox_->SetSelectedIndex(0);
908 } else {
909 server_ca_cert_combobox_->SetSelectedIndex(0);
913 if (user_cert_combobox_) {
914 user_cert_combobox_->ModelChanged();
915 if (enable_user_cert_ && !client_cert_id_.empty()) {
916 int cert_index =
917 CertLibrary::Get()->GetUserCertIndexByPkcs11Id(client_cert_id_);
918 if (cert_index >= 0)
919 user_cert_combobox_->SetSelectedIndex(cert_index);
920 else
921 user_cert_combobox_->SetSelectedIndex(0);
922 } else {
923 user_cert_combobox_->SetSelectedIndex(0);
927 UpdateErrorLabel();
930 void VPNConfigView::UpdateControlsToEnable() {
931 enable_psk_passphrase_ = false;
932 enable_user_cert_ = false;
933 enable_server_ca_cert_ = false;
934 enable_otp_ = false;
935 enable_group_name_ = false;
936 int provider_type_index = GetProviderTypeIndex();
937 if (provider_type_index == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK) {
938 enable_psk_passphrase_ = true;
939 enable_group_name_ = true;
940 } else if (provider_type_index == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT) {
941 enable_server_ca_cert_ = true;
942 enable_user_cert_ = HaveUserCerts();
943 enable_group_name_ = true;
944 } else { // PROVIDER_TYPE_INDEX_OPEN_VPN (default)
945 enable_server_ca_cert_ = true;
946 enable_user_cert_ = HaveUserCerts();
947 enable_otp_ = true;
951 void VPNConfigView::UpdateControls() {
952 UpdateControlsToEnable();
954 if (psk_passphrase_label_)
955 psk_passphrase_label_->SetEnabled(enable_psk_passphrase_);
956 if (psk_passphrase_textfield_)
957 psk_passphrase_textfield_->SetEnabled(enable_psk_passphrase_ &&
958 psk_passphrase_ui_data_.IsEditable());
960 if (user_cert_label_)
961 user_cert_label_->SetEnabled(enable_user_cert_);
962 if (user_cert_combobox_)
963 user_cert_combobox_->SetEnabled(enable_user_cert_ &&
964 user_cert_ui_data_.IsEditable());
966 if (server_ca_cert_label_)
967 server_ca_cert_label_->SetEnabled(enable_server_ca_cert_);
968 if (server_ca_cert_combobox_)
969 server_ca_cert_combobox_->SetEnabled(enable_server_ca_cert_ &&
970 ca_cert_ui_data_.IsEditable());
972 if (otp_label_)
973 otp_label_->SetEnabled(enable_otp_);
974 if (otp_textfield_)
975 otp_textfield_->SetEnabled(enable_otp_);
977 if (group_name_label_)
978 group_name_label_->SetEnabled(enable_group_name_);
979 if (group_name_textfield_)
980 group_name_textfield_->SetEnabled(enable_group_name_ &&
981 group_name_ui_data_.IsEditable());
984 void VPNConfigView::UpdateErrorLabel() {
985 // Error message.
986 base::string16 error_msg;
987 bool cert_required =
988 GetProviderTypeIndex() == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT;
989 if (cert_required && CertLibrary::Get()->CertificatesLoaded()) {
990 if (!HaveUserCerts()) {
991 error_msg = l10n_util::GetStringUTF16(
992 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PLEASE_INSTALL_USER_CERT);
993 } else if (!IsUserCertValid()) {
994 error_msg = l10n_util::GetStringUTF16(
995 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_REQUIRE_HARDWARE_BACKED);
998 if (error_msg.empty() && !service_path_.empty()) {
999 // TODO(kuan): differentiate between bad psk and user passphrases.
1000 const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
1001 GetNetworkState(service_path_);
1002 if (vpn && vpn->connection_state() == shill::kStateFailure)
1003 error_msg = ui::NetworkConnect::Get()->GetShillErrorString(
1004 vpn->last_error(), vpn->path());
1006 if (!error_msg.empty()) {
1007 error_label_->SetText(error_msg);
1008 error_label_->SetVisible(true);
1009 } else {
1010 error_label_->SetVisible(false);
1014 void VPNConfigView::UpdateCanLogin() {
1015 parent_->GetDialogClientView()->UpdateDialogButtons();
1018 bool VPNConfigView::HaveUserCerts() const {
1019 return CertLibrary::Get()->NumCertificates(CertLibrary::CERT_TYPE_USER) > 0;
1022 bool VPNConfigView::IsUserCertValid() const {
1023 if (!user_cert_combobox_ || !enable_user_cert_)
1024 return false;
1025 int index = user_cert_combobox_->selected_index();
1026 if (index < 0)
1027 return false;
1028 // Currently only hardware-backed user certificates are valid.
1029 if (!CertLibrary::Get()->IsCertHardwareBackedAt(CertLibrary::CERT_TYPE_USER,
1030 index)) {
1031 return false;
1033 return true;
1036 const std::string VPNConfigView::GetTextFromField(views::Textfield* textfield,
1037 bool trim_whitespace) const {
1038 if (!textfield)
1039 return std::string();
1040 std::string untrimmed = base::UTF16ToUTF8(textfield->text());
1041 if (!trim_whitespace)
1042 return untrimmed;
1043 std::string result;
1044 base::TrimWhitespaceASCII(untrimmed, base::TRIM_ALL, &result);
1045 return result;
1048 const std::string VPNConfigView::GetPassphraseFromField(
1049 PassphraseTextfield* textfield) const {
1050 if (!textfield)
1051 return std::string();
1052 return textfield->GetPassphrase();
1055 void VPNConfigView::ParseVPNUIProperty(
1056 const NetworkState* network,
1057 const std::string& dict_key,
1058 const std::string& key,
1059 NetworkPropertyUIData* property_ui_data) {
1060 ::onc::ONCSource onc_source = ::onc::ONC_SOURCE_NONE;
1061 const base::DictionaryValue* onc =
1062 onc::FindPolicyForActiveUser(network->guid(), &onc_source);
1064 VLOG_IF(1, !onc) << "No ONC found for VPN network " << network->guid();
1065 property_ui_data->ParseOncProperty(
1066 onc_source,
1067 onc,
1068 base::StringPrintf("%s.%s.%s",
1069 ::onc::network_config::kVPN,
1070 dict_key.c_str(),
1071 key.c_str()));
1074 } // namespace chromeos