cros: Polish SAML signin.
[chromium-blink-merge.git] / google_apis / gaia / fake_gaia.cc
blob7474aca80a9b0c0f184869f1295b13b1a6142fb0
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/file_util.h"
11 #include "base/files/file_path.h"
12 #include "base/json/json_writer.h"
13 #include "base/logging.h"
14 #include "base/path_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_split.h"
17 #include "base/strings/string_util.h"
18 #include "base/values.h"
19 #include "google_apis/gaia/gaia_urls.h"
20 #include "net/base/url_util.h"
21 #include "net/http/http_status_code.h"
22 #include "net/test/embedded_test_server/http_request.h"
23 #include "net/test/embedded_test_server/http_response.h"
24 #include "url/url_parse.h"
26 using namespace net::test_server;
28 namespace {
29 const base::FilePath::CharType kServiceLogin[] =
30 FILE_PATH_LITERAL("google_apis/test/service_login.html");
33 FakeGaia::AccessTokenInfo::AccessTokenInfo()
34 : expires_in(3600) {}
36 FakeGaia::AccessTokenInfo::~AccessTokenInfo() {}
38 FakeGaia::FakeGaia() {
39 base::FilePath source_root_dir;
40 PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir);
41 CHECK(base::ReadFileToString(
42 source_root_dir.Append(base::FilePath(kServiceLogin)),
43 &service_login_response_));
46 FakeGaia::~FakeGaia() {}
48 scoped_ptr<HttpResponse> FakeGaia::HandleRequest(const HttpRequest& request) {
49 GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
51 // The scheme and host of the URL is actually not important but required to
52 // get a valid GURL in order to parse |request.relative_url|.
53 GURL request_url = GURL("http://localhost").Resolve(request.relative_url);
54 std::string request_path = request_url.path();
56 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse());
57 if (request_path == gaia_urls->service_login_url().path()) {
58 http_response->set_code(net::HTTP_OK);
59 http_response->set_content(service_login_response_);
60 http_response->set_content_type("text/html");
61 } else if (request_path == gaia_urls->service_login_auth_url().path()) {
62 std::string continue_url = gaia_urls->service_login_url().spec();
63 GetQueryParameter(request.content, "continue", &continue_url);
64 std::string redirect_url = continue_url;
66 std::string email;
67 if (GetQueryParameter(request.content, "Email", &email) &&
68 saml_account_idp_map_.find(email) != saml_account_idp_map_.end()) {
69 GURL url(saml_account_idp_map_[email]);
70 url = net::AppendQueryParameter(url, "SAMLRequest", "fake_request");
71 url = net::AppendQueryParameter(url, "RelayState", continue_url);
72 redirect_url = url.spec();
75 http_response->set_code(net::HTTP_TEMPORARY_REDIRECT);
76 http_response->AddCustomHeader("Location", redirect_url);
77 } else if (request_path == gaia_urls->oauth2_token_url().path()) {
78 std::string refresh_token;
79 std::string client_id;
80 std::string scope;
81 const AccessTokenInfo* token_info = NULL;
82 GetQueryParameter(request.content, "scope", &scope);
83 if (GetQueryParameter(request.content, "refresh_token", &refresh_token) &&
84 GetQueryParameter(request.content, "client_id", &client_id) &&
85 (token_info = GetAccessTokenInfo(refresh_token, client_id, scope))) {
86 base::DictionaryValue response_dict;
87 response_dict.SetString("access_token", token_info->token);
88 response_dict.SetInteger("expires_in", 3600);
89 FormatJSONResponse(response_dict, http_response.get());
90 } else {
91 http_response->set_code(net::HTTP_BAD_REQUEST);
93 } else if (request_path == gaia_urls->oauth2_token_info_url().path()) {
94 const AccessTokenInfo* token_info = NULL;
95 std::string access_token;
96 if (GetQueryParameter(request.content, "access_token", &access_token)) {
97 for (AccessTokenInfoMap::const_iterator entry(
98 access_token_info_map_.begin());
99 entry != access_token_info_map_.end();
100 ++entry) {
101 if (entry->second.token == access_token) {
102 token_info = &(entry->second);
103 break;
108 if (token_info) {
109 base::DictionaryValue response_dict;
110 response_dict.SetString("issued_to", token_info->issued_to);
111 response_dict.SetString("audience", token_info->audience);
112 response_dict.SetString("user_id", token_info->user_id);
113 std::vector<std::string> scope_vector(token_info->scopes.begin(),
114 token_info->scopes.end());
115 response_dict.SetString("scope", JoinString(scope_vector, " "));
116 response_dict.SetInteger("expires_in", token_info->expires_in);
117 response_dict.SetString("email", token_info->email);
118 FormatJSONResponse(response_dict, http_response.get());
119 } else {
120 http_response->set_code(net::HTTP_BAD_REQUEST);
122 } else if (request_path == gaia_urls->oauth2_issue_token_url().path()) {
123 std::string access_token;
124 std::map<std::string, std::string>::const_iterator auth_header_entry =
125 request.headers.find("Authorization");
126 if (auth_header_entry != request.headers.end()) {
127 if (StartsWithASCII(auth_header_entry->second, "Bearer ", true))
128 access_token = auth_header_entry->second.substr(7);
131 std::string scope;
132 std::string client_id;
133 const AccessTokenInfo* token_info = NULL;
134 if (GetQueryParameter(request.content, "scope", &scope) &&
135 GetQueryParameter(request.content, "client_id", &client_id) &&
136 (token_info = GetAccessTokenInfo(access_token, client_id, scope))) {
137 base::DictionaryValue response_dict;
138 response_dict.SetString("issueAdvice", "auto");
139 response_dict.SetString("expiresIn",
140 base::IntToString(token_info->expires_in));
141 response_dict.SetString("token", token_info->token);
142 FormatJSONResponse(response_dict, http_response.get());
143 } else {
144 http_response->set_code(net::HTTP_BAD_REQUEST);
146 } else if (request_path == "/SSO") {
147 std::string relay_state;
148 GetQueryParameter(request.content, "RelayState", &relay_state);
149 std::string redirect_url = relay_state;
150 http_response->set_code(net::HTTP_TEMPORARY_REDIRECT);
151 http_response->AddCustomHeader("Location", redirect_url);
152 } else {
153 // Request not understood.
154 return scoped_ptr<HttpResponse>();
157 return http_response.PassAs<HttpResponse>();
160 void FakeGaia::IssueOAuthToken(const std::string& auth_token,
161 const AccessTokenInfo& token_info) {
162 access_token_info_map_.insert(std::make_pair(auth_token, token_info));
165 void FakeGaia::RegisterSamlUser(const std::string& account_id,
166 const GURL& saml_idp) {
167 saml_account_idp_map_[account_id] = saml_idp;
170 // static
171 bool FakeGaia::GetQueryParameter(const std::string& query,
172 const std::string& key,
173 std::string* value) {
174 // Name and scheme actually don't matter, but are required to get a valid URL
175 // for parsing.
176 GURL query_url("http://localhost?" + query);
177 return net::GetValueForKeyInQuery(query_url, key, value);
180 void FakeGaia::FormatJSONResponse(const base::DictionaryValue& response_dict,
181 BasicHttpResponse* http_response) {
182 std::string response_json;
183 base::JSONWriter::Write(&response_dict, &response_json);
184 http_response->set_content(response_json);
185 http_response->set_code(net::HTTP_OK);
188 const FakeGaia::AccessTokenInfo* FakeGaia::GetAccessTokenInfo(
189 const std::string& auth_token,
190 const std::string& client_id,
191 const std::string& scope_string) const {
192 if (auth_token.empty() || client_id.empty())
193 return NULL;
195 std::vector<std::string> scope_list;
196 base::SplitString(scope_string, ' ', &scope_list);
197 ScopeSet scopes(scope_list.begin(), scope_list.end());
199 for (AccessTokenInfoMap::const_iterator entry(
200 access_token_info_map_.lower_bound(auth_token));
201 entry != access_token_info_map_.upper_bound(auth_token);
202 ++entry) {
203 if (entry->second.audience == client_id &&
204 (scope_string.empty() || entry->second.scopes == scopes)) {
205 return &(entry->second);
209 return NULL;