permission_request_creator_apiary.cc revision 116680a4aac90f2aa7413d9095a592090648e557
1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// found in the LICENSE file.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/supervised_user/permission_request_creator_apiary.h"
6cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/callback.h"
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/command_line.h"
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/json/json_reader.h"
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/json/json_writer.h"
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/logging.h"
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/strings/stringprintf.h"
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/values.h"
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/browser/signin/signin_manager_factory.h"
17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "chrome/browser/sync/supervised_user_signin_manager_wrapper.h"
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "chrome/common/chrome_switches.h"
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/signin/core/browser/profile_oauth2_token_service.h"
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/signin/core/browser/signin_manager.h"
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "components/signin/core/browser/signin_manager_base.h"
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "google_apis/gaia/google_service_auth_error.h"
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/base/load_flags.h"
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/base/net_errors.h"
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/http/http_status_code.h"
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/url_request/url_request_status.h"
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)using net::URLFetcher;
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const int kNumRetries = 1;
32cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kIdKey[] = "id";
33cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kNamespace[] = "CHROME";
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)const char kState[] = "PENDING";
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)static const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s";
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)PermissionRequestCreatorApiary::PermissionRequestCreatorApiary(
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    OAuth2TokenService* oauth2_token_service,
40116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<SupervisedUserSigninManagerWrapper> signin_wrapper,
41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    net::URLRequestContextGetter* context)
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    : OAuth2TokenService::Consumer("permissions_creator"),
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      oauth2_token_service_(oauth2_token_service),
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      signin_wrapper_(signin_wrapper.Pass()),
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      context_(context),
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      access_token_expired_(false) {}
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)PermissionRequestCreatorApiary::~PermissionRequestCreatorApiary() {}
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// static
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)scoped_ptr<PermissionRequestCreator>
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)PermissionRequestCreatorApiary::CreateWithProfile(Profile* profile) {
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  ProfileOAuth2TokenService* token_service =
54cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
55cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile);
56116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  scoped_ptr<SupervisedUserSigninManagerWrapper> signin_wrapper(
57116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch      new SupervisedUserSigninManagerWrapper(profile, signin));
58cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<PermissionRequestCreator> creator(
59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new PermissionRequestCreatorApiary(
60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)          token_service, signin_wrapper.Pass(), profile->GetRequestContext()));
61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return creator.Pass();
62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
64cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PermissionRequestCreatorApiary::CreatePermissionRequest(
65cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& url_requested,
66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::Closure& callback) {
67cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  url_requested_ = url_requested;
68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  callback_ = callback;
69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  StartFetching();
70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PermissionRequestCreatorApiary::StartFetching() {
73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  OAuth2TokenService::ScopeSet scopes;
74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scopes.insert(signin_wrapper_->GetSyncScopeToUse());
75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  access_token_request_ = oauth2_token_service_->StartRequest(
76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      signin_wrapper_->GetAccountIdToUse(), scopes, this);
77cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
78cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
79cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PermissionRequestCreatorApiary::OnGetTokenSuccess(
80cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const OAuth2TokenService::Request* request,
81cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const std::string& access_token,
82cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const base::Time& expiration_time) {
83cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK_EQ(access_token_request_.get(), request);
84cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  access_token_ = access_token;
85cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  GURL url(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      switches::kPermissionRequestApiUrl));
87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const int id = 0;
88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  url_fetcher_.reset(URLFetcher::Create(id, url, URLFetcher::POST, this));
90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  url_fetcher_->SetRequestContext(context_);
92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                             net::LOAD_DO_NOT_SAVE_COOKIES);
94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(kNumRetries);
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  url_fetcher_->AddExtraRequestHeader(
96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      base::StringPrintf(kAuthorizationHeaderFormat, access_token.c_str()));
97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::DictionaryValue dict;
99cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  dict.SetStringWithoutPathExpansion("namespace", kNamespace);
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  dict.SetStringWithoutPathExpansion("objectRef", url_requested_);
101cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  dict.SetStringWithoutPathExpansion("state", kState);
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string body;
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::JSONWriter::Write(&dict, &body);
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  url_fetcher_->SetUploadData("application/json", body);
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  url_fetcher_->Start();
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PermissionRequestCreatorApiary::OnGetTokenFailure(
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const OAuth2TokenService::Request* request,
111cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const GoogleServiceAuthError& error) {
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DCHECK_EQ(access_token_request_.get(), request);
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  callback_.Run();
114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  callback_.Reset();
115cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
116cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PermissionRequestCreatorApiary::OnURLFetchComplete(
118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const URLFetcher* source) {
119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  const net::URLRequestStatus& status = source->GetStatus();
120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!status.is_success()) {
121cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DispatchNetworkError(status.error());
122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
123cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
124cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
125cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  int response_code = source->GetResponseCode();
126cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (response_code == net::HTTP_UNAUTHORIZED && !access_token_expired_) {
127cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    access_token_expired_ = true;
128cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    OAuth2TokenService::ScopeSet scopes;
129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    scopes.insert(signin_wrapper_->GetSyncScopeToUse());
130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    oauth2_token_service_->InvalidateToken(
131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        signin_wrapper_->GetAccountIdToUse(), scopes, access_token_);
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    StartFetching();
133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
136cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (response_code != net::HTTP_OK) {
137cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DLOG(WARNING) << "HTTP error " << response_code;
138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DispatchGoogleServiceAuthError(
139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED));
140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string response_body;
144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  source->GetResponseAsString(&response_body);
145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<base::Value> value(base::JSONReader::Read(response_body));
146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  base::DictionaryValue* dict = NULL;
147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!value || !value->GetAsDictionary(&dict)) {
148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DispatchNetworkError(net::ERR_INVALID_RESPONSE);
149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  std::string id;
152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  if (!dict->GetString(kIdKey, &id)) {
153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    DispatchNetworkError(net::ERR_INVALID_RESPONSE);
154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return;
155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  callback_.Run();
157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  callback_.Reset();
158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PermissionRequestCreatorApiary::DispatchNetworkError(int error_code) {
161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  DispatchGoogleServiceAuthError(
162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      GoogleServiceAuthError::FromConnectionError(error_code));
163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void PermissionRequestCreatorApiary::DispatchGoogleServiceAuthError(
166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    const GoogleServiceAuthError& error) {
167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  callback_.Run();
168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  callback_.Reset();
169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
170