diff options
-rw-r--r-- | components/signin.gypi | 21 | ||||
-rw-r--r-- | components/signin/core/browser/signin_client.h | 14 | ||||
-rw-r--r-- | components/signin/core/browser/test_signin_client.cc | 8 | ||||
-rw-r--r-- | components/signin/core/browser/test_signin_client.h | 4 | ||||
-rw-r--r-- | components/signin/ios/DEPS | 3 | ||||
-rw-r--r-- | components/signin/ios/browser/profile_oauth2_token_service_ios.h | 163 | ||||
-rw-r--r-- | components/signin/ios/browser/profile_oauth2_token_service_ios.mm | 498 | ||||
-rw-r--r-- | ios/provider/ios_components.gyp | 20 | ||||
-rw-r--r-- | ios/public/DEPS | 12 | ||||
-rw-r--r-- | ios/public/provider/components/signin/browser/profile_oauth2_token_service_ios_provider.h | 78 |
10 files changed, 809 insertions, 12 deletions
diff --git a/components/signin.gypi b/components/signin.gypi index aa09f77..5473b57 100644 --- a/components/signin.gypi +++ b/components/signin.gypi @@ -103,4 +103,25 @@ ], }, ], + 'conditions': [ + ['OS == "ios"', { + 'targets': [ + { + 'target_name': 'signin_ios_browser', + 'type': 'static_library', + 'dependencies': [ + 'signin_core_browser', + '../ios/provider/ios_components.gyp:ios_components', + ], + 'include_dirs': [ + '..', + ], + 'sources': [ + 'signin/ios/browser/profile_oauth2_token_service_ios.h', + 'signin/ios/browser/profile_oauth2_token_service_ios.mm', + ], + }, + ], + }], + ], } diff --git a/components/signin/core/browser/signin_client.h b/components/signin/core/browser/signin_client.h index 4b8837c..4187f47 100644 --- a/components/signin/core/browser/signin_client.h +++ b/components/signin/core/browser/signin_client.h @@ -17,6 +17,14 @@ class CanonicalCookie; class URLRequestContextGetter; } +#if defined(OS_IOS) +namespace ios { +// TODO(msarda): http://crbug.com/358544 Remove this iOS specific code from the +// core SigninClient. +class ProfileOAuth2TokenServiceIOSProvider; +} +#endif + // An interface that needs to be supplied to the Signin component by its // embedder. class SigninClient { @@ -57,6 +65,12 @@ class SigninClient { // Called when Google signin has succeeded. virtual void GoogleSigninSucceeded(const std::string& username, const std::string& password) {} + +#if defined(OS_IOS) + // TODO(msarda): http://crbug.com/358544 Remove this iOS specific code from + // the core SigninClient. + virtual ios::ProfileOAuth2TokenServiceIOSProvider* GetIOSProvider() = 0; +#endif }; #endif // COMPONENTS_SIGNIN_CORE_BROWSER_SIGNIN_CLIENT_H_ diff --git a/components/signin/core/browser/test_signin_client.cc b/components/signin/core/browser/test_signin_client.cc index 86bb74f..af05dd1 100644 --- a/components/signin/core/browser/test_signin_client.cc +++ b/components/signin/core/browser/test_signin_client.cc @@ -53,3 +53,11 @@ bool TestSigninClient::ShouldMergeSigninCredentialsIntoCookieJar() { void TestSigninClient::SetCookieChangedCallback( const CookieChangedCallback& callback) {} + +#if defined(OS_IOS) +ios::ProfileOAuth2TokenServiceIOSProvider* TestSigninClient::GetIOSProvider() { + // Just returns NULL for now. It should be changed to return an + // |ios::FakeProfileOAuth2TokenServiceIOSProvider|. + return NULL; +} +#endif diff --git a/components/signin/core/browser/test_signin_client.h b/components/signin/core/browser/test_signin_client.h index ff82be0..03e0b88 100644 --- a/components/signin/core/browser/test_signin_client.h +++ b/components/signin/core/browser/test_signin_client.h @@ -39,6 +39,10 @@ class TestSigninClient : public SigninClient { // Returns a TestURLRequestContextGetter. virtual net::URLRequestContextGetter* GetURLRequestContext() OVERRIDE; +#if defined(OS_IOS) + virtual ios::ProfileOAuth2TokenServiceIOSProvider* GetIOSProvider() OVERRIDE; +#endif + // Returns true. virtual bool ShouldMergeSigninCredentialsIntoCookieJar() OVERRIDE; diff --git a/components/signin/ios/DEPS b/components/signin/ios/DEPS new file mode 100644 index 0000000..9af4fb8 --- /dev/null +++ b/components/signin/ios/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+ios/public/provider/components/signin", +] diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios.h b/components/signin/ios/browser/profile_oauth2_token_service_ios.h new file mode 100644 index 0000000..2f32d1c --- /dev/null +++ b/components/signin/ios/browser/profile_oauth2_token_service_ios.h @@ -0,0 +1,163 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_SIGNIN_IOS_BROWSER_PROFILE_OAUTH2_TOKEN_SERVICE_IOS_H_ +#define COMPONENTS_SIGNIN_IOS_BROWSER_PROFILE_OAUTH2_TOKEN_SERVICE_IOS_H_ + +#include <string> + +#include "base/threading/thread_checker.h" +#include "components/signin/core/browser/mutable_profile_oauth2_token_service.h" + +class OAuth2AccessTokenFetcher; + +namespace ios{ +class ProfileOAuth2TokenServiceIOSProvider; +} + +// A specialization of ProfileOAuth2TokenService for OS_IOS. It fetches access +// tokens from the SSOAuth library if the user is signed in using shared +// authentication or defaults to the parent class +// |MutableProfileOAuth2TokenService| for pre-SSO signed in users. +// +// See |ProfileOAuth2TokenService| for usage details. +class ProfileOAuth2TokenServiceIOS : public MutableProfileOAuth2TokenService { + public: + virtual ~ProfileOAuth2TokenServiceIOS(); + + // KeyedService + virtual void Shutdown() OVERRIDE; + + // OAuth2TokenService + virtual bool RefreshTokenIsAvailable( + const std::string& account_id) const OVERRIDE; + + virtual void InvalidateOAuth2Token(const std::string& account_id, + const std::string& client_id, + const ScopeSet& scopes, + const std::string& access_token) OVERRIDE; + + // ProfileOAuth2TokenService + virtual void Initialize(SigninClient* client) OVERRIDE; + virtual void LoadCredentials(const std::string& primary_account_id) OVERRIDE; + virtual std::vector<std::string> GetAccounts() OVERRIDE; + virtual void UpdateAuthError(const std::string& account_id, + const GoogleServiceAuthError& error) OVERRIDE; + + // This method should not be called when using shared authentication. + virtual void UpdateCredentials(const std::string& account_id, + const std::string& refresh_token) OVERRIDE; + + // Removes all credentials from this instance of |ProfileOAuth2TokenService|, + // however, it does not revoke the identities from the device. + // Subsequent calls to |RefreshTokenIsAvailable| will return |false|. + virtual void RevokeAllCredentials() OVERRIDE; + + // Returns the refresh token for |account_id| . + // Must only be called when |ShouldUseIOSSharedAuthentication| returns false. + std::string GetRefreshTokenWhenNotUsingSharedAuthentication( + const std::string& account_id); + + // Reloads accounts from the provider. Fires |OnRefreshTokenAvailable| for + // each new account. Fires |OnRefreshTokenRevoked| for each account that was + // removed. + void ReloadCredentials(); + + // Upgrades to using shared authentication token service. + // + // Note: If this |ProfileOAuth2TokenServiceIOS| was using the legacy token + // service, then this call also revokes all tokens from the parent + // |MutableProfileOAuth2TokenService|. + void StartUsingSharedAuthentication(); + + // Sets |use_legacy_token_service_| to |use_legacy_token_service|. + // + // Should only be called for testing. + void SetUseLegacyTokenServiceForTesting(bool use_legacy_token_service); + + // Revokes the OAuth2 refresh tokens for all accounts from the parent + // |MutableProfileOAuth2TokenService|. + // + // Note: This method should only be called if the legacy pre-SSOAuth token + // service is used. + void ForceInvalidGrantResponses(); + + protected: + friend class ProfileOAuth2TokenServiceFactory; + + ProfileOAuth2TokenServiceIOS(); + + virtual OAuth2AccessTokenFetcher* CreateAccessTokenFetcher( + const std::string& account_id, + net::URLRequestContextGetter* getter, + OAuth2AccessTokenConsumer* consumer) OVERRIDE; + + // Protected and virtual to be overriden by fake for testing. + + // Adds |account_id| to |accounts_| if it does not exist or udpates + // the auth error state of |account_id| if it exists. Fires + // |OnRefreshTokenAvailable| if the account info is updated. + virtual void AddOrUpdateAccount(const std::string& account_id); + + // Removes |account_id| from |accounts_|. Fires |OnRefreshTokenRevoked| + // if the account info is removed. + virtual void RemoveAccount(const std::string& account_id); + + private: + class AccountInfo : public SigninErrorController::AuthStatusProvider { + public: + AccountInfo(ProfileOAuth2TokenService* token_service, + const std::string& account_id); + virtual ~AccountInfo(); + + void SetLastAuthError(const GoogleServiceAuthError& error); + + // SigninErrorController::AuthStatusProvider implementation. + virtual std::string GetAccountId() const OVERRIDE; + virtual GoogleServiceAuthError GetAuthStatus() const OVERRIDE; + + private: + ProfileOAuth2TokenService* token_service_; + std::string account_id_; + GoogleServiceAuthError last_auth_error_; + + DISALLOW_COPY_AND_ASSIGN(AccountInfo); + }; + + // Maps the |account_id| of accounts known to ProfileOAuth2TokenService + // to information about the account. + typedef std::map<std::string, linked_ptr<AccountInfo> > AccountInfoMap; + + // MutableProfileOAuth2TokenService + virtual std::string GetRefreshToken( + const std::string& account_id) const OVERRIDE; + + // Returns the iOS provider; + ios::ProfileOAuth2TokenServiceIOSProvider* GetProvider(); + + // Info about the existing accounts. + AccountInfoMap accounts_; + + // Calls to this class are expected to be made from the browser UI thread. + // The purpose of this this checker is to warn us if the upstream usage of + // ProfileOAuth2TokenService ever gets changed to have it be used across + // multiple threads. + base::ThreadChecker thread_checker_; + + // Whether to use the legacy pre-SSOAuth token service. + // + // |use_legacy_token_service_| is true iff the provider is not using shared + // authentication during |LoadCredentials|. Note that |LoadCredentials| is + // called exactly once after the PO2TS initialization iff the user is signed + // in. + // + // If |use_legacy_token_service_| is true, then this + // |ProfileOAuth2TokenServiceIOS| delegates all calls to the parent + // |MutableProfileOAuth2TokenService|. + bool use_legacy_token_service_; + + DISALLOW_COPY_AND_ASSIGN(ProfileOAuth2TokenServiceIOS); +}; + +#endif // COMPONENTS_SIGNIN_IOS_BROWSER_PROFILE_OAUTH2_TOKEN_SERVICE_IOS_H_ diff --git a/components/signin/ios/browser/profile_oauth2_token_service_ios.mm b/components/signin/ios/browser/profile_oauth2_token_service_ios.mm new file mode 100644 index 0000000..b17a701 --- /dev/null +++ b/components/signin/ios/browser/profile_oauth2_token_service_ios.mm @@ -0,0 +1,498 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/signin/ios/browser/profile_oauth2_token_service_ios.h" + +#include <Foundation/Foundation.h> + +#include <set> +#include <string> +#include <vector> + +#include "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "base/strings/sys_string_conversions.h" +#include "components/signin/core/browser/signin_client.h" +#include "google_apis/gaia/oauth2_access_token_fetcher.h" +#include "ios/public/provider/components/signin/browser/profile_oauth2_token_service_ios_provider.h" +#include "net/url_request/url_request_status.h" + +namespace { + +const char* kForceInvalidGrantResponsesRefreshToken = + "force_invalid_grant_responses_refresh_token"; + +// Match the way Chromium handles authentication errors in +// google_apis/gaia/oauth2_access_token_fetcher.cc: +GoogleServiceAuthError GetGoogleServiceAuthErrorFromNSError( + ios::ProfileOAuth2TokenServiceIOSProvider* provider, + NSError* error) { + if (!error) + return GoogleServiceAuthError::AuthErrorNone(); + + ios::AuthenticationErrorCategory errorCategory = + provider->GetAuthenticationErrorCategory(error); + switch (errorCategory) { + case ios::kAuthenticationErrorCategoryUnknownErrors: + // Treat all unknown error as unexpected service response errors. + // This may be too general and may require a finer grain filtering. + return GoogleServiceAuthError( + GoogleServiceAuthError::UNEXPECTED_SERVICE_RESPONSE); + case ios::kAuthenticationErrorCategoryAuthorizationErrors: + return GoogleServiceAuthError( + GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); + case ios::kAuthenticationErrorCategoryAuthorizationForbiddenErrors: + // HTTP_FORBIDDEN (403) is treated as temporary error, because it may be + // '403 Rate Limit Exceeded.' (for more details, see + // google_apis/gaia/oauth2_access_token_fetcher.cc). + return GoogleServiceAuthError( + GoogleServiceAuthError::SERVICE_UNAVAILABLE); + case ios::kAuthenticationErrorCategoryNetworkServerErrors: + // Just set the connection error state to FAILED. + return GoogleServiceAuthError::FromConnectionError( + net::URLRequestStatus::FAILED); + case ios::kAuthenticationErrorCategoryUserCancellationErrors: + return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED); + case ios::kAuthenticationErrorCategoryUnknownIdentityErrors: + return GoogleServiceAuthError(GoogleServiceAuthError::USER_NOT_SIGNED_UP); + } +} + +class SSOAccessTokenFetcher : public OAuth2AccessTokenFetcher { + public: + SSOAccessTokenFetcher(OAuth2AccessTokenConsumer* consumer, + ios::ProfileOAuth2TokenServiceIOSProvider* provider, + const std::string account_id); + virtual ~SSOAccessTokenFetcher(); + + virtual void Start(const std::string& client_id, + const std::string& client_secret, + const std::vector<std::string>& scopes) OVERRIDE; + + virtual void CancelRequest() OVERRIDE; + + // Handles an access token response. + void OnAccessTokenResponse(NSString* token, + NSDate* expiration, + NSError* error); + + private: + base::WeakPtrFactory<SSOAccessTokenFetcher> weak_factory_; + ios::ProfileOAuth2TokenServiceIOSProvider* provider_; // weak + std::string account_id_; + bool request_was_cancelled_; + + DISALLOW_COPY_AND_ASSIGN(SSOAccessTokenFetcher); +}; + +SSOAccessTokenFetcher::SSOAccessTokenFetcher( + OAuth2AccessTokenConsumer* consumer, + ios::ProfileOAuth2TokenServiceIOSProvider* provider, + const std::string account_id) + : OAuth2AccessTokenFetcher(consumer), + weak_factory_(this), + provider_(provider), + account_id_(account_id), + request_was_cancelled_(false) { + DCHECK(provider_); +} + +SSOAccessTokenFetcher::~SSOAccessTokenFetcher() {} + +void SSOAccessTokenFetcher::Start(const std::string& client_id, + const std::string& client_secret, + const std::vector<std::string>& scopes) { + std::set<std::string> scopes_set(scopes.begin(), scopes.end()); + provider_->GetAccessToken( + account_id_, client_id, client_secret, scopes_set, + base::Bind(&SSOAccessTokenFetcher::OnAccessTokenResponse, + weak_factory_.GetWeakPtr())); +} + +void SSOAccessTokenFetcher::CancelRequest() { request_was_cancelled_ = true; } + +void SSOAccessTokenFetcher::OnAccessTokenResponse(NSString* token, + NSDate* expiration, + NSError* error) { + if (request_was_cancelled_) { + // Ignore the callback if the request was cancelled. + return; + } + GoogleServiceAuthError auth_error = + GetGoogleServiceAuthErrorFromNSError(provider_, error); + if (auth_error.state() == GoogleServiceAuthError::NONE) { + base::Time expiration_date = + base::Time::FromDoubleT([expiration timeIntervalSince1970]); + FireOnGetTokenSuccess(base::SysNSStringToUTF8(token), expiration_date); + } else { + FireOnGetTokenFailure(auth_error); + } +} + +// Fetcher that returns INVALID_GAIA_CREDENTIALS responses for all requests. +class InvalidGrantAccessTokenFetcher : public OAuth2AccessTokenFetcher { + public: + explicit InvalidGrantAccessTokenFetcher(OAuth2AccessTokenConsumer* consumer); + virtual ~InvalidGrantAccessTokenFetcher(); + + // OAuth2AccessTokenFetcher + virtual void Start(const std::string& client_id, + const std::string& client_secret, + const std::vector<std::string>& scopes) OVERRIDE; + virtual void CancelRequest() OVERRIDE; + + // Fires token failure notifications with INVALID_GAIA_CREDENTIALS error. + void FireInvalidGrant(); + + private: + bool request_was_cancelled_; + DISALLOW_COPY_AND_ASSIGN(InvalidGrantAccessTokenFetcher); +}; + +InvalidGrantAccessTokenFetcher::InvalidGrantAccessTokenFetcher( + OAuth2AccessTokenConsumer* consumer) + : OAuth2AccessTokenFetcher(consumer), + request_was_cancelled_(false) {} + +InvalidGrantAccessTokenFetcher::~InvalidGrantAccessTokenFetcher() {} + +void InvalidGrantAccessTokenFetcher::Start( + const std::string& client_id, + const std::string& client_secret, + const std::vector<std::string>& scopes) { + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&InvalidGrantAccessTokenFetcher::FireInvalidGrant, + base::Unretained(this))); +}; + +void InvalidGrantAccessTokenFetcher::FireInvalidGrant() { + if (request_was_cancelled_) + return; + GoogleServiceAuthError auth_error( + GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS); + FireOnGetTokenFailure(auth_error); +} + +void InvalidGrantAccessTokenFetcher::CancelRequest() { + request_was_cancelled_ = true; +} + +} // namespace + +ProfileOAuth2TokenServiceIOS::AccountInfo::AccountInfo( + ProfileOAuth2TokenService* token_service, + const std::string& account_id) + : token_service_(token_service), + account_id_(account_id), + last_auth_error_(GoogleServiceAuthError::NONE) { + DCHECK(token_service_); + DCHECK(!account_id_.empty()); + token_service_->signin_error_controller()->AddProvider(this); +} + +ProfileOAuth2TokenServiceIOS::AccountInfo::~AccountInfo() { + token_service_->signin_error_controller()->RemoveProvider(this); +} + +void ProfileOAuth2TokenServiceIOS::AccountInfo::SetLastAuthError( + const GoogleServiceAuthError& error) { + if (error.state() != last_auth_error_.state()) { + last_auth_error_ = error; + token_service_->signin_error_controller()->AuthStatusChanged(); + } +} + +std::string ProfileOAuth2TokenServiceIOS::AccountInfo::GetAccountId() const { + return account_id_; +} + +GoogleServiceAuthError +ProfileOAuth2TokenServiceIOS::AccountInfo::GetAuthStatus() const { + return last_auth_error_; +} + +ProfileOAuth2TokenServiceIOS::ProfileOAuth2TokenServiceIOS() + : MutableProfileOAuth2TokenService(), + use_legacy_token_service_(false) { + DCHECK(thread_checker_.CalledOnValidThread()); +} + +ProfileOAuth2TokenServiceIOS::~ProfileOAuth2TokenServiceIOS() { + DCHECK(thread_checker_.CalledOnValidThread()); +} + +void ProfileOAuth2TokenServiceIOS::Initialize(SigninClient* client) { + DCHECK(thread_checker_.CalledOnValidThread()); + MutableProfileOAuth2TokenService::Initialize(client); +} + +void ProfileOAuth2TokenServiceIOS::Shutdown() { + DCHECK(thread_checker_.CalledOnValidThread()); + CancelAllRequests(); + accounts_.clear(); + MutableProfileOAuth2TokenService::Shutdown(); +} + +ios::ProfileOAuth2TokenServiceIOSProvider* +ProfileOAuth2TokenServiceIOS::GetProvider() { + ios::ProfileOAuth2TokenServiceIOSProvider* provider = + client()->GetIOSProvider(); + DCHECK(provider); + return provider; +} + +void ProfileOAuth2TokenServiceIOS::LoadCredentials( + const std::string& primary_account_id) { + DCHECK(thread_checker_.CalledOnValidThread()); + + // LoadCredentials() is called iff the user is signed in to Chrome, so the + // primary account id must not be empty. + DCHECK(!primary_account_id.empty()); + + use_legacy_token_service_ = !GetProvider()->IsUsingSharedAuthentication(); + if (use_legacy_token_service_) { + MutableProfileOAuth2TokenService::LoadCredentials(primary_account_id); + return; + } + + GetProvider()->InitializeSharedAuthentication(); + ReloadCredentials(); + FireRefreshTokensLoaded(); +} + +void ProfileOAuth2TokenServiceIOS::ReloadCredentials() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (use_legacy_token_service_) { + NOTREACHED(); + return; + } + + // Remove all old accounts that do not appear in |new_accounts| and then + // load |new_accounts|. + std::vector<std::string> new_accounts(GetProvider()->GetAllAccountIds()); + std::vector<std::string> old_accounts(GetAccounts()); + for (auto i = old_accounts.begin(); i != old_accounts.end(); ++i) { + if (std::find(new_accounts.begin(), new_accounts.end(), *i) == + new_accounts.end()) { + RemoveAccount(*i); + } + } + + // Load all new_accounts. + for (auto i = new_accounts.begin(); i != new_accounts.end(); ++i) { + AddOrUpdateAccount(*i); + } +} + +void ProfileOAuth2TokenServiceIOS::UpdateCredentials( + const std::string& account_id, + const std::string& refresh_token) { + DCHECK(thread_checker_.CalledOnValidThread()); + if (use_legacy_token_service_) { + MutableProfileOAuth2TokenService::UpdateCredentials(account_id, + refresh_token); + return; + } + NOTREACHED() << "Unexpected call to UpdateCredentials when using shared " + "authentication."; +} + +void ProfileOAuth2TokenServiceIOS::RevokeAllCredentials() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (use_legacy_token_service_) { + MutableProfileOAuth2TokenService::RevokeAllCredentials(); + return; + } + + CancelAllRequests(); + ClearCache(); + AccountInfoMap toRemove = accounts_; + for (AccountInfoMap::iterator i = toRemove.begin(); i != toRemove.end(); ++i) + RemoveAccount(i->first); + + DCHECK_EQ(0u, accounts_.size()); +} + +OAuth2AccessTokenFetcher* +ProfileOAuth2TokenServiceIOS::CreateAccessTokenFetcher( + const std::string& account_id, + net::URLRequestContextGetter* getter, + OAuth2AccessTokenConsumer* consumer) { + if (use_legacy_token_service_) { + std::string refresh_token = GetRefreshToken(account_id); + DCHECK(!refresh_token.empty()); + if (refresh_token == kForceInvalidGrantResponsesRefreshToken) { + return new InvalidGrantAccessTokenFetcher(consumer); + } else { + return MutableProfileOAuth2TokenService::CreateAccessTokenFetcher( + account_id, getter, consumer); + } + } + + return new SSOAccessTokenFetcher(consumer, GetProvider(), account_id); +} + +void ProfileOAuth2TokenServiceIOS::ForceInvalidGrantResponses() { + if (!use_legacy_token_service_) { + NOTREACHED(); + return; + } + std::vector<std::string> accounts = + MutableProfileOAuth2TokenService::GetAccounts(); + if (accounts.empty()) { + NOTREACHED(); + return; + } + + std::string first_account_id = *accounts.begin(); + if (RefreshTokenIsAvailable(first_account_id) && + GetRefreshToken(first_account_id) != + kForceInvalidGrantResponsesRefreshToken) { + MutableProfileOAuth2TokenService::RevokeAllCredentials(); + } + + for (auto i = accounts.begin(); i != accounts.end(); ++i) { + std::string account_id = *i; + MutableProfileOAuth2TokenService::UpdateCredentials( + account_id, + kForceInvalidGrantResponsesRefreshToken); + } +} + +void ProfileOAuth2TokenServiceIOS::InvalidateOAuth2Token( + const std::string& account_id, + const std::string& client_id, + const ScopeSet& scopes, + const std::string& access_token) { + DCHECK(thread_checker_.CalledOnValidThread()); + + // Call |MutableProfileOAuth2TokenService::InvalidateOAuth2Token| to clear the + // cached access token. + MutableProfileOAuth2TokenService::InvalidateOAuth2Token(account_id, + client_id, + scopes, + access_token); + + // There is no need to inform the authentication library that the access + // token is invalid as it never caches the token. +} + +std::vector<std::string> ProfileOAuth2TokenServiceIOS::GetAccounts() { + DCHECK(thread_checker_.CalledOnValidThread()); + if (use_legacy_token_service_) { + return MutableProfileOAuth2TokenService::GetAccounts(); + } + + std::vector<std::string> account_ids; + for (auto i = accounts_.begin(); i != accounts_.end(); ++i) + account_ids.push_back(i->first); + return account_ids; +} + +bool ProfileOAuth2TokenServiceIOS::RefreshTokenIsAvailable( + const std::string& account_id) const { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (use_legacy_token_service_) { + return MutableProfileOAuth2TokenService::RefreshTokenIsAvailable( + account_id); + } + + return accounts_.count(account_id) > 0; +} + +std::string ProfileOAuth2TokenServiceIOS::GetRefreshToken( + const std::string& account_id) const { + DCHECK(thread_checker_.CalledOnValidThread()); + if (use_legacy_token_service_) + return MutableProfileOAuth2TokenService::GetRefreshToken(account_id); + + // On iOS, the refresh token does not exist as ProfileOAuth2TokenServiceIOS + // fetches the access token from the iOS authentication library. + NOTREACHED(); + return std::string(); +} + +std::string +ProfileOAuth2TokenServiceIOS::GetRefreshTokenWhenNotUsingSharedAuthentication( + const std::string& account_id) { + DCHECK(use_legacy_token_service_); + return GetRefreshToken(account_id); +} + +void ProfileOAuth2TokenServiceIOS::UpdateAuthError( + const std::string& account_id, + const GoogleServiceAuthError& error) { + DCHECK(thread_checker_.CalledOnValidThread()); + + if (use_legacy_token_service_) { + MutableProfileOAuth2TokenService::UpdateAuthError(account_id, error); + return; + } + + // Do not report connection errors as these are not actually auth errors. + // We also want to avoid masking a "real" auth error just because we + // subsequently get a transient network error. + if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED || + error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE) { + return; + } + + if (accounts_.count(account_id) == 0) { + NOTREACHED(); + return; + } + accounts_[account_id]->SetLastAuthError(error); +} + +// Clear the authentication error state and notify all observers that a new +// refresh token is available so that they request new access tokens. +void ProfileOAuth2TokenServiceIOS::AddOrUpdateAccount( + const std::string& account_id) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(!account_id.empty()); + + bool account_present = accounts_.count(account_id) > 0; + if (account_present && accounts_[account_id]->GetAuthStatus().state() == + GoogleServiceAuthError::NONE) { + // No need to update the account if it is already a known account and if + // there is no auth error. + return; + } + + if (account_present) { + CancelRequestsForAccount(account_id); + ClearCacheForAccount(account_id); + } else { + accounts_[account_id].reset(new AccountInfo(this, account_id)); + } + UpdateAuthError(account_id, GoogleServiceAuthError::AuthErrorNone()); + FireRefreshTokenAvailable(account_id); +} + +void ProfileOAuth2TokenServiceIOS::RemoveAccount( + const std::string& account_id) { + DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(!account_id.empty()); + + if (accounts_.count(account_id) > 0) { + CancelRequestsForAccount(account_id); + ClearCacheForAccount(account_id); + accounts_.erase(account_id); + FireRefreshTokenRevoked(account_id); + } +} + +void ProfileOAuth2TokenServiceIOS::StartUsingSharedAuthentication() { + if (!use_legacy_token_service_) + return; + MutableProfileOAuth2TokenService::RevokeAllCredentials(); + use_legacy_token_service_ = false; +} + +void ProfileOAuth2TokenServiceIOS::SetUseLegacyTokenServiceForTesting( + bool use_legacy_token_service) { + use_legacy_token_service_ = use_legacy_token_service; +} diff --git a/ios/provider/ios_components.gyp b/ios/provider/ios_components.gyp new file mode 100644 index 0000000..002c43a --- /dev/null +++ b/ios/provider/ios_components.gyp @@ -0,0 +1,20 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +{ + 'variables': { + 'chromium_code': 1, + }, + 'targets': [ + { + 'target_name': 'ios_components', + 'type': 'none', + 'include_dirs': [ + '../..', + ], + 'sources': [ + '../public/provider/components/signin/browser/profile_oauth2_token_service_ios_provider.h', + ] + }, + ], +} diff --git a/ios/public/DEPS b/ios/public/DEPS deleted file mode 100644 index c04c1d5..0000000 --- a/ios/public/DEPS +++ /dev/null @@ -1,12 +0,0 @@ -include_rules = [ - # The public interfaces cannot reference Chromium code, so all allowances - # that the top-level DEPS file introduces are removed here. This list should - # be kept in sync with src/DEPS. - "-base", - "-build", - "-library_loaders", - "-testing", - "-third_party/icu/source/common/unicode", - "-third_party/icu/source/i18n/unicode", - "-url", -] diff --git a/ios/public/provider/components/signin/browser/profile_oauth2_token_service_ios_provider.h b/ios/public/provider/components/signin/browser/profile_oauth2_token_service_ios_provider.h new file mode 100644 index 0000000..d6f5238 --- /dev/null +++ b/ios/public/provider/components/signin/browser/profile_oauth2_token_service_ios_provider.h @@ -0,0 +1,78 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IOS_PUBLIC_PROVIDER_COMPONENTS_SIGNIN_BROWSER_PROFILE_OAUTH2_TOKEN_SERVICE_IOS_PROVIDER_H_ +#define IOS_PUBLIC_PROVIDER_COMPONENTS_SIGNIN_BROWSER_PROFILE_OAUTH2_TOKEN_SERVICE_IOS_PROVIDER_H_ + +#if defined(__OBJC__) +@class NSDate; +@class NSError; +@class NSString; +#else +class NSDate; +class NSError; +class NSString; +#endif // defined(__OBJC__) + +#include <set> +#include <string> +#include <vector> + +#include "base/callback.h" + +namespace ios { + +enum AuthenticationErrorCategory { + // Unknown errors. + kAuthenticationErrorCategoryUnknownErrors, + // Authorization errors. + kAuthenticationErrorCategoryAuthorizationErrors, + // Authorization errors with HTTP_FORBIDDEN (403) error code. + kAuthenticationErrorCategoryAuthorizationForbiddenErrors, + // Network server errors includes parsing error and should be treated as + // transient/offline errors. + kAuthenticationErrorCategoryNetworkServerErrors, + // User cancellation errors should be handled by treating them as a no-op. + kAuthenticationErrorCategoryUserCancellationErrors, + // User identity not found errors. + kAuthenticationErrorCategoryUnknownIdentityErrors, +}; + +// Interface that provides support for ProfileOAuth2TokenServiceIOS. +class ProfileOAuth2TokenServiceIOSProvider { + public: + typedef base::Callback<void(NSString* token, + NSDate* expiration, + NSError* error)> AccessTokenCallback; + + ProfileOAuth2TokenServiceIOSProvider() {}; + virtual ~ProfileOAuth2TokenServiceIOSProvider() {}; + + // Returns whether authentication is using the shared authentication library. + virtual bool IsUsingSharedAuthentication() const = 0; + + // Initializes the shared authentication library. This method should be called + // when loading credentials if the user is signed in to Chrome via the shared + // authentication library. + virtual void InitializeSharedAuthentication() = 0; + + // Returns the ids of all accounts. + virtual std::vector<std::string> GetAllAccountIds() = 0; + + // Starts fetching an access token for the account with id |account_id| with + // the given |scopes|. Once the token is obtained, |callback| is called. + virtual void GetAccessToken(const std::string& account_id, + const std::string& client_id, + const std::string& client_secret, + const std::set<std::string>& scopes, + const AccessTokenCallback& callback) = 0; + + // Returns the authentication error category of |error|. + virtual AuthenticationErrorCategory GetAuthenticationErrorCategory( + NSError* error) const = 0; +}; + +} // namespace ios + +#endif // IOS_PUBLIC_PROVIDER_COMPONENTS_SIGNIN_BROWSER_PROFILE_OAUTH2_TOKEN_SERVICE_IOS_PROVIDER_H_ |