authie 3.3.1 → 4.0.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/db/migrate/20141012174250_create_authie_sessions.rb +4 -2
- data/db/migrate/20141013115205_add_indexes_to_authie_sessions.rb +4 -2
- data/db/migrate/20150109144120_add_parent_id_to_authie_sessions.rb +2 -0
- data/db/migrate/20150305135400_add_two_factor_auth_fields_to_authie.rb +3 -1
- data/db/migrate/20170417170000_add_token_hashes_to_authie_sessions.rb +2 -0
- data/db/migrate/20170421174100_add_index_to_token_hashes_on_authie_sessions.rb +3 -1
- data/db/migrate/20180215152200_add_host_to_authie_sessions.rb +2 -0
- data/lib/authie/config.rb +19 -35
- data/lib/authie/controller_delegate.rb +67 -40
- data/lib/authie/controller_extension.rb +14 -37
- data/lib/authie/engine.rb +3 -3
- data/lib/authie/error.rb +2 -0
- data/lib/authie/event_manager.rb +12 -8
- data/lib/authie/rack_controller.rb +6 -10
- data/lib/authie/session.rb +244 -277
- data/lib/authie/session_model.rb +141 -0
- data/lib/authie/user.rb +3 -3
- data/lib/authie/version.rb +8 -1
- data/lib/authie.rb +3 -3
- metadata +215 -28
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d5347676808e3554dde1670a91c8402ed166be59767298dfea961a9020659843
|
4
|
+
data.tar.gz: 03ee0e9cc60e7ae24a9e83c7a6ead5d72ebec109ef558898395d476014843a65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 219676dee96408c5cb85432ab4d919967415b9e575cb9681c4b4a9d210f041213af2a841a63ebdd4c88d9a8d3856f4ab306ddfd5e4947dee6e3d3654de8538b0
|
7
|
+
data.tar.gz: 7dd321dd2d407fd73b89ea6e1894d60362ac7e4fd792d0d74ea9e2cc5178b30eebd8d42ab3bf7baa356bc3d6f161d6809e0c545d9430d6db3267e8dfbda87190
|
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class CreateAuthieSessions < ActiveRecord::Migration[4.2]
|
2
4
|
def change
|
3
5
|
create_table :authie_sessions do |t|
|
4
6
|
t.string :token, :browser_id
|
5
7
|
t.integer :user_id
|
6
|
-
t.boolean :active, :
|
8
|
+
t.boolean :active, default: true
|
7
9
|
t.text :data
|
8
10
|
t.datetime :expires_at
|
9
11
|
t.datetime :login_at
|
@@ -11,7 +13,7 @@ class CreateAuthieSessions < ActiveRecord::Migration[4.2]
|
|
11
13
|
t.datetime :last_activity_at
|
12
14
|
t.string :last_activity_ip, :last_activity_path
|
13
15
|
t.string :user_agent
|
14
|
-
t.timestamps :
|
16
|
+
t.timestamps null: true
|
15
17
|
end
|
16
18
|
end
|
17
19
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class AddIndexesToAuthieSessions < ActiveRecord::Migration[4.2]
|
2
4
|
def change
|
3
5
|
add_column :authie_sessions, :user_type, :string
|
4
|
-
add_index :authie_sessions, :token, :
|
5
|
-
add_index :authie_sessions, :browser_id, :
|
6
|
+
add_index :authie_sessions, :token, length: 10
|
7
|
+
add_index :authie_sessions, :browser_id, length: 10
|
6
8
|
add_index :authie_sessions, :user_id
|
7
9
|
end
|
8
10
|
end
|
@@ -1,8 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class AddTwoFactorAuthFieldsToAuthie < ActiveRecord::Migration[4.2]
|
2
4
|
def change
|
3
5
|
add_column :authie_sessions, :two_factored_at, :datetime
|
4
6
|
add_column :authie_sessions, :two_factored_ip, :string
|
5
|
-
add_column :authie_sessions, :requests, :integer, :
|
7
|
+
add_column :authie_sessions, :requests, :integer, default: 0
|
6
8
|
add_column :authie_sessions, :password_seen_at, :datetime
|
7
9
|
end
|
8
10
|
end
|
data/lib/authie/config.rb
CHANGED
@@ -1,48 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'authie/event_manager'
|
2
4
|
|
3
5
|
module Authie
|
4
6
|
class Config
|
7
|
+
attr_accessor :session_inactivity_timeout
|
8
|
+
attr_accessor :persistent_session_length
|
9
|
+
attr_accessor :sudo_session_timeout
|
10
|
+
attr_accessor :browser_id_cookie_name
|
11
|
+
attr_accessor :events
|
5
12
|
|
6
13
|
def initialize
|
7
|
-
@
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
@
|
12
|
-
end
|
13
|
-
attr_writer :session_inactivity_timeout
|
14
|
-
|
15
|
-
def persistent_session_length
|
16
|
-
@persistent_session_length || 2.months
|
17
|
-
end
|
18
|
-
attr_writer :persistent_session_length
|
19
|
-
|
20
|
-
def sudo_session_timeout
|
21
|
-
@sudo_session_timeout || 10.minutes
|
22
|
-
end
|
23
|
-
attr_writer :sudo_session_timeout
|
24
|
-
|
25
|
-
def user_relationship_options
|
26
|
-
@user_relationship_options ||= {}
|
14
|
+
@session_inactivity_timeout = 12.hours
|
15
|
+
@persistent_session_length = 2.months
|
16
|
+
@sudo_session_timeout = 10.minutes
|
17
|
+
@browser_id_cookie_name = :browser_id
|
18
|
+
@events = EventManager.new
|
27
19
|
end
|
20
|
+
end
|
28
21
|
|
29
|
-
|
30
|
-
|
22
|
+
class << self
|
23
|
+
def config
|
24
|
+
@config ||= Config.new
|
31
25
|
end
|
32
|
-
attr_writer :browser_id_cookie_name
|
33
26
|
|
34
|
-
def
|
35
|
-
|
27
|
+
def configure(&block)
|
28
|
+
block.call(config)
|
29
|
+
config
|
36
30
|
end
|
37
31
|
end
|
38
|
-
|
39
|
-
def self.config
|
40
|
-
@config ||= Config.new
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.configure(&block)
|
44
|
-
block.call(config)
|
45
|
-
config
|
46
|
-
end
|
47
|
-
|
48
32
|
end
|
@@ -1,86 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'securerandom'
|
2
4
|
require 'authie/session'
|
5
|
+
require 'authie/config'
|
6
|
+
require 'authie/session_model'
|
3
7
|
|
4
8
|
module Authie
|
9
|
+
# The controller delegate implements methods that can be used by a controller. These are then
|
10
|
+
# extended into controllers as needed (see ControllerExtension).
|
5
11
|
class ControllerDelegate
|
6
|
-
|
12
|
+
# @param controller [ActionController::Base]
|
13
|
+
# @return [Authie::ControllerDelegate]
|
7
14
|
def initialize(controller)
|
8
15
|
@controller = controller
|
9
16
|
end
|
10
17
|
|
11
|
-
#
|
18
|
+
# Sets a browser ID. This must be performed on any page request where AUthie will be used.
|
19
|
+
# It should be triggered before any other Authie provided methods. This will ensure that
|
20
|
+
# the given browser ID is unique.
|
21
|
+
#
|
22
|
+
# @return [String] the generated browser ID
|
12
23
|
def set_browser_id
|
13
24
|
until cookies[Authie.config.browser_id_cookie_name]
|
14
25
|
proposed_browser_id = SecureRandom.uuid
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
26
|
+
next if Authie::SessionModel.where(browser_id: proposed_browser_id).exists?
|
27
|
+
|
28
|
+
cookies[Authie.config.browser_id_cookie_name] = {
|
29
|
+
value: proposed_browser_id,
|
30
|
+
expires: 5.years.from_now,
|
31
|
+
httponly: true,
|
32
|
+
secure: @controller.request.ssl?
|
33
|
+
}
|
34
|
+
Authie.config.events.dispatch(:set_browser_id, proposed_browser_id)
|
25
35
|
end
|
36
|
+
proposed_browser_id
|
26
37
|
end
|
27
38
|
|
28
|
-
# Touch the
|
39
|
+
# Touch the session on each request to ensure that it is validated and all last activity
|
40
|
+
# information is updated. This will return the session if one has been touched otherwise
|
41
|
+
# it will reteurn false if there is no session/not logged in. It is safe to run this on
|
42
|
+
# all requests even if there is no session.
|
43
|
+
#
|
44
|
+
# @return [Authie::Session, false]
|
29
45
|
def touch_auth_session
|
30
|
-
if logged_in?
|
31
|
-
|
32
|
-
|
46
|
+
return auth_session.touch if logged_in?
|
47
|
+
|
48
|
+
false
|
33
49
|
end
|
34
50
|
|
35
|
-
# Return the currently logged in user
|
51
|
+
# Return the user for the currently logged in user or nil if no user is logged in
|
52
|
+
#
|
53
|
+
# @return [ActiveRecord::Base, nil]
|
36
54
|
def current_user
|
37
|
-
|
38
|
-
end
|
55
|
+
return nil unless logged_in?
|
39
56
|
|
40
|
-
|
41
|
-
def current_user=(user)
|
42
|
-
create_auth_session(user)
|
43
|
-
user
|
57
|
+
auth_session.session.user
|
44
58
|
end
|
45
59
|
|
46
|
-
# Create a new session for the given user
|
60
|
+
# Create a new session for the given user. If nil is provided as a user, the existing session
|
61
|
+
# will be invalidated.
|
62
|
+
#
|
63
|
+
# @return [Authie::Session, nil]
|
47
64
|
def create_auth_session(user)
|
48
65
|
if user
|
49
|
-
@auth_session = Authie::Session.start(@controller, :
|
50
|
-
|
51
|
-
auth_session.invalidate! if logged_in?
|
52
|
-
@auth_session = :none
|
66
|
+
@auth_session = Authie::Session.start(@controller, user: user)
|
67
|
+
return @auth_session
|
53
68
|
end
|
69
|
+
|
70
|
+
invalidate_auth_session
|
71
|
+
nil
|
54
72
|
end
|
55
73
|
|
56
|
-
# Invalidate
|
74
|
+
# Invalidate the existing auth session if one exists. Return true if a sesion has been invalidated
|
75
|
+
# otherwise return false.
|
76
|
+
#
|
77
|
+
# @return [Boolean]
|
57
78
|
def invalidate_auth_session
|
58
79
|
if logged_in?
|
59
|
-
auth_session.invalidate
|
60
|
-
@auth_session =
|
61
|
-
true
|
62
|
-
else
|
63
|
-
false
|
80
|
+
auth_session.invalidate
|
81
|
+
@auth_session = nil
|
82
|
+
return true
|
64
83
|
end
|
84
|
+
|
85
|
+
false
|
65
86
|
end
|
66
87
|
|
67
|
-
# Is anyone currently logged in?
|
88
|
+
# Is anyone currently logged in? Return true if there is an auth session present.
|
89
|
+
#
|
90
|
+
# Note: this does not check the validatity of the session. You must always ensure that the `validate`
|
91
|
+
# or `touch` method is invoked to ensure that the session that has been found is active.
|
92
|
+
#
|
93
|
+
# @return [Boolean]
|
68
94
|
def logged_in?
|
69
95
|
auth_session.is_a?(Session)
|
70
96
|
end
|
71
97
|
|
72
|
-
# Return
|
98
|
+
# Return an auth session that has been found in the current cookies.
|
99
|
+
#
|
100
|
+
# @return [Authie::Session]
|
73
101
|
def auth_session
|
74
|
-
@auth_session
|
75
|
-
|
102
|
+
return @auth_session if instance_variable_defined?('@auth_session')
|
103
|
+
|
104
|
+
@auth_session = Authie::Session.get_session(@controller)
|
76
105
|
end
|
77
106
|
|
78
107
|
private
|
79
108
|
|
80
|
-
# Return cookies for the controller
|
81
109
|
def cookies
|
82
110
|
@controller.send(:cookies)
|
83
111
|
end
|
84
|
-
|
85
112
|
end
|
86
113
|
end
|
@@ -1,12 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'authie/controller_delegate'
|
2
4
|
|
3
5
|
module Authie
|
4
6
|
module ControllerExtension
|
7
|
+
class << self
|
8
|
+
def included(base)
|
9
|
+
base.helper_method :logged_in?, :current_user, :auth_session
|
10
|
+
base.before_action :set_browser_id, :touch_auth_session
|
5
11
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
12
|
+
base.delegate :set_browser_id, to: :auth_session_delegate
|
13
|
+
base.delegate :touch_auth_session, to: :auth_session_delegate
|
14
|
+
base.delegate :current_user, to: :auth_session_delegate
|
15
|
+
base.delegate :create_auth_session, to: :auth_session_delegate
|
16
|
+
base.delegate :invalidate_auth_session, to: :auth_session_delegate
|
17
|
+
base.delegate :logged_in?, to: :auth_session_delegate
|
18
|
+
base.delegate :auth_session, to: :auth_session_delegate
|
19
|
+
end
|
10
20
|
end
|
11
21
|
|
12
22
|
private
|
@@ -14,38 +24,5 @@ module Authie
|
|
14
24
|
def auth_session_delegate
|
15
25
|
@auth_session_delegate ||= Authie::ControllerDelegate.new(self)
|
16
26
|
end
|
17
|
-
|
18
|
-
def set_browser_id
|
19
|
-
auth_session_delegate.set_browser_id
|
20
|
-
end
|
21
|
-
|
22
|
-
def touch_auth_session
|
23
|
-
auth_session_delegate.touch_auth_session
|
24
|
-
end
|
25
|
-
|
26
|
-
def current_user
|
27
|
-
auth_session_delegate.current_user
|
28
|
-
end
|
29
|
-
|
30
|
-
def current_user=(user)
|
31
|
-
auth_session_delegate.current_user = user
|
32
|
-
end
|
33
|
-
|
34
|
-
def create_auth_session(user)
|
35
|
-
auth_session_delegate.create_auth_session(user)
|
36
|
-
end
|
37
|
-
|
38
|
-
def invalidate_auth_session
|
39
|
-
auth_session_delegate.invalidate_auth_session
|
40
|
-
end
|
41
|
-
|
42
|
-
def logged_in?
|
43
|
-
auth_session_delegate.logged_in?
|
44
|
-
end
|
45
|
-
|
46
|
-
def auth_session
|
47
|
-
auth_session_delegate.auth_session
|
48
|
-
end
|
49
|
-
|
50
27
|
end
|
51
28
|
end
|
data/lib/authie/engine.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Authie
|
2
4
|
class Engine < ::Rails::Engine
|
3
|
-
|
4
5
|
engine_name 'authie'
|
5
6
|
|
6
|
-
initializer 'authie.initialize' do |
|
7
|
+
initializer 'authie.initialize' do |_app|
|
7
8
|
ActiveSupport.on_load :active_record do
|
8
9
|
require 'authie/session'
|
9
10
|
end
|
@@ -13,6 +14,5 @@ module Authie
|
|
13
14
|
include Authie::ControllerExtension
|
14
15
|
end
|
15
16
|
end
|
16
|
-
|
17
17
|
end
|
18
18
|
end
|
data/lib/authie/error.rb
CHANGED
data/lib/authie/event_manager.rb
CHANGED
@@ -1,15 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Authie
|
2
4
|
class EventManager
|
5
|
+
attr_reader :callbacks
|
3
6
|
|
4
7
|
def initialize
|
5
8
|
@callbacks = {}
|
6
9
|
end
|
7
10
|
|
8
11
|
def dispatch(event, *args)
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
12
|
+
callbacks = @callbacks[event.to_sym]
|
13
|
+
return if callbacks.nil?
|
14
|
+
|
15
|
+
callbacks.each do |cb|
|
16
|
+
cb.call(*args)
|
13
17
|
end
|
14
18
|
end
|
15
19
|
|
@@ -19,10 +23,10 @@ module Authie
|
|
19
23
|
end
|
20
24
|
|
21
25
|
def remove(event, block)
|
22
|
-
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
26
|
+
cb = @callbacks[event.to_sym]
|
27
|
+
return if cb.nil?
|
26
28
|
|
29
|
+
cb.delete(block)
|
30
|
+
end
|
27
31
|
end
|
28
32
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# If you're dealing with your authentication in a middleware and you only have
|
2
4
|
# access to your rack environment, this will wrap around rack and make it look
|
3
5
|
# close enough to an ActionController to work with Authie
|
@@ -9,7 +11,6 @@
|
|
9
11
|
|
10
12
|
module Authie
|
11
13
|
class RackController
|
12
|
-
|
13
14
|
attr_reader :request
|
14
15
|
|
15
16
|
def initialize(env)
|
@@ -26,27 +27,22 @@ module Authie
|
|
26
27
|
def set_browser_id
|
27
28
|
until cookies[:browser_id]
|
28
29
|
proposed_browser_id = SecureRandom.uuid
|
29
|
-
unless Session.where(:
|
30
|
-
cookies[:browser_id] = {:
|
30
|
+
unless Session.where(browser_id: proposed_browser_id).exists?
|
31
|
+
cookies[:browser_id] = { value: proposed_browser_id, expires: 20.years.from_now }
|
31
32
|
end
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
35
36
|
def current_user=(user)
|
36
|
-
Session.start(self, :
|
37
|
+
Session.start(self, user: user)
|
37
38
|
end
|
38
39
|
|
39
40
|
def current_user
|
40
|
-
if auth_session.is_a?(Session)
|
41
|
-
auth_session.user
|
42
|
-
else
|
43
|
-
nil
|
44
|
-
end
|
41
|
+
auth_session.user if auth_session.is_a?(Session)
|
45
42
|
end
|
46
43
|
|
47
44
|
def auth_session
|
48
45
|
@auth_session ||= Session.get_session(self)
|
49
46
|
end
|
50
|
-
|
51
47
|
end
|
52
48
|
end
|