Kraut

Interface for the Atlassian Crowd SOAP service.

Crowd endpoint

Kraut needs to know the SOAP endpoint of your Crowd installation. Set it via:

Kraut.endpoint = "http://example.com/crowd/services/SecurityServer"

Kraut::Application

Crowd manages principals and applications. Kraut::Application obviously represents the latter. To authenticate your application with Crowd, you need to provide its name and password:

Kraut::Application.authenticate "my_app", "secret"

After being authenticated, you can access the following attributes:

Kraut::Application.name     => "my_app"
Kraut::Application.password => "secret"
Kraut::Application.token    => "Dem7p7Ns97uRV92so4IE1h10"

Kraut stores the time of the latest authentication:

Kraut::Application.authenticated_at  # => Mon Jan 10 16:35:58 +0100 2011

To check whether the application needs to (re-)authenticate itself, you can use the following method:

Kraut::Application.authentication_required?(timeout = 10)  # defaults to 10 minutes

Kraut::Principal

Represents a Crowd principal. To authenticate a principal:

Kraut::Principal.authenticate "user", "password"

The .authenticate method returns a Kraut::Principal instance with basic attributes:

  • #name => "user"
  • #password => "password"
  • #token => "3p7Xs3dIuTVb2pO4II1h8A"

It also contains the following attributes:

  • #display_name => "Chuck Norris"
  • #email => "[email protected]"
  • #attributes => { :display_name => "Chuck Norris", ... }

Make sure to verify whether a principal's password is expired. Principal's with an expired password are still able to authenticate and access your application.

Kraut::Principal.requires_password_change?

Groups

To verify whether a principal belongs to a certain group:

Kraut::Principal#member_of?(group)

Kraut stores all positive and negative group-requests in a Hash:

Kraut::Principal#groups => { "staff" => true, "supervisor" => false }

Login

In order to provide easy login to your apps, just require 'kraut/rails/engine' instead of just 'kraut':

gem "kraut", :require => "kraut/rails/engine"

Then, you'll have a login controller unter '/sessions/new'. To configure its behaviour, add it in 'config/initializers/kraut.rb':

Kraut.endpoint = AppConfig.webservices.crowd.baseaddress
# the layout to use for the login page
Kraut::Rails::Engine.config.layout = "application"
# hash containing user and password for authenticatin the crowd app
Kraut::Rails::Engine.config.webservice = AppConfig.webservices.crowd
# hash containing :action => [crowd_group1, crowd_group2] pairs
Kraut::Rails::Engine.config.authorizations = AppConfig.authorizations
# starting url after authentication
Kraut::Rails::Engine.config.entry_url = "/"

In your controllers, you have three methods to use as before_filter:

  • check_for_crowd_token => checks for params[:crowd_token] and logs in with that token
  • verify_login => checks whether a user is logged in and redirects to the login page if necessary
  • verify_access => checks whether the logged in user has access to the current action

verify_access uses the Kraut::Rails::Engine.config.authorizations hash. It checks for controller-action actions (eg :orders_show). If a controller action protected by verify_access isn't listed there, no one can access this action!

In your controllers and views, you can access user specific methods:

  • logged_in? => checks whether someone is logged in
  • user => returns the currently logged in user (or nil)
  • allowed_to? => checks whether someone is logged in and this user has access to the given action (see Kraut::Rails::Engine.config.authorizations above)

Testing authentication/authorization behaviour

In your spec_helper.rb:

require "kraut/rails/spec_helper"

Then you have in all your specs:

  • create_user => creates a new user to spec against

And in your controller/view/helper specs:

  • login! => log in with a newly created user
  • logout! => log out again
  • user => user you're logged in with

And finally in your controller specs:

  • describe_protected_action => tests an action protected by verify_login/verify_access

Example:

describe_protected_action "GET :show", :orders_index do
  unauthorized_request { get :show, :id => "5" }

  before do
    @order = Order.create
  end

  it "should be successful" do
    get :index, :id => @order.id
    response.should be_success
    assigns(:order).should == @order
  end
end

This runs three tests:

  • the test written in the block above that checks whether the response is a success when logged with a user allowed to do :orders_index
  • an automatically generated test that checks that you're redirected to the login page when logged in with a user not allowed to do :orders_index
  • an automatically generated test that checks that you're redirected to the login page when not logged in

If you leave out the action parameter (:orders_index in the example), the first test only checks with a logged in user and the second test is omitted.

If you leave out the unauthorized_request, the second and third test are omitted and only the successful tests are executed.

unauthorized_request is run outside the scope of the describe_protected_action block, so you can't access stuff initialized within it's before block (eg the @order above).