Re-write OpenID code to use new authentication plugin. Tested to work!

This commit is contained in:
Eric Allen 2008-12-08 00:52:57 -05:00
parent e92dae2ffc
commit 930999829b
7 changed files with 143 additions and 189 deletions

View file

@ -6,114 +6,45 @@ class LoginController < ApplicationController
skip_before_filter :login_required
before_filter :login_optional
before_filter :get_current_user
open_id_consumer if openid_enabled?
def login
@page_title = "TRACKS::Login"
@openid_url = cookies[:openid_url] if openid_enabled?
case request.method
when :post
if @user = User.authenticate(params['user_login'], params['user_password'])
session['user_id'] = @user.id
# If checkbox on login page checked, we don't expire the session after 1 hour
# of inactivity and we remember this user for future browser sessions
session['noexpiry'] = params['user_noexpiry']
msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire."
notify :notice, "Login successful: session #{msg}"
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => TRACKS_COOKIES_SECURE }
unless should_expire_sessions?
@user.remember_me
cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => TRACKS_COOKIES_SECURE }
if openid_enabled? && using_open_id?
login_openid
else
@page_title = "TRACKS::Login"
case request.method
when :post
if @user = User.authenticate(params['user_login'], params['user_password'])
session['user_id'] = @user.id
# If checkbox on login page checked, we don't expire the session after 1 hour
# of inactivity and we remember this user for future browser sessions
session['noexpiry'] = params['user_noexpiry']
msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire."
notify :notice, "Login successful: session #{msg}"
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => TRACKS_COOKIES_SECURE }
unless should_expire_sessions?
@user.remember_me
cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => TRACKS_COOKIES_SECURE }
end
redirect_back_or_home
return
else
@login = params['user_login']
notify :warning, "Login unsuccessful"
end
redirect_back_or_home
return
else
@login = params['user_login']
notify :warning, "Login unsuccessful"
end
when :get
if User.no_users_yet?
redirect_to :controller => 'users', :action => 'new'
return
end
end
respond_to do |format|
format.html
format.m { render :action => 'login_mobile.html.erb', :layout => 'mobile' }
when :get
if User.no_users_yet?
redirect_to :controller => 'users', :action => 'new'
return
end
end
respond_to do |format|
format.html
format.m { render :action => 'login_mobile.html.erb', :layout => 'mobile' }
end
end
end
def begin
# If the URL was unusable (either because of network conditions,
# a server error, or that the response returned was not an OpenID
# identity page), the library will return HTTP_FAILURE or PARSE_ERROR.
# Let the user know that the URL is unusable.
case open_id_response.status
when OpenID::SUCCESS
session['openid_url'] = params[:openid_url]
session['user_noexpiry'] = params[:user_noexpiry]
# The URL was a valid identity URL. Now we just need to send a redirect
# to the server using the redirect_url the library created for us.
# redirect to the server
respond_to do |format|
format.html { redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), open_id_complete_url) }
format.m { redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), formatted_open_id_complete_url(:format => 'm')) }
end
else
notify :warning, "Unable to find openid server for <q>#{openid_url}</q>"
redirect_to_login
end
end
def complete
openid_url = session['openid_url']
if openid_url.blank?
notify :error, "expected an openid_url"
end
case open_id_response.status
when OpenID::FAILURE
# In the case of failure, if info is non-nil, it is the
# URL that we were verifying. We include it in the error
# message to help the user figure out what happened.
if open_id_response.identity_url
msg = "Verification of #{openid_url}(#{open_id_response.identity_url}) failed. "
else
msg = "Verification failed. "
end
notify :error, open_id_response.msg.to_s + msg
when OpenID::SUCCESS
# Success means that the transaction completed without
# error. If info is nil, it means that the user cancelled
# the verification.
@user = User.find_by_open_id_url(openid_url)
unless (@user.nil?)
session['user_id'] = @user.id
session['noexpiry'] = session['user_noexpiry']
msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire."
notify :notice, "You have successfully verified #{openid_url} as your identity. Login successful: session #{msg}"
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => TRACKS_COOKIES_SECURE }
unless should_expire_sessions?
@user.remember_me
cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => TRACKS_COOKIES_SECURE }
end
cookies[:openid_url] = { :value => openid_url, :expires => Time.now + 1.year, :secure => TRACKS_COOKIES_SECURE }
redirect_back_or_home
else
notify :warning, "You have successfully verified #{openid_url} as your identity, but you do not have a Tracks account. Please ask your administrator to sign you up."
end
when OpenID::CANCEL
notify :warning, "Verification cancelled."
else
notify :warning, "Unknown response status: #{open_id_response.status}"
end
redirect_to_login unless performed?
end
def logout
@user.forget_me if logged_in?
cookies.delete :auth_token
@ -156,5 +87,31 @@ class LoginController < ApplicationController
def should_expire_sessions?
session['noexpiry'] != "on"
end
protected
def login_openid
# If checkbox on login page checked, we don't expire the session after 1 hour
# of inactivity and we remember this user for future browser sessions
session['noexpiry'] ||= params['user_noexpiry']
authenticate_with_open_id do |result, identity_url|
if result.successful?
if @user = User.find_by_identity_url(identity_url)
session['user_id'] = @user.id
msg = (should_expire_sessions?) ? "will expire after 1 hour of inactivity." : "will not expire."
notify :notice, "Login successful: session #{msg}"
cookies[:tracks_login] = { :value => @user.login, :expires => Time.now + 1.year, :secure => TRACKS_COOKIES_SECURE }
unless should_expire_sessions?
@user.remember_me
cookies[:auth_token] = { :value => @user.remember_token , :expires => @user.remember_token_expires_at, :secure => TRACKS_COOKIES_SECURE }
end
redirect_back_or_home
else
notify :warning, "Sorry, no user by that identity URL exists (#{identity_url})"
end
else
notify :warning, result.message
end
end
end
end

View file

@ -1,10 +1,4 @@
class UsersController < ApplicationController
if openid_enabled?
open_id_consumer
before_filter :begin_open_id_auth, :only => :update_auth_type
end
before_filter :admin_login_required, :only => [ :index, :show, :destroy ]
skip_before_filter :login_required, :only => [ :new, :create ]
prepend_before_filter :login_optional, :only => [ :new, :create ]
@ -153,18 +147,25 @@ class UsersController < ApplicationController
end
def update_auth_type
if (params[:user][:auth_type] == 'open_id') && openid_enabled?
case open_id_response.status
when OpenID::SUCCESS
# The URL was a valid identity URL. Now we just need to send a redirect
# to the server using the redirect_url the library created for us.
session['openid_url'] = params[:openid_url]
# redirect to the server
redirect_to open_id_response.redirect_url((request.protocol + request.host_with_port + "/"), url_for(:action => 'complete'))
if (params[:open_id_complete] || (params[:user][:auth_type] == 'open_id')) && openid_enabled?
authenticate_with_open_id do |result, identity_url|
if result.successful?
# Success means that the transaction completed without
# error. If info is nil, it means that the user cancelled
# the verification.
@user.auth_type = 'open_id'
@user.identity_url = identity_url
if @user.save
notify :notice, "You have successfully verified #{identity_url} as your identity and set your authentication type to Open ID."
else
debugger
notify :warning, "You have successfully verified #{identity_url} as your identity but there was a problem saving your authentication preferences."
end
redirect_to preferences_path
else
notify :warning, "Unable to find openid server for <q>#{openid_url}</q>"
notify :warning, result.message
redirect_to :action => 'change_auth_type'
end
end
return
end
@ -178,47 +179,6 @@ class UsersController < ApplicationController
end
end
def complete
return unless openid_enabled?
openid_url = session['openid_url']
if openid_url.blank?
notify :error, "expected an openid_url"
end
case open_id_response.status
when OpenID::FAILURE
# In the case of failure, if info is non-nil, it is the
# URL that we were verifying. We include it in the error
# message to help the user figure out what happened.
if open_id_response.identity_url
msg = "Verification of #{openid_url}(#{open_id_response.identity_url}) failed. "
else
msg = "Verification failed. "
end
notify :error, open_id_response.msg.to_s + msg
when OpenID::SUCCESS
# Success means that the transaction completed without
# error. If info is nil, it means that the user cancelled
# the verification.
@user.auth_type = 'open_id'
@user.open_id_url = openid_url
if @user.save
notify :notice, "You have successfully verified #{openid_url} as your identity and set your authentication type to Open ID."
else
notify :warning, "You have successfully verified #{openid_url} as your identity but there was a problem saving your authentication preferences."
end
redirect_to preferences_path
when OpenID::CANCEL
notify :warning, "Verification cancelled."
else
notify :warning, "Unknown response status: #{open_id_response.status}"
end
redirect_to :action => 'change_auth_type' unless performed?
end
def refresh_token
@user.generate_token
@user.save!

View file

@ -116,11 +116,11 @@ class User < ActiveRecord::Base
validates_confirmation_of :password
validates_length_of :login, :within => 3..80
validates_uniqueness_of :login, :on => :create
validates_presence_of :open_id_url, :if => :using_openid?
validates_presence_of :identity_url, :if => :using_openid?
before_create :crypt_password, :generate_token
before_update :crypt_password
before_save :normalize_open_id_url
before_save :normalize_identity_url
#for will_paginate plugin
cattr_accessor :per_page
@ -145,9 +145,9 @@ class User < ActiveRecord::Base
return nil
end
def self.find_by_open_id_url(raw_open_id_url)
normalized_open_id_url = normalize_open_id_url(raw_open_id_url)
find(:first, :conditions => ['open_id_url = ?', normalized_open_id_url])
def self.find_by_identity_url(raw_identity_url)
normalized_identity_url = OpenIdAuthentication.normalize_url(raw_identity_url)
find(:first, :conditions => ['identity_url = ?', normalized_identity_url])
end
def self.no_users_yet?
@ -235,15 +235,8 @@ protected
crypted_password == sha1(pass)
end
def normalize_open_id_url
return if open_id_url.nil?
self.open_id_url = self.class.normalize_open_id_url(open_id_url)
def normalize_identity_url
return if identity_url.nil?
self.identity_url = OpenIdAuthentication.normalize_url(identity_url)
end
def self.normalize_open_id_url(raw_open_id_url)
normalized = raw_open_id_url
normalized = "http://#{raw_open_id_url}" unless raw_open_id_url =~ /\:\/\//
normalized.downcase.chomp('/')
end
end

View file

@ -36,7 +36,7 @@
<% if show_openid_form %>
<div id="openid_auth_form" style="display:none">
<% form_tag :action=> 'login', :action => 'begin' do %>
<% form_tag :action=> 'login' do %>
<table>
<tr>
<td><label for="openid_url">Identity URL:</label></td>

View file

@ -6,10 +6,6 @@ ActionController::Routing::Routes.draw do |map|
login.formatted_login 'login.:format', :action => 'login'
login.logout 'logout', :action => 'logout'
login.formatted_logout 'logout.:format', :action => 'logout'
login.open_id_begin 'begin', :action => 'begin'
login.formatted_open_id_begin 'begin.:format', :action => 'begin'
login.open_id_complete 'complete', :action => 'complete'
login.formatted_open_id_complete 'complete.:format', :action => 'complete'
end
map.resources :users,
@ -57,6 +53,7 @@ ActionController::Routing::Routes.draw do |map|
todos.mobile_abbrev 'm', :action => "index", :format => 'm'
todos.mobile_abbrev_new 'm/new', :action => "new", :format => 'm'
end
map.root :controller => 'todos' # Make OpenID happy because it needs #root_url defined
map.resources :notes
map.feeds 'feeds', :controller => 'feedlist', :action => 'index'

View file

@ -0,0 +1,47 @@
class UpgradeOpenId < ActiveRecord::Migration
def self.up
create_table :open_id_authentication_associations, :force => true do |t|
t.integer :issued, :lifetime
t.string :handle, :assoc_type
t.binary :server_url, :secret
end
create_table :open_id_authentication_nonces, :force => true do |t|
t.integer :timestamp, :null => false
t.string :server_url, :null => true
t.string :salt, :null => false
end
add_column :users, :identity_url, :string
drop_table :open_id_associations
drop_table :open_id_nonces
drop_table :open_id_settings
end
def self.down
drop_table :open_id_authentication_associations
drop_table :open_id_authentication_nonces
create_table "open_id_associations", :force => true do |t|
t.binary "server_url"
t.string "handle"
t.binary "secret"
t.integer "issued"
t.integer "lifetime"
t.string "assoc_type"
end
create_table "open_id_nonces", :force => true do |t|
t.string "nonce"
t.integer "created"
end
create_table "open_id_settings", :force => true do |t|
t.string "setting"
t.binary "value"
end
remove_column :users, :identity_url
end
end

View file

@ -326,18 +326,18 @@ class UserTest < Test::Rails::TestCase
assert_nil users(:other_user).remember_token
end
def test_normalizes_open_id_url_on_save
def test_normalizes_identity_url_on_save
['www.johndoe.com', 'WWW.JOHNDOE.COM', 'http://www.johndoe.com/', 'http://www.johndoe.com'].each do |initial|
assert_open_id_url_normalized_on_save initial, 'http://www.johndoe.com'
assert_identity_url_normalized_on_save initial, 'http://www.johndoe.com/'
end
end
def test_normalizes_open_id_url_on_find
def test_normalizes_identity_url_on_find
u = users(:other_user)
u.open_id_url = 'http://www.johndoe.com'
u.identity_url = 'http://www.johndoe.com'
u.save
['www.johndoe.com', 'WWW.JOHNDOE.COM', 'http://www.johndoe.com/', 'http://www.johndoe.com'].each do |raw_open_id_url|
assert_equal u.id, User.find_by_open_id_url(raw_open_id_url).id
['www.johndoe.com', 'WWW.JOHNDOE.COM', 'http://www.johndoe.com/', 'http://www.johndoe.com'].each do |raw_identity_url|
assert_equal u.id, User.find_by_identity_url(raw_identity_url).id
end
end
@ -348,11 +348,11 @@ class UserTest < Test::Rails::TestCase
User.create({ :login => 'quire', :password => 'quire', :password_confirmation => 'quire' }.merge(options))
end
def assert_open_id_url_normalized_on_save(initial, expected)
def assert_identity_url_normalized_on_save(initial, expected)
u = users(:other_user)
u.open_id_url = initial
u.identity_url = initial
u.save
assert_equal expected, u.open_id_url
assert_equal expected, u.identity_url
end
end