Picnic::Authentication::Cas provides basic CAS (Central Authentication System) authentication for your Camping app.
To learn more about CAS, see rubycas-client.googlecode.com and www.ja-sig.org/products/cas.
The module defines a service
method that intercepts every
request to check for CAS authentication. If the user has already been
authenticated, the request proceeds as normal and the authenticated user's
username is made available under <tt>@state. Otherwise the request is
redirected to your CAS server for authentication.
To activate CAS authentication for your application:
Picnic-fy your Camping app (e.g: Camping.goes :your_app;
YourApp.picnic!
)
Call YourApp.authenticate_using :cas
.
In your app's configuration YAML file add something like this:
authentication: cas_base_url: https://login.example.com/cas
Where the value for </tt>cas_base_url</tt> is the URL of your CAS server.
That's it. Now whenever a user tries to access any of your controller's actions, the request will be checked for CAS authentication. If the user is authenticated, their username is availabe in @state. Note that there is currently no way to apply CAS authentication only to certain controllers or actions. When enabled, CAS authentication applies to your entire application, except for items placed in the /public subdirectory (CSS files, JavaScripts, images, etc.). The public directory does not require CAS authentication, so anyone can access its contents.
For some reason the Module#included callback is just not working for me, so I had to resort to overriding ::append_features(). If anyone has any ideas why, please let me know!
# File lib/picnic/authentication.rb, line 152 def self.append_features(mod) super require 'camping/db' require 'camping/session' $: << File.dirname(File.expand_path(__FILE__))+"/../../../rubycas-client2/lib" # for development require 'rubycas-client' end
# File lib/picnic/authentication.rb, line 191 def self.included(mod) mod.module_eval do include Cas::Session end end
# File lib/picnic/authentication.rb, line 197 def service(*a) $LOG.debug "Running CAS filter for request #{a.inspect}..." if @env['PATH_INFO'] =~ %r^\/public\/.*/ $LOG.debug "Access to items in /public subdirectory does not require CAS authentication." return super(*a) end if @state[:cas_username] $LOG.debug "Local CAS session exists for user #{@state[:cas_username]}." return super(*a) end client = CASClient::Client.new($CONF[:authentication].merge(:logger => $LOG)) ticket = @input[:ticket] cas_login_url = client.add_service_to_login_url(read_service_url(@env)) if ticket if ticket =~ %r^PT-/ st = CASClient::ProxyTicket.new(ticket, read_service_url(@env), @input[:renew]) else st = CASClient::ServiceTicket.new(ticket, read_service_url(@env), @input[:renew]) end $LOG.debug "Got CAS ticket: #{st.inspect}" client.validate_service_ticket(st) if st.is_valid? $LOG.info "CAS ticket #{st.ticket.inspect} is valid. Opening local CAS session for user #{st.response.user.inspect}." @state[:cas_username] = st.response.user return super(*a) else $LOG.warn "CAS ticket #{st.ticket.inspect} is INVALID. Redirecting back to CAS server at #{cas_login_url.inspect} for authentication." @state[:cas_username] = nil redirect cas_login_url s = self end else $LOG.info "User is unauthenticated and no CAS ticket found. Redirecting to CAS server at #{cas_login_url.inspect} for authentication." @state[:cas_username] = nil redirect cas_login_url s = self end s end