Skip to content

Commit

Permalink
Add SSO with Shibboleth
Browse files Browse the repository at this point in the history
  • Loading branch information
Janell-Huyck committed Aug 19, 2024
1 parent 3643fc0 commit aa71118
Show file tree
Hide file tree
Showing 17 changed files with 436 additions and 23 deletions.
5 changes: 3 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,9 @@ jobs:
key: v1-dependencies-{{ checksum "Gemfile.lock" }}

# Database setup
- run: bundle exec rake db:create
- run: bundle exec rake db:schema:load
- run: bundle exec rails db:create
- run: bundle exec rails db:schema:load
- run: bundle exec rails db:seed

- run:
name: Rubocop
Expand Down
8 changes: 4 additions & 4 deletions .env.development
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Admin Variables
ADMIN_USERNAME=test
ADMIN_PASSWORD=password
# Admin Variables
ADMIN_USERNAME=test
ADMIN_PASSWORD=password

# Mail Variables
MAIL_SENDER=[email protected]
Expand All @@ -15,6 +15,6 @@
TREATMENT_DATABASE_TIMEOUT=5000
TREATMENT_DATABASE_USERNAME=

Mailer settings
# Mailer settings
TREATMENT_PRODUCTION_MAILER_FROM=[email protected]
TREATMENT_PRODUCTION_MAILER_URL=localhost
2 changes: 1 addition & 1 deletion .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@
TREATMENT_DATABASE_POOL=5
TREATMENT_DATABASE_PORT=
TREATMENT_DATABASE_TIMEOUT=5000
TREATMENT_DATABASE_USERNAME=
TREATMENT_DATABASE_USERNAME=
9 changes: 7 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,18 @@ gem 'devise' # Flexible authentication solution for Rails with Warden

# Additional Functionality
gem 'nokogiri' # HTML, XML, SAX, and Reader parser
gem 'pagy' # Pagination library that is fast, lightweight, and flexible
gem 'pagy', '~> 9.0' # Pagination library that is fast, lightweight, and flexible
gem 'paper_trail' # Track changes to your models' data
gem 'pdfkit' # Uses wkhtmltopdf to generate PDFs from HTML
gem 'wkhtmltopdf-binary', '>= 0.12.6.7' # Enables PDF generation from HTML

# Windows specific timezone data
gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby] # Timezone data for Windows

gem 'show_me_the_cookies' # Cookie inspection for tests

gem 'omniauth-shibboleth' # Provides Shibboleth-based SSO authentication

group :development, :test do
# Debugging tools
gem 'byebug', platforms: %i[mri mingw x64_mingw] # Debugging tool for Ruby
Expand All @@ -59,7 +63,6 @@ group :development, :test do
gem 'factory_bot_rails' # A fixtures replacement with a straightforward definition syntax
gem 'rails-controller-testing' # Adds missing helper methods for controller tests in Rails 5
gem 'rspec_junit_formatter' # Outputs RSpec results in JUnit format
gem 'rspec-rails', '~> 6.0.0' # RSpec for Rails 6+
gem 'selenium-webdriver', '~> 4.18.1' # WebDriver for testing web applications

# Coverage and code analysis
Expand Down Expand Up @@ -96,6 +99,8 @@ group :test do
gem 'capybara', '>= 2.15' # Integration testing tool for rack-based web applications
gem 'database_cleaner-active_record' # Strategies for cleaning databases in Ruby
gem 'launchy' # Opens a given URL in a browser
gem 'rack-test' # Small, simple testing API for Rack apps
gem 'rspec-rails', '~> 6.0.0' # RSpec for Rails 6+
end

group :production do
Expand Down
41 changes: 28 additions & 13 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ GEM
i18n
rake (>= 10.0.0)
sshkit (>= 1.9.0)
capistrano-bundler (2.1.0)
capistrano-bundler (2.1.1)
capistrano (~> 3.1)
capistrano-rails (1.6.3)
capistrano (~> 3.1)
Expand All @@ -108,8 +108,9 @@ GEM
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
childprocess (5.0.0)
concurrent-ruby (1.3.3)
childprocess (5.1.0)
logger (~> 1.5)
concurrent-ruby (1.3.4)
coveralls_reborn (0.28.0)
simplecov (~> 0.22.0)
term-ansicolor (~> 1.7)
Expand Down Expand Up @@ -156,6 +157,7 @@ GEM
forwardable (1.3.3)
globalid (1.2.1)
activesupport (>= 6.1)
hashie (5.0.0)
i18n (1.14.5)
concurrent-ruby (~> 1.0)
ipaddr (1.2.6)
Expand All @@ -173,6 +175,7 @@ GEM
listen (3.9.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.6.0)
loofah (2.22.0)
crass (~> 1.0.2)
nokogiri (>= 1.12.0)
Expand All @@ -186,7 +189,6 @@ GEM
method_source (1.1.0)
mini_mime (1.1.5)
minitest (5.24.1)
mize (0.6.0)
mutex_m (0.2.0)
mysql2 (0.5.6)
net-imap (0.4.14)
Expand Down Expand Up @@ -217,13 +219,19 @@ GEM
nokogiri (1.16.7-x86_64-linux)
racc (~> 1.4)
observer (0.1.2)
omniauth (2.1.2)
hashie (>= 3.4.6)
rack (>= 2.2.3)
rack-protection
omniauth-shibboleth (1.3.0)
omniauth (>= 1.0.0)
orm_adapter (0.5.0)
pagy (9.0.4)
pagy (9.0.5)
paper_trail (15.1.0)
activerecord (>= 6.1)
request_store (~> 1.4)
parallel (1.25.1)
parser (3.3.4.0)
parallel (1.26.2)
parser (3.3.4.2)
ast (~> 2.4.1)
racc
pdfkit (0.8.7.3)
Expand All @@ -233,6 +241,9 @@ GEM
nio4r (~> 2.0)
racc (1.8.1)
rack (2.2.9)
rack-protection (3.2.0)
base64 (>= 0.1.0)
rack (~> 2.2, >= 2.2.4)
rack-test (2.1.0)
rack (>= 1.3)
rails (6.1.7.8)
Expand Down Expand Up @@ -282,7 +293,7 @@ GEM
responders (3.1.1)
actionpack (>= 5.2)
railties (>= 5.2)
rexml (3.3.4)
rexml (3.3.5)
strscan
rinda (0.2.0)
drb
Expand Down Expand Up @@ -318,7 +329,7 @@ GEM
rubocop-ast (>= 1.31.1, < 2.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.31.3)
rubocop-ast (1.32.0)
parser (>= 3.3.1.0)
rubocop-rails (2.25.1)
activesupport (>= 4.2.0)
Expand All @@ -340,6 +351,8 @@ GEM
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
websocket (~> 1.0)
show_me_the_cookies (6.0.0)
capybara (>= 2, < 4)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
Expand Down Expand Up @@ -372,8 +385,7 @@ GEM
strscan (3.1.0)
sync (0.5.0)
syslog (0.1.2)
term-ansicolor (1.10.4)
mize (~> 0.5)
term-ansicolor (1.11.2)
tins (~> 1.0)
thor (1.3.1)
tilt (2.4.0)
Expand Down Expand Up @@ -451,11 +463,13 @@ DEPENDENCIES
nkf (~> 0.2.0)
nokogiri
observer (~> 0.1.2)
pagy
omniauth-shibboleth
pagy (~> 9.0)
paper_trail
pdfkit
puma
racc (~> 1.8)
rack-test
rails (~> 6.1.7)
rails-controller-testing
rb-readline
Expand All @@ -467,6 +481,7 @@ DEPENDENCIES
rubocop-rails
sassc-rails (~> 2.1)
selenium-webdriver (~> 4.18.1)
show_me_the_cookies
simplecov
simplecov-lcov
spring
Expand All @@ -483,4 +498,4 @@ RUBY VERSION
ruby 3.3.3p89

BUNDLED WITH
2.5.10
2.5.15
24 changes: 24 additions & 0 deletions app/controllers/callbacks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# frozen_string_literal: true

class CallbacksController < ApplicationController
# Authenticate user not yet defined
# skip_before_action :authenticate_user!, only: [:shibboleth]

def shibboleth
# This is a placeholder for the Shibboleth callback.
render plain: 'Shibboleth callback received'

# Possible implementation of Shibboleth callback:
# shib_attributes = request.env['Shib-Attributes']
# email = shib_attributes[:email]
# username = shib_attributes[:username]
#
# user = User.find(email: email) do |user|
# user.username = username
# # Assign other user attributes as needed
# end
#
# session[:user_id] = user.id
# redirect_to root_path
end
end
4 changes: 4 additions & 0 deletions config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

require 'rails/all'
require 'dotenv-rails'
require_relative '../lib/middleware/shibboleth'

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Expand All @@ -16,6 +17,9 @@ class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version.
config.load_defaults 5.2

# Load middleware for Shibboleth
config.middleware.use Middleware::Shibboleth

# Settings in config/environments/* take precedence over those specified here.
# Application configuration can go into files in config/initializers
# -- all .rb files in that directory are automatically loaded after loading
Expand Down
3 changes: 3 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@
get 'conservation_records/:id/treatment_report', to: 'conservation_records#treatment_report', as: 'treatment_report'
get 'conservation_records/:id/abbreviated_treatment_report', to: 'conservation_records#abbreviated_treatment_report', as: 'abbreviated_treatment_report'
get 'reports/download_csv'

get 'auth/shibboleth/callback', to: 'callbacks#shibboleth', as: :shibboleth_callback
delete 'logout', to: 'sessions#destroy', as: :logout
end
26 changes: 26 additions & 0 deletions lib/middleware/shibboleth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

module Middleware
class Shibboleth
def initialize(app)
@app = app
end

def call(env)
request = Rack::Request.new(env)

# Extract Shibboleth attributes from the request environment
shib_attributes = {
email: request.env['mail'],
username: request.env['uid'],
first_name: request.env['givenName'],
last_name: request.env['sn']
}

# Store Shibboleth attributes in the environment
env['Shib-Attributes'] = shib_attributes

@app.call(env)
end
end
end
93 changes: 93 additions & 0 deletions spec/controllers/callbacks_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe CallbacksController, type: :controller do
describe 'GET #shibboleth' do
it 'returns a plain text response' do
get :shibboleth
expect(response).to have_http_status(:ok)
expect(response.body).to eq('Shibboleth callback received')
end
end
end

# 4/30 copied directly from ucrate controller spec for our own transition to Shibboleth.
# We will need to modify these tests to fit our own application.
# Callbacks are functions that handle the response from an external service such as Shibboleth.

# Skipping this because we don't have a CallbacksController.

# describe CallbacksController do
# describe 'omniauth-shibboleth' do
# let(:uid) { '[email protected]' }
# let(:provider) { :shibboleth }
#
# before do
# @request.env['devise.mapping'] = Devise.mappings[:user]
# omniauth_hash = { provider: 'shibboleth',
# uid:,
# extra: {
# raw_info: {
# mail: uid,
# title: 'title',
# telephoneNumber: '123-456-7890',
# givenName: 'Fake',
# sn: 'User',
# uceduPrimaryAffiliation: 'staff',
# ou: 'department'
# }
# } }
# OmniAuth.config.add_mock(provider, omniauth_hash)
# request.env['omniauth.auth'] = OmniAuth.config.mock_auth[provider]
# end
#
# context 'with a user who is already logged in' do
# let(:user) { FactoryBot.create(:user) }
#
# before do
# controller.stub(:current_user).and_return(user)
# end
# it 'redirects to the dashboard' do
# get provider
# expect(response).to redirect_to(Hyrax::Engine.routes.url_helpers.dashboard_path)
# end
# end
#
# shared_examples 'Shibboleth login' do
# it 'assigns the user and redirects' do
# get provider
# expect(flash[:notice]).to match(/You are now signed in as */)
# expect(assigns(:user).email).to eq(email)
# expect(assigns(:user).uid).to eq(request.env['omniauth.auth']['uid'])
# expect(response).to be_redirect
# end
# end
#
# it_behaves_like 'Shibboleth login'
#
# it 'updates the shibboleth attributes' do
# get provider
# expect(assigns(:user).mail).to eq(request.env['omniauth.auth']['extra']['raw_info']['email'])
# end
# end
#
# context 'with a registered user who has previously logged in' do
# let!(:user) { FactoryBot.create(:shibboleth_user, count: 1, profile_update_not_required: false) }
# let(:email) { user.email }
#
# it_behaves_like 'Shibboleth login'
# end
#
# context 'with a registered user who has never logged in' do
# let!(:user) { FactoryBot.create(:shibboleth_user, count: 0, profile_update_not_required: false) }
# let(:email) { user.email }
#
# it_behaves_like 'Shibboleth login'
#
# it 'updates the shibboleth attributes' do
# get provider
# expect(assigns(:user).mail).to eq(request.env['omniauth.auth']['extra']['raw_info']['email'])
# end
# end
# end
Loading

0 comments on commit aa71118

Please sign in to comment.