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