Cross-site auto login using auth_source

Added by Darren Cook over 8 years ago

Hi,
The requirement I am trying to meet for my project is:
"When users click the link to the [Redmine] site from our website, they should be automatically authenticated in [Redmine] using their existing user name from our site. If they don't have a [Redmine] account yet, one should be created with the right permissions."

I have never touched Ruby or Rails before so this is all new ground for me. We also have no single-sign-on or other options

I found this page: http://www.redmine.org/projects/redmine/wiki/Alternativecustom_authentication_HowTo
...and various other examples on the web (I am authenticating against a webservice instead of a database) so this seemed feasible. I began writing my own auth_source module and at least got it to authenticate against my webservice.

The code I have come up with so far is:

require 'net/http'

class AuthSourceSkutrainApp < AuthSource
  def authenticate(login, password)
    return nil if login.blank? || password.blank?

    result = Net::HTTP.get(URI.parse( "http://www.mycompanysite.com/auth/?loginid=" + login + "&pwd=" + password ))
    return nil if result.nil? || result.empty?

    user = ActiveSupport::JSON.decode( result )
    return nil if user.blank?

    retVal = {    :firstname => user["FIRSTNAME"],
                :lastname => user["LASTNAME"],
                :mail => user["EMAIL"],
                :auth_source_id => self.id
             } if(onthefly_register?)
    return retVal
  end

  def auth_method_name
    "MyApp" 
  end
end

Where I'm running into trouble is authenticating from my site. I have been trying an automatic form post to Redmine as a test, mimicking the login screen:

<body onLoad="document.autoLogin.submit()">
    <form id="autoLogin" name="autoLogin" method="POST" action="http://redmine.mycompanysite.com/login" style="display:none;">
        <input name="username" value="testuser" />
        <input name="password" value="C95F044AF8124AEA27FAD3C86D51EF39" /><!--- 1-time use UUID --->
        <input name="authurl" value="http://www.mycompanysite.com/auth?" />
        <input name="role" value="Admin">
    </form>
</body>


(The password as you see is a 1-time use UUID, which www.mycompanysite.com creates and associates to the user before generating the form. The authurl webservice destroys the UUID and returns user data if the login ID & UUID match. This way I can authenticate without sending the password across the network).

So my AuthSource model works, and a new user account is created....but then an error occurs in Redmine and the user is not logged in. (If I submit a pre-existing user's info, I get the same error). The error is:
Processing AccountController#login (for [myIP] at 2011-11-01 14:37:55) [POST]
Parameters: {"action"=>"login", "username"=>"testuser", "authurl"=>"http://www.mycompanysite.com/auth?", "controller"=>"account", "password"=>"[FILTERED]"}

NoMethodError (undefined method `destroy' for {}:Hash):
app/controllers/application_controller.rb:92:in `logged_user='
app/controllers/account_controller.rb:203:in `successful_authentication'
app/controllers/account_controller.rb:155:in `password_authentication'
app/controllers/account_controller.rb:142:in `authenticate_user'
app/controllers/account_controller.rb:30:in `login'
passenger (2.2.14) lib/phusion_passenger/rack/request_handler.rb:92:in `process_request'
passenger (2.2.14) lib/phusion_passenger/abstract_request_handler.rb:207:in `main_loop'
passenger (2.2.14) lib/phusion_passenger/railz/application_spawner.rb:441:in `start_request_handler'
passenger (2.2.14) lib/phusion_passenger/railz/application_spawner.rb:381:in `handle_spawn_application'
passenger (2.2.14) lib/phusion_passenger/utils.rb:252:in `safe_fork'
passenger (2.2.14) lib/phusion_passenger/railz/application_spawner.rb:377:in `handle_spawn_application'
passenger (2.2.14) lib/phusion_passenger/abstract_server.rb:352:in `__send__'
passenger (2.2.14) lib/phusion_passenger/abstract_server.rb:352:in `main_loop'
passenger (2.2.14) lib/phusion_passenger/abstract_server.rb:196:in `start_synchronously'
passenger (2.2.14) lib/phusion_passenger/abstract_server.rb:163:in `start'
passenger (2.2.14) lib/phusion_passenger/railz/application_spawner.rb:222:in `start'
passenger (2.2.14) lib/phusion_passenger/spawn_manager.rb:262:in `spawn_rails_application'
passenger (2.2.14) lib/phusion_passenger/abstract_server_collection.rb:126:in `lookup_or_add'
passenger (2.2.14) lib/phusion_passenger/spawn_manager.rb:256:in `spawn_rails_application'
passenger (2.2.14) lib/phusion_passenger/abstract_server_collection.rb:80:in `synchronize'
passenger (2.2.14) lib/phusion_passenger/abstract_server_collection.rb:79:in `synchronize'
passenger (2.2.14) lib/phusion_passenger/spawn_manager.rb:255:in `spawn_rails_application'
passenger (2.2.14) lib/phusion_passenger/spawn_manager.rb:154:in `spawn_application'
passenger (2.2.14) lib/phusion_passenger/spawn_manager.rb:287:in `handle_spawn_application'
passenger (2.2.14) lib/phusion_passenger/abstract_server.rb:352:in `__send__'
passenger (2.2.14) lib/phusion_passenger/abstract_server.rb:352:in `main_loop'
passenger (2.2.14) lib/phusion_passenger/abstract_server.rb:196:in `start_synchronously'

The only difference as I can figure it is when I use the Redmine login screen manually, I have a session ID from Redmine. But when I post my own form from a different subdomain, I don't. Maybe this error is an attempt to prevent cross-site scripting on the part of Rails...

Any advice or suggestions at this point would be appreciated. I'm not sure what to try next or if there is another method to this madness that I should be using....

I've been tackling this on and off for a few days but now I am up against my deadline and need to solve in the next day or two...please help if you can!

$ RAILS_ENV=production script/about
About your application's environment
Ruby version 1.8.7 (i686-linux)
RubyGems version 1.3.7
Rack version 1.1
Rails version 2.3.11
Active Record version 2.3.11
Active Resource version 2.3.11
Action Mailer version 2.3.11
Active Support version 2.3.11
Edge Rails revision unknown
Application root /var/www/railsapp
Environment production
Database adapter mysql
Database schema version 20110511000000

About your Redmine plugins
Redmine CKEditor plugin 0.0.6
Redmine Backlogs master branch (unstable)
HTTP Authentication plugin 0.3.0-dev
Redmine Favicon plugin 0.1
Redmine Attach Screenshot plugin 0.1.0
Redmine Light Box plugin 0.0.1

Replies (1)

RE: Cross-site auto login using auth_source - Added by Sam G about 8 years ago

I'm having the same issue and am also a bit of a noob. But I think I found the problem.

Open app/controllers/account_controller.rb

After this line:
skip_before_filter :check_if_login_required

Add:
skip_before_filter :verify_authenticity_token

This will skip the token verification

(1-1/1)