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/child_accounts/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/common/chrome_switches.h"
18 #include "components/signin/core/browser/profile_oauth2_token_service.h"
19 #include "components/signin/core/browser/signin_manager.h"
20 #include "components/signin/core/browser/signin_manager_base.h"
21 #include "google_apis/gaia/google_service_auth_error.h"
22 #include "net/base/load_flags.h"
23 #include "net/base/net_errors.h"
24 #include "net/http/http_status_code.h"
25 #include "net/url_request/url_fetcher.h"
26 #include "net/url_request/url_request_status.h"
29 using net::URLFetcher
;
31 const char kApiUrl
[] =
32 "https://www.googleapis.com/kidsmanagement/v1/people/me/permissionRequests";
33 const char kApiScope
[] = "https://www.googleapis.com/auth/kid.permission";
35 const int kNumRetries
= 1;
37 const char kAuthorizationHeaderFormat
[] = "Authorization: Bearer %s";
40 const char kEventTypeKey
[] = "eventType";
41 const char kObjectRefKey
[] = "objectRef";
42 const char kStateKey
[] = "state";
45 const char kEventTypeURLRequest
[] = "PERMISSION_CHROME_URL";
46 const char kEventTypeUpdateRequest
[] = "PERMISSION_CHROME_CWS_ITEM_UPDATE";
47 const char kState
[] = "PENDING";
50 const char kPermissionRequestKey
[] = "permissionRequest";
51 const char kIdKey
[] = "id";
53 struct PermissionRequestCreatorApiary::Request
{
54 Request(const std::string
& request_type
,
55 const std::string
& object_ref
,
56 const SuccessCallback
& callback
,
60 std::string request_type
;
61 std::string object_ref
;
62 SuccessCallback callback
;
63 scoped_ptr
<OAuth2TokenService::Request
> access_token_request
;
64 std::string access_token
;
65 bool access_token_expired
;
67 scoped_ptr
<URLFetcher
> url_fetcher
;
70 PermissionRequestCreatorApiary::Request::Request(
71 const std::string
& request_type
,
72 const std::string
& object_ref
,
73 const SuccessCallback
& callback
,
75 : request_type(request_type
),
76 object_ref(object_ref
),
78 access_token_expired(false),
79 url_fetcher_id(url_fetcher_id
) {
82 PermissionRequestCreatorApiary::Request::~Request() {}
84 PermissionRequestCreatorApiary::PermissionRequestCreatorApiary(
85 OAuth2TokenService
* oauth2_token_service
,
86 const std::string
& account_id
,
87 net::URLRequestContextGetter
* context
)
88 : OAuth2TokenService::Consumer("permissions_creator"),
89 oauth2_token_service_(oauth2_token_service
),
90 account_id_(account_id
),
95 PermissionRequestCreatorApiary::~PermissionRequestCreatorApiary() {}
98 scoped_ptr
<PermissionRequestCreator
>
99 PermissionRequestCreatorApiary::CreateWithProfile(Profile
* profile
) {
100 ProfileOAuth2TokenService
* token_service
=
101 ProfileOAuth2TokenServiceFactory::GetForProfile(profile
);
102 SigninManagerBase
* signin
= SigninManagerFactory::GetForProfile(profile
);
103 return make_scoped_ptr(new PermissionRequestCreatorApiary(
105 signin
->GetAuthenticatedAccountId(),
106 profile
->GetRequestContext()));
109 bool PermissionRequestCreatorApiary::IsEnabled() const {
113 void PermissionRequestCreatorApiary::CreateURLAccessRequest(
114 const GURL
& url_requested
,
115 const SuccessCallback
& callback
) {
116 CreateRequest(kEventTypeURLRequest
, url_requested
.spec(), callback
);
119 void PermissionRequestCreatorApiary::CreateExtensionUpdateRequest(
120 const std::string
& id
,
121 const SuccessCallback
& callback
) {
122 CreateRequest(kEventTypeUpdateRequest
, id
, callback
);
125 GURL
PermissionRequestCreatorApiary::GetApiUrl() const {
126 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
127 switches::kPermissionRequestApiUrl
)) {
128 GURL
url(base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
129 switches::kPermissionRequestApiUrl
));
130 LOG_IF(WARNING
, !url
.is_valid())
131 << "Got invalid URL for " << switches::kPermissionRequestApiUrl
;
134 return GURL(kApiUrl
);
138 std::string
PermissionRequestCreatorApiary::GetApiScope() const {
139 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
140 switches::kPermissionRequestApiScope
)) {
141 return base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
142 switches::kPermissionRequestApiScope
);
148 void PermissionRequestCreatorApiary::CreateRequest(
149 const std::string
& request_type
,
150 const std::string
& object_ref
,
151 const SuccessCallback
& callback
) {
153 new Request(request_type
, object_ref
, callback
, url_fetcher_id_
));
154 StartFetching(requests_
.back());
157 void PermissionRequestCreatorApiary::StartFetching(Request
* request
) {
158 OAuth2TokenService::ScopeSet scopes
;
159 scopes
.insert(GetApiScope());
160 request
->access_token_request
= oauth2_token_service_
->StartRequest(
161 account_id_
, scopes
, this);
164 void PermissionRequestCreatorApiary::OnGetTokenSuccess(
165 const OAuth2TokenService::Request
* request
,
166 const std::string
& access_token
,
167 const base::Time
& expiration_time
) {
168 RequestIterator it
= requests_
.begin();
169 while (it
!= requests_
.end()) {
170 if (request
== (*it
)->access_token_request
.get())
174 DCHECK(it
!= requests_
.end());
175 (*it
)->access_token
= access_token
;
177 (*it
)->url_fetcher
= URLFetcher::Create((*it
)->url_fetcher_id
, GetApiUrl(),
178 URLFetcher::POST
, this);
180 (*it
)->url_fetcher
->SetRequestContext(context_
);
181 (*it
)->url_fetcher
->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES
|
182 net::LOAD_DO_NOT_SAVE_COOKIES
);
183 (*it
)->url_fetcher
->SetAutomaticallyRetryOnNetworkChanges(kNumRetries
);
184 (*it
)->url_fetcher
->AddExtraRequestHeader(
185 base::StringPrintf(kAuthorizationHeaderFormat
, access_token
.c_str()));
187 base::DictionaryValue dict
;
188 dict
.SetStringWithoutPathExpansion(kEventTypeKey
, (*it
)->request_type
);
189 dict
.SetStringWithoutPathExpansion(kObjectRefKey
, (*it
)->object_ref
);
190 dict
.SetStringWithoutPathExpansion(kStateKey
, kState
);
193 base::JSONWriter::Write(dict
, &body
);
194 (*it
)->url_fetcher
->SetUploadData("application/json", body
);
196 (*it
)->url_fetcher
->Start();
199 void PermissionRequestCreatorApiary::OnGetTokenFailure(
200 const OAuth2TokenService::Request
* request
,
201 const GoogleServiceAuthError
& error
) {
202 VLOG(1) << "Couldn't get token";
203 RequestIterator it
= requests_
.begin();
204 while (it
!= requests_
.end()) {
205 if (request
== (*it
)->access_token_request
.get())
209 DCHECK(it
!= requests_
.end());
210 (*it
)->callback
.Run(false);
214 void PermissionRequestCreatorApiary::OnURLFetchComplete(
215 const URLFetcher
* source
) {
216 RequestIterator it
= requests_
.begin();
217 while (it
!= requests_
.end()) {
218 if (source
== (*it
)->url_fetcher
.get())
222 DCHECK(it
!= requests_
.end());
224 const net::URLRequestStatus
& status
= source
->GetStatus();
225 if (!status
.is_success()) {
226 DispatchNetworkError(it
, status
.error());
230 int response_code
= source
->GetResponseCode();
231 if (response_code
== net::HTTP_UNAUTHORIZED
&& !(*it
)->access_token_expired
) {
232 (*it
)->access_token_expired
= true;
233 OAuth2TokenService::ScopeSet scopes
;
234 scopes
.insert(GetApiScope());
235 oauth2_token_service_
->InvalidateAccessToken(account_id_
, scopes
,
236 (*it
)->access_token
);
241 if (response_code
!= net::HTTP_OK
) {
242 LOG(WARNING
) << "HTTP error " << response_code
;
243 DispatchGoogleServiceAuthError(
244 it
, GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED
));
248 std::string response_body
;
249 source
->GetResponseAsString(&response_body
);
250 scoped_ptr
<base::Value
> value
= base::JSONReader::Read(response_body
);
251 base::DictionaryValue
* dict
= NULL
;
252 if (!value
|| !value
->GetAsDictionary(&dict
)) {
253 DispatchNetworkError(it
, net::ERR_INVALID_RESPONSE
);
256 base::DictionaryValue
* permission_dict
= NULL
;
257 if (!dict
->GetDictionary(kPermissionRequestKey
, &permission_dict
)) {
258 DispatchNetworkError(it
, net::ERR_INVALID_RESPONSE
);
262 if (!permission_dict
->GetString(kIdKey
, &id
)) {
263 DispatchNetworkError(it
, net::ERR_INVALID_RESPONSE
);
266 (*it
)->callback
.Run(true);
270 void PermissionRequestCreatorApiary::DispatchNetworkError(RequestIterator it
,
272 DispatchGoogleServiceAuthError(
273 it
, GoogleServiceAuthError::FromConnectionError(error_code
));
276 void PermissionRequestCreatorApiary::DispatchGoogleServiceAuthError(
278 const GoogleServiceAuthError
& error
) {
279 VLOG(1) << "GoogleServiceAuthError: " << error
.ToString();
280 (*it
)->callback
.Run(false);