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

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
68 IssueAdviceInfoEntry::IssueAdviceInfoEntry() {}
69 IssueAdviceInfoEntry::~IssueAdviceInfoEntry() {}
70
71 bool IssueAdviceInfoEntry::operator ==(const IssueAdviceInfoEntry& rhs) const {
72 return description == rhs.description && details == rhs.details;
73 }
74
75 OAuth2MintTokenFlow::Parameters::Parameters() : mode(MODE_ISSUE_ADVICE) {}
76
77 OAuth2MintTokenFlow::Parameters::Parameters(
78 const std::string& rt,
79 const std::string& eid,
80 const std::string& cid,
81 const std::vector<std::string>& scopes_arg,
82 Mode mode_arg)
83 : login_refresh_token(rt),
84 extension_id(eid),
85 client_id(cid),
86 scopes(scopes_arg),
87 mode(mode_arg) {
88 }
89
90 OAuth2MintTokenFlow::Parameters::~Parameters() {}
91
26 // static 92 // static
27 void OAuth2MintTokenFlow::SetInterceptorForTests( 93 void OAuth2MintTokenFlow::SetInterceptorForTests(
28 OAuth2MintTokenFlow::InterceptorForTests* interceptor) { 94 OAuth2MintTokenFlow::InterceptorForTests* interceptor) {
29 CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType)); 95 CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kTestType));
30 CHECK(NULL == g_interceptor_for_tests); // Only one at a time. 96 CHECK(NULL == g_interceptor_for_tests); // Only one at a time.
31 g_interceptor_for_tests = interceptor; 97 g_interceptor_for_tests = interceptor;
32 } 98 }
33 99
34 OAuth2MintTokenFlow::OAuth2MintTokenFlow( 100 OAuth2MintTokenFlow::OAuth2MintTokenFlow(
35 URLRequestContextGetter* context, 101 URLRequestContextGetter* context,
36 Delegate* delegate) 102 Delegate* delegate,
37 : context_(context), 103 const Parameters& parameters)
104 : OAuth2ApiCallFlow(
105 context, parameters.login_refresh_token,
106 "", std::vector<std::string>()),
107 context_(context),
38 delegate_(delegate), 108 delegate_(delegate),
39 state_(INITIAL) { 109 parameters_(parameters) {
40 } 110 }
41 111
42 OAuth2MintTokenFlow::~OAuth2MintTokenFlow() { } 112 OAuth2MintTokenFlow::~OAuth2MintTokenFlow() { }
43 113
44 void OAuth2MintTokenFlow::Start( 114 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) { 115 if (g_interceptor_for_tests) {
55 std::string auth_token; 116 std::string auth_token;
56 GoogleServiceAuthError error = GoogleServiceAuthError::None(); 117 GoogleServiceAuthError error = GoogleServiceAuthError::None();
57 118
58 // We use PostTask, instead of calling the delegate directly, because the 119 // 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 120 // message loop will run a few times before we notify the delegate in the
60 // real implementation. 121 // real implementation.
61 if (g_interceptor_for_tests->DoIntercept(this, &auth_token, &error)) { 122 if (g_interceptor_for_tests->DoIntercept(this, &auth_token, &error)) {
62 MessageLoop::current()->PostTask( 123 MessageLoop::current()->PostTask(
63 FROM_HERE, 124 FROM_HERE,
64 base::Bind(&OAuth2MintTokenFlow::Delegate::OnMintTokenSuccess, 125 base::Bind(&OAuth2MintTokenFlow::Delegate::OnMintTokenSuccess,
65 base::Unretained(delegate_), auth_token)); 126 base::Unretained(delegate_), auth_token));
66 } else { 127 } else {
67 MessageLoop::current()->PostTask( 128 MessageLoop::current()->PostTask(
68 FROM_HERE, 129 FROM_HERE,
69 base::Bind(&OAuth2MintTokenFlow::Delegate::OnMintTokenFailure, 130 base::Bind(&OAuth2MintTokenFlow::Delegate::OnMintTokenFailure,
70 base::Unretained(delegate_), error)); 131 base::Unretained(delegate_), error));
71 } 132 }
72 return; 133 return;
73 } 134 }
74 135
75 BeginGetLoginAccessToken(); 136 OAuth2ApiCallFlow::Start();
76 } 137 }
77 138
78 void OAuth2MintTokenFlow::OnGetTokenSuccess( 139 void OAuth2MintTokenFlow::ReportSuccess(const std::string& access_token) {
79 const std::string& access_token) { 140 if (delegate_) {
80 login_access_token_ = access_token; 141 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 } 142 }
111 } 143 }
112 144
113 void OAuth2MintTokenFlow::OnMintTokenSuccess( 145 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_) { 146 if (delegate_) {
152 delegate_->OnMintTokenSuccess(app_access_token_); 147 delegate_->OnIssueAdviceSuccess(issue_advice);
153 } 148 }
154 } 149 }
155 150
156 void OAuth2MintTokenFlow::ReportFailure( 151 void OAuth2MintTokenFlow::ReportFailure(
157 const GoogleServiceAuthError& error) { 152 const GoogleServiceAuthError& error) {
158 CHECK_EQ(ERROR_STATE, state_);
159
160 if (delegate_) { 153 if (delegate_) {
161 delegate_->OnMintTokenFailure(error); 154 delegate_->OnMintTokenFailure(error);
162 } 155 }
163 } 156 }
164 157
165 OAuth2AccessTokenFetcher* OAuth2MintTokenFlow::CreateAccessTokenFetcher() { 158 GURL OAuth2MintTokenFlow::CreateApiCallUrl() {
166 return new OAuth2AccessTokenFetcher(this, context_); 159 return GURL(GaiaUrls::GetInstance()->oauth2_issue_token_url());
167 } 160 }
168 161
169 OAuth2MintTokenFetcher* OAuth2MintTokenFlow::CreateMintTokenFetcher() { 162 std::string OAuth2MintTokenFlow::CreateApiCallBody() {
170 return new OAuth2MintTokenFetcher(this, context_, "OAuth2MintTokenFlow"); 163 const char* force_value =
164 (parameters_.mode == MODE_MINT_TOKEN_FORCE ||
165 parameters_.mode == MODE_RECORD_GRANT)
166 ? kForceValueTrue : kForceValueFalse;
167 const char* response_type_value =
168 (parameters_.mode == MODE_MINT_TOKEN_NO_FORCE ||
169 parameters_.mode == MODE_MINT_TOKEN_FORCE)
170 ? kResponseTypeValueToken : kResponseTypeValueNone;
171 return StringPrintf(
172 kOAuth2IssueTokenBodyFormat,
173 net::EscapeUrlEncodedData(force_value, true).c_str(),
174 net::EscapeUrlEncodedData(response_type_value, true).c_str(),
175 net::EscapeUrlEncodedData(
176 JoinString(parameters_.scopes, ' '), true).c_str(),
177 net::EscapeUrlEncodedData(parameters_.client_id, true).c_str(),
178 net::EscapeUrlEncodedData(parameters_.extension_id, true).c_str());
171 } 179 }
180
181 void OAuth2MintTokenFlow::ProcessApiCallSuccess(
182 const content::URLFetcher* source) {
183 // TODO(munjal): Change error code paths in this method to report an
184 // internal error.
185 std::string response_body;
186 source->GetResponseAsString(&response_body);
187 base::JSONReader reader;
188 scoped_ptr<base::Value> value(reader.Read(response_body, false));
189 DictionaryValue* dict = NULL;
190 if (!value.get() || !value->GetAsDictionary(&dict)) {
191 ReportFailure(GoogleServiceAuthError::FromConnectionError(101));
192 return;
193 }
194
195 std::string issue_advice;
196 if (!dict->GetString(kIssueAdviceKey, &issue_advice)) {
197 ReportFailure(GoogleServiceAuthError::FromConnectionError(101));
198 return;
199 }
200 if (issue_advice == kIssueAdviceValueConsent) {
201 IssueAdviceInfo issue_advice;
202 if (ParseIssueAdviceResponse(dict, &issue_advice))
203 ReportSuccess(issue_advice);
204 else
205 ReportFailure(GoogleServiceAuthError::FromConnectionError(101));
206 } else {
207 std::string access_token;
208 if (ParseMintTokenResponse(dict, &access_token))
209 ReportSuccess(access_token);
210 else
211 ReportFailure(GoogleServiceAuthError::FromConnectionError(101));
212 }
213 }
214
215 void OAuth2MintTokenFlow::ProcessApiCallFailure(
216 const content::URLFetcher* source) {
217 ReportFailure(CreateAuthError(source->GetStatus()));
218 }
219 void OAuth2MintTokenFlow::ProcessNewAccessToken(
220 const std::string& access_token) {
221 // We don't currently store new access tokens. We generate one every time.
222 // So we have nothing to do here.
223 return;
224 }
225 void OAuth2MintTokenFlow::ProcessMintAccessTokenFailure(
226 const GoogleServiceAuthError& error) {
227 ReportFailure(error);
228 }
229
230 // static
231 bool OAuth2MintTokenFlow::ParseMintTokenResponse(
232 const base::DictionaryValue* dict, std::string* access_token) {
233 CHECK(dict);
234 CHECK(access_token);
235 return dict->GetString(kAccessTokenKey, access_token);
236 }
237
238 // static
239 bool OAuth2MintTokenFlow::ParseIssueAdviceResponse(
240 const base::DictionaryValue* dict, IssueAdviceInfo* issue_advice) {
241 CHECK(dict);
242 CHECK(issue_advice);
243
244 base::DictionaryValue* consent_dict = NULL;
245 if (!dict->GetDictionary(kConsentKey, &consent_dict))
246 return false;
247
248 base::ListValue* scopes_list = NULL;
249 if (!consent_dict->GetList(kScopesKey, &scopes_list))
250 return false;
251
252 bool success = true;
253 for (size_t index = 0; index < scopes_list->GetSize(); ++index) {
254 base::DictionaryValue* scopes_entry = NULL;
255 IssueAdviceInfoEntry entry;
256 std::string detail;
257 if (!scopes_list->GetDictionary(index, &scopes_entry) ||
258 !scopes_entry->GetString(kDescriptionKey, &entry.description) ||
259 !scopes_entry->GetString(kDetailKey, &detail)) {
260 success = false;
261 break;
262 }
263
264 Tokenize(detail, kDetailSeparators, &entry.details);
265 issue_advice->push_back(entry);
266 }
267
268 if (!success)
269 issue_advice->clear();
270
271 return success;
272 }
OLDNEW
« no previous file with comments | « chrome/common/net/gaia/oauth2_mint_token_flow.h ('k') | chrome/common/net/gaia/oauth2_mint_token_flow_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698