| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/supervised_user/supervised_user_google_auth_navigation_throttle.h" |
| |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/signin/identity_manager_factory.h" |
| #include "chrome/browser/supervised_user/child_accounts/child_account_service.h" |
| #include "chrome/browser/supervised_user/child_accounts/child_account_service_factory.h" |
| #include "components/google/core/common/google_util.h" |
| #include "content/public/browser/navigation_handle.h" |
| #include "content/public/browser/web_contents.h" |
| #include "services/identity/public/cpp/identity_manager.h" |
| |
| #if defined(OS_ANDROID) |
| #include "chrome/browser/supervised_user/child_accounts/child_account_service_android.h" |
| #endif |
| |
| // static |
| std::unique_ptr<SupervisedUserGoogleAuthNavigationThrottle> |
| SupervisedUserGoogleAuthNavigationThrottle::MaybeCreate( |
| content::NavigationHandle* navigation_handle) { |
| Profile* profile = Profile::FromBrowserContext( |
| navigation_handle->GetWebContents()->GetBrowserContext()); |
| if (!profile->IsChild()) |
| return nullptr; |
| |
| return base::WrapUnique(new SupervisedUserGoogleAuthNavigationThrottle( |
| profile, navigation_handle)); |
| } |
| |
| SupervisedUserGoogleAuthNavigationThrottle:: |
| SupervisedUserGoogleAuthNavigationThrottle( |
| Profile* profile, |
| content::NavigationHandle* navigation_handle) |
| : content::NavigationThrottle(navigation_handle), |
| child_account_service_( |
| ChildAccountServiceFactory::GetForProfile(profile)), |
| #if defined(OS_ANDROID) |
| has_shown_reauth_(false), |
| #endif |
| weak_ptr_factory_(this) { |
| } |
| |
| SupervisedUserGoogleAuthNavigationThrottle:: |
| ~SupervisedUserGoogleAuthNavigationThrottle() = default; |
| |
| content::NavigationThrottle::ThrottleCheckResult |
| SupervisedUserGoogleAuthNavigationThrottle::WillStartRequest() { |
| return WillStartOrRedirectRequest(); |
| } |
| |
| content::NavigationThrottle::ThrottleCheckResult |
| SupervisedUserGoogleAuthNavigationThrottle::WillRedirectRequest() { |
| return WillStartOrRedirectRequest(); |
| } |
| |
| const char* SupervisedUserGoogleAuthNavigationThrottle::GetNameForLogging() { |
| return "SupervisedUserGoogleAuthNavigationThrottle"; |
| } |
| |
| content::NavigationThrottle::ThrottleCheckResult |
| SupervisedUserGoogleAuthNavigationThrottle::WillStartOrRedirectRequest() { |
| const GURL& url = navigation_handle()->GetURL(); |
| if (!google_util::IsGoogleSearchUrl(url) && |
| !google_util::IsGoogleHomePageUrl(url) && |
| !google_util::IsYoutubeDomainUrl(url, google_util::ALLOW_SUBDOMAIN, |
| google_util::ALLOW_NON_STANDARD_PORTS)) { |
| return content::NavigationThrottle::PROCEED; |
| } |
| |
| content::NavigationThrottle::ThrottleCheckResult result = ShouldProceed(); |
| |
| if (result.action() == content::NavigationThrottle::DEFER) { |
| google_auth_state_subscription_ = |
| child_account_service_->ObserveGoogleAuthState( |
| base::Bind(&SupervisedUserGoogleAuthNavigationThrottle:: |
| OnGoogleAuthStateChanged, |
| base::Unretained(this))); |
| } |
| |
| return result; |
| } |
| |
| void SupervisedUserGoogleAuthNavigationThrottle::OnGoogleAuthStateChanged() { |
| content::NavigationThrottle::ThrottleCheckResult result = ShouldProceed(); |
| |
| switch (result.action()) { |
| case content::NavigationThrottle::PROCEED: { |
| google_auth_state_subscription_.reset(); |
| Resume(); |
| break; |
| } |
| case content::NavigationThrottle::CANCEL: |
| case content::NavigationThrottle::CANCEL_AND_IGNORE: { |
| CancelDeferredNavigation(result); |
| break; |
| } |
| case content::NavigationThrottle::DEFER: { |
| // Keep blocking. |
| break; |
| } |
| case content::NavigationThrottle::BLOCK_REQUEST: |
| case content::NavigationThrottle::BLOCK_REQUEST_AND_COLLAPSE: |
| case content::NavigationThrottle::BLOCK_RESPONSE: { |
| NOTREACHED(); |
| } |
| } |
| } |
| |
| content::NavigationThrottle::ThrottleCheckResult |
| SupervisedUserGoogleAuthNavigationThrottle::ShouldProceed() { |
| ChildAccountService::AuthState authStatus = |
| child_account_service_->GetGoogleAuthState(); |
| if (authStatus == ChildAccountService::AuthState::AUTHENTICATED) |
| return content::NavigationThrottle::PROCEED; |
| if (authStatus == ChildAccountService::AuthState::PENDING) |
| return content::NavigationThrottle::DEFER; |
| |
| #if defined(OS_CHROMEOS) |
| // A credentials re-mint is already underway when we reach here (Mirror |
| // account reconciliation). Nothing to do here except block the navigation |
| // while re-minting is underway. |
| return content::NavigationThrottle::DEFER; |
| #elif defined(OS_ANDROID) |
| if (!has_shown_reauth_) { |
| has_shown_reauth_ = true; |
| |
| content::WebContents* web_contents = navigation_handle()->GetWebContents(); |
| Profile* profile = |
| Profile::FromBrowserContext(web_contents->GetBrowserContext()); |
| auto* identity_manager = IdentityManagerFactory::GetForProfile(profile); |
| AccountInfo account_info = identity_manager->GetPrimaryAccountInfo(); |
| ReauthenticateChildAccount( |
| web_contents, account_info.email, |
| base::Bind(&SupervisedUserGoogleAuthNavigationThrottle:: |
| OnReauthenticationResult, |
| weak_ptr_factory_.GetWeakPtr())); |
| } |
| return content::NavigationThrottle::DEFER; |
| #else |
| NOTREACHED(); |
| |
| // This should never happen but needs to be included to avoid compilation |
| // error on debug builds. |
| return content::NavigationThrottle::CANCEL_AND_IGNORE; |
| #endif |
| } |
| |
| void SupervisedUserGoogleAuthNavigationThrottle::OnReauthenticationResult( |
| bool reauth_successful) { |
| if (reauth_successful) { |
| // If reauthentication was not successful, wait until the cookies are |
| // refreshed, which will call us back separately. |
| return; |
| } |
| |
| // Otherwise cancel immediately. |
| CancelDeferredNavigation(content::NavigationThrottle::CANCEL_AND_IGNORE); |
| } |