Commit 2f18ff3d authored by bartfab@chromium.org's avatar bartfab@chromium.org

Switch GAIA e-mail address retrieval from /GetUserInfo to /ListAccounts

Previously, the Chrome OS SAML login flow was passing the LSID obtained
via /ServiceLogin to /GetUserInfo in order to retrieve the authenticated
user's e-mail address. It turns out that this is wrong because
/ServiceLogin yields a browser LSID and /GetUserInfo expects a
programmatic LSID. In many cases, the two LSID flavors are identical and
the existing code worked. But under some conditions, the browser LSID
could be different, causing /GetUserInfo to fail.

This CL switches to /ListAccounts instead, which handles browser LSIDs.
An additional advantage of /ListAccounts is that it will read the LSID
from cookies, removing the need to extract the LSID from the cookie jar
explicitly.

I could have further simplified the code by doing an XHR to /ListAccounts
from the JS code of the auth extension, avoiding the JS -> C++ -> JS round
trip. However, this would have been a CORS request, requiring the GAIA
URL to be hard-coded in the auth extension's manifest. The implementation
in this CL, which makes the /ListAccounts call from C++, is more flexible
as it preserves the ability to change the GAIA URL via a command-line
flag.

BUG=332132
TEST=Updated browser test and manual

Review URL: https://codereview.chromium.org/134483008

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@245585 0039d316-1c4b-4281-b951-d872f2087c98
parent 7c456e1f
...@@ -4,84 +4,39 @@ ...@@ -4,84 +4,39 @@
#include "chrome/browser/ui/webui/chromeos/login/authenticated_user_email_retriever.h" #include "chrome/browser/ui/webui/chromeos/login/authenticated_user_email_retriever.h"
#include "base/bind.h" #include <vector>
#include "base/callback.h"
#include "base/location.h" #include "google_apis/gaia/gaia_auth_util.h"
#include "base/logging.h"
#include "content/public/browser/browser_thread.h"
#include "google_apis/gaia/gaia_auth_fetcher.h"
#include "google_apis/gaia/gaia_constants.h" #include "google_apis/gaia/gaia_constants.h"
#include "google_apis/gaia/gaia_urls.h"
#include "google_apis/gaia/google_service_auth_error.h" #include "google_apis/gaia/google_service_auth_error.h"
#include "net/cookies/cookie_monster.h" #include "net/url_request/url_request_context_getter.h"
#include "net/url_request/url_request_context.h"
#include "url/gurl.h"
namespace chromeos { namespace chromeos {
namespace {
scoped_refptr<net::CookieStore> GetCookieStoreOnIO(
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
return url_request_context_getter->GetURLRequestContext()->cookie_store();
}
} // namespace
AuthenticatedUserEmailRetriever::AuthenticatedUserEmailRetriever( AuthenticatedUserEmailRetriever::AuthenticatedUserEmailRetriever(
const AuthenticatedUserEmailCallback& callback, const AuthenticatedUserEmailCallback& callback,
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter) scoped_refptr<net::URLRequestContextGetter> url_request_context_getter)
: callback_(callback), : callback_(callback),
url_request_context_getter_(url_request_context_getter), gaia_auth_fetcher_(this,
weak_factory_(this) { GaiaConstants::kChromeSource,
content::BrowserThread::PostTaskAndReplyWithResult( url_request_context_getter) {
content::BrowserThread::IO, gaia_auth_fetcher_.StartListAccounts();
FROM_HERE,
base::Bind(&GetCookieStoreOnIO, url_request_context_getter),
base::Bind(&AuthenticatedUserEmailRetriever::ExtractCookies,
weak_factory_.GetWeakPtr()));
} }
AuthenticatedUserEmailRetriever::~AuthenticatedUserEmailRetriever() { AuthenticatedUserEmailRetriever::~AuthenticatedUserEmailRetriever() {
} }
void AuthenticatedUserEmailRetriever::OnGetUserInfoSuccess( void AuthenticatedUserEmailRetriever::OnListAccountsSuccess(
const UserInfoMap& data) { const std::string& data) {
UserInfoMap::const_iterator it = data.find("email"); std::vector<std::string> accounts = gaia::ParseListAccountsData(data);
callback_.Run(it != data.end() ? it->second : ""); if (accounts.size() != 1)
}
void AuthenticatedUserEmailRetriever::OnGetUserInfoFailure(
const GoogleServiceAuthError& error) {
callback_.Run(std::string());
}
void AuthenticatedUserEmailRetriever::ExtractCookies(
scoped_refptr<net::CookieStore> cookie_store) {
if (!cookie_store) {
callback_.Run(std::string()); callback_.Run(std::string());
return; else
} callback_.Run(accounts.front());
cookie_store->GetCookieMonster()->GetAllCookiesForURLAsync(
GaiaUrls::GetInstance()->gaia_url(),
base::Bind(&AuthenticatedUserEmailRetriever::ExtractLSIDFromCookies,
weak_factory_.GetWeakPtr()));
} }
void AuthenticatedUserEmailRetriever::ExtractLSIDFromCookies( void AuthenticatedUserEmailRetriever::OnListAccountsFailure(
const net::CookieList& cookies) { const GoogleServiceAuthError& error) {
for (net::CookieList::const_iterator it = cookies.begin();
it != cookies.end(); ++it) {
if (it->Name() == "LSID") {
gaia_auth_fetcher_.reset(new GaiaAuthFetcher(
this,
GaiaConstants::kChromeSource,
url_request_context_getter_));
gaia_auth_fetcher_->StartGetUserInfo(it->Value());
return;
}
}
callback_.Run(std::string()); callback_.Run(std::string());
} }
......
...@@ -8,17 +8,18 @@ ...@@ -8,17 +8,18 @@
#include <string> #include <string>
#include "base/basictypes.h" #include "base/basictypes.h"
#include "base/callback_forward.h" #include "base/callback.h"
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "google_apis/gaia/gaia_auth_consumer.h" #include "google_apis/gaia/gaia_auth_consumer.h"
#include "net/cookies/canonical_cookie.h" #include "google_apis/gaia/gaia_auth_fetcher.h"
#include "net/cookies/cookie_store.h"
#include "net/url_request/url_request_context_getter.h"
class GaiaAuthFetcher; class GaiaAuthFetcher;
namespace net {
class URLRequestContextGetter;
}
namespace chromeos { namespace chromeos {
// Helper class that retrieves the authenticated user's e-mail address. // Helper class that retrieves the authenticated user's e-mail address.
...@@ -27,30 +28,23 @@ class AuthenticatedUserEmailRetriever : public GaiaAuthConsumer { ...@@ -27,30 +28,23 @@ class AuthenticatedUserEmailRetriever : public GaiaAuthConsumer {
typedef base::Callback<void(const std::string&)> typedef base::Callback<void(const std::string&)>
AuthenticatedUserEmailCallback; AuthenticatedUserEmailCallback;
// Extracts the GAIA cookies from |url_request_context_getter|, retrieves the // Retrieves the authenticated user's e-mail address from GAIA and passes it
// authenticated user's e-mail address from GAIA and passes it to |callback|. // to |callback|. Requires that |url_request_context_getter| contain the GAIA
// If the e-mail address cannot be retrieved, an empty string is passed to // cookies for exactly one user. If the e-mail address cannot be retrieved, an
// the |callback|. // empty string is passed to the |callback|.
AuthenticatedUserEmailRetriever( AuthenticatedUserEmailRetriever(
const AuthenticatedUserEmailCallback& callback, const AuthenticatedUserEmailCallback& callback,
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter); scoped_refptr<net::URLRequestContextGetter> url_request_context_getter);
virtual ~AuthenticatedUserEmailRetriever(); virtual ~AuthenticatedUserEmailRetriever();
// GaiaAuthConsumer: // GaiaAuthConsumer:
virtual void OnGetUserInfoSuccess(const UserInfoMap& data) OVERRIDE; virtual void OnListAccountsSuccess(const std::string& data) OVERRIDE;
virtual void OnGetUserInfoFailure( virtual void OnListAccountsFailure(const GoogleServiceAuthError& error)
const GoogleServiceAuthError& error) OVERRIDE; OVERRIDE;
private: private:
void ExtractCookies(scoped_refptr<net::CookieStore> cookie_store); const AuthenticatedUserEmailCallback callback_;
void ExtractLSIDFromCookies(const net::CookieList& cookies); GaiaAuthFetcher gaia_auth_fetcher_;
AuthenticatedUserEmailCallback callback_;
scoped_refptr<net::URLRequestContextGetter> url_request_context_getter_;
scoped_ptr<GaiaAuthFetcher> gaia_auth_fetcher_;
base::WeakPtrFactory<AuthenticatedUserEmailRetriever> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(AuthenticatedUserEmailRetriever); DISALLOW_COPY_AND_ASSIGN(AuthenticatedUserEmailRetriever);
}; };
......
...@@ -47,6 +47,9 @@ const base::FilePath::CharType kServiceLogin[] = ...@@ -47,6 +47,9 @@ const base::FilePath::CharType kServiceLogin[] =
const char kAuthHeaderBearer[] = "Bearer "; const char kAuthHeaderBearer[] = "Bearer ";
const char kAuthHeaderOAuth[] = "OAuth "; const char kAuthHeaderOAuth[] = "OAuth ";
const char kListAccountsResponseFormat[] =
"[\"gaia.l.a.r\",[[\"gaia.l.a\",1,\"\",\"%s\",\"\",1,1,0]]]";
typedef std::map<std::string, std::string> CookieMap; typedef std::map<std::string, std::string> CookieMap;
// Parses cookie name-value map our of |request|. // Parses cookie name-value map our of |request|.
...@@ -169,9 +172,9 @@ void FakeGaia::Initialize() { ...@@ -169,9 +172,9 @@ void FakeGaia::Initialize() {
REGISTER_RESPONSE_HANDLER( REGISTER_RESPONSE_HANDLER(
gaia_urls->oauth2_issue_token_url(), HandleIssueToken); gaia_urls->oauth2_issue_token_url(), HandleIssueToken);
// Handles /GetUserInfo GAIA call. // Handles /ListAccounts GAIA call.
REGISTER_RESPONSE_HANDLER( REGISTER_RESPONSE_HANDLER(
gaia_urls->get_user_info_url(), HandleGetUserInfo); gaia_urls->list_accounts_url(), HandleListAccounts);
} }
scoped_ptr<HttpResponse> FakeGaia::HandleRequest(const HttpRequest& request) { scoped_ptr<HttpResponse> FakeGaia::HandleRequest(const HttpRequest& request) {
...@@ -519,20 +522,9 @@ void FakeGaia::HandleIssueToken(const HttpRequest& request, ...@@ -519,20 +522,9 @@ void FakeGaia::HandleIssueToken(const HttpRequest& request,
} }
} }
void FakeGaia::HandleGetUserInfo(const HttpRequest& request, void FakeGaia::HandleListAccounts(const HttpRequest& request,
BasicHttpResponse* http_response) { BasicHttpResponse* http_response) {
std::string lsid;
if (!GetQueryParameter(request.content, "LSID", &lsid)) {
http_response->set_code(net::HTTP_BAD_REQUEST);
LOG(ERROR) << "/GetUserInfo missing LSID";
return;
}
if (lsid != merge_session_params_.auth_lsid_cookie) {
http_response->set_code(net::HTTP_BAD_REQUEST);
LOG(ERROR) << "/GetUserInfo contains unknown LSID";
return;
}
http_response->set_content(base::StringPrintf( http_response->set_content(base::StringPrintf(
"email=%s", merge_session_params_.email.c_str())); kListAccountsResponseFormat, merge_session_params_.email.c_str()));
http_response->set_code(net::HTTP_OK); http_response->set_code(net::HTTP_OK);
} }
...@@ -72,7 +72,7 @@ class FakeGaia { ...@@ -72,7 +72,7 @@ class FakeGaia {
std::string session_sid_cookie; std::string session_sid_cookie;
std::string session_lsid_cookie; std::string session_lsid_cookie;
// The e-mail address returned by /GetUserInfo. // The e-mail address returned by /ListAccounts.
std::string email; std::string email;
}; };
...@@ -148,8 +148,8 @@ class FakeGaia { ...@@ -148,8 +148,8 @@ class FakeGaia {
net::test_server::BasicHttpResponse* http_response); net::test_server::BasicHttpResponse* http_response);
void HandleIssueToken(const net::test_server::HttpRequest& request, void HandleIssueToken(const net::test_server::HttpRequest& request,
net::test_server::BasicHttpResponse* http_response); net::test_server::BasicHttpResponse* http_response);
void HandleGetUserInfo(const net::test_server::HttpRequest& request, void HandleListAccounts(const net::test_server::HttpRequest& request,
net::test_server::BasicHttpResponse* http_response); net::test_server::BasicHttpResponse* http_response);
// Returns the access token associated with |auth_token| that matches the // Returns the access token associated with |auth_token| that matches the
// given |client_id| and |scope_string|. If |scope_string| is empty, the first // given |client_id| and |scope_string|. If |scope_string| is empty, the first
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment