authenticate 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +21 -0
- data/Gemfile.lock +154 -0
- data/LICENSE +20 -0
- data/README.md +240 -0
- data/Rakefile +6 -0
- data/app/assets/config/authenticate_manifest.js +0 -0
- data/app/assets/images/authenticate/.keep +0 -0
- data/app/assets/javascripts/authenticate/.keep +0 -0
- data/app/assets/stylesheets/authenticate/.keep +0 -0
- data/app/controllers/.keep +0 -0
- data/app/helpers/.keep +0 -0
- data/app/mailers/.keep +0 -0
- data/app/models/.keep +0 -0
- data/app/views/.keep +0 -0
- data/authenticate.gemspec +38 -0
- data/bin/rails +12 -0
- data/config/routes.rb +2 -0
- data/lib/authenticate.rb +12 -0
- data/lib/authenticate/callbacks/authenticatable.rb +4 -0
- data/lib/authenticate/callbacks/brute_force.rb +31 -0
- data/lib/authenticate/callbacks/lifetimed.rb +5 -0
- data/lib/authenticate/callbacks/timeoutable.rb +15 -0
- data/lib/authenticate/callbacks/trackable.rb +8 -0
- data/lib/authenticate/configuration.rb +144 -0
- data/lib/authenticate/controller.rb +110 -0
- data/lib/authenticate/crypto/bcrypt.rb +30 -0
- data/lib/authenticate/debug.rb +10 -0
- data/lib/authenticate/engine.rb +21 -0
- data/lib/authenticate/lifecycle.rb +120 -0
- data/lib/authenticate/login_status.rb +27 -0
- data/lib/authenticate/model/brute_force.rb +51 -0
- data/lib/authenticate/model/db_password.rb +71 -0
- data/lib/authenticate/model/email.rb +76 -0
- data/lib/authenticate/model/lifetimed.rb +48 -0
- data/lib/authenticate/model/timeoutable.rb +47 -0
- data/lib/authenticate/model/trackable.rb +43 -0
- data/lib/authenticate/model/username.rb +45 -0
- data/lib/authenticate/modules.rb +61 -0
- data/lib/authenticate/session.rb +123 -0
- data/lib/authenticate/token.rb +7 -0
- data/lib/authenticate/user.rb +50 -0
- data/lib/authenticate/version.rb +3 -0
- data/lib/tasks/authenticate_tasks.rake +4 -0
- data/spec/configuration_spec.rb +60 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/images/.keep +0 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +5 -0
- data/spec/dummy/app/controllers/concerns/.keep +0 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/mailers/.keep +0 -0
- data/spec/dummy/app/models/.keep +0 -0
- data/spec/dummy/app/models/concerns/.keep +0 -0
- data/spec/dummy/app/models/user.rb +3 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/bin/setup +29 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +26 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/production.rb +79 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/authenticate.rb +7 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +56 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20160120003910_create_users.rb +18 -0
- data/spec/dummy/db/schema.rb +31 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/lib/assets/.keep +0 -0
- data/spec/dummy/log/.keep +0 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/factories/users.rb +23 -0
- data/spec/model/session_spec.rb +86 -0
- data/spec/model/token_spec.rb +11 -0
- data/spec/model/user_spec.rb +12 -0
- data/spec/orm/active_record.rb +17 -0
- data/spec/spec_helper.rb +148 -0
- metadata +255 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
module Authenticate
|
2
|
+
class Engine < ::Rails::Engine
|
3
|
+
# config.generators do |g|
|
4
|
+
# g.test_framework :rspec
|
5
|
+
# g.fixture_replacement :factory_girl, dir: 'spec/factories'
|
6
|
+
# end
|
7
|
+
|
8
|
+
# viget
|
9
|
+
config.generators do |g|
|
10
|
+
g.test_framework :rspec
|
11
|
+
g.fixture_replacement :factory_girl, dir: 'spec/factories'
|
12
|
+
|
13
|
+
|
14
|
+
# g.test_framework :rspec, fixture: false
|
15
|
+
# g.fixture_replacement :factory_girl, dir: 'spec/factories'
|
16
|
+
# g.assets false
|
17
|
+
# g.helper false
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
module Authenticate
|
2
|
+
|
3
|
+
# Lifecycle stores and runs callbacks for authorization events.
|
4
|
+
#
|
5
|
+
# Heavily borrowed from warden (https://github.com/hassox/warden).
|
6
|
+
#
|
7
|
+
# = Events:
|
8
|
+
# :set_user - called after the user object is loaded, either through id/password or via session token.
|
9
|
+
# :authentication - called after the user authenticates with id & password
|
10
|
+
#
|
11
|
+
# Callbacks are added via after_set_user or after_authentication.
|
12
|
+
#
|
13
|
+
# Callbacks can throw(:failure,message) to signal an authentication/authorization failure, or perform
|
14
|
+
# actions on the user or session.
|
15
|
+
#
|
16
|
+
# = Options
|
17
|
+
#
|
18
|
+
# The callback options may optionally specify when to run the callback:
|
19
|
+
# only - executes the callback only if it matches the event(s) given
|
20
|
+
# except - executes the callback except if it matches the event(s) given
|
21
|
+
#
|
22
|
+
# The callback may also specify a 'name' key in options. This is for debugging purposes only.
|
23
|
+
#
|
24
|
+
# = Callback block parameters
|
25
|
+
#
|
26
|
+
# Callbacks are invoked with the following block parameters: |user, session, opts|
|
27
|
+
# user - the user object just loaded
|
28
|
+
# session - the Authenticate::Session
|
29
|
+
# opts - any options you want passed into the callback
|
30
|
+
#
|
31
|
+
# = Example
|
32
|
+
#
|
33
|
+
# # A callback to track the users successful logins:
|
34
|
+
# Authenticate.lifecycle.after_set_user do |user, session, opts|
|
35
|
+
# user.sign_in_count += 1
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
class Lifecycle
|
39
|
+
include Debug
|
40
|
+
@@conditions = [:only, :except, :event]
|
41
|
+
|
42
|
+
# This callback is triggered after the first time a user is set during per-hit authorization, or during login.
|
43
|
+
def after_set_user(options = {}, method = :push, &block)
|
44
|
+
raise BlockNotGiven unless block_given?
|
45
|
+
options = process_opts(options)
|
46
|
+
# puts "register after_set_user #{options.inspect}"
|
47
|
+
after_set_user_callbacks.send(method, [block, options])
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
# A callback to run after the user successfully authenticates, during the login process.
|
53
|
+
# Mechanically identical to [#after_set_user].
|
54
|
+
def after_authentication(options = {}, method = :push, &block)
|
55
|
+
raise BlockNotGiven unless block_given?
|
56
|
+
options = process_opts(options)
|
57
|
+
# puts "register after_authentication #{options}"
|
58
|
+
after_authentication_callbacks.send(method, [block, options])
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def run_callbacks(kind, *args) # args - |user, session, opts|
|
63
|
+
# Last callback arg MUST be a Hash
|
64
|
+
options = args.last
|
65
|
+
d "@@@@@@@@@@@@ run_callbacks kind:#{kind} options:#{options.inspect}"
|
66
|
+
|
67
|
+
# each callback has 'conditions' stored with it
|
68
|
+
send("#{kind}_callbacks").each do |callback, conditions|
|
69
|
+
conditions = conditions.dup # make a copy, we mutate it
|
70
|
+
d "running callback -- #{conditions.inspect}"
|
71
|
+
conditions.delete_if {|key, val| !@@conditions.include? key}
|
72
|
+
# d "conditions after filter:#{conditions.inspect}"
|
73
|
+
invalid = conditions.find do |key, value|
|
74
|
+
# d "!!!!!!! conditions key:#{key} value:#{value} options[key]:#{options[key].inspect}"
|
75
|
+
# d("!value.include?(options[key]):#{!value.include?(options[key])}") if value.is_a?(Array)
|
76
|
+
value.is_a?(Array) ? !value.include?(options[key]) : (value != options[key])
|
77
|
+
end
|
78
|
+
d "callback invalid? #{invalid.inspect}"
|
79
|
+
callback.call(*args) unless invalid
|
80
|
+
end
|
81
|
+
d "FINISHED run_callbacks #{kind}"
|
82
|
+
nil
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
def prepend_after_authentication(options = {}, &block)
|
87
|
+
after_authentication(options, :unshift, &block)
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# set event: to run callback on based on options
|
93
|
+
def process_opts(options)
|
94
|
+
if options.key?(:only)
|
95
|
+
options[:event] = options.delete(:only)
|
96
|
+
elsif options.key?(:except)
|
97
|
+
options[:event] = [:set_user, :authentication] - Array(options.delete(:except))
|
98
|
+
end
|
99
|
+
options
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
def after_set_user_callbacks
|
104
|
+
@after_set_user_callbacks ||= []
|
105
|
+
end
|
106
|
+
|
107
|
+
def after_authentication_callbacks
|
108
|
+
@after_authentication_callbacks ||= []
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
def self.lifecycle
|
114
|
+
@lifecycle ||= Lifecycle.new
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.lifecycle=(lifecycle)
|
118
|
+
@lifecycle = lifecycle
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Authenticate
|
2
|
+
|
3
|
+
# Indicate login attempt was successful. Allows caller to supply a block to login() predicated on success?
|
4
|
+
class Success
|
5
|
+
def success?
|
6
|
+
true
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# Indicate login attempt was a failure, with a message.
|
11
|
+
# Allows caller to supply a block to login() predicated on success?
|
12
|
+
class Failure
|
13
|
+
# The reason the sign in failed.
|
14
|
+
attr_reader :message
|
15
|
+
|
16
|
+
# @param [String] message The reason the login failed.
|
17
|
+
def initialize(message)
|
18
|
+
@message = message
|
19
|
+
end
|
20
|
+
|
21
|
+
def success?
|
22
|
+
false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'authenticate/callbacks/brute_force'
|
2
|
+
|
3
|
+
module Authenticate
|
4
|
+
module Model
|
5
|
+
|
6
|
+
|
7
|
+
# Protect from brute force attacks.
|
8
|
+
# Lock accounts that have too many failed consecutive logins.
|
9
|
+
# Todo: email user to allow faster unlocking via token.
|
10
|
+
module BruteForce
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
def self.required_fields(klass)
|
14
|
+
[:failed_logins_count, :lock_expires_at]
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def register_failed_login!
|
19
|
+
self.failed_logins_count ||= 0
|
20
|
+
self.failed_logins_count += 1
|
21
|
+
lock! if self.failed_logins_count >= max_bad_logins
|
22
|
+
end
|
23
|
+
|
24
|
+
def lock!
|
25
|
+
self.update_attribute(:lock_expires_at, Time.now.utc + lockout_period)
|
26
|
+
end
|
27
|
+
|
28
|
+
def unlock!
|
29
|
+
self.update_attributes({failed_logins_count: 0, lock_expires_at: nil})
|
30
|
+
end
|
31
|
+
|
32
|
+
def locked?
|
33
|
+
!unlocked?
|
34
|
+
end
|
35
|
+
|
36
|
+
def unlocked?
|
37
|
+
self.lock_expires_at.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def max_bad_logins
|
43
|
+
Authenticate.configuration.max_consecutive_bad_logins_allowed
|
44
|
+
end
|
45
|
+
|
46
|
+
def lockout_period
|
47
|
+
Authenticate.configuration.bad_login_lockout_period
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'authenticate/crypto/bcrypt'
|
2
|
+
|
3
|
+
|
4
|
+
module Authenticate
|
5
|
+
module Model
|
6
|
+
|
7
|
+
# Encrypts and stores a password in the database to validate the authenticity of a user while signing in.
|
8
|
+
#
|
9
|
+
# Authenticate can plug in any crypto provider, but currently only features BCrypt.
|
10
|
+
#
|
11
|
+
# = Methods
|
12
|
+
#
|
13
|
+
# The following methods are added to your user model:
|
14
|
+
# - password_match?(password) - checks to see if the user's password matches the given password
|
15
|
+
# - password=(new_password) - encrypt and set the user password
|
16
|
+
#
|
17
|
+
# = Validations
|
18
|
+
#
|
19
|
+
# - :password validation, requiring the password is set
|
20
|
+
#
|
21
|
+
module DbPassword
|
22
|
+
extend ActiveSupport::Concern
|
23
|
+
|
24
|
+
def self.required_fields(klass)
|
25
|
+
[:encrypted_password]
|
26
|
+
end
|
27
|
+
|
28
|
+
included do
|
29
|
+
include crypto_provider
|
30
|
+
attr_reader :password
|
31
|
+
attr_accessor :password_changing
|
32
|
+
validates :password, presence: true, unless: :skip_password_validation?
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
module ClassMethods
|
38
|
+
|
39
|
+
# We only have one crypto provider at the moment, but this is a pluggable point
|
40
|
+
# to install different crypto.
|
41
|
+
def crypto_provider
|
42
|
+
Authenticate.configuration.crypto_provider || Authenticate::Crypto::BCrypt
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
def password_match?(password)
|
50
|
+
match?(password, self.encrypted_password)
|
51
|
+
end
|
52
|
+
|
53
|
+
def password=(new_password)
|
54
|
+
@password = new_password
|
55
|
+
|
56
|
+
if new_password.present?
|
57
|
+
self.encrypted_password = encrypt(new_password)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# If we already have an encrypted password and it's not changing, skip the validation.
|
64
|
+
def skip_password_validation?
|
65
|
+
encrypted_password.present? && !password_changing
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'email_validator'
|
2
|
+
|
3
|
+
module Authenticate
|
4
|
+
module Model
|
5
|
+
|
6
|
+
# Use :email as the identifier for the user. Must be unique to the system.
|
7
|
+
#
|
8
|
+
# = Columns
|
9
|
+
# - :email containing the email address of the user
|
10
|
+
#
|
11
|
+
# = Validations
|
12
|
+
# - :email requires email is set, validations the format, and ensure it is unique
|
13
|
+
#
|
14
|
+
# = Callbacks
|
15
|
+
# - :normalize_email - normalize the email, removing spaces etc, before saving
|
16
|
+
#
|
17
|
+
# = Methods
|
18
|
+
# - :email - require the email address is set and is a valid format
|
19
|
+
#
|
20
|
+
# = class methods
|
21
|
+
# - authenticate(email, password) - find user with given email, validate their password, return the user.
|
22
|
+
# - normalize_email(email) - clean up the given email and return it.
|
23
|
+
# - find_by_normalized_email(email) - normalize the given email, then look for the user with that email.
|
24
|
+
#
|
25
|
+
module Email
|
26
|
+
extend ActiveSupport::Concern
|
27
|
+
|
28
|
+
def self.required_fields(klass)
|
29
|
+
[:email]
|
30
|
+
end
|
31
|
+
|
32
|
+
included do
|
33
|
+
before_validation :normalize_email
|
34
|
+
validates :email,
|
35
|
+
email: { strict_mode: true },
|
36
|
+
presence: true,
|
37
|
+
uniqueness: { allow_blank: true }
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
module ClassMethods
|
42
|
+
|
43
|
+
def credentials(params)
|
44
|
+
# todo closure from configuration
|
45
|
+
[params[:session][:email], params[:session][:password]]
|
46
|
+
end
|
47
|
+
|
48
|
+
def authenticate(credentials)
|
49
|
+
user = find_by_credentials(credentials)
|
50
|
+
user && user.password_match?(credentials[1]) ? user : nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def find_by_credentials(credentials)
|
54
|
+
email = credentials[0]
|
55
|
+
puts "find_by_credentials email: #{email}"
|
56
|
+
find_by_email normalize_email(email)
|
57
|
+
end
|
58
|
+
|
59
|
+
def normalize_email(email)
|
60
|
+
email.to_s.downcase.gsub(/\s+/, '')
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
# Sets the email on this instance to the value returned by
|
66
|
+
# {.normalize_email}
|
67
|
+
#
|
68
|
+
# @return [String]
|
69
|
+
def normalize_email
|
70
|
+
self.email = self.class.normalize_email(email)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'authenticate/callbacks/lifetimed'
|
2
|
+
|
3
|
+
module Authenticate
|
4
|
+
module Model
|
5
|
+
|
6
|
+
# The user session has a maximum allowed lifespan, after which the session is expired and requires
|
7
|
+
# re-authentication.
|
8
|
+
#
|
9
|
+
# = configuration
|
10
|
+
#
|
11
|
+
# Set the maximum session lifetime in the initializer, giving a timestamp.
|
12
|
+
#
|
13
|
+
# Authenticate.configure do |config|
|
14
|
+
# config.max_session_lifetime = 8.hours
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# If the max_session_lifetime configuration parameter is nil, the :lifetimed module is not loaded.
|
18
|
+
#
|
19
|
+
# = columns
|
20
|
+
# Requires the `current_sign_in_at` column. This column is managed by the :trackable plugin.
|
21
|
+
#
|
22
|
+
# = methods
|
23
|
+
# - max_session_timedout? - true if the user's session is too old and must be reaped
|
24
|
+
#
|
25
|
+
#
|
26
|
+
module Lifetimed
|
27
|
+
extend ActiveSupport::Concern
|
28
|
+
|
29
|
+
def self.required_fields(klass)
|
30
|
+
[:current_sign_in_at]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Has the session reached its maximum allowed lifespan?
|
34
|
+
def max_session_timedout?
|
35
|
+
return false if max_session_lifetime.nil?
|
36
|
+
return false if current_sign_in_at.nil?
|
37
|
+
current_sign_in_at <= max_session_lifetime.ago
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def max_session_lifetime
|
43
|
+
Authenticate.configuration.max_session_lifetime
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'authenticate/callbacks/timeoutable'
|
2
|
+
|
3
|
+
module Authenticate
|
4
|
+
module Model
|
5
|
+
|
6
|
+
# Expire user sessions that have not been accessed within a certain period of time.
|
7
|
+
# Expired users will be asked for credentials again.
|
8
|
+
#
|
9
|
+
# == Columns
|
10
|
+
#
|
11
|
+
# This module expects and tracks this column on your user model:
|
12
|
+
# - last_access_at - timestamp of the last access by the user
|
13
|
+
#
|
14
|
+
# == Configuration
|
15
|
+
#
|
16
|
+
# Timeoutable is enabled and configured with the `timeout_in` configuration parameter.
|
17
|
+
# `timeout_in` expects a timestamp. Example:
|
18
|
+
#
|
19
|
+
# Authenticate.configure do |config|
|
20
|
+
# config.timeout_in = 15.minutes
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# You must specify a non-nil timeout_in in your initializer to enable Timeoutable.
|
24
|
+
#
|
25
|
+
module Timeoutable
|
26
|
+
extend ActiveSupport::Concern
|
27
|
+
|
28
|
+
def self.required_fields(klass)
|
29
|
+
[:last_access_at]
|
30
|
+
end
|
31
|
+
|
32
|
+
# Checks whether the user session has expired based on configured time.
|
33
|
+
def timedout?
|
34
|
+
Rails.logger.info "User.timedout? timeout_in:#{timeout_in} last_access_at:#{last_access_at}"
|
35
|
+
return false if timeout_in.nil?
|
36
|
+
return false if last_access_at.nil?
|
37
|
+
# result = Time.now.utc > (last_access_at + timeout_in)
|
38
|
+
Rails.logger.info "User.timedout? #{last_access_at >= timeout_in.ago} timeout_in.ago:#{timeout_in.ago} last_access_at:#{last_access_at}"
|
39
|
+
last_access_at <= timeout_in.ago
|
40
|
+
end
|
41
|
+
|
42
|
+
def timeout_in
|
43
|
+
Authenticate.configuration.timeout_in
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|