Changesets can be listed by changeset number.
The Git repository is here.
Changeset 103
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.
- Comitted by: adh
- Date: Friday October 20 19:33:17 2006 (over 17 years ago)
Affected files:
rool/rails/hub/trunk/app/views/user_notifier/destruction.rhtml
rool/rails/hub/trunk/lib/
rool/rails/hub/trunk/app/helpers/tasks_controller.rb
rool/rails/hub/trunk/app/controllers/account_controller.rb (diff)
rool/rails/hub/trunk/app/controllers/application.rb (diff)
rool/rails/hub/trunk/app/controllers/tasks_controller.rb (diff)
rool/rails/hub/trunk/app/models/user.rb (diff)
rool/rails/hub/trunk/app/models/user_notifier.rb (diff)
rool/rails/hub/trunk/app/views/account/edit_roles.rhtml (diff)
rool/rails/hub/trunk/app/views/account/login.rhtml (diff)
rool/rails/hub/trunk/app/views/tasks/index.rhtml (diff)
rool/rails/hub/trunk/config/environment.rb (diff)
rool/rails/hub/trunk/test/functional/account_controller_test.rb (diff)
rool/rails/hub/trunk/app/controllers/account_controller.rb:
prev. | current | |
class AccountController < ApplicationController | ||
3 | | |
layout 'default.rhtml' | ||
6 | | |
5 | # Action permissions for this class as a class variable, exposed | |
6 | # to the public through a class method. | |
8 | | |
9 | | |
10 | | |
11 | | |
12 | | |
13 | | |
14 | | |
15 | | |
16 | | |
17 | | |
18 | | |
19 | | |
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 | }) | |
def AccountController.permissions | ||
@@permissions | ||
... | ... | |
# if the user is trying to log out. | ||
attr_accessor :permissions | ||
30 | | |
31 | | |
32 | | |
33 | | |
34 | | |
35 | | |
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 ] | |
# If you want "remember me" functionality, add this before_filter and | ||
# uncomment relevant code in some of the methods below. | ||
... | ... | |
# Set up the notification mailer. | ||
observer :user_observer | ||
44 | # HTTPS enforcement | |
45 | before_filter :hubssolib_ensure_https | |
46 | ||
def login | ||
@title = 'Log in' | ||
return unless request.post? | ||
@email = params[:email] | ||
49 | | |
52 | self.hubssolib_current_user = User.authenticate(@email, params[:password]) | |
51 | | |
54 | if self.hubssolib_current_user | |
# If you reinstate (uncomment) this code, ensure you reinstate | ||
# relevant code in the 'logout' method too. | ||
# | ||
# if params[:remember_me] == "1" | ||
57 | ||
58 | ||
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 } | |
# end | ||
session[:last_used] = Time.now.utc | ||
flash[:notice] = 'Logged in successfully.' | ||
63 | | |
68 | hubssolib_redirect_back_or_default(:controller => 'tasks', :action => nil) | |
else | ||
flash[:alert] = 'Incorrect e-mail address or password.' | ||
flash.discard # Ensure the flash message is discarded after this action, | ||
... | ... | |
users = User.find_all | ||
if (users.empty? or users.nil?) | ||
119 | | |
124 | @user.roles = HubSsoLib::Roles.new(true).to_s | |
@user.save! | ||
@user.activate | ||
127 | self.hubssolib_current_user = @user | |
123 | | |
124 | ||
flash[:notice] = 'Thanks for signing up. You are now the system administrator ' << | ||
'and your account has been automatically activated.' | ||
else | ||
129 | | |
133 | @user.roles = HubSsoLib::Roles.new(false).to_s | |
@user.save! | ||
flash[:notice] = 'Thanks for signing up. Your site account must be activated ' << | ||
... | ... | |
@user = User.find_by_activation_code(activation_code) | ||
if @user and @user.activate | ||
150 | | |
154 | self.hubssolib_current_user = @user | |
session[:last_used] = Time.now.utc | ||
flash[:notice] = 'Your RISC OS Open web site account is now active.' | ||
154 | | |
158 | hubssolib_redirect_back_or_default(:controller => 'tasks', :action => nil) | |
else | ||
flash[:alert] = 'Unable to activate your RISC OS Open web site account. ' << | ||
'Is the activation code correct, or has it already been used? ' << | ||
... | ... | |
@title = 'Change password' | ||
return unless request.post? | ||
172 | | |
176 | user = self.hubssolib_current_user | |
177 | ||
178 | if User.authenticate(user.email, params[:old_password]) | |
if (params[:password] == params[:password_confirmation]) | ||
174 | | |
175 | | |
176 | | |
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 | |
redirect_to :controller => 'tasks', :action => nil | ||
else | ||
... | ... | |
def change_details | ||
@title = 'Update account details' | ||
194 | | |
201 | @user = self.hubssolib_current_user | |
@real_name = @user ? @user.real_name || '' : '' | ||
return unless request.post? | ||
... | ... | |
if (params[:real_name]) | ||
@user.real_name = @real_name = params[:real_name] | ||
@user.save! | ||
209 | self.hubssolib_current_user = @user | |
flash[:notice] = 'Account details updated successfully.' | ||
flash.discard # The flash is going to be shown on the same URL so it won't | ||
... | ... | |
if @user = User.find_by_email(params[:email]) | ||
@user.forgot_password | ||
216 | | |
224 | @user.save! | |
225 | self.hubssolib_current_user = @user | |
226 | ||
flash[:notice] = 'An e-mail message which tells you how to reset your ' << | ||
'account password has been set to your e-mail address.' | ||
... | ... | |
@title = 'Reset password' | ||
if params[:id].nil? | ||
231 | | |
241 | hubssolib_redirect_back_or_default(:controller => 'tasks', :action => nil) | |
return | ||
end | ||
... | ... | |
'link so it spanned more than one line? If so, please try again, ' << | ||
'copying all of the link in the message however many lines it spans.' | ||
242 | | |
252 | hubssolib_redirect_back_or_default(:controller => 'tasks', :action => nil) | |
return | ||
end | ||
... | ... | |
@user.password = params[:password] | ||
@user.reset_password | ||
save_password_and_set_flash(@user) | ||
274 | self.hubssolib_current_user = @user | |
redirect_to :controller => 'tasks', :action => nil | ||
return | ||
else | ||
... | ... | |
end | ||
def delete_confirm | ||
280 | | |
291 | me = self.hubssolib_current_user | |
actually_log_out() | ||
me.destroy | ||
... | ... | |
else | ||
@user.roles = roles.to_s | ||
@user.save! | ||
335 | self.hubssolib_current_user = @user | |
flash[:notice] = 'Account roles updated successfully.' | ||
redirect_to :action => 'show', :id => @user.id | ||
... | ... | |
def destroy | ||
user = User.find(params[:id]) | ||
333 | | |
345 | if (user == self.hubssolib_current_user) | |
flash[:alert] = 'Please use the normal control panel to delete your own account.' | ||
elsif (user.roles.to_authenticated_roles.include?(:admin)) | ||
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.' | ||
... | ... | |
redirect_to :action => 'list' | ||
end | ||
345 | | |
357 | protected | |
def save_password_and_set_flash(user) | ||
user.save ? | ||
... | ... | |
end | ||
def actually_log_out | ||
358 | | |
359 | ||
370 | self.hubssolib_current_user.forget_me if hubssolib_logged_in? | |
# Calling reset_session() is more thorough, but stops the flash[...] from | ||
362 | | |
363 | | |
364 | | |
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 | |
end | ||
378 | ||
end |
rool/rails/hub/trunk/app/controllers/application.rb:
prev. | current | |
class ApplicationController < ActionController::Base | ||
6 | | |
7 | | |
6 | # Include the authorisation engine support code. | |
9 | | |
10 | | |
11 | | |
8 | require 'hub_sso_lib' | |
9 | include HubSsoLib::Core | |
13 | | |
11 | # Make sure the authorisation engine is always called before anything | |
12 | # else is allowed. The login requirement filter checks for session expiry | |
13 | # on authorised pages when logged in. We also call an update filter so | |
14 | # that the expiry timeout is updated for methods that don't need login. | |
15 | | |
16 | | |
16 | before_filter :hubssolib_login_required | |
17 | before_filter :hubssolib_update_session_expiry | |
end |
rool/rails/hub/trunk/app/controllers/tasks_controller.rb:
prev. | current | |
helper :Tasks | ||
layout 'default.rhtml' | ||
16 | | |
16 | skip_before_filter :hubssolib_login_required | |
def index | ||
# Generate a list of available tasks. |
rool/rails/hub/trunk/app/models/user.rb:
prev. | current | |
# Returns true if the user has just been activated. | ||
def recently_activated? | ||
76 | | |
76 | activated = @activated | |
77 | @activated = false | |
78 | return activated | |
end | ||
# Deal with forgotten passwords | ||
... | ... | |
end | ||
def recently_reset_password? | ||
97 | | |
99 | reset_password = @reset_password | |
100 | @reset_password = false | |
101 | return reset_password | |
end | ||
def recently_forgot_password? | ||
101 | | |
105 | forgotten_password = @forgotten_password | |
106 | @forgotten_password = false | |
107 | return forgotten_password | |
end | ||
110 | def destroy | |
111 | UserNotifier.deliver_destruction(self) | |
112 | super | |
113 | end | |
114 | ||
protected | ||
# before filter | ||
def encrypt_password |
rool/rails/hub/trunk/app/models/user_notifier.rb:
prev. | current | |
class UserNotifier < ActionMailer::Base | ||
def signup_notification(user) | ||
setup_email(user) | ||
4 | | |
4 | @subject += 'Please activate your new RISC OS Open web site account' | |
@body[:url] = "https://#{EMAIL_HOST}#{PATH_PREFIX}/account/activate/#{user.activation_code}" | ||
end | ||
def activation(user) | ||
setup_email(user) | ||
10 | | |
10 | @subject += 'Your RISC OS Open web site account has been activated' | |
@body[:url] = "https://#{EMAIL_HOST}#{PATH_PREFIX}/tasks" | ||
end | ||
def forgot_password(user) | ||
setup_email(user) | ||
16 | | |
16 | @subject += 'Request to change a RISC OS Open web site account password' | |
@body[:url] = "https://#{EMAIL_HOST}#{PATH_PREFIX}/account/reset_password/#{user.password_reset_code}" | ||
end | ||
def reset_password(user) | ||
setup_email(user) | ||
22 | | |
22 | @subject += 'Your RISC OS Open web site account password has been reset' | |
@body[:url] = EMAIL_ADMIN | ||
end | ||
26 | def destruction(user) | |
27 | setup_email(user) | |
28 | @subject += 'Your RISC OS Open web site account has been deleted' | |
29 | @body[:url] = EMAIL_ADMIN | |
30 | end | |
31 | ||
protected | ||
def setup_email(user) |
rool/rails/hub/trunk/app/views/account/edit_roles.rhtml:
prev. | current | |
<td align="center"> | ||
<%= create_roles_selector('user', | ||
'roles', | ||
23 | | |
24 | | |
23 | HubSsoLib::Roles.get_role_symbols, | |
24 | @user.roles) { |symbol| HubSsoLib::Roles.get_display_name(symbol) } -%> | |
</td> | ||
</tr> | ||
</table> |
rool/rails/hub/trunk/app/views/account/login.rhtml:
prev. | current | |
<%= end_form_tag %> | ||
<p /> | ||
23 | | |
23 | Other options: | |
24 | ||
25 | <p /> | |
26 | <ul> | |
27 | <li><%= link_to 'Go back to the list of tasks', :controller => 'tasks', :action => 'index' %></li> | |
28 | <li><%= link_to 'Forgotten your password?', :controller => 'account', :action => 'forgot_password' %></li> | |
29 | </ul> |
rool/rails/hub/trunk/app/views/tasks/index.rhtml:
prev. | current | |
<p /> | ||
<ul> | ||
11 | ||
11 | <% unless hubssolib_logged_in? -%> | |
<li><%= link_to 'Log in to your web site account', :controller => 'account', :action => 'login' %></li> | ||
<li><%= link_to 'Create a new account', :controller => 'account', :action => 'signup' %></li> | ||
<li><%= link_to "Forgotten your password?", :controller => 'account', :action => 'forgot_password' %></li> | ||
... | ... | |
<% end -%> | ||
</ul> | ||
23 | ||
23 | <% if hubssolib_logged_in? && hubssolib_authorized?('list', AccountController) -%> | |
<p /> | ||
Administrative options: | ||
rool/rails/hub/trunk/config/environment.rb:
prev. | current | |
# Hostname to use in notification messages. The PATH_PREFIX and | ||
# controller/action data will be appended to it. | ||
89 | ||
89 | EMAIL_HOST = 'pond.org.uk' | |
# Time limit, *in seconds*, for password reset e-mail codes. The | ||
# codes persist in the database indefinitely but will be rejected | ||
... | ... | |
# If a user performs no Clubhouse actions during this time they | ||
# will be automatically logged out upon their next action. | ||
IDLE_TIME_LIMIT = 15 * 60 | ||
100 | ||
101 | # Random file location | |
102 | RND_FILE_PATH = '/home/adh/.rnd' | |
103 | ||
104 | # Session data cookie name | |
105 | SESSION_DATA_KEY = 'hubapp_session_data' | |
106 | ||
107 | # Session data cookie expiry time in seconds | |
108 | SESSION_DATA_EXPIRY = 2 * 24 * 60 * 60 |
rool/rails/hub/trunk/test/functional/account_controller_test.rb:
prev. | current | |
def test_should_login_and_redirect | ||
post :login, :login => 'quentin', :password => 'test' | ||
assert session[:user] | ||
23 | assert session[:user_id] | |
assert_response :redirect | ||
end | ||
def test_should_fail_login_and_not_redirect | ||
post :login, :login => 'quentin', :password => 'bad password' | ||
assert_nil session[:user] | ||
30 | assert_nil session[:user_id] | |
assert_response :success | ||
end | ||
... | ... | |
login_as :quentin | ||
get :logout | ||
assert_nil session[:user] | ||
77 | assert_nil session[:user_id] | |
assert_response :redirect | ||
end | ||
... | ... | |
post :login, :login => 'quentin', :password => 'test', :remember_me => "0" | ||
assert_nil @response.cookies["auth_token"] | ||
end | ||
87 | | |
90 | ||
def test_should_delete_token_on_logout | ||
login_as :quentin | ||
get :logout | ||
... | ... | |
protected | ||
def create_user(options = {}) | ||
118 | | |
121 | post :signup, :user => { :login => 'quire', :email => 'quire@example.com', | |
:password => 'quire', :password_confirmation => 'quire' }.merge(options) | ||
end | ||
121 | | |
124 | ||
def auth_token(token) | ||
CGI::Cookie.new('name' => 'auth_token', 'value' => token) | ||
end | ||
125 | | |
128 | ||
def cookie_for(user) | ||
auth_token users(user).remember_token | ||
end |