1 // Copyright 2014 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/chromeos/login/saml/saml_offline_signin_limiter.h" 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/bind_helpers.h" 11 #include "base/location.h" 12 #include "base/logging.h" 13 #include "base/prefs/pref_service.h" 14 #include "base/time/clock.h" 15 #include "base/time/time.h" 16 #include "chrome/browser/chromeos/profiles/profile_helper.h" 17 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/common/pref_names.h" 19 #include "components/pref_registry/pref_registry_syncable.h" 20 #include "components/user_manager/user.h" 21 #include "components/user_manager/user_manager.h" 22 23 namespace chromeos { 24 25 namespace { 26 27 const int kDefaultSAMLOfflineSigninTimeLimit = 14 * 24 * 60 * 60; // 14 days. 28 29 } // namespace 30 31 // static 32 void SAMLOfflineSigninLimiter::RegisterProfilePrefs( 33 user_prefs::PrefRegistrySyncable* registry) { 34 registry->RegisterIntegerPref( 35 prefs::kSAMLOfflineSigninTimeLimit, 36 kDefaultSAMLOfflineSigninTimeLimit, 37 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 38 registry->RegisterInt64Pref( 39 prefs::kSAMLLastGAIASignInTime, 40 0, 41 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 42 } 43 44 void SAMLOfflineSigninLimiter::SignedIn(UserContext::AuthFlow auth_flow) { 45 PrefService* prefs = profile_->GetPrefs(); 46 const user_manager::User* user = 47 ProfileHelper::Get()->GetUserByProfile(profile_); 48 if (!user) { 49 NOTREACHED(); 50 return; 51 } 52 const std::string& user_id = user->email(); 53 54 if (auth_flow == UserContext::AUTH_FLOW_GAIA_WITHOUT_SAML) { 55 // The user went through online authentication and GAIA did not redirect to 56 // a SAML IdP. No limit applies in this case. Clear the time of last login 57 // with SAML and the flag enforcing online login, then return. 58 prefs->ClearPref(prefs::kSAMLLastGAIASignInTime); 59 user_manager::UserManager::Get()->SaveForceOnlineSignin(user_id, false); 60 return; 61 } 62 63 if (auth_flow == UserContext::AUTH_FLOW_GAIA_WITH_SAML) { 64 // The user went through online authentication and GAIA did redirect to a 65 // SAML IdP. Update the time of last login with SAML and clear the flag 66 // enforcing online login. The flag will be set again when the limit 67 // expires. If the limit already expired (e.g. because it was set to zero), 68 // the flag will be set again immediately. 69 user_manager::UserManager::Get()->SaveForceOnlineSignin(user_id, false); 70 prefs->SetInt64(prefs::kSAMLLastGAIASignInTime, 71 clock_->Now().ToInternalValue()); 72 } 73 74 // Start listening for pref changes. 75 pref_change_registrar_.Init(prefs); 76 pref_change_registrar_.Add(prefs::kSAMLOfflineSigninTimeLimit, 77 base::Bind(&SAMLOfflineSigninLimiter::UpdateLimit, 78 base::Unretained(this))); 79 80 // Arm the |offline_signin_limit_timer_| if a limit is in force. 81 UpdateLimit(); 82 } 83 84 void SAMLOfflineSigninLimiter::Shutdown() { 85 pref_change_registrar_.RemoveAll(); 86 offline_signin_limit_timer_.reset(); 87 } 88 89 SAMLOfflineSigninLimiter::SAMLOfflineSigninLimiter(Profile* profile, 90 base::Clock* clock) 91 : profile_(profile), 92 clock_(clock ? clock : &default_clock_) { 93 } 94 95 SAMLOfflineSigninLimiter::~SAMLOfflineSigninLimiter() { 96 } 97 98 void SAMLOfflineSigninLimiter::UpdateLimit() { 99 // Stop the |offline_signin_limit_timer_|. 100 offline_signin_limit_timer_.reset(); 101 102 PrefService* prefs = pref_change_registrar_.prefs(); 103 const base::TimeDelta offline_signin_time_limit = 104 base::TimeDelta::FromSeconds( 105 prefs->GetInteger(prefs::kSAMLOfflineSigninTimeLimit)); 106 base::Time last_gaia_signin_time = base::Time::FromInternalValue( 107 prefs->GetInt64(prefs::kSAMLLastGAIASignInTime)); 108 if (offline_signin_time_limit < base::TimeDelta() || 109 last_gaia_signin_time.is_null()) { 110 // If no limit is in force, return. 111 return; 112 } 113 114 const base::Time now = clock_->Now(); 115 if (last_gaia_signin_time > now) { 116 // If the time of last login with SAML lies in the future, set it to the 117 // current time. 118 NOTREACHED(); 119 last_gaia_signin_time = now; 120 prefs->SetInt64(prefs::kSAMLLastGAIASignInTime, now.ToInternalValue()); 121 } 122 123 const base::TimeDelta time_since_last_gaia_signin = 124 now - last_gaia_signin_time; 125 if (time_since_last_gaia_signin >= offline_signin_time_limit) { 126 // If the limit already expired, set the flag enforcing online login 127 // immediately and return. 128 ForceOnlineLogin(); 129 return; 130 } 131 132 // Arm |offline_signin_limit_timer_| so that it sets the flag enforcing online 133 // login when the limit expires. 134 offline_signin_limit_timer_.reset( 135 new base::OneShotTimer<SAMLOfflineSigninLimiter>); 136 offline_signin_limit_timer_->Start( 137 FROM_HERE, 138 offline_signin_time_limit - time_since_last_gaia_signin, 139 this, 140 &SAMLOfflineSigninLimiter::ForceOnlineLogin); 141 } 142 143 void SAMLOfflineSigninLimiter::ForceOnlineLogin() { 144 user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile_); 145 if (!user) { 146 NOTREACHED(); 147 return; 148 } 149 150 user_manager::UserManager::Get()->SaveForceOnlineSignin(user->email(), true); 151 offline_signin_limit_timer_.reset(); 152 } 153 154 } // namespace chromeos 155