/
controller.rb
162 lines (136 loc) · 4.88 KB
/
controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
module Sorcery
module Controller
def self.included(klass)
klass.class_eval do
extend ClassMethods
include InstanceMethods
Config.submodules.each do |mod|
begin
include Submodules.const_get(mod.to_s.split("_").map {|p| p.capitalize}.join(""))
rescue NameError
# don't stop on a missing submodule.
end
end
Config.update!
end
end
module ClassMethods
def activate_sorcery!(&block)
yield Config if block_given?
after_config!
end
def after_config!
Config.after_config.each {|c| send(c)}
end
end
module InstanceMethods
# To be used as before_filter.
# Will trigger auto-login attempts via the call to logged_in?
# If all attempts to auto-login fail, the failure callback will be called.
def require_login
if !logged_in?
session[:user_wanted_url] = request.url if Config.save_user_wanted_url
self.send(Config.not_authenticated_action)
end
end
def login(*credentials)
user = Config.user_class.authenticate(*credentials)
if user
reset_session # protect from session fixation attacks
login_user(user)
after_login!(user, credentials)
logged_in_user
else
after_failed_login!(credentials)
nil
end
end
def logout
if logged_in?
before_logout!(logged_in_user)
reset_session
after_logout!
end
end
def logged_in?
!!logged_in_user
end
# attempts to auto-login from the sources defined (session, basic_auth, cookie, etc.)
# returns the logged in user if found, false if not (using old restful-authentication trick, nil != false).
def logged_in_user
@logged_in_user ||= login_from_session || login_from_other_sources unless @logged_in_user == false
end
def login_from_other_sources
result = nil
Config.login_sources.find do |source|
result = send(source)
end
result || false
end
def not_authenticated
redirect_to root_path
end
protected
def login_user(user)
session[:user_id] = user.id
end
def login_from_session
@logged_in_user = (Config.user_class.find_by_id(session[:user_id]) if session[:user_id]) || false
end
def after_login!(user, credentials)
Config.after_login.each {|c| self.send(c, user, credentials)}
end
def after_failed_login!(credentials)
Config.after_failed_login.each {|c| self.send(c, credentials)}
end
def before_logout!(user)
Config.before_logout.each {|c| self.send(c, user)}
end
def after_logout!
Config.after_logout.each {|c| self.send(c)}
end
end
module Config
class << self
attr_accessor :submodules,
:user_class, # what class to use as the user class.
:not_authenticated_action, # what controller action to call for non-authenticated users.
:save_user_wanted_url, # when a non logged in user tries to enter a page that requires login, save the URL he wanted to reach,
# and send him there after login.
:login_sources,
:after_login,
:after_failed_login,
:before_logout,
:after_logout,
:after_config
def init!
@defaults = {
:@user_class => nil,
:@submodules => [],
:@not_authenticated_action => :not_authenticated,
:@login_sources => [],
:@after_login => [],
:@after_failed_login => [],
:@before_logout => [],
:@after_logout => [],
:@after_config => [],
:@save_user_wanted_url => true
}
end
# Resets all configuration options to their default values.
def reset!
@defaults.each do |k,v|
instance_variable_set(k,v)
end
end
def update!
@defaults.each do |k,v|
instance_variable_set(k,v) if !instance_variable_defined?(k)
end
end
end
init!
reset!
end
end
end