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.
5 #include "chrome/browser/supervised_user/permission_request_creator_apiary.h"
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"
29 using net::URLFetcher
;
31 const int kNumRetries
= 1;
32 const char kNamespace
[] = "PERMISSION_CHROME_URL";
33 const char kState
[] = "PENDING";
35 const char kPermissionRequestKey
[] = "permissionRequest";
36 const char kIdKey
[] = "id";
38 static const char kAuthorizationHeaderFormat
[] = "Authorization: Bearer %s";
40 struct PermissionRequestCreatorApiary::Request
{
41 Request(const GURL
& url_requested
,
42 const SuccessCallback
& callback
,
47 SuccessCallback callback
;
48 scoped_ptr
<OAuth2TokenService::Request
> access_token_request
;
49 std::string access_token
;
50 bool access_token_expired
;
52 scoped_ptr
<net::URLFetcher
> url_fetcher
;
55 PermissionRequestCreatorApiary::Request::Request(
56 const GURL
& url_requested
,
57 const SuccessCallback
& callback
,
59 : url_requested(url_requested
),
61 access_token_expired(false),
62 url_fetcher_id(url_fetcher_id
) {
65 PermissionRequestCreatorApiary::Request::~Request() {}
67 PermissionRequestCreatorApiary::PermissionRequestCreatorApiary(
68 OAuth2TokenService
* oauth2_token_service
,
69 scoped_ptr
<SupervisedUserSigninManagerWrapper
> signin_wrapper
,
70 net::URLRequestContextGetter
* context
,
71 const GURL
& apiary_url
)
72 : OAuth2TokenService::Consumer("permissions_creator"),
73 oauth2_token_service_(oauth2_token_service
),
74 signin_wrapper_(signin_wrapper
.Pass()),
76 apiary_url_(apiary_url
),
78 DCHECK(apiary_url_
.is_valid());
81 PermissionRequestCreatorApiary::~PermissionRequestCreatorApiary() {}
84 scoped_ptr
<PermissionRequestCreator
>
85 PermissionRequestCreatorApiary::CreateWithProfile(Profile
* profile
,
86 const GURL
& apiary_url
) {
87 ProfileOAuth2TokenService
* token_service
=
88 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
);
89 SigninManagerBase
* signin
= SigninManagerFactory::GetForProfile(profile
);
90 scoped_ptr
<SupervisedUserSigninManagerWrapper
> signin_wrapper(
91 new SupervisedUserSigninManagerWrapper(profile
, signin
));
92 return make_scoped_ptr(new PermissionRequestCreatorApiary(
93 token_service
, signin_wrapper
.Pass(), profile
->GetRequestContext(),
97 bool PermissionRequestCreatorApiary::IsEnabled() const {
101 void PermissionRequestCreatorApiary::CreatePermissionRequest(
102 const GURL
& url_requested
,
103 const SuccessCallback
& callback
) {
104 requests_
.push_back(new Request(url_requested
, callback
, url_fetcher_id_
));
105 StartFetching(requests_
.back());
108 std::string
PermissionRequestCreatorApiary::GetApiScopeToUse() const {
109 if (CommandLine::ForCurrentProcess()->HasSwitch(
110 switches::kPermissionRequestApiScope
)) {
111 return CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
112 switches::kPermissionRequestApiScope
);
114 return signin_wrapper_
->GetSyncScopeToUse();
118 void PermissionRequestCreatorApiary::StartFetching(Request
* request
) {
119 OAuth2TokenService::ScopeSet scopes
;
120 scopes
.insert(GetApiScopeToUse());
121 request
->access_token_request
= oauth2_token_service_
->StartRequest(
122 signin_wrapper_
->GetAccountIdToUse(), scopes
, this);
125 void PermissionRequestCreatorApiary::OnGetTokenSuccess(
126 const OAuth2TokenService::Request
* request
,
127 const std::string
& access_token
,
128 const base::Time
& expiration_time
) {
129 RequestIterator it
= requests_
.begin();
130 while (it
!= requests_
.end()) {
131 if (request
== (*it
)->access_token_request
.get())
135 DCHECK(it
!= requests_
.end());
136 (*it
)->access_token
= access_token
;
138 (*it
)->url_fetcher
.reset(URLFetcher::Create((*it
)->url_fetcher_id
,
143 (*it
)->url_fetcher
->SetRequestContext(context_
);
144 (*it
)->url_fetcher
->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES
|
145 net::LOAD_DO_NOT_SAVE_COOKIES
);
146 (*it
)->url_fetcher
->SetAutomaticallyRetryOnNetworkChanges(kNumRetries
);
147 (*it
)->url_fetcher
->AddExtraRequestHeader(
148 base::StringPrintf(kAuthorizationHeaderFormat
, access_token
.c_str()));
150 base::DictionaryValue dict
;
151 dict
.SetStringWithoutPathExpansion("namespace", kNamespace
);
152 dict
.SetStringWithoutPathExpansion("objectRef", (*it
)->url_requested
.spec());
153 dict
.SetStringWithoutPathExpansion("state", kState
);
155 base::JSONWriter::Write(&dict
, &body
);
156 (*it
)->url_fetcher
->SetUploadData("application/json", body
);
158 (*it
)->url_fetcher
->Start();
161 void PermissionRequestCreatorApiary::OnGetTokenFailure(
162 const OAuth2TokenService::Request
* request
,
163 const GoogleServiceAuthError
& error
) {
164 RequestIterator it
= requests_
.begin();
165 while (it
!= requests_
.end()) {
166 if (request
== (*it
)->access_token_request
.get())
170 DCHECK(it
!= requests_
.end());
171 (*it
)->callback
.Run(false);
175 void PermissionRequestCreatorApiary::OnURLFetchComplete(
176 const URLFetcher
* source
) {
177 RequestIterator it
= requests_
.begin();
178 while (it
!= requests_
.end()) {
179 if (source
== (*it
)->url_fetcher
.get())
183 DCHECK(it
!= requests_
.end());
185 const net::URLRequestStatus
& status
= source
->GetStatus();
186 if (!status
.is_success()) {
187 DispatchNetworkError(it
, status
.error());
191 int response_code
= source
->GetResponseCode();
192 if (response_code
== net::HTTP_UNAUTHORIZED
&& !(*it
)->access_token_expired
) {
193 (*it
)->access_token_expired
= true;
194 OAuth2TokenService::ScopeSet scopes
;
195 scopes
.insert(GetApiScopeToUse());
196 oauth2_token_service_
->InvalidateToken(
197 signin_wrapper_
->GetAccountIdToUse(), scopes
, (*it
)->access_token
);
202 if (response_code
!= net::HTTP_OK
) {
203 DLOG(WARNING
) << "HTTP error " << response_code
;
204 DispatchGoogleServiceAuthError(
205 it
, GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED
));
209 std::string response_body
;
210 source
->GetResponseAsString(&response_body
);
211 scoped_ptr
<base::Value
> value(base::JSONReader::Read(response_body
));
212 base::DictionaryValue
* dict
= NULL
;
213 if (!value
|| !value
->GetAsDictionary(&dict
)) {
214 DispatchNetworkError(it
, net::ERR_INVALID_RESPONSE
);
217 base::DictionaryValue
* permission_dict
= NULL
;
218 if (!dict
->GetDictionary(kPermissionRequestKey
, &permission_dict
)) {
219 DispatchNetworkError(it
, net::ERR_INVALID_RESPONSE
);
223 if (!permission_dict
->GetString(kIdKey
, &id
)) {
224 DispatchNetworkError(it
, net::ERR_INVALID_RESPONSE
);
227 (*it
)->callback
.Run(true);
231 void PermissionRequestCreatorApiary::DispatchNetworkError(RequestIterator it
,
233 DispatchGoogleServiceAuthError(
234 it
, GoogleServiceAuthError::FromConnectionError(error_code
));
237 void PermissionRequestCreatorApiary::DispatchGoogleServiceAuthError(
239 const GoogleServiceAuthError
& error
) {
240 (*it
)->callback
.Run(false);