test_oauth_token_getter.cc 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. // Copyright 2019 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. #include "remoting/test/test_oauth_token_getter.h"
  5. #include <utility>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/command_line.h"
  9. #include "base/strings/escape.h"
  10. #include "base/strings/stringprintf.h"
  11. #include "base/threading/thread_task_runner_handle.h"
  12. #include "google_apis/google_api_keys.h"
  13. #include "remoting/base/fake_oauth_token_getter.h"
  14. #include "remoting/base/oauth_token_getter_impl.h"
  15. #include "remoting/base/url_request_context_getter.h"
  16. #include "remoting/test/cli_util.h"
  17. #include "remoting/test/test_token_storage.h"
  18. #include "services/network/public/cpp/shared_url_loader_factory.h"
  19. #include "services/network/transitional_url_loader_factory_owner.h"
  20. namespace remoting {
  21. namespace test {
  22. namespace {
  23. constexpr char kChromotingAuthScopeValues[] =
  24. "https://www.googleapis.com/auth/chromoting.me2me.host "
  25. "https://www.googleapis.com/auth/chromoting.remote.support "
  26. "https://www.googleapis.com/auth/userinfo.email "
  27. "https://www.googleapis.com/auth/tachyon";
  28. constexpr char kOauthRedirectUrl[] =
  29. "https://remotedesktop.google.com/_/oauthredirect";
  30. std::string GetAuthorizationCodeUri(bool show_consent_page) {
  31. // Replace space characters with a '+' sign when formatting.
  32. bool use_plus = true;
  33. std::string uri = base::StringPrintf(
  34. "https://accounts.google.com/o/oauth2/auth"
  35. "?scope=%s"
  36. "&redirect_uri=https://remotedesktop.google.com/_/oauthredirect"
  37. "&response_type=code"
  38. "&client_id=%s"
  39. "&access_type=offline",
  40. base::EscapeUrlEncodedData(kChromotingAuthScopeValues, use_plus).c_str(),
  41. base::EscapeUrlEncodedData(
  42. google_apis::GetOAuth2ClientID(google_apis::CLIENT_REMOTING),
  43. use_plus)
  44. .c_str());
  45. if (show_consent_page) {
  46. uri += "&approval_prompt=force";
  47. }
  48. return uri;
  49. }
  50. } // namespace
  51. constexpr char TestOAuthTokenGetter::kSwitchNameAuthCode[];
  52. // static
  53. bool TestOAuthTokenGetter::IsServiceAccount(const std::string& email) {
  54. return email.find("@chromoting.gserviceaccount.com") != std::string::npos;
  55. }
  56. TestOAuthTokenGetter::TestOAuthTokenGetter(TestTokenStorage* token_storage) {
  57. DCHECK(token_storage);
  58. token_storage_ = token_storage;
  59. auto url_request_context_getter =
  60. base::MakeRefCounted<URLRequestContextGetter>(
  61. base::ThreadTaskRunnerHandle::Get());
  62. url_loader_factory_owner_ =
  63. std::make_unique<network::TransitionalURLLoaderFactoryOwner>(
  64. url_request_context_getter);
  65. }
  66. TestOAuthTokenGetter::~TestOAuthTokenGetter() = default;
  67. void TestOAuthTokenGetter::Initialize(base::OnceClosure on_done) {
  68. std::string user_email = token_storage_->FetchUserEmail();
  69. std::string access_token = token_storage_->FetchAccessToken();
  70. std::string refresh_token = token_storage_->FetchRefreshToken();
  71. if (user_email.empty() || (access_token.empty() && refresh_token.empty())) {
  72. ResetWithAuthenticationFlow(std::move(on_done));
  73. return;
  74. }
  75. VLOG(0) << "Reusing user_email: " << user_email;
  76. if (!refresh_token.empty()) {
  77. VLOG(0) << "Reusing refresh_token: " << refresh_token;
  78. token_getter_ = CreateWithRefreshToken(refresh_token, user_email);
  79. } else {
  80. VLOG(0) << "Reusing access token: " << access_token;
  81. token_getter_ = std::make_unique<FakeOAuthTokenGetter>(
  82. OAuthTokenGetter::Status::SUCCESS, user_email, access_token);
  83. }
  84. std::move(on_done).Run();
  85. }
  86. void TestOAuthTokenGetter::ResetWithAuthenticationFlow(
  87. base::OnceClosure on_done) {
  88. on_authentication_done_.push(std::move(on_done));
  89. InvalidateCache();
  90. }
  91. void TestOAuthTokenGetter::CallWithToken(TokenCallback on_access_token) {
  92. token_getter_->CallWithToken(std::move(on_access_token));
  93. }
  94. void TestOAuthTokenGetter::InvalidateCache() {
  95. if (is_authenticating_) {
  96. return;
  97. }
  98. is_authenticating_ = true;
  99. printf(
  100. "Is your account allowlisted to use 1P scope in consent page? [Y/n]: ");
  101. bool show_consent_page = test::ReadYNBool(true);
  102. static const std::string read_auth_code_prompt = base::StringPrintf(
  103. "Please authenticate at:\n\n"
  104. " %s\n\n"
  105. "Enter the auth code: ",
  106. GetAuthorizationCodeUri(show_consent_page).c_str());
  107. std::string auth_code = test::ReadStringFromCommandLineOrStdin(
  108. kSwitchNameAuthCode, read_auth_code_prompt);
  109. // Make sure we don't try to reuse an auth code.
  110. base::CommandLine::ForCurrentProcess()->RemoveSwitch(kSwitchNameAuthCode);
  111. token_getter_ = CreateFromIntermediateCredentials(
  112. auth_code, base::BindRepeating(&TestOAuthTokenGetter::OnCredentialsUpdate,
  113. weak_factory_.GetWeakPtr()));
  114. // This triggers |OnCredentialsUpdate| to be called.
  115. token_getter_->CallWithToken(base::DoNothing());
  116. }
  117. base::WeakPtr<TestOAuthTokenGetter> TestOAuthTokenGetter::GetWeakPtr() {
  118. return weak_factory_.GetWeakPtr();
  119. }
  120. std::unique_ptr<OAuthTokenGetter>
  121. TestOAuthTokenGetter::CreateFromIntermediateCredentials(
  122. const std::string& auth_code,
  123. const OAuthTokenGetter::CredentialsUpdatedCallback& on_credentials_update) {
  124. auto oauth_credentials =
  125. std::make_unique<OAuthTokenGetter::OAuthIntermediateCredentials>(
  126. auth_code, /* is_service_account */ false);
  127. oauth_credentials->oauth_redirect_uri = kOauthRedirectUrl;
  128. return std::make_unique<OAuthTokenGetterImpl>(
  129. std::move(oauth_credentials), on_credentials_update,
  130. url_loader_factory_owner_->GetURLLoaderFactory(),
  131. /* auto_refresh */ true);
  132. }
  133. std::unique_ptr<OAuthTokenGetter> TestOAuthTokenGetter::CreateWithRefreshToken(
  134. const std::string& refresh_token,
  135. const std::string& email) {
  136. bool is_service_account = IsServiceAccount(email);
  137. auto oauth_credentials =
  138. std::make_unique<OAuthTokenGetter::OAuthAuthorizationCredentials>(
  139. email, refresh_token, is_service_account);
  140. return std::make_unique<OAuthTokenGetterImpl>(
  141. std::move(oauth_credentials),
  142. url_loader_factory_owner_->GetURLLoaderFactory(),
  143. /*auto_refresh=*/true);
  144. }
  145. void TestOAuthTokenGetter::OnCredentialsUpdate(
  146. const std::string& user_email,
  147. const std::string& refresh_token) {
  148. VLOG(0) << "Received user_email: " << user_email
  149. << ", refresh_token: " << refresh_token;
  150. token_storage_->StoreUserEmail(user_email);
  151. if (refresh_token.empty()) {
  152. VLOG(0)
  153. << "No refresh token is returned. Will cache the access token instead.";
  154. token_getter_->CallWithToken(base::BindOnce(
  155. &TestOAuthTokenGetter::OnAccessToken, weak_factory_.GetWeakPtr()));
  156. return;
  157. }
  158. is_authenticating_ = false;
  159. token_storage_->StoreRefreshToken(refresh_token);
  160. RunAuthenticationDoneCallbacks();
  161. }
  162. void TestOAuthTokenGetter::OnAccessToken(OAuthTokenGetter::Status status,
  163. const std::string& user_email,
  164. const std::string& access_token) {
  165. is_authenticating_ = false;
  166. if (status != OAuthTokenGetter::Status::SUCCESS) {
  167. fprintf(stderr,
  168. "Failed to authenticate. Please check if your access token is "
  169. "correct.\n");
  170. InvalidateCache();
  171. return;
  172. }
  173. VLOG(0) << "Received access_token: " << access_token;
  174. token_storage_->StoreAccessToken(access_token);
  175. RunAuthenticationDoneCallbacks();
  176. }
  177. void TestOAuthTokenGetter::RunAuthenticationDoneCallbacks() {
  178. while (!on_authentication_done_.empty()) {
  179. std::move(on_authentication_done_.front()).Run();
  180. on_authentication_done_.pop();
  181. }
  182. }
  183. } // namespace test
  184. } // namespace remoting