Changesets can be listed by changeset number.
The Git repository is here.
Changeset 112
After many attempts, a new version of Hub that requires the HubSsoLib
Gem v0.1.0 (see future Changeset #113). HubSsoLib no longer uses cookies
because of problems with the Rails cookies interface and the only viable
workaround being scuppered by after_filter code not always being called
(e.g. if you redirect from within a before_filter). Ultimately, the
solution of using a (very) simple DRb-based authorisation server, as
suggested by RubyPanther on the rubyonrails IRC channel, is perhaps a
little slower but a lot more scalable and a lot more reliable. The server
is included in the 'server' directory.
- Comitted by: adh
- Date: Friday October 27 15:48:03 2006 (over 18 years ago)
Affected files:
- rool/rails/hub/trunk/public/images/icons/
- rool/rails/hub/trunk/server/
- rool/rails/hub/trunk/VERSION
- rool/rails/hub/trunk/app/views/tasks/service.rhtml
- rool/rails/hub/trunk/public/images/icons/logged_in.png
- rool/rails/hub/trunk/public/images/icons/not_logged_in.png
- rool/rails/hub/trunk/server/hub_sso_server.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/helpers/tasks_helper.rb (diff)
- rool/rails/hub/trunk/app/views/account/signup.rhtml (diff)
- rool/rails/hub/trunk/config/environment.rb (diff)
- rool/rails/hub/trunk/public/stylesheets/risc_os_open.css (diff)
rool/rails/hub/trunk/app/controllers/account_controller.rb:
prev. | current | |
end | ||
# Set up the notification mailer. | ||
24 | ||
observer :user_observer | ||
26 | | |
27 | | |
27 | # HTTPS enforcement for all methods, except the login indicator; if someone | |
28 | # is on an HTTP page, the login indicator needs to be fetched by HTTP too so | |
29 | # it can show "logged out" as the secure-only cookies won't get sent. It is | |
30 | # very confusing to be on an HTTP page, apparently fetching the indicator by | |
31 | # HTTP, only to have the image fetch quietly redirect behind the scenes, go | |
32 | # to HTTPS, and say you're logged in - when everyone else thinks you're not. | |
34 | before_filter :hubssolib_ensure_https, :except => :login_indication | |
35 | ||
# The "proper" login method | ||
# | ||
def login | ||
... | ... | |
if (self.hubssolib_current_user and self.hubssolib_current_user != :false) | ||
hubssolib_set_last_used(Time.now.utc) | ||
41 | | |
42 | | |
48 | privileges = hubssolib_get_user_roles.to_human_s.downcase | |
49 | hubssolib_set_flash(:notice, "Logged in successfully. Welcome, #{self.hubssolib_current_user.user_real_name}. You have #{privileges} privileges.") | |
hubssolib_redirect_back_or_default(:controller => 'tasks', :action => nil) | ||
else | ||
flash[:alert] = 'Incorrect e-mail address or password.' | ||
... | ... | |
if @user = User.find_by_email(params[:email]) | ||
@user.forgot_password | ||
@user.save! | ||
170 | | |
flash[:notice] = 'An e-mail message which tells you how to reset your ' << | ||
'account password has been set to your e-mail address.' | ||
... | ... | |
redirect_to :action => 'list' | ||
end | ||
310 | # The login_indication method is unusual; it returns data for an image, | |
311 | # with no-cache parameters set, to indicate whether or not the user is | |
312 | # logged in. It does not render a view. | |
313 | # | |
314 | # The idea is that a caller which caches HTML can include an image tag | |
315 | # that points its source data to this method; the image will be updated | |
316 | # even if the HTML stays cached. | |
317 | # | |
318 | def login_indication | |
319 | file = "#{LOGIN_ICONS}#{hubssolib_logged_in? ? '/logged_in.png' : '/not_logged_in.png'}" | |
320 | ||
321 | @headers['Pragma'] = 'no-cache' | |
322 | @headers['Cache-Control'] = 'no-cache, must-revalidate' | |
323 | ||
324 | send_file file, | |
325 | :type => 'image/png', | |
326 | :disposition => 'inline' | |
327 | end | |
328 | ||
329 | # A supporting unusual method is login_conditional, which redirects to | |
330 | # the login page if the user is logged out or the tasks page if the user | |
331 | # is logged in. It explicitly clears a return-to link, if there is one, | |
332 | # so that the user doesn't drop out of Hub. This is useful if the page | |
333 | # from which the user came cannot support (for example) the Flash display | |
334 | # because of, say, caching. | |
335 | # | |
336 | def login_conditional | |
337 | if (hubssolib_ensure_https) # Redirect back to here using HTTPS, if not already | |
338 | hubssolib_store_location(nil) | |
339 | ||
340 | if (hubssolib_logged_in?) | |
341 | redirect_to :controller => 'tasks', :action => nil | |
342 | else | |
343 | redirect_to :action => 'login' | |
344 | end | |
345 | end | |
346 | end | |
347 | ||
348 | # The login_hop method is also unusual; it redirects to the login page | |
349 | # if the user is logged out, or the tasks page if the user is logged in. | |
350 | # For logging in, an attempt is made to remember the previous URL by HTTP | |
351 | # 'referer' header, with the redirection post-login/logout set to go back | |
352 | # to that page. | |
353 | # | |
354 | # The idea is that a caller which caches HTML can provide a link to this | |
355 | # method which redirects to a more relevant location depending on the | |
356 | # user login status. | |
357 | # | |
358 | def login_hop | |
359 | ret = request.env["HTTP_REFERER"] | |
360 | ||
361 | if hubssolib_logged_in? | |
362 | if (ret && !ret.empty?) | |
363 | uri = URI.parse(ret) | |
364 | ||
365 | # There's a Referer header; did it come from an SSL connection? If | |
366 | # so redirect to the control panel. If not, perhaps the only reason | |
367 | # the user got bounced to the login_hop method was because they were | |
368 | # logged in but had dropped back to HTTP, thus hiding their login | |
369 | # state. Redirect back to the referer, but with HTTPS. Should they | |
370 | # in turn bounce here *again*, we'll be over HTTPS this time, so will | |
371 | # go onto the control panel. | |
372 | ||
373 | if (uri.scheme == 'https') | |
374 | redirect_to :controller => 'tasks', :action => nil | |
375 | else | |
376 | hubssolib_set_flash(:attention, "You were logged in, but using an insecure connection to the web site. You've been moved onto a secure connection and may not need to log in again as a result.") | |
377 | redirect_to hubssolib_promote_uri_to_ssl(ret) | |
378 | end | |
379 | else | |
380 | ||
381 | # There's no Referer header. We're logged in; show the control | |
382 | # panel. | |
383 | ||
384 | redirect_to :controller => 'tasks', :action => nil | |
385 | end | |
386 | else | |
387 | ||
388 | # Try to store the referer header for future reference (won't work | |
389 | # unless we're over HTTPS, but the HubSsoLib deals with some | |
390 | # redirections related to that) and go to the login page. | |
391 | ||
392 | hubssolib_store_location(ret) if (ret && !ret.empty?) | |
393 | redirect_to :action => 'login' | |
394 | end | |
395 | end | |
396 | ||
protected | ||
# Pass a HubSsoLib::User object. Returns an equivalent User Model object. | ||
# | ||
def to_real_user(user) | ||
return nil if user.nil? | ||
310 | | |
403 | raise 'Incorrect argument class' unless (user.class == HubSsoLib::User or user.class == DRbObject) | |
312 | | |
405 | # Unpleasant "user_" prefix in HubSsoLib::User field names is to avoid | |
406 | # collisions (e.g. of "id") with DRbObject. | |
407 | ||
408 | real_user = User.find(user.user_id) | |
raise 'No equivalent real user' unless real_user | ||
315 | | |
316 | | |
317 | | |
318 | | |
319 | | |
320 | | |
321 | | |
322 | | |
323 | | |
324 | | |
325 | | |
326 | | |
411 | real_user.salt = user.user_salt | |
412 | real_user.roles = user.user_roles | |
413 | real_user.activated_at = user.user_activated_at | |
414 | real_user.real_name = user.user_real_name | |
415 | real_user.crypted_password = user.user_crypted_password | |
416 | real_user.remember_token_expires_at = user.user_remember_token_expires_at | |
417 | real_user.activation_code = user.user_activation_code | |
418 | real_user.member_id = user.user_member_id | |
419 | real_user.password_reset_code = user.user_password_reset_code | |
420 | real_user.remember_token = user.user_remember_token | |
421 | real_user.email = user.user_email | |
422 | real_user.password_reset_code_expires_at = user.user_password_reset_code_expires_at | |
return real_user | ||
end | ||
... | ... | |
user = HubSsoLib::User.new | ||
339 | | |
340 | | |
341 | | |
342 | | |
343 | | |
344 | | |
345 | | |
346 | | |
347 | | |
348 | | |
349 | | |
350 | | |
351 | | |
352 | | |
353 | | |
435 | user.user_salt = real_user.salt | |
436 | user.user_roles = real_user.roles | |
437 | user.user_updated_at = real_user.updated_at | |
438 | user.user_activated_at = real_user.activated_at | |
439 | user.user_real_name = real_user.real_name | |
440 | user.user_crypted_password = real_user.crypted_password | |
441 | user.user_remember_token_expires_at = real_user.remember_token_expires_at | |
442 | user.user_activation_code = real_user.activation_code | |
443 | user.user_member_id = real_user.member_id | |
444 | user.user_id = real_user.id | |
445 | user.user_password_reset_code = real_user.password_reset_code | |
446 | user.user_remember_token = real_user.remember_token | |
447 | user.user_email = real_user.email | |
448 | user.user_created_at = real_user.created_at | |
449 | user.user_password_reset_code_expires_at = real_user.password_reset_code_expires_at | |
return user | ||
end |
rool/rails/hub/trunk/app/controllers/application.rb:
prev. | current | |
require 'hub_sso_lib' | ||
include HubSsoLib::Core | ||
10 | | |
10 | before_filter :hubssolib_beforehand | |
11 | after_filter :hubssolib_afterwards | |
end |
rool/rails/hub/trunk/app/controllers/tasks_controller.rb:
prev. | current | |
@title = 'Control panel' | ||
end | ||
23 | ||
24 | def service | |
25 | # Warn that there is a service problem. | |
26 | ||
27 | @title = 'Service failure' | |
28 | @exception_data = hubssolib_get_exception_message(params[:id]) | |
29 | end | |
end |
rool/rails/hub/trunk/app/helpers/tasks_helper.rb:
prev. | current | |
####################################################################### | ||
module TasksHelper | ||
13 | def exception_info | |
14 | data = '<div class="exception">' | |
15 | ||
16 | if (defined?(@exception_data) && @exception_data && !@exception_data.empty?) | |
17 | data << "<p /><b>Technical data:</b><p /><tt>#{h(@exception_data)}</tt>" | |
18 | else | |
19 | data << "<p />Further technical information on this failure is not available." | |
20 | end | |
21 | ||
22 | return data + '</div>' | |
23 | end | |
end |
rool/rails/hub/trunk/app/views/account/signup.rhtml:
prev. | current | |
<p /> | ||
We will never pass your details to third parties or send you unsolicited e-mail messages. | ||
42 | | |
42 | For more information, please see our <a href="/rails/radiant/documents/privacy/">privacy | |
page</a>. | ||
rool/rails/hub/trunk/config/environment.rb:
prev. | current | |
# Location of application relative to document root in terms of | ||
# URLs (i.e. according to the web server configuration, not the | ||
15 | ||
15 | # filesystem location) and location in the filesystem, rather than | |
16 | # according to the Web server, of the login indicator icons. | |
PATH_PREFIX = '/rails/hub' | ||
18 | LOGIN_ICONS = '/home/adh/rails/hub/public/images/icons' | |
Rails::Initializer.run do |config| | ||
# We don't run in the document root, so images etc. must come from |
rool/rails/hub/trunk/public/stylesheets/risc_os_open.css:
prev. | current | |
@import url("/css/risc_os_open.css"); | ||
8 | /* Account listings */ | |
9 | ||
TABLE.list | ||
{ | ||
border-collapse: collapse; | ||
... | ... | |
text-align: center; | ||
} | ||
45 | /* Button-based dangerous action links */ | |
46 | ||
TABLE TD.dangerous IMG, | ||
TABLE TD.dangerous INPUT[type='image'] | ||
{ | ||
... | ... | |
background: inherit; | ||
} | ||
73 | /* Icon-based buttons */ | |
74 | ||
DIV.content A.image, | ||
DIV.content A.image:hover | ||
{ | ||
... | ... | |
border: none; | ||
} | ||
82 | /* Exception handling */ | |
83 | ||
84 | DIV.exception | |
85 | { | |
86 | border: 1px solid #aaa; | |
87 | background: #eee; | |
88 | padding: 10px; | |
89 | color: #A77; | |
90 | font-size: 90% | |
91 | } | |
92 | ||
93 | DIV.exception P | |
94 | { | |
95 | margin: 0; | |
96 | padding: 0; | |
97 | } | |
98 |