1 // Copyright 2015 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/chromeos/login/signin/token_handle_fetcher.h"
7 #include "base/metrics/histogram_macros.h"
8 #include "chrome/browser/chromeos/login/signin/token_handle_util.h"
9 #include "chrome/browser/chromeos/profiles/profile_helper.h"
10 #include "chrome/browser/profiles/profile.h"
11 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
12 #include "chrome/browser/signin/signin_manager_factory.h"
13 #include "chrome/browser/signin/signin_manager_factory.h"
14 #include "components/keyed_service/content/browser_context_keyed_service_shutdown_notifier_factory.h"
15 #include "components/signin/core/browser/profile_oauth2_token_service.h"
16 #include "components/signin/core/browser/signin_manager.h"
17 #include "google_apis/gaia/gaia_constants.h"
20 const int kMaxRetries
= 3;
22 class ShutdownNotifierFactory
23 : public BrowserContextKeyedServiceShutdownNotifierFactory
{
25 static ShutdownNotifierFactory
* GetInstance() {
26 return Singleton
<ShutdownNotifierFactory
>::get();
30 friend struct DefaultSingletonTraits
<ShutdownNotifierFactory
>;
32 ShutdownNotifierFactory()
33 : BrowserContextKeyedServiceShutdownNotifierFactory(
34 "TokenHandleFetcher") {
35 DependsOn(ProfileOAuth2TokenServiceFactory::GetInstance());
37 ~ShutdownNotifierFactory() override
{}
39 DISALLOW_COPY_AND_ASSIGN(ShutdownNotifierFactory
);
44 TokenHandleFetcher::TokenHandleFetcher(TokenHandleUtil
* util
,
45 const user_manager::UserID
& user_id
)
46 : OAuth2TokenService::Consumer("user_session_manager"),
47 token_handle_util_(util
),
49 token_service_(nullptr),
50 waiting_for_refresh_token_(false),
52 tokeninfo_response_start_time_(base::TimeTicks()) {
55 TokenHandleFetcher::~TokenHandleFetcher() {
56 if (waiting_for_refresh_token_
)
57 token_service_
->RemoveObserver(this);
60 void TokenHandleFetcher::BackfillToken(Profile
* profile
,
61 const TokenFetchingCallback
& callback
) {
65 token_service_
= ProfileOAuth2TokenServiceFactory::GetForProfile(profile
);
66 SigninManagerBase
* signin_manager
=
67 SigninManagerFactory::GetForProfile(profile
);
68 std::string account_id
= signin_manager
->GetAuthenticatedAccountId();
69 if (!token_service_
->RefreshTokenIsAvailable(account_id
)) {
70 account_without_token_
= account_id
;
71 profile_shutdown_notification_
=
72 ShutdownNotifierFactory::GetInstance()->Get(profile
)->Subscribe(
73 base::Bind(&TokenHandleFetcher::OnProfileDestroyed
,
74 base::Unretained(this)));
76 token_service_
->AddObserver(this);
77 waiting_for_refresh_token_
= true;
80 RequestAccessToken(account_id
);
83 void TokenHandleFetcher::OnRefreshTokenAvailable(
84 const std::string
& account_id
) {
85 if (account_without_token_
!= account_id
)
87 waiting_for_refresh_token_
= false;
88 token_service_
->RemoveObserver(this);
89 RequestAccessToken(account_id
);
92 void TokenHandleFetcher::RequestAccessToken(const std::string
& account_id
) {
93 OAuth2TokenService::ScopeSet scopes
;
94 scopes
.insert(GaiaConstants::kOAuth1LoginScope
);
95 oauth2_access_token_request_
=
96 token_service_
->StartRequest(account_id
, scopes
, this);
99 void TokenHandleFetcher::OnGetTokenSuccess(
100 const OAuth2TokenService::Request
* request
,
101 const std::string
& access_token
,
102 const base::Time
& expiration_time
) {
103 oauth2_access_token_request_
.reset();
104 FillForAccessToken(access_token
);
107 void TokenHandleFetcher::OnGetTokenFailure(
108 const OAuth2TokenService::Request
* request
,
109 const GoogleServiceAuthError
& error
) {
110 oauth2_access_token_request_
.reset();
111 LOG(ERROR
) << "Could not get access token to backfill token handler"
113 callback_
.Run(user_id_
, false);
116 void TokenHandleFetcher::FillForNewUser(const std::string
& access_token
,
117 const TokenFetchingCallback
& callback
) {
118 profile_
= chromeos::ProfileHelper::Get()->GetSigninProfile();
119 callback_
= callback
;
120 FillForAccessToken(access_token
);
123 void TokenHandleFetcher::FillForAccessToken(const std::string
& access_token
) {
124 if (!gaia_client_
.get())
126 new gaia::GaiaOAuthClient(profile_
->GetRequestContext()));
127 tokeninfo_response_start_time_
= base::TimeTicks::Now();
128 gaia_client_
->GetTokenInfo(access_token
, kMaxRetries
, this);
131 void TokenHandleFetcher::OnOAuthError() {
132 callback_
.Run(user_id_
, false);
135 void TokenHandleFetcher::OnNetworkError(int response_code
) {
136 callback_
.Run(user_id_
, false);
139 void TokenHandleFetcher::OnGetTokenInfoResponse(
140 scoped_ptr
<base::DictionaryValue
> token_info
) {
141 bool success
= false;
142 if (!token_info
->HasKey("error")) {
144 if (token_info
->GetString("token_handle", &handle
)) {
146 token_handle_util_
->StoreTokenHandle(user_id_
, handle
);
149 const base::TimeDelta duration
=
150 base::TimeTicks::Now() - tokeninfo_response_start_time_
;
151 UMA_HISTOGRAM_TIMES("Login.TokenObtainResponseTime", duration
);
152 callback_
.Run(user_id_
, success
);
155 void TokenHandleFetcher::OnProfileDestroyed() {
156 callback_
.Run(user_id_
, false);