Skip to content

Commit

Permalink
Merge pull request #275 from NYULibraries/mcain/shibboleth-omniauth
Browse files Browse the repository at this point in the history
Integrate Shibboleth SSO
  • Loading branch information
the-codetrane authored Aug 7, 2023
2 parents 620d4b9 + 6e9c6ef commit 511aeaa
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 137 deletions.
2 changes: 2 additions & 0 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
ruby 2.7.8
nodejs 18.10.0
3 changes: 2 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ gem 'jbuilder'
gem 'jquery-rails'
gem 'mimemagic', github: 'mimemagicrb/mimemagic', ref: '01f92d86d15d85cfd0f20dabd025dcbd36a8a60f'
gem 'mysql2'
gem 'omniauth-nyulibraries', git: 'https://github.com/NYULibraries/omniauth-nyulibraries', branch: 'v2.2.0'
gem 'omniauth'
gem 'omniauth-oauth2'
gem 'rails'
gem 'rainbow'
gem 'rsolr'
Expand Down
11 changes: 2 additions & 9 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
GIT
remote: https://github.com/NYULibraries/omniauth-nyulibraries
revision: 2a77afefc346669e5a50ff5c84e48a012490dfbc
branch: v2.2.0
specs:
omniauth-nyulibraries (2.2.0)
omniauth-oauth2 (~> 1.2.0)

GIT
remote: https://github.com/mimemagicrb/mimemagic.git
revision: 01f92d86d15d85cfd0f20dabd025dcbd36a8a60f
Expand Down Expand Up @@ -434,7 +426,8 @@ DEPENDENCIES
jquery-rails
mimemagic!
mysql2
omniauth-nyulibraries!
omniauth
omniauth-oauth2
puma
rails
rainbow
Expand Down
1 change: 1 addition & 0 deletions app/assets/config/manifest.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//= link_tree ../images
//= link_tree ../javascripts
//= link_tree ../stylesheets
//= link_directory ../stylesheets .css
2 changes: 1 addition & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def after_sign_out_path_for(resource_or_scope)
end

def logout_path
'https://login.library.nyu.edu/logout'
Settings.LOGOUT_URL || 'https://qa.auth.it.nyu.edu/oidc/logout'
end
private :logout_path
end
82 changes: 82 additions & 0 deletions app/controllers/omniauth_callbacks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# frozen_string_literal: true

class OmniauthCallbacksController < Devise::OmniauthCallbacksController
before_action :require_valid_omniauth, only: :shibboleth

def shibboleth
Rails.logger.info("OmniauthCallbacksController#shibboleth: #{omniauth.inspect}")
set_user
if @user.persisted?
log_in
else
redirect_to_login
end
end

def failure
redirect_to root_path
end

private

def redirect_to_login
Rails.logger.error(find_message(:failure, kind: 'NYU Shibboleth', reason: 'User not persisted'))
session['devise.shibboleth_data'] = request.env['omniauth.auth']
redirect_to root_path
end

def log_in
sign_in_and_redirect @user, event: :authentication
set_flash_message(:notice, :success, kind: 'NYU Shibboleth')
logger.info(find_message(:success, kind: 'NYU Shibboleth'))
end

def require_valid_omniauth
head :bad_request unless valid_omniauth?
end

def valid_omniauth?
omniauth.present?
end

def omniauth
@omniauth ||= request.env['omniauth.auth']
end

def omniauth_provider
@omniauth_provider ||= omniauth.provider
end

def attributes_from_omniauth
{
provider: omniauth.provider,
username: omniauth.uid,
email: omniauth_email,
firstname: omniauth_firstname,
lastname: omniauth_lastname
}
end

def omniauth_email
@omniauth_email ||= omniauth.info.email
end

def omniauth_firstname
@omniauth_firstname ||= omniauth.info.first_name
end

def omniauth_lastname
@omniauth_lastname ||= omniauth.info.last_name
end

def set_user
# Find existing or initialize new user,
# and save new attributes each time
@user = find_user
@user.update_attributes(attributes_from_omniauth)
end

def find_user
@find_user ||= User.create_from_provider_data(request.env['omniauth.auth'])
end
end
107 changes: 0 additions & 107 deletions app/controllers/users/omniauth_callbacks_controller.rb

This file was deleted.

11 changes: 10 additions & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,21 @@ class User < ActiveRecord::Base
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable and :omniauthable

devise :omniauthable, omniauth_providers: [:nyulibraries]
devise :omniauthable, omniauth_providers: [:shibboleth]

# Method added by Blacklight; Blacklight uses #to_s on your
# user class to get a user-displayable login/identifier for
# the account.
def to_s
email
end

def self.create_from_provider_data(provider_data)
where(provider: provider_data.provider,
username: provider_data.uid)
.first_or_create do |user|
user.email = provider_data.info.email
user.username = provider_data.uid
end
end
end
7 changes: 4 additions & 3 deletions config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@
config.password_length = 8..128
config.reset_password_within = 60.minutes
config.sign_out_via = :get
config.omniauth :nyulibraries, Settings.APP_ID, Settings.APP_SECRET, client_options: {
site: Settings.LOGIN_URL,
authorize_path: '/oauth/authorize'
config.omniauth :shibboleth, Settings.APP_ID, Settings.APP_SECRET, client_options: {
site: (Settings.LOGIN_URL || "https://qa.auth.it.nyu.edu"),
authorize_url: "/oauth2/authorize",
token_url: "/oauth2/token",
}
end
46 changes: 46 additions & 0 deletions config/initializers/omniauth/strategies/shibboleth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
module OmniAuth
module Strategies
require 'omniauth-oauth2'
class Shibboleth < OmniAuth::Strategies::OAuth2
if defined?(::Rails) && ::Rails.env.development?
silence_warnings do
OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
end
end
option :name, :shibboleth
option :authorize_params, { scope: "openid" }

uid do
raw_info["sub"]
end

info do
{
email: raw_info["sub"],
last_name: last_name,
first_name: first_name
}
end

def raw_info
response = access_token.get("/oauth2/userinfo?schema=openid")
Rails.logger.info("Shibboleth raw_info: #{response.parsed}")
@raw_info ||= response.parsed
end

# Extract Last Name from identity
def last_name
@last_name ||= raw_info["lastname"] rescue nil
end

# Extract First Name from identity
def first_name
@first_name ||= raw_info["firstname"] rescue nil
end

def log(level, message)
Rails.logger.send(level, "(#{name}) #{message}")
end
end
end
end
6 changes: 3 additions & 3 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
Rails.application.routes.draw do
devise_for :users, controllers: {omniauth_callbacks: 'users/omniauth_callbacks'}
devise_for :users, path: '', controllers: {omniauth_callbacks: 'omniauth_callbacks'}
devise_scope :user do
get 'logout', to: 'devise/sessions#destroy', as: :logout
get 'login', to: redirect { |params, request| "#{Rails.application.config.relative_url_root}/users/auth/nyulibraries?#{request.query_string}" }, as: :login
get 'login', to: redirect { |params, request| "#{Rails.application.config.relative_url_root}/auth/shibboleth?#{request.query_string}" }, as: :login

resources :suggest, only: :index, defaults: {format: 'json'}

Expand Down Expand Up @@ -51,4 +51,4 @@
end
end
end
end
end
24 changes: 12 additions & 12 deletions spec/routing/user_routing_spec.rb
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
# frozen_string_literal: true

describe 'routes for users' do
describe 'GET /users/auth/nyulibraries' do
subject { get('/users/auth/nyulibraries') }
describe 'GET /auth/shibboleth' do
subject { get('/auth/shibboleth') }
it do
should route_to({
controller: 'users/omniauth_callbacks',
controller: 'omniauth_callbacks',
action: 'passthru'
})
end
end

describe 'POST /users/auth/nyulibraries' do
subject { post('/users/auth/nyulibraries') }
describe 'POST /auth/shibboleth' do
subject { post('/auth/shibboleth') }
it do
should route_to({
controller: 'users/omniauth_callbacks',
controller: 'omniauth_callbacks',
action: 'passthru'
})
end
end

describe 'GET /users/auth/nyulibraries/callback' do
subject { get('/users/auth/nyulibraries/callback') }
it { should route_to({ controller: 'users/omniauth_callbacks', action: 'nyulibraries' }) }
describe 'GET /auth/shibboleth/callback' do
subject { get('/auth/shibboleth/callback') }
it { should route_to({ controller: 'omniauth_callbacks', action: 'shibboleth' }) }
end

describe 'POST /users/auth/nyulibraries/callback' do
subject { post('/users/auth/nyulibraries/callback') }
it { should route_to({ controller: 'users/omniauth_callbacks', action: 'nyulibraries' }) }
describe 'POST /auth/shibboleth/callback' do
subject { post('/auth/shibboleth/callback') }
it { should route_to({ controller: 'omniauth_callbacks', action: 'shibboleth' }) }
end
end

0 comments on commit 511aeaa

Please sign in to comment.