Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / identity_internals_ui.cc
1 // Copyright 2013 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 "chrome/browser/ui/webui/identity_internals_ui.h"
6
7 #include <set>
8 #include <string>
9
10 #include "base/bind.h"
11 #include "base/i18n/time_formatting.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "base/values.h"
14 #include "chrome/browser/extensions/api/identity/identity_api.h"
15 #include "chrome/browser/extensions/extension_service.h"
16 #include "chrome/browser/profiles/profile.h"
17 #include "chrome/common/url_constants.h"
18 #include "content/public/browser/web_ui.h"
19 #include "content/public/browser/web_ui_controller.h"
20 #include "content/public/browser/web_ui_data_source.h"
21 #include "content/public/browser/web_ui_message_handler.h"
22 #include "extensions/browser/extension_system.h"
23 #include "google_apis/gaia/gaia_auth_fetcher.h"
24 #include "google_apis/gaia/gaia_constants.h"
25 #include "grit/browser_resources.h"
26 #include "grit/generated_resources.h"
27 #include "ui/base/l10n/l10n_util.h"
28
29 namespace {
30
31 // Properties of the Javascript object representing a token.
32 const char kExtensionId[] = "extensionId";
33 const char kExtensionName[] = "extensionName";
34 const char kScopes[] = "scopes";
35 const char kStatus[] = "status";
36 const char kTokenExpirationTime[] = "expirationTime";
37 const char kAccessToken[] = "accessToken";
38
39 // RevokeToken message parameter offsets.
40 const int kRevokeTokenExtensionOffset = 0;
41 const int kRevokeTokenTokenOffset = 1;
42
43 class IdentityInternalsTokenRevoker;
44
45 // Class acting as a controller of the chrome://identity-internals WebUI.
46 class IdentityInternalsUIMessageHandler : public content::WebUIMessageHandler {
47  public:
48   IdentityInternalsUIMessageHandler();
49   virtual ~IdentityInternalsUIMessageHandler();
50
51   // Ensures that a proper clean up happens after a token is revoked. That
52   // includes deleting the |token_revoker|, removing the token from Identity API
53   // cache and updating the UI that the token is gone.
54   void OnTokenRevokerDone(IdentityInternalsTokenRevoker* token_revoker);
55
56   // WebUIMessageHandler implementation.
57   virtual void RegisterMessages() OVERRIDE;
58
59  private:
60   // Gets the name of an extension referred to by |token_cache_key| as a string.
61   const std::string GetExtensionName(
62       const extensions::ExtensionTokenKey& token_cache_key);
63
64   // Gets a list of scopes specified in |token_cache_key| and returns a pointer
65   // to a ListValue containing the scopes. The caller gets ownership of the
66   // returned object.
67   base::ListValue* GetScopes(
68       const extensions::ExtensionTokenKey& token_cache_key);
69
70   // Gets a localized status of the access token in |token_cache_value|.
71   const base::string16 GetStatus(
72       const extensions::IdentityTokenCacheValue& token_cache_value);
73
74   // Gets a string representation of an expiration time of the access token in
75   // |token_cache_value|.
76   const std::string GetExpirationTime(
77       const extensions::IdentityTokenCacheValue& token_cache_value);
78
79   // Converts a pair of |token_cache_key| and |token_cache_value| to a
80   // DictionaryValue object with corresponding information in a localized and
81   // readable form and returns a pointer to created object. Caller gets the
82   // ownership of the returned object.
83   base::DictionaryValue* GetInfoForToken(
84       const extensions::ExtensionTokenKey& token_cache_key,
85       const extensions::IdentityTokenCacheValue& token_cache_value);
86
87   // Gets all of the tokens stored in IdentityAPI token cache and returns them
88   // to the caller using Javascript callback function
89   // |identity_internals.returnTokens()|.
90   void GetInfoForAllTokens(const base::ListValue* args);
91
92   // Initiates revoking of the token, based on the extension ID and token
93   // passed as entries in the |args| list. Updates the caller of completion
94   // using Javascript callback function |identity_internals.tokenRevokeDone()|.
95   void RevokeToken(const base::ListValue* args);
96
97   // A vector of token revokers that are currently revoking tokens.
98   ScopedVector<IdentityInternalsTokenRevoker> token_revokers_;
99 };
100
101 // Handles the revoking of an access token and helps performing the clean up
102 // after it is revoked by holding information about the access token and related
103 // extension ID.
104 class IdentityInternalsTokenRevoker : public GaiaAuthConsumer {
105  public:
106   // Revokes |access_token| from extension with |extension_id|.
107   // |profile| is required for its request context. |consumer| will be
108   // notified when revocation succeeds via |OnTokenRevokerDone()|.
109   IdentityInternalsTokenRevoker(const std::string& extension_id,
110                                 const std::string& access_token,
111                                 Profile* profile,
112                                 IdentityInternalsUIMessageHandler* consumer);
113   virtual ~IdentityInternalsTokenRevoker();
114
115   // Returns the access token being revoked.
116   const std::string& access_token() const { return access_token_; }
117
118   // Returns the ID of the extension the access token is related to.
119   const std::string& extension_id() const { return extension_id_; }
120
121   // GaiaAuthConsumer implementation.
122   virtual void OnOAuth2RevokeTokenCompleted() OVERRIDE;
123
124  private:
125   // An object used to start a token revoke request.
126   GaiaAuthFetcher fetcher_;
127   // An ID of an extension the access token is related to.
128   const std::string extension_id_;
129   // The access token to revoke.
130   const std::string access_token_;
131   // An object that needs to be notified once the access token is revoked.
132   IdentityInternalsUIMessageHandler* consumer_;  // weak.
133
134   DISALLOW_COPY_AND_ASSIGN(IdentityInternalsTokenRevoker);
135 };
136
137 IdentityInternalsUIMessageHandler::IdentityInternalsUIMessageHandler() {}
138
139 IdentityInternalsUIMessageHandler::~IdentityInternalsUIMessageHandler() {}
140
141 void IdentityInternalsUIMessageHandler::OnTokenRevokerDone(
142     IdentityInternalsTokenRevoker* token_revoker) {
143   // Remove token from the cache.
144   extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
145       Profile::FromWebUI(web_ui()))->EraseCachedToken(
146           token_revoker->extension_id(), token_revoker->access_token());
147
148   // Update view about the token being removed.
149   base::ListValue result;
150   result.AppendString(token_revoker->access_token());
151   web_ui()->CallJavascriptFunction("identity_internals.tokenRevokeDone",
152                                    result);
153
154   // Erase the revoker.
155   ScopedVector<IdentityInternalsTokenRevoker>::iterator iter =
156       std::find(token_revokers_.begin(), token_revokers_.end(), token_revoker);
157   DCHECK(iter != token_revokers_.end());
158   token_revokers_.erase(iter);
159 }
160
161 const std::string IdentityInternalsUIMessageHandler::GetExtensionName(
162     const extensions::ExtensionTokenKey& token_cache_key) {
163   ExtensionService* extension_service = extensions::ExtensionSystem::Get(
164       Profile::FromWebUI(web_ui()))->extension_service();
165   const extensions::Extension* extension =
166       extension_service->extensions()->GetByID(token_cache_key.extension_id);
167   if (!extension)
168     return std::string();
169   return extension->name();
170 }
171
172 base::ListValue* IdentityInternalsUIMessageHandler::GetScopes(
173     const extensions::ExtensionTokenKey& token_cache_key) {
174   base::ListValue* scopes_value = new base::ListValue();
175   for (std::set<std::string>::const_iterator
176            iter = token_cache_key.scopes.begin();
177        iter != token_cache_key.scopes.end(); ++iter) {
178     scopes_value->AppendString(*iter);
179   }
180   return scopes_value;
181 }
182
183 const base::string16 IdentityInternalsUIMessageHandler::GetStatus(
184     const extensions::IdentityTokenCacheValue& token_cache_value) {
185   switch (token_cache_value.status()) {
186     case extensions::IdentityTokenCacheValue::CACHE_STATUS_ADVICE:
187       // Fallthrough to NOT FOUND case, as ADVICE is short lived.
188     case extensions::IdentityTokenCacheValue::CACHE_STATUS_NOTFOUND:
189       return l10n_util::GetStringUTF16(
190           IDS_IDENTITY_INTERNALS_TOKEN_NOT_FOUND);
191     case extensions::IdentityTokenCacheValue::CACHE_STATUS_TOKEN:
192       return l10n_util::GetStringUTF16(
193           IDS_IDENTITY_INTERNALS_TOKEN_PRESENT);
194   }
195   NOTREACHED();
196   return base::string16();
197 }
198
199 const std::string IdentityInternalsUIMessageHandler::GetExpirationTime(
200     const extensions::IdentityTokenCacheValue& token_cache_value) {
201   return base::UTF16ToUTF8(base::TimeFormatFriendlyDateAndTime(
202       token_cache_value.expiration_time()));
203 }
204
205 base::DictionaryValue* IdentityInternalsUIMessageHandler::GetInfoForToken(
206     const extensions::ExtensionTokenKey& token_cache_key,
207     const extensions::IdentityTokenCacheValue& token_cache_value) {
208   base::DictionaryValue* token_data = new base::DictionaryValue();
209   token_data->SetString(kExtensionId, token_cache_key.extension_id);
210   token_data->SetString(kExtensionName, GetExtensionName(token_cache_key));
211   token_data->Set(kScopes, GetScopes(token_cache_key));
212   token_data->SetString(kStatus, GetStatus(token_cache_value));
213   token_data->SetString(kAccessToken, token_cache_value.token());
214   token_data->SetString(kTokenExpirationTime,
215                         GetExpirationTime(token_cache_value));
216   return token_data;
217 }
218
219 void IdentityInternalsUIMessageHandler::GetInfoForAllTokens(
220     const base::ListValue* args) {
221   base::ListValue results;
222   extensions::IdentityAPI::CachedTokens tokens =
223       extensions::IdentityAPI::GetFactoryInstance()->GetForProfile(
224           Profile::FromWebUI(web_ui()))->GetAllCachedTokens();
225   for (extensions::IdentityAPI::CachedTokens::const_iterator
226            iter = tokens.begin(); iter != tokens.end(); ++iter) {
227     results.Append(GetInfoForToken(iter->first, iter->second));
228   }
229
230   web_ui()->CallJavascriptFunction("identity_internals.returnTokens", results);
231 }
232
233 void IdentityInternalsUIMessageHandler::RegisterMessages() {
234   web_ui()->RegisterMessageCallback("identityInternalsGetTokens",
235       base::Bind(&IdentityInternalsUIMessageHandler::GetInfoForAllTokens,
236                  base::Unretained(this)));
237   web_ui()->RegisterMessageCallback("identityInternalsRevokeToken",
238       base::Bind(&IdentityInternalsUIMessageHandler::RevokeToken,
239                  base::Unretained(this)));
240 }
241
242 void IdentityInternalsUIMessageHandler::RevokeToken(
243     const base::ListValue* args) {
244   std::string extension_id;
245   std::string access_token;
246   args->GetString(kRevokeTokenExtensionOffset, &extension_id);
247   args->GetString(kRevokeTokenTokenOffset, &access_token);
248   token_revokers_.push_back(new IdentityInternalsTokenRevoker(
249       extension_id, access_token, Profile::FromWebUI(web_ui()), this));
250 }
251
252 IdentityInternalsTokenRevoker::IdentityInternalsTokenRevoker(
253     const std::string& extension_id,
254     const std::string& access_token,
255     Profile* profile,
256     IdentityInternalsUIMessageHandler* consumer)
257     : fetcher_(this, GaiaConstants::kChromeSource,
258                profile->GetRequestContext()),
259       extension_id_(extension_id),
260       access_token_(access_token),
261       consumer_(consumer) {
262   DCHECK(consumer_);
263   fetcher_.StartRevokeOAuth2Token(access_token);
264 }
265
266 IdentityInternalsTokenRevoker::~IdentityInternalsTokenRevoker() {}
267
268 void IdentityInternalsTokenRevoker::OnOAuth2RevokeTokenCompleted() {
269   consumer_->OnTokenRevokerDone(this);
270 }
271
272 }  // namespace
273
274 IdentityInternalsUI::IdentityInternalsUI(content::WebUI* web_ui)
275   : content::WebUIController(web_ui) {
276   // chrome://identity-internals source.
277   content::WebUIDataSource* html_source =
278     content::WebUIDataSource::Create(chrome::kChromeUIIdentityInternalsHost);
279   html_source->SetUseJsonJSFormatV2();
280
281   // Localized strings
282   html_source->AddLocalizedString("tokenCacheHeader",
283       IDS_IDENTITY_INTERNALS_TOKEN_CACHE_TEXT);
284   html_source->AddLocalizedString("accessToken",
285       IDS_IDENTITY_INTERNALS_ACCESS_TOKEN);
286   html_source->AddLocalizedString("extensionName",
287       IDS_IDENTITY_INTERNALS_EXTENSION_NAME);
288   html_source->AddLocalizedString("extensionId",
289       IDS_IDENTITY_INTERNALS_EXTENSION_ID);
290   html_source->AddLocalizedString("tokenStatus",
291       IDS_IDENTITY_INTERNALS_TOKEN_STATUS);
292   html_source->AddLocalizedString("expirationTime",
293       IDS_IDENTITY_INTERNALS_EXPIRATION_TIME);
294   html_source->AddLocalizedString("scopes",
295       IDS_IDENTITY_INTERNALS_SCOPES);
296   html_source->AddLocalizedString("revoke",
297       IDS_IDENTITY_INTERNALS_REVOKE);
298   html_source->SetJsonPath("strings.js");
299
300   // Required resources
301   html_source->AddResourcePath("identity_internals.css",
302       IDR_IDENTITY_INTERNALS_CSS);
303   html_source->AddResourcePath("identity_internals.js",
304       IDR_IDENTITY_INTERNALS_JS);
305   html_source->SetDefaultResource(IDR_IDENTITY_INTERNALS_HTML);
306
307   content::WebUIDataSource::Add(Profile::FromWebUI(web_ui), html_source);
308
309   web_ui->AddMessageHandler(new IdentityInternalsUIMessageHandler());
310 }
311
312 IdentityInternalsUI::~IdentityInternalsUI() {}