Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@

# Ignore config files
/config/bibdata.yml
/config/database.yml
/config/folio.yml
/config/redis.yml
/config/resque.yml
config/permissions.yml

# macOS Files
.DS_Store
Expand Down
2 changes: 1 addition & 1 deletion Capfile
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ install_plugin Capistrano::SCM::Git
# Include tasks from other gems included in your Gemfile
require 'capistrano/cul'
require 'capistrano/bundler'
# require "capistrano/rails/migrations"
require 'capistrano/rails/migrations'
require 'capistrano/passenger'

# Load custom tasks from `lib/capistrano/tasks` if you have any defined
Expand Down
20 changes: 18 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ gem "rails", "~> 8.0.2"
gem "puma", ">= 5.0"
# Build JSON APIs with ease [https://github.com/rails/jbuilder]
# gem "jbuilder"
# Use Redis adapter to run Action Cable in production
# gem "redis", ">= 4.0.1"

# For ActiveRecord, mysql for deployed server databases
gem 'mysql2', '~> 0.5.6'

# Use Active Model has_secure_password [https://guides.rubyonrails.org/active_model_basics.html#securepassword]
# gem "bcrypt", "~> 3.1.7"
Expand Down Expand Up @@ -38,6 +39,18 @@ gem "rainbow", "~> 3.0"
# Retriable for retrying operations in response to specific exceptions
gem 'retriable', '~> 3.1'

# Resque/Redis (for queued jobs)
gem 'redis', '~> 4.8' # NOTE: Updating the redis gem to v5 breaks the current redis namespace setup
gem 'redis-namespace', '~> 1.11'
gem 'resque', '~> 2.6'

# For authentication
gem 'devise', '~> 4.9'
gem 'omniauth', '~> 2.1'
gem 'omniauth-rails_csrf_protection', '~> 1.0'
# gem 'omniauth-cul', '~> 0.2.0'
gem 'omniauth-cul', git: 'https://github.com/cul/omniauth-cul', ref: 'improved-implementation'

# FOLIO Client
gem "folio_api_client", "~> 0.4.3"
# gem "folio_api_client", path: "../folio_api_client"
Expand All @@ -55,6 +68,9 @@ group :development, :test do
gem "rspec-rails", "~> 8.0"

gem "simplecov", require: false

# For ActiveRecord, use sqlite for dev/test databases and mysql for deployed server databases
gem 'sqlite3', '~> 2.8'
end

group :development do
Expand Down
75 changes: 75 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
GIT
remote: https://github.com/cul/omniauth-cul
revision: 116607e324e109dd335a409596d81d8b377fcbf5
ref: improved-implementation
specs:
omniauth-cul (0.2.0)
devise (>= 4.9)
omniauth (>= 2.0)

GEM
remote: https://rubygems.org/
specs:
Expand Down Expand Up @@ -76,6 +85,7 @@ GEM
sshkit (>= 1.6.1, != 1.7.0)
ast (2.4.3)
base64 (0.3.0)
bcrypt (3.1.20)
bcrypt_pbkdf (1.1.1)
bcrypt_pbkdf (1.1.1-arm64-darwin)
bcrypt_pbkdf (1.1.1-x86_64-darwin)
Expand Down Expand Up @@ -113,6 +123,12 @@ GEM
debug (1.11.0)
irb (~> 1.10)
reline (>= 0.3.8)
devise (4.9.4)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 4.1.0)
responders
warden (~> 1.2.3)
diff-lcs (1.6.2)
docile (1.4.1)
dotenv (3.1.8)
Expand All @@ -132,6 +148,7 @@ GEM
zeitwerk (~> 2.7)
globalid (1.3.0)
activesupport (>= 6.1)
hashie (5.0.0)
i18n (1.14.7)
concurrent-ruby (~> 1.0)
io-console (0.8.1)
Expand Down Expand Up @@ -168,7 +185,13 @@ GEM
mini_mime (1.1.5)
mini_portile2 (2.8.9)
minitest (5.25.5)
mono_logger (1.1.2)
msgpack (1.8.0)
multi_json (1.17.0)
mustermann (3.0.4)
ruby2_keywords (~> 0.0.1)
mysql2 (0.5.7)
bigdecimal
net-http (0.6.0)
uri
net-imap (0.5.12)
Expand All @@ -189,6 +212,15 @@ GEM
nokogiri (1.18.10)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
omniauth (2.1.4)
hashie (>= 3.4.6)
logger
rack (>= 2.2.3)
rack-protection
omniauth-rails_csrf_protection (1.0.2)
actionpack (>= 4.2)
omniauth (~> 2.0)
orm_adapter (0.5.0)
ostruct (0.6.3)
parallel (1.27.0)
parser (3.3.9.0)
Expand All @@ -205,6 +237,10 @@ GEM
nio4r (~> 2.0)
racc (1.8.1)
rack (3.2.3)
rack-protection (4.2.1)
base64 (>= 0.1.0)
logger (>= 1.6.0)
rack (>= 3.0.0, < 4)
rack-session (2.1.1)
base64 (>= 0.1.0)
rack (>= 3.0.0)
Expand Down Expand Up @@ -248,9 +284,20 @@ GEM
erb
psych (>= 4.0.0)
tsort
redis (4.8.1)
redis-namespace (1.11.0)
redis (>= 4)
regexp_parser (2.11.2)
reline (0.6.2)
io-console (~> 0.5)
responders (3.2.0)
actionpack (>= 7.0)
railties (>= 7.0)
resque (2.7.0)
mono_logger (~> 1)
multi_json (~> 1.0)
redis-namespace (~> 1.6)
sinatra (>= 0.9.2)
retriable (3.1.2)
rexml (3.4.4)
rspec-core (3.13.5)
Expand Down Expand Up @@ -315,13 +362,29 @@ GEM
rubocop-rails (~> 2.25)
rubocop-rspec (~> 2.28)
ruby-progressbar (1.13.0)
ruby2_keywords (0.0.5)
securerandom (0.4.1)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
simplecov-html (0.13.1)
simplecov_json_formatter (0.1.4)
sinatra (4.2.1)
logger (>= 1.6.0)
mustermann (~> 3.0)
rack (>= 3.0.0, < 4)
rack-protection (= 4.2.1)
rack-session (>= 2.0.0, < 3)
tilt (~> 2.0)
sqlite3 (2.8.0-aarch64-linux-gnu)
sqlite3 (2.8.0-aarch64-linux-musl)
sqlite3 (2.8.0-arm-linux-gnu)
sqlite3 (2.8.0-arm-linux-musl)
sqlite3 (2.8.0-arm64-darwin)
sqlite3 (2.8.0-x86_64-darwin)
sqlite3 (2.8.0-x86_64-linux-gnu)
sqlite3 (2.8.0-x86_64-linux-musl)
sshkit (1.24.0)
base64
logger
Expand All @@ -336,13 +399,16 @@ GEM
thruster (0.1.15-arm64-darwin)
thruster (0.1.15-x86_64-darwin)
thruster (0.1.15-x86_64-linux)
tilt (2.6.1)
timeout (0.4.3)
tsort (0.2.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unicode-display_width (2.6.0)
uri (1.0.4)
useragent (0.16.11)
warden (1.2.9)
rack (>= 2.0.9)
websocket-driver (0.8.0)
base64
websocket-extensions (>= 0.1.0)
Expand All @@ -369,17 +435,26 @@ DEPENDENCIES
capistrano-passenger (~> 0.1)
capistrano-rails (~> 1.4)
debug
devise (~> 4.9)
folio_api_client (~> 0.4.3)
kamal
marc (~> 1.3)
mysql2 (~> 0.5.6)
nokogiri (~> 1.18, >= 1.18.10)
omniauth (~> 2.1)
omniauth-cul!
omniauth-rails_csrf_protection (~> 1.0)
puma (>= 5.0)
rails (~> 8.0.2)
rainbow (~> 3.0)
redis (~> 4.8)
redis-namespace (~> 1.11)
resque (~> 2.6)
retriable (~> 3.1)
rspec-rails (~> 8.0)
rubocul (~> 4.0.12)
simplecov
sqlite3 (~> 2.8)
thruster
tzinfo-data

Expand Down
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@ bundle install

# Copy config template files
./bin/copy-config-template-files

# Start Redis with docker (in a separate terminal window)
docker compose up

# Start the rails server
rails s
```
7 changes: 7 additions & 0 deletions app/controllers/api_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class ApiController < ActionController::API
# Unlike ActionController::Base, ActionController::API does not include token HttpAuthentication Token
# methods by default, so we'll include it.
include ActionController::HttpAuthentication::Token::ControllerMethods
end
9 changes: 1 addition & 8 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
# frozen_string_literal: true

class ApplicationController < ActionController::API
# Unlike ActionController::Base, ActionController::API does not include token HttpAuthentication Token
# methods by default, so we'll include it.
include ActionController::HttpAuthentication::Token::ControllerMethods

def index
render plain: "#{Rails.application.class.module_parent_name}\nVersion: #{VERSION}"
end
class ApplicationController < ActionController::Base
end
5 changes: 5 additions & 0 deletions app/controllers/pages_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

class PagesController < ApplicationController
def home; end
end
54 changes: 54 additions & 0 deletions app/controllers/users/omniauth_callbacks_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# frozen_string_literal: true

require 'omniauth/cul'

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# See https://github.com/omniauth/omniauth/wiki/FAQ#rails-session-is-clobbered-after-callback-on-developer-strategy
# The CAS login redirect to the columbia_cas callback endpoint AND the developer form submission to the
# developer_uid callback do not send authenticity tokens, so we'll skip token verification for these actions.
skip_before_action :verify_authenticity_token, only: [:columbia_cas, :developer_uid]

# POST /users/auth/developer_uid/callback
def developer_uid
return unless Rails.env.development? # Only allow this action to run in the development environment

uid = params[:uid]
user = User.find_by(uid: uid) || User.create!(
uid: uid,
email: "#{uid}@library.columbia.edu"
)

unless user
flash[:alert] = "Login attempt failed. User #{uid} does not have an account."
redirect_to root_path
return
end

sign_in_and_redirect user, event: :authentication # this will throw if user is not activated
end

# POST /users/auth/columbia_cas/callback
def columbia_cas # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
callback_url = user_columbia_cas_omniauth_callback_url # The columbia_cas callback route in this application
uid, affils = Omniauth::Cul::ColumbiaCas.validation_callback(request.params['ticket'], callback_url)

if Omniauth::Cul::PermissionFileValidator.permitted?(uid, affils)
user = User.find_by(uid: uid) || User.create!(
uid: uid,
email: "#{uid}@columbia.edu"
)
sign_in_and_redirect user, event: :authentication # this will throw if user is not activated
else
flash[:alert] = 'Login attempt failed'
redirect_to root_path
end
rescue Omniauth::Cul::Exceptions::Error => e
# If an unexpected CAS ticket validation occurs, log the error message and ask the user to try
# logging in again. Do not display the exception object's original message to the user because it may
# contain information that only a developer should see.
error_message = 'CAS login validation failed. Please try again.'
Rails.logger.debug(error_message + " #{e.class.name}: #{e.message}")
flash[:alert] = error_message
redirect_to root_path
end
end
17 changes: 17 additions & 0 deletions app/controllers/users/sessions_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

# rubocop:disable Lint/UselessMethodDefinition

class Users::SessionsController < Devise::SessionsController
# GET /users/sign_in
def new
super
end

# DELETE /users/sign_out
def destroy
super
end
end

# rubocop:enable Lint/UselessMethodDefinition
5 changes: 5 additions & 0 deletions app/models/application_record.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

class ApplicationRecord < ActiveRecord::Base
self.abstract_class = true
end
5 changes: 5 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

class User < ApplicationRecord
devise :omniauthable, omniauth_providers: Devise.omniauth_configs.keys
end
17 changes: 17 additions & 0 deletions app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<head>
<title>Triclops</title>
<%= csrf_meta_tags %>
<%= csp_meta_tag %>

<%= stylesheet_link_tag 'application', media: 'all' %>
</head>

<body>
<% flash.each do |type, msg| %>
<div class="alert"><%= msg %></div>
<% end %>
<%= yield %>
</body>
</html>
Loading