Chromium Code Reviews| Index: chromeos/network/network_connection_handler.cc |
| diff --git a/chromeos/network/network_connection_handler.cc b/chromeos/network/network_connection_handler.cc |
| index 97cc9f8d9e25f52aa931ecb1ce3d67fa4c5a21d7..93191a2be8a4e6dd050edf80cbb3e2d04249c4d7 100644 |
| --- a/chromeos/network/network_connection_handler.cc |
| +++ b/chromeos/network/network_connection_handler.cc |
| @@ -100,13 +100,6 @@ bool VPNIsConfigured(const std::string& service_path, |
| NET_LOG_EVENT("OpenVPN: No passphrase", service_path); |
| return false; |
| } |
| - std::string client_cert_id; |
| - properties->GetStringWithoutPathExpansion( |
| - flimflam::kOpenVPNClientCertIdProperty, &client_cert_id); |
| - if (client_cert_id.empty()) { |
| - NET_LOG_EVENT("OpenVPN: No cert id", service_path); |
| - return false; |
| - } |
| NET_LOG_EVENT("OpenVPN Is Configured", service_path); |
| } else { |
| bool passphrase_required = false; |
| @@ -122,27 +115,6 @@ bool VPNIsConfigured(const std::string& service_path, |
| return true; |
| } |
| -bool CertificateIsConfigured(NetworkUIData* ui_data) { |
| - if (ui_data->certificate_type() != CLIENT_CERT_TYPE_PATTERN) |
| - return true; // No certificate or a reference. |
| - if (ui_data->onc_source() == onc::ONC_SOURCE_DEVICE_POLICY) { |
| - // We skip checking certificate patterns for device policy ONC so that an |
| - // unmanaged user can't get to the place where a cert is presented for them |
| - // involuntarily. |
| - return true; |
| - } |
| - if (ui_data->certificate_pattern().Empty()) |
| - return false; |
| - |
| - // Find the matching certificate. |
| - scoped_refptr<net::X509Certificate> matching_cert = |
| - certificate_pattern::GetCertificateMatch( |
| - ui_data->certificate_pattern()); |
| - if (!matching_cert.get()) |
| - return false; |
| - return true; |
| -} |
| - |
| } // namespace |
| const char NetworkConnectionHandler::kErrorNotFound[] = "not-found"; |
| @@ -162,9 +134,11 @@ const char NetworkConnectionHandler::kErrorConnectFailed[] = "connect-failed"; |
| const char NetworkConnectionHandler::kErrorUnknown[] = "unknown-error"; |
| struct NetworkConnectionHandler::ConnectRequest { |
| - ConnectRequest(const base::Closure& success, |
| + ConnectRequest(const std::string& service_path, |
| + const base::Closure& success, |
| const network_handler::ErrorCallback& error) |
| - : connect_state(CONNECT_REQUESTED), |
| + : service_path(service_path), |
| + connect_state(CONNECT_REQUESTED), |
| success_callback(success), |
| error_callback(error) { |
| } |
| @@ -173,29 +147,43 @@ struct NetworkConnectionHandler::ConnectRequest { |
| CONNECT_STARTED = 1, |
| CONNECT_CONNECTING = 2 |
| }; |
| + std::string service_path; |
| ConnectState connect_state; |
| base::Closure success_callback; |
| network_handler::ErrorCallback error_callback; |
| }; |
| NetworkConnectionHandler::NetworkConnectionHandler() |
| - : network_state_handler_(NULL), |
| - network_configuration_handler_(NULL) { |
| - const char* new_handler_enabled = |
| - CommandLine::ForCurrentProcess()->HasSwitch( |
| - chromeos::switches::kUseNewNetworkConnectionHandler) ? |
| - "enabled" : "disabled"; |
| - NET_LOG_EVENT("NewNetworkConnectionHandler", new_handler_enabled); |
| + : cert_loader_(NULL), |
| + network_state_handler_(NULL), |
| + network_configuration_handler_(NULL), |
| + logged_in_(false), |
| + certificates_loaded_(false) { |
| } |
| NetworkConnectionHandler::~NetworkConnectionHandler() { |
| if (network_state_handler_) |
| network_state_handler_->RemoveObserver(this); |
| + if (cert_loader_) |
| + cert_loader_->RemoveObserver(this); |
| + if (LoginState::IsInitialized()) |
| + LoginState::Get()->RemoveObserver(this); |
| } |
| void NetworkConnectionHandler::Init( |
| + CertLoader* cert_loader, |
| NetworkStateHandler* network_state_handler, |
| NetworkConfigurationHandler* network_configuration_handler) { |
| + LoginState::Get()->AddObserver(this); |
| + logged_in_ = |
| + LoginState::Get()->GetLoggedInState() == LoginState::LOGGED_IN_ACTIVE; |
| + if (cert_loader) { |
| + cert_loader_ = cert_loader; |
| + cert_loader_->AddObserver(this); |
| + certificates_loaded_ = cert_loader->certificates_loaded(); |
| + } else { |
| + certificates_loaded_ = true; |
| + } |
| if (network_state_handler) { |
| network_state_handler_ = network_state_handler; |
| network_state_handler_->AddObserver(this); |
| @@ -203,12 +191,44 @@ void NetworkConnectionHandler::Init( |
| network_configuration_handler_ = network_configuration_handler; |
| } |
| +void NetworkConnectionHandler::LoggedInStateChanged( |
| + LoginState::LoggedInState state) { |
| + NET_LOG_EVENT("NewNetworkConnectionHandler", |
| + CommandLine::ForCurrentProcess()->HasSwitch( |
| + chromeos::switches::kUseNewNetworkConnectionHandler) ? |
| + "enabled" : "disabled"); |
| + if (state == LoginState::LOGGED_IN_ACTIVE) { |
| + logged_in_ = true; |
| + NET_LOG_EVENT("Logged In", ""); |
| + } |
| +} |
| + |
| +void NetworkConnectionHandler::OnCertificatesLoaded( |
| + const net::CertificateList& cert_list, |
| + bool initial_load) { |
| + certificates_loaded_ = true; |
| + NET_LOG_EVENT("Certificates Loaded", ""); |
| + if (queued_connect_) { |
| + NET_LOG_EVENT("Connecting to Queued Network", |
| + queued_connect_->service_path); |
| + ConnectToNetwork(queued_connect_->service_path, |
| + queued_connect_->success_callback, |
| + queued_connect_->error_callback, |
| + true /* ignore_error_state */); |
| + } else if (initial_load) { |
| + // Once certificates have loaded, connect to the "best" available network. |
| + NetworkHandler::Get()->network_state_handler()->ConnectToBestWifiNetwork(); |
| + } |
| +} |
| + |
| void NetworkConnectionHandler::ConnectToNetwork( |
| const std::string& service_path, |
| const base::Closure& success_callback, |
| const network_handler::ErrorCallback& error_callback, |
| bool ignore_error_state) { |
| NET_LOG_USER("ConnectToNetwork", service_path); |
| + // Clear any existing queued connect request. |
| + queued_connect_.reset(); |
| const NetworkState* network = |
| network_state_handler_->GetNetworkState(service_path); |
| if (!network) { |
| @@ -257,9 +277,11 @@ void NetworkConnectionHandler::ConnectToNetwork( |
| // All synchronous checks passed, add |service_path| to connecting list. |
| pending_requests_.insert(std::make_pair( |
| - service_path, ConnectRequest(success_callback, error_callback))); |
| + service_path, |
| + ConnectRequest(service_path, success_callback, error_callback))); |
| - if (!NetworkConnectable(network) && NetworkMayNeedCredentials(network)) { |
| + if (!NetworkConnectable(network) && |
| + NetworkMayNeedCredentials(network)) { |
| // Request additional properties to check. |
| network_configuration_handler_->GetProperties( |
| network->path(), |
| @@ -320,43 +342,101 @@ void NetworkConnectionHandler::VerifyConfiguredAndConnect( |
| const std::string& service_path, |
| const base::DictionaryValue& properties) { |
| NET_LOG_EVENT("VerifyConfiguredAndConnect", service_path); |
| - ConnectRequest* request = pending_request(service_path); |
| - DCHECK(request); |
| - network_handler::ErrorCallback error_callback = request->error_callback; |
| const NetworkState* network = |
| network_state_handler_->GetNetworkState(service_path); |
| if (!network) { |
| - pending_requests_.erase(service_path); |
| - InvokeErrorCallback(service_path, error_callback, kErrorNotFound); |
| + ErrorCallbackForPendingRequest(service_path, kErrorNotFound); |
| return; |
| } |
| // VPN requires a host and username to be set. |
| if (network->type() == flimflam::kTypeVPN && |
| !VPNIsConfigured(service_path, properties)) { |
| - pending_requests_.erase(service_path); |
| - InvokeErrorCallback(service_path, error_callback, |
| - kErrorConfigurationRequired); |
| + ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired); |
| return; |
| } |
| // Check certificate properties in kUIDataProperty. |
| scoped_ptr<NetworkUIData> ui_data = |
| ManagedNetworkConfigurationHandler::GetUIData(properties); |
| - if (ui_data && !CertificateIsConfigured(ui_data.get())) { |
| - pending_requests_.erase(service_path); |
| - InvokeErrorCallback(service_path, error_callback, |
| - kErrorCertificateRequired); |
| - return; |
| + if (ui_data && ui_data->certificate_type() == CLIENT_CERT_TYPE_PATTERN) { |
| + // User must be logged in to connect to a network requiring a certificate. |
| + if (!logged_in_ || !cert_loader_) { |
| + ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired); |
| + return; |
| + } |
| + // If certificates have not been loaded yet, queue the connect request. |
| + if (!certificates_loaded_) { |
| + ConnectRequest* request = pending_request(service_path); |
| + DCHECK(request); |
| + NET_LOG_EVENT("Connect Request Queued", service_path); |
| + queued_connect_.reset(new ConnectRequest( |
| + service_path, request->success_callback, request->error_callback)); |
| + pending_requests_.erase(service_path); |
| + return; |
| + } |
| + |
| + // Ensure the certificate is available. |
| + std::string pkcs11_id; |
| + if (!CertificateIsConfigured(ui_data.get(), &pkcs11_id)) { |
| + ErrorCallbackForPendingRequest(service_path, kErrorCertificateRequired); |
| + return; |
| + } |
| + |
| + // The network may not be 'Connectable' because the certificate data is |
| + // not set up, so configure tpm slot/pin and pkcs11_id before connecting. |
| + // TODO(stevenjb): Remove this code once NetworkConfigurationHandler |
|
Greg Spencer (Chromium)
2013/06/06 01:11:46
So, why can't you just move it there now? What's
|
| + // handles this. |
| + NET_LOG_EVENT("Configuring Network", service_path); |
| + const std::string& tpm_slot = cert_loader_->tpm_token_slot(); |
| + const std::string& tpm_pin = cert_loader_->tpm_user_pin(); |
| + base::DictionaryValue config_properties; |
| + network->GetConfigProperties(&config_properties); |
| + |
| + if (network->type() == flimflam::kTypeVPN) { |
| + std::string provider_type; |
| + properties.GetString(flimflam::kTypeProperty, &provider_type); |
| + if (provider_type == flimflam::kProviderOpenVpn) { |
| + config_properties.SetStringWithoutPathExpansion( |
| + flimflam::kOpenVPNClientCertSlotProperty, tpm_slot); |
| + config_properties.SetStringWithoutPathExpansion( |
| + flimflam::kOpenVPNPinProperty, tpm_pin); |
| + config_properties.SetStringWithoutPathExpansion( |
| + flimflam::kOpenVPNClientCertIdProperty, pkcs11_id); |
| + } else { |
| + config_properties.SetStringWithoutPathExpansion( |
| + flimflam::kL2tpIpsecClientCertSlotProperty, tpm_slot); |
| + config_properties.SetStringWithoutPathExpansion( |
| + flimflam::kL2tpIpsecPinProperty, tpm_pin); |
| + config_properties.SetStringWithoutPathExpansion( |
| + flimflam::kL2tpIpsecClientCertIdProperty, pkcs11_id); |
| + } |
| + } else if (network->type() == flimflam::kTypeWifi) { |
| + config_properties.SetStringWithoutPathExpansion( |
| + flimflam::kEapPinProperty, cert_loader_->tpm_user_pin()); |
| + config_properties.SetStringWithoutPathExpansion( |
| + flimflam::kEapCertIdProperty, pkcs11_id); |
| + config_properties.SetStringWithoutPathExpansion( |
| + flimflam::kEapKeyIdProperty, pkcs11_id); |
| + } |
| + network_configuration_handler_->SetProperties( |
| + service_path, |
| + config_properties, |
| + base::Bind(&NetworkConnectionHandler::CallShillConnect, |
| + AsWeakPtr(), service_path), |
| + base::Bind(&NetworkConnectionHandler::HandleConfigurationFailure, |
| + AsWeakPtr(), service_path)); |
| + return; |
| } |
| - CallShillConnect(service_path); |
| + // Otherwise, we need to configure the network. |
| + ErrorCallbackForPendingRequest(service_path, kErrorConfigurationRequired); |
| } |
| void NetworkConnectionHandler::CallShillConnect( |
| const std::string& service_path) { |
| - NET_LOG_EVENT("Connect Request", service_path); |
| + NET_LOG_EVENT("Sending Connect Request to Shill", service_path); |
| DBusThreadManager::Get()->GetShillServiceClient()->Connect( |
| dbus::ObjectPath(service_path), |
| base::Bind(&NetworkConnectionHandler::HandleShillConnectSuccess, |
| @@ -382,7 +462,7 @@ void NetworkConnectionHandler::HandleShillConnectSuccess( |
| ConnectRequest* request = pending_request(service_path); |
| DCHECK(request); |
| request->connect_state = ConnectRequest::CONNECT_STARTED; |
| - NET_LOG_EVENT("Connect Request Sent", service_path); |
| + NET_LOG_EVENT("Connect Request Acknowledged", service_path); |
| // Do not call success_callback here, wait for one of the following |
| // conditions: |
| // * State transitions to a non connecting state indicating succes or failure |
| @@ -412,9 +492,7 @@ void NetworkConnectionHandler::CheckPendingRequest( |
| const NetworkState* network = |
| network_state_handler_->GetNetworkState(service_path); |
| if (!network) { |
| - network_handler::ErrorCallback error_callback = request->error_callback; |
| - pending_requests_.erase(service_path); |
| - InvokeErrorCallback(service_path, error_callback, kErrorNotFound); |
| + ErrorCallbackForPendingRequest(service_path, kErrorNotFound); |
| return; |
| } |
| if (network->IsConnectingState()) { |
| @@ -462,6 +540,37 @@ void NetworkConnectionHandler::CheckAllPendingRequests() { |
| } |
| } |
| +bool NetworkConnectionHandler::CertificateIsConfigured(NetworkUIData* ui_data, |
| + std::string* pkcs11_id) { |
| + if (ui_data->onc_source() == onc::ONC_SOURCE_DEVICE_POLICY) { |
| + // We skip checking certificate patterns for device policy ONC so that an |
| + // unmanaged user can't get to the place where a cert is presented for them |
| + // involuntarily. |
| + return true; |
| + } |
| + if (ui_data->certificate_pattern().Empty()) |
| + return false; |
| + |
| + // Find the matching certificate. |
| + scoped_refptr<net::X509Certificate> matching_cert = |
| + certificate_pattern::GetCertificateMatch(ui_data->certificate_pattern()); |
| + if (!matching_cert.get()) |
| + return false; |
| + *pkcs11_id = cert_loader_->GetPkcs11IdForCert(*matching_cert.get()); |
| + return true; |
| +} |
| + |
| +void NetworkConnectionHandler::ErrorCallbackForPendingRequest( |
| + const std::string& service_path, |
| + const std::string& error_name) { |
| + ConnectRequest* request = pending_request(service_path); |
| + DCHECK(request); |
| + // Remove the entry before invoking the callback in case it triggers a retry. |
| + network_handler::ErrorCallback error_callback = request->error_callback; |
| + pending_requests_.erase(service_path); |
| + InvokeErrorCallback(service_path, error_callback, error_name); |
| +} |
| + |
| // Disconnect |
| void NetworkConnectionHandler::CallShillDisconnect( |