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/managed_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 29 using net::URLFetcher; 30 31 const int kNumRetries = 1; 32 const char kIdKey[] = "id"; 33 const char kNamespace[] = "CHROME"; 34 const char kState[] = "PENDING"; 35 36 static const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s"; 37 38 PermissionRequestCreatorApiary::PermissionRequestCreatorApiary( 39 OAuth2TokenService* oauth2_token_service, 40 scoped_ptr<ManagedUserSigninManagerWrapper> 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 48 PermissionRequestCreatorApiary::~PermissionRequestCreatorApiary() {} 49 50 // static 51 scoped_ptr<PermissionRequestCreator> 52 PermissionRequestCreatorApiary::CreateWithProfile(Profile* profile) { 53 ProfileOAuth2TokenService* token_service = 54 ProfileOAuth2TokenServiceFactory::GetForProfile(profile); 55 SigninManagerBase* signin = SigninManagerFactory::GetForProfile(profile); 56 scoped_ptr<ManagedUserSigninManagerWrapper> signin_wrapper( 57 new ManagedUserSigninManagerWrapper(profile, signin)); 58 scoped_ptr<PermissionRequestCreator> creator( 59 new PermissionRequestCreatorApiary( 60 token_service, signin_wrapper.Pass(), profile->GetRequestContext())); 61 return creator.Pass(); 62 } 63 64 void 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 72 void PermissionRequestCreatorApiary::StartFetching() { 73 OAuth2TokenService::ScopeSet scopes; 74 scopes.insert(signin_wrapper_->GetSyncScopeToUse()); 75 access_token_request_ = oauth2_token_service_->StartRequest( 76 signin_wrapper_->GetAccountIdToUse(), scopes, this); 77 } 78 79 void PermissionRequestCreatorApiary::OnGetTokenSuccess( 80 const OAuth2TokenService::Request* request, 81 const std::string& access_token, 82 const base::Time& expiration_time) { 83 DCHECK_EQ(access_token_request_.get(), request); 84 access_token_ = access_token; 85 GURL url(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( 86 switches::kPermissionRequestApiUrl)); 87 const int id = 0; 88 89 url_fetcher_.reset(URLFetcher::Create(id, url, URLFetcher::POST, this)); 90 91 url_fetcher_->SetRequestContext(context_); 92 url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | 93 net::LOAD_DO_NOT_SAVE_COOKIES); 94 url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(kNumRetries); 95 url_fetcher_->AddExtraRequestHeader( 96 base::StringPrintf(kAuthorizationHeaderFormat, access_token.c_str())); 97 98 base::DictionaryValue dict; 99 dict.SetStringWithoutPathExpansion("namespace", kNamespace); 100 dict.SetStringWithoutPathExpansion("objectRef", url_requested_); 101 dict.SetStringWithoutPathExpansion("state", kState); 102 std::string body; 103 base::JSONWriter::Write(&dict, &body); 104 url_fetcher_->SetUploadData("application/json", body); 105 106 url_fetcher_->Start(); 107 } 108 109 void PermissionRequestCreatorApiary::OnGetTokenFailure( 110 const OAuth2TokenService::Request* request, 111 const GoogleServiceAuthError& error) { 112 DCHECK_EQ(access_token_request_.get(), request); 113 callback_.Run(); 114 callback_.Reset(); 115 } 116 117 void PermissionRequestCreatorApiary::OnURLFetchComplete( 118 const URLFetcher* source) { 119 const net::URLRequestStatus& status = source->GetStatus(); 120 if (!status.is_success()) { 121 DispatchNetworkError(status.error()); 122 return; 123 } 124 125 int response_code = source->GetResponseCode(); 126 if (response_code == net::HTTP_UNAUTHORIZED && !access_token_expired_) { 127 access_token_expired_ = true; 128 OAuth2TokenService::ScopeSet scopes; 129 scopes.insert(signin_wrapper_->GetSyncScopeToUse()); 130 oauth2_token_service_->InvalidateToken( 131 signin_wrapper_->GetAccountIdToUse(), scopes, access_token_); 132 StartFetching(); 133 return; 134 } 135 136 if (response_code != net::HTTP_OK) { 137 DLOG(WARNING) << "HTTP error " << response_code; 138 DispatchGoogleServiceAuthError( 139 GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED)); 140 return; 141 } 142 143 std::string response_body; 144 source->GetResponseAsString(&response_body); 145 scoped_ptr<base::Value> value(base::JSONReader::Read(response_body)); 146 base::DictionaryValue* dict = NULL; 147 if (!value || !value->GetAsDictionary(&dict)) { 148 DispatchNetworkError(net::ERR_INVALID_RESPONSE); 149 return; 150 } 151 std::string id; 152 if (!dict->GetString(kIdKey, &id)) { 153 DispatchNetworkError(net::ERR_INVALID_RESPONSE); 154 return; 155 } 156 callback_.Run(); 157 callback_.Reset(); 158 } 159 160 void PermissionRequestCreatorApiary::DispatchNetworkError(int error_code) { 161 DispatchGoogleServiceAuthError( 162 GoogleServiceAuthError::FromConnectionError(error_code)); 163 } 164 165 void PermissionRequestCreatorApiary::DispatchGoogleServiceAuthError( 166 const GoogleServiceAuthError& error) { 167 callback_.Run(); 168 callback_.Reset(); 169 } 170