Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: components/signin/core/browser/access_token_fetcher.cc

Issue 2582573002: Signin/OAuth: Create an AccessTokenFetcher helper class (Closed)
Patch Set: review5 Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 "components/signin/core/browser/access_token_fetcher.h"
6
7 #include <utility>
8
9 #include "base/logging.h"
10
11 AccessTokenFetcher::AccessTokenFetcher(
12 const std::string& oauth_consumer_name,
13 SigninManagerBase* signin_manager,
14 OAuth2TokenService* token_service,
15 const OAuth2TokenService::ScopeSet& scopes,
16 TokenCallback callback)
17 : OAuth2TokenService::Consumer(oauth_consumer_name),
18 signin_manager_(signin_manager),
19 token_service_(token_service),
20 scopes_(scopes),
21 callback_(std::move(callback)),
22 waiting_for_sign_in_(false),
23 waiting_for_refresh_token_(false),
24 access_token_retried_(false) {
25 Start();
26 }
27
28 AccessTokenFetcher::~AccessTokenFetcher() {
29 if (waiting_for_sign_in_) {
30 signin_manager_->RemoveObserver(this);
31 }
32 if (waiting_for_refresh_token_) {
33 token_service_->RemoveObserver(this);
34 }
35 }
36
37 void AccessTokenFetcher::Start() {
38 if (signin_manager_->IsAuthenticated()) {
39 // Already signed in: Make sure we have a refresh token, then get the access
40 // token.
41 WaitForRefreshToken();
42 return;
43 }
44
45 // Not signed in: Wait for a sign-in to complete (to get the refresh token),
46 // then get the access token.
47 DCHECK(!waiting_for_sign_in_);
48 waiting_for_sign_in_ = true;
49 signin_manager_->AddObserver(this);
50 }
51
52 void AccessTokenFetcher::WaitForRefreshToken() {
53 DCHECK(signin_manager_->IsAuthenticated());
54 DCHECK(!waiting_for_refresh_token_);
55
56 if (token_service_->RefreshTokenIsAvailable(
57 signin_manager_->GetAuthenticatedAccountId())) {
58 // Already have refresh token: Get the access token directly.
59 StartAccessTokenRequest();
60 return;
61 }
62
63 // Signed in, but refresh token isn't there yet: Wait for the refresh
64 // token to be loaded, then get the access token.
65 waiting_for_refresh_token_ = true;
66 token_service_->AddObserver(this);
67 }
68
69 void AccessTokenFetcher::StartAccessTokenRequest() {
70 // Note: We might get here even in cases where we know that there's no refresh
71 // token. We're requesting an access token anyway, so that the token service
72 // will generate an appropriate error code that we can return to the client.
73 DCHECK(!access_token_request_);
74 access_token_request_ = token_service_->StartRequest(
75 signin_manager_->GetAuthenticatedAccountId(), scopes_, this);
76 }
77
78 void AccessTokenFetcher::GoogleSigninSucceeded(const std::string& account_id,
79 const std::string& username,
80 const std::string& password) {
81 DCHECK(waiting_for_sign_in_);
82 DCHECK(!waiting_for_refresh_token_);
83 DCHECK(signin_manager_->IsAuthenticated());
84 waiting_for_sign_in_ = false;
85 signin_manager_->RemoveObserver(this);
86
87 WaitForRefreshToken();
88 }
89
90 void AccessTokenFetcher::GoogleSigninFailed(
91 const GoogleServiceAuthError& error) {
92 DCHECK(waiting_for_sign_in_);
93 DCHECK(!waiting_for_refresh_token_);
94 waiting_for_sign_in_ = false;
95 signin_manager_->RemoveObserver(this);
96
97 std::move(callback_).Run(error, std::string());
98 }
99
100 void AccessTokenFetcher::OnRefreshTokenAvailable(
101 const std::string& account_id) {
102 DCHECK(waiting_for_refresh_token_);
103 DCHECK(!waiting_for_sign_in_);
104
105 // Only react on tokens for the account the user has signed in with.
106 if (account_id != signin_manager_->GetAuthenticatedAccountId()) {
107 return;
108 }
109
110 waiting_for_refresh_token_ = false;
111 token_service_->RemoveObserver(this);
112 StartAccessTokenRequest();
113 }
114
115 void AccessTokenFetcher::OnRefreshTokensLoaded() {
116 DCHECK(waiting_for_refresh_token_);
117 DCHECK(!waiting_for_sign_in_);
118 DCHECK(!access_token_request_);
119
120 // All refresh tokens were loaded, but we didn't get one for the account we
121 // care about. We probably won't get one any time soon.
122 // Attempt to fetch an access token anyway, so that the token service will
123 // provide us with an appropriate error code.
124 waiting_for_refresh_token_ = false;
125 token_service_->RemoveObserver(this);
126 StartAccessTokenRequest();
127 }
128
129 void AccessTokenFetcher::OnGetTokenSuccess(
130 const OAuth2TokenService::Request* request,
131 const std::string& access_token,
132 const base::Time& expiration_time) {
133 DCHECK_EQ(request, access_token_request_.get());
134 std::unique_ptr<OAuth2TokenService::Request> request_deleter(
135 std::move(access_token_request_));
136
137 std::move(callback_).Run(GoogleServiceAuthError::AuthErrorNone(),
138 access_token);
139 }
140
141 void AccessTokenFetcher::OnGetTokenFailure(
142 const OAuth2TokenService::Request* request,
143 const GoogleServiceAuthError& error) {
144 DCHECK_EQ(request, access_token_request_.get());
145 std::unique_ptr<OAuth2TokenService::Request> request_deleter(
146 std::move(access_token_request_));
147
148 // There is a special case for Android that RefreshTokenIsAvailable and
149 // StartRequest are called to pre-fetch the account image and name before
150 // sign-in. In that case, our ongoing access token request gets cancelled.
151 // Moreover, OnRefreshTokenAvailable might happen after startup when the
152 // credentials are changed/updated.
153 // To handle these cases, we retry a canceled request once.
154 // However, a request may also get cancelled for legitimate reasons, e.g.
155 // because the user signed out. In those cases, there's no point in retrying,
156 // so only retry if there (still) is a valid refresh token.
157 // NOTE: Maybe we should retry for all transient errors here, so that clients
158 // don't have to.
159 if (!access_token_retried_ &&
160 error.state() == GoogleServiceAuthError::State::REQUEST_CANCELED &&
161 token_service_->RefreshTokenIsAvailable(
162 signin_manager_->GetAuthenticatedAccountId())) {
163 access_token_retried_ = true;
164 StartAccessTokenRequest();
165 return;
166 }
167
168 std::move(callback_).Run(error, std::string());
169 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698