Skip to content
Closed
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: 2 additions & 2 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ gem 'grape-swagger', '~> 2.0.0'
gem 'mustermann', '~> 2.0'
gem 'om', '3.1.1'
gem 'omniauth', '>= 2.1'
gem 'omniauth-cul'
gem 'omniauth-rails_csrf_protection', '~> 1.0'
gem 'omniauth-cul', '~> 0.3.0'

gem 'fugit', '>= 1.11.1'
gem 'http'
Expand Down Expand Up @@ -86,6 +85,7 @@ group :development, :test do
gem 'factory_bot_rails', '~> 6.5.0'
gem 'jettywrapper', '>=1.4.0', git: 'https://github.com/samvera-deprecated/jettywrapper.git', branch: 'master'
# gem 'json_spec'
gem 'rails-controller-testing'
gem 'rspec-its', '~> 2.0.0'
gem 'rspec-rails', '~> 8.0.0'
gem 'selenium-webdriver', '~> 4.11'
Expand Down
13 changes: 7 additions & 6 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -387,12 +387,9 @@ GEM
hashie (>= 3.4.6)
rack (>= 2.2.3)
rack-protection
omniauth-cul (0.2.0)
omniauth-cul (0.3.0)
devise (>= 4.9)
omniauth (>= 2.0)
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)
Expand Down Expand Up @@ -446,6 +443,10 @@ GEM
activesupport (= 8.0.4)
bundler (>= 1.15.0)
railties (= 8.0.4)
rails-controller-testing (1.0.5)
actionpack (>= 5.0.1.rc1)
actionview (>= 5.0.1.rc1)
activesupport (>= 5.0.1.rc1)
rails-dom-testing (2.3.0)
activesupport (>= 5.0.0)
minitest
Expand Down Expand Up @@ -754,12 +755,12 @@ DEPENDENCIES
okcomputer
om (= 3.1.1)
omniauth (>= 2.1)
omniauth-cul
omniauth-rails_csrf_protection (~> 1.0)
omniauth-cul (~> 0.3.0)
premailer (~> 1.27.0)
premailer-rails
puma (~> 5.2)
rails (= 8.0.4)
rails-controller-testing
rainbow
resque (~> 2.7.0)
resque-scheduler (>= 4.10.2)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ example: http://petstore.swagger.io/?url=http://www.example.com/api/v1/swagger_d

## Helpful things to know
### Authentication/Authorization
We are using cul_omniauth to provide Columbia CAS login (authentication). In addition, we are using CanCanCan for authorization of specific tasks. Right now, we just have one role, and that's 'admin.' Later, we might want a more complex permissions structure, but for right now this fits our needs. Any page that requires authentication will redirect the user to the Columbia CAS login page. If a json response is requested, the user is not redirected.
We are using [omniauth-cul gem](https://github.com/cul/omniauth-cul) to provide Columbia CAS login (_authentication_). In addition, we are using CanCanCan for _authorization_ of specific tasks. Right now, we just have one role, and that's 'admin.' Later, we might want a more complex permissions structure, but for right now this fits our needs. Any page that requires authentication will redirect the user to the Columbia CAS login page. If a json response is requested, the user is not redirected.

### Statistics
For every asset and item in Academic Commons we store view and download statistics. Assets should only have download statistics and items should only have view statistics. When we calculate download statistics for an item we use the download statistics of its assets. If there are multiple assets associated with an item, we use the download statistics for the most downloaded asset.
Expand Down
2 changes: 1 addition & 1 deletion app/components/blacklight/search_bar_component.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<% before_input_groups.each do |input_group| %>
<%= input_group %>
<% end %>
<div class="input-group bradley">
<div class="input-group">
<%= prepend %>

<% if search_fields.length > 1 %>
Expand Down
54 changes: 29 additions & 25 deletions app/controllers/users/omniauth_callbacks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,43 @@
require 'omniauth/cul'

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
# Adding the line below so that if the auth endpoint POSTs to our cas endpoint, it won't
# be rejected by authenticity token verification.
# See https://github.com/omniauth/omniauth/wiki/FAQ#rails-session-is-clobbered-after-callback-on-developer-strategy
skip_before_action :verify_authenticity_token, only: :cas
# 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]

def app_cas_callback_endpoint
"#{request.base_url}/users/auth/cas/callback"
end
# POST /users/auth/developer_uid/callback
def developer_uid
return unless Rails.env.development? # Only allow this action to run in the development environment

# In local development, use devise's controller action. In deployed env, use CAS server
def passthru
if Rails.env.development?
super
else
redirect_to Omniauth::Cul::Cas3.passthru_redirect_url(app_cas_callback_endpoint), allow_other_host: true
end
end
uid = params[:uid]
user = User.find_by(uid: uid)

def developer
current_user ||= User.find_or_create_by(
uid: request.env['omniauth.auth'][:uid], provider: :developer
)
unless user
flash[:alert] = "Login attempt failed. User #{uid} does not have an account."
redirect_to root_path
return
end

sign_in_and_redirect current_user, event: :authentication
flash[:success] = 'You have succesfully logged in.'
sign_in_and_redirect user, event: :authentication # this will throw if user is not activated
end

def cas
user_id, _affils = Omniauth::Cul::Cas3.validation_callback(request.params['ticket'], app_cas_callback_endpoint)
# POST /users/auth/columbia_cas/callback
def columbia_cas # rubocop:disable Metrics/AbcSize
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)

user = User.find_by(uid: user_id) || User.create!(
uid: user_id,
email: "#{user_id}@columbia.edu"
)
user = User.find_by(uid: uid) || User.create(uid: uid, email: "#{uid}@columbia.edu")
flash[:success] = 'You have succesfully logged in.'
sign_in_and_redirect user, event: :authentication
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
8 changes: 4 additions & 4 deletions app/controllers/users/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ class Users::SessionsController < Devise::SessionsController
# that sends a POST req to our omniauth endpoint (this is the secure way and
# POST is not possible with redirect_to)
# inspiration: https://stackoverflow.com/questions/985596/redirect-to-using-post-in-rails
def new
render 'users/sessions/new'
def new # rubocop:disable Lint/UselessMethodDefinition
super
end

# This is needed if not using database authenticable (see https://github.com/heartcombo/devise/wiki/OmniAuth:-Overview#using-omniauth-without-other-authentications)
# This is needed if not using database authenticatable (see https://github.com/heartcombo/devise/wiki/OmniAuth:-Overview#using-omniauth-without-other-authentications)
def new_session_path(scope)
new_user_session_path # this accomodates Users namespace of the controller
new_user_session_path # this accommodates Users namespace of the controller
end

private
Expand Down
6 changes: 3 additions & 3 deletions app/models/site_configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# like you would if accessing a typical singleton class in Ruby
class SiteConfiguration < ApplicationRecord
SINGLETON_GUARD_VALUE = 0
DOWNLOADS_ENABLED_MESSAGE_DEF = 'Downloading has been temporarily disabled for Academic Commons. Contact an administrator for more information.' # rubocop:disable Layout/LineLength
DOWNLOADS_DISABLED_MESSAGE_DEFAULT = 'Downloading has been temporarily disabled for Academic Commons. Contact an administrator for more information.' # rubocop:disable Layout/LineLength

# The singleton_guard column is a unique column that must be set to 0
# This ensures that only one record of type SiteConfiguration is ever created
Expand All @@ -22,7 +22,7 @@ class SiteConfiguration < ApplicationRecord
def self.instance
where(singleton_guard: 0).first_or_create! do |site_config|
site_config.downloads_enabled = true
site_config.downloads_message = DOWNLOADS_ENABLED_MESSAGE_DEF
site_config.downloads_message = DOWNLOADS_DISABLED_MESSAGE_DEFAULT
site_config.deposits_enabled = true
site_config.alert_message = ''
site_config.singleton_guard = SINGLETON_GUARD_VALUE
Expand All @@ -34,7 +34,7 @@ def self.downloads_enabled
end

def self.downloads_message
return DOWNLOADS_ENABLED_MESSAGE_DEF if instance.downloads_message == ''
return DOWNLOADS_DISABLED_MESSAGE_DEFAULT if instance.downloads_message == ''

instance.downloads_message
end
Expand Down
2 changes: 1 addition & 1 deletion app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class User < ApplicationRecord
before_save :set_personal_info_via_ldap

# Configure devise for our User model
devise :rememberable, :trackable, :omniauthable, omniauth_providers: [Rails.env.development? ? :developer : :cas]
devise :rememberable, :trackable, :omniauthable, omniauth_providers: Devise.omniauth_configs.keys

ADMIN = 'admin'.freeze
ROLES = [ADMIN].freeze
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/email_preferences/_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

<%= form_with model: [:admin, @email_preference], local: true, data: { turbo: false } do |f| %>
<%= form_with model: [:admin, @email_preference], local: true, id: 'email-preference-form', data: { turbo: false } do |f| %>
<p>
<%= f.label :uni %>
<%= f.text_field :uni %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/admin/index.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<% title 'Admin' %>

<p class="admin-intro-message">
Choose an item from the Adminstration menu.
Choose an item from the Administration menu.
</p>
14 changes: 8 additions & 6 deletions app/views/admin/site_configurations/_alert_message_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<%= form_with url: admin_site_configuration_path, method: :patch, local: true, data: { turbo: false } do |form| %>
<div>
<%= form.text_area :alert_message, value: SiteConfiguration.alert_message %>
</div>
<%= form.submit 'Submit', class: 'btn btn-primary' %>
<% end %>
<div id='alert-message-form'>
<%= form_with url: admin_site_configuration_path, method: :patch, local: true do |form| %>
<div>
<%= form.text_area :alert_message, value: SiteConfiguration.alert_message %>
</div>
<%= form.submit 'Submit', class: 'btn btn-primary' %>
<% end %>
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="mt-3">
<div class="mt-3" id='downloads-message-form'>
<%= form_with url: admin_site_configuration_path, method: :patch, local: true, data: { turbo: false } do |form| %>
<%= form.text_area :downloads_message, value: SiteConfiguration.downloads_message %>
<%= form.submit 'Save Message', class: 'btn btn-primary' %>
Expand Down
22 changes: 12 additions & 10 deletions app/views/admin/site_configurations/_toggle_deposits_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<%= form_with url: admin_site_configuration_path, method: :patch, local: true, data: { turbo: false } do |form| %>
<% if SiteConfiguration.deposits_enabled %>
<% action_label = "Disable Deposits" %>
<% enable = false %>
<% else %>
<% action_label = "Enable Deposits" %>
<% enable = true %>
<div id='deposits-toggle-form'>
<%= form_with url: admin_site_configuration_path, method: :patch, local: true, data: { turbo: false } do |form| %>
<% if SiteConfiguration.deposits_enabled %>
<% action_label = "Disable Deposits" %>
<% enable = false %>
<% else %>
<% action_label = "Enable Deposits" %>
<% enable = true %>
<% end %>
<%= form.hidden_field :deposits_enabled, value: enable %>
<%= form.submit action_label, class: "btn btn-primary" %>
<% end %>
<%= form.hidden_field :deposits_enabled, value: enable %>
<%= form.submit action_label, class: "btn btn-primary" %>
<% end %>
</div>
26 changes: 14 additions & 12 deletions app/views/admin/site_configurations/_toggle_downloads_form.html.erb
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
<%= form_with url: admin_site_configuration_path, method: :patch, local: true, data: { turbo: false } do |form| %>
<% if SiteConfiguration.downloads_enabled %>
<% action_label = "Disable Downloads" %>
<% enable = false %>
<% else %>
<% action_label = "Enable Downloads" %>
<% enable = true %>
<div id='downloads-toggle-form'>
<%= form_with url: admin_site_configuration_path, method: :patch, local: true, data: { turbo: false } do |form| %>
<% if SiteConfiguration.downloads_enabled %>
<% action_label = "Disable Downloads" %>
<% enable = false %>
<% else %>
<% action_label = "Enable Downloads" %>
<% enable = true %>
<% end %>
<div>
<%= form.hidden_field :downloads_enabled, value: enable %>
<%= form.submit action_label, class: "btn btn-primary" %>
</div>
<% end %>
<div>
<%= form.hidden_field :downloads_enabled, value: enable %>
<%= form.submit action_label, class: "btn btn-primary" %>
</div>
<% end %>
</div>
2 changes: 2 additions & 0 deletions app/views/errors/forbidden.html.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<%# ERROR CODE 403 %>

<h2>Forbidden</h2>

<p>You do not have access.</p>
Expand Down
2 changes: 2 additions & 0 deletions app/views/errors/internal_server_error.html.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<%# ERROR CODE 500 %>

<h2>Internal Server Error</h2>

<p>The server has encountered an unexpected error.</p>
2 changes: 2 additions & 0 deletions app/views/errors/not_found.html.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<%# ERROR CODE 404 %>

<h2>Not Found</h2>

<p>The page you are looking for doesn't exist. Please try again or visit our <%= link_to 'homepage', root_path %>.</p>
2 changes: 2 additions & 0 deletions app/views/errors/record_not_found.html.erb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<%# ERROR CODE 404 for Blacklight Records %>

<h2>Record Not Found</h2>

<p>This item does not exist in Academic Commons or may have been removed.</p>
Expand Down
2 changes: 1 addition & 1 deletion app/views/info/developers.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<%= link_to nil, "http://petstore.swagger.io/?url=#{root_url}api/v1/swagger_doc" %></p>
<p>Note that data feeds (data_feed) provide bulk, unpaginated access to a previously-defined subset of records from the API. Data feeds are not API alternatives unless the requestor is a Columbia entity that regularly crawls all of the responses to a consistent query. For example, a specific department name or genre type. To access the data_feed functionality of the API, please contact us at <a href="mailto:ac@columbia.edu">ac@columbia.edu</a>. </p>
<p>The API supports GET requests; users interested in making POST requests should consider using the SWORD protocol detailed below.</p>
<p>To see an example of an AC API integration, visit <a href="https://people.climate.columbia.edu/users/profile/ruth-s-defries">Dr. Ruth S. DeFries's profile</a> in the <a href="https://www.earth.columbia.edu/users">Earth Institute Directory</a>.</p>
<p>To see an example of an AC API integration, visit <a href="https://people.climate.columbia.edu/users/profile/ruth-s-defries">Dr. Ruth S. DeFries's profile</a> in the <a href="https://people.climate.columbia.edu/users/">Columbia Climate School Staff & Affiliates Directory</a>.</p>
<p>For questions about how to integrate an API feed into your Columbia Site, please contact <a href="mailto:ac@columbia.edu">ac@columbia.edu</a>.</p>

<h2 id="oai">OAI-PMH</h2>
Expand Down
3 changes: 2 additions & 1 deletion app/views/info/faq.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,11 @@
<p>We do not require that featured partners will make contributions to the repository on a particular schedule. We welcome featured partners who are interested in how Academic Commons can help increase the impact of their research and who will provide us with feedback on their experiences with, and ideas for, the repository.</p>

<h2 id="data-storage">Data Storage</h2>

<h3>Can I use Academic Commons as the data repository for my research data?</h3>
<p>Academic Commons is committed to making research data as Findable, Accessible, Interoperable, and Reusable as possible, in accordance with the <a href="https://www.go-fair.org/fair-principles/">FAIR Principles</a>. However, Academic Commons is not a dedicated data repository, nor do staff curate submissions.</p>
<p>We are happy to discuss how Academic Commons or another repository can meet your data sharing needs. Please note that in the case of funded research, funders may have specific requirements for the repositories to which you submit. For larger datasets (over 10GB) Academic Commons is not appropriate. Consider <a href="https://research.columbia.edu/nih-policy-data-management-sharing-plan-23">these resources</a> from the Office of the Executive Vice President for Research (EVPR) when selecting a repository.</p>
<p>If you are considering Academic Commons for your research data, we strongly encourage you to contact us when you are planning your project. Email us at <a href="mailto:ac@columbia.edu">ac@columbia.edu</a>. Note: Academic Commons does not accept data that includes personally identifiable information for human subjects.</p>
<p>If you are considering Academic Commons for your research data, we strongly encourage you to contact us when you are planning your project. Email us at <a href="mailto:data-deposit@columbia.edu">data-deposit@columbia.edu</a>. Note: Academic Commons does not accept data that includes personally identifiable information for human subjects.</p>

<h3>Are there other data repositories for me to use to share my data?</h3>
<p>Yes. There are numerous data platforms that may be appropriate repositories for your data. Disciplinary repositories, when available, often have the best tools for describing your data. The Office of the Executive Vice President for Research (EVPR) provides a page listing <a href="https://research.columbia.edu/content/research-data-storage">places where Columbia researchers can share their data</a>.</p>
Expand Down
2 changes: 1 addition & 1 deletion app/views/user/my_works.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<% unless @pending_works.empty? %>
<h3>Pending Works</h3>
<table class="table small">
<table class="table small" id="pending-works-table">
<% @pending_works.each do |document| %>
<tr>
<td><%= document.title %></td>
Expand Down
2 changes: 1 addition & 1 deletion app/views/users/sessions/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
Our Sessions Controller is scoped to users (not user), hence the directory
structure. %>

<%= form_with url: (Rails.env.development? ? user_developer_omniauth_authorize_path : user_cas_omniauth_authorize_path),
<%= form_with url: (Rails.env.development? ? user_developer_uid_omniauth_authorize_path : user_columbia_cas_omniauth_authorize_path),
method: :post, data: { turbo: false }, id: 'signInForm' do |f| %>
<p>Redirecting you to be authenticated...</p>
<%= f.submit 'Sign In', style: 'display: none;', id: 'signInRedirect' %>
Expand Down
7 changes: 2 additions & 5 deletions config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -250,11 +250,8 @@
# config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'
# config.omniauth :developer, { fields: [:uid], uid_field: :uid } # TODO : These options...

if Rails.env.development?
config.omniauth :developer, fields: [:uid], uid_field: :uid
else
config.omniauth :cas, strategy_class: Omniauth::Cul::Strategies::Cas3Strategy
end
config.omniauth :columbia_cas, { label: 'Columbia SSO (CAS)' }
config.omniauth :developer_uid, { label: 'Developer UID' } if Rails.env.development?

# ==> Warden configuration
# If you want to use other strategies, that are not supported by Devise, or
Expand Down
5 changes: 5 additions & 0 deletions config/initializers/omniauth.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

# From omniauth-cul v0.3.0 Readme
# Mitigate CVE-2015-9284
OmniAuth.config.request_validation_phase = OmniAuth::AuthenticityTokenProtection.new(key: :_csrf_token)
Loading
Loading