Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / supervised_user / child_accounts / permission_request_creator_apiary.cc
blob37483a124f2ce750983d568889ce7f3cfb1b9254
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"
27 #include "url/gurl.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";
39 // Request keys.
40 const char kEventTypeKey[] = "eventType";
41 const char kObjectRefKey[] = "objectRef";
42 const char kStateKey[] = "state";
44 // Request values.
45 const char kEventTypeURLRequest[] = "PERMISSION_CHROME_URL";
46 const char kEventTypeUpdateRequest[] = "PERMISSION_CHROME_CWS_ITEM_UPDATE";
47 const char kState[] = "PENDING";
49 // Response keys.
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,
57 int url_fetcher_id);
58 ~Request();
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;
66 int url_fetcher_id;
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,
74 int url_fetcher_id)
75 : request_type(request_type),
76 object_ref(object_ref),
77 callback(callback),
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),
91 context_(context),
92 url_fetcher_id_(0) {
95 PermissionRequestCreatorApiary::~PermissionRequestCreatorApiary() {}
97 // static
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(
104 token_service,
105 signin->GetAuthenticatedAccountId(),
106 profile->GetRequestContext()));
109 bool PermissionRequestCreatorApiary::IsEnabled() const {
110 return true;
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;
132 return url;
133 } else {
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);
143 } else {
144 return kApiScope;
148 void PermissionRequestCreatorApiary::CreateRequest(
149 const std::string& request_type,
150 const std::string& object_ref,
151 const SuccessCallback& callback) {
152 requests_.push_back(
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())
171 break;
172 ++it;
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);
192 std::string body;
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())
206 break;
207 ++it;
209 DCHECK(it != requests_.end());
210 (*it)->callback.Run(false);
211 requests_.erase(it);
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())
219 break;
220 ++it;
222 DCHECK(it != requests_.end());
224 const net::URLRequestStatus& status = source->GetStatus();
225 if (!status.is_success()) {
226 DispatchNetworkError(it, status.error());
227 return;
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);
237 StartFetching(*it);
238 return;
241 if (response_code != net::HTTP_OK) {
242 LOG(WARNING) << "HTTP error " << response_code;
243 DispatchGoogleServiceAuthError(
244 it, GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED));
245 return;
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);
254 return;
256 base::DictionaryValue* permission_dict = NULL;
257 if (!dict->GetDictionary(kPermissionRequestKey, &permission_dict)) {
258 DispatchNetworkError(it, net::ERR_INVALID_RESPONSE);
259 return;
261 std::string id;
262 if (!permission_dict->GetString(kIdKey, &id)) {
263 DispatchNetworkError(it, net::ERR_INVALID_RESPONSE);
264 return;
266 (*it)->callback.Run(true);
267 requests_.erase(it);
270 void PermissionRequestCreatorApiary::DispatchNetworkError(RequestIterator it,
271 int error_code) {
272 DispatchGoogleServiceAuthError(
273 it, GoogleServiceAuthError::FromConnectionError(error_code));
276 void PermissionRequestCreatorApiary::DispatchGoogleServiceAuthError(
277 RequestIterator it,
278 const GoogleServiceAuthError& error) {
279 VLOG(1) << "GoogleServiceAuthError: " << error.ToString();
280 (*it)->callback.Run(false);
281 requests_.erase(it);