Giter Club home page Giter Club logo

devise_openid_authenticatable's Introduction

devise_openid_authenticatable Build Status

Written by Nat Budin

devise_openid_authenticatable is OpenID authentication support for Devise applications. It is very thin and uses Rack::OpenID for most of the actual work.

Requirements

  • Devise 1.3 or higher
  • rack-openid

Installation

Add the following to your project's Gemfile:

gem "devise_openid_authenticatable"

Then run bundle install.

Setup

Once devise_openid_authenticatable is installed, add the following to your user model:

devise :openid_authenticatable

You can also add other modules such as token_authenticatable, trackable, etc. Database_authenticatable should work fine alongside openid_authenticatable.

You'll also need to set up the database schema for this:

create_table :users do |t|
  t.string :identity_url
end

and, optionally, indexes:

add_index :users, :identity_url, :unique => true

Option 1: Configure a global identity_url

If the identity URL does not vary per user and you do not want to bother users with that you can configure a static identity URL through Devise.

In config/initializers/devise.rb, add:

Devise.setup do |config|
  config.openid_authenticatable do |openid|
    openid.identity_url = 'http://foobar.com'
  end
end

Option 2: Pass the identity_url along via the login form

In addition, you'll need to modify sessions/new.html.erb (or the appropriate scoped view if you're using those). You need to add a field for identity_url, and remove username and password if you aren't using database_authenticatable:

<% form_for resource_name, resource, :url => session_path(resource_name) do |f| -%>
  <p><%= f.label :identity_url %></p>
  <p><%= f.text_field :identity_url %></p>

  <% if devise_mapping.rememberable? -%>
    <p><%= f.check_box :remember_me %> <%= f.label :remember_me %></p>
  <% end -%>

  <p><%= f.submit "Sign in" %></p>
<% end -%>

Rails 2

Finally, Rails 2 users, you'll need to wire up Rack::OpenID in your Rails configuration:

config.middleware.insert_before(Warden::Manager, Rack::OpenID)

(Rack::OpenID needs to come before Warden in the middleware stack so that by the time devise_openid_authenticatable tries to authenticate the user, the OpenID response will have already been decoded by Rack::OpenID.)

Automatically creating users

If you want to have users automatically created when a new OpenID identity URL is successfully used to sign in, you can implement a method called "build_from_identity_url" to your user model class:

class User < ActiveRecord::Base
  devise :openid_authenticatable

  def self.build_from_identity_url(identity_url)
    User.new(:identity_url => identity_url)
  end
end

SReg and AX Extensions

As of version 1.0.0.alpha4, devise_openid_authenticatable now supports the SReg (simple registration) and AX (attribute exchange) extensions. This allows OpenID providers to pass you additional user details, such as name, email address, gender, nickname, etc.

To add SReg and AX support to your User model, you'll need to do two things: first, you need to specify what fields you'd like to request from OpenID providers. Second, you need to provide a method for processing these fields during authentication.

To specify which fields to request, you can implement one (or both) of two class methods: openid_required_fields and openid_optional_fields. For example:

def self.openid_required_fields
  ["fullname", "email", "http://axschema.org/namePerson", "http://axschema.org/contact/email"]
end

def self.openid_optional_fields
  ["gender", "http://axschema.org/person/gender"]
end

Required fields should be used for fields without which your app can't operate properly. Optional fields should be used for fields which are nice to have, but not necessary for your app. Note that just because you specify a field as "required" doesn't necessarily mean that the OpenID provider has to give it to you (for example, a provider might not have that field for its users).

In the above example, we're specifying both SReg fields (fullname, email, and gender) and the equivalent AX fields (the ones that look like URLs). A list of defined AX fields and their equivalent SReg fields can be found at http://www.axschema.org/types. It is highly recommended to specify both AX and SReg fields, as both are implemented by different common OpenID providers.

Once a successful OpenID response comes back, you still need to process the fields that the provider returned to your app. To do that, implement an instance method called openid_fields=. This method takes a hash that maps each returned field to a string value. For example:

def openid_fields=(fields)
  fields.each do |key, value|
    # Some AX providers can return multiple values per key
    if value.is_a? Array
      value = value.first
    end

    case key.to_s
    when "fullname", "http://axschema.org/namePerson"
      self.name = value
    when "email", "http://axschema.org/contact/email"
      self.email = value
    when "gender", "http://axschema.org/person/gender"
      self.gender = value
    else
      logger.error "Unknown OpenID field: #{key}"
    end
  end
end

See also

TODO

  • Test on non-ActiveRecord ORMs

devise_openid_authenticatable's People

Contributors

dim avatar ecoologic avatar iltempo avatar nbudin avatar neildecapia avatar skyeagle avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

devise_openid_authenticatable's Issues

Deprecation warnings

We should fix the deprecation warnings in Rails 5.

DEPRECATION WARNING: alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super. (called from block in <module:Controller> at /Users/dante/Sites/devise_openid_authenticatable/lib/devise_openid_authenticatable/controller.rb:6)
DEPRECATION WARNING: alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super. (called from <top (required)> at /Users/dante/Sites/devise_openid_authenticatable/spec/spec_helper.rb:7)
DEPRECATION WARNING: alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super. (called from <top (required)> at /Users/dante/Sites/devise_openid_authenticatable/spec/spec_helper.rb:7)
DEPRECATION WARNING: Directly inheriting from ActiveRecord::Migration is deprecated. Please specify the Rails release the migration was written for:

  class CreateTables < ActiveRecord::Migration[4.2] (called from <top (required)> at /Users/dante/Sites/devise_openid_authenticatable/spec/support/migrations.rb:4)
DEPRECATION WARNING: use_transactional_fixtures= is deprecated and will be removed from Rails 5.1 (use use_transactional_tests= instead) (called from <top (required)> at /Users/dante/Sites/devise_openid_authenticatable/spec/model_spec.rb:3)
DEPRECATION WARNING: use_transactional_fixtures= is deprecated and will be removed from Rails 5.1 (use use_transactional_tests= instead) (called from <top (required)> at /Users/dante/Sites/devise_openid_authenticatable/spec/strategy_spec.rb:3)
.DEPRECATION WARNING: before_filter is deprecated and will be removed in Rails 5.1. Use before_action instead. (called from <class:ApplicationController> at /Users/dante/Sites/devise_openid_authenticatable/spec/scenario/app/controllers/application_controller.rb:3)
...DEPRECATION WARNING: ActionDispatch::IntegrationTest HTTP request methods will accept only
the following keyword arguments in future Rails versions:
params, headers, env, xhr, as

Examples:

get '/profile',
  params: { id: 1 },
  headers: { 'X-Extra-Header' => '123' },
  env: { 'action_dispatch.custom' => 'custom' },
  xhr: true,
  as: :json
 (called from block (3 levels) in <top (required)> at /Users/dante/Sites/devise_openid_authenticatable/spec/strategy_spec.rb:88)
.DEPRECATION WARNING: ActionDispatch::IntegrationTest HTTP request methods will accept only
the following keyword arguments in future Rails versions:
params, headers, env, xhr, as

and in lib/devise_openid_authenticable/controller.rb:15 change !!env to !!request.env

Documentation issue?

Hi,

I'm trying to create an example application using Rails 3.1 and only openid_authenticatable, without database_authenticable. The user model looks like this:

class User < ActiveRecord::Base
  devise :openid_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  attr_accessible :email, :remember_me
end

The migration looks like this:

class DeviseCreateUsers < ActiveRecord::Migration
  def self.up
    create_table(:users) do |t|
      t.openid_authenticatable
      t.recoverable
      t.rememberable
      t.trackable
      t.string :email
      t.timestamps
    end

    add_index :users, :email,                :unique => true
  end

  def self.down
    drop_table :users
  end
end

If I go to http://0.0.0.0:3000/users/sign_in

It responds with:

NoMethodError in Devise/sessions#new

Showing .../openid/app/views/devise/sessions/new.html.erb where line #3 raised:

undefined method `session_path' for #<#<Class:0x7fc03a0fe298>:0x7fc03a0f7498>
Extracted source (around line #3):

1: <h2>Sign in</h2>
2: 
3: <%= form_for(resource, :as => resource_name, :url => session_path(resource_name)) do |f| %>
4:   <div><%= f.label :email %><br />
5:   <%= f.email_field :email %></div>
6: 

If I add database_authenticatable, the problem goes away, but I'm trying to do without that. My understanding, looking at the example app for Rails 2.x is that this is supported. Right?

I have:

  • devise (1.4.8)
  • devise_openid_authenticatable (1.0.0)

Does this still work?

This hasn't been updated in over 5 years. Is this still being maintained? If not, could you refer me to a maintained repo?

Error in rails 5.1

I am working on Rails 5.1 application. Getting error when trying to add devise_openid_authenticatable to my Gemfile:

backend_1        | [1] ! Unable to load application: NoMethodError: undefined method `alias_method_chain' for ActionController::Base:Class
backend_1        | Did you mean?  alias_method
backend_1        | bundler: failed to load command: puma (/usr/local/bundle/bin/puma)
backend_1        | NoMethodError: undefined method `alias_method_chain' for ActionController::Base:Class
backend_1        | Did you mean?  alias_method
backend_1        |   /usr/local/bundle/gems/devise_openid_authenticatable-1.3.0/lib/devise_openid_authenticatable/controller.rb:6:in `block in <module:Controller>'
backend_1        |   /usr/local/bundle/gems/activesupport-5.1.2/lib/active_support/concern.rb:120:in `class_eval'
backend_1        |   /usr/local/bundle/gems/activesupport-5.1.2/lib/active_support/concern.rb:120:in `append_features'
backend_1        |   /usr/local/bundle/gems/devise_openid_authenticatable-1.3.0/lib/devise_openid_authenticatable/railtie.rb:11:in `include'
backend_1        |   /usr/local/bundle/gems/devise_openid_authenticatable-1.3.0/lib/devise_openid_authenticatable/railtie.rb:11:in `block in <class:Railtie>'
backend_1        |   /usr/local/bundle/gems/railties-5.1.2/lib/rails/initializable.rb:30:in `instance_exec'
backend_1        |   /usr/local/bundle/gems/railties-5.1.2/lib/rails/initializable.rb:30:in `run'
backend_1        |   /usr/local/bundle/gems/railties-5.1.2/lib/rails/initializable.rb:59:in `block in run_initializers'
backend_1        |   /usr/local/lib/ruby/2.4.0/tsort.rb:228:in `block in tsort_each'
backend_1        |   /usr/local/lib/ruby/2.4.0/tsort.rb:350:in `block (2 levels) in each_strongly_connected_component'
backend_1        |   /usr/local/lib/ruby/2.4.0/tsort.rb:431:in `each_strongly_connected_component_from'
backend_1        |   /usr/local/lib/ruby/2.4.0/tsort.rb:349:in `block in each_strongly_connected_component'
backend_1        |   /usr/local/lib/ruby/2.4.0/tsort.rb:347:in `each'
backend_1        |   /usr/local/lib/ruby/2.4.0/tsort.rb:347:in `call'
backend_1        |   /usr/local/lib/ruby/2.4.0/tsort.rb:347:in `each_strongly_connected_component'
backend_1        |   /usr/local/lib/ruby/2.4.0/tsort.rb:226:in `tsort_each'
backend_1        |   /usr/local/lib/ruby/2.4.0/tsort.rb:205:in `tsort_each'
backend_1        |   /usr/local/bundle/gems/railties-5.1.2/lib/rails/initializable.rb:58:in `run_initializers'
backend_1        |   /usr/local/bundle/gems/railties-5.1.2/lib/rails/application.rb:353:in `initialize!'
backend_1        |   /arbitrue/backend/config/environment.rb:5:in `<top (required)>'
backend_1        |   config.ru:3:in `require_relative'
backend_1        |   config.ru:3:in `block in <main>'
backend_1        |   /usr/local/bundle/gems/rack-2.0.3/lib/rack/builder.rb:55:in `instance_eval'
backend_1        |   /usr/local/bundle/gems/rack-2.0.3/lib/rack/builder.rb:55:in `initialize'
backend_1        |   config.ru:in `new'
backend_1        |   config.ru:in `<main>'
backend_1        |   /usr/local/bundle/gems/rack-2.0.3/lib/rack/builder.rb:49:in `eval'
backend_1        |   /usr/local/bundle/gems/rack-2.0.3/lib/rack/builder.rb:49:in `new_from_string'
backend_1        |   /usr/local/bundle/gems/rack-2.0.3/lib/rack/builder.rb:40:in `parse_file'
backend_1        |   /usr/local/bundle/gems/puma-3.9.1/lib/puma/configuration.rb:313:in `load_rackup'
backend_1        |   /usr/local/bundle/gems/puma-3.9.1/lib/puma/configuration.rb:242:in `app'
backend_1        |   /usr/local/bundle/gems/puma-3.9.1/lib/puma/runner.rb:138:in `load_and_bind'
backend_1        |   /usr/local/bundle/gems/puma-3.9.1/lib/puma/cluster.rb:391:in `run'
backend_1        |   /usr/local/bundle/gems/puma-3.9.1/lib/puma/launcher.rb:174:in `run'
backend_1        |   /usr/local/bundle/gems/puma-3.9.1/lib/puma/cli.rb:77:in `run'
backend_1        |   /usr/local/bundle/gems/puma-3.9.1/bin/puma:10:in `<top (required)>'
backend_1        |   /usr/local/bundle/bin/puma:17:in `load'
backend_1        |   /usr/local/bundle/bin/puma:17:in `<top (required)>'

Support for devise 2.2.3?

I'm going through the gem documentation for an up-to-date rails app, and am getting the following exception when trying to run the migration:

-- create_table(:users)
rake aborted!
An error has occurred, this and all later migrations canceled:

undefined method `openid_authenticatable' for #<ActiveRecord::ConnectionAdapters::TableDefinition:0x007ff198c97750>
/Users/preston/Developer/git/pipecleaner/db/migrate/20130228170815_devise_create_users.rb:39:in `block in change'
/Users/preston/.rvm/gems/ruby-1.9.3-p392/gems/activerecord-3.2.12/lib/active_record/connection_adapters/abstract/schema_statements.rb:160:in `create_table'

adding more required parameters

Hey, i have a question about parameters what are asked from openid server. Right now i think only name is asked. How would it be possible to add requireing nickname and email allso?

Entering a OpenID identifier that includes a comma turns the input into an array causing an error

For instance:

NoMethodError in Devise::SessionsController#create
undefined method `match' for ["http://foo.openid.ne", "jp"]:Array

Entering just a comma for the identifier also causes an error.

It would be nice to render a flash error (Invalid OpenId identifier etc.) for these two instances.

I don't have a regular devise installation (with password login) to test on, so I can't tell if this is actually a issue with devise itself.

allow to connect accounts

if you pass the email to the find (or create) method I can see if there is a user with that email and connect the accounts

Rails 4: Session can not be set after invalid CSRF token

Dear nbudin

When logging in with openid you will see the following warning when a successful openid request is processed:

WARNING: Can't verify CSRF token authenticity

In Rails 3 it doesn't really matter because you override the store? method to always return true which means the session is recreated after it is destroyed by the handle_unverified_request logic. To refresh your memory, look at #19. Note that before you overrided store? you sent the csrf token through in the return_to parameters as discussed in #17 which won't work anymore as discussed #19.

The problem is in Rails 4 (actionpack 4) when a unverified request is detected it completely removes the ability to write anything to the session:

def handle_unverified_request
  request = @controller.request
  request.session = NullSessionHash.new(request.env)
  request.env['action_dispatch.request.flash_hash'] = nil
  request.env['rack.session.options'] = { skip: true }
  request.env['action_dispatch.cookies'] = NullCookieJar.build(request)
end

You can view it on line 110 in https://github.com/rails/rails/blob/4-0-stable/actionpack/lib/action_controller/metal/request_forgery_protection.rb

This means that even though the store method of the warden session_serializer is called, it doesn't recreate the session cookie which doesn't cause a successful login.

Do you know of anyone using this gem successfully with Rails 4? If my investigation is correct and you can not use this gem with Rails 4 I will start investigating how to fix this problem.

Regards,
Pierre

openid fields with Ruby 1.9.2 not working as expected

Hi,

first of all thank you for your work.

I had a little problem with openid fields and ruby 1.9.2. Array.to_s returns now an escaped array:
["BLUB"].to_s
=> "BLUB" # 1.8.7

["BLUB"].to_s
=> "[\"BLUB\"]"  # 1.9.2-rc1

["BLUB"].join
=> "BLUB" # 1.8.7 and 1.9.2-rc1

So join works in ruby 1.8.7 and 1.9.2 as intended.

IMHO: I am not sure if it is a good idea to return a string instead of the array. What happens if a user has multiple email addresses? Would the returned value be something like: [email protected]@example.com? Or is it not possible to get more then one email in return?

BTW a quickfix:
when "http://axschema.org/contact/email"
self.email = value[2..-3]

Trivial to forge a login

First, thanks for working on an OpenID plugin for Devise!

I've unfortunately found (I think) a significant security hole. The openid_authenticatable seems to trust whatever the user enters into the form as their OpenID, rather than verifying it with the identity provider. I've verified this with your devise_openid_example app.

For example: in the example app, I can type http://openid.aol.com/xyz into the "identity url" field. When I submit, I'm redirected to the AOL auth site, which has a "username" and "password" form. On that form, it's trivial to change the username to something else -- in fact, when I get to the page, my browser, via LastPass, automatically inserts "MikeFischer" into the username field. I enter my password, and I'm returned to my app, where it says I'm logged in as http://openid.aol.com/xyz ... but of course, I'm not. The big risk here is that someone else can now come along, type "xyz" into the "openid url" box, and log in with THEIR aol credentials, and then have access to my information on the devise site.

Hope that all makes sense. I'll poke around to see if there's any easy solution, but I have no OpenID expertise so I'm starting from scratch.

PS: Direct login site like Google don't have this problem since they return a new identity_url with a unique identifier, and devise_openid_authenticatable seems to pick that up.

Doesn't work with rememberable

It appears that when devise_openid_authenticatable constructs the OpenID HTTP request, it drops the "remember_me" parameter, thus breaking rememberable.

undefined method `apply_schema' for User:Class (NoMethodError)

Getting the following error when using devise with mongoid:

/Users/fredrik/.rvm/gems/ree-1.8.7-2010.02/gems/devise_openid_authenticatable-1.0.0.alpha2/lib/devise_openid_authenticatable/schema.rb:3:in openid_authenticatable': undefined methodapply_schema' for User:Class (NoMethodError)
from /Users/fredrik/.rvm/gems/ree-1.8.7-2010.02/gems/devise-1.1.0/lib/devise/orm/mongoid.rb:9:in send' from /Users/fredrik/.rvm/gems/ree-1.8.7-2010.02/gems/devise-1.1.0/lib/devise/orm/mongoid.rb:9:indevise_modules_hook!'
from /Users/fredrik/.rvm/gems/ree-1.8.7-2010.02/gems/devise-1.1.0/lib/devise/orm/mongoid.rb:9:in each' from /Users/fredrik/.rvm/gems/ree-1.8.7-2010.02/gems/devise-1.1.0/lib/devise/orm/mongoid.rb:9:indevise_modules_hook!'
from /Users/fredrik/.rvm/gems/ree-1.8.7-2010.02/gems/devise-1.1.0/lib/devise/models.rb:66:in `devise'

Seems to be the same with activerecord:
http://stackoverflow.com/questions/3186536/devise-with-openid-in-rails3-beta4-but-raise-undefined-method-apply-schema-er

[Q] authenticate google apps via a GET request

So google apps will send a user to your app with a url you specify and adds to parameters

from=google
domain=[the google apps domain]

It's a GET request. The identity url is constructed like this

"https://www.google.com/accounts/o8/site-xrds?hd=#{params[:domain]}"

How do I initiate the openid conversation with google immediately on receiving the GET?

referring to this:

https://github.com/nbudin/devise_openid_authenticatable/wiki/Using-devise_openid_authenticatable-with-Heroku-and-Google-Federated-Login

implies to me that there is a "log in using google" button on the sign in page.

that isn't the case here. I could render such a page and preset the identity_url that posts into /users/sign_in but Google expected the signin to happen without a intermediate page to give "a good user experience"

Am I talking nonsense?

Thanks

Geoff

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.