diff options
Diffstat (limited to 'chrome/browser/policy/device_management_backend_impl.cc')
-rw-r--r-- | chrome/browser/policy/device_management_backend_impl.cc | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/chrome/browser/policy/device_management_backend_impl.cc b/chrome/browser/policy/device_management_backend_impl.cc new file mode 100644 index 0000000..c0e9b07 --- /dev/null +++ b/chrome/browser/policy/device_management_backend_impl.cc @@ -0,0 +1,415 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/policy/device_management_backend_impl.h" + +#include <utility> +#include <vector> + +#include "base/stl_util-inl.h" +#include "base/stringprintf.h" +#include "chrome/browser/browser_thread.h" +#include "chrome/common/net/url_request_context_getter.h" +#include "net/base/cookie_monster.h" +#include "net/base/escape.h" +#include "net/base/host_resolver.h" +#include "net/base/ssl_config_service_defaults.h" +#include "net/http/http_auth_handler_factory.h" +#include "net/http/http_network_layer.h" +#include "net/proxy/proxy_service.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_status.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/io_thread.h" +#include "chrome/browser/net/chrome_net_log.h" +#include "chrome/common/chrome_version_info.h" + +namespace policy { + +namespace { + +// Name constants for URL query parameters. +const char kServiceParamRequest[] = "request"; +const char kServiceParamDeviceType[] = "devicetype"; +const char kServiceParamDeviceID[] = "deviceid"; +const char kServiceParamAgent[] = "agent"; + +// String constants for the device type and agent we report to the service. +const char kServiceValueDeviceType[] = "Chrome"; +const char kServiceValueAgent[] = + "%s enterprise management client version %s (%s)"; + +const char kServiceTokenAuthHeader[] = "Authorization: GoogleLogin auth="; +const char kDMTokenAuthHeader[] = "Authorization: GoogleDMToken token="; + +} // namespace + +// Custom request context implementation that allows to override the user agent, +// amongst others. Using the default request context is not an option since this +// service may be constructed before the default request context is created +// (i.e. before the profile has been loaded). +class DeviceManagementBackendRequestContext : public URLRequestContext { + public: + explicit DeviceManagementBackendRequestContext(IOThread::Globals* io_globals); + virtual ~DeviceManagementBackendRequestContext(); + + private: + virtual const std::string& GetUserAgent(const GURL& url) const; + + std::string user_agent_; +}; + +DeviceManagementBackendRequestContext::DeviceManagementBackendRequestContext( + IOThread::Globals* io_globals) { + net_log_ = io_globals->net_log.get(); + host_resolver_ = io_globals->host_resolver.get(); + proxy_service_ = net::ProxyService::CreateDirect(); + ssl_config_service_ = net::SSLConfigService::CreateSystemSSLConfigService(); + http_auth_handler_factory_ = + net::HttpAuthHandlerFactory::CreateDefault(host_resolver_); + http_transaction_factory_ = + net::HttpNetworkLayer::CreateFactory(host_resolver_, + io_globals->dnsrr_resolver.get(), + NULL /* ssl_host_info_factory */, + proxy_service_, + ssl_config_service_, + http_auth_handler_factory_, + NULL /* network_delegate */, + net_log_); + cookie_store_ = new net::CookieMonster(NULL, NULL); + user_agent_ = DeviceManagementBackendImpl::GetAgentString(); + accept_language_ = "*"; + accept_charset_ = "*"; +} + +DeviceManagementBackendRequestContext + ::~DeviceManagementBackendRequestContext() { + delete http_transaction_factory_; + delete http_auth_handler_factory_; +} + +const std::string& +DeviceManagementBackendRequestContext::GetUserAgent(const GURL& url) const { + return user_agent_; +} + +// Request context holder. +class DeviceManagementBackendRequestContextGetter + : public URLRequestContextGetter { + public: + DeviceManagementBackendRequestContextGetter() + : io_thread_(g_browser_process->io_thread()) {} + + // URLRequestContextGetter overrides. + virtual URLRequestContext* GetURLRequestContext(); + virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() const; + + private: + scoped_refptr<URLRequestContext> context_; + IOThread* io_thread_; +}; + + +URLRequestContext* +DeviceManagementBackendRequestContextGetter::GetURLRequestContext() { + if (!context_) + context_ = new DeviceManagementBackendRequestContext(io_thread_->globals()); + + return context_.get(); +} + +scoped_refptr<base::MessageLoopProxy> +DeviceManagementBackendRequestContextGetter::GetIOMessageLoopProxy() const { + return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO); +} + +// Helper class for URL query parameter encoding/decoding. +class URLQueryParameters { + public: + URLQueryParameters() {} + + // Add a query parameter. + void Put(const std::string& name, const std::string& value); + + // Produce the query string, taking care of properly encoding and assembling + // the names and values. + std::string Encode(); + + private: + typedef std::vector<std::pair<std::string, std::string> > ParameterMap; + ParameterMap params_; + + DISALLOW_COPY_AND_ASSIGN(URLQueryParameters); +}; + +void URLQueryParameters::Put(const std::string& name, + const std::string& value) { + params_.push_back(std::make_pair(name, value)); +} + +std::string URLQueryParameters::Encode() { + std::string result; + for (ParameterMap::const_iterator entry(params_.begin()); + entry != params_.end(); + ++entry) { + if (entry != params_.begin()) + result += '&'; + result += EscapeUrlEncodedData(entry->first); + result += '='; + result += EscapeUrlEncodedData(entry->second); + } + return result; +} + +// Wraps common response parsing and handling functionality. +class ResponseHandler { + public: + ResponseHandler() {} + virtual ~ResponseHandler() {} + + // Handles the URL request response. + void HandleResponse(const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data); + + // Forwards the given error to the delegate. + virtual void OnError(DeviceManagementBackend::ErrorCode error) = 0; + + private: + // Implemented by subclasses to handle the decoded response. + virtual void ProcessResponse( + const em::DeviceManagementResponse& response) = 0; +}; + +void ResponseHandler::HandleResponse(const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) { + if (status.status() != URLRequestStatus::SUCCESS) { + OnError(DeviceManagementBackend::kErrorRequestFailed); + return; + } + + if (response_code != 200) { + OnError(DeviceManagementBackend::kErrorHttpStatus); + return; + } + + em::DeviceManagementResponse response; + if (!response.ParseFromString(data)) { + OnError(DeviceManagementBackend::kErrorResponseDecoding); + return; + } + + // Check service error code. + switch (response.error()) { + case em::DeviceManagementResponse::SUCCESS: + break; + case em::DeviceManagementResponse::DEVICE_MANAGEMENT_NOT_SUPPORTED: + OnError(DeviceManagementBackend::kErrorServiceManagementNotSupported); + return; + case em::DeviceManagementResponse::DEVICE_NOT_FOUND: + OnError(DeviceManagementBackend::kErrorServiceDeviceNotFound); + return; + case em::DeviceManagementResponse::DEVICE_MANAGEMENT_TOKEN_INVALID: + OnError(DeviceManagementBackend::kErrorServiceManagementTokenInvalid); + return; + case em::DeviceManagementResponse::ACTIVATION_PENDING: + OnError(DeviceManagementBackend::kErrorServiceActivationPending); + return; + default: + // This should be caught by the protobuf decoder. + NOTREACHED(); + OnError(DeviceManagementBackend::kErrorResponseDecoding); + return; + } + + ProcessResponse(response); +} + +// Handles device registration responses. +class RegisterResponseHandler : public ResponseHandler { + public: + RegisterResponseHandler( + DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate) + : delegate_(delegate) {} + + private: + // ResponseHandler overrides. + virtual void OnError(DeviceManagementBackend::ErrorCode error) { + delegate_->OnError(error); + } + virtual void ProcessResponse(const em::DeviceManagementResponse& response) { + delegate_->HandleRegisterResponse(response.register_response()); + } + + DeviceManagementBackend::DeviceRegisterResponseDelegate* delegate_; +}; + +// Handles device unregister responses. +class UnregisterResponseHandler : public ResponseHandler { + public: + UnregisterResponseHandler( + DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate) + : delegate_(delegate) {} + + private: + // ResponseHandler overrides. + virtual void OnError(DeviceManagementBackend::ErrorCode error) { + delegate_->OnError(error); + } + virtual void ProcessResponse(const em::DeviceManagementResponse& response) { + delegate_->HandleUnregisterResponse(response.unregister_response()); + } + + DeviceManagementBackend::DeviceUnregisterResponseDelegate* delegate_; +}; + +// Handles device policy responses. +class PolicyResponseHandler : public ResponseHandler { + public: + PolicyResponseHandler( + DeviceManagementBackend::DevicePolicyResponseDelegate* delegate) + : delegate_(delegate) {} + + private: + // ResponseHandler overrides. + virtual void OnError(DeviceManagementBackend::ErrorCode error) { + delegate_->OnError(error); + } + virtual void ProcessResponse(const em::DeviceManagementResponse& response) { + delegate_->HandlePolicyResponse(response.policy_response()); + } + + DeviceManagementBackend::DevicePolicyResponseDelegate* delegate_; +}; + +DeviceManagementBackendImpl::DeviceManagementBackendImpl( + const std::string& server_url) + : server_url_(server_url), + request_context_getter_( + new DeviceManagementBackendRequestContextGetter()) { +} + +DeviceManagementBackendImpl::~DeviceManagementBackendImpl() { + // Cancel all pending requests. + STLDeleteContainerPairPointers(response_handlers_.begin(), + response_handlers_.end()); +} + +void DeviceManagementBackendImpl::ProcessRegisterRequest( + const std::string& auth_token, + const std::string& device_id, + const em::DeviceRegisterRequest& request, + DeviceRegisterResponseDelegate* delegate) { + em::DeviceManagementRequest request_wrapper; + request_wrapper.mutable_register_request()->CopyFrom(request); + + URLQueryParameters params; + PutCommonQueryParameters(¶ms); + params.Put(kServiceParamRequest, "register"); + params.Put(kServiceParamDeviceID, device_id); + + CreateFetcher(request_wrapper, + new RegisterResponseHandler(delegate), + params.Encode(), + kServiceTokenAuthHeader + auth_token); +} + +void DeviceManagementBackendImpl::ProcessUnregisterRequest( + const std::string& device_management_token, + const em::DeviceUnregisterRequest& request, + DeviceUnregisterResponseDelegate* delegate) { + em::DeviceManagementRequest request_wrapper; + request_wrapper.mutable_unregister_request()->CopyFrom(request); + + URLQueryParameters params; + PutCommonQueryParameters(¶ms); + params.Put(kServiceParamRequest, "unregister"); + + CreateFetcher(request_wrapper, + new UnregisterResponseHandler(delegate), + params.Encode(), + kDMTokenAuthHeader + device_management_token); +} + +void DeviceManagementBackendImpl::ProcessPolicyRequest( + const std::string& device_management_token, + const em::DevicePolicyRequest& request, + DevicePolicyResponseDelegate* delegate) { + em::DeviceManagementRequest request_wrapper; + request_wrapper.mutable_policy_request()->CopyFrom(request); + + URLQueryParameters params; + PutCommonQueryParameters(¶ms); + params.Put(kServiceParamRequest, "policy"); + + CreateFetcher(request_wrapper, + new PolicyResponseHandler(delegate), + params.Encode(), + kDMTokenAuthHeader + device_management_token); +} + +// static +std::string DeviceManagementBackendImpl::GetAgentString() { + chrome::VersionInfo version_info; + return base::StringPrintf(kServiceValueAgent, + version_info.Name().c_str(), + version_info.Version().c_str(), + version_info.LastChange().c_str()); +} + +void DeviceManagementBackendImpl::OnURLFetchComplete( + const URLFetcher* source, + const GURL& url, + const URLRequestStatus& status, + int response_code, + const ResponseCookies& cookies, + const std::string& data) { + ResponseHandlerMap::iterator entry(response_handlers_.find(source)); + if (entry != response_handlers_.end()) { + ResponseHandler* handler = entry->second; + handler->HandleResponse(status, response_code, cookies, data); + response_handlers_.erase(entry); + delete handler; + } else { + NOTREACHED() << "Callback from foreign URL fetcher"; + } + delete source; +} + +void DeviceManagementBackendImpl::CreateFetcher( + const em::DeviceManagementRequest& request, + ResponseHandler* handler, + const std::string& query_params, + const std::string& extra_headers) { + scoped_ptr<ResponseHandler> handler_ptr(handler); + + // Construct the payload. + std::string payload; + if (!request.SerializeToString(&payload)) { + handler->OnError(DeviceManagementBackend::kErrorRequestInvalid); + return; + } + + // Instantiate the fetcher. + GURL url(server_url_ + '?' + query_params); + URLFetcher* fetcher = URLFetcher::Create(0, url, URLFetcher::POST, this); + fetcher->set_request_context(request_context_getter_.get()); + fetcher->set_upload_data("application/octet-stream", payload); + fetcher->set_extra_request_headers(extra_headers); + response_handlers_[fetcher] = handler_ptr.release(); + + // Start the request. The fetcher will call OnURLFetchComplete when done. + fetcher->Start(); +} + +void DeviceManagementBackendImpl::PutCommonQueryParameters( + URLQueryParameters* params) { + params->Put(kServiceParamDeviceType, kServiceValueDeviceType); + params->Put(kServiceParamAgent, GetAgentString()); +} + +} // namespace policy |