Chromium Code Reviews| OLD | NEW |
|---|---|
| (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 #include "base/threading/thread_task_runner_handle.h" | |
| 11 #include "components/signin/core/browser/signin_manager_base.h" | |
| 12 #include "google_apis/gaia/google_service_auth_error.h" | |
| 13 | |
| 14 AccessTokenFetcher::AccessTokenFetcher( | |
| 15 const std::string& oauth_consumer_name, | |
| 16 const SigninManagerBase* signin_manager, | |
| 17 OAuth2TokenService* token_service, | |
| 18 const OAuth2TokenService::ScopeSet& scopes, | |
| 19 const TokenCallback& callback) | |
| 20 : OAuth2TokenService::Consumer(oauth_consumer_name), | |
| 21 signin_manager_(signin_manager), | |
| 22 token_service_(token_service), | |
| 23 scopes_(scopes), | |
| 24 callback_(callback), | |
| 25 weak_ptr_factory_(this) { | |
| 26 Start(); | |
| 27 } | |
| 28 | |
| 29 AccessTokenFetcher::~AccessTokenFetcher() { | |
| 30 if (waiting_for_refresh_token_) { | |
| 31 token_service_->RemoveObserver(this); | |
| 32 } | |
| 33 } | |
| 34 | |
| 35 void AccessTokenFetcher::Start() { | |
| 36 if (signin_manager_->IsAuthenticated() && | |
| 37 token_service_->RefreshTokenIsAvailable( | |
| 38 signin_manager_->GetAuthenticatedAccountId())) { | |
| 39 // Already have refresh token: Get the access token directly. | |
| 40 StartAccessTokenRequest(); | |
| 41 } else if (signin_manager_->IsAuthenticated() || | |
| 42 signin_manager_->AuthInProgress()) { | |
| 43 // Currently signing in, or signed in but refresh token isn't there yet: | |
| 44 // Wait for auth to finish (to get the refresh token), then get the access | |
| 45 // token. | |
| 46 // TODO(treib): In the AuthInProgress case, should we wait for | |
| 47 // GoogleSigninSucceeded/Failed (from SigninManagerBase::Observer) first? | |
|
msarda
2017/01/18 21:55:19
I agree this is a tricky question: currently the r
Marc Treib
2017/01/19 15:03:55
Done.
However, I'm still not super confident that
msarda
2017/01/23 17:08:09
I think using a timeout is not a good API.
This c
Marc Treib
2017/01/24 10:17:32
Not calling the callback after we're destroyed is
| |
| 48 DCHECK(!waiting_for_refresh_token_); | |
| 49 waiting_for_refresh_token_ = true; | |
| 50 token_service_->AddObserver(this); | |
| 51 } else { | |
| 52 // Not signed in, no access token. Make sure not to run the callback | |
| 53 // synchronously, and not to run it if we get deleted in the meantime. | |
| 54 base::ThreadTaskRunnerHandle::Get()->PostTask( | |
|
msarda
2017/01/18 21:55:19
It is not clear to me how you would use this API:
Marc Treib
2017/01/19 15:03:55
There are some (future) clients of this class that
| |
| 55 FROM_HERE, base::Bind(&AccessTokenFetcher::NotSignedInCallback, | |
| 56 weak_ptr_factory_.GetWeakPtr())); | |
| 57 } | |
| 58 } | |
| 59 | |
| 60 void AccessTokenFetcher::NotSignedInCallback() { | |
| 61 callback_.Run(std::string()); | |
|
msarda
2017/01/18 21:55:19
We should to pass an error to the callback here a
msarda
2017/01/18 21:55:19
We should use a callback that may be called only o
Marc Treib
2017/01/19 15:03:55
I actually did use OnceCallback in a previous iter
Marc Treib
2017/01/19 15:03:55
So far, none of the callers I'm aware of care abou
msarda
2017/01/23 17:08:09
I think the current API is fine for discussion, bu
| |
| 62 } | |
| 63 | |
| 64 void AccessTokenFetcher::OnRefreshTokenAvailable( | |
| 65 const std::string& account_id) { | |
| 66 DCHECK(waiting_for_refresh_token_); | |
|
msarda
2017/01/18 21:55:19
Just to make sure what I said in my previous comme
Marc Treib
2017/01/19 15:03:55
Done.
| |
| 67 | |
| 68 // Only react on tokens for the account the user has signed in with. | |
| 69 if (account_id != signin_manager_->GetAuthenticatedAccountId()) { | |
| 70 return; | |
| 71 } | |
| 72 | |
|
msarda
2017/01/18 21:55:18
Nit: I would set waiting_for_refresh_token_ before
Marc Treib
2017/01/19 15:03:55
Done.
| |
| 73 token_service_->RemoveObserver(this); | |
| 74 waiting_for_refresh_token_ = false; | |
| 75 StartAccessTokenRequest(); | |
| 76 } | |
| 77 | |
| 78 void AccessTokenFetcher::OnRefreshTokensLoaded() { | |
| 79 DCHECK(waiting_for_refresh_token_); | |
| 80 | |
| 81 // All refresh tokens were loaded, but we didn't get one for the account we | |
| 82 // care about. We probably won't get one any time soon. | |
| 83 token_service_->RemoveObserver(this); | |
| 84 waiting_for_refresh_token_ = false; | |
| 85 callback_.Run(std::string()); | |
| 86 } | |
| 87 | |
| 88 void AccessTokenFetcher::StartAccessTokenRequest() { | |
| 89 access_token_request_ = token_service_->StartRequest( | |
| 90 signin_manager_->GetAuthenticatedAccountId(), scopes_, this); | |
| 91 } | |
| 92 | |
| 93 void AccessTokenFetcher::OnGetTokenSuccess( | |
| 94 const OAuth2TokenService::Request* request, | |
| 95 const std::string& access_token, | |
| 96 const base::Time& expiration_time) { | |
| 97 DCHECK_EQ(request, access_token_request_.get()); | |
| 98 std::unique_ptr<OAuth2TokenService::Request> request_deleter( | |
| 99 std::move(access_token_request_)); | |
| 100 | |
| 101 callback_.Run(access_token); | |
| 102 } | |
| 103 | |
| 104 void AccessTokenFetcher::OnGetTokenFailure( | |
| 105 const OAuth2TokenService::Request* request, | |
| 106 const GoogleServiceAuthError& error) { | |
| 107 DCHECK_EQ(request, access_token_request_.get()); | |
| 108 std::unique_ptr<OAuth2TokenService::Request> request_deleter( | |
| 109 std::move(access_token_request_)); | |
| 110 | |
| 111 if (!access_token_retried_ && | |
| 112 error.state() == GoogleServiceAuthError::State::REQUEST_CANCELED) { | |
| 113 // The request can get reset by loading the refresh token (happens during | |
| 114 // startup) - try one more time. | |
| 115 access_token_retried_ = true; | |
| 116 StartAccessTokenRequest(); | |
|
msarda
2017/01/18 21:55:19
It is not clear to me yet why we need to retry. I
Marc Treib
2017/01/19 15:03:55
We had a case on Android where sometimes during st
jkrcal
2017/01/19 15:48:45
I agree it is ugly. Reasoning for the retry: https
msarda
2017/01/23 17:08:09
Thank you for the pointer. I think we should not d
Marc Treib
2017/01/24 10:17:32
The thread is not public unfortunately, so we can'
| |
| 117 return; | |
| 118 } | |
| 119 | |
| 120 DLOG(WARNING) << "Unable to get token: " << error.ToString(); | |
| 121 callback_.Run(std::string()); | |
|
msarda
2017/01/18 21:55:18
We need an API that would allow us to pass the err
Marc Treib
2017/01/24 10:17:32
I'd actually prefer if any retrying were handled w
msarda
2017/01/25 09:54:28
I agree with this - we should hide the nasty thing
| |
| 122 } | |
| OLD | NEW |