xmlrpc authentication

Hi all,

  what is the recommended way to do user authentication for
xmlrpc ruby on rails webservices?

Thanks,
  -Armin

Use http authentication. Put this into lib/http_authentication.rb:

# From http://wiki.rubyonrails.com/rails/pages/HowtoAuthenticateWithHTTP with a few
# minor fixes.

module HttpAuthentication

  protected

  def http_authenticate(realm=@request.host + ' Web Password', errormessage="Couldn't authenticate you")
    username, passwd = get_http_authentication_data
    # Check authorization
    unless username
      send_http_authentication_response(realm, errormessage) and return
    end
    user = User.authenticate(username, passwd)
    unless user && user.isremote?
      logger.info("sending auth response");
      send_http_authentication_response(realm, errormessage) and return
    end
    # No session, so make this a class variable
    @user = user
  end

  private

  def send_http_authentication_response(realm, errormessage)
    response.headers["Status"] = "Unauthorized"
    response.headers["WWW-Authenticate"] = "Basic realm=\"#{realm}\""
    render :text => errormessage, :status => 401
  end

  def get_http_authentication_data
    user, pass = '', ''
    # extract authorisation credentials
    if request.env.has_key? 'X-HTTP_AUTHORIZATION'
      # try to get it where mod_rewrite might have put it
      authdata = request.env['X-HTTP_AUTHORIZATION'].to_s.split
    elsif request.env.has_key? 'Authorization'
      # for Apace/mod_fastcgi with -pass-header Authorization
      authdata = request.env['Authorization'].to_s.split
    elsif request.env.has_key? 'HTTP_AUTHORIZATION'
      # this is the regular location
      authdata = request.env['HTTP_AUTHORIZATION'].to_s.split
    elsif request.env.has_key? 'Authorization'
      # this is the regular location, for Apache 2
      authdata = @request.env['Authorization'].to_s.split
    end

    # at the moment we only support basic authentication
    if authdata and authdata[0] == 'Basic'
      user, pass = Base64.decode64(authdata[1]).split(':')[0..1]
    end
    return [user, pass]
  end

end

Then in the controller for your web service:

require_dependency "http_authentication"

class RemoteController < ApplicationController
  include HttpAuthentication
  wsdl_service_name 'Remote'
  web_service_api 'Remote'
  before_filter :http_authenticate
  session :off
....
end

The only thing you probably need to worry about is the
"user = User.authenticate..." part in the http_authenticate method. I
use my regular user table, but with a type of "Remote". Then only
those remote users may be used to get to web services, and non-remote
users may not be used.

Michael