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.
5 #include "extensions/shell/browser/api/identity/identity_api.h"
10 #include "base/guid.h"
11 #include "content/public/browser/browser_context.h"
12 #include "extensions/common/manifest_handlers/oauth2_manifest_handler.h"
13 #include "extensions/shell/browser/shell_oauth2_token_service.h"
14 #include "extensions/shell/common/api/identity.h"
15 #include "google_apis/gaia/gaia_auth_util.h"
17 namespace extensions
{
21 const char kIdentityApiId
[] = "identity_api";
22 const char kErrorNoUserAccount
[] = "No user account.";
23 const char kErrorNoRefreshToken
[] = "No refresh token.";
24 const char kErrorNoScopesInManifest
[] = "No scopes in manifest.";
25 const char kErrorUserPermissionRequired
[] =
26 "User permission required but not available in app_shell";
29 IdentityAPI::IdentityAPI(content::BrowserContext
* context
)
30 : device_id_(base::GenerateGUID()) {
33 IdentityAPI::~IdentityAPI() {
37 IdentityAPI
* IdentityAPI::Get(content::BrowserContext
* context
) {
38 return BrowserContextKeyedAPIFactory
<IdentityAPI
>::Get(context
);
42 BrowserContextKeyedAPIFactory
<IdentityAPI
>* IdentityAPI::GetFactoryInstance() {
43 static base::LazyInstance
<BrowserContextKeyedAPIFactory
<IdentityAPI
>>
44 factory
= LAZY_INSTANCE_INITIALIZER
;
45 return factory
.Pointer();
48 ///////////////////////////////////////////////////////////////////////////////
50 IdentityGetAuthTokenFunction::IdentityGetAuthTokenFunction()
51 : OAuth2TokenService::Consumer(kIdentityApiId
) {
54 IdentityGetAuthTokenFunction::~IdentityGetAuthTokenFunction() {
57 void IdentityGetAuthTokenFunction::SetMintTokenFlowForTesting(
58 OAuth2MintTokenFlow
* flow
) {
59 mint_token_flow_
.reset(flow
);
62 ExtensionFunction::ResponseAction
IdentityGetAuthTokenFunction::Run() {
63 scoped_ptr
<api::identity::GetAuthToken::Params
> params(
64 api::identity::GetAuthToken::Params::Create(*args_
));
65 EXTENSION_FUNCTION_VALIDATE(params
.get());
67 ShellOAuth2TokenService
* service
= ShellOAuth2TokenService::GetInstance();
68 std::string account_id
= service
->AccountId();
69 if (account_id
.empty())
70 return RespondNow(Error(kErrorNoUserAccount
));
72 if (!service
->RefreshTokenIsAvailable(account_id
))
73 return RespondNow(Error(kErrorNoRefreshToken
));
75 // Verify that we have scopes.
76 const OAuth2Info
& oauth2_info
= OAuth2Info::GetOAuth2Info(extension());
77 if (oauth2_info
.scopes
.empty())
78 return RespondNow(Error(kErrorNoScopesInManifest
));
80 // Balanced in OnGetTokenFailure() and in the OAuth2MintTokenFlow callbacks.
83 // First, fetch a logged-in-user access token for the Chrome project client ID
84 // and client secret. This token is used later to get a second access token
85 // that will be returned to the app.
86 std::set
<std::string
> no_scopes
;
87 access_token_request_
=
88 service
->StartRequest(service
->AccountId(), no_scopes
, this);
89 return RespondLater();
92 void IdentityGetAuthTokenFunction::OnGetTokenSuccess(
93 const OAuth2TokenService::Request
* request
,
94 const std::string
& access_token
,
95 const base::Time
& expiration_time
) {
96 // Tests may override the mint token flow.
97 if (!mint_token_flow_
) {
98 const OAuth2Info
& oauth2_info
= OAuth2Info::GetOAuth2Info(extension());
99 DCHECK(!oauth2_info
.scopes
.empty());
101 mint_token_flow_
.reset(new OAuth2MintTokenFlow(
103 OAuth2MintTokenFlow::Parameters(
105 oauth2_info
.client_id
,
107 IdentityAPI::Get(browser_context())->device_id(),
108 OAuth2MintTokenFlow::MODE_MINT_TOKEN_FORCE
)));
111 // Use the logging-in-user access token to mint an access token for this app.
112 mint_token_flow_
->Start(browser_context()->GetRequestContext(), access_token
);
115 void IdentityGetAuthTokenFunction::OnGetTokenFailure(
116 const OAuth2TokenService::Request
* request
,
117 const GoogleServiceAuthError
& error
) {
118 Respond(Error(error
.ToString()));
119 Release(); // Balanced in Run().
122 void IdentityGetAuthTokenFunction::OnMintTokenSuccess(
123 const std::string
& access_token
,
125 Respond(OneArgument(new base::StringValue(access_token
)));
126 Release(); // Balanced in Run().
129 void IdentityGetAuthTokenFunction::OnIssueAdviceSuccess(
130 const IssueAdviceInfo
& issue_advice
) {
131 Respond(Error(kErrorUserPermissionRequired
));
132 Release(); // Balanced in Run().
135 void IdentityGetAuthTokenFunction::OnMintTokenFailure(
136 const GoogleServiceAuthError
& error
) {
137 Respond(Error(error
.ToString()));
138 Release(); // Balanced in Run().
141 ///////////////////////////////////////////////////////////////////////////////
143 IdentityRemoveCachedAuthTokenFunction::IdentityRemoveCachedAuthTokenFunction() {
146 IdentityRemoveCachedAuthTokenFunction::
147 ~IdentityRemoveCachedAuthTokenFunction() {
150 ExtensionFunction::ResponseAction
IdentityRemoveCachedAuthTokenFunction::Run() {
151 scoped_ptr
<api::identity::RemoveCachedAuthToken::Params
> params(
152 api::identity::RemoveCachedAuthToken::Params::Create(*args_
));
153 EXTENSION_FUNCTION_VALIDATE(params
.get());
154 // This stub identity API does not maintain a token cache, so there is nothing
156 return RespondNow(NoArguments());
160 } // namespace extensions