OLD | NEW |
---|---|
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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/gaia_authenticator2.h" | 5 #include "chrome/common/net/gaia/gaia_authenticator2.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 | 8 |
9 #include "base/string_split.h" | 9 #include "base/string_split.h" |
10 #include "base/string_util.h" | 10 #include "base/string_util.h" |
(...skipping 16 matching lines...) Expand all Loading... | |
27 // static | 27 // static |
28 const char GaiaAuthenticator2::kClientLoginCaptchaFormat[] = | 28 const char GaiaAuthenticator2::kClientLoginCaptchaFormat[] = |
29 "Email=%s&" | 29 "Email=%s&" |
30 "Passwd=%s&" | 30 "Passwd=%s&" |
31 "PersistentCookie=%s&" | 31 "PersistentCookie=%s&" |
32 "accountType=%s&" | 32 "accountType=%s&" |
33 "source=%s&" | 33 "source=%s&" |
34 "service=%s&" | 34 "service=%s&" |
35 "logintoken=%s&" | 35 "logintoken=%s&" |
36 "logincaptcha=%s"; | 36 "logincaptcha=%s"; |
37 // static | |
38 const char GaiaAuthenticator2::kIssueAuthTokenFormat[] = | |
39 "SID=%s&" | |
40 "LSID=%s&" | |
41 "service=%s&" | |
42 "Session=true"; | |
37 | 43 |
38 // static | 44 // static |
39 const char GaiaAuthenticator2::kCookiePersistence[] = "true"; | 45 const char GaiaAuthenticator2::kCookiePersistence[] = "true"; |
40 // static | 46 // static |
41 const char GaiaAuthenticator2::kAccountType[] = "HOSTED_OR_GOOGLE"; | 47 const char GaiaAuthenticator2::kAccountType[] = "HOSTED_OR_GOOGLE"; |
42 // static | 48 // static |
43 const char GaiaAuthenticator2::kChromeOSSource[] = "chromeos"; | 49 const char GaiaAuthenticator2::kChromeOSSource[] = "chromeos"; |
44 // static | 50 // static |
45 // Service name for Gaia Contacts API. API is used to get user's image. | 51 // Service name for Gaia Contacts API. API is used to get user's image. |
46 const char GaiaAuthenticator2::kContactsService[] = "cp"; | 52 const char GaiaAuthenticator2::kContactsService[] = "cp"; |
47 // static | 53 // static |
48 const char GaiaAuthenticator2::kSecondFactor[] = "Info=InvalidSecondFactor"; | 54 const char GaiaAuthenticator2::kSecondFactor[] = "Info=InvalidSecondFactor"; |
49 | 55 |
50 // TODO(chron): These urls are also in auth_response_handler.h. | 56 // TODO(chron): These urls are also in auth_response_handler.h. |
51 // The URLs for different calls in the Google Accounts programmatic login API. | 57 // The URLs for different calls in the Google Accounts programmatic login API. |
52 const char GaiaAuthenticator2::kClientLoginUrl[] = | 58 const char GaiaAuthenticator2::kClientLoginUrl[] = |
53 "https://www.google.com/accounts/ClientLogin"; | 59 "https://www.google.com/accounts/ClientLogin"; |
54 const char GaiaAuthenticator2::kIssueAuthTokenUrl[] = | 60 const char GaiaAuthenticator2::kIssueAuthTokenUrl[] = |
55 "https://www.google.com/accounts/IssueAuthToken"; | 61 "https://www.google.com/accounts/IssueAuthToken"; |
56 // TODO(chron): Fix this URL not to hardcode source | |
57 // TODO(cmasone): make sure that using an http:// URL in the "continue" | |
58 // parameter here doesn't open the system up to attack long-term. | |
59 const char GaiaAuthenticator2::kTokenAuthUrl[] = | |
60 "https://www.google.com/accounts/TokenAuth?" | |
61 "continue=http://www.google.com/webhp&source=chromeos&auth="; | |
62 | 62 |
63 GaiaAuthenticator2::GaiaAuthenticator2(GaiaAuthConsumer* consumer, | 63 GaiaAuthenticator2::GaiaAuthenticator2(GaiaAuthConsumer* consumer, |
64 const std::string& source, | 64 const std::string& source, |
65 URLRequestContextGetter* getter) | 65 URLRequestContextGetter* getter) |
66 : consumer_(consumer), | 66 : consumer_(consumer), |
67 getter_(getter), | 67 getter_(getter), |
68 source_(source), | 68 source_(source), |
69 client_login_gurl_(kClientLoginUrl), | 69 client_login_gurl_(kClientLoginUrl), |
70 fetch_pending_(false){} | 70 issue_auth_token_gurl_(kIssueAuthTokenUrl), |
71 fetch_pending_(false) {} | |
71 | 72 |
72 GaiaAuthenticator2::~GaiaAuthenticator2() {} | 73 GaiaAuthenticator2::~GaiaAuthenticator2() {} |
73 | 74 |
74 bool GaiaAuthenticator2::HasPendingFetch() { | 75 bool GaiaAuthenticator2::HasPendingFetch() { |
75 return fetch_pending_; | 76 return fetch_pending_; |
76 } | 77 } |
77 | 78 |
78 void GaiaAuthenticator2::CancelRequest() { | 79 void GaiaAuthenticator2::CancelRequest() { |
79 fetcher_.reset(); | 80 fetcher_.reset(); |
80 fetch_pending_ = false; | 81 fetch_pending_ = false; |
81 } | 82 } |
82 | 83 |
83 // static | 84 // static |
84 URLFetcher* GaiaAuthenticator2::CreateClientLoginFetcher( | 85 URLFetcher* GaiaAuthenticator2::CreateGaiaFetcher( |
85 URLRequestContextGetter* getter, | 86 URLRequestContextGetter* getter, |
86 const std::string& body, | 87 const std::string& body, |
87 const GURL& client_login_gurl, | 88 const GURL& gaia_gurl, |
88 URLFetcher::Delegate* delegate) { | 89 URLFetcher::Delegate* delegate) { |
89 | 90 |
90 URLFetcher* to_return = | 91 URLFetcher* to_return = |
91 URLFetcher::Create(0, | 92 URLFetcher::Create(0, |
92 client_login_gurl, | 93 gaia_gurl, |
93 URLFetcher::POST, | 94 URLFetcher::POST, |
94 delegate); | 95 delegate); |
95 to_return->set_request_context(getter); | 96 to_return->set_request_context(getter); |
96 to_return->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES); | 97 to_return->set_load_flags(net::LOAD_DO_NOT_SEND_COOKIES); |
97 to_return->set_upload_data("application/x-www-form-urlencoded", body); | 98 to_return->set_upload_data("application/x-www-form-urlencoded", body); |
98 return to_return; | 99 return to_return; |
99 } | 100 } |
100 | 101 |
101 std::string GaiaAuthenticator2::GenerateRequestBody( | 102 // static |
103 std::string GaiaAuthenticator2::MakeClientLoginBody( | |
102 const std::string& username, | 104 const std::string& username, |
103 const std::string& password, | 105 const std::string& password, |
104 const std::string& source, | 106 const std::string& source, |
105 const char* service, | 107 const char* service, |
106 const std::string& login_token, | 108 const std::string& login_token, |
107 const std::string& login_captcha) { | 109 const std::string& login_captcha) { |
108 | 110 |
109 if (login_token.empty() || login_captcha.empty()) { | 111 if (login_token.empty() || login_captcha.empty()) { |
110 return StringPrintf(kClientLoginFormat, | 112 return StringPrintf(kClientLoginFormat, |
111 UrlEncodeString(username).c_str(), | 113 UrlEncodeString(username).c_str(), |
112 UrlEncodeString(password).c_str(), | 114 UrlEncodeString(password).c_str(), |
113 kCookiePersistence, | 115 kCookiePersistence, |
114 kAccountType, | 116 kAccountType, |
115 source.c_str(), | 117 source.c_str(), |
116 service); | 118 service); |
117 } | 119 } |
118 | 120 |
119 return StringPrintf(kClientLoginCaptchaFormat, | 121 return StringPrintf(kClientLoginCaptchaFormat, |
120 UrlEncodeString(username).c_str(), | 122 UrlEncodeString(username).c_str(), |
121 UrlEncodeString(password).c_str(), | 123 UrlEncodeString(password).c_str(), |
122 kCookiePersistence, | 124 kCookiePersistence, |
123 kAccountType, | 125 kAccountType, |
124 source.c_str(), | 126 source.c_str(), |
125 service, | 127 service, |
126 UrlEncodeString(login_token).c_str(), | 128 UrlEncodeString(login_token).c_str(), |
127 UrlEncodeString(login_captcha).c_str()); | 129 UrlEncodeString(login_captcha).c_str()); |
128 | 130 |
129 } | 131 } |
130 | 132 |
131 // Helper method that extracts tokens from a successful reply, and saves them | 133 // static |
132 // in the right fields. | 134 std::string GaiaAuthenticator2::MakeIssueAuthTokenBody( |
135 const std::string& sid, | |
136 const std::string& lsid, | |
137 const char* const service) { | |
138 | |
139 return StringPrintf(kIssueAuthTokenFormat, | |
140 UrlEncodeString(sid).c_str(), | |
141 UrlEncodeString(lsid).c_str(), | |
142 service); | |
143 } | |
144 | |
145 // Helper method that extracts tokens from a successful reply. | |
133 // static | 146 // static |
134 void GaiaAuthenticator2::ParseClientLoginResponse(const std::string& data, | 147 void GaiaAuthenticator2::ParseClientLoginResponse(const std::string& data, |
135 std::string* sid, | 148 std::string* sid, |
136 std::string* lsid, | 149 std::string* lsid, |
137 std::string* token) { | 150 std::string* token) { |
138 using std::vector; | 151 using std::vector; |
139 using std::pair; | 152 using std::pair; |
140 using std::string; | 153 using std::string; |
141 | 154 |
142 vector<pair<string, string> > tokens; | 155 vector<pair<string, string> > tokens; |
143 base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens); | 156 base::SplitStringIntoKeyValuePairs(data, '=', '\n', &tokens); |
144 for (vector<pair<string, string> >::iterator i = tokens.begin(); | 157 for (vector<pair<string, string> >::iterator i = tokens.begin(); |
145 i != tokens.end(); ++i) { | 158 i != tokens.end(); ++i) { |
146 if (i->first == "SID") { | 159 if (i->first == "SID") { |
147 sid->assign(i->second); | 160 sid->assign(i->second); |
148 } else if (i->first == "LSID") { | 161 } else if (i->first == "LSID") { |
149 lsid->assign(i->second); | 162 lsid->assign(i->second); |
150 } else if (i->first == "Auth") { | 163 } else if (i->first == "Auth") { |
151 token->assign(i->second); | 164 token->assign(i->second); |
152 } | 165 } |
153 } | 166 } |
154 } | 167 } |
155 | 168 |
156 void GaiaAuthenticator2::StartClientLogin(const std::string& username, | 169 void GaiaAuthenticator2::StartClientLogin(const std::string& username, |
157 const std::string& password, | 170 const std::string& password, |
158 const char* service, | 171 const char* const service, |
159 const std::string& login_token, | 172 const std::string& login_token, |
160 const std::string& login_captcha) { | 173 const std::string& login_captcha) { |
161 | 174 |
175 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; | |
176 | |
162 // This class is thread agnostic, so be sure to call this only on the | 177 // This class is thread agnostic, so be sure to call this only on the |
163 // same thread each time. | 178 // same thread each time. |
164 LOG(INFO) << "Starting new ClientLogin fetch."; | 179 LOG(INFO) << "Starting new ClientLogin fetch for:" << username; |
165 | 180 |
166 // Must outlive fetcher_. | 181 // Must outlive fetcher_. |
167 request_body_ = GenerateRequestBody(username, | 182 request_body_ = MakeClientLoginBody(username, |
168 password, | 183 password, |
169 source_, | 184 source_, |
170 service, | 185 service, |
171 login_token, | 186 login_token, |
172 login_captcha); | 187 login_captcha); |
173 | 188 fetcher_.reset(CreateGaiaFetcher(getter_, |
174 fetcher_.reset(CreateClientLoginFetcher(getter_, | 189 request_body_, |
175 request_body_, | 190 client_login_gurl_, |
176 client_login_gurl_, | 191 this)); |
177 this)); | |
178 fetch_pending_ = true; | 192 fetch_pending_ = true; |
179 fetcher_->Start(); | 193 fetcher_->Start(); |
180 } | 194 } |
181 | 195 |
182 void GaiaAuthenticator2::OnClientLoginFetched(const std::string& data, | 196 void GaiaAuthenticator2::StartIssueAuthToken(const std::string& sid, |
183 const URLRequestStatus& status, | 197 const std::string& lsid, |
184 int response_code) { | 198 const char* const service) { |
185 | 199 |
186 if (status.is_success() && response_code == RC_REQUEST_OK) { | 200 DCHECK(!fetch_pending_) << "Tried to fetch two things at once!"; |
187 LOG(INFO) << "ClientLogin successful!"; | |
188 std::string sid; | |
189 std::string lsid; | |
190 std::string token; | |
191 ParseClientLoginResponse(data, &sid, &lsid, &token); | |
192 consumer_->OnClientLoginSuccess( | |
193 GaiaAuthConsumer::ClientLoginResult(sid, lsid, token, data)); | |
194 return; | |
195 } | |
196 | 201 |
197 GaiaAuthConsumer::ClientLoginError error; | 202 LOG(INFO) << "Starting IssueAuthToken for: " << service; |
203 requested_service_ = service; | |
204 request_body_ = MakeIssueAuthTokenBody(sid, lsid, service); | |
205 fetcher_.reset(CreateGaiaFetcher(getter_, | |
206 request_body_, | |
207 issue_auth_token_gurl_, | |
208 this)); | |
209 fetch_pending_ = true; | |
210 fetcher_->Start(); | |
211 } | |
212 | |
213 GaiaAuthConsumer::GaiaAuthError GaiaAuthenticator2::GenerateAuthError( | |
214 const std::string& data, | |
215 const URLRequestStatus& status) { | |
216 | |
217 GaiaAuthConsumer::GaiaAuthError error; | |
198 error.data = data; | 218 error.data = data; |
199 | 219 |
200 if (!status.is_success()) { | 220 if (!status.is_success()) { |
201 if (status.status() == URLRequestStatus::CANCELED) { | 221 if (status.status() == URLRequestStatus::CANCELED) { |
202 error.code = GaiaAuthConsumer::REQUEST_CANCELED; | 222 error.code = GaiaAuthConsumer::REQUEST_CANCELED; |
203 } else { | 223 } else { |
204 error.code = GaiaAuthConsumer::NETWORK_ERROR; | 224 error.code = GaiaAuthConsumer::NETWORK_ERROR; |
205 error.network_error = status.os_error(); | 225 error.network_error = status.os_error(); |
206 LOG(WARNING) << "Could not reach Google Accounts servers: errno " | 226 LOG(WARNING) << "Could not reach Google Accounts servers: errno " |
207 << status.os_error(); | 227 << status.os_error(); |
208 } | 228 } |
209 } else { | 229 } else { |
210 if (IsSecondFactorSuccess(data)) { | 230 if (IsSecondFactorSuccess(data)) { |
211 error.code = GaiaAuthConsumer::TWO_FACTOR; | 231 error.code = GaiaAuthConsumer::TWO_FACTOR; |
212 } else { | 232 } else { |
213 error.code = GaiaAuthConsumer::PERMISSION_DENIED; | 233 error.code = GaiaAuthConsumer::PERMISSION_DENIED; |
214 } | 234 } |
215 } | 235 } |
216 | 236 |
217 consumer_->OnClientLoginFailure(error); | 237 return error; |
238 } | |
239 | |
240 void GaiaAuthenticator2::OnClientLoginFetched(const std::string& data, | |
241 const URLRequestStatus& status, | |
242 int response_code) { | |
243 | |
244 if (status.is_success() && response_code == RC_REQUEST_OK) { | |
245 LOG(INFO) << "ClientLogin successful!"; | |
246 std::string sid; | |
247 std::string lsid; | |
248 std::string token; | |
249 ParseClientLoginResponse(data, &sid, &lsid, &token); | |
250 consumer_->OnClientLoginSuccess( | |
251 GaiaAuthConsumer::ClientLoginResult(sid, lsid, token, data)); | |
252 return; | |
253 } | |
Zachary Kuznia
2010/07/06 03:33:23
Perhaps make this an "} else {" to make the flow o
| |
254 | |
255 consumer_->OnClientLoginFailure(GenerateAuthError(data, status)); | |
256 } | |
257 | |
258 void GaiaAuthenticator2::OnIssueAuthTokenFetched( | |
259 const std::string& data, | |
260 const URLRequestStatus& status, | |
261 int response_code) { | |
262 if (status.is_success() && response_code == RC_REQUEST_OK) { | |
263 // Only the bare token is returned in the body of this Gaia call | |
264 // without any padding. | |
265 consumer_->OnIssueAuthTokenSuccess(requested_service_, data); | |
266 } else { | |
267 consumer_->OnIssueAuthTokenFailure(requested_service_, | |
268 GenerateAuthError(data, status)); | |
269 } | |
218 } | 270 } |
219 | 271 |
220 void GaiaAuthenticator2::OnURLFetchComplete(const URLFetcher* source, | 272 void GaiaAuthenticator2::OnURLFetchComplete(const URLFetcher* source, |
221 const GURL& url, | 273 const GURL& url, |
222 const URLRequestStatus& status, | 274 const URLRequestStatus& status, |
223 int response_code, | 275 int response_code, |
224 const ResponseCookies& cookies, | 276 const ResponseCookies& cookies, |
225 const std::string& data) { | 277 const std::string& data) { |
226 fetch_pending_ = false; | 278 fetch_pending_ = false; |
227 if (url == client_login_gurl_) { | 279 if (url == client_login_gurl_) { |
228 OnClientLoginFetched(data, status, response_code); | 280 OnClientLoginFetched(data, status, response_code); |
229 return; | 281 } else if (url == issue_auth_token_gurl_) { |
282 OnIssueAuthTokenFetched(data, status, response_code); | |
283 } else { | |
284 NOTREACHED(); | |
230 } | 285 } |
231 NOTREACHED(); | |
232 } | 286 } |
233 | 287 |
234 // static | 288 // static |
235 bool GaiaAuthenticator2::IsSecondFactorSuccess( | 289 bool GaiaAuthenticator2::IsSecondFactorSuccess( |
236 const std::string& alleged_error) { | 290 const std::string& alleged_error) { |
237 return alleged_error.find(kSecondFactor) != | 291 return alleged_error.find(kSecondFactor) != |
238 std::string::npos; | 292 std::string::npos; |
239 } | 293 } |
OLD | NEW |