• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "google_apis/gaia/fake_gaia.h"
6 
7 #include "base/base_paths.h"
8 #include "base/file_util.h"
9 #include "base/files/file_path.h"
10 #include "base/json/json_writer.h"
11 #include "base/logging.h"
12 #include "base/path_service.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/string_util.h"
16 #include "base/values.h"
17 #include "google_apis/gaia/gaia_urls.h"
18 #include "net/base/url_util.h"
19 #include "net/http/http_status_code.h"
20 #include "net/test/embedded_test_server/http_request.h"
21 #include "net/test/embedded_test_server/http_response.h"
22 #include "url/url_parse.h"
23 
24 using namespace net::test_server;
25 
26 namespace {
27 const base::FilePath::CharType kServiceLogin[] =
28     FILE_PATH_LITERAL("google_apis/test/service_login.html");
29 }
30 
AccessTokenInfo()31 FakeGaia::AccessTokenInfo::AccessTokenInfo()
32   : expires_in(3600) {}
33 
~AccessTokenInfo()34 FakeGaia::AccessTokenInfo::~AccessTokenInfo() {}
35 
FakeGaia()36 FakeGaia::FakeGaia() {
37   base::FilePath source_root_dir;
38   PathService::Get(base::DIR_SOURCE_ROOT, &source_root_dir);
39   CHECK(base::ReadFileToString(
40       source_root_dir.Append(base::FilePath(kServiceLogin)),
41       &service_login_response_));
42 }
43 
~FakeGaia()44 FakeGaia::~FakeGaia() {}
45 
HandleRequest(const HttpRequest & request)46 scoped_ptr<HttpResponse> FakeGaia::HandleRequest(const HttpRequest& request) {
47   GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
48 
49   // The scheme and host of the URL is actually not important but required to
50   // get a valid GURL in order to parse |request.relative_url|.
51   GURL request_url = GURL("http://localhost").Resolve(request.relative_url);
52   std::string request_path = request_url.path();
53 
54   scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse());
55   if (request_path == gaia_urls->service_login_url().path()) {
56     http_response->set_code(net::HTTP_OK);
57     http_response->set_content(service_login_response_);
58     http_response->set_content_type("text/html");
59   } else if (request_path == gaia_urls->service_login_auth_url().path()) {
60     std::string continue_url = gaia_urls->service_login_url().spec();
61     GetQueryParameter(request.content, "continue", &continue_url);
62     http_response->set_code(net::HTTP_OK);
63     const std::string redirect_js =
64         "document.location.href = '" + continue_url + "'";
65     http_response->set_content(
66         "<HTML><HEAD><SCRIPT>\n" + redirect_js + "\n</SCRIPT></HEAD></HTML>");
67     http_response->set_content_type("text/html");
68   } else if (request_path == gaia_urls->oauth2_token_url().path()) {
69     std::string refresh_token;
70     std::string client_id;
71     std::string scope;
72     const AccessTokenInfo* token_info = NULL;
73     GetQueryParameter(request.content, "scope", &scope);
74     if (GetQueryParameter(request.content, "refresh_token", &refresh_token) &&
75         GetQueryParameter(request.content, "client_id", &client_id) &&
76         (token_info = GetAccessTokenInfo(refresh_token, client_id, scope))) {
77       base::DictionaryValue response_dict;
78       response_dict.SetString("access_token", token_info->token);
79       response_dict.SetInteger("expires_in", 3600);
80       FormatJSONResponse(response_dict, http_response.get());
81     } else {
82       http_response->set_code(net::HTTP_BAD_REQUEST);
83     }
84   } else if (request_path == gaia_urls->oauth2_token_info_url().path()) {
85     const AccessTokenInfo* token_info = NULL;
86     std::string access_token;
87     if (GetQueryParameter(request.content, "access_token", &access_token)) {
88       for (AccessTokenInfoMap::const_iterator entry(
89                access_token_info_map_.begin());
90            entry != access_token_info_map_.end();
91            ++entry) {
92         if (entry->second.token == access_token) {
93           token_info = &(entry->second);
94           break;
95         }
96       }
97     }
98 
99     if (token_info) {
100       base::DictionaryValue response_dict;
101       response_dict.SetString("issued_to", token_info->issued_to);
102       response_dict.SetString("audience", token_info->audience);
103       response_dict.SetString("user_id", token_info->user_id);
104       std::vector<std::string> scope_vector(token_info->scopes.begin(),
105                                             token_info->scopes.end());
106       response_dict.SetString("scope", JoinString(scope_vector, " "));
107       response_dict.SetInteger("expires_in", token_info->expires_in);
108       response_dict.SetString("email", token_info->email);
109       FormatJSONResponse(response_dict, http_response.get());
110     } else {
111       http_response->set_code(net::HTTP_BAD_REQUEST);
112     }
113   } else if (request_path == gaia_urls->oauth2_issue_token_url().path()) {
114     std::string access_token;
115     std::map<std::string, std::string>::const_iterator auth_header_entry =
116         request.headers.find("Authorization");
117     if (auth_header_entry != request.headers.end()) {
118       if (StartsWithASCII(auth_header_entry->second, "Bearer ", true))
119         access_token = auth_header_entry->second.substr(7);
120     }
121 
122     std::string scope;
123     std::string client_id;
124     const AccessTokenInfo* token_info = NULL;
125     if (GetQueryParameter(request.content, "scope", &scope) &&
126         GetQueryParameter(request.content, "client_id", &client_id) &&
127         (token_info = GetAccessTokenInfo(access_token, client_id, scope))) {
128       base::DictionaryValue response_dict;
129       response_dict.SetString("issueAdvice", "auto");
130       response_dict.SetString("expiresIn",
131                               base::IntToString(token_info->expires_in));
132       response_dict.SetString("token", token_info->token);
133       FormatJSONResponse(response_dict, http_response.get());
134     } else {
135       http_response->set_code(net::HTTP_BAD_REQUEST);
136     }
137   } else {
138     // Request not understood.
139     return scoped_ptr<HttpResponse>();
140   }
141 
142   return http_response.PassAs<HttpResponse>();
143 }
144 
IssueOAuthToken(const std::string & auth_token,const AccessTokenInfo & token_info)145 void FakeGaia::IssueOAuthToken(const std::string& auth_token,
146                                const AccessTokenInfo& token_info) {
147   access_token_info_map_.insert(std::make_pair(auth_token, token_info));
148 }
149 
FormatJSONResponse(const base::DictionaryValue & response_dict,BasicHttpResponse * http_response)150 void FakeGaia::FormatJSONResponse(const base::DictionaryValue& response_dict,
151                                   BasicHttpResponse* http_response) {
152   std::string response_json;
153   base::JSONWriter::Write(&response_dict, &response_json);
154   http_response->set_content(response_json);
155   http_response->set_code(net::HTTP_OK);
156 }
157 
GetAccessTokenInfo(const std::string & auth_token,const std::string & client_id,const std::string & scope_string) const158 const FakeGaia::AccessTokenInfo* FakeGaia::GetAccessTokenInfo(
159     const std::string& auth_token,
160     const std::string& client_id,
161     const std::string& scope_string) const {
162   if (auth_token.empty() || client_id.empty())
163     return NULL;
164 
165   std::vector<std::string> scope_list;
166   base::SplitString(scope_string, ' ', &scope_list);
167   ScopeSet scopes(scope_list.begin(), scope_list.end());
168 
169   for (AccessTokenInfoMap::const_iterator entry(
170            access_token_info_map_.lower_bound(auth_token));
171        entry != access_token_info_map_.upper_bound(auth_token);
172        ++entry) {
173     if (entry->second.audience == client_id &&
174         (scope_string.empty() || entry->second.scopes == scopes)) {
175       return &(entry->second);
176     }
177   }
178 
179   return NULL;
180 }
181 
182 // static
GetQueryParameter(const std::string & query,const std::string & key,std::string * value)183 bool FakeGaia::GetQueryParameter(const std::string& query,
184                                  const std::string& key,
185                                  std::string* value) {
186   // Name and scheme actually don't matter, but are required to get a valid URL
187   // for parsing.
188   GURL query_url("http://localhost?" + query);
189   return net::GetValueForKeyInQuery(query_url, key, value);
190 }
191