Add ENABLE_MEDIA_ROUTER define to builds other than Android and iOS.
[chromium-blink-merge.git] / chrome / browser / chromeos / options / vpn_config_view.cc
blob7c3334b7258c66f2d331324c16a003edb92352db
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 title_(0),
232 layout_(NULL),
233 server_textfield_(NULL),
234 service_text_(NULL),
235 service_textfield_(NULL),
236 provider_type_combobox_(NULL),
237 provider_type_text_label_(NULL),
238 psk_passphrase_label_(NULL),
239 psk_passphrase_textfield_(NULL),
240 user_cert_label_(NULL),
241 user_cert_combobox_(NULL),
242 server_ca_cert_label_(NULL),
243 server_ca_cert_combobox_(NULL),
244 username_textfield_(NULL),
245 user_passphrase_textfield_(NULL),
246 otp_label_(NULL),
247 otp_textfield_(NULL),
248 group_name_label_(NULL),
249 group_name_textfield_(NULL),
250 save_credentials_checkbox_(NULL),
251 error_label_(NULL),
252 provider_type_index_(PROVIDER_TYPE_INDEX_MAX),
253 weak_ptr_factory_(this) {
254 Init();
257 VPNConfigView::~VPNConfigView() {
258 RemoveAllChildViews(true); // Destroy children before models
259 CertLibrary::Get()->RemoveObserver(this);
262 base::string16 VPNConfigView::GetTitle() const {
263 DCHECK_NE(title_, 0);
264 return l10n_util::GetStringUTF16(title_);
267 views::View* VPNConfigView::GetInitiallyFocusedView() {
268 if (service_path_.empty()) {
269 // Put focus in the first editable field.
270 if (server_textfield_)
271 return server_textfield_;
272 else if (service_textfield_)
273 return service_textfield_;
274 else if (provider_type_combobox_)
275 return provider_type_combobox_;
276 else if (psk_passphrase_textfield_ && psk_passphrase_textfield_->enabled())
277 return psk_passphrase_textfield_;
278 else if (user_cert_combobox_ && user_cert_combobox_->enabled())
279 return user_cert_combobox_;
280 else if (server_ca_cert_combobox_ && server_ca_cert_combobox_->enabled())
281 return server_ca_cert_combobox_;
283 if (user_passphrase_textfield_)
284 return user_passphrase_textfield_;
285 else if (otp_textfield_)
286 return otp_textfield_;
287 return NULL;
290 bool VPNConfigView::CanLogin() {
291 // Username is always required.
292 if (GetUsername().empty())
293 return false;
295 // TODO(stevenjb): min kMinPassphraseLen length?
296 if (service_path_.empty() &&
297 (GetService().empty() || GetServer().empty()))
298 return false;
300 // Block login if certs are required but user has none.
301 bool cert_required =
302 GetProviderTypeIndex() == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT;
303 if (cert_required && (!HaveUserCerts() || !IsUserCertValid()))
304 return false;
306 return true;
309 void VPNConfigView::ContentsChanged(views::Textfield* sender,
310 const base::string16& new_contents) {
311 if (sender == server_textfield_ && !service_text_modified_) {
312 // Set the service name to the server name up to '.', unless it has
313 // been explicitly set by the user.
314 base::string16 server = server_textfield_->text();
315 base::string16::size_type n = server.find_first_of(L'.');
316 service_name_from_server_ = server.substr(0, n);
317 service_textfield_->SetText(service_name_from_server_);
319 if (sender == service_textfield_) {
320 if (new_contents.empty())
321 service_text_modified_ = false;
322 else if (new_contents != service_name_from_server_)
323 service_text_modified_ = true;
325 UpdateCanLogin();
328 bool VPNConfigView::HandleKeyEvent(views::Textfield* sender,
329 const ui::KeyEvent& key_event) {
330 if ((sender == psk_passphrase_textfield_ ||
331 sender == user_passphrase_textfield_) &&
332 key_event.key_code() == ui::VKEY_RETURN) {
333 parent_->GetDialogClientView()->AcceptWindow();
335 return false;
338 void VPNConfigView::ButtonPressed(views::Button* sender,
339 const ui::Event& event) {
342 void VPNConfigView::OnPerformAction(views::Combobox* combobox) {
343 UpdateControls();
344 UpdateErrorLabel();
345 UpdateCanLogin();
348 void VPNConfigView::OnCertificatesLoaded(bool initial_load) {
349 Refresh();
352 bool VPNConfigView::Login() {
353 if (service_path_.empty()) {
354 base::DictionaryValue properties;
355 // Identifying properties
356 properties.SetStringWithoutPathExpansion(
357 shill::kTypeProperty, shill::kTypeVPN);
358 properties.SetStringWithoutPathExpansion(
359 shill::kNameProperty, GetService());
360 properties.SetStringWithoutPathExpansion(
361 shill::kProviderHostProperty, GetServer());
362 properties.SetStringWithoutPathExpansion(
363 shill::kProviderTypeProperty, GetProviderTypeString());
365 SetConfigProperties(&properties);
366 bool shared = false;
367 bool modifiable = false;
368 ChildNetworkConfigView::GetShareStateForLoginState(&shared, &modifiable);
370 bool only_policy_autoconnect =
371 onc::PolicyAllowsOnlyPolicyNetworksToAutoconnect(!shared);
372 if (only_policy_autoconnect) {
373 properties.SetBooleanWithoutPathExpansion(shill::kAutoConnectProperty,
374 false);
377 ui::NetworkConnect::Get()->CreateConfigurationAndConnect(&properties,
378 shared);
379 } else {
380 const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
381 GetNetworkState(service_path_);
382 if (!vpn) {
383 // Shill no longer knows about this network (edge case).
384 // TODO(stevenjb): Add notification for this.
385 NET_LOG_ERROR("Network not found", service_path_);
386 return true; // Close dialog
388 base::DictionaryValue properties;
389 SetConfigProperties(&properties);
390 ui::NetworkConnect::Get()->ConfigureNetworkAndConnect(
391 service_path_, properties, false /* not shared */);
393 return true; // Close dialog.
396 void VPNConfigView::Cancel() {
399 void VPNConfigView::InitFocus() {
400 views::View* view_to_focus = GetInitiallyFocusedView();
401 if (view_to_focus)
402 view_to_focus->RequestFocus();
405 const std::string VPNConfigView::GetService() const {
406 if (service_textfield_ != NULL)
407 return GetTextFromField(service_textfield_, true);
408 return service_path_;
411 const std::string VPNConfigView::GetServer() const {
412 if (server_textfield_ != NULL)
413 return GetTextFromField(server_textfield_, true);
414 return std::string();
417 const std::string VPNConfigView::GetPSKPassphrase() const {
418 if (psk_passphrase_textfield_ &&
419 enable_psk_passphrase_ &&
420 psk_passphrase_textfield_->visible())
421 return GetPassphraseFromField(psk_passphrase_textfield_);
422 return std::string();
425 const std::string VPNConfigView::GetUsername() const {
426 return GetTextFromField(username_textfield_, true);
429 const std::string VPNConfigView::GetUserPassphrase() const {
430 return GetPassphraseFromField(user_passphrase_textfield_);
433 const std::string VPNConfigView::GetGroupName() const {
434 return GetTextFromField(group_name_textfield_, false);
437 const std::string VPNConfigView::GetOTP() const {
438 return GetTextFromField(otp_textfield_, true);
441 const std::string VPNConfigView::GetServerCACertPEM() const {
442 int index = server_ca_cert_combobox_ ?
443 server_ca_cert_combobox_->selected_index() : 0;
444 if (index == 0) {
445 // First item is "Default".
446 return std::string();
447 } else {
448 int cert_index = index - 1;
449 return CertLibrary::Get()->GetServerCACertPEMAt(cert_index);
453 void VPNConfigView::SetUserCertProperties(
454 chromeos::client_cert::ConfigType client_cert_type,
455 base::DictionaryValue* properties) const {
456 if (!HaveUserCerts()) {
457 // No certificate selected or not required.
458 chromeos::client_cert::SetEmptyShillProperties(client_cert_type,
459 properties);
460 } else {
461 // Certificates are listed in the order they appear in the model.
462 int index = user_cert_combobox_ ? user_cert_combobox_->selected_index() : 0;
463 int slot_id = -1;
464 const std::string pkcs11_id =
465 CertLibrary::Get()->GetUserCertPkcs11IdAt(index, &slot_id);
466 chromeos::client_cert::SetShillProperties(
467 client_cert_type, slot_id, pkcs11_id, properties);
471 bool VPNConfigView::GetSaveCredentials() const {
472 return save_credentials_checkbox_->checked();
475 int VPNConfigView::GetProviderTypeIndex() const {
476 if (provider_type_combobox_)
477 return provider_type_combobox_->selected_index();
478 return provider_type_index_;
481 std::string VPNConfigView::GetProviderTypeString() const {
482 int index = GetProviderTypeIndex();
483 switch (index) {
484 case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK:
485 case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT:
486 return shill::kProviderL2tpIpsec;
487 case PROVIDER_TYPE_INDEX_OPEN_VPN:
488 return shill::kProviderOpenVpn;
490 NOTREACHED();
491 return std::string();
494 void VPNConfigView::Init() {
495 const NetworkState* vpn = NULL;
496 if (!service_path_.empty()) {
497 vpn = NetworkHandler::Get()->network_state_handler()->
498 GetNetworkState(service_path_);
499 DCHECK(vpn && vpn->type() == shill::kTypeVPN);
501 layout_ = views::GridLayout::CreatePanel(this);
502 SetLayoutManager(layout_);
504 // Observer any changes to the certificate list.
505 CertLibrary::Get()->AddObserver(this);
507 views::ColumnSet* column_set = layout_->AddColumnSet(0);
508 // Label.
509 column_set->AddColumn(views::GridLayout::LEADING, views::GridLayout::FILL, 1,
510 views::GridLayout::USE_PREF, 0, 0);
511 column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing);
512 // Textfield, combobox.
513 column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
514 views::GridLayout::USE_PREF, 0,
515 ChildNetworkConfigView::kInputFieldMinWidth);
516 column_set->AddPaddingColumn(0, views::kRelatedControlSmallHorizontalSpacing);
517 // Policy indicator.
518 column_set->AddColumn(views::GridLayout::CENTER, views::GridLayout::CENTER, 0,
519 views::GridLayout::USE_PREF, 0, 0);
521 // Initialize members.
522 service_text_modified_ = false;
523 title_ = vpn ? IDS_OPTIONS_SETTINGS_JOIN_VPN : IDS_OPTIONS_SETTINGS_ADD_VPN;
525 // By default enable all controls.
526 enable_psk_passphrase_ = true;
527 enable_user_cert_ = true;
528 enable_server_ca_cert_ = true;
529 enable_otp_ = true;
530 enable_group_name_ = true;
532 // Server label and input.
533 layout_->StartRow(0, 0);
534 views::View* server_label =
535 new views::Label(l10n_util::GetStringUTF16(
536 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVER_HOSTNAME));
537 layout_->AddView(server_label);
538 server_textfield_ = new views::Textfield();
539 server_textfield_->set_controller(this);
540 layout_->AddView(server_textfield_);
541 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
542 if (!service_path_.empty()) {
543 server_label->SetEnabled(false);
544 server_textfield_->SetEnabled(false);
547 // Service label and name or input.
548 layout_->StartRow(0, 0);
549 layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
550 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_SERVICE_NAME)));
551 if (service_path_.empty()) {
552 service_textfield_ = new views::Textfield();
553 service_textfield_->set_controller(this);
554 layout_->AddView(service_textfield_);
555 service_text_ = NULL;
556 } else {
557 service_text_ = new views::Label();
558 service_text_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
559 layout_->AddView(service_text_);
560 service_textfield_ = NULL;
562 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
564 // Provider type label and select.
565 layout_->StartRow(0, 0);
566 layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
567 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PROVIDER_TYPE)));
568 if (service_path_.empty()) {
569 provider_type_combobox_model_.reset(
570 new internal::ProviderTypeComboboxModel);
571 provider_type_combobox_ = new views::Combobox(
572 provider_type_combobox_model_.get());
573 provider_type_combobox_->set_listener(this);
574 layout_->AddView(provider_type_combobox_);
575 provider_type_text_label_ = NULL;
576 } else {
577 provider_type_text_label_ = new views::Label();
578 provider_type_text_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
579 layout_->AddView(provider_type_text_label_);
580 provider_type_combobox_ = NULL;
582 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
584 // PSK passphrase label, input and visible button.
585 layout_->StartRow(0, 0);
586 psk_passphrase_label_ = new views::Label(l10n_util::GetStringUTF16(
587 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_PSK_PASSPHRASE));
588 layout_->AddView(psk_passphrase_label_);
589 psk_passphrase_textfield_ = new PassphraseTextfield();
590 psk_passphrase_textfield_->set_controller(this);
591 layout_->AddView(psk_passphrase_textfield_);
592 layout_->AddView(
593 new ControlledSettingIndicatorView(psk_passphrase_ui_data_));
594 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
596 // Server CA certificate
597 if (service_path_.empty()) {
598 layout_->StartRow(0, 0);
599 server_ca_cert_label_ = new views::Label(l10n_util::GetStringUTF16(
600 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_CERT_SERVER_CA));
601 layout_->AddView(server_ca_cert_label_);
602 server_ca_cert_combobox_model_.reset(
603 new internal::VpnServerCACertComboboxModel());
604 server_ca_cert_combobox_ = new views::Combobox(
605 server_ca_cert_combobox_model_.get());
606 layout_->AddView(server_ca_cert_combobox_);
607 layout_->AddView(new ControlledSettingIndicatorView(ca_cert_ui_data_));
608 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
609 } else {
610 server_ca_cert_label_ = NULL;
611 server_ca_cert_combobox_ = NULL;
614 // User certificate label and input.
615 layout_->StartRow(0, 0);
616 user_cert_label_ = new views::Label(l10n_util::GetStringUTF16(
617 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_CERT));
618 layout_->AddView(user_cert_label_);
619 user_cert_combobox_model_.reset(
620 new internal::VpnUserCertComboboxModel());
621 user_cert_combobox_ = new views::Combobox(user_cert_combobox_model_.get());
622 user_cert_combobox_->set_listener(this);
623 layout_->AddView(user_cert_combobox_);
624 layout_->AddView(new ControlledSettingIndicatorView(user_cert_ui_data_));
625 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
627 // Username label and input.
628 layout_->StartRow(0, 0);
629 layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
630 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USERNAME)));
631 username_textfield_ = new views::Textfield();
632 username_textfield_->set_controller(this);
633 username_textfield_->SetEnabled(username_ui_data_.IsEditable());
634 layout_->AddView(username_textfield_);
635 layout_->AddView(new ControlledSettingIndicatorView(username_ui_data_));
636 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
638 // User passphrase label, input and visble button.
639 layout_->StartRow(0, 0);
640 layout_->AddView(new views::Label(l10n_util::GetStringUTF16(
641 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_USER_PASSPHRASE)));
642 user_passphrase_textfield_ = new PassphraseTextfield();
643 user_passphrase_textfield_->set_controller(this);
644 user_passphrase_textfield_->SetEnabled(user_passphrase_ui_data_.IsEditable());
645 layout_->AddView(user_passphrase_textfield_);
646 layout_->AddView(
647 new ControlledSettingIndicatorView(user_passphrase_ui_data_));
648 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
650 // OTP label and input.
651 layout_->StartRow(0, 0);
652 otp_label_ = new views::Label(l10n_util::GetStringUTF16(
653 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_OTP));
654 layout_->AddView(otp_label_);
655 otp_textfield_ = new views::Textfield();
656 otp_textfield_->set_controller(this);
657 layout_->AddView(otp_textfield_);
658 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
660 // Group Name label and input.
661 layout_->StartRow(0, 0);
662 group_name_label_ = new views::Label(l10n_util::GetStringUTF16(
663 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_VPN_GROUP_NAME));
664 layout_->AddView(group_name_label_);
665 group_name_textfield_ =
666 new views::Textfield();
667 group_name_textfield_->set_controller(this);
668 layout_->AddView(group_name_textfield_);
669 layout_->AddView(new ControlledSettingIndicatorView(group_name_ui_data_));
670 layout_->AddPaddingRow(0, views::kRelatedControlVerticalSpacing);
672 // Save credentials
673 layout_->StartRow(0, 0);
674 save_credentials_checkbox_ = new views::Checkbox(
675 l10n_util::GetStringUTF16(
676 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_SAVE_CREDENTIALS));
677 save_credentials_checkbox_->SetEnabled(
678 save_credentials_ui_data_.IsEditable());
679 layout_->SkipColumns(1);
680 layout_->AddView(save_credentials_checkbox_);
681 layout_->AddView(
682 new ControlledSettingIndicatorView(save_credentials_ui_data_));
684 // Error label.
685 layout_->StartRow(0, 0);
686 layout_->SkipColumns(1);
687 error_label_ = new views::Label();
688 error_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT);
689 error_label_->SetEnabledColor(SK_ColorRED);
690 layout_->AddView(error_label_);
692 // Set or hide the UI, update comboboxes and error labels.
693 Refresh();
695 if (vpn) {
696 NetworkHandler::Get()->network_configuration_handler()->GetShillProperties(
697 service_path_, base::Bind(&VPNConfigView::InitFromProperties,
698 weak_ptr_factory_.GetWeakPtr()),
699 base::Bind(&VPNConfigView::GetPropertiesError,
700 weak_ptr_factory_.GetWeakPtr()));
704 void VPNConfigView::InitFromProperties(
705 const std::string& service_path,
706 const base::DictionaryValue& service_properties) {
707 const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
708 GetNetworkState(service_path);
709 if (!vpn) {
710 NET_LOG_ERROR("Shill Error getting properties VpnConfigView", service_path);
711 return;
714 std::string provider_type, server_hostname, username, group_name;
715 bool psk_passphrase_required = false;
716 bool user_passphrase_required = true;
717 const base::DictionaryValue* provider_properties;
718 if (service_properties.GetDictionaryWithoutPathExpansion(
719 shill::kProviderProperty, &provider_properties)) {
720 provider_properties->GetStringWithoutPathExpansion(
721 shill::kTypeProperty, &provider_type);
722 provider_properties->GetStringWithoutPathExpansion(
723 shill::kHostProperty, &server_hostname);
724 if (provider_type == shill::kProviderL2tpIpsec) {
725 provider_properties->GetStringWithoutPathExpansion(
726 shill::kL2tpIpsecClientCertIdProperty, &client_cert_id_);
727 ca_cert_pem_ = GetPemFromDictionary(
728 provider_properties, shill::kL2tpIpsecCaCertPemProperty);
729 provider_properties->GetBooleanWithoutPathExpansion(
730 shill::kL2tpIpsecPskRequiredProperty, &psk_passphrase_required);
731 provider_properties->GetStringWithoutPathExpansion(
732 shill::kL2tpIpsecUserProperty, &username);
733 provider_properties->GetStringWithoutPathExpansion(
734 shill::kL2tpIpsecTunnelGroupProperty, &group_name);
735 } else if (provider_type == shill::kProviderOpenVpn) {
736 provider_properties->GetStringWithoutPathExpansion(
737 shill::kOpenVPNClientCertIdProperty, &client_cert_id_);
738 ca_cert_pem_ = GetPemFromDictionary(
739 provider_properties, shill::kOpenVPNCaCertPemProperty);
740 provider_properties->GetStringWithoutPathExpansion(
741 shill::kOpenVPNUserProperty, &username);
742 provider_properties->GetBooleanWithoutPathExpansion(
743 shill::kPassphraseRequiredProperty, &user_passphrase_required);
746 bool save_credentials = false;
747 service_properties.GetBooleanWithoutPathExpansion(
748 shill::kSaveCredentialsProperty, &save_credentials);
750 provider_type_index_ = ProviderTypeToIndex(provider_type, client_cert_id_);
752 if (service_text_)
753 service_text_->SetText(base::ASCIIToUTF16(vpn->name()));
754 if (provider_type_text_label_)
755 provider_type_text_label_->SetText(
756 ProviderTypeIndexToString(provider_type_index_));
758 if (server_textfield_ && !server_hostname.empty())
759 server_textfield_->SetText(base::UTF8ToUTF16(server_hostname));
760 if (username_textfield_ && !username.empty())
761 username_textfield_->SetText(base::UTF8ToUTF16(username));
762 if (group_name_textfield_ && !group_name.empty())
763 group_name_textfield_->SetText(base::UTF8ToUTF16(group_name));
764 if (psk_passphrase_textfield_)
765 psk_passphrase_textfield_->SetShowFake(!psk_passphrase_required);
766 if (user_passphrase_textfield_)
767 user_passphrase_textfield_->SetShowFake(!user_passphrase_required);
768 if (save_credentials_checkbox_)
769 save_credentials_checkbox_->SetChecked(save_credentials);
771 Refresh();
772 UpdateCanLogin();
775 void VPNConfigView::ParseUIProperties(const NetworkState* vpn) {
776 std::string type_dict_name =
777 ProviderTypeIndexToONCDictKey(provider_type_index_);
778 if (provider_type_index_ == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK) {
779 ParseVPNUIProperty(vpn, type_dict_name, ::onc::ipsec::kServerCARef,
780 &ca_cert_ui_data_);
781 ParseVPNUIProperty(vpn, type_dict_name, ::onc::ipsec::kPSK,
782 &psk_passphrase_ui_data_);
783 ParseVPNUIProperty(vpn, type_dict_name, ::onc::ipsec::kGroup,
784 &group_name_ui_data_);
785 } else if (provider_type_index_ == PROVIDER_TYPE_INDEX_OPEN_VPN) {
786 ParseVPNUIProperty(vpn, type_dict_name, ::onc::openvpn::kServerCARef,
787 &ca_cert_ui_data_);
789 ParseVPNUIProperty(vpn, type_dict_name, ::onc::client_cert::kClientCertRef,
790 &user_cert_ui_data_);
792 const std::string credentials_dict_name(
793 provider_type_index_ == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK ?
794 ::onc::vpn::kL2TP : type_dict_name);
795 ParseVPNUIProperty(vpn, credentials_dict_name, ::onc::vpn::kUsername,
796 &username_ui_data_);
797 ParseVPNUIProperty(vpn, credentials_dict_name, ::onc::vpn::kPassword,
798 &user_passphrase_ui_data_);
799 ParseVPNUIProperty(vpn, credentials_dict_name, ::onc::vpn::kSaveCredentials,
800 &save_credentials_ui_data_);
803 void VPNConfigView::GetPropertiesError(
804 const std::string& error_name,
805 scoped_ptr<base::DictionaryValue> error_data) {
806 NET_LOG_ERROR("Shill Error from VpnConfigView: " + error_name, "");
809 void VPNConfigView::SetConfigProperties(
810 base::DictionaryValue* properties) {
811 int provider_type_index = GetProviderTypeIndex();
812 std::string user_passphrase = GetUserPassphrase();
813 std::string user_name = GetUsername();
814 std::string group_name = GetGroupName();
815 switch (provider_type_index) {
816 case PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK: {
817 std::string psk_passphrase = GetPSKPassphrase();
818 if (!psk_passphrase.empty()) {
819 properties->SetStringWithoutPathExpansion(
820 shill::kL2tpIpsecPskProperty, GetPSKPassphrase());
822 if (!group_name.empty()) {
823 properties->SetStringWithoutPathExpansion(
824 shill::kL2tpIpsecTunnelGroupProperty, group_name);
826 if (!user_name.empty()) {
827 properties->SetStringWithoutPathExpansion(
828 shill::kL2tpIpsecUserProperty, user_name);
830 if (!user_passphrase.empty()) {
831 properties->SetStringWithoutPathExpansion(
832 shill::kL2tpIpsecPasswordProperty, user_passphrase);
834 break;
836 case PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT: {
837 if (server_ca_cert_combobox_) {
838 std::string ca_cert_pem = GetServerCACertPEM();
839 base::ListValue* pem_list = new base::ListValue;
840 if (!ca_cert_pem.empty())
841 pem_list->AppendString(ca_cert_pem);
842 properties->SetWithoutPathExpansion(shill::kL2tpIpsecCaCertPemProperty,
843 pem_list);
845 SetUserCertProperties(client_cert::CONFIG_TYPE_IPSEC, properties);
846 if (!group_name.empty()) {
847 properties->SetStringWithoutPathExpansion(
848 shill::kL2tpIpsecTunnelGroupProperty, GetGroupName());
850 if (!user_name.empty()) {
851 properties->SetStringWithoutPathExpansion(
852 shill::kL2tpIpsecUserProperty, user_name);
854 if (!user_passphrase.empty()) {
855 properties->SetStringWithoutPathExpansion(
856 shill::kL2tpIpsecPasswordProperty, user_passphrase);
858 break;
860 case PROVIDER_TYPE_INDEX_OPEN_VPN: {
861 if (server_ca_cert_combobox_) {
862 std::string ca_cert_pem = GetServerCACertPEM();
863 base::ListValue* pem_list = new base::ListValue;
864 if (!ca_cert_pem.empty())
865 pem_list->AppendString(ca_cert_pem);
866 properties->SetWithoutPathExpansion(shill::kOpenVPNCaCertPemProperty,
867 pem_list);
869 SetUserCertProperties(client_cert::CONFIG_TYPE_OPENVPN, properties);
870 properties->SetStringWithoutPathExpansion(
871 shill::kOpenVPNUserProperty, GetUsername());
872 if (!user_passphrase.empty()) {
873 properties->SetStringWithoutPathExpansion(
874 shill::kOpenVPNPasswordProperty, user_passphrase);
876 std::string otp = GetOTP();
877 if (!otp.empty()) {
878 properties->SetStringWithoutPathExpansion(
879 shill::kOpenVPNOTPProperty, otp);
881 break;
883 case PROVIDER_TYPE_INDEX_MAX:
884 NOTREACHED();
885 break;
887 properties->SetBooleanWithoutPathExpansion(
888 shill::kSaveCredentialsProperty, GetSaveCredentials());
891 void VPNConfigView::Refresh() {
892 UpdateControls();
894 // Set certificate combo boxes.
895 if (server_ca_cert_combobox_) {
896 server_ca_cert_combobox_->ModelChanged();
897 if (enable_server_ca_cert_ && !ca_cert_pem_.empty()) {
898 // Select the current server CA certificate in the combobox.
899 int cert_index =
900 CertLibrary::Get()->GetServerCACertIndexByPEM(ca_cert_pem_);
901 if (cert_index >= 0) {
902 // Skip item for "Default"
903 server_ca_cert_combobox_->SetSelectedIndex(1 + cert_index);
904 } else {
905 server_ca_cert_combobox_->SetSelectedIndex(0);
907 } else {
908 server_ca_cert_combobox_->SetSelectedIndex(0);
912 if (user_cert_combobox_) {
913 user_cert_combobox_->ModelChanged();
914 if (enable_user_cert_ && !client_cert_id_.empty()) {
915 int cert_index =
916 CertLibrary::Get()->GetUserCertIndexByPkcs11Id(client_cert_id_);
917 if (cert_index >= 0)
918 user_cert_combobox_->SetSelectedIndex(cert_index);
919 else
920 user_cert_combobox_->SetSelectedIndex(0);
921 } else {
922 user_cert_combobox_->SetSelectedIndex(0);
926 UpdateErrorLabel();
929 void VPNConfigView::UpdateControlsToEnable() {
930 enable_psk_passphrase_ = false;
931 enable_user_cert_ = false;
932 enable_server_ca_cert_ = false;
933 enable_otp_ = false;
934 enable_group_name_ = false;
935 int provider_type_index = GetProviderTypeIndex();
936 if (provider_type_index == PROVIDER_TYPE_INDEX_L2TP_IPSEC_PSK) {
937 enable_psk_passphrase_ = true;
938 enable_group_name_ = true;
939 } else if (provider_type_index == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT) {
940 enable_server_ca_cert_ = true;
941 enable_user_cert_ = HaveUserCerts();
942 enable_group_name_ = true;
943 } else { // PROVIDER_TYPE_INDEX_OPEN_VPN (default)
944 enable_server_ca_cert_ = true;
945 enable_user_cert_ = HaveUserCerts();
946 enable_otp_ = true;
950 void VPNConfigView::UpdateControls() {
951 UpdateControlsToEnable();
953 if (psk_passphrase_label_)
954 psk_passphrase_label_->SetEnabled(enable_psk_passphrase_);
955 if (psk_passphrase_textfield_)
956 psk_passphrase_textfield_->SetEnabled(enable_psk_passphrase_ &&
957 psk_passphrase_ui_data_.IsEditable());
959 if (user_cert_label_)
960 user_cert_label_->SetEnabled(enable_user_cert_);
961 if (user_cert_combobox_)
962 user_cert_combobox_->SetEnabled(enable_user_cert_ &&
963 user_cert_ui_data_.IsEditable());
965 if (server_ca_cert_label_)
966 server_ca_cert_label_->SetEnabled(enable_server_ca_cert_);
967 if (server_ca_cert_combobox_)
968 server_ca_cert_combobox_->SetEnabled(enable_server_ca_cert_ &&
969 ca_cert_ui_data_.IsEditable());
971 if (otp_label_)
972 otp_label_->SetEnabled(enable_otp_);
973 if (otp_textfield_)
974 otp_textfield_->SetEnabled(enable_otp_);
976 if (group_name_label_)
977 group_name_label_->SetEnabled(enable_group_name_);
978 if (group_name_textfield_)
979 group_name_textfield_->SetEnabled(enable_group_name_ &&
980 group_name_ui_data_.IsEditable());
983 void VPNConfigView::UpdateErrorLabel() {
984 // Error message.
985 base::string16 error_msg;
986 bool cert_required =
987 GetProviderTypeIndex() == PROVIDER_TYPE_INDEX_L2TP_IPSEC_USER_CERT;
988 if (cert_required && CertLibrary::Get()->CertificatesLoaded()) {
989 if (!HaveUserCerts()) {
990 error_msg = l10n_util::GetStringUTF16(
991 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_PLEASE_INSTALL_USER_CERT);
992 } else if (!IsUserCertValid()) {
993 error_msg = l10n_util::GetStringUTF16(
994 IDS_OPTIONS_SETTINGS_INTERNET_OPTIONS_REQUIRE_HARDWARE_BACKED);
997 if (error_msg.empty() && !service_path_.empty()) {
998 // TODO(kuan): differentiate between bad psk and user passphrases.
999 const NetworkState* vpn = NetworkHandler::Get()->network_state_handler()->
1000 GetNetworkState(service_path_);
1001 if (vpn && vpn->connection_state() == shill::kStateFailure)
1002 error_msg = ui::NetworkConnect::Get()->GetShillErrorString(
1003 vpn->last_error(), vpn->path());
1005 if (!error_msg.empty()) {
1006 error_label_->SetText(error_msg);
1007 error_label_->SetVisible(true);
1008 } else {
1009 error_label_->SetVisible(false);
1013 void VPNConfigView::UpdateCanLogin() {
1014 parent_->GetDialogClientView()->UpdateDialogButtons();
1017 bool VPNConfigView::HaveUserCerts() const {
1018 return CertLibrary::Get()->NumCertificates(CertLibrary::CERT_TYPE_USER) > 0;
1021 bool VPNConfigView::IsUserCertValid() const {
1022 if (!user_cert_combobox_ || !enable_user_cert_)
1023 return false;
1024 int index = user_cert_combobox_->selected_index();
1025 if (index < 0)
1026 return false;
1027 // Currently only hardware-backed user certificates are valid.
1028 if (!CertLibrary::Get()->IsCertHardwareBackedAt(CertLibrary::CERT_TYPE_USER,
1029 index)) {
1030 return false;
1032 return true;
1035 const std::string VPNConfigView::GetTextFromField(views::Textfield* textfield,
1036 bool trim_whitespace) const {
1037 if (!textfield)
1038 return std::string();
1039 std::string untrimmed = base::UTF16ToUTF8(textfield->text());
1040 if (!trim_whitespace)
1041 return untrimmed;
1042 std::string result;
1043 base::TrimWhitespaceASCII(untrimmed, base::TRIM_ALL, &result);
1044 return result;
1047 const std::string VPNConfigView::GetPassphraseFromField(
1048 PassphraseTextfield* textfield) const {
1049 if (!textfield)
1050 return std::string();
1051 return textfield->GetPassphrase();
1054 void VPNConfigView::ParseVPNUIProperty(
1055 const NetworkState* network,
1056 const std::string& dict_key,
1057 const std::string& key,
1058 NetworkPropertyUIData* property_ui_data) {
1059 ::onc::ONCSource onc_source = ::onc::ONC_SOURCE_NONE;
1060 const base::DictionaryValue* onc =
1061 onc::FindPolicyForActiveUser(network->guid(), &onc_source);
1063 VLOG_IF(1, !onc) << "No ONC found for VPN network " << network->guid();
1064 property_ui_data->ParseOncProperty(
1065 onc_source,
1066 onc,
1067 base::StringPrintf("%s.%s.%s",
1068 ::onc::network_config::kVPN,
1069 dict_key.c_str(),
1070 key.c_str()));
1073 } // namespace chromeos