Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pass any AX response to the callback along with the SReg response #5

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.gem
8 changes: 8 additions & 0 deletions CONTRIBUTION_GUIDELINES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
Contributing to open_id_authentication:

1. Fork the [official repository](http://github.com/Velir/open_id_authentication/tree/master).
2. Make your changes in a topic branch.
3. Send a pull request.

Notes:
* Please don't update the Gem version.
115 changes: 67 additions & 48 deletions README → README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,26 @@ The specification used is http://openid.net/specs/openid-authentication-2_0.html


Prerequisites
=============
-------------

OpenID authentication uses the session, so be sure that you haven't turned that off.

Alternatively, you can use the file-based store, which just relies on on tmp/openids being present in RAILS_ROOT. But be aware that this store only works if you have a single application server. And it's not safe to use across NFS. It's recommended that you use the database store if at all possible. To use the file-based store, you'll also have to add this line to your config/environment.rb:

OpenIdAuthentication.store = :file
OpenIdAuthentication.store = :file

This particular plugin also relies on the fact that the authentication action allows for both POST and GET operations.
If you're using RESTful authentication, you'll need to explicitly allow for this in your routes.rb.

The plugin also expects to find a root_url method that points to the home page of your site. You can accomplish this by using a root route in config/routes.rb:

map.root :controller => 'articles'
root :to => "articles#index"

This plugin relies on Rails Edge revision 6317 or newer.


Example
=======
-------

This example is just to meant to demonstrate how you could use OpenID authentication. You might well want to add
salted hash logins instead of plain text passwords and other requirements on top of this. Treat it as a starting point,
Expand All @@ -42,66 +42,70 @@ model you are using for authentication.

Also of note is the following code block used in the example below:

authenticate_with_open_id do |result, identity_url|
...
end
authenticate_with_open_id do |result, identity_url|
...
end

In the above code block, 'identity_url' will need to match user.identity_url exactly. 'identity_url' will be a string in the form of 'http://example.com' -
If you are storing just 'example.com' with your user, the lookup will fail.

There is a handy method in this plugin called 'normalize_url' that will help with validating OpenID URLs.

OpenIdAuthentication.normalize_url(user.identity_url)
OpenIdAuthentication.normalize_url(user.identity_url)

The above will return a standardized version of the OpenID URL - the above called with 'example.com' will return 'http://example.com/'
It will also raise an InvalidOpenId exception if the URL is determined to not be valid.
Use the above code in your User model and validate OpenID URLs before saving them.

config/routes.rb

map.root :controller => 'articles'
map.resource :session

#config/routes.rb
root :to => "articles#index"
resource :session

app/views/sessions/new.erb

<% form_tag(session_url) do %>
<p>
<label for="name">Username:</label>
<%= text_field_tag "name" %>
</p>
#app/views/sessions/new.erb
<% form_tag(session_url) do %>
<p>
<label for="name">Username:</label>
<%= text_field_tag "name" %>
</p>

<p>
<label for="password">Password:</label>
<%= password_field_tag %>
</p>
<p>
<label for="password">Password:</label>
<%= password_field_tag %>
</p>

<p>
...or use:
</p>
<p>
<!-- ...or use: -->
</p>

<p>
<label for="openid_identifier">OpenID:</label>
<%= text_field_tag "openid_identifier" %>
</p>
<p>
<label for="openid_identifier">OpenID:</label>
<%= text_field_tag "openid_identifier" %>
</p>

<p>
<%= submit_tag 'Sign in', :disable_with => "Signing in&hellip;" %>
</p>
<% end %>

<p>
<%= submit_tag 'Sign in', :disable_with => "Signing in&hellip;" %>
</p>
<% end %>

app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def create
if using_open_id?
open_id_authentication
else
password_authentication(params[:name], params[:password])

#app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def create
if using_open_id?
open_id_authentication
else
password_authentication(params[:name], params[:password])
end
end
end


protected
protected
def password_authentication(name, password)
if @current_user = @account.users.authenticate(params[:name], params[:password])
successful_login
Expand All @@ -125,7 +129,7 @@ app/controllers/sessions_controller.rb
end


private
private
def successful_login
session[:user_id] = @current_user.id
redirect_to(root_url)
Expand All @@ -135,7 +139,7 @@ app/controllers/sessions_controller.rb
flash[:error] = message
redirect_to(new_session_url)
end
end
end



Expand All @@ -154,15 +158,16 @@ you can collapse the case into a mere boolean:


Simple Registration OpenID Extension
====================================
------------------------------------

Some OpenID Providers support this lightweight profile exchange protocol. See more: http://www.openidenabled.com/openid/simple-registration-extension

You can support it in your app by changing #open_id_authentication

def open_id_authentication(identity_url)
# Pass optional :required and :optional keys to specify what sreg fields you want.
# Be sure to yield registration, a third argument in the #authenticate_with_open_id block.
# Be sure to yield registration, a third argument in the
# #authenticate_with_open_id block.
authenticate_with_open_id(identity_url,
:required => [ :nickname, :email ],
:optional => :fullname) do |result, identity_url, registration|
Expand Down Expand Up @@ -207,17 +212,31 @@ You can support it in your app by changing #open_id_authentication
end

Attribute Exchange OpenID Extension
===================================
-----------------------------------

Some OpenID providers also support the OpenID AX (attribute exchange) protocol for exchanging identity information between endpoints. See more: http://openid.net/specs/openid-attribute-exchange-1_0.html

Accessing AX data is very similar to the Simple Registration process, described above -- just add the URI identifier for the AX field to your :optional or :required parameters. For example:

authenticate_with_open_id(identity_url,
:required => [ :email, 'http://schema.openid.net/birthDate' ]) do |result, identity_url, registration|
authenticate_with_open_id(identity_url,
:required => [ :email, 'http://schema.openid.net/birthDate' ]) do
|result, identity_url, registration, ax|

This would provide the sreg data for :email via registration, and the AX data for http://schema.openid.net/birthDate via ax.

Contributing
------------

Please see the [contribution guidelines](http://github.com/Velir/open_id_authentication/blob/master/CONTRIBUTION_GUIDELINES.md).

Credits
-------

This would provide the sreg data for :email, and the AX data for 'http://schema.openid.net/birthDate'
open_id_authentication was written by David Heinemeier Hansson with a number of other [contributors](https://github.com/Velir/open_id_authentication/contributors).

open_id_authentication maintenance is funded by [Velir](http://velir.com).


Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license
License
-------
Copyright (c) 2007-2011 David Heinemeier Hansson, released under the MIT license
2 changes: 1 addition & 1 deletion init.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@

config.after_initialize do
OpenID::Util.logger = Rails.logger
ActionController::Base.send :include, OpenIdAuthentication
ActionController::Base.send :include, OpenIdAuthentication::ControllerMethods
end
108 changes: 63 additions & 45 deletions lib/open_id_authentication.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,21 @@ def self.store=(*store_option)

self.store = nil

if Rails.version >= '3'
class Railtie < ::Rails::Railtie
config.app_middleware.use OpenIdAuthentication

config.after_initialize do
OpenID::Util.logger = Rails.logger
end

ActiveSupport.on_load :action_controller do
ActionController::Base.send :include, ControllerMethods
#ActionController::Base.extend ControllerMethods
end
end
end

class Result
ERROR_MESSAGES = {
:missing => "Sorry, the OpenID server couldn't be found",
Expand Down Expand Up @@ -73,56 +88,59 @@ def message
end
end

protected
# The parameter name of "openid_identifier" is used rather than
# the Rails convention "open_id_identifier" because that's what
# the specification dictates in order to get browser auto-complete
# working across sites
def using_open_id?(identifier = nil) #:doc:
identifier ||= open_id_identifier
!identifier.blank? || request.env[Rack::OpenID::RESPONSE]
end
module ControllerMethods
protected
# The parameter name of "openid_identifier" is used rather than
# the Rails convention "open_id_identifier" because that's what
# the specification dictates in order to get browser auto-complete
# working across sites
def using_open_id?(identifier = nil) #:doc:
identifier ||= open_id_identifier
!identifier.blank? || request.env[Rack::OpenID::RESPONSE]
end

def authenticate_with_open_id(identifier = nil, options = {}, &block) #:doc:
identifier ||= open_id_identifier
def authenticate_with_open_id(identifier = nil, options = {}, &block) #:doc:
identifier ||= open_id_identifier

if request.env[Rack::OpenID::RESPONSE]
complete_open_id_authentication(&block)
else
begin_open_id_authentication(identifier, options, &block)
if request.env[Rack::OpenID::RESPONSE]
complete_open_id_authentication(&block)
else
begin_open_id_authentication(identifier, options, &block)
end
end
end

private
def open_id_identifier
params[:openid_identifier] || params[:openid_url]
end
private
def open_id_identifier
params[:openid_identifier] || params[:openid_url]
end

def begin_open_id_authentication(identifier, options = {})
options[:identifier] = identifier
value = Rack::OpenID.build_header(options)
response.headers[Rack::OpenID::AUTHENTICATE_HEADER] = value
head :unauthorized
end
def begin_open_id_authentication(identifier, options = {})
options[:identifier] = identifier
value = Rack::OpenID.build_header(options)
response.headers[Rack::OpenID::AUTHENTICATE_HEADER] = value
head :unauthorized
end

def complete_open_id_authentication
response = request.env[Rack::OpenID::RESPONSE]
identifier = response.display_identifier

case response.status
when OpenID::Consumer::SUCCESS
yield Result[:successful], identifier,
OpenID::SReg::Response.from_success_response(response)
when :missing
yield Result[:missing], identifier, nil
when :invalid
yield Result[:invalid], identifier, nil
when OpenID::Consumer::CANCEL
yield Result[:canceled], identifier, nil
when OpenID::Consumer::FAILURE
yield Result[:failed], identifier, nil
when OpenID::Consumer::SETUP_NEEDED
yield Result[:setup_needed], response.setup_url, nil
def complete_open_id_authentication
response = request.env[Rack::OpenID::RESPONSE]
identifier = response.display_identifier

case response.status
when OpenID::Consumer::SUCCESS
yield Result[:successful], identifier,
OpenID::SReg::Response.from_success_response(response),
OpenID::AX::FetchResponse.from_success_response(response)
when :missing
yield Result[:missing], identifier, nil
when :invalid
yield Result[:invalid], identifier, nil
when OpenID::Consumer::CANCEL
yield Result[:canceled], identifier, nil
when OpenID::Consumer::FAILURE
yield Result[:failed], identifier, nil
when OpenID::Consumer::SETUP_NEEDED
yield Result[:setup_needed], response.setup_url, nil
end
end
end
end
end
4 changes: 4 additions & 0 deletions lib/open_id_authentication/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
module OpenIdAuthentication
VERSION = "1.0.0"
end

32 changes: 32 additions & 0 deletions open_id_authentication.gemspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
$LOAD_PATH << File.join(File.dirname(__FILE__), 'lib')
require 'open_id_authentication/version'
Gem::Specification.new do |s|
s.name = %q{open_id_authentication}
s.version = OpenIdAuthentication::VERSION
s.summary = %q{open_id_authentication provides a thin wrapper around the excellent rack-openid
gem.}
s.description = %q{open_id_authentication provides a thin wrapper around the excellent rack-openid
gem.}

s.files = Dir['[A-Z]*', 'lib/**/*.rb']
s.require_path = 'lib'

s.authors = ["Patrick Robertson"]
s.email = %q{[email protected]}
s.homepage = "https://github.com/Velir/open_id_authentication"

s.platform = Gem::Platform::RUBY
s.rubygems_version = %q{1.2.0}

if s.respond_to? :specification_version then
s.specification_version = 3

if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
s.add_runtime_dependency(%q<rack-openid>, ["~> 1.3"])
else
s.add_dependency(%q<rack-openid>, ["~> 1.3"])
end
else
s.add_dependency(%q<rack-openid>, ["~> 1.3"])
end
end