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

Side by Side Diff: chrome/common/net/gaia/oauth2_mint_token_flow.cc

Issue 10012051: Add a mode to OAuth2MintTokenFlow that fetches the messages to show to the user. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 8 years, 8 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/common/net/gaia/oauth2_mint_token_flow.h" 5 #include "chrome/common/net/gaia/oauth2_mint_token_flow.h"
6 6
7 #include <string> 7 #include <string>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/basictypes.h" 10 #include "base/basictypes.h"
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/command_line.h" 12 #include "base/command_line.h"
13 #include "base/json/json_reader.h"
13 #include "base/message_loop.h" 14 #include "base/message_loop.h"
15 #include "base/string_util.h"
16 #include "base/stringprintf.h"
17 #include "base/values.h"
14 #include "chrome/common/chrome_switches.h" 18 #include "chrome/common/chrome_switches.h"
15 #include "chrome/common/net/gaia/gaia_urls.h" 19 #include "chrome/common/net/gaia/gaia_urls.h"
16 #include "chrome/common/net/gaia/google_service_auth_error.h" 20 #include "chrome/common/net/gaia/google_service_auth_error.h"
21 #include "content/public/common/url_fetcher.h"
22 #include "net/base/escape.h"
23 #include "net/url_request/url_request_context_getter.h"
24 #include "net/url_request/url_request_status.h"
17 25
26 using content::URLFetcher;
18 using net::URLRequestContextGetter; 27 using net::URLRequestContextGetter;
28 using net::URLRequestStatus;
19 29
20 namespace { 30 namespace {
21 31
32 static const char kForceValueFalse[] = "false";
33 static const char kForceValueTrue[] = "true";
34 static const char kResponseTypeValueNone[] = "none";
35 static const char kResponseTypeValueToken[] = "token";
36
37 static const char kOAuth2IssueTokenBodyFormat[] =
38 "force=%s"
39 "&response_type=%s"
40 "&scope=%s"
41 "&client_id=%s"
42 "&origin=%s";
43 static const char kIssueAdviceKey[] = "issueAdvice";
44 static const char kIssueAdviceValueAuto[] = "auto";
45 static const char kIssueAdviceValueConsent[] = "consent";
46 static const char kAccessTokenKey[] = "token";
47 static const char kConsentKey[] = "consent";
48 static const char kScopesKey[] = "scopes";
49 static const char kDescriptionKey[] = "description";
50 static const char kDetailKey[] = "detail";
51 static const char kDetailSeparators[] = "\n";
52
53 static GoogleServiceAuthError CreateAuthError(URLRequestStatus status) {
54 CHECK(!status.is_success());
55 if (status.status() == URLRequestStatus::CANCELED) {
56 return GoogleServiceAuthError(GoogleServiceAuthError::REQUEST_CANCELED);
57 } else {
58 DLOG(WARNING) << "Could not reach Google Accounts servers: errno "
59 << status.error();
60 return GoogleServiceAuthError::FromConnectionError(status.error());
61 }
62 }
63
22 OAuth2MintTokenFlow::InterceptorForTests* g_interceptor_for_tests = NULL; 64 OAuth2MintTokenFlow::InterceptorForTests* g_interceptor_for_tests = NULL;
23 65
24 } // namespace 66 } // namespace
25 67
26 // static 68 // static
27 void OAuth2MintTokenFlow::SetInterceptorForTests( 69 void OAuth2MintTokenFlow::SetInterceptorForTests(
28 OAuth2MintTokenFlow::InterceptorForTests* interceptor) { 70 OAuth2MintTokenFlow::InterceptorForTests* interceptor) {
29 CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)); 71 CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType));
30 CHECK(NULL == g_interceptor_for_tests); // Only one at a time. 72 CHECK(NULL == g_interceptor_for_tests); // Only one at a time.
31 g_interceptor_for_tests = interceptor; 73 g_interceptor_for_tests = interceptor;
32 } 74 }
33 75
34 OAuth2MintTokenFlow::OAuth2MintTokenFlow( 76 OAuth2MintTokenFlow::OAuth2MintTokenFlow(
35 URLRequestContextGetter* context, 77 URLRequestContextGetter* context,
36 Delegate* delegate) 78 Delegate* delegate,
37 : context_(context), 79 const Parameters& parameters)
80 : OAuth2ApiCallFlow(
81 context, parameters.login_refresh_token,
82 "", std::vector<std::string>()),
83 context_(context),
38 delegate_(delegate), 84 delegate_(delegate),
39 state_(INITIAL) { 85 parameters_(parameters) {
40 } 86 }
41 87
42 OAuth2MintTokenFlow::~OAuth2MintTokenFlow() { } 88 OAuth2MintTokenFlow::~OAuth2MintTokenFlow() { }
43 89
44 void OAuth2MintTokenFlow::Start( 90 void OAuth2MintTokenFlow::Start() {
45 const std::string& login_refresh_token,
46 const std::string& extension_id,
47 const std::string& client_id,
48 const std::vector<std::string>& scopes) {
49 login_refresh_token_ = login_refresh_token;
50 extension_id_ = extension_id;
51 client_id_ = client_id;
52 scopes_ = scopes;
53
54 if (g_interceptor_for_tests) { 91 if (g_interceptor_for_tests) {
55 std::string auth_token; 92 std::string auth_token;
56 GoogleServiceAuthError error = GoogleServiceAuthError::None(); 93 GoogleServiceAuthError error = GoogleServiceAuthError::None();
57 94
58 // We use PostTask, instead of calling the delegate directly, because the 95 // We use PostTask, instead of calling the delegate directly, because the
59 // message loop will run a few times before we notify the delegate in the 96 // message loop will run a few times before we notify the delegate in the
60 // real implementation. 97 // real implementation.
61 if (g_interceptor_for_tests->DoIntercept(this, &auth_token, &error)) { 98 if (g_interceptor_for_tests->DoIntercept(this, &auth_token, &error)) {
62 MessageLoop::current()->PostTask( 99 MessageLoop::current()->PostTask(
63 FROM_HERE, 100 FROM_HERE,
64 base::Bind(&OAuth2MintTokenFlow::Delegate::OnMintTokenSuccess, 101 base::Bind(&OAuth2MintTokenFlow::Delegate::OnMintTokenSuccess,
65 base::Unretained(delegate_), auth_token)); 102 base::Unretained(delegate_), auth_token));
66 } else { 103 } else {
67 MessageLoop::current()->PostTask( 104 MessageLoop::current()->PostTask(
68 FROM_HERE, 105 FROM_HERE,
69 base::Bind(&OAuth2MintTokenFlow::Delegate::OnMintTokenFailure, 106 base::Bind(&OAuth2MintTokenFlow::Delegate::OnMintTokenFailure,
70 base::Unretained(delegate_), error)); 107 base::Unretained(delegate_), error));
71 } 108 }
72 return; 109 return;
73 } 110 }
74 111
75 BeginGetLoginAccessToken(); 112 OAuth2ApiCallFlow::Start();
76 } 113 }
77 114
78 void OAuth2MintTokenFlow::OnGetTokenSuccess( 115 void OAuth2MintTokenFlow::ReportSuccess(const std::string& access_token) {
79 const std::string& access_token) { 116 if (delegate_) {
80 login_access_token_ = access_token; 117 delegate_->OnMintTokenSuccess(access_token);
81 EndGetLoginAccessToken(NULL);
82 }
83
84 void OAuth2MintTokenFlow::OnGetTokenFailure(
85 const GoogleServiceAuthError& error) {
86 EndGetLoginAccessToken(&error);
87 }
88
89 void OAuth2MintTokenFlow::BeginGetLoginAccessToken() {
90 CHECK_EQ(INITIAL, state_);
91 state_ = FETCH_LOGIN_ACCESS_TOKEN_STARTED;
92
93 oauth2_access_token_fetcher_.reset(CreateAccessTokenFetcher());
94 oauth2_access_token_fetcher_->Start(
95 GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
96 GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
97 login_refresh_token_,
98 std::vector<std::string>());
99 }
100
101 void OAuth2MintTokenFlow::EndGetLoginAccessToken(
102 const GoogleServiceAuthError* error) {
103 CHECK_EQ(FETCH_LOGIN_ACCESS_TOKEN_STARTED, state_);
104 if (!error) {
105 state_ = FETCH_LOGIN_ACCESS_TOKEN_DONE;
106 BeginMintAccessToken();
107 } else {
108 state_ = ERROR_STATE;
109 ReportFailure(*error);
110 } 118 }
111 } 119 }
112 120
113 void OAuth2MintTokenFlow::OnMintTokenSuccess( 121 void OAuth2MintTokenFlow::ReportSuccess(const IssueAdviceInfo& issue_advice) {
114 const std::string& access_token) {
115 app_access_token_ = access_token;
116 EndMintAccessToken(NULL);
117 }
118 void OAuth2MintTokenFlow::OnMintTokenFailure(
119 const GoogleServiceAuthError& error) {
120 EndMintAccessToken(&error);
121 }
122
123 void OAuth2MintTokenFlow::BeginMintAccessToken() {
124 CHECK_EQ(FETCH_LOGIN_ACCESS_TOKEN_DONE, state_);
125 state_ = MINT_ACCESS_TOKEN_STARTED;
126
127 oauth2_mint_token_fetcher_.reset(CreateMintTokenFetcher());
128 oauth2_mint_token_fetcher_->Start(
129 login_access_token_,
130 client_id_,
131 scopes_,
132 extension_id_);
133 }
134
135 void OAuth2MintTokenFlow::EndMintAccessToken(
136 const GoogleServiceAuthError* error) {
137 CHECK_EQ(MINT_ACCESS_TOKEN_STARTED, state_);
138
139 if (!error) {
140 state_ = MINT_ACCESS_TOKEN_DONE;
141 ReportSuccess();
142 } else {
143 state_ = ERROR_STATE;
144 ReportFailure(*error);
145 }
146 }
147
148 void OAuth2MintTokenFlow::ReportSuccess() {
149 CHECK_EQ(MINT_ACCESS_TOKEN_DONE, state_);
150
151 if (delegate_) { 122 if (delegate_) {
152 delegate_->OnMintTokenSuccess(app_access_token_); 123 delegate_->OnIssueAdviceSuccess(issue_advice);
153 } 124 }
154 } 125 }
155 126
156 void OAuth2MintTokenFlow::ReportFailure( 127 void OAuth2MintTokenFlow::ReportFailure(
157 const GoogleServiceAuthError& error) { 128 const GoogleServiceAuthError& error) {
158 CHECK_EQ(ERROR_STATE, state_);
159
160 if (delegate_) { 129 if (delegate_) {
161 delegate_->OnMintTokenFailure(error); 130 delegate_->OnMintTokenFailure(error);
162 } 131 }
163 } 132 }
164 133
165 OAuth2AccessTokenFetcher* OAuth2MintTokenFlow::CreateAccessTokenFetcher() { 134 GURL OAuth2MintTokenFlow::CreateApiCallUrl() {
166 return new OAuth2AccessTokenFetcher(this, context_); 135 return GURL(GaiaUrls::GetInstance()->oauth2_issue_token_url());
167 } 136 }
168 137
169 OAuth2MintTokenFetcher* OAuth2MintTokenFlow::CreateMintTokenFetcher() { 138 std::string OAuth2MintTokenFlow::CreateApiCallBody() {
170 return new OAuth2MintTokenFetcher(this, context_, "OAuth2MintTokenFlow"); 139 const char* force_value =
140 (parameters_.mode == MODE_MINT_TOKEN_FORCE ||
141 parameters_.mode == MODE_RECORD_GRANT)
142 ? kForceValueTrue : kForceValueFalse;
143 const char* response_type_value =
144 (parameters_.mode == MODE_MINT_TOKEN_NO_FORCE ||
145 parameters_.mode == MODE_MINT_TOKEN_FORCE)
146 ? kResponseTypeValueToken : kResponseTypeValueNone;
147 return StringPrintf(
148 kOAuth2IssueTokenBodyFormat,
149 net::EscapeUrlEncodedData(force_value, true).c_str(),
150 net::EscapeUrlEncodedData(response_type_value, true).c_str(),
151 net::EscapeUrlEncodedData(
152 JoinString(parameters_.scopes, ' '), true).c_str(),
153 net::EscapeUrlEncodedData(parameters_.client_id, true).c_str(),
154 net::EscapeUrlEncodedData(parameters_.extension_id, true).c_str());
171 } 155 }
156
157 void OAuth2MintTokenFlow::ProcessApiCallSuccess(
158 const content::URLFetcher* source) {
159 // TODO(munjal): Change error code paths in this method to report an
160 // internal error.
161 scoped_ptr<base::DictionaryValue> dict(ParseResponse(source));
162 if (!dict.get()) {
163 ReportFailure(GoogleServiceAuthError::FromConnectionError(101));
164 return;
165 }
166 std::string issue_advice;
167 if (!dict->GetString(kIssueAdviceKey, &issue_advice)) {
168 ReportFailure(GoogleServiceAuthError::FromConnectionError(101));
169 return;
170 }
171 if (issue_advice == kIssueAdviceValueConsent) {
172 IssueAdviceInfo issue_advice;
173 if (ParseIssueAdviceResponse(dict.get(), &issue_advice))
174 ReportSuccess(issue_advice);
175 else
176 ReportFailure(GoogleServiceAuthError::FromConnectionError(101));
177 } else {
178 std::string access_token;
179 if (ParseMintTokenResponse(dict.get(), &access_token))
180 ReportSuccess(access_token);
181 else
182 ReportFailure(GoogleServiceAuthError::FromConnectionError(101));
183 }
184 }
185
186 void OAuth2MintTokenFlow::ProcessApiCallFailure(
187 const content::URLFetcher* source) {
188 ReportFailure(CreateAuthError(source->GetStatus()));
189 }
190 void OAuth2MintTokenFlow::ProcessNewAccessToken(
191 const std::string& access_token) {
192 // We don't currently store new access tokens. We generate one every time.
193 // So we have nothing to do here.
194 return;
195 }
196 void OAuth2MintTokenFlow::ProcessMintAccessTokenFailure(
197 const GoogleServiceAuthError& error) {
198 ReportFailure(error);
199 }
200
201 // static
202 base::DictionaryValue* OAuth2MintTokenFlow::ParseResponse(
203 const URLFetcher* url_fetcher) {
204 CHECK(url_fetcher);
205 std::string response_body;
206 url_fetcher->GetResponseAsString(&response_body);
207 base::JSONReader reader;
208 scoped_ptr<base::Value> value(reader.Read(response_body, false));
209 if (!value.get() || value->GetType() != Value::TYPE_DICTIONARY)
210 return NULL;
211
212 return static_cast<base::DictionaryValue*>(value.release());
asargent_no_longer_on_chrome 2012/04/10 22:47:25 nit: I think you can use Value::GetAsDictionary he
Munjal (Google) 2012/04/10 23:15:35 Done. Note that it did not simplify a lot of the
213 }
214
215 // static
216 bool OAuth2MintTokenFlow::ParseMintTokenResponse(
217 const base::DictionaryValue* dict, std::string* access_token) {
218 CHECK(dict);
219 CHECK(access_token);
220 return dict->GetString(kAccessTokenKey, access_token);
221 }
222
223 // static
224 bool OAuth2MintTokenFlow::ParseIssueAdviceResponse(
225 const base::DictionaryValue* dict, IssueAdviceInfo* issue_advice) {
226 CHECK(dict);
227 CHECK(issue_advice);
228
229 base::DictionaryValue* consent_dict = NULL;
230 if (!dict->GetDictionary(kConsentKey, &consent_dict))
231 return false;
232
233 base::ListValue* scopes_list = NULL;
234 if (!consent_dict->GetList(kScopesKey, &scopes_list))
235 return false;
236
237 bool success = true;
238 for (size_t index = 0; index < scopes_list->GetSize(); ++index) {
239 base::DictionaryValue* scopes_entry = NULL;
240 if (!scopes_list->GetDictionary(index, &scopes_entry)) {
241 success = false;
242 break;
243 }
244 IssueAdviceInfoEntry entry;
245 if (!scopes_entry->GetString(kDescriptionKey, &entry.description)) {
246 success = false;
247 break;
248 }
249 std::string detail;
250 if (!scopes_entry->GetString(kDetailKey, &detail)) {
251 success = false;
252 break;
253 }
254
255 Tokenize(detail, kDetailSeparators, &entry.details);
256 issue_advice->push_back(entry);
257 }
258
259 if (!success)
260 issue_advice->clear();
261
262 return success;
263 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698