model_security_generator 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/templates/controllers/user_controller.rb +4 -4
- data/templates/lib/modal.rb +22 -8
- data/templates/lib/user_support.rb +34 -21
- data/templates/models/user.rb +52 -23
- data/templates/views/login.rhtml +12 -2
- metadata +2 -2
@@ -69,13 +69,14 @@ public
|
|
69
69
|
# If this method is called login_admin (it's an alias), keep trying
|
70
70
|
# until an administrator logs in or the user pushes the "back" button.
|
71
71
|
def login
|
72
|
-
if
|
72
|
+
if flash[:login_succeeded]
|
73
73
|
redirect_back_or_default :action => :success
|
74
74
|
return
|
75
75
|
end
|
76
76
|
|
77
77
|
@user = User.new
|
78
78
|
|
79
|
+
flash[:login_succeeded] = false
|
79
80
|
http_authorize
|
80
81
|
end
|
81
82
|
|
@@ -93,7 +94,7 @@ public
|
|
93
94
|
def logout
|
94
95
|
User.sign_off
|
95
96
|
reset_session
|
96
|
-
|
97
|
+
flash[:skip_user_setup] = true
|
97
98
|
redirect_to :action => 'login'
|
98
99
|
end
|
99
100
|
|
@@ -112,8 +113,7 @@ public
|
|
112
113
|
@user.admin = 1
|
113
114
|
@user.activated = 1
|
114
115
|
@user.save
|
115
|
-
User.
|
116
|
-
session[:user_id] = 1
|
116
|
+
User.current = @user
|
117
117
|
render :action => 'admin_created'
|
118
118
|
# Mail the user instructions on how to activate their account.
|
119
119
|
else
|
data/templates/lib/modal.rb
CHANGED
@@ -30,9 +30,14 @@ module Modal
|
|
30
30
|
def modal_setup
|
31
31
|
# Set modal return.
|
32
32
|
if r = @params['ret']
|
33
|
+
logger.info("modal_setup: Save location #{r.sub(/\.L/, '#L')}")
|
33
34
|
self.return_location = r.sub(/\.L/, '#L')
|
34
35
|
elsif return_location.nil?
|
35
|
-
|
36
|
+
r = @request.env['HTTP_REFERER']
|
37
|
+
if r
|
38
|
+
logger.info("modal_setup: Save HTTP Referer #{r}")
|
39
|
+
self.return_location = @request.env['HTTP_REFERER']
|
40
|
+
end
|
36
41
|
end
|
37
42
|
true
|
38
43
|
end
|
@@ -40,19 +45,22 @@ module Modal
|
|
40
45
|
# Get the location to return to after a modal action. The argument should
|
41
46
|
# be a string containing a URL.
|
42
47
|
def return_location
|
43
|
-
|
48
|
+
session[:return_to]
|
44
49
|
end
|
45
50
|
|
46
51
|
# Set the location to return to after a modal action. The return value should
|
47
52
|
# be a string containing a URL.
|
48
53
|
def return_location= a
|
49
|
-
|
54
|
+
logger.info("return_location= #{a}")
|
55
|
+
session[:return_to] = a
|
50
56
|
end
|
51
57
|
|
52
58
|
# Store the location to return to after a modal action from the request URI.
|
53
59
|
# This is usually called before redirecting to another action.
|
54
60
|
def store_location
|
55
|
-
|
61
|
+
uri = @request.request_uri
|
62
|
+
logger.info("Store location: #{uri}")
|
63
|
+
self.return_location = uri
|
56
64
|
end
|
57
65
|
|
58
66
|
# Redirect to the stored return location. If no stored return location
|
@@ -61,11 +69,17 @@ module Modal
|
|
61
69
|
def redirect_back_or_default(attributes = {}, *method_params)
|
62
70
|
r = return_location
|
63
71
|
if r
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
72
|
+
if r == @request.request_uri
|
73
|
+
logger.info("redirect_back_or_default: BREAKING REDIRECTION LOOP #{r}.")
|
74
|
+
else
|
75
|
+
logger.info("redirect_back_or_default: return to #{r}")
|
76
|
+
self.return_location = nil
|
77
|
+
redirect_to_url r
|
78
|
+
return
|
79
|
+
end
|
68
80
|
end
|
81
|
+
logger.info("redirect_back_or_default: go to default #{attributes.inspect}, #{method_params.inspect}")
|
82
|
+
redirect_to attributes, method_params
|
69
83
|
end
|
70
84
|
|
71
85
|
# Create a URL optionally including an internal anchor. If the +id+ argument
|
@@ -22,23 +22,28 @@ module UserSupport
|
|
22
22
|
end
|
23
23
|
|
24
24
|
|
25
|
-
# FIX: This only works for require_login and require_admin for now, because
|
26
|
-
# I'm not passing the block across invocations.
|
27
|
-
#
|
28
25
|
# This is meant to be used as a before_filter.
|
29
26
|
# A condition that is dependent on the user's login is in the block.
|
30
27
|
# If the condition isn't true, a login panel is put up, and the explanation
|
31
28
|
# that is passed as an argument may (or may not) be presented to the user,
|
32
29
|
# depending on whether we're using HTTP authentication or not.
|
33
30
|
# Once the condition is met, it resumes the action it was protecting.
|
34
|
-
def require_condition(
|
31
|
+
def require_condition(header = nil, message = nil)
|
35
32
|
if yield
|
36
33
|
return true
|
37
34
|
else
|
38
|
-
if controller_name != 'user'
|
35
|
+
if controller_name != 'user' or (action_name != 'login' and action_name != 'login_admin')
|
39
36
|
store_location
|
40
37
|
end
|
41
|
-
|
38
|
+
|
39
|
+
# This test is to avoid writing the flash unnecessarily.
|
40
|
+
# Currently, writing the flash causes the entire session, not just the
|
41
|
+
# variables in question, to be written twice.
|
42
|
+
if header or message
|
43
|
+
flash[:login_header] = header
|
44
|
+
flash[:login_message] = message
|
45
|
+
end
|
46
|
+
redirect_to :controller => 'user', :action => 'login'
|
42
47
|
return false
|
43
48
|
end
|
44
49
|
end
|
@@ -48,7 +53,11 @@ module UserSupport
|
|
48
53
|
# isn't currently logged in. Once the administrator logs in, it resumes
|
49
54
|
# the action it was protecting.
|
50
55
|
def require_admin
|
51
|
-
|
56
|
+
header = "Administrative user required."
|
57
|
+
message = "You must be an administrative user to perform this action. " \
|
58
|
+
+ "If you don't have an administrative login, please use the back button "\
|
59
|
+
+ "of your browser to cancel this action."
|
60
|
+
require_condition(header, message) { admin? }
|
52
61
|
end
|
53
62
|
|
54
63
|
# This is meant to be used as a before_filter. It requires a
|
@@ -56,7 +65,7 @@ module UserSupport
|
|
56
65
|
# logged in. Once a user logs in, it resumes the action it was
|
57
66
|
# protecting.
|
58
67
|
def require_login
|
59
|
-
require_condition("
|
68
|
+
require_condition(nil, "You must be logged in to perform this action.") { User.current }
|
60
69
|
end
|
61
70
|
|
62
71
|
# This is a before filter for the entire application, used to set up the
|
@@ -72,23 +81,30 @@ module UserSupport
|
|
72
81
|
# security tests of ModelSecurity that are based on User, or anything
|
73
82
|
# that expects login information.
|
74
83
|
#
|
84
|
+
# Keep this function in sync with User.current() and User.current=().
|
85
|
+
# It's aware of the way those functions store the user information.
|
86
|
+
#
|
75
87
|
def user_setup
|
76
88
|
# require_* use Modal to return to what they were doing after HTTP
|
77
89
|
# authentication.
|
78
90
|
modal_setup
|
79
91
|
|
92
|
+
# User.current=() needs a thread-global reference to the session.
|
93
|
+
Thread.current[:session] = session
|
94
|
+
logger.info("Session is #{Thread.current[:session]}")
|
95
|
+
|
80
96
|
# This is used by the logout action to discard the old HTTP authentiction.
|
81
97
|
# Logout redirects to login and that generates a new authentication
|
82
98
|
# request. That request is the only input that can tell the browser to
|
83
99
|
# stop sending the old authentication data with every request!
|
84
|
-
if
|
85
|
-
|
100
|
+
if flash[:skip_user_setup] == true
|
101
|
+
flash[:skip_user_setup] = false
|
86
102
|
return true
|
87
103
|
end
|
88
104
|
|
89
|
-
|
90
|
-
|
105
|
+
login = password = nil
|
91
106
|
r = @request.env
|
107
|
+
old_user = user = session[:user]
|
92
108
|
|
93
109
|
# If the request contains an HTTP authentication, decode it.
|
94
110
|
# Don't use it to authenticate the user yet.
|
@@ -102,11 +118,6 @@ module UserSupport
|
|
102
118
|
end
|
103
119
|
end
|
104
120
|
|
105
|
-
# If the user is already logged into the session, get the user record.
|
106
|
-
if (id = @session[:user_id])
|
107
|
-
user = User.sign_on_by_session(id)
|
108
|
-
end
|
109
|
-
|
110
121
|
# If the HTTP authentication is for a different user name, the user wants
|
111
122
|
# to change logins. This can happen if an operation requires an
|
112
123
|
# administrative login and the current user isn't the administrator but
|
@@ -137,11 +148,13 @@ module UserSupport
|
|
137
148
|
user = User.sign_on_by_token(@params[:id], @params['token'])
|
138
149
|
end
|
139
150
|
|
140
|
-
|
141
|
-
|
142
|
-
|
151
|
+
# User.current must always be set with each request. It's backed by a
|
152
|
+
# class-global variable.
|
153
|
+
User.current = user
|
154
|
+
|
155
|
+
if user != old_user
|
156
|
+
flash[:login_succeeded] = true
|
143
157
|
end
|
144
|
-
logger.info("Current user is #{User.current.inspect}.")
|
145
158
|
|
146
159
|
true
|
147
160
|
end
|
data/templates/models/user.rb
CHANGED
@@ -156,6 +156,53 @@ public
|
|
156
156
|
let_write :password_confirmation, :if => :new_or_me?
|
157
157
|
let_write :old_password, :if => :me?
|
158
158
|
|
159
|
+
# Return the user for the current request. It is guaranteed that this is
|
160
|
+
# set for each request in the before_filter for the application.
|
161
|
+
#
|
162
|
+
# This function uses the Ruby Thread class to do thread-local storage,
|
163
|
+
# which will be overkill if the Rails server implementation isn't also
|
164
|
+
# using Ruby threads, but works everywhere.
|
165
|
+
#
|
166
|
+
# User.current(), User.current=(), and UserSupport#user_setup encapsulate
|
167
|
+
# session storage of user information. Only these three functions should
|
168
|
+
# know whether we store the entire User object in the session or only
|
169
|
+
# User#id.
|
170
|
+
#
|
171
|
+
def User.current
|
172
|
+
# This does not refer to the session because the application has set
|
173
|
+
# this from the session in user_setup.
|
174
|
+
Thread.current[:user]
|
175
|
+
end
|
176
|
+
|
177
|
+
# Set the user for the current request. It is guaranteed that this is
|
178
|
+
# set for each request in the before_filter for the application.
|
179
|
+
#
|
180
|
+
# This function uses the Ruby Thread class to do thread-local storage,
|
181
|
+
# which will be overkill if the Rails server implementation isn't also
|
182
|
+
# using Ruby threads, but works everywhere.
|
183
|
+
#
|
184
|
+
# User.current(), User.current=(), and UserSupport#user_setup encapsulate
|
185
|
+
# session storage of user information. Only these three functions should
|
186
|
+
# know whether we store the entire User object in the session or only
|
187
|
+
# User#id.
|
188
|
+
#
|
189
|
+
def User.current=(u)
|
190
|
+
Thread.current[:user] = u
|
191
|
+
|
192
|
+
session = Thread.current[:session]
|
193
|
+
|
194
|
+
if session.nil?
|
195
|
+
message = "Programming error: Please add \"before_filter :user_setup\" to your application controller. See the ModelSecurity documentation."
|
196
|
+
|
197
|
+
raise RuntimeError.new(message)
|
198
|
+
end
|
199
|
+
|
200
|
+
# Don't cause a session store unnecessarily
|
201
|
+
if session[:user] != u
|
202
|
+
session[:user] = u
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
159
206
|
# Change the user's password. Confirm the old password while doing so.
|
160
207
|
def change_password(attributes)
|
161
208
|
@password_is_new = true
|
@@ -172,26 +219,18 @@ public
|
|
172
219
|
self.old_password = attributes['old_password']
|
173
220
|
end
|
174
221
|
|
175
|
-
# Return the currently-logged-in user.
|
176
|
-
def User.current
|
177
|
-
@current_user
|
178
|
-
end
|
179
|
-
|
180
|
-
# Set the currently-logged-in user.
|
181
|
-
def User.current=(u)
|
182
|
-
@current_user = u
|
183
|
-
end
|
184
|
-
|
185
222
|
# Return true if this record corresponds to the currently-logged-in user.
|
186
223
|
# This is used as a security test.
|
187
224
|
def me?
|
188
|
-
|
225
|
+
u = User.current
|
226
|
+
u and u.id == id
|
189
227
|
end
|
190
228
|
|
191
229
|
# Return true if the currently-logged-in user is the administrator.
|
192
230
|
# Class method. This is used as a pseudo-security test by let_display.
|
193
231
|
def User.admin?
|
194
|
-
|
232
|
+
u = User.current
|
233
|
+
return ((u != nil ) and (u.admin.to_i == 1))
|
195
234
|
end
|
196
235
|
|
197
236
|
# Return true if the currently-logged-in user is the administrator.
|
@@ -305,16 +344,6 @@ public
|
|
305
344
|
end
|
306
345
|
end
|
307
346
|
|
308
|
-
# Continue the current login, from the session data.
|
309
|
-
# This should be called by User.setup .
|
310
|
-
def User.sign_on_by_session(user_id)
|
311
|
-
begin
|
312
|
-
return (User.current = User.find(user_id))
|
313
|
-
rescue
|
314
|
-
end
|
315
|
-
return nil
|
316
|
-
end
|
317
|
-
|
318
347
|
# Sign on the user using a security token. Instance method.
|
319
348
|
def sign_on_by_token(t)
|
320
349
|
User.current = User.login_user
|
@@ -323,7 +352,7 @@ public
|
|
323
352
|
self.token_expiry = Time.now
|
324
353
|
self.activated = 1
|
325
354
|
save
|
326
|
-
User
|
355
|
+
User.current = self
|
327
356
|
return self;
|
328
357
|
end
|
329
358
|
return nil
|
data/templates/views/login.rhtml
CHANGED
@@ -1,6 +1,16 @@
|
|
1
|
-
<h1>
|
1
|
+
<h1>
|
2
|
+
<% if flash[:login_header] %>
|
3
|
+
<%= flash[:login_header] + '. ' %>
|
4
|
+
<% end %>
|
5
|
+
Please log in.
|
6
|
+
</h1>
|
2
7
|
|
3
|
-
|
8
|
+
<% if flash[:login_message] %>
|
9
|
+
<p>
|
10
|
+
<%= flash[:login_message] %>
|
11
|
+
</p>
|
12
|
+
<% end %>
|
13
|
+
<%= form_tag :action => 'login' %>
|
4
14
|
<p><label for="user_login">User ID</label><br/>
|
5
15
|
<%= text_field 'user', 'login' %></p>
|
6
16
|
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: model_security_generator
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2005-10-
|
6
|
+
version: 0.0.7
|
7
|
+
date: 2005-10-11
|
8
8
|
summary: "[Rails] Model security and authentication generator."
|
9
9
|
require_paths:
|
10
10
|
- "."
|