module Picnic::Authentication::Basic

Picnic::Authentication::Basic provides Basic HTTP Authentication for your Camping app. The module defines a service method that only continues the request chain when proper credentials are provided by the client (browser).

Getting Started

To activate Basic Authentication for your application:

  1. Picnic-fy your Camping app (e.g: Camping.goes :your_app; YourApp.picnic!)

  2. Call YourApp.authenticate_using :basic.

  3. Define an authenticate method on your application module that takes a hash. The hash contains credentials like :username, :password, and :hostname, although future authentication modules may submit other credentials. The authenticate method should return true when the credentials are valid. Examples:

    module Blog
      def authenticate(credentials)
        credentials[:username] == 'admin' &&
          credentials[:password] == 'flapper30'
      end
      module_function :authenticate
    end
    

    or

    module Wiki
      def authenticate(credentials)
        u = credentials[:username]
        p = credentials[:password]
        Models::User.find_by_username_and_password u, p
      end
      module_function :authenticate
    end
    
  4. service sets @credentials to the credentials of the person who logged in.


This code is based on Camping::BasicAuth written by Manfred Stienstra (see www.fngtps.com/2006/05/basic-authentication-for-camping).

Public Instance Methods

read_credentials() click to toggle source

Reads the username and password from the headers and returns them.

# File lib/picnic/authentication.rb, line 87
def read_credentials
  if d = %w{REDIRECT_X_HTTP_AUTHORIZATION X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION}.inject([])            { |d,h| @env.has_key?(h) ? @env[h].to_s.split : d }
    u,p = ::Base64.decode64(d[1]).split(':')[0..1] if d[0] == 'Basic'
    return {:username => u, :password => p}
  end
end
service(*a) click to toggle source
# File lib/picnic/authentication.rb, line 95
def service(*a)
  app = Kernel.const_get self.class.name.gsub(%r^(\w+)::.+$/, '\1')
  unless app.respond_to? :authenticate
    raise "Basic authentication is enabled but the 'authenticate' method has not been defined."
  end
  
  @credentials = read_credentials || {}
  
  if app.authenticate(@credentials)
    s = super(*a)
  else
    @status = 401
    headers['Content-type'] = @headers['Content-type'] || 'text/plain'
    #headers['Status'] = 'Unauthorized'
    headers['WWW-Authenticate'] = "Basic realm=\"#{app}\""
    @body = 'Unauthorized'
    s = self
  end
  s
end