| 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..16b90af9d2ecd066f35573d7c3da2bd86850cb81 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,44 @@ 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 {
|
| + // TODO(stevenjb): Require a mock or stub cert_loader in tests.
|
| + certificates_loaded_ = true;
|
| + }
|
| if (network_state_handler) {
|
| network_state_handler_ = network_state_handler;
|
| network_state_handler_->AddObserver(this);
|
| @@ -203,12 +192,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 +278,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 +343,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
|
| + // 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 +463,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 +493,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 +541,31 @@ void NetworkConnectionHandler::CheckAllPendingRequests() {
|
| }
|
| }
|
|
|
| +bool NetworkConnectionHandler::CertificateIsConfigured(NetworkUIData* ui_data,
|
| + std::string* pkcs11_id) {
|
| + 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(
|
|
|