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 3 // found in the LICENSE file. 4 5 #include "chrome/browser/signin/signin_manager.h" 6 7 #include "base/bind.h" 8 #include "base/bind_helpers.h" 9 #include "base/compiler_specific.h" 10 #include "base/prefs/pref_service.h" 11 #include "base/prefs/testing_pref_service.h" 12 #include "base/run_loop.h" 13 #include "base/strings/stringprintf.h" 14 #include "chrome/browser/browser_process.h" 15 #include "chrome/browser/chrome_notification_types.h" 16 #include "chrome/browser/prefs/browser_prefs.h" 17 #include "chrome/browser/signin/chrome_signin_manager_delegate.h" 18 #include "chrome/browser/signin/fake_profile_oauth2_token_service.h" 19 #include "chrome/browser/signin/profile_oauth2_token_service.h" 20 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h" 21 #include "chrome/browser/signin/signin_manager_factory.h" 22 #include "chrome/common/pref_names.h" 23 #include "chrome/common/url_constants.h" 24 #include "chrome/test/base/testing_browser_process.h" 25 #include "chrome/test/base/testing_profile.h" 26 #include "components/webdata/encryptor/encryptor.h" 27 #include "content/public/browser/child_process_security_policy.h" 28 #include "content/public/browser/notification_source.h" 29 #include "content/public/test/test_browser_thread_bundle.h" 30 #include "content/public/test/test_notification_tracker.h" 31 #include "google_apis/gaia/gaia_constants.h" 32 #include "google_apis/gaia/gaia_urls.h" 33 #include "net/cookies/cookie_monster.h" 34 #include "net/url_request/test_url_fetcher_factory.h" 35 #include "net/url_request/url_request.h" 36 #include "net/url_request/url_request_context_getter.h" 37 #include "net/url_request/url_request_status.h" 38 39 #include "testing/gmock/include/gmock/gmock.h" 40 #include "testing/gtest/include/gtest/gtest.h" 41 42 namespace { 43 44 const char kGetTokenPairValidResponse[] = 45 "{" 46 " \"refresh_token\": \"rt1\"," 47 " \"access_token\": \"at1\"," 48 " \"expires_in\": 3600," 49 " \"token_type\": \"Bearer\"" 50 "}"; 51 52 const char kUberAuthTokenURLFormat[] = "?source=%s&issueuberauth=1"; 53 54 BrowserContextKeyedService* SigninManagerBuild( 55 content::BrowserContext* context) { 56 SigninManager* service = NULL; 57 Profile* profile = static_cast<Profile*>(context); 58 service = new SigninManager( 59 scoped_ptr<SigninManagerDelegate>( 60 new ChromeSigninManagerDelegate(profile))); 61 service->Initialize(profile, NULL); 62 return service; 63 } 64 65 } // namespace 66 67 68 class SigninManagerTest : public testing::Test { 69 public: 70 SigninManagerTest() : manager_(NULL) {} 71 virtual ~SigninManagerTest() {} 72 73 virtual void SetUp() OVERRIDE { 74 manager_ = NULL; 75 prefs_.reset(new TestingPrefServiceSimple); 76 chrome::RegisterLocalState(prefs_->registry()); 77 TestingBrowserProcess::GetGlobal()->SetLocalState( 78 prefs_.get()); 79 TestingProfile::Builder builder; 80 builder.AddTestingFactory(ProfileOAuth2TokenServiceFactory::GetInstance(), 81 FakeProfileOAuth2TokenService::Build); 82 profile_ = builder.Build(); 83 google_login_success_.ListenFor( 84 chrome::NOTIFICATION_GOOGLE_SIGNIN_SUCCESSFUL, 85 content::Source<Profile>(profile())); 86 google_login_failure_.ListenFor(chrome::NOTIFICATION_GOOGLE_SIGNIN_FAILED, 87 content::Source<Profile>(profile())); 88 } 89 90 virtual void TearDown() OVERRIDE { 91 // Destroy the SigninManager here, because it relies on profile() which is 92 // freed in the base class. 93 if (naked_manager_) { 94 naked_manager_->Shutdown(); 95 naked_manager_.reset(NULL); 96 } 97 TestingBrowserProcess::GetGlobal()->SetLocalState(NULL); 98 99 // Manually destroy PrefService and Profile so that they are shutdown 100 // in the correct order. Both need to be destroyed before the 101 // |thread_bundle_| member. 102 prefs_.reset(); 103 profile_.reset(); 104 } 105 106 TestingProfile* profile() { return profile_.get(); } 107 108 // Create a signin manager as a service if other code will try to get it as 109 // a PKS. 110 void CreateSigninManagerAsService() { 111 DCHECK(!manager_); 112 DCHECK(!naked_manager_); 113 manager_ = static_cast<SigninManager*>( 114 SigninManagerFactory::GetInstance()->SetTestingFactoryAndUse( 115 profile(), SigninManagerBuild)); 116 } 117 118 // Create a naked signin manager if integration with PKSs is not needed. 119 void CreateNakedSigninManager() { 120 DCHECK(!manager_); 121 naked_manager_.reset(new SigninManager( 122 scoped_ptr<SigninManagerDelegate>( 123 new ChromeSigninManagerDelegate(profile())))); 124 125 manager_ = naked_manager_.get(); 126 } 127 128 void SetupFetcherAndComplete(const GURL& url, 129 int response_code, 130 const net::ResponseCookies& cookies, 131 const std::string& response_string) { 132 net::TestURLFetcher* fetcher = factory_.GetFetcherByID(0); 133 DCHECK(fetcher); 134 DCHECK(fetcher->delegate()); 135 136 cookies_.insert(cookies_.end(), cookies.begin(), cookies.end()); 137 fetcher->set_url(url); 138 fetcher->set_status(net::URLRequestStatus()); 139 fetcher->set_response_code(response_code); 140 fetcher->SetResponseString(response_string); 141 fetcher->set_cookies(cookies); 142 fetcher->delegate()->OnURLFetchComplete(fetcher); 143 } 144 145 void SimulateValidResponseSignInWithCredentials() { 146 // Simulate the correct StartOAuthLoginTokenFetch response. This involves 147 // two separate fetches. 148 SetupFetcherAndComplete( 149 GaiaUrls::GetInstance()->client_login_to_oauth2_url(), 200, 150 net::ResponseCookies(), kGetTokenPairValidResponse); 151 152 SetupFetcherAndComplete(GaiaUrls::GetInstance()->oauth2_token_url(), 200, 153 net::ResponseCookies(), kGetTokenPairValidResponse); 154 155 // Simulate the correct StartOAuthLogin response. 156 SetupFetcherAndComplete(GaiaUrls::GetInstance()->oauth1_login_url(), 200, 157 net::ResponseCookies(), 158 "SID=sid\nLSID=lsid\nAuth=auth_token"); 159 160 SimulateValidResponseGetClientInfo(false); 161 } 162 163 void SimulateValidResponseClientLogin(bool isGPlusUser) { 164 SetupFetcherAndComplete(GaiaUrls::GetInstance()->client_login_url(), 200, 165 net::ResponseCookies(), 166 "SID=sid\nLSID=lsid\nAuth=auth"); 167 SimulateValidResponseGetClientInfo(isGPlusUser); 168 } 169 170 void SimulateValidResponseGetClientInfo(bool isGPlusUser) { 171 // Simulate the correct ClientLogin response. 172 std::string response_string = isGPlusUser ? 173 "email=user (at) gmail.com\ndisplayEmail=USER (at) gmail.com\n" 174 "allServices=googleme" : 175 "email=user (at) gmail.com\ndisplayEmail=USER (at) gmail.com\n" 176 "allServices="; 177 SetupFetcherAndComplete(GaiaUrls::GetInstance()->get_user_info_url(), 200, 178 net::ResponseCookies(), response_string); 179 } 180 181 void SimulateValidUberToken() { 182 SetupFetcherAndComplete(GaiaUrls::GetInstance()->oauth2_token_url(), 200, 183 net::ResponseCookies(), kGetTokenPairValidResponse); 184 const GURL uberauth_token_gurl = 185 GaiaUrls::GetInstance()->oauth1_login_url().Resolve( 186 base::StringPrintf(kUberAuthTokenURLFormat, "source")); 187 SetupFetcherAndComplete(uberauth_token_gurl, 200, 188 net::ResponseCookies(), "ut1"); 189 190 net::ResponseCookies cookies; 191 cookies.push_back("checkCookie = true"); 192 SetupFetcherAndComplete(GaiaUrls::GetInstance()->merge_session_url(), 200, 193 cookies, "<html></html>"); 194 } 195 196 void ExpectSignInWithCredentialsSuccess() { 197 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 198 199 SimulateValidResponseSignInWithCredentials(); 200 201 EXPECT_FALSE(manager_->GetAuthenticatedUsername().empty()); 202 203 ProfileOAuth2TokenService* token_service = 204 ProfileOAuth2TokenServiceFactory::GetForProfile(profile()); 205 EXPECT_TRUE(token_service->RefreshTokenIsAvailable( 206 manager_->GetAuthenticatedUsername())); 207 208 // Should go into token service and stop. 209 EXPECT_EQ(1U, google_login_success_.size()); 210 EXPECT_EQ(0U, google_login_failure_.size()); 211 } 212 213 // Helper method that wraps the logic when signin with credentials 214 // should fail. If |requestSent| is true, then simulate valid resopnse. 215 // Otherwise the sign-in is aborted before any request is sent, thus no need 216 // to simulatate response. 217 void ExpectSignInWithCredentialsFail(bool requestSent) { 218 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 219 220 if (requestSent) 221 SimulateValidResponseSignInWithCredentials(); 222 223 ProfileOAuth2TokenService* token_service = 224 ProfileOAuth2TokenServiceFactory::GetForProfile(profile()); 225 EXPECT_FALSE(token_service->RefreshTokenIsAvailable( 226 manager_->GetAuthenticatedUsername())); 227 228 // Should go into token service and stop. 229 EXPECT_EQ(0U, google_login_success_.size()); 230 EXPECT_EQ(1U, google_login_failure_.size()); 231 } 232 233 void CompleteSigninCallback(const std::string& oauth_token) { 234 oauth_tokens_fetched_.push_back(oauth_token); 235 manager_->CompletePendingSignin(); 236 } 237 238 void CancelSigninCallback(const std::string& oauth_token) { 239 oauth_tokens_fetched_.push_back(oauth_token); 240 manager_->SignOut(); 241 } 242 243 content::TestBrowserThreadBundle thread_bundle_; 244 net::TestURLFetcherFactory factory_; 245 scoped_ptr<SigninManager> naked_manager_; 246 SigninManager* manager_; 247 scoped_ptr<TestingProfile> profile_; 248 content::TestNotificationTracker google_login_success_; 249 content::TestNotificationTracker google_login_failure_; 250 std::vector<std::string> oauth_tokens_fetched_; 251 scoped_ptr<TestingPrefServiceSimple> prefs_; 252 std::vector<std::string> cookies_; 253 }; 254 255 TEST_F(SigninManagerTest, SignInWithCredentials) { 256 CreateSigninManagerAsService(); 257 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 258 259 manager_->StartSignInWithCredentials( 260 "0", 261 "user (at) gmail.com", 262 "password", 263 SigninManager::OAuthTokenFetchedCallback()); 264 265 ExpectSignInWithCredentialsSuccess(); 266 267 // Should persist across resets. 268 manager_->Shutdown(); 269 manager_ = NULL; 270 CreateNakedSigninManager(); 271 manager_->Initialize(profile(), NULL); 272 EXPECT_EQ("user (at) gmail.com", manager_->GetAuthenticatedUsername()); 273 } 274 275 TEST_F(SigninManagerTest, SignInWithCredentialsNonCanonicalEmail) { 276 CreateSigninManagerAsService(); 277 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 278 279 manager_->StartSignInWithCredentials( 280 "0", 281 "user", 282 "password", 283 SigninManager::OAuthTokenFetchedCallback()); 284 285 ExpectSignInWithCredentialsSuccess(); 286 } 287 288 TEST_F(SigninManagerTest, SignInWithCredentialsWrongEmail) { 289 CreateSigninManagerAsService(); 290 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 291 292 // If the email address used to start the sign in does not match the 293 // email address returned by /GetUserInfo, the sign in should fail. 294 manager_->StartSignInWithCredentials( 295 "0", 296 "user2 (at) gmail.com", 297 "password", 298 SigninManager::OAuthTokenFetchedCallback()); 299 300 ExpectSignInWithCredentialsFail(true /* requestSent */); 301 } 302 303 TEST_F(SigninManagerTest, SignInWithCredentialsEmptyPasswordValidCookie) { 304 CreateSigninManagerAsService(); 305 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 306 307 // Set a valid LSID cookie in the test cookie store. 308 scoped_refptr<net::CookieMonster> cookie_monster = 309 profile()->GetCookieMonster(); 310 net::CookieOptions options; 311 options.set_include_httponly(); 312 cookie_monster->SetCookieWithOptionsAsync( 313 GURL("https://accounts.google.com"), 314 "LSID=1234; secure; httponly", options, 315 net::CookieMonster::SetCookiesCallback()); 316 317 // Since the password is empty, will verify the gaia cookies first. 318 manager_->StartSignInWithCredentials( 319 "0", 320 "user (at) gmail.com", 321 std::string(), 322 SigninManager::OAuthTokenFetchedCallback()); 323 324 base::RunLoop().RunUntilIdle(); 325 326 // Verification should succeed and continue with auto signin. 327 ExpectSignInWithCredentialsSuccess(); 328 } 329 330 TEST_F(SigninManagerTest, SignInWithCredentialsEmptyPasswordNoValidCookie) { 331 CreateSigninManagerAsService(); 332 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 333 334 // Since the password is empty, will verify the gaia cookies first. 335 manager_->StartSignInWithCredentials( 336 "0", 337 "user (at) gmail.com", 338 std::string(), 339 SigninManager::OAuthTokenFetchedCallback()); 340 341 base::RunLoop().RunUntilIdle(); 342 343 // Since the test cookie store is empty, verification should fail and throws 344 // a login error. 345 ExpectSignInWithCredentialsFail(false /* requestSent */); 346 } 347 348 TEST_F(SigninManagerTest, SignInWithCredentialsEmptyPasswordInValidCookie) { 349 CreateSigninManagerAsService(); 350 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 351 352 // Set an invalid LSID cookie in the test cookie store. 353 scoped_refptr<net::CookieMonster> cookie_monster = 354 profile()->GetCookieMonster(); 355 net::CookieOptions options; 356 options.set_include_httponly(); 357 cookie_monster->SetCookieWithOptionsAsync( 358 GURL("https://accounts.google.com"), 359 "LSID=1234; domain=google.com; secure; httponly", options, 360 net::CookieMonster::SetCookiesCallback()); 361 362 // Since the password is empty, must verify the gaia cookies first. 363 manager_->StartSignInWithCredentials( 364 "0", 365 "user (at) gmail.com", 366 std::string(), 367 SigninManager::OAuthTokenFetchedCallback()); 368 369 base::RunLoop().RunUntilIdle(); 370 371 // Since the LSID cookie is invalid, verification should fail and throws 372 // a login error. 373 ExpectSignInWithCredentialsFail(false /* requestSent */); 374 } 375 376 TEST_F(SigninManagerTest, SignInWithCredentialsCallbackComplete) { 377 CreateSigninManagerAsService(); 378 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 379 380 // Since the password is empty, must verify the gaia cookies first. 381 SigninManager::OAuthTokenFetchedCallback callback = 382 base::Bind(&SigninManagerTest::CompleteSigninCallback, 383 base::Unretained(this)); 384 manager_->StartSignInWithCredentials( 385 "0", 386 "user (at) gmail.com", 387 "password", 388 callback); 389 390 ExpectSignInWithCredentialsSuccess(); 391 ASSERT_EQ(1U, oauth_tokens_fetched_.size()); 392 EXPECT_EQ(oauth_tokens_fetched_[0], "rt1"); 393 } 394 395 TEST_F(SigninManagerTest, SignInWithCredentialsCallbackCancel) { 396 CreateSigninManagerAsService(); 397 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 398 399 // Since the password is empty, must verify the gaia cookies first. 400 SigninManager::OAuthTokenFetchedCallback callback = 401 base::Bind(&SigninManagerTest::CancelSigninCallback, 402 base::Unretained(this)); 403 manager_->StartSignInWithCredentials( 404 "0", 405 "user (at) gmail.com", 406 "password", 407 callback); 408 409 // Signin should fail since it would be cancelled by the callback. 410 ExpectSignInWithCredentialsFail(true); 411 ASSERT_EQ(1U, oauth_tokens_fetched_.size()); 412 EXPECT_EQ(oauth_tokens_fetched_[0], "rt1"); 413 } 414 415 TEST_F(SigninManagerTest, SignOut) { 416 CreateSigninManagerAsService(); 417 SigninManager::OAuthTokenFetchedCallback dummy; 418 manager_->StartSignInWithCredentials("0", "user (at) gmail.com", "password", 419 dummy); 420 ExpectSignInWithCredentialsSuccess(); 421 422 manager_->SignOut(); 423 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 424 // Should not be persisted anymore 425 manager_->Shutdown(); 426 manager_ = NULL; 427 CreateNakedSigninManager(); 428 manager_->Initialize(profile(), NULL); 429 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 430 } 431 432 TEST_F(SigninManagerTest, SignOutMidConnect) { 433 CreateSigninManagerAsService(); 434 SigninManager::OAuthTokenFetchedCallback dummy; 435 manager_->StartSignInWithCredentials("0", "user (at) gmail.com", "password", 436 dummy); 437 438 manager_->SignOut(); 439 EXPECT_EQ(0U, google_login_success_.size()); 440 EXPECT_EQ(1U, google_login_failure_.size()); 441 442 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 443 EXPECT_TRUE(manager_->GetUsernameForAuthInProgress().empty()); 444 } 445 446 TEST_F(SigninManagerTest, SignOutWhileProhibited) { 447 CreateSigninManagerAsService(); 448 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 449 450 manager_->SetAuthenticatedUsername("user (at) gmail.com"); 451 manager_->ProhibitSignout(true); 452 manager_->SignOut(); 453 EXPECT_FALSE(manager_->GetAuthenticatedUsername().empty()); 454 manager_->ProhibitSignout(false); 455 manager_->SignOut(); 456 EXPECT_TRUE(manager_->GetAuthenticatedUsername().empty()); 457 } 458 459 TEST_F(SigninManagerTest, TestIsWebBasedSigninFlowURL) { 460 EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL( 461 GURL("http://www.google.com"))); 462 EXPECT_TRUE(SigninManager::IsWebBasedSigninFlowURL( 463 GURL("https://accounts.google.com/ServiceLogin?service=chromiumsync"))); 464 EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL( 465 GURL("http://accounts.google.com/ServiceLogin?service=chromiumsync"))); 466 // http, not https, should not be treated as web based signin. 467 EXPECT_FALSE(SigninManager::IsWebBasedSigninFlowURL( 468 GURL("http://accounts.google.com/ServiceLogin?service=googlemail"))); 469 // chromiumsync is double-embedded in a continue query param. 470 EXPECT_TRUE(SigninManager::IsWebBasedSigninFlowURL( 471 GURL("https://accounts.google.com/CheckCookie?" 472 "continue=https%3A%2F%2Fwww.google.com%2Fintl%2Fen-US%2Fchrome" 473 "%2Fblank.html%3Fsource%3D3%26nonadv%3D1&service=chromiumsync"))); 474 } 475 476 TEST_F(SigninManagerTest, Prohibited) { 477 g_browser_process->local_state()->SetString( 478 prefs::kGoogleServicesUsernamePattern, ".*@google.com"); 479 CreateNakedSigninManager(); 480 manager_->Initialize(profile(), g_browser_process->local_state()); 481 EXPECT_TRUE(manager_->IsAllowedUsername("test (at) google.com")); 482 EXPECT_TRUE(manager_->IsAllowedUsername("happy (at) google.com")); 483 EXPECT_FALSE(manager_->IsAllowedUsername("test (at) invalid.com")); 484 EXPECT_FALSE(manager_->IsAllowedUsername("test (at) notgoogle.com")); 485 EXPECT_FALSE(manager_->IsAllowedUsername(std::string())); 486 } 487 488 TEST_F(SigninManagerTest, TestAlternateWildcard) { 489 // Test to make sure we accept "*@google.com" as a pattern (treat it as if 490 // the admin entered ".*@google.com"). 491 g_browser_process->local_state()->SetString( 492 prefs::kGoogleServicesUsernamePattern, "*@google.com"); 493 CreateNakedSigninManager(); 494 manager_->Initialize(profile(), g_browser_process->local_state()); 495 EXPECT_TRUE(manager_->IsAllowedUsername("test (at) google.com")); 496 EXPECT_TRUE(manager_->IsAllowedUsername("happy (at) google.com")); 497 EXPECT_FALSE(manager_->IsAllowedUsername("test (at) invalid.com")); 498 EXPECT_FALSE(manager_->IsAllowedUsername("test (at) notgoogle.com")); 499 EXPECT_FALSE(manager_->IsAllowedUsername(std::string())); 500 } 501 502 TEST_F(SigninManagerTest, ProhibitedAtStartup) { 503 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername, 504 "monkey (at) invalid.com"); 505 g_browser_process->local_state()->SetString( 506 prefs::kGoogleServicesUsernamePattern, ".*@google.com"); 507 CreateNakedSigninManager(); 508 manager_->Initialize(profile(), g_browser_process->local_state()); 509 // Currently signed in user is prohibited by policy, so should be signed out. 510 EXPECT_EQ("", manager_->GetAuthenticatedUsername()); 511 } 512 513 TEST_F(SigninManagerTest, ProhibitedAfterStartup) { 514 std::string user("monkey (at) invalid.com"); 515 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername, user); 516 CreateNakedSigninManager(); 517 manager_->Initialize(profile(), g_browser_process->local_state()); 518 EXPECT_EQ(user, manager_->GetAuthenticatedUsername()); 519 // Update the profile - user should be signed out. 520 g_browser_process->local_state()->SetString( 521 prefs::kGoogleServicesUsernamePattern, ".*@google.com"); 522 EXPECT_EQ("", manager_->GetAuthenticatedUsername()); 523 } 524 525 TEST_F(SigninManagerTest, ExternalSignIn) { 526 CreateNakedSigninManager(); 527 manager_->Initialize(profile(), g_browser_process->local_state()); 528 EXPECT_EQ("", 529 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername)); 530 EXPECT_EQ("", manager_->GetAuthenticatedUsername()); 531 EXPECT_EQ(0u, google_login_success_.size()); 532 533 manager_->OnExternalSigninCompleted("external (at) example.com"); 534 EXPECT_EQ(1u, google_login_success_.size()); 535 EXPECT_EQ(0u, google_login_failure_.size()); 536 EXPECT_EQ("external (at) example.com", 537 profile()->GetPrefs()->GetString(prefs::kGoogleServicesUsername)); 538 EXPECT_EQ("external (at) example.com", manager_->GetAuthenticatedUsername()); 539 } 540 541 TEST_F(SigninManagerTest, SigninNotAllowed) { 542 std::string user("user (at) google.com"); 543 profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername, user); 544 profile()->GetPrefs()->SetBoolean(prefs::kSigninAllowed, false); 545 CreateSigninManagerAsService(); 546 } 547