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 23namespace chromeos { 24 25namespace { 26 27const int kDefaultSAMLOfflineSigninTimeLimit = 14 * 24 * 60 * 60; // 14 days. 28 29} // namespace 30 31// static 32void 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 44void 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 84void SAMLOfflineSigninLimiter::Shutdown() { 85 pref_change_registrar_.RemoveAll(); 86 offline_signin_limit_timer_.reset(); 87} 88 89SAMLOfflineSigninLimiter::SAMLOfflineSigninLimiter(Profile* profile, 90 base::Clock* clock) 91 : profile_(profile), 92 clock_(clock ? clock : &default_clock_) { 93} 94 95SAMLOfflineSigninLimiter::~SAMLOfflineSigninLimiter() { 96} 97 98void 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 143void 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