Implementing Shibboleth login in Rails application

Further to the basic configuration to make Shibboleth working with Apache 2, it’s time to configure Rails application with Shibboleth. You may want to get Phusion Passenger working first, here is the tutorial: Setting up Phusion Passenger with Apache2.

Rails

0) Environements

Ubuntu: 16
Apache: 2.4.7
Ruby: 2.3.1
Phusion Passenger: 5.1.5
Shibboleth: 2.5.2

1) Configure Apache2

First, edit /etc/apache2/sites-enabled/default-ssl.conf and add:

1
2
3
4
<Location "/Shibboleth.sso">
Require all granted
PassengerEnabled off
</Location>

and

1
2
3
4
5
<Location "/users/auth/shibboleth">
AuthType shibboleth
ShibRequestSetting requireSession 1
require valid-user
</Location>

You may want to comment out the following line in /etc/apache2/apache2.conf, otherwise, you have to grant acess to each individual path.

1
2
3
4
5
#<Directory />
# Options FollowSymLinks
# AllowOverride None
# Require all denied
#</Directory>

2) Configure/develop Rails application to support Shibooleth

2.1) Add gem ‘omniauth-shibboleth’ into Gemfile and run

1
bundle install

2.2) Edit config/initializers/devise.rb:

1
2
3
4
5
config.omniauth :shibboleth, {:uid_field => 'eppn',
:info_fields => {
:affiliation => lambda {|request_param| request_param.call('unscoped-affiliation').split(';')},
},
}

2.3) Edit app/models/user.rb

Add method:

1
2
3
4
5
6
7
8
def self.from_omniauth(auth)
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.provider = auth.provider
user.uid = auth.uid
user.email = auth.uid
user.password = Devise.friendly_token[0,20]
end
end

Also add :omniauthable to declaration in user.rb

2.4) Add a controller, e.g. app/controllers/omniauthcallbacks_controller.rb

1
2
3
4
5
6
7
8
9
10
11
class OmniauthcallbacksController < Devise::OmniauthCallbacksController
def shibboleth
@user = User.from_omniauth(request.env["omniauth.auth"])
session['shib_user_data'] = request.env["omniauth.auth"]
sign_in_and_redirect @user
end
def failure
redirect_to new_local_user_session_path, :notice => "Cannot login via Shibboleth - redirect to local login ..."
end
end

2.5) edit config/routes.rb

1
devise_for :users, :controllers => { :omniauth_callbacks => "omniauthcallbacks" }, :skip => [:sessions]

Run:

1
2
rails g migration AddColumnsToUsers provider uid
rake db:migrate

2.6) edit routes.rb and add:

1
2
3
4
5
6
devise_scope :user do
match "/users/auth/shibboleth" => "omniauth_callbacks#passthru", as: "new_user_session", via: [:get]
match "/users/sign_in" => "devise/sessions#new", as: "new_local_user_session", via: [:get]
match "/users/sign_in" => "devise/sessions#create", as: "user_session", via: [:post]
match "/users/sign_out" => "devise/sessions#destroy", as: "destroy_user_session", via: [:get]
end
Share