Changesets can be listed by changeset number.
The Git repository is here.
- Revision:
- 103
- Log:
The next iteration of Hub. Requires the hubssolib Gem. Stores user
login details in a secure cookie rather than the session, opening up
the potential for cross-application access. Still need to move session
expiry and last-recorded-URL stuff into a cookie, otherwise it's all
done. Many bugs fixed, though some may have been introduced in splitting
functionality into the Gem.No solution presently to whether or not the User object will be understood
or accessible in any way from other applications (not yet tried). Checking
this version in because it's reached a stage of reasonable stability,
before the next step of attempting wider integration.Remember, this won't work at all unless hubssolib 0.0.3 is installed.
- Author:
- adh
- Date:
- Fri Oct 20 19:33:17 +0100 2006
- Size:
- 13068 Bytes
1 | class AccountController < ApplicationController |
2 | |
3 | layout 'default.rhtml' |
4 | |
5 | # Action permissions for this class as a class variable, exposed |
6 | # to the public through a class method. |
7 | |
8 | @@permissions = HubSsoLib::Permissions.new({ |
9 | :logout => [ :admin, :webmaster, :privileged, :normal ], |
10 | :expire => [ :admin, :webmaster, :privileged, :normal ], |
11 | :change_password => [ :admin, :webmaster, :privileged, :normal ], |
12 | :change_details => [ :admin, :webmaster, :privileged, :normal ], |
13 | :delete => [ :admin, :webmaster, :privileged, :normal ], |
14 | :delete_confirm => [ :admin, :webmaster, :privileged, :normal ], |
15 | :list => [ :admin, :webmaster, :privileged ], |
16 | :show => [ :admin ], |
17 | :edit_roles => [ :admin ], |
18 | :destroy => [ :admin ] |
19 | }) |
20 | |
21 | def AccountController.permissions |
22 | @@permissions |
23 | end |
24 | |
25 | # Ensure that we don't try to ask for log-in or sign up except |
26 | # for authorisation-only methods. Avoid session expiry checks# |
27 | # if the user is trying to log out. |
28 | |
29 | attr_accessor :permissions |
30 | skip_before_filter :hubssolib_check_session_expiry, :only => [ :logout, :expire ] |
31 | skip_before_filter :hubssolib_login_required, :only => [ :login, |
32 | :signup, |
33 | :activate, |
34 | :forgot_password, |
35 | :reset_password ] |
36 | |
37 | # If you want "remember me" functionality, add this before_filter and |
38 | # uncomment relevant code in some of the methods below. |
39 | # before_filter :login_from_cookie |
40 | |
41 | # Set up the notification mailer. |
42 | observer :user_observer |
43 | |
44 | # HTTPS enforcement |
45 | before_filter :hubssolib_ensure_https |
46 | |
47 | def login |
48 | @title = 'Log in' |
49 | return unless request.post? |
50 | |
51 | @email = params[:email] |
52 | self.hubssolib_current_user = User.authenticate(@email, params[:password]) |
53 | |
54 | if self.hubssolib_current_user |
55 | |
56 | # If you reinstate (uncomment) this code, ensure you reinstate |
57 | # relevant code in the 'logout' method too. |
58 | # |
59 | # if params[:remember_me] == "1" |
60 | # user = self.hubssolib_current_user |
61 | # user.remember_me |
62 | # self.hubssolib_current_user = user |
63 | # cookies[:auth_token] = { :value => self.hubssolib_current_user.remember_token , :expires => self.hubssolib_current_user.remember_token_expires_at } |
64 | # end |
65 | |
66 | session[:last_used] = Time.now.utc |
67 | flash[:notice] = 'Logged in successfully.' |
68 | hubssolib_redirect_back_or_default(:controller => 'tasks', :action => nil) |
69 | else |
70 | flash[:alert] = 'Incorrect e-mail address or password.' |
71 | flash.discard # Ensure the flash message is discarded after this action, |
72 | # since it's going to be shown on the same URL so it won't |
73 | # get automatically discarded. |
74 | end |
75 | end |
76 | |
77 | # The logout method is a standard action but with an optional parameter |
78 | # which change the 'flash' message shown to the user. By default the user |
79 | # sees a normal 'you have logged out' message, but by passing 'true', the |
80 | # message changes to an indication that the session timed out. See also |
81 | # the 'expire' method below. |
82 | # |
83 | def logout(expired = false) |
84 | @title = 'Log out' |
85 | actually_log_out() |
86 | |
87 | if (expired) |
88 | flash[:attention] = 'Sorry, your session timed out; please log in again.' |
89 | redirect_to :controller => 'account', :action => 'login' |
90 | else |
91 | flash[:attention] = 'You are now logged out.' |
92 | redirect_to :controller => 'tasks', :action => nil |
93 | end |
94 | end |
95 | |
96 | # This method is called by the application controller if it sees that |
97 | # a user as been idle for longer than the idle timeout period. It redirects |
98 | # to a URL which causes this action to be run. In turn, all we do is call |
99 | # the logout method but set the 'expired' flag to get a better 'flash' |
100 | # message shown to the user. |
101 | # |
102 | def expire |
103 | self.logout(true) |
104 | end |
105 | |
106 | def signup |
107 | @title = 'Sign up' |
108 | return unless request.post? |
109 | |
110 | # Bulk assignment from the params hash is safe because the User object |
111 | # contains nothing that won't be overwritten anyway or isn't already |
112 | # protected by attr_accessible in the User model. |
113 | |
114 | @user = User.new(params[:user]) |
115 | |
116 | # Are there any users yet? If not, grant this user admin permissions. |
117 | # Administrators are for just this application; whether or not admin |
118 | # privileges affect other applications depends on the level of external |
119 | # SSO integration. |
120 | |
121 | users = User.find_all |
122 | |
123 | if (users.empty? or users.nil?) |
124 | @user.roles = HubSsoLib::Roles.new(true).to_s |
125 | @user.save! |
126 | @user.activate |
127 | self.hubssolib_current_user = @user |
128 | |
129 | flash[:notice] = 'Thanks for signing up. You are now the system administrator ' << |
130 | 'and your account has been automatically activated.' |
131 | else |
132 | |
133 | @user.roles = HubSsoLib::Roles.new(false).to_s |
134 | @user.save! |
135 | |
136 | flash[:notice] = 'Thanks for signing up. Your site account must be activated ' << |
137 | 'before you can use it - please check your e-mail account ' << |
138 | 'for a message which tells you what you should do next.' |
139 | end |
140 | |
141 | redirect_to :controller => 'tasks', :action => nil |
142 | |
143 | rescue ActiveRecord::RecordInvalid |
144 | render :action => 'signup' |
145 | end |
146 | |
147 | def activate |
148 | activation_code = params[:activation_code] || params[:id] |
149 | |
150 | unless activation_code.nil? |
151 | @user = User.find_by_activation_code(activation_code) |
152 | |
153 | if @user and @user.activate |
154 | self.hubssolib_current_user = @user |
155 | session[:last_used] = Time.now.utc |
156 | |
157 | flash[:notice] = 'Your RISC OS Open web site account is now active.' |
158 | hubssolib_redirect_back_or_default(:controller => 'tasks', :action => nil) |
159 | else |
160 | flash[:alert] = 'Unable to activate your RISC OS Open web site account. ' << |
161 | 'Is the activation code correct, or has it already been used? ' << |
162 | 'If in doubt please try to sign up again. Contact ROOL if you ' << |
163 | 'keep having trouble.' |
164 | |
165 | redirect_to :controller => 'account', :action => 'signup' |
166 | end |
167 | else |
168 | redirect_to :controller => 'account', :action => 'signup' |
169 | end |
170 | end |
171 | |
172 | def change_password |
173 | @title = 'Change password' |
174 | return unless request.post? |
175 | |
176 | user = self.hubssolib_current_user |
177 | |
178 | if User.authenticate(user.email, params[:old_password]) |
179 | if (params[:password] == params[:password_confirmation]) |
180 | user.password_confirmation = params[:password_confirmation] |
181 | user.password = params[:password] |
182 | save_password_and_set_flash(user) |
183 | self.hubssolib_current_user = user |
184 | |
185 | redirect_to :controller => 'tasks', :action => nil |
186 | else |
187 | set_password_mismatch_flash |
188 | flash.discard # Staying on same URL, so it won't be discarded automatically - |
189 | # do it manually now. |
190 | |
191 | @old_password = params[:old_password] |
192 | end |
193 | else |
194 | flash[:alert] = 'Incorrect current password.' |
195 | flash.discard # Staying on same URL again, so discard it manually |
196 | end |
197 | end |
198 | |
199 | def change_details |
200 | @title = 'Update account details' |
201 | @user = self.hubssolib_current_user |
202 | @real_name = @user ? @user.real_name || '' : '' |
203 | |
204 | return unless request.post? |
205 | |
206 | if (params[:real_name]) |
207 | @user.real_name = @real_name = params[:real_name] |
208 | @user.save! |
209 | self.hubssolib_current_user = @user |
210 | |
211 | flash[:notice] = 'Account details updated successfully.' |
212 | flash.discard # The flash is going to be shown on the same URL so it won't |
213 | # be automatically discarded; discard it now so it only shows |
214 | # up once. |
215 | end |
216 | end |
217 | |
218 | def forgot_password |
219 | @title = 'Forgotten password' |
220 | return unless request.post? |
221 | |
222 | if @user = User.find_by_email(params[:email]) |
223 | @user.forgot_password |
224 | @user.save! |
225 | self.hubssolib_current_user = @user |
226 | |
227 | flash[:notice] = 'An e-mail message which tells you how to reset your ' << |
228 | 'account password has been set to your e-mail address.' |
229 | |
230 | redirect_to :controller => 'tasks', :action => nil |
231 | else |
232 | flash[:alert] = 'No account was found for the given e-mail address.' |
233 | flash.discard # Saying on same URL, so manually ensure that flash is discarded after use |
234 | end |
235 | end |
236 | |
237 | def reset_password |
238 | @title = 'Reset password' |
239 | |
240 | if params[:id].nil? |
241 | hubssolib_redirect_back_or_default(:controller => 'tasks', :action => nil) |
242 | return |
243 | end |
244 | |
245 | @user = User.find_by_password_reset_code(params[:id]) |
246 | |
247 | if (@user.nil?) |
248 | flash[:alert] = 'Invalid reset code. Did your e-mail client break up the reset ' << |
249 | 'link so it spanned more than one line? If so, please try again, ' << |
250 | 'copying all of the link in the message however many lines it spans.' |
251 | |
252 | hubssolib_redirect_back_or_default(:controller => 'tasks', :action => nil) |
253 | return |
254 | end |
255 | |
256 | t = Time.now.utc |
257 | if (t >= (@user.password_reset_code_expires_at || t)) # Allows for 'nil' in expiry field |
258 | flash[:alert] = 'The reset code has expired. Please try your reset request again.' |
259 | redirect_to :controller => 'account', :action => 'forgot_password' |
260 | return |
261 | end |
262 | |
263 | unless params[:password] |
264 | flash[:alert] = 'Reset your password using the form below.' |
265 | flash.discard # Staying on same URL, so ensure the flash is discarded after use |
266 | return |
267 | end |
268 | |
269 | if (params[:password] == params[:password_confirmation]) |
270 | @user.password_confirmation = params[:password_confirmation] |
271 | @user.password = params[:password] |
272 | @user.reset_password |
273 | save_password_and_set_flash(@user) |
274 | self.hubssolib_current_user = @user |
275 | redirect_to :controller => 'tasks', :action => nil |
276 | return |
277 | else |
278 | set_password_mismatch_flash |
279 | flash.discard # Staying on same URL, so ensure the flash is discarded after use |
280 | return |
281 | end |
282 | end |
283 | |
284 | def delete |
285 | flash[:alert] = 'Are you sure?' |
286 | flash.discard |
287 | title = 'Delete account: Are you sure?' |
288 | end |
289 | |
290 | def delete_confirm |
291 | me = self.hubssolib_current_user |
292 | actually_log_out() |
293 | me.destroy |
294 | |
295 | flash.clear |
296 | flash[:alert] = 'Your account has been deleted.' |
297 | redirect_to :controller => 'tasks', :action => nil |
298 | end |
299 | |
300 | def list |
301 | @title = 'List of user accounts' |
302 | @users = User.find_all |
303 | end |
304 | |
305 | def show |
306 | @title = 'User account details' |
307 | @user = User.find(params[:id]) |
308 | end |
309 | |
310 | def edit_roles |
311 | @title = 'Edit account roles' |
312 | |
313 | # We must have a valid ID |
314 | |
315 | unless (request.post?) and (params[:id]) and (@user = User.find(params[:id])) |
316 | redirect_to :controller => tasks, :action => nil |
317 | return |
318 | end |
319 | |
320 | # If 'commit' is present, the form was submitted with details rather than |
321 | # visited from a list or account details view. |
322 | |
323 | return unless (params[:commit]) |
324 | |
325 | # Validate the result |
326 | |
327 | roles = (params[:user] ? params[:user][:roles] : '').to_authenticated_roles |
328 | |
329 | unless (roles.validate) |
330 | flash[:alert] = 'Invalid roles chosen. Ensure at least one item in the list is selected.' |
331 | flash.discard # Staying on the same action, so must manually discard the flash |
332 | else |
333 | @user.roles = roles.to_s |
334 | @user.save! |
335 | self.hubssolib_current_user = @user |
336 | |
337 | flash[:notice] = 'Account roles updated successfully.' |
338 | redirect_to :action => 'show', :id => @user.id |
339 | end |
340 | end |
341 | |
342 | def destroy |
343 | user = User.find(params[:id]) |
344 | |
345 | if (user == self.hubssolib_current_user) |
346 | flash[:alert] = 'Please use the normal control panel to delete your own account.' |
347 | elsif (user.roles.to_authenticated_roles.include?(:admin)) |
348 | flash[:alert] = 'You cannot destroy an administrator account! You can only do that at the control panel when logged into the account, or at the database level.' |
349 | else |
350 | user.destroy |
351 | flash[:alert] = 'The account has been deleted.' |
352 | end |
353 | |
354 | redirect_to :action => 'list' |
355 | end |
356 | |
357 | protected |
358 | |
359 | def save_password_and_set_flash(user) |
360 | user.save ? |
361 | flash[:notice] = 'Your password has been changed.' : |
362 | flash[:alert] = 'Sorry, your password could not be changed.' |
363 | end |
364 | |
365 | def set_password_mismatch_flash |
366 | flash[:alert] = 'The new password differed from the password confirmation you entered.' |
367 | end |
368 | |
369 | def actually_log_out |
370 | self.hubssolib_current_user.forget_me if hubssolib_logged_in? |
371 | |
372 | # Calling reset_session() is more thorough, but stops the flash[...] from |
373 | # working. Clearing the user field works well enough. We must clear the |
374 | # current user to ensure the security cookie is cleared too. |
375 | session[:user] = nil |
376 | self.hubssolib_current_user = nil |
377 | end |
378 | |
379 | end |