Skip to content

Commit a051638

Browse files
authored
Merge pull request #98 from emory-libraries/shib
Adds initial shib config
2 parents 1b0b160 + 29f68c3 commit a051638

13 files changed

Lines changed: 264 additions & 7 deletions

File tree

.circleci/config.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ jobs:
1111
- FEDORA_URL=http://localhost:8080/fcrepo/rest
1212
- FEDORA_TIMEOUT=300
1313
- RAILS_ENV=test
14+
- DATABASE_AUTH=true
1415
# Secondary container image on common network.
1516
- image: postgres:10-alpine
1617
environment:

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ gem 'ims-lti', '~> 1.1.13'
5959
gem 'net-ldap'
6060
gem 'omniauth-identity'
6161
gem 'omniauth-lti', git: "https://github.com/avalonmediasystem/omniauth-lti.git", tag: 'avalon-r4'
62+
gem 'omniauth-saml', '~> 1.10', '>= 1.10.3'
6263

6364
# Media Access & Transcoding
6465
gem 'active_encode', '~> 0.7.0'

Gemfile.lock

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,9 @@ GEM
582582
omniauth-identity (1.1.1)
583583
bcrypt-ruby (~> 3.0)
584584
omniauth (~> 1.0)
585+
omniauth-saml (1.10.3)
586+
omniauth (~> 1.3, >= 1.3.2)
587+
ruby-saml (~> 1.9)
585588
orm_adapter (0.5.0)
586589
os (1.0.1)
587590
parallel (1.17.0)
@@ -757,6 +760,8 @@ GEM
757760
multipart-post
758761
oauth2
759762
ruby-progressbar (1.10.0)
763+
ruby-saml (1.11.0)
764+
nokogiri (>= 1.5.10)
760765
ruby_dep (1.5.0)
761766
rubydora (1.9.1)
762767
activemodel
@@ -978,6 +983,7 @@ DEPENDENCIES
978983
noid-rails (~> 3.0.1)
979984
omniauth-identity
980985
omniauth-lti!
986+
omniauth-saml (~> 1.10, >= 1.10.3)
981987
parallel
982988
pg
983989
pry-byebug

app/controllers/users/omniauth_callbacks_controller.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,21 @@ def find_user(auth_type)
7474
end
7575
end
7676

77+
def shibboleth
78+
@user = User.from_omniauth(request.env["omniauth.auth"])
79+
80+
if @user.persisted?
81+
sign_in @user
82+
# This will help the user go back to where they came.
83+
# Refer: https://github.com/omniauth/omniauth/wiki/Saving-User-Location
84+
redirect_to request.env["omniauth.origin"] || root_url
85+
set_flash_message(:notice, :success, kind: "Shibboleth")
86+
else
87+
redirect_to root_path
88+
set_flash_message(:notice, :failure, kind: "Shibboleth", reason: "you aren't authorized to use this application.")
89+
end
90+
end
91+
7792
protected :find_user
7893

7994
rescue_from Avalon::MissingUserId do |exception|

app/models/auth_config.rb

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# frozen_string_literal: true
2+
3+
class AuthConfig
4+
# In production, we use Shibboleth for user authentication,
5+
# but in development mode, you may want to use local database
6+
# authentication instead.
7+
def self.use_database_auth?
8+
ENV['DATABASE_AUTH'] == 'true'
9+
end
10+
end

app/models/user.rb

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,8 @@ class User < ActiveRecord::Base
2626
# Include default devise modules. Others available are:
2727
# :confirmable, :lockable, :timeoutable
2828
# Registration is controlled via settings.yml
29-
devise_list = [ :database_authenticatable, :invitable, :omniauthable,
30-
:recoverable, :rememberable, :trackable, :validatable ]
31-
devise_list << :registerable if Settings.auth.registerable
32-
devise_list << { authentication_keys: [:login] }
29+
devise_list = [:omniauthable, :rememberable, :trackable, omniauth_providers: [:shibboleth], authentication_keys: [:login]]
30+
devise_list.prepend(:database_authenticatable) if AuthConfig.use_database_auth?
3331

3432
devise(*devise_list)
3533

@@ -158,6 +156,32 @@ def self.walk_ldap_groups(groups, seen)
158156
end
159157
seen
160158
end
159+
160+
# When a user authenticates via shibboleth, find their User object or make
161+
# a new one. Populate it with data we get from shibboleth.
162+
# @param [OmniAuth::AuthHash] auth
163+
def self.from_omniauth(auth)
164+
begin
165+
user = find_by!(provider: auth.provider, username: auth.uid.downcase)
166+
rescue ActiveRecord::RecordNotFound
167+
log_omniauth_error(auth)
168+
return User.new
169+
end
170+
user.assign_attributes(display_name: auth.info.display_name, ppid: auth.uid, uid: auth.info.uid)
171+
# [email protected] isn't a real email address
172+
user.email = auth.info.uid + '@emory.edu' unless auth.info.uid == 'tezprox'
173+
user.save
174+
user
175+
end
176+
177+
def self.log_omniauth_error(auth)
178+
if auth.info.uid.empty?
179+
Rails.logger.error "Nil user detected: Shibboleth didn't pass a uid for #{auth.inspect}"
180+
else
181+
# Log unauthorized logins to error.
182+
Rails.logger.error "Unauthorized user attemped login: #{auth.inspect}"
183+
end
184+
end
161185
end
162186

163187
class Avalon::MissingUserId < StandardError; end

config/environments/production.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,20 @@
115115

116116
# Additional production specific initializers
117117
Dir["config/environments/production/*.rb"].each {|file| load file }
118+
119+
# OmniAuth configuration settings
120+
config.idp_slo_target_url = ENV['IDP_SLO_TARGET_URL']
121+
config.assertion_consumer_service_url = ENV['ASSERTION_CS_URL']
122+
config.assertion_consumer_logout_service_url = ENV['ASSERTION_LOGOUT_URL']
123+
config.issuer = ENV['ISSUER']
124+
config.idp_sso_target_url = ENV['IDP_SSO_TARGET_URL']
125+
config.idp_cert = ENV['IDP_CERT']
126+
config.certificate = ENV['SP_CERT']
127+
config.private_key = ENV['SP_KEY']
128+
config.attribute_statements = {}
129+
config.uid_attribute = "urn:oid:0.9.2342.19200300.100.1.1"
130+
config.security = {
131+
:want_assertions_encrypted => true, #makes a 2nd KeyDescriptor, this one says use="encryption"
132+
:want_assertions_signed => true, # goes on md SPSSODescriptor tag
133+
}
118134
end

config/initializers/omniauth.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Rails.application.config.middleware.use OmniAuth::Builder do
2+
if !Rails.env.development? && !Rails.env.test?
3+
provider :shibboleth,
4+
:assertion_consumer_service_url => Rails.application.config.assertion_consumer_service_url,
5+
:assertion_consumer_logout_service_url => Rails.application.config.assertion_consumer_logout_service_url,
6+
:issuer => Rails.application.config.issuer,
7+
:idp_sso_target_url => Rails.application.config.idp_sso_target_url,
8+
:idp_slo_target_url => Rails.application.config.idp_slo_target_url,
9+
:idp_cert => Rails.application.config.idp_cert,
10+
:certificate => Rails.application.config.certificate,
11+
:private_key => Rails.application.config.private_key,
12+
:attribute_statements => Rails.application.config.attribute_statements,
13+
:uid_attribute => Rails.application.config.uid_attribute,
14+
:security => Rails.application.config.security
15+
end
16+
end
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
class AddOmniauthToUsers < ActiveRecord::Migration[5.2]
2+
def change
3+
add_column :users, :display_name, :string
4+
add_column :users, :ppid, :string
5+
end
6+
end

db/schema.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
#
1111
# It's strongly recommended that you check this file into your version control system.
1212

13-
ActiveRecord::Schema.define(version: 2019_10_16_195828) do
13+
ActiveRecord::Schema.define(version: 2020_10_20_210257) do
1414

1515
create_table "active_encode_encode_records", force: :cascade do |t|
1616
t.string "global_id"
@@ -233,6 +233,8 @@
233233
t.integer "invited_by_id"
234234
t.string "invited_by_type"
235235
t.datetime "deleted_at"
236+
t.string "display_name"
237+
t.string "ppid"
236238
t.index ["deleted_at"], name: "index_users_on_deleted_at"
237239
t.index ["email"], name: "index_users_on_email", unique: true
238240
t.index ["invitation_token"], name: "index_users_on_invitation_token", unique: true

0 commit comments

Comments
 (0)