 Chromium Code Reviews
 Chromium Code Reviews Issue 10332187:
  Properly handle accounts that don't have GMail.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src
    
  
    Issue 10332187:
  Properly handle accounts that don't have GMail.  (Closed) 
  Base URL: svn://svn.chromium.org/chrome/trunk/src| OLD | NEW | 
|---|---|
| 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 "remoting/host/gaia_oauth_client.h" | 5 #include "remoting/host/gaia_oauth_client.h" | 
| 6 | 6 | 
| 7 #include "base/bind.h" | 7 #include "base/bind.h" | 
| 8 #include "base/json/json_reader.h" | 8 #include "base/json/json_reader.h" | 
| 9 #include "base/logging.h" | 9 #include "base/logging.h" | 
| 10 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" | 
| 11 #include "base/values.h" | 11 #include "base/values.h" | 
| 12 #include "googleurl/src/gurl.h" | 12 #include "googleurl/src/gurl.h" | 
| 13 #include "net/base/escape.h" | 13 #include "net/base/escape.h" | 
| 14 #include "net/http/http_status_code.h" | 14 #include "net/http/http_status_code.h" | 
| 15 #include "net/url_request/url_request_context_getter.h" | 15 #include "net/url_request/url_request_context_getter.h" | 
| 16 #include "net/url_request/url_request_status.h" | 16 #include "net/url_request/url_request_status.h" | 
| 17 #include "remoting/host/url_fetcher.h" | 17 #include "remoting/host/url_fetcher.h" | 
| 18 | 18 | 
| 19 namespace { | 19 namespace { | 
| 20 | |
| 21 const char kUserInfoUrl[] = "https://www.googleapis.com/oauth2/v1/userinfo"; | |
| 
Wez
2012/05/16 23:00:07
It seems wrong for the GaiaOAuth2Url to be a param
 
Sergey Ulanov
2012/05/17 00:38:11
Made them both configurable.
 | |
| 22 | |
| 20 const char kAccessTokenValue[] = "access_token"; | 23 const char kAccessTokenValue[] = "access_token"; | 
| 21 const char kRefreshTokenValue[] = "refresh_token"; | 24 const char kRefreshTokenValue[] = "refresh_token"; | 
| 22 const char kExpiresInValue[] = "expires_in"; | 25 const char kExpiresInValue[] = "expires_in"; | 
| 26 const char kEmailValue[] = "email"; | |
| 
Wez
2012/05/16 23:00:07
nit: Keep this definition with the URL definition,
 
Sergey Ulanov
2012/05/17 00:38:11
Done.
 | |
| 27 | |
| 23 } // namespace | 28 } // namespace | 
| 24 | 29 | 
| 25 namespace remoting { | 30 namespace remoting { | 
| 26 | 31 | 
| 27 class GaiaOAuthClient::Core | 32 class GaiaOAuthClient::Core | 
| 28 : public base::RefCountedThreadSafe<GaiaOAuthClient::Core> { | 33 : public base::RefCountedThreadSafe<GaiaOAuthClient::Core> { | 
| 29 public: | 34 public: | 
| 30 Core(const std::string& gaia_url, | 35 Core(const std::string& gaia_url, | 
| 31 net::URLRequestContextGetter* request_context_getter) | 36 net::URLRequestContextGetter* request_context_getter) | 
| 32 : gaia_url_(gaia_url), | 37 : gaia_url_(gaia_url), | 
| 33 request_context_getter_(request_context_getter), | 38 request_context_getter_(request_context_getter), | 
| 34 delegate_(NULL) { | 39 delegate_(NULL) { | 
| 35 } | 40 } | 
| 36 | 41 | 
| 37 void RefreshToken(const OAuthClientInfo& oauth_client_info, | 42 void RefreshToken(const OAuthClientInfo& oauth_client_info, | 
| 38 const std::string& refresh_token, | 43 const std::string& refresh_token, | 
| 39 GaiaOAuthClient::Delegate* delegate); | 44 GaiaOAuthClient::Delegate* delegate); | 
| 40 | 45 | 
| 41 private: | 46 private: | 
| 42 friend class base::RefCountedThreadSafe<Core>; | 47 friend class base::RefCountedThreadSafe<Core>; | 
| 43 virtual ~Core() {} | 48 virtual ~Core() {} | 
| 44 | 49 | 
| 45 void OnUrlFetchComplete(const net::URLRequestStatus& status, | 50 void OnAuthTokenFetchComplete(const net::URLRequestStatus& status, | 
| 46 int response_code, | 51 int response_code, | 
| 47 const std::string& response); | 52 const std::string& response); | 
| 53 void FetchUserInfo(); | |
| 54 void OnUserInfoFetchComplete(const net::URLRequestStatus& status, | |
| 55 int response_code, | |
| 56 const std::string& response); | |
| 48 | 57 | 
| 49 GURL gaia_url_; | 58 GURL gaia_url_; | 
| 50 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; | 59 scoped_refptr<net::URLRequestContextGetter> request_context_getter_; | 
| 51 GaiaOAuthClient::Delegate* delegate_; | 60 GaiaOAuthClient::Delegate* delegate_; | 
| 52 scoped_ptr<UrlFetcher> request_; | 61 scoped_ptr<UrlFetcher> request_; | 
| 62 | |
| 63 std::string access_token_; | |
| 64 int expires_in_seconds_; | |
| 53 }; | 65 }; | 
| 54 | 66 | 
| 55 void GaiaOAuthClient::Core::RefreshToken( | 67 void GaiaOAuthClient::Core::RefreshToken( | 
| 56 const OAuthClientInfo& oauth_client_info, | 68 const OAuthClientInfo& oauth_client_info, | 
| 57 const std::string& refresh_token, | 69 const std::string& refresh_token, | 
| 58 GaiaOAuthClient::Delegate* delegate) { | 70 GaiaOAuthClient::Delegate* delegate) { | 
| 59 DCHECK(!request_.get()) << "Tried to fetch two things at once!"; | 71 DCHECK(!request_.get()) << "Tried to fetch two things at once!"; | 
| 60 | 72 | 
| 73 delegate_ = delegate; | |
| 74 | |
| 75 access_token_.clear(); | |
| 76 expires_in_seconds_ = 0; | |
| 77 | |
| 61 std::string post_body = | 78 std::string post_body = | 
| 62 "refresh_token=" + net::EscapeUrlEncodedData(refresh_token, true) + | 79 "refresh_token=" + net::EscapeUrlEncodedData(refresh_token, true) + | 
| 63 "&client_id=" + net::EscapeUrlEncodedData(oauth_client_info.client_id, | 80 "&client_id=" + net::EscapeUrlEncodedData(oauth_client_info.client_id, | 
| 64 true) + | 81 true) + | 
| 65 "&client_secret=" + | 82 "&client_secret=" + | 
| 66 net::EscapeUrlEncodedData(oauth_client_info.client_secret, true) + | 83 net::EscapeUrlEncodedData(oauth_client_info.client_secret, true) + | 
| 67 "&grant_type=refresh_token"; | 84 "&grant_type=refresh_token"; | 
| 68 delegate_ = delegate; | |
| 69 request_.reset(new UrlFetcher(gaia_url_, UrlFetcher::POST)); | 85 request_.reset(new UrlFetcher(gaia_url_, UrlFetcher::POST)); | 
| 70 request_->SetRequestContext(request_context_getter_); | 86 request_->SetRequestContext(request_context_getter_); | 
| 71 request_->SetUploadData("application/x-www-form-urlencoded", post_body); | 87 request_->SetUploadData("application/x-www-form-urlencoded", post_body); | 
| 72 request_->Start(base::Bind(&GaiaOAuthClient::Core::OnUrlFetchComplete, this)); | 88 request_->Start( | 
| 89 base::Bind(&GaiaOAuthClient::Core::OnAuthTokenFetchComplete, this)); | |
| 73 } | 90 } | 
| 74 | 91 | 
| 75 void GaiaOAuthClient::Core::OnUrlFetchComplete( | 92 void GaiaOAuthClient::Core::OnAuthTokenFetchComplete( | 
| 76 const net::URLRequestStatus& status, | 93 const net::URLRequestStatus& status, | 
| 77 int response_code, | 94 int response_code, | 
| 78 const std::string& response) { | 95 const std::string& response) { | 
| 79 request_.reset(); | 96 request_.reset(); | 
| 80 | 97 | 
| 81 if (!status.is_success()) { | 98 if (!status.is_success()) { | 
| 82 delegate_->OnNetworkError(response_code); | 99 delegate_->OnNetworkError(response_code); | 
| 83 return; | 100 return; | 
| 84 } | 101 } | 
| 85 | 102 | 
| 86 // HTTP_BAD_REQUEST means the arguments are invalid. | 103 // HTTP_BAD_REQUEST means the arguments are invalid. | 
| 87 if (response_code == net::HTTP_BAD_REQUEST) { | 104 if (response_code == net::HTTP_BAD_REQUEST) { | 
| 88 LOG(ERROR) << "Gaia response: response code=net::HTTP_BAD_REQUEST."; | 105 LOG(ERROR) << "Gaia response: response code=net::HTTP_BAD_REQUEST."; | 
| 89 delegate_->OnOAuthError(); | 106 delegate_->OnOAuthError(); | 
| 90 return; | 107 return; | 
| 91 } | 108 } | 
| 92 | 109 | 
| 93 std::string access_token; | |
| 94 std::string refresh_token; | |
| 95 int expires_in_seconds = 0; | |
| 96 if (response_code == net::HTTP_OK) { | 110 if (response_code == net::HTTP_OK) { | 
| 97 scoped_ptr<Value> message_value(base::JSONReader::Read(response)); | 111 scoped_ptr<Value> message_value(base::JSONReader::Read(response)); | 
| 98 if (message_value.get() && | 112 if (message_value.get() && | 
| 99 message_value->IsType(Value::TYPE_DICTIONARY)) { | 113 message_value->IsType(Value::TYPE_DICTIONARY)) { | 
| 100 scoped_ptr<DictionaryValue> response_dict( | 114 scoped_ptr<DictionaryValue> response_dict( | 
| 101 static_cast<DictionaryValue*>(message_value.release())); | 115 static_cast<DictionaryValue*>(message_value.release())); | 
| 102 response_dict->GetString(kAccessTokenValue, &access_token); | 116 response_dict->GetString(kAccessTokenValue, &access_token_); | 
| 103 response_dict->GetString(kRefreshTokenValue, &refresh_token); | 117 response_dict->GetInteger(kExpiresInValue, &expires_in_seconds_); | 
| 104 response_dict->GetInteger(kExpiresInValue, &expires_in_seconds); | |
| 105 } | 118 } | 
| 106 VLOG(1) << "Gaia response: acess_token='" << access_token | 119 VLOG(1) << "Gaia response: acess_token='" << access_token_ | 
| 107 << "', refresh_token='" << refresh_token | 120 << "', expires in " << expires_in_seconds_ << " second(s)"; | 
| 108 << "', expires in " << expires_in_seconds << " second(s)"; | |
| 109 } else { | 121 } else { | 
| 110 LOG(ERROR) << "Gaia response: response code=" << response_code; | 122 LOG(ERROR) << "Gaia response: response code=" << response_code; | 
| 111 } | 123 } | 
| 112 | 124 | 
| 113 if (access_token.empty()) { | 125 if (access_token_.empty()) { | 
| 114 delegate_->OnNetworkError(response_code); | 126 delegate_->OnNetworkError(response_code); | 
| 115 } else if (refresh_token.empty()) { | 127 } else { | 
| 116 // If we only have an access token, then this was a refresh request. | 128 FetchUserInfo(); | 
| 117 delegate_->OnRefreshTokenResponse(access_token, expires_in_seconds); | |
| 118 } | 129 } | 
| 119 } | 130 } | 
| 120 | 131 | 
| 132 void GaiaOAuthClient::Core::FetchUserInfo() { | |
| 
Wez
2012/05/16 23:00:07
Since this fetches the UserInfo and then notifies
 
Sergey Ulanov
2012/05/17 00:38:11
Renamed it to FetchUserInfoAndInvokeCallback(), bu
 | |
| 133 request_.reset(new UrlFetcher(GURL(kUserInfoUrl), UrlFetcher::GET)); | |
| 134 request_->SetRequestContext(request_context_getter_); | |
| 135 request_->SetHeader("Authorization", "Bearer " + access_token_); | |
| 136 request_->Start( | |
| 137 base::Bind(&GaiaOAuthClient::Core::OnUserInfoFetchComplete, this)); | |
| 138 } | |
| 139 | |
| 140 void GaiaOAuthClient::Core::OnUserInfoFetchComplete( | |
| 141 const net::URLRequestStatus& status, | |
| 142 int response_code, | |
| 143 const std::string& response) { | |
| 144 std::string email; | |
| 145 if (response_code == net::HTTP_OK) { | |
| 146 scoped_ptr<Value> message_value(base::JSONReader::Read(response)); | |
| 
Wez
2012/05/16 23:00:07
nit: Indentation.
 
Sergey Ulanov
2012/05/17 00:38:11
Done.
 | |
| 147 if (message_value.get() && | |
| 148 message_value->IsType(Value::TYPE_DICTIONARY)) { | |
| 149 scoped_ptr<DictionaryValue> response_dict( | |
| 150 static_cast<DictionaryValue*>(message_value.release())); | |
| 
Wez
2012/05/16 23:00:07
Can't use AsDictionaryValue() here?
 
Sergey Ulanov
2012/05/17 00:38:11
Yes, I can, but it makes this code shorter only wh
 | |
| 151 response_dict->GetString(kEmailValue, &email); | |
| 152 } | |
| 153 } | |
| 154 | |
| 155 if (email.empty()) { | |
| 156 delegate_->OnNetworkError(response_code); | |
| 157 } else { | |
| 158 delegate_->OnRefreshTokenResponse( | |
| 159 email, access_token_, expires_in_seconds_); | |
| 160 } | |
| 161 } | |
| 162 | |
| 121 GaiaOAuthClient::GaiaOAuthClient(const std::string& gaia_url, | 163 GaiaOAuthClient::GaiaOAuthClient(const std::string& gaia_url, | 
| 122 net::URLRequestContextGetter* context_getter) { | 164 net::URLRequestContextGetter* context_getter) { | 
| 123 core_ = new Core(gaia_url, context_getter); | 165 core_ = new Core(gaia_url, context_getter); | 
| 124 } | 166 } | 
| 125 | 167 | 
| 126 GaiaOAuthClient::~GaiaOAuthClient() { | 168 GaiaOAuthClient::~GaiaOAuthClient() { | 
| 127 } | 169 } | 
| 128 | 170 | 
| 129 void GaiaOAuthClient::RefreshToken(const OAuthClientInfo& oauth_client_info, | 171 void GaiaOAuthClient::RefreshToken(const OAuthClientInfo& oauth_client_info, | 
| 130 const std::string& refresh_token, | 172 const std::string& refresh_token, | 
| 131 Delegate* delegate) { | 173 Delegate* delegate) { | 
| 132 return core_->RefreshToken(oauth_client_info, | 174 return core_->RefreshToken(oauth_client_info, | 
| 133 refresh_token, | 175 refresh_token, | 
| 134 delegate); | 176 delegate); | 
| 135 } | 177 } | 
| 136 | 178 | 
| 137 } // namespace remoting | 179 } // namespace remoting | 
| OLD | NEW |