OpenID-2.0.2 with Rails-2.0.2

Posted by face on December 29, 2007

OpenID makes sense. Dr. Nick’s multi-OpenIDs per user example app makes even more sense.

In the middle of integrating it into my project, gem-1.0.1 came out and broke ruby-openid-1.1.4. Dr. Nick’s great example no longer worked!

A little digging and I found Dr. Nick’s example uses the standard open_id_authentication. That has a patch to work on ruby-openid-2.0.2 and rails 2 which can be found here.

So in a nutshell, I grabbed openidauth_multiopenid-0.3.2 from Dr. Nick, removed a bunch of stuff from vendor plugins. Updated Rakefile, config/boot.rb, and config/environment.rb for rails 2.0.2. Patched vendor/plugins/open_id_authentication for ruby-openid-2.0.2. Regenerated db/migration/002_add_open_id_authentication_tables.rb. And installed ruby-openid-2.0.2 as a system gem.

As a little code is worth more than a thousand words, here is Dr. Nick’s example application fully ported to rails 2.0.2 in ZIP and TAR.gz.

For my port of Dr. Nick’s example above to work, you will need rails-2.0.2 and ruby-openid-2.0.2 installed as a gems.

Security Update: January 4th, 2007 I noticed the example adds edit, update, and destroy to users_controller.rb using params[:id] thus allowing any logged in user to edit, update, and destroy any user of the system. To fix, simply change the first line of edit, update, and destroy to use the current logged in user (i.e. @user = User.find(self.current_user.id)).

Another Update:February 27th, 2007 One of my clients noticed the user_openids_controller’s index method finds all openids for all users if you surf to user_openids URL. To fix, change the find in user_openids_controller.index to be @user_openids = UserOpenid.find_all_by_user_id(@user.id). I think it’s time I put this example under SVN and apply these security upates…

It should look something like this under rails 2.0.2:

References:

http://drnicwilliams.com/2007/07/26/sample-app-rails-multiple-openids-per-user/
http://dev.rubyonrails.org/ticket/10604
http://openidenabled.com/ruby-openid/
http://svn.rubyonrails.org/rails/plugins/open_id_authentication/
http://openid.net/


Digg! Delicious! Technorati Blinklist Furl Reddit
Comments

Leave a response

  1. Dr NicDecember 29, 2007 @ 03:36 AM
    Champion effort!
  2. yahooJanuary 25, 2008 @ 10:51 PM
    I downloaded the tar file and tried to login via my yahoo OpenID and get: "Sorry! You will not be able to login to this website as it is using an older version of the the OpenID technology. Yahoo! only supports OpenID 2.0 because it is more secure." Any ideas?
  3. faceJanuary 27, 2008 @ 01:47 AM

    Got me stumped…I suspect it is Yahoo’s problem though.

    I looked at the ruby code it all looks OpenID 2.0…

    The example consumer from ruby-openid exhibits the same problem for me: http://openidenabled.com/ruby-openid/trunk/examples/consumer

    I’ll investigate this further next week when Yahoo has an open beta.

    -Thanks

  4. DanFebruary 24, 2008 @ 08:17 PM

    Great job…I didn’t want to start a project with openid unless I could get openid 2.0 to work and this is just what I needed.

  5. MaxFebruary 28, 2008 @ 07:32 PM

    If you have a space before or after the openid url inside the login box, it craps out. Spaces need to be “strip”ed out.

  6. JesseMarch 05, 2008 @ 03:08 PM

    Has anyobdy figured anything else out about yahoo openid and ruby-openid? I implemented the 2.0 patched plugin on our system and both Yahoo and Flickr openid fails.

  7. faceMarch 05, 2008 @ 04:54 PM

    I have gotten the signin part to work, but not simple registration attribute exchange.

    You are most likely running into the extra security hoops Yahoo makes you run through. For example, localhost:3000 will not work while http://myutil.com/ will work. This is from the Yahoo OpenID developers FAQ:

    Yahoo! Security Policies Yahoo! will only support Relying Parties running on webservers with real hostnames (IP addresses are not supported) running on standard ports (Port 80 for HTTP and Port 443 for HTTPS).

    -face

  8. JesseMarch 05, 2008 @ 05:14 PM

    Yeah. I figured that out shortly after I commented earlier. Now I am running into a problem with normalize_url throwing an exception:

    {{{ OpenIdAuthentication::InvalidOpenId (bad URI: http://): /vendor/plugins/open_id_authentication/lib/open_id_authentication.rb:69:in `normalize_url’ /vendor/plugins/open_id_authentication/lib/open_id_authentication.rb:74:in `normalize_url’ /vendor/plugins/open_id_authentication/lib/open_id_authentication.rb:85:in `authenticate_with_open_id’ /app/helpers/open_ids_helper.rb:7:in `open_id_authentication’ }}}

    The redirect to yahoo still completes so I am not real sure what is going on here.

    I can’t reproduce the problem from the console either. Wrapping the two calls to URI.parse in begin/rescue blocks it seems that the exception is being thrown from line 65:

    {{{ uri = URI.parse(“http://#{uri}”) unless uri.scheme }}}

  9. JesseMarch 05, 2008 @ 06:34 PM

    Ok, so after digging through my logs and adding some debug statements, it looks like the Yahoo OpenId API is calling the return_to url with an HTTP GET and no parameters as it processes the initial request. So, since there are no params, :open_id_complete isn’t set so begin_open_id_authentication and normalize_url get called with a null identity_url which causes an error in normalize_url at line 65.

    I’m adding:

    return if identity_url.blank?

    as the first line in authenticate_with_open_id.

    I’ll blog this and submit a patch to the plugin tomorrow.

    You also might need to handle OpenIdsHelper#open_id_authentication returning false.

  10. faceMarch 05, 2008 @ 08:28 PM

    Thanks Jesse. The algorithm should tack on open_id_complete=1 to your return URL before it goes out to Yahoo.

    begin_open_id_authentication calls open_id_redirect_url which tacks on open_id_request.return_to_args[‘open_id_complete’] = ‘1’.

    So, as your return URL already has the open_id_completed = 1, you should get it back from Yahoo.

    At least this is what happens in Dr. Nicks example that I ported to OpenID 2 (attached)...

    Hope this helps, -face

  11. JesseMarch 06, 2008 @ 10:19 AM

    It does tack the open_id_complete param on when it redirects AFTER openid authentication completes. What I’m saying is that Yahoo pings the return_to url once BEFORE authenticating without ANY parameters. No identity_url, no open_id_complete no nothing. This was leading to the bug I described in my previous comment.

    -jesse

  12. faceMarch 06, 2008 @ 03:54 PM

    Thanks for clarifying…..You are correct. I missed this because Yahoo pings my root index, which doesn’t require authentication and hence doesn’t trigger an exception for me.

    Where you get an exception, I get something like:
    Processing HomeController#index (for 66.163.170.96 at 2008-03-05 20:34:43) [GET]
      Session ID: c0a67849109f1b58b76b4c5e3e17f009
      Parameters: {"action"=>"index", "controller"=>"home"}
    Rendering template within layouts/application
    Rendering home/index
    Completed in 0.00410 (243 reqs/sec) | Rendering: 0.00200 (48%) | DB: 0.00000 (0%) | 200 OK [http://myutil.com/]
    

    Thanks again Jesse,

    -face

  13. yuMarch 24, 2008 @ 08:29 PM

    hi,

    i left my project before rails 2 was released, when i tried to make it work again under rails 2.0 i got stuck at this OpenID bit.

    i had rails 2.0.2 and openid gem 2.0.4 installed, when i tried to run your example app, i’ve got this on the console, is there anything that i missed? thanks.

    c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:263:in `load_missing_constant’: uninitialized constant OpenID::OpenIDError (NameError) from c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:453:in `const_missing’ from c:/ruby/lib/ruby/gems/1.8/gems/ruby-openid-2.0.4/lib/openid/protocolerror.rb:6 from c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require’ from c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require’ from c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:496:in `require’ from c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:342:in `new_constants_in’ from c:/ruby/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/dependencies.rb:496:in `require’ from c:/ruby/lib/ruby/gems/1.8/gems/ruby-openid-2.0.4/lib/openid/consumer/idres.rb:2 ... 43 levels… from c:/ruby/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require’ from ./script/server:3 from -e:2:in `load’ from -e:2

  14. LiMarch 28, 2008 @ 01:42 AM

    The year on security updates is incorrect, should be Security Update: January 4th, 2008 instead of Security Update: January 4th, 2007

  15. Noah (angelbob)June 20, 2008 @ 03:40 PM

    I’m putting together a rails project based on your code, and a minor bug bit me. Thought I’d share it :-)

    In the test data, user “quentin” has both an activation_code and an activated_at field. The code in /app/models/user.rb assumes that a user has either one or the other, but not both. You could fix this assumption in user.rb by changing the function “activated?” to use the activated_at field instead of the activation_code field. Or you could fix user “quentin” to only have “activated_at” (and maybe make a new test user who isn’t activated?). Or both.

  16. Noah (angelbob)June 20, 2008 @ 04:34 PM

    Hm. Or you can just remove the activation code from the “quentin” test data. So maybe the simple solution will work just fine :-)

  17. Noah (angelbob)June 20, 2008 @ 06:12 PM

    Also: local site users, the ones who just create an account, require activation to log in. While the activation code stuff is mostly there, it looks like config/routes.rb doesn’t bother to install the necessary route to make it work. The route should look like:

    map.connect ‘activate/:activation_code’, :controller => “users”, :action => “activate”

    I don’t have email set up properly on my machine, but if I pull the activation code out of the database and use the URL the email should send, this works for me.

  18. Noah (angelbob)June 22, 2008 @ 03:05 PM

    And in case anybody is also using this code and still reading comments… The UserObserver class needs to be registered in config/environment.rb for the registration code to work, and the registration code needs to work for site accounts to work beyond the initial login. There’s a line to register it there already, but it’s commented out.

  19. snowmaninthesunJune 23, 2008 @ 05:14 PM

    downloaded the code, i have rails 2.0.2 when i “gem list” i see i have “ruby-openid (2.0.4)” yet when i try to start the server running your code compliation i get ”`require’: no such file to load—openid/extensions/sreg (MissingSourceFile)” while my console also tells me to “Install the ruby-openid gem to enable OpenID support”. I can CD to the folder and see the file it claims i’m missing. Could there be a broken path or link somewhere or a way i can point my application to the correct folder??

  20. Li Chu ChengDecember 05, 2008 @ 07:11 AM

    multi-OpenID is not working anymore after I upgrade to Rails 2.2.2. It was working still at Rails 2.1. Something about the relative_url_root being deprecated after 2.1. Anyone has any solutions? I googled for a night but couldn’t find one.

Comment

Hint: Comments now accept textile.