Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / google_apis / gaia / fake_gaia.cc
blob6749393faa85d08bf7d20421cc1446c1dd285f8a
1 // Copyright (c) 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.
5 #include "google_apis/gaia/fake_gaia.h"
7 #include <vector>
9 #include "base/base_paths.h"
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/files/file_path.h"
13 #include "base/files/file_util.h"
14 #include "base/json/json_writer.h"
15 #include "base/logging.h"
16 #include "base/memory/linked_ptr.h"
17 #include "base/path_service.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_split.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/stringprintf.h"
22 #include "base/values.h"
23 #include "google_apis/gaia/gaia_constants.h"
24 #include "google_apis/gaia/gaia_urls.h"
25 #include "net/base/url_util.h"
26 #include "net/cookies/parsed_cookie.h"
27 #include "net/http/http_status_code.h"
28 #include "net/test/embedded_test_server/http_request.h"
29 #include "net/test/embedded_test_server/http_response.h"
30 #include "url/third_party/mozilla/url_parse.h"
32 #define REGISTER_RESPONSE_HANDLER(url, method) \
33 request_handlers_.insert(std::make_pair( \
34 url.path(), base::Bind(&FakeGaia::method, base::Unretained(this))))
36 #define REGISTER_PATH_RESPONSE_HANDLER(path, method) \
37 request_handlers_.insert(std::make_pair( \
38 path, base::Bind(&FakeGaia::method, base::Unretained(this))))
40 using namespace net::test_server;
42 namespace {
44 const char kTestAuthCode[] = "fake-auth-code";
45 const char kTestGaiaUberToken[] = "fake-uber-token";
46 const char kTestAuthLoginAccessToken[] = "fake-access-token";
47 const char kTestRefreshToken[] = "fake-refresh-token";
48 const char kTestSessionSIDCookie[] = "fake-session-SID-cookie";
49 const char kTestSessionLSIDCookie[] = "fake-session-LSID-cookie";
50 const char kTestOAuthLoginSID[] = "fake-oauth-SID-cookie";
51 const char kTestOAuthLoginLSID[] = "fake-oauth-LSID-cookie";
52 const char kTestOAuthLoginAuthCode[] = "fake-oauth-auth-code";
54 const char kDefaultGaiaId[] = "12345";
56 const base::FilePath::CharType kServiceLogin[] =
57 FILE_PATH_LITERAL("google_apis/test/service_login.html");
59 const base::FilePath::CharType kEmbeddedSetupChromeos[] =
60 FILE_PATH_LITERAL("google_apis/test/embedded_setup_chromeos.html");
62 // OAuth2 Authentication header value prefix.
63 const char kAuthHeaderBearer[] = "Bearer ";
64 const char kAuthHeaderOAuth[] = "OAuth ";
66 const char kListAccountsResponseFormat[] =
67 "[\"gaia.l.a.r\",[[\"gaia.l.a\",1,\"\",\"%s\",\"\",1,1,0,0,1,\"12345\"]]]";
69 typedef std::map<std::string, std::string> CookieMap;
71 // Parses cookie name-value map our of |request|.
72 CookieMap GetRequestCookies(const HttpRequest& request) {
73 CookieMap result;
74 std::map<std::string, std::string>::const_iterator iter =
75 request.headers.find("Cookie");
76 if (iter != request.headers.end()) {
77 std::vector<std::string> cookie_nv_pairs;
78 base::SplitString(iter->second, ' ', &cookie_nv_pairs);
79 for(std::vector<std::string>::const_iterator cookie_line =
80 cookie_nv_pairs.begin();
81 cookie_line != cookie_nv_pairs.end();
82 ++cookie_line) {
83 std::vector<std::string> name_value;
84 base::SplitString(*cookie_line, '=', &name_value);
85 if (name_value.size() != 2)
86 continue;
88 std::string value = name_value[1];
89 if (value.size() && value[value.size() - 1] == ';')
90 value = value.substr(0, value.size() -1);
92 result.insert(std::make_pair(name_value[0], value));
95 return result;
98 // Extracts the |access_token| from authorization header of |request|.
99 bool GetAccessToken(const HttpRequest& request,
100 const char* auth_token_prefix,
101 std::string* access_token) {
102 std::map<std::string, std::string>::const_iterator auth_header_entry =
103 request.headers.find("Authorization");
104 if (auth_header_entry != request.headers.end()) {
105 if (base::StartsWith(auth_header_entry->second, auth_token_prefix,
106 base::CompareCase::SENSITIVE)) {
107 *access_token = auth_header_entry->second.substr(
108 strlen(auth_token_prefix));
109 return true;
113 return false;
116 void SetCookies(BasicHttpResponse* http_response,
117 const std::string& sid_cookie,
118 const std::string& lsid_cookie) {
119 http_response->AddCustomHeader(
120 "Set-Cookie",
121 base::StringPrintf("SID=%s; Path=/; HttpOnly", sid_cookie.c_str()));
122 http_response->AddCustomHeader(
123 "Set-Cookie",
124 base::StringPrintf("LSID=%s; Path=/; HttpOnly", lsid_cookie.c_str()));
127 } // namespace
129 FakeGaia::AccessTokenInfo::AccessTokenInfo()
130 : expires_in(3600) {}
132 FakeGaia::AccessTokenInfo::~AccessTokenInfo() {}
134 FakeGaia::MergeSessionParams::MergeSessionParams() {
137 FakeGaia::MergeSessionParams::~MergeSessionParams() {
140 void FakeGaia::MergeSessionParams::Update(const MergeSessionParams& update) {
141 // This lambda uses a pointer to data member to merge attributes.
142 auto maybe_update_field =
143 [this, &update](std::string MergeSessionParams::* field_ptr) {
144 if (!(update.*field_ptr).empty())
145 this->*field_ptr = update.*field_ptr;
148 maybe_update_field(&MergeSessionParams::auth_sid_cookie);
149 maybe_update_field(&MergeSessionParams::auth_lsid_cookie);
150 maybe_update_field(&MergeSessionParams::auth_code);
151 maybe_update_field(&MergeSessionParams::refresh_token);
152 maybe_update_field(&MergeSessionParams::access_token);
153 maybe_update_field(&MergeSessionParams::gaia_uber_token);
154 maybe_update_field(&MergeSessionParams::session_sid_cookie);
155 maybe_update_field(&MergeSessionParams::session_lsid_cookie);
156 maybe_update_field(&MergeSessionParams::email);
159 FakeGaia::FakeGaia() : issue_oauth_code_cookie_(false) {
160 base::FilePath source_root_dir;
161 PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir);
162 CHECK(base::ReadFileToString(
163 source_root_dir.Append(base::FilePath(kServiceLogin)),
164 &service_login_response_));
165 CHECK(base::ReadFileToString(
166 source_root_dir.Append(base::FilePath(kEmbeddedSetupChromeos)),
167 &embedded_setup_chromeos_response_));
170 FakeGaia::~FakeGaia() {}
172 void FakeGaia::SetFakeMergeSessionParams(
173 const std::string& email,
174 const std::string& auth_sid_cookie,
175 const std::string& auth_lsid_cookie) {
176 FakeGaia::MergeSessionParams params;
177 params.auth_sid_cookie = auth_sid_cookie;
178 params.auth_lsid_cookie = auth_lsid_cookie;
179 params.auth_code = kTestAuthCode;
180 params.refresh_token = kTestRefreshToken;
181 params.access_token = kTestAuthLoginAccessToken;
182 params.gaia_uber_token = kTestGaiaUberToken;
183 params.session_sid_cookie = kTestSessionSIDCookie;
184 params.session_lsid_cookie = kTestSessionLSIDCookie;
185 params.email = email;
186 SetMergeSessionParams(params);
189 void FakeGaia::SetMergeSessionParams(
190 const MergeSessionParams& params) {
191 merge_session_params_ = params;
194 void FakeGaia::UpdateMergeSessionParams(const MergeSessionParams& params) {
195 merge_session_params_.Update(params);
198 void FakeGaia::MapEmailToGaiaId(const std::string& email,
199 const std::string& gaia_id) {
200 DCHECK(!email.empty());
201 DCHECK(!gaia_id.empty());
202 email_to_gaia_id_map_[email] = gaia_id;
205 std::string FakeGaia::GetGaiaIdOfEmail(const std::string& email) const {
206 DCHECK(!email.empty());
207 const auto it = email_to_gaia_id_map_.find(email);
208 return it == email_to_gaia_id_map_.end() ? std::string(kDefaultGaiaId) :
209 it->second;
212 void FakeGaia::AddGoogleAccountsSigninHeader(
213 net::test_server::BasicHttpResponse* http_response,
214 const std::string& email) const {
215 DCHECK(!email.empty());
216 http_response->AddCustomHeader("google-accounts-signin",
217 base::StringPrintf(
218 "email=\"%s\", obfuscatedid=\"%s\", sessionindex=0",
219 email.c_str(), GetGaiaIdOfEmail(email).c_str()));
222 void FakeGaia::SetOAuthCodeCookie(
223 net::test_server::BasicHttpResponse* http_response) const {
224 http_response->AddCustomHeader(
225 "Set-Cookie",
226 base::StringPrintf(
227 "oauth_code=%s; Path=/o/GetOAuth2Token; Secure; HttpOnly;",
228 merge_session_params_.auth_code.c_str()));
231 void FakeGaia::Initialize() {
232 GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
233 // Handles /MergeSession GAIA call.
234 REGISTER_RESPONSE_HANDLER(
235 gaia_urls->merge_session_url(), HandleMergeSession);
237 // Handles /o/oauth2/programmatic_auth GAIA call.
238 REGISTER_RESPONSE_HANDLER(
239 gaia_urls->client_login_to_oauth2_url(), HandleProgramaticAuth);
241 // Handles /ServiceLogin GAIA call.
242 REGISTER_RESPONSE_HANDLER(
243 gaia_urls->service_login_url(), HandleServiceLogin);
245 // Handles /embedded/setup/chromeos GAIA call.
246 REGISTER_RESPONSE_HANDLER(gaia_urls->embedded_setup_chromeos_url(),
247 HandleEmbeddedSetupChromeos);
249 // Handles /OAuthLogin GAIA call.
250 REGISTER_RESPONSE_HANDLER(
251 gaia_urls->oauth1_login_url(), HandleOAuthLogin);
253 // Handles /ServiceLoginAuth GAIA call.
254 REGISTER_RESPONSE_HANDLER(
255 gaia_urls->service_login_auth_url(), HandleServiceLoginAuth);
257 // Handles /_/embedded/lookup/accountlookup for /embedded/setup/chromeos
258 // authentication request.
259 REGISTER_PATH_RESPONSE_HANDLER("/_/embedded/lookup/accountlookup",
260 HandleEmbeddedLookupAccountLookup);
262 // Handles /_/embedded/signin/challenge for /embedded/setup/chromeos
263 // authentication request.
264 REGISTER_PATH_RESPONSE_HANDLER("/_/embedded/signin/challenge",
265 HandleEmbeddedSigninChallenge);
267 // Handles /SSO GAIA call (not GAIA, made up for SAML tests).
268 REGISTER_PATH_RESPONSE_HANDLER("/SSO", HandleSSO);
270 // Handles /oauth2/v4/token GAIA call.
271 REGISTER_RESPONSE_HANDLER(
272 gaia_urls->oauth2_token_url(), HandleAuthToken);
274 // Handles /oauth2/v2/tokeninfo GAIA call.
275 REGISTER_RESPONSE_HANDLER(
276 gaia_urls->oauth2_token_info_url(), HandleTokenInfo);
278 // Handles /oauth2/v2/IssueToken GAIA call.
279 REGISTER_RESPONSE_HANDLER(
280 gaia_urls->oauth2_issue_token_url(), HandleIssueToken);
282 // Handles /ListAccounts GAIA call.
283 REGISTER_RESPONSE_HANDLER(
284 gaia_urls->ListAccountsURLWithSource(std::string()), HandleListAccounts);
286 // Handles /GetUserInfo GAIA call.
287 REGISTER_RESPONSE_HANDLER(
288 gaia_urls->get_user_info_url(), HandleGetUserInfo);
290 // Handles /oauth2/v1/userinfo call.
291 REGISTER_RESPONSE_HANDLER(
292 gaia_urls->oauth_user_info_url(), HandleOAuthUserInfo);
295 scoped_ptr<HttpResponse> FakeGaia::HandleRequest(const HttpRequest& request) {
296 // The scheme and host of the URL is actually not important but required to
297 // get a valid GURL in order to parse |request.relative_url|.
298 GURL request_url = GURL("http://localhost").Resolve(request.relative_url);
299 std::string request_path = request_url.path();
300 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse());
301 RequestHandlerMap::iterator iter = request_handlers_.find(request_path);
302 if (iter != request_handlers_.end()) {
303 LOG(WARNING) << "Serving request " << request_path;
304 iter->second.Run(request, http_response.get());
305 } else {
306 LOG(ERROR) << "Unhandled request " << request_path;
307 return scoped_ptr<HttpResponse>(); // Request not understood.
310 return http_response.Pass();
313 void FakeGaia::IssueOAuthToken(const std::string& auth_token,
314 const AccessTokenInfo& token_info) {
315 access_token_info_map_.insert(std::make_pair(auth_token, token_info));
318 void FakeGaia::RegisterSamlUser(const std::string& account_id,
319 const GURL& saml_idp) {
320 saml_account_idp_map_[account_id] = saml_idp;
323 // static
324 bool FakeGaia::GetQueryParameter(const std::string& query,
325 const std::string& key,
326 std::string* value) {
327 // Name and scheme actually don't matter, but are required to get a valid URL
328 // for parsing.
329 GURL query_url("http://localhost?" + query);
330 return net::GetValueForKeyInQuery(query_url, key, value);
333 std::string FakeGaia::GetDeviceIdByRefreshToken(
334 const std::string& refresh_token) const {
335 auto it = refresh_token_to_device_id_map_.find(refresh_token);
336 return it != refresh_token_to_device_id_map_.end() ? it->second
337 : std::string();
340 void FakeGaia::SetRefreshTokenToDeviceIdMap(
341 const RefreshTokenToDeviceIdMap& refresh_token_to_device_id_map) {
342 refresh_token_to_device_id_map_ = refresh_token_to_device_id_map;
345 void FakeGaia::HandleMergeSession(const HttpRequest& request,
346 BasicHttpResponse* http_response) {
347 http_response->set_code(net::HTTP_UNAUTHORIZED);
348 if (merge_session_params_.session_sid_cookie.empty() ||
349 merge_session_params_.session_lsid_cookie.empty()) {
350 http_response->set_code(net::HTTP_BAD_REQUEST);
351 return;
354 std::string uber_token;
355 if (!GetQueryParameter(request.content, "uberauth", &uber_token) ||
356 uber_token != merge_session_params_.gaia_uber_token) {
357 LOG(ERROR) << "Missing or invalid 'uberauth' param in /MergeSession call";
358 return;
361 std::string continue_url;
362 if (!GetQueryParameter(request.content, "continue", &continue_url)) {
363 LOG(ERROR) << "Missing or invalid 'continue' param in /MergeSession call";
364 return;
367 std::string source;
368 if (!GetQueryParameter(request.content, "source", &source)) {
369 LOG(ERROR) << "Missing or invalid 'source' param in /MergeSession call";
370 return;
373 SetCookies(http_response,
374 merge_session_params_.session_sid_cookie,
375 merge_session_params_.session_lsid_cookie);
376 // TODO(zelidrag): Not used now.
377 http_response->set_content("OK");
378 http_response->set_code(net::HTTP_OK);
381 void FakeGaia::HandleProgramaticAuth(
382 const HttpRequest& request,
383 BasicHttpResponse* http_response) {
384 http_response->set_code(net::HTTP_UNAUTHORIZED);
385 if (merge_session_params_.auth_code.empty()) {
386 http_response->set_code(net::HTTP_BAD_REQUEST);
387 return;
390 GURL request_url = GURL("http://localhost").Resolve(request.relative_url);
391 std::string request_query = request_url.query();
393 GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
394 std::string scope;
395 if (!GetQueryParameter(request_query, "scope", &scope) ||
396 GaiaConstants::kOAuth1LoginScope != scope) {
397 return;
400 CookieMap cookies = GetRequestCookies(request);
401 CookieMap::const_iterator sid_iter = cookies.find("SID");
402 if (sid_iter == cookies.end() ||
403 sid_iter->second != merge_session_params_.auth_sid_cookie) {
404 LOG(ERROR) << "/o/oauth2/programmatic_auth missing SID cookie";
405 return;
407 CookieMap::const_iterator lsid_iter = cookies.find("LSID");
408 if (lsid_iter == cookies.end() ||
409 lsid_iter->second != merge_session_params_.auth_lsid_cookie) {
410 LOG(ERROR) << "/o/oauth2/programmatic_auth missing LSID cookie";
411 return;
414 std::string client_id;
415 if (!GetQueryParameter(request_query, "client_id", &client_id) ||
416 gaia_urls->oauth2_chrome_client_id() != client_id) {
417 return;
420 http_response->AddCustomHeader(
421 "Set-Cookie",
422 base::StringPrintf(
423 "oauth_code=%s; Path=/o/GetOAuth2Token; Secure; HttpOnly;",
424 merge_session_params_.auth_code.c_str()));
425 http_response->set_code(net::HTTP_OK);
426 http_response->set_content_type("text/html");
429 void FakeGaia::FormatJSONResponse(const base::DictionaryValue& response_dict,
430 BasicHttpResponse* http_response) {
431 std::string response_json;
432 base::JSONWriter::Write(response_dict, &response_json);
433 http_response->set_content(response_json);
434 http_response->set_code(net::HTTP_OK);
437 const FakeGaia::AccessTokenInfo* FakeGaia::FindAccessTokenInfo(
438 const std::string& auth_token,
439 const std::string& client_id,
440 const std::string& scope_string) const {
441 if (auth_token.empty() || client_id.empty())
442 return NULL;
444 std::vector<std::string> scope_list;
445 base::SplitString(scope_string, ' ', &scope_list);
446 ScopeSet scopes(scope_list.begin(), scope_list.end());
448 for (AccessTokenInfoMap::const_iterator entry(
449 access_token_info_map_.lower_bound(auth_token));
450 entry != access_token_info_map_.upper_bound(auth_token);
451 ++entry) {
452 if (entry->second.audience == client_id &&
453 (scope_string.empty() || entry->second.scopes == scopes)) {
454 return &(entry->second);
458 return NULL;
461 const FakeGaia::AccessTokenInfo* FakeGaia::GetAccessTokenInfo(
462 const std::string& access_token) const {
463 for (AccessTokenInfoMap::const_iterator entry(
464 access_token_info_map_.begin());
465 entry != access_token_info_map_.end();
466 ++entry) {
467 if (entry->second.token == access_token)
468 return &(entry->second);
471 return NULL;
474 void FakeGaia::HandleServiceLogin(const HttpRequest& request,
475 BasicHttpResponse* http_response) {
476 http_response->set_code(net::HTTP_OK);
477 http_response->set_content(service_login_response_);
478 http_response->set_content_type("text/html");
481 void FakeGaia::HandleEmbeddedSetupChromeos(const HttpRequest& request,
482 BasicHttpResponse* http_response) {
483 http_response->set_code(net::HTTP_OK);
484 http_response->set_content(embedded_setup_chromeos_response_);
485 http_response->set_content_type("text/html");
488 void FakeGaia::HandleOAuthLogin(const HttpRequest& request,
489 BasicHttpResponse* http_response) {
490 http_response->set_code(net::HTTP_UNAUTHORIZED);
491 if (merge_session_params_.gaia_uber_token.empty()) {
492 http_response->set_code(net::HTTP_FORBIDDEN);
493 return;
496 std::string access_token;
497 if (!GetAccessToken(request, kAuthHeaderBearer, &access_token) &&
498 !GetAccessToken(request, kAuthHeaderOAuth, &access_token)) {
499 LOG(ERROR) << "/OAuthLogin missing access token in the header";
500 return;
503 GURL request_url = GURL("http://localhost").Resolve(request.relative_url);
504 std::string request_query = request_url.query();
506 std::string source;
507 if (!GetQueryParameter(request_query, "source", &source) &&
508 !GetQueryParameter(request.content, "source", &source)) {
509 LOG(ERROR) << "Missing 'source' param in /OAuthLogin call";
510 return;
513 std::string issue_uberauth;
514 if (GetQueryParameter(request_query, "issueuberauth", &issue_uberauth) &&
515 issue_uberauth == "1") {
516 http_response->set_content(merge_session_params_.gaia_uber_token);
517 http_response->set_code(net::HTTP_OK);
518 // Issue GAIA uber token.
519 } else {
520 http_response->set_content(base::StringPrintf(
521 "SID=%s\nLSID=%s\nAuth=%s",
522 kTestOAuthLoginSID, kTestOAuthLoginLSID, kTestOAuthLoginAuthCode));
523 http_response->set_code(net::HTTP_OK);
527 void FakeGaia::HandleServiceLoginAuth(const HttpRequest& request,
528 BasicHttpResponse* http_response) {
529 std::string continue_url =
530 GaiaUrls::GetInstance()->service_login_url().spec();
531 GetQueryParameter(request.content, "continue", &continue_url);
533 std::string redirect_url = continue_url;
535 std::string email;
536 const bool is_saml =
537 GetQueryParameter(request.content, "Email", &email) &&
538 saml_account_idp_map_.find(email) != saml_account_idp_map_.end();
540 if (is_saml) {
541 GURL url(saml_account_idp_map_[email]);
542 url = net::AppendQueryParameter(url, "SAMLRequest", "fake_request");
543 url = net::AppendQueryParameter(url, "RelayState", continue_url);
544 redirect_url = url.spec();
545 http_response->AddCustomHeader("Google-Accounts-SAML", "Start");
546 } else if (!merge_session_params_.auth_sid_cookie.empty() &&
547 !merge_session_params_.auth_lsid_cookie.empty()) {
548 SetCookies(http_response,
549 merge_session_params_.auth_sid_cookie,
550 merge_session_params_.auth_lsid_cookie);
553 http_response->set_code(net::HTTP_TEMPORARY_REDIRECT);
554 http_response->AddCustomHeader("Location", redirect_url);
556 // SAML sign-ins complete in HandleSSO().
557 if (is_saml)
558 return;
560 AddGoogleAccountsSigninHeader(http_response, email);
561 if (issue_oauth_code_cookie_)
562 SetOAuthCodeCookie(http_response);
565 void FakeGaia::HandleEmbeddedLookupAccountLookup(
566 const net::test_server::HttpRequest& request,
567 net::test_server::BasicHttpResponse* http_response) {
568 std::string email;
569 const bool is_saml =
570 GetQueryParameter(request.content, "identifier", &email) &&
571 saml_account_idp_map_.find(email) != saml_account_idp_map_.end();
573 if (!is_saml)
574 return;
576 GURL url(saml_account_idp_map_[email]);
577 url = net::AppendQueryParameter(url, "SAMLRequest", "fake_request");
578 url = net::AppendQueryParameter(
579 url, "RelayState",
580 GaiaUrls::GetInstance()->signin_completed_continue_url().spec());
581 std::string redirect_url = url.spec();
582 http_response->AddCustomHeader("Google-Accounts-SAML", "Start");
584 http_response->AddCustomHeader("continue", redirect_url);
587 void FakeGaia::HandleEmbeddedSigninChallenge(const HttpRequest& request,
588 BasicHttpResponse* http_response) {
589 std::string email;
590 GetQueryParameter(request.content, "identifier", &email);
592 if (!merge_session_params_.auth_sid_cookie.empty() &&
593 !merge_session_params_.auth_lsid_cookie.empty()) {
594 SetCookies(http_response, merge_session_params_.auth_sid_cookie,
595 merge_session_params_.auth_lsid_cookie);
598 AddGoogleAccountsSigninHeader(http_response, email);
600 if (issue_oauth_code_cookie_)
601 SetOAuthCodeCookie(http_response);
604 void FakeGaia::HandleSSO(const HttpRequest& request,
605 BasicHttpResponse* http_response) {
606 if (!merge_session_params_.auth_sid_cookie.empty() &&
607 !merge_session_params_.auth_lsid_cookie.empty()) {
608 SetCookies(http_response,
609 merge_session_params_.auth_sid_cookie,
610 merge_session_params_.auth_lsid_cookie);
612 std::string relay_state;
613 GetQueryParameter(request.content, "RelayState", &relay_state);
614 std::string redirect_url = relay_state;
615 http_response->set_code(net::HTTP_TEMPORARY_REDIRECT);
616 http_response->AddCustomHeader("Location", redirect_url);
617 http_response->AddCustomHeader("Google-Accounts-SAML", "End");
619 if (!merge_session_params_.email.empty())
620 AddGoogleAccountsSigninHeader(http_response, merge_session_params_.email);
622 if (issue_oauth_code_cookie_)
623 SetOAuthCodeCookie(http_response);
626 void FakeGaia::HandleAuthToken(const HttpRequest& request,
627 BasicHttpResponse* http_response) {
628 std::string grant_type;
629 if (!GetQueryParameter(request.content, "grant_type", &grant_type)) {
630 http_response->set_code(net::HTTP_BAD_REQUEST);
631 LOG(ERROR) << "No 'grant_type' param in /oauth2/v4/token";
632 return;
635 if (grant_type == "authorization_code") {
636 std::string auth_code;
637 if (!GetQueryParameter(request.content, "code", &auth_code) ||
638 auth_code != merge_session_params_.auth_code) {
639 http_response->set_code(net::HTTP_BAD_REQUEST);
640 LOG(ERROR) << "No 'code' param in /oauth2/v4/token";
641 return;
644 std::string device_id;
645 if (GetQueryParameter(request.content, "device_id", &device_id)) {
646 std::string device_type;
647 if (!GetQueryParameter(request.content, "device_type", &device_type)) {
648 http_response->set_code(net::HTTP_BAD_REQUEST);
649 LOG(ERROR) << "'device_type' should be set if 'device_id' is set.";
650 return;
652 if (device_type != "chrome") {
653 http_response->set_code(net::HTTP_BAD_REQUEST);
654 LOG(ERROR) << "'device_type' is not 'chrome'.";
655 return;
659 base::DictionaryValue response_dict;
660 response_dict.SetString("refresh_token",
661 merge_session_params_.refresh_token);
662 if (!device_id.empty())
663 refresh_token_to_device_id_map_[merge_session_params_.refresh_token] =
664 device_id;
665 response_dict.SetString("access_token",
666 merge_session_params_.access_token);
667 response_dict.SetInteger("expires_in", 3600);
668 FormatJSONResponse(response_dict, http_response);
669 return;
672 std::string scope;
673 GetQueryParameter(request.content, "scope", &scope);
675 std::string refresh_token;
676 std::string client_id;
677 if (GetQueryParameter(request.content, "refresh_token", &refresh_token) &&
678 GetQueryParameter(request.content, "client_id", &client_id)) {
679 const AccessTokenInfo* token_info =
680 FindAccessTokenInfo(refresh_token, client_id, scope);
681 if (token_info) {
682 base::DictionaryValue response_dict;
683 response_dict.SetString("access_token", token_info->token);
684 response_dict.SetInteger("expires_in", 3600);
685 FormatJSONResponse(response_dict, http_response);
686 return;
690 LOG(ERROR) << "Bad request for /oauth2/v4/token - "
691 << "refresh_token = " << refresh_token
692 << ", scope = " << scope
693 << ", client_id = " << client_id;
694 http_response->set_code(net::HTTP_BAD_REQUEST);
697 void FakeGaia::HandleTokenInfo(const HttpRequest& request,
698 BasicHttpResponse* http_response) {
699 const AccessTokenInfo* token_info = NULL;
700 std::string access_token;
701 if (GetQueryParameter(request.content, "access_token", &access_token))
702 token_info = GetAccessTokenInfo(access_token);
704 if (token_info) {
705 base::DictionaryValue response_dict;
706 response_dict.SetString("issued_to", token_info->issued_to);
707 response_dict.SetString("audience", token_info->audience);
708 response_dict.SetString("user_id", token_info->user_id);
709 std::vector<std::string> scope_vector(token_info->scopes.begin(),
710 token_info->scopes.end());
711 response_dict.SetString("scope", base::JoinString(scope_vector, " "));
712 response_dict.SetInteger("expires_in", token_info->expires_in);
713 response_dict.SetString("email", token_info->email);
714 FormatJSONResponse(response_dict, http_response);
715 } else {
716 http_response->set_code(net::HTTP_BAD_REQUEST);
720 void FakeGaia::HandleIssueToken(const HttpRequest& request,
721 BasicHttpResponse* http_response) {
722 std::string access_token;
723 std::string scope;
724 std::string client_id;
725 if (GetAccessToken(request, kAuthHeaderBearer, &access_token) &&
726 GetQueryParameter(request.content, "scope", &scope) &&
727 GetQueryParameter(request.content, "client_id", &client_id)) {
728 const AccessTokenInfo* token_info =
729 FindAccessTokenInfo(access_token, client_id, scope);
730 if (token_info) {
731 base::DictionaryValue response_dict;
732 response_dict.SetString("issueAdvice", "auto");
733 response_dict.SetString("expiresIn",
734 base::IntToString(token_info->expires_in));
735 response_dict.SetString("token", token_info->token);
736 FormatJSONResponse(response_dict, http_response);
737 return;
740 http_response->set_code(net::HTTP_BAD_REQUEST);
743 void FakeGaia::HandleListAccounts(const HttpRequest& request,
744 BasicHttpResponse* http_response) {
745 http_response->set_content(base::StringPrintf(
746 kListAccountsResponseFormat, merge_session_params_.email.c_str()));
747 http_response->set_code(net::HTTP_OK);
750 void FakeGaia::HandleGetUserInfo(const HttpRequest& request,
751 BasicHttpResponse* http_response) {
752 http_response->set_content(base::StringPrintf(
753 "email=%s\ndisplayEmail=%s",
754 merge_session_params_.email.c_str(),
755 merge_session_params_.email.c_str()));
756 http_response->set_code(net::HTTP_OK);
759 void FakeGaia::HandleOAuthUserInfo(
760 const net::test_server::HttpRequest& request,
761 net::test_server::BasicHttpResponse* http_response) {
762 const AccessTokenInfo* token_info = NULL;
763 std::string access_token;
764 if (GetAccessToken(request, kAuthHeaderBearer, &access_token) ||
765 GetAccessToken(request, kAuthHeaderOAuth, &access_token)) {
766 token_info = GetAccessTokenInfo(access_token);
769 if (token_info) {
770 base::DictionaryValue response_dict;
771 response_dict.SetString("id", GetGaiaIdOfEmail(token_info->email));
772 response_dict.SetString("email", token_info->email);
773 response_dict.SetString("verified_email", token_info->email);
774 FormatJSONResponse(response_dict, http_response);
775 } else {
776 http_response->set_code(net::HTTP_BAD_REQUEST);