Skip to content

Commit

Permalink
Add shibboleth single sign on
Browse files Browse the repository at this point in the history
  • Loading branch information
rawOrlando committed Aug 6, 2024
1 parent f1d32cc commit 4860293
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 12 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ gem 'jbuilder', '~> 2.5'
# gem 'redis', '~> 4.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'
gem 'omniauth', '1.9.1'
gem 'omniauth-shibboleth'

# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development
Expand Down
8 changes: 8 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ GEM
tilt
hamster (3.0.0)
concurrent-ruby (~> 1.0)
hashie (5.0.0)
hiredis (0.6.3)
htmlentities (4.3.4)
http_logger (0.6.0)
Expand Down Expand Up @@ -592,6 +593,11 @@ GEM
multi_xml (~> 0.5)
rack (>= 1.2, < 3)
okcomputer (1.18.4)
omniauth (1.9.1)
hashie (>= 3.4.6)
rack (>= 1.6.2, < 3)
omniauth-shibboleth (1.3.0)
omniauth (>= 1.0.0)
open4 (1.3.4)
openseadragon (0.6.0)
rails (> 3.2.0)
Expand Down Expand Up @@ -911,6 +917,8 @@ DEPENDENCIES
mimemagic (= 0.3.10)
mysql2
okcomputer
omniauth (= 1.9.1)
omniauth-shibboleth
pretender
puma (~> 4.3)
rails (~> 5.2)
Expand Down
12 changes: 12 additions & 0 deletions app/controllers/omniauth_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

# frozen_string_literal: true
class OmniauthController < Devise::SessionsController
def new
Rails.logger.debug "SessionsController#new: request.referer = #{request.referer}"
if Rails.env.production? || Rails.env.stage?
redirect_to user_shibboleth_omniauth_authorize_path
else
super
end
end
end
45 changes: 45 additions & 0 deletions app/controllers/omniauthcallbacks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# frozen_string_literal: true
class OmniauthcallbacksController < Devise::OmniauthCallbacksController
# handle omniauth logins from shibboleth
def shibboleth
# auth_headers = %w(HTTP_AFFILIATION HTTP_AUTH_TYPE HTTP_COOKIE HTTP_HOST
# HTTP_PERSISTENT_ID HTTP_EPPN HTTP_REMOTE_USER HTTP_SHIB_APPLICATION_ID
# HTTP_SHIB_AUTHENTICATION_INSTANT HTTP_SHIB_AUTHENTICATION_METHOD
# HTTP_SHIB_AUTHNCONTEXT_CLASS HTTP_SHIB_HANDLER HTTP_SHIB_IDENTITY_PROVIDER
# HTTP_SHIB_SESSION_ID HTTP_SHIB_SESSION_INDEX HTTP_UNSCOPED_AFFILIATION)
#
auth_headers = {
uid: 'uid',
shib_session_id: 'Shib-Session-ID',
shib_application_id: 'Shib-Application-ID',
provider: 'Shib-Identity-Provider',
name: 'displayName',
mail: 'mail'
}
auth = {}
# Rails.logger.warn "request = #{request.env.inspect}"
auth_headers.each do |k, v|
auth[k] = request.env[v]
end
# Rails.logger.warn "request2 = #{auth.inspect}"
# if auth.fetch('unscoped_affiliation', nil)
# auth['affiliation'] = auth['unscoped_affiliation'].split(';').map(&:strip)
# end
auth.delete_if { |_k, v| v.blank? }
@user = User.from_omniauth(auth)
# capture data about the user from shib
# session['shib_user_data'] = auth
# sign_in_and_redirect @user, event: :authentication
set_flash_message :notice, :success, kind: "Shibboleth"
# logger.warn "auth_type :: #{current_user.inspect}"
# logger.warn "#{request.env["omniauth.auth"]}"
sign_in_and_redirect @user
end

## when shib login fails
def failure
## redirect them to the devise local login page
# redirect_to new_local_user_session_path, :notice => "Shibboleth isn't available - local login only"
redirect_to root_path, notice: "Shibboleth isn't available - local login only"
end
end
22 changes: 21 additions & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ class User < ApplicationRecord
include Blacklight::User
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :ldap_authenticatable, :rememberable, :validatable
if Rails.env.development? || Rails.env.test?
devise :ldap_authenticatable, :rememberable, :validatable
else
devise_modules = [:omniauthable, :rememberable, :trackable, omniauth_providers: [:shibboleth]]
##devise_modules.prepend(:database_authenticatable) if AuthConfig.use_database_auth?
devise(*devise_modules)
end

# Method added by Blacklight; Blacklight uses #to_s on your
# user class to get a user-displayable login/identifier for
Expand Down Expand Up @@ -51,6 +57,20 @@ def ldap_before_save
self.email = Devise::LDAP::Adapter.get_ldap_param(username, "mail").first
self.display_name = Devise::LDAP::Adapter.get_ldap_param(username, "tuftsEduDisplayNameLF").first
end

# allow omniauth (including shibboleth) logins
# this will create a local user based on an omniauth/shib login
# if they haven't logged in before
def self.from_omniauth(auth)
Rails.logger.warn "auth = #{auth.inspect}"
# Uncomment the debugger above to capture what a shib auth object looks like for testing
user = where(username: auth[:uid]).first_or_create
user.display_name = auth[:name]
user.username = auth[:uid]
user.email = auth[:mail]
user.save
user
end
end


Expand Down
32 changes: 22 additions & 10 deletions config/initializers/devise.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
# frozen_string_literal: true
require "omniauth-shibboleth"

# Use this hook to configure devise mailer, warden hooks and so forth.
# Many of these configuration options can be set straight in your model.
Devise.setup do |config|
# ==> LDAP Configuration
config.ldap_logger = true
config.ldap_create_user = true
# config.ldap_update_password = true
config.ldap_config = Rails.root.join('config', 'ldap.yml')
# config.ldap_check_group_membership = false
# config.ldap_check_group_membership_without_admin = false
# config.ldap_check_attributes = false
# config.ldap_check_attributes_presence = false
config.ldap_use_admin_to_bind = false
# config.ldap_ad_group_check = false
if Rails.env.development? || Rails.env.test?
config.ldap_logger = true
config.ldap_create_user = true
# config.ldap_update_password = true
config.ldap_config = Rails.root.join('config', 'ldap.yml')
# config.ldap_check_group_membership = false
# config.ldap_check_group_membership_without_admin = false
# config.ldap_check_attributes = false
# config.ldap_check_attributes_presence = false
config.ldap_use_admin_to_bind = false
# config.ldap_ad_group_check = false
end

# The secret key used by Devise. Devise uses this key to generate
# random tokens. Changing this key will render invalid all existing
Expand Down Expand Up @@ -312,4 +315,13 @@
# When set to false, does not sign a user in automatically after their password is
# changed. Defaults to true, so a user is signed in automatically after changing a password.
# config.sign_in_after_change_password = true

if Rails.env.production? || Rails.env.stage?
config.omniauth :shibboleth, {
uid_field: 'uid',
info_fields: { display_name: 'displayName', uid: 'uid', mail: 'mail' },
callback_url: '/users/auth/shibboleth/callback',
strategy_class: OmniAuth::Strategies::Shibboleth
}
end
end
12 changes: 11 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,17 @@
concerns :range_searchable
end

devise_for :users
if Rails.env.production? || Rails.env.stage?
devise_for :users, controllers: { omniauth_callbacks: "omniauthcallbacks" }, skip: [:sessions]
devise_scope :user do
post 'sign_in', to: 'omniauth#new', as: :new_user_session
post 'sign_in', to: 'omniauth_callbacks#shibboleth', as: :new_session
get 'sign_out', to: 'devise/sessions#destroy', as: :destroy_user_session
end
else
devise_for :users
end

mount Hydra::RoleManagement::Engine => '/'

mount Qa::Engine => '/authorities'
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20240806194048_add_column_to_users.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddColumnToUsers < ActiveRecord::Migration[5.2]
def change
add_column :users, :provider, :string
end
end

0 comments on commit 4860293

Please sign in to comment.