Home | History | Annotate | Download | only in saml
      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