From 568289f2df4247747e0465f238641e5648df4386 Mon Sep 17 00:00:00 2001 From: Mark Bussey Date: Fri, 8 Dec 2017 16:15:19 -0600 Subject: [PATCH 01/18] Add LDAP authentication using e-mail as the login id This commit adds the devise_ldap_authenticatable gem to support authentication via LDAP. The application already has devise installed, so you only need to run the devise_ldap_authenticatable genearator as described in https://github.com/cschiewek/devise_ldap_authenticatable#setup The committ also adds the ladle gem to provide a LDAP server which can be used in the test and development environments. It also updates Travis to start the LDAP server before running the test suite. --- Gemfile | 2 + Gemfile.lock | 9 +++++ README.md | 26 +++++++++++-- app/controllers/application_controller.rb | 3 ++ app/models/user.rb | 2 +- config/initializers/devise.rb | 11 ++++++ config/ldap.yml | 47 +++++++++++++++++++++++ config/ldap_seed_users.ldif | 34 ++++++++++++++++ lib/tasks/ladle.rake | 22 +++++++++++ 9 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 config/ldap.yml create mode 100644 config/ldap_seed_users.ldif create mode 100644 lib/tasks/ladle.rake diff --git a/Gemfile b/Gemfile index fc472087..3f9d07cb 100644 --- a/Gemfile +++ b/Gemfile @@ -69,7 +69,9 @@ gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] gem 'active_job_status', '~> 1.2.1' gem 'devise' gem 'devise-guests', '~> 0.6' +gem 'devise_ldap_authenticatable' gem 'handle-system', '0.1.1' +gem 'ladle' gem 'mysql2' gem 'react-rails' gem 'redis-activesupport', '~> 5.0.4' diff --git a/Gemfile.lock b/Gemfile.lock index 7d7ab9fe..1b7a77ff 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -229,6 +229,9 @@ GEM warden (~> 1.2.3) devise-guests (0.6.0) devise + devise_ldap_authenticatable (0.8.5) + devise (>= 3.4.1) + net-ldap (>= 0.6.0, <= 0.11) diff-lcs (1.3) docile (1.1.5) dotenv (2.2.1) @@ -459,6 +462,8 @@ GEM kaminari-core (1.0.1) kaminari_route_prefix (0.1.1) kaminari (~> 1.0) + ladle (1.0.1) + open4 (~> 1.0) launchy (2.4.3) addressable (~> 2.3) ld-patch (0.3.2) @@ -533,6 +538,7 @@ GEM nest (2.1.0) redic net-http-persistent (2.9.4) + net-ldap (0.11) net-scp (1.2.1) net-ssh (>= 2.6.5) net-ssh (4.1.0) @@ -555,6 +561,7 @@ GEM activesupport nokogiri (>= 1.4.2) solrizer (~> 3.3) + open4 (1.3.4) openseadragon (0.4.0) rails (> 3.2.0) orm_adapter (0.5.0) @@ -884,6 +891,7 @@ DEPENDENCIES database_cleaner devise devise-guests (~> 0.6) + devise_ldap_authenticatable dotenv-rails factory_girl_rails fcrepo_wrapper @@ -894,6 +902,7 @@ DEPENDENCIES hyrax (= 2.0.0) jbuilder (~> 2.5) jquery-rails + ladle listen (~> 3.0.5) mysql2 nokogiri (>= 1.8.1) diff --git a/README.md b/README.md index dc235b03..77d90d88 100644 --- a/README.md +++ b/README.md @@ -32,15 +32,34 @@ bundle exec rails db:setup bundle exec rake spec ``` +### running the development environment LDAP server +You need to start up the LDAP server using the `ladle` task and Solr, Fedora, and a webserver using the `hydra:server` task. +It's usually best to run each service in it's own terminal session. +```sh +# if you checked out new code, run the next two commands +# bundle install +# bundle exec rake db:migrate +bundle exec rake ladle #start an LDAP server in a new window +bundle exec hydra:server #start the development server, fedora, and solr in a new window +# visit http://localhost:3000 +``` + +The applicaiton is configured to use LDAP for authentication. The development and test +environments use the [ladle](https://github.com/NUBIC/ladle) gem to launch a self-contained LDAP server. +LDAP users are seeded from the file at `config/ldap_seed_users.ldif`, so you can login +using either `user@example.org` or `admin@example.org` with the password 'password'. + ### making an admin user -First, you'll need to start your development server and create a new user. +First, you'll need to start your development server and login as one of the LDAP users. +We'll assume you logged in as `admin@example.org` ```sh bundle exec rails c -> u = User.create(email: 'admin@example.org', display_name: 'Admin, Example', password: 'password') +> u = User.find_by(email: 'admin@example.org') > u.add_role('admin') > exit ``` -Now you should be able to login as `admin@example.org` with access to the administator dashboard. +If you go back and refresh your browser where `admin@example.org` is logged in, you +should now have access to the administator dashboard. ### seeding deposit types MIRA supports a number of configurable deposit types. A seed configuration is checked into the repository at @@ -53,6 +72,7 @@ If you wish to make changes to the seeds, use the "Manage Self Deposit Types" op Make any changes you want, export the configuration using the "Export Deposit Type Data" link at the bottom of the "Manage Deposit Types" view, and then check the updated deposit type configuration CSV file into the repository. + ## Re-create derivatives If you need to re-create derivatives, use these rake tasks: 1. One at a time, by id: `RAILS_ENV=production bundle exec rake derivatives:recreate_by_id[2801pg32c]` diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4163086e..1e296861 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,4 +1,7 @@ class ApplicationController < ActionController::Base + rescue_from DeviseLdapAuthenticatable::LdapException do |exception| + render text: exception, status: 500 + end helper Openseadragon::OpenseadragonHelper # Adds a few additional behaviors into the application controller include Blacklight::Controller diff --git a/app/models/user.rb b/app/models/user.rb index 28a20226..c6ee0d76 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -15,7 +15,7 @@ class User < ApplicationRecord include Blacklight::User # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable - devise :database_authenticatable, :registerable, + devise :ldap_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable ## diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 86e57ef4..3f49c940 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -1,6 +1,17 @@ # Use this hook to configure devise mailer, warden hooks and so forth. # Many of these configuration options can be set straight in your model. Devise.setup do |config| + # ==> LDAP Configuration + config.ldap_logger = true + config.ldap_create_user = true + # config.ldap_update_password = true + # config.ldap_config = "#{Rails.root}/config/ldap.yml" + # config.ldap_check_group_membership = false + # config.ldap_check_group_membership_without_admin = false + # config.ldap_check_attributes = false + # config.ldap_use_admin_to_bind = false + # config.ldap_ad_group_check = false + # The secret key used by Devise. Devise uses this key to generate # random tokens. Changing this key will render invalid all existing # confirmation, reset password and unlock tokens in the database. diff --git a/config/ldap.yml b/config/ldap.yml new file mode 100644 index 00000000..6f664f58 --- /dev/null +++ b/config/ldap.yml @@ -0,0 +1,47 @@ +## Authorizations +# Uncomment out the merging for each environment that you'd like to include. +# You can also just copy and paste the tree (do not include the "authorizations") to each +# environment if you need something different per enviornment. +authorizations: &AUTHORIZATIONS + allow_unauthenticated_bind: false + group_base: ou=groups,dc=example,dc=org + ## Requires config.ldap_check_group_membership in devise.rb be true + # Can have multiple values, must match all to be authorized + required_groups: + # If only a group name is given, membership will be checked against "uniqueMember" + - cn=admins,ou=groups,dc=example,dc=org + - cn=users,ou=groups,dc=example,dc=org + # If an array is given, the first element will be the attribute to check against, the second the group name + - ["moreMembers", "cn=users,ou=groups,dc=example,dc=org"] + ## Requires config.ldap_check_attributes in devise.rb to be true + ## Can have multiple attributes and values, must match all to be authorized + require_attribute: + objectClass: inetOrgPerson + +## Environment + +development: + host: localhost + port: 3389 + attribute: mail + base: ou=people,dc=example,dc=org + ssl: false + # <<: *AUTHORIZATIONS + +test: + host: localhost + port: 3389 + attribute: mail + base: ou=people,dc=example,dc=org + ssl: false + # <<: *AUTHORIZATIONS + +production: + host: localhost + port: 689 + attribute: mail + base: ou=people,dc=example,dc=org + admin_user: cn=admin,ou=people,dc=my_domain,dc=com + admin_password: admin_password + ssl: start_tls + # <<: *AUTHORIZATIONS diff --git a/config/ldap_seed_users.ldif b/config/ldap_seed_users.ldif new file mode 100644 index 00000000..cd116834 --- /dev/null +++ b/config/ldap_seed_users.ldif @@ -0,0 +1,34 @@ + +version: 1 + +# people.example.org +dn: ou=people,dc=example,dc=org +objectClass: top +objectClass: organizationalUnit +ou: people + +# user.people.examle.org +dn: cn=user,ou=people,dc=example,dc=org +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +sn: Ffrind +givenName: Rhyw +uid: example_user +mail: user@example.org +cn: user +userPassword: password + +# admin.people.examle.org +dn: cn=admin,ou=people,dc=example,dc=org +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +sn: Arall +givenName: Rhywun +uid: admin_user +mail: admin@example.org +cn: admin +userPassword: password diff --git a/lib/tasks/ladle.rake b/lib/tasks/ladle.rake new file mode 100644 index 00000000..e6c3e845 --- /dev/null +++ b/lib/tasks/ladle.rake @@ -0,0 +1,22 @@ +require 'ladle' + +desc 'Start a ladle server' +task :ladle do + conf_path = Rails.root.join('config') + ldap_port = Rails.application.config_for(:ldap)['port'] + + server = Ladle::Server.new( + port: ldap_port, + quiet: false, + ldif: conf_path.join('ldap_seed_users.ldif').to_s + ) + + begin + server.start + sleep + rescue Interrupt + puts ' Stopping server' + ensure + server.stop + end +end From 26800c3a5369911f2b8a888c6fb5ba36c97289f8 Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Fri, 15 Dec 2017 15:54:23 -0500 Subject: [PATCH 02/18] Add username to the user model Update User factory to match Configure Devise to user :username instead of :email for authentication --- config/initializers/devise.rb | 6 +++--- config/initializers/hyrax.rb | 4 ++-- db/migrate/20171215144758_add_username_to_users.rb | 6 ++++++ db/schema.rb | 4 +++- spec/factories/users.rb | 5 ++++- spec/models/user_spec.rb | 6 ++++++ 6 files changed, 24 insertions(+), 7 deletions(-) create mode 100644 db/migrate/20171215144758_add_username_to_users.rb diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 3f49c940..c2669655 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -45,7 +45,7 @@ # session. If you need permissions, you should implement that in a before filter. # You can also supply a hash where the value is a boolean determining whether # or not authentication should be aborted when the value is not present. - # config.authentication_keys = [:email] + config.authentication_keys = [:username] # Configure parameters from the request object used for authentication. Each entry # given should be a request method and it will automatically be passed to the @@ -57,12 +57,12 @@ # Configure which authentication keys should be case-insensitive. # These keys will be downcased upon creating or modifying a user and when used # to authenticate or find a user. Default is :email. - config.case_insensitive_keys = [:email] + config.case_insensitive_keys = [:username] # Configure which authentication keys should have whitespace stripped. # These keys will have whitespace before and after removed upon creating or # modifying a user and when used to authenticate or find a user. Default is :email. - config.strip_whitespace_keys = [:email] + config.strip_whitespace_keys = [:username] # Tell if authentication through request.params is enabled. True by default. # It can be set to an array that will enable params authentication only for the diff --git a/config/initializers/hyrax.rb b/config/initializers/hyrax.rb index 1cb032d1..285d9d65 100644 --- a/config/initializers/hyrax.rb +++ b/config/initializers/hyrax.rb @@ -120,10 +120,10 @@ # config.display_share_button_when_not_logged_in = true # The user who runs batch jobs. Update this if you aren't using emails - # config.batch_user_key = 'batchuser@example.com' + config.batch_user_key = 'batchuser' # The user who runs fixity check jobs. Update this if you aren't using emails - # config.audit_user_key = 'audituser@example.com' + config.audit_user_key = 'audituser' # # The banner image. Should be 5000px wide by 1000px tall # config.banner_image = 'https://cloud.githubusercontent.com/assets/92044/18370978/88ecac20-75f6-11e6-8399-6536640ef695.jpg' diff --git a/db/migrate/20171215144758_add_username_to_users.rb b/db/migrate/20171215144758_add_username_to_users.rb new file mode 100644 index 00000000..7ba31180 --- /dev/null +++ b/db/migrate/20171215144758_add_username_to_users.rb @@ -0,0 +1,6 @@ +class AddUsernameToUsers < ActiveRecord::Migration[5.0] + def change + add_column :users, :username, :string + add_index :users, :username, unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index feb368c0..ab115222 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20171009170516) do +ActiveRecord::Schema.define(version: 20171215144758) do create_table "batch_tasks", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t| t.string "batch_type" @@ -546,8 +546,10 @@ t.string "arkivo_subscription" t.binary "zotero_token", limit: 65535 t.string "zotero_userid" + t.string "username" t.index ["email"], name: "index_users_on_email", unique: true, using: :btree t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree + t.index ["username"], name: "index_users_on_username", unique: true, using: :btree end create_table "version_committers", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t| diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 9a57e322..1feece07 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -3,7 +3,10 @@ FactoryGirl.define do factory :user do sequence :email do |n| - "person#{User.count}_#{n}@example.com" + "#{n}#{FFaker::Internet.email}" + end + sequence :username do |n| + "#{FFaker::Internet.user_name}#{n}" end password 'password' display_name FFaker::Name.name diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 38d07063..c45b50d1 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -73,4 +73,10 @@ expect(admin_user).to be_admin end end + + describe '#username' do + it "has a username" do + expect(user.username).not_to be_blank + end + end end From e9b3700f810f0eb5e1f92affe624e31a701f6abe Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Fri, 15 Dec 2017 15:55:12 -0500 Subject: [PATCH 03/18] Update notifications to respect user_key Instead of looking up users by email, use Hydra.config.user_key_field and find_by_user_key methods so that when we update the user key things don't break. --- spec/services/hyrax/workflow/comment_notification_spec.rb | 4 ++-- spec/services/hyrax/workflow/published_notification_spec.rb | 4 ++-- spec/services/hyrax/workflow/unpublished_notification_spec.rb | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/services/hyrax/workflow/comment_notification_spec.rb b/spec/services/hyrax/workflow/comment_notification_spec.rb index f74329c5..ce44112c 100644 --- a/spec/services/hyrax/workflow/comment_notification_spec.rb +++ b/spec/services/hyrax/workflow/comment_notification_spec.rb @@ -22,13 +22,13 @@ end it "can find depositor" do expect(notification.depositor).to be_instance_of(::User) - expect(notification.depositor.email).to eq depositor.user_key + expect(notification.depositor.user_key).to eq depositor.user_key end it "can find admins" do expect(notification.admins).to be_instance_of(Array) expect(notification.admins.pluck(:id)).to contain_exactly(admin.id) end it "sends notifications to the depositor, application admins and no one else" do - expect(notification.recipients["to"].pluck(:email)).to contain_exactly(depositor.user_key, admin.user_key) + expect(notification.recipients["to"].pluck(Hydra.config.user_key_field)).to contain_exactly(depositor.user_key, admin.user_key) end end diff --git a/spec/services/hyrax/workflow/published_notification_spec.rb b/spec/services/hyrax/workflow/published_notification_spec.rb index 386302c4..d784af02 100644 --- a/spec/services/hyrax/workflow/published_notification_spec.rb +++ b/spec/services/hyrax/workflow/published_notification_spec.rb @@ -22,13 +22,13 @@ end it "can find depositor" do expect(notification.depositor).to be_instance_of(::User) - expect(notification.depositor.email).to eq depositor.user_key + expect(notification.depositor.user_key).to eq depositor.user_key end it "can find admins" do expect(notification.admins).to be_instance_of(Array) expect(notification.admins.pluck(:id)).to include(admin.id) end it "sends notifications to the depositor, application admins and no one else" do - expect(notification.recipients["to"].pluck(:email)).to contain_exactly(depositor.user_key, admin.user_key) + expect(notification.recipients["to"].pluck(Hydra.config.user_key_field)).to contain_exactly(depositor.user_key, admin.user_key) end end diff --git a/spec/services/hyrax/workflow/unpublished_notification_spec.rb b/spec/services/hyrax/workflow/unpublished_notification_spec.rb index 70692f3f..b8686e31 100644 --- a/spec/services/hyrax/workflow/unpublished_notification_spec.rb +++ b/spec/services/hyrax/workflow/unpublished_notification_spec.rb @@ -22,13 +22,13 @@ end it "can find depositor" do expect(notification.depositor).to be_instance_of(::User) - expect(notification.depositor.email).to eq depositor.user_key + expect(notification.depositor.user_key).to eq depositor.user_key end it "can find admins" do expect(notification.admins).to be_instance_of(Array) expect(notification.admins.pluck(:id)).to contain_exactly(admin.id) end it "sends notifications to application admins and no one else" do - expect(notification.recipients["to"].pluck(:email)).to contain_exactly(admin.user_key) + expect(notification.recipients["to"].pluck(Hydra.config.user_key_field)).to contain_exactly(admin.user_key) end end From 3404d1235948fe435965cc85a96f03fbdd7de4e1 Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Fri, 15 Dec 2017 16:27:09 -0500 Subject: [PATCH 04/18] Create system users by username instead of email Note we will also need to remove the password from this method if we stop storing user passwords. --- app/models/user.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/models/user.rb b/app/models/user.rb index c6ee0d76..772836bd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -56,3 +56,17 @@ def preferred_locale 'en' end end + +# Override a Hyrax class that expects to create system users with passwords +module Hyrax::User + module ClassMethods + def find_or_create_system_user(user_key) + u = ::User.find_or_create_by(username: user_key) + u.display_name = user_key + u.email = "#{user_key}@example.com" + u.password = ('a'..'z').to_a.shuffle(random: Random.new).join + u.save + u + end + end +end From 47152ce64c11ea31764801aad0930380960199d9 Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Fri, 15 Dec 2017 17:51:49 -0500 Subject: [PATCH 05/18] Use user_key instead of email in contribute controller --- app/models/forms/contribution.rb | 6 +++--- app/models/forms/generic_tisch_deposit.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/forms/contribution.rb b/app/models/forms/contribution.rb index f11d9e9b..6303b445 100644 --- a/app/models/forms/contribution.rb +++ b/app/models/forms/contribution.rb @@ -40,9 +40,9 @@ def tufts_pdf internal_note: note ) copy_attributes - add_to_collection - user = User.find_by(email: @depositor) - current_ability = ::Ability.new(user) +< add_to_collection + user = ::User.find_by_user_key(@depositor) +> current_ability = ::Ability.new(user) uploaded_file = Hyrax::UploadedFile.create(user: user, file: @attachment) attributes = { uploaded_files: [uploaded_file.id] } env = Hyrax::Actors::Environment.new(@tufts_pdf, current_ability, attributes) diff --git a/app/models/forms/generic_tisch_deposit.rb b/app/models/forms/generic_tisch_deposit.rb index 555baa90..4b9b8b9d 100644 --- a/app/models/forms/generic_tisch_deposit.rb +++ b/app/models/forms/generic_tisch_deposit.rb @@ -20,7 +20,7 @@ def tufts_pdf ) copy_attributes add_to_collection - user = User.find_by(email: @depositor) + user = ::User.find_by_user_key(@depositor) current_ability = ::Ability.new(user) uploaded_file = Hyrax::UploadedFile.create(user: user, file: @attachment) attributes = { uploaded_files: [uploaded_file.id] } From b86db5da8f3c112a52246e1b08e1a81155aa8593 Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Mon, 18 Dec 2017 14:13:33 -0500 Subject: [PATCH 06/18] Set email before save --- app/models/user.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/user.rb b/app/models/user.rb index 772836bd..8ec42272 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -55,6 +55,10 @@ def mailboxer_email(_object) def preferred_locale 'en' end + + def ldap_before_save + self.email = Devise::LDAP::Adapter.get_ldap_param(self.username,"mail").first + end end # Override a Hyrax class that expects to create system users with passwords From 68baac4f7ba4d1bbfcab6fd656b190c58b9c2eaf Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Mon, 18 Dec 2017 14:31:33 -0500 Subject: [PATCH 07/18] Log in with username --- app/views/devise/sessions/new.html.erb | 2 +- config/ldap.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 9f2265f6..969720f8 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -3,7 +3,7 @@ <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<%= f.label 'Tufts Username' %>
- <%= f.email_field :email, autofocus: true %> + <%= f.text_field :username, autofocus: true %>
diff --git a/config/ldap.yml b/config/ldap.yml index 6f664f58..bc733047 100644 --- a/config/ldap.yml +++ b/config/ldap.yml @@ -23,7 +23,7 @@ authorizations: &AUTHORIZATIONS development: host: localhost port: 3389 - attribute: mail + attribute: cn base: ou=people,dc=example,dc=org ssl: false # <<: *AUTHORIZATIONS @@ -31,7 +31,7 @@ development: test: host: localhost port: 3389 - attribute: mail + attribute: cn base: ou=people,dc=example,dc=org ssl: false # <<: *AUTHORIZATIONS @@ -39,7 +39,7 @@ test: production: host: localhost port: 689 - attribute: mail + attribute: cn base: ou=people,dc=example,dc=org admin_user: cn=admin,ou=people,dc=my_domain,dc=com admin_password: admin_password From e0abbf30716417b193ffafd8c95c51fb30e14878 Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Mon, 18 Dec 2017 15:00:52 -0500 Subject: [PATCH 08/18] Define Tufts specific LDAP display name field --- app/models/forms/contribution.rb | 4 ++-- app/models/user.rb | 3 ++- config/ldap_seed_users.ldif | 4 ++++ config/tufts_schema.ldif | 23 +++++++++++++++++++++++ lib/tasks/ladle.rake | 1 + 5 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 config/tufts_schema.ldif diff --git a/app/models/forms/contribution.rb b/app/models/forms/contribution.rb index 6303b445..f6a2164e 100644 --- a/app/models/forms/contribution.rb +++ b/app/models/forms/contribution.rb @@ -40,9 +40,9 @@ def tufts_pdf internal_note: note ) copy_attributes -< add_to_collection + add_to_collection user = ::User.find_by_user_key(@depositor) -> current_ability = ::Ability.new(user) + current_ability = ::Ability.new(user) uploaded_file = Hyrax::UploadedFile.create(user: user, file: @attachment) attributes = { uploaded_files: [uploaded_file.id] } env = Hyrax::Actors::Environment.new(@tufts_pdf, current_ability, attributes) diff --git a/app/models/user.rb b/app/models/user.rb index 8ec42272..7c97a192 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -57,7 +57,8 @@ def preferred_locale end def ldap_before_save - self.email = Devise::LDAP::Adapter.get_ldap_param(self.username,"mail").first + self.email = Devise::LDAP::Adapter.get_ldap_param(username, "mail").first + self.display_name = Devise::LDAP::Adapter.get_ldap_param(username, "tuftsEduDisplayNameLF").first end end diff --git a/config/ldap_seed_users.ldif b/config/ldap_seed_users.ldif index cd116834..8a6bb17c 100644 --- a/config/ldap_seed_users.ldif +++ b/config/ldap_seed_users.ldif @@ -13,6 +13,8 @@ objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson +objectClass: tuftsEduPerson +tuftsEduDisplayNameLF: Ffrind, Rhyw sn: Ffrind givenName: Rhyw uid: example_user @@ -26,6 +28,8 @@ objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson +objectClass: tuftsEduPerson +tuftsEduDisplayNameLF: Arall, Rhywun sn: Arall givenName: Rhywun uid: admin_user diff --git a/config/tufts_schema.ldif b/config/tufts_schema.ldif new file mode 100644 index 00000000..d1b42a68 --- /dev/null +++ b/config/tufts_schema.ldif @@ -0,0 +1,23 @@ +version: 1 + +dn: m-oid=1.3.6.1.4.1.6940.1.1.1.1.2.1.1.47,ou=attributeTypes,cn=other,ou=schema +objectClass: metaAttributeType +objectClass: metaTop +objectClass: top +m-collective: FALSE +m-description: 'displayName in last, first form' +m-name: tuftsEduDisplayNameLF +m-syntax: 1.3.6.1.4.1.1466.115.121.1.15 +m-usage: USER_APPLICATIONS +m-oid: 1.3.6.1.4.1.6940.1.1.1.1.2.1.1.47 + +dn: m-oid=1.3.6.1.4.1.6940.1.1.1.1.2.1.2.1,ou=objectClasses,cn=other,ou=schema +objectClass: metaObjectClass +objectClass: metaTop +objectClass: top +m-description: Tufts schema extensions for people directory entries +m-may: tuftsEduDisplayNameLF +m-supobjectclass: top +m-name: tuftsEduPerson +m-oid: 1.3.6.1.4.1.6940.1.1.1.1.2.1.2.1 +m-typeobjectclass: ABSTRACT diff --git a/lib/tasks/ladle.rake b/lib/tasks/ladle.rake index e6c3e845..20030522 100644 --- a/lib/tasks/ladle.rake +++ b/lib/tasks/ladle.rake @@ -8,6 +8,7 @@ task :ladle do server = Ladle::Server.new( port: ldap_port, quiet: false, + custom_schemas: conf_path.join('tufts_schema.ldif').to_s, ldif: conf_path.join('ldap_seed_users.ldif').to_s ) From a28272b195e5f9d859f6372ffa1e96e8f4969e48 Mon Sep 17 00:00:00 2001 From: Mark Bussey Date: Fri, 8 Dec 2017 16:15:19 -0600 Subject: [PATCH 09/18] Add LDAP authentication using e-mail as the login id This commit adds the devise_ldap_authenticatable gem to support authentication via LDAP. The application already has devise installed, so you only need to run the devise_ldap_authenticatable genearator as described in https://github.com/cschiewek/devise_ldap_authenticatable#setup The committ also adds the ladle gem to provide a LDAP server which can be used in the test and development environments. It also updates Travis to start the LDAP server before running the test suite. --- Gemfile | 2 + Gemfile.lock | 9 +++++ README.md | 26 +++++++++++-- app/controllers/application_controller.rb | 3 ++ app/models/user.rb | 2 +- config/initializers/devise.rb | 11 ++++++ config/ldap.yml | 47 +++++++++++++++++++++++ config/ldap_seed_users.ldif | 34 ++++++++++++++++ lib/tasks/ladle.rake | 22 +++++++++++ 9 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 config/ldap.yml create mode 100644 config/ldap_seed_users.ldif create mode 100644 lib/tasks/ladle.rake diff --git a/Gemfile b/Gemfile index beb2d9f3..61e0cc42 100644 --- a/Gemfile +++ b/Gemfile @@ -69,7 +69,9 @@ gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] gem 'active_job_status', '~> 1.2.1' gem 'devise' gem 'devise-guests', '~> 0.6' +gem 'devise_ldap_authenticatable' gem 'handle-system', '0.1.1' +gem 'ladle' gem 'mysql2' gem 'react-rails' gem 'redis-activesupport', '~> 5.0.4' diff --git a/Gemfile.lock b/Gemfile.lock index cf79ee7d..71556506 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -229,6 +229,9 @@ GEM warden (~> 1.2.3) devise-guests (0.6.0) devise + devise_ldap_authenticatable (0.8.5) + devise (>= 3.4.1) + net-ldap (>= 0.6.0, <= 0.11) diff-lcs (1.3) docile (1.1.5) dotenv (2.2.1) @@ -459,6 +462,8 @@ GEM kaminari-core (1.0.1) kaminari_route_prefix (0.1.1) kaminari (~> 1.0) + ladle (1.0.1) + open4 (~> 1.0) launchy (2.4.3) addressable (~> 2.3) ld-patch (0.3.2) @@ -533,6 +538,7 @@ GEM nest (2.1.0) redic net-http-persistent (2.9.4) + net-ldap (0.11) net-scp (1.2.1) net-ssh (>= 2.6.5) net-ssh (4.1.0) @@ -555,6 +561,7 @@ GEM activesupport nokogiri (>= 1.4.2) solrizer (~> 3.3) + open4 (1.3.4) openseadragon (0.4.0) rails (> 3.2.0) orm_adapter (0.5.0) @@ -884,6 +891,7 @@ DEPENDENCIES database_cleaner devise devise-guests (~> 0.6) + devise_ldap_authenticatable dotenv-rails factory_girl_rails fcrepo_wrapper @@ -894,6 +902,7 @@ DEPENDENCIES hyrax (= 2.0.0) jbuilder (~> 2.5) jquery-rails + ladle listen (~> 3.0.5) mysql2 nokogiri (>= 1.8.1) diff --git a/README.md b/README.md index dc235b03..77d90d88 100644 --- a/README.md +++ b/README.md @@ -32,15 +32,34 @@ bundle exec rails db:setup bundle exec rake spec ``` +### running the development environment LDAP server +You need to start up the LDAP server using the `ladle` task and Solr, Fedora, and a webserver using the `hydra:server` task. +It's usually best to run each service in it's own terminal session. +```sh +# if you checked out new code, run the next two commands +# bundle install +# bundle exec rake db:migrate +bundle exec rake ladle #start an LDAP server in a new window +bundle exec hydra:server #start the development server, fedora, and solr in a new window +# visit http://localhost:3000 +``` + +The applicaiton is configured to use LDAP for authentication. The development and test +environments use the [ladle](https://github.com/NUBIC/ladle) gem to launch a self-contained LDAP server. +LDAP users are seeded from the file at `config/ldap_seed_users.ldif`, so you can login +using either `user@example.org` or `admin@example.org` with the password 'password'. + ### making an admin user -First, you'll need to start your development server and create a new user. +First, you'll need to start your development server and login as one of the LDAP users. +We'll assume you logged in as `admin@example.org` ```sh bundle exec rails c -> u = User.create(email: 'admin@example.org', display_name: 'Admin, Example', password: 'password') +> u = User.find_by(email: 'admin@example.org') > u.add_role('admin') > exit ``` -Now you should be able to login as `admin@example.org` with access to the administator dashboard. +If you go back and refresh your browser where `admin@example.org` is logged in, you +should now have access to the administator dashboard. ### seeding deposit types MIRA supports a number of configurable deposit types. A seed configuration is checked into the repository at @@ -53,6 +72,7 @@ If you wish to make changes to the seeds, use the "Manage Self Deposit Types" op Make any changes you want, export the configuration using the "Export Deposit Type Data" link at the bottom of the "Manage Deposit Types" view, and then check the updated deposit type configuration CSV file into the repository. + ## Re-create derivatives If you need to re-create derivatives, use these rake tasks: 1. One at a time, by id: `RAILS_ENV=production bundle exec rake derivatives:recreate_by_id[2801pg32c]` diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 4163086e..1e296861 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,4 +1,7 @@ class ApplicationController < ActionController::Base + rescue_from DeviseLdapAuthenticatable::LdapException do |exception| + render text: exception, status: 500 + end helper Openseadragon::OpenseadragonHelper # Adds a few additional behaviors into the application controller include Blacklight::Controller diff --git a/app/models/user.rb b/app/models/user.rb index 28a20226..c6ee0d76 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -15,7 +15,7 @@ class User < ApplicationRecord include Blacklight::User # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable and :omniauthable - devise :database_authenticatable, :registerable, + devise :ldap_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable ## diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 86e57ef4..3f49c940 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -1,6 +1,17 @@ # Use this hook to configure devise mailer, warden hooks and so forth. # Many of these configuration options can be set straight in your model. Devise.setup do |config| + # ==> LDAP Configuration + config.ldap_logger = true + config.ldap_create_user = true + # config.ldap_update_password = true + # config.ldap_config = "#{Rails.root}/config/ldap.yml" + # config.ldap_check_group_membership = false + # config.ldap_check_group_membership_without_admin = false + # config.ldap_check_attributes = false + # config.ldap_use_admin_to_bind = false + # config.ldap_ad_group_check = false + # The secret key used by Devise. Devise uses this key to generate # random tokens. Changing this key will render invalid all existing # confirmation, reset password and unlock tokens in the database. diff --git a/config/ldap.yml b/config/ldap.yml new file mode 100644 index 00000000..6f664f58 --- /dev/null +++ b/config/ldap.yml @@ -0,0 +1,47 @@ +## Authorizations +# Uncomment out the merging for each environment that you'd like to include. +# You can also just copy and paste the tree (do not include the "authorizations") to each +# environment if you need something different per enviornment. +authorizations: &AUTHORIZATIONS + allow_unauthenticated_bind: false + group_base: ou=groups,dc=example,dc=org + ## Requires config.ldap_check_group_membership in devise.rb be true + # Can have multiple values, must match all to be authorized + required_groups: + # If only a group name is given, membership will be checked against "uniqueMember" + - cn=admins,ou=groups,dc=example,dc=org + - cn=users,ou=groups,dc=example,dc=org + # If an array is given, the first element will be the attribute to check against, the second the group name + - ["moreMembers", "cn=users,ou=groups,dc=example,dc=org"] + ## Requires config.ldap_check_attributes in devise.rb to be true + ## Can have multiple attributes and values, must match all to be authorized + require_attribute: + objectClass: inetOrgPerson + +## Environment + +development: + host: localhost + port: 3389 + attribute: mail + base: ou=people,dc=example,dc=org + ssl: false + # <<: *AUTHORIZATIONS + +test: + host: localhost + port: 3389 + attribute: mail + base: ou=people,dc=example,dc=org + ssl: false + # <<: *AUTHORIZATIONS + +production: + host: localhost + port: 689 + attribute: mail + base: ou=people,dc=example,dc=org + admin_user: cn=admin,ou=people,dc=my_domain,dc=com + admin_password: admin_password + ssl: start_tls + # <<: *AUTHORIZATIONS diff --git a/config/ldap_seed_users.ldif b/config/ldap_seed_users.ldif new file mode 100644 index 00000000..cd116834 --- /dev/null +++ b/config/ldap_seed_users.ldif @@ -0,0 +1,34 @@ + +version: 1 + +# people.example.org +dn: ou=people,dc=example,dc=org +objectClass: top +objectClass: organizationalUnit +ou: people + +# user.people.examle.org +dn: cn=user,ou=people,dc=example,dc=org +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +sn: Ffrind +givenName: Rhyw +uid: example_user +mail: user@example.org +cn: user +userPassword: password + +# admin.people.examle.org +dn: cn=admin,ou=people,dc=example,dc=org +objectClass: top +objectClass: person +objectClass: organizationalPerson +objectClass: inetOrgPerson +sn: Arall +givenName: Rhywun +uid: admin_user +mail: admin@example.org +cn: admin +userPassword: password diff --git a/lib/tasks/ladle.rake b/lib/tasks/ladle.rake new file mode 100644 index 00000000..e6c3e845 --- /dev/null +++ b/lib/tasks/ladle.rake @@ -0,0 +1,22 @@ +require 'ladle' + +desc 'Start a ladle server' +task :ladle do + conf_path = Rails.root.join('config') + ldap_port = Rails.application.config_for(:ldap)['port'] + + server = Ladle::Server.new( + port: ldap_port, + quiet: false, + ldif: conf_path.join('ldap_seed_users.ldif').to_s + ) + + begin + server.start + sleep + rescue Interrupt + puts ' Stopping server' + ensure + server.stop + end +end From 9cf239c155499c7a668cb2fb93f055f874ff01ee Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Fri, 15 Dec 2017 15:54:23 -0500 Subject: [PATCH 10/18] Add username to the user model Update User factory to match Configure Devise to user :username instead of :email for authentication --- config/initializers/devise.rb | 6 +++--- config/initializers/hyrax.rb | 4 ++-- db/migrate/20171215144758_add_username_to_users.rb | 6 ++++++ db/schema.rb | 4 +++- spec/factories/users.rb | 5 ++++- spec/models/user_spec.rb | 6 ++++++ 6 files changed, 24 insertions(+), 7 deletions(-) create mode 100644 db/migrate/20171215144758_add_username_to_users.rb diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 3f49c940..c2669655 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -45,7 +45,7 @@ # session. If you need permissions, you should implement that in a before filter. # You can also supply a hash where the value is a boolean determining whether # or not authentication should be aborted when the value is not present. - # config.authentication_keys = [:email] + config.authentication_keys = [:username] # Configure parameters from the request object used for authentication. Each entry # given should be a request method and it will automatically be passed to the @@ -57,12 +57,12 @@ # Configure which authentication keys should be case-insensitive. # These keys will be downcased upon creating or modifying a user and when used # to authenticate or find a user. Default is :email. - config.case_insensitive_keys = [:email] + config.case_insensitive_keys = [:username] # Configure which authentication keys should have whitespace stripped. # These keys will have whitespace before and after removed upon creating or # modifying a user and when used to authenticate or find a user. Default is :email. - config.strip_whitespace_keys = [:email] + config.strip_whitespace_keys = [:username] # Tell if authentication through request.params is enabled. True by default. # It can be set to an array that will enable params authentication only for the diff --git a/config/initializers/hyrax.rb b/config/initializers/hyrax.rb index f9ee27d4..f4957079 100644 --- a/config/initializers/hyrax.rb +++ b/config/initializers/hyrax.rb @@ -115,10 +115,10 @@ # config.display_share_button_when_not_logged_in = true # The user who runs batch jobs. Update this if you aren't using emails - # config.batch_user_key = 'batchuser@example.com' + config.batch_user_key = 'batchuser' # The user who runs fixity check jobs. Update this if you aren't using emails - # config.audit_user_key = 'audituser@example.com' + config.audit_user_key = 'audituser' # # The banner image. Should be 5000px wide by 1000px tall # config.banner_image = 'https://cloud.githubusercontent.com/assets/92044/18370978/88ecac20-75f6-11e6-8399-6536640ef695.jpg' diff --git a/db/migrate/20171215144758_add_username_to_users.rb b/db/migrate/20171215144758_add_username_to_users.rb new file mode 100644 index 00000000..7ba31180 --- /dev/null +++ b/db/migrate/20171215144758_add_username_to_users.rb @@ -0,0 +1,6 @@ +class AddUsernameToUsers < ActiveRecord::Migration[5.0] + def change + add_column :users, :username, :string + add_index :users, :username, unique: true + end +end diff --git a/db/schema.rb b/db/schema.rb index feb368c0..ab115222 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20171009170516) do +ActiveRecord::Schema.define(version: 20171215144758) do create_table "batch_tasks", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t| t.string "batch_type" @@ -546,8 +546,10 @@ t.string "arkivo_subscription" t.binary "zotero_token", limit: 65535 t.string "zotero_userid" + t.string "username" t.index ["email"], name: "index_users_on_email", unique: true, using: :btree t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree + t.index ["username"], name: "index_users_on_username", unique: true, using: :btree end create_table "version_committers", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t| diff --git a/spec/factories/users.rb b/spec/factories/users.rb index 9a57e322..1feece07 100644 --- a/spec/factories/users.rb +++ b/spec/factories/users.rb @@ -3,7 +3,10 @@ FactoryGirl.define do factory :user do sequence :email do |n| - "person#{User.count}_#{n}@example.com" + "#{n}#{FFaker::Internet.email}" + end + sequence :username do |n| + "#{FFaker::Internet.user_name}#{n}" end password 'password' display_name FFaker::Name.name diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 38d07063..c45b50d1 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -73,4 +73,10 @@ expect(admin_user).to be_admin end end + + describe '#username' do + it "has a username" do + expect(user.username).not_to be_blank + end + end end From e966cb2aaa9c477e7f8cfc21f3e0798eceb23e58 Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Fri, 15 Dec 2017 15:55:12 -0500 Subject: [PATCH 11/18] Update notifications to respect user_key Instead of looking up users by email, use Hydra.config.user_key_field and find_by_user_key methods so that when we update the user key things don't break. --- spec/services/hyrax/workflow/comment_notification_spec.rb | 4 ++-- spec/services/hyrax/workflow/published_notification_spec.rb | 4 ++-- spec/services/hyrax/workflow/unpublished_notification_spec.rb | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/services/hyrax/workflow/comment_notification_spec.rb b/spec/services/hyrax/workflow/comment_notification_spec.rb index f74329c5..ce44112c 100644 --- a/spec/services/hyrax/workflow/comment_notification_spec.rb +++ b/spec/services/hyrax/workflow/comment_notification_spec.rb @@ -22,13 +22,13 @@ end it "can find depositor" do expect(notification.depositor).to be_instance_of(::User) - expect(notification.depositor.email).to eq depositor.user_key + expect(notification.depositor.user_key).to eq depositor.user_key end it "can find admins" do expect(notification.admins).to be_instance_of(Array) expect(notification.admins.pluck(:id)).to contain_exactly(admin.id) end it "sends notifications to the depositor, application admins and no one else" do - expect(notification.recipients["to"].pluck(:email)).to contain_exactly(depositor.user_key, admin.user_key) + expect(notification.recipients["to"].pluck(Hydra.config.user_key_field)).to contain_exactly(depositor.user_key, admin.user_key) end end diff --git a/spec/services/hyrax/workflow/published_notification_spec.rb b/spec/services/hyrax/workflow/published_notification_spec.rb index 386302c4..d784af02 100644 --- a/spec/services/hyrax/workflow/published_notification_spec.rb +++ b/spec/services/hyrax/workflow/published_notification_spec.rb @@ -22,13 +22,13 @@ end it "can find depositor" do expect(notification.depositor).to be_instance_of(::User) - expect(notification.depositor.email).to eq depositor.user_key + expect(notification.depositor.user_key).to eq depositor.user_key end it "can find admins" do expect(notification.admins).to be_instance_of(Array) expect(notification.admins.pluck(:id)).to include(admin.id) end it "sends notifications to the depositor, application admins and no one else" do - expect(notification.recipients["to"].pluck(:email)).to contain_exactly(depositor.user_key, admin.user_key) + expect(notification.recipients["to"].pluck(Hydra.config.user_key_field)).to contain_exactly(depositor.user_key, admin.user_key) end end diff --git a/spec/services/hyrax/workflow/unpublished_notification_spec.rb b/spec/services/hyrax/workflow/unpublished_notification_spec.rb index 70692f3f..b8686e31 100644 --- a/spec/services/hyrax/workflow/unpublished_notification_spec.rb +++ b/spec/services/hyrax/workflow/unpublished_notification_spec.rb @@ -22,13 +22,13 @@ end it "can find depositor" do expect(notification.depositor).to be_instance_of(::User) - expect(notification.depositor.email).to eq depositor.user_key + expect(notification.depositor.user_key).to eq depositor.user_key end it "can find admins" do expect(notification.admins).to be_instance_of(Array) expect(notification.admins.pluck(:id)).to contain_exactly(admin.id) end it "sends notifications to application admins and no one else" do - expect(notification.recipients["to"].pluck(:email)).to contain_exactly(admin.user_key) + expect(notification.recipients["to"].pluck(Hydra.config.user_key_field)).to contain_exactly(admin.user_key) end end From 8a540d2976ae8dfdbb31924dd6e69db379617842 Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Fri, 15 Dec 2017 16:27:09 -0500 Subject: [PATCH 12/18] Create system users by username instead of email Note we will also need to remove the password from this method if we stop storing user passwords. --- app/models/user.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/app/models/user.rb b/app/models/user.rb index c6ee0d76..772836bd 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -56,3 +56,17 @@ def preferred_locale 'en' end end + +# Override a Hyrax class that expects to create system users with passwords +module Hyrax::User + module ClassMethods + def find_or_create_system_user(user_key) + u = ::User.find_or_create_by(username: user_key) + u.display_name = user_key + u.email = "#{user_key}@example.com" + u.password = ('a'..'z').to_a.shuffle(random: Random.new).join + u.save + u + end + end +end From 158af6313cf94f908d8ec79fb2442a3eb3d6fc39 Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Fri, 15 Dec 2017 17:51:49 -0500 Subject: [PATCH 13/18] Use user_key instead of email in contribute controller --- app/models/forms/contribution.rb | 6 +++--- app/models/forms/generic_tisch_deposit.rb | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/forms/contribution.rb b/app/models/forms/contribution.rb index f11d9e9b..6303b445 100644 --- a/app/models/forms/contribution.rb +++ b/app/models/forms/contribution.rb @@ -40,9 +40,9 @@ def tufts_pdf internal_note: note ) copy_attributes - add_to_collection - user = User.find_by(email: @depositor) - current_ability = ::Ability.new(user) +< add_to_collection + user = ::User.find_by_user_key(@depositor) +> current_ability = ::Ability.new(user) uploaded_file = Hyrax::UploadedFile.create(user: user, file: @attachment) attributes = { uploaded_files: [uploaded_file.id] } env = Hyrax::Actors::Environment.new(@tufts_pdf, current_ability, attributes) diff --git a/app/models/forms/generic_tisch_deposit.rb b/app/models/forms/generic_tisch_deposit.rb index 555baa90..4b9b8b9d 100644 --- a/app/models/forms/generic_tisch_deposit.rb +++ b/app/models/forms/generic_tisch_deposit.rb @@ -20,7 +20,7 @@ def tufts_pdf ) copy_attributes add_to_collection - user = User.find_by(email: @depositor) + user = ::User.find_by_user_key(@depositor) current_ability = ::Ability.new(user) uploaded_file = Hyrax::UploadedFile.create(user: user, file: @attachment) attributes = { uploaded_files: [uploaded_file.id] } From ba9af0c7dc7201ede47dee2f28c449e7e6b70c44 Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Mon, 18 Dec 2017 14:13:33 -0500 Subject: [PATCH 14/18] Set email before save --- app/models/user.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/models/user.rb b/app/models/user.rb index 772836bd..8ec42272 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -55,6 +55,10 @@ def mailboxer_email(_object) def preferred_locale 'en' end + + def ldap_before_save + self.email = Devise::LDAP::Adapter.get_ldap_param(self.username,"mail").first + end end # Override a Hyrax class that expects to create system users with passwords From cbc8a2bd3c0fbb5bc6974d02eeb958ef60e7338e Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Mon, 18 Dec 2017 14:31:33 -0500 Subject: [PATCH 15/18] Log in with username --- app/views/devise/sessions/new.html.erb | 2 +- config/ldap.yml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb index 9f2265f6..969720f8 100644 --- a/app/views/devise/sessions/new.html.erb +++ b/app/views/devise/sessions/new.html.erb @@ -3,7 +3,7 @@ <%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<%= f.label 'Tufts Username' %>
- <%= f.email_field :email, autofocus: true %> + <%= f.text_field :username, autofocus: true %>
diff --git a/config/ldap.yml b/config/ldap.yml index 6f664f58..bc733047 100644 --- a/config/ldap.yml +++ b/config/ldap.yml @@ -23,7 +23,7 @@ authorizations: &AUTHORIZATIONS development: host: localhost port: 3389 - attribute: mail + attribute: cn base: ou=people,dc=example,dc=org ssl: false # <<: *AUTHORIZATIONS @@ -31,7 +31,7 @@ development: test: host: localhost port: 3389 - attribute: mail + attribute: cn base: ou=people,dc=example,dc=org ssl: false # <<: *AUTHORIZATIONS @@ -39,7 +39,7 @@ test: production: host: localhost port: 689 - attribute: mail + attribute: cn base: ou=people,dc=example,dc=org admin_user: cn=admin,ou=people,dc=my_domain,dc=com admin_password: admin_password From 98f5ac698afb328bd2c2380268f40a337fff4762 Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Mon, 18 Dec 2017 15:00:52 -0500 Subject: [PATCH 16/18] Define Tufts specific LDAP display name field --- app/models/forms/contribution.rb | 4 ++-- app/models/user.rb | 3 ++- config/ldap_seed_users.ldif | 4 ++++ config/tufts_schema.ldif | 23 +++++++++++++++++++++++ lib/tasks/ladle.rake | 1 + 5 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 config/tufts_schema.ldif diff --git a/app/models/forms/contribution.rb b/app/models/forms/contribution.rb index 6303b445..f6a2164e 100644 --- a/app/models/forms/contribution.rb +++ b/app/models/forms/contribution.rb @@ -40,9 +40,9 @@ def tufts_pdf internal_note: note ) copy_attributes -< add_to_collection + add_to_collection user = ::User.find_by_user_key(@depositor) -> current_ability = ::Ability.new(user) + current_ability = ::Ability.new(user) uploaded_file = Hyrax::UploadedFile.create(user: user, file: @attachment) attributes = { uploaded_files: [uploaded_file.id] } env = Hyrax::Actors::Environment.new(@tufts_pdf, current_ability, attributes) diff --git a/app/models/user.rb b/app/models/user.rb index 8ec42272..7c97a192 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -57,7 +57,8 @@ def preferred_locale end def ldap_before_save - self.email = Devise::LDAP::Adapter.get_ldap_param(self.username,"mail").first + self.email = Devise::LDAP::Adapter.get_ldap_param(username, "mail").first + self.display_name = Devise::LDAP::Adapter.get_ldap_param(username, "tuftsEduDisplayNameLF").first end end diff --git a/config/ldap_seed_users.ldif b/config/ldap_seed_users.ldif index cd116834..8a6bb17c 100644 --- a/config/ldap_seed_users.ldif +++ b/config/ldap_seed_users.ldif @@ -13,6 +13,8 @@ objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson +objectClass: tuftsEduPerson +tuftsEduDisplayNameLF: Ffrind, Rhyw sn: Ffrind givenName: Rhyw uid: example_user @@ -26,6 +28,8 @@ objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson +objectClass: tuftsEduPerson +tuftsEduDisplayNameLF: Arall, Rhywun sn: Arall givenName: Rhywun uid: admin_user diff --git a/config/tufts_schema.ldif b/config/tufts_schema.ldif new file mode 100644 index 00000000..d1b42a68 --- /dev/null +++ b/config/tufts_schema.ldif @@ -0,0 +1,23 @@ +version: 1 + +dn: m-oid=1.3.6.1.4.1.6940.1.1.1.1.2.1.1.47,ou=attributeTypes,cn=other,ou=schema +objectClass: metaAttributeType +objectClass: metaTop +objectClass: top +m-collective: FALSE +m-description: 'displayName in last, first form' +m-name: tuftsEduDisplayNameLF +m-syntax: 1.3.6.1.4.1.1466.115.121.1.15 +m-usage: USER_APPLICATIONS +m-oid: 1.3.6.1.4.1.6940.1.1.1.1.2.1.1.47 + +dn: m-oid=1.3.6.1.4.1.6940.1.1.1.1.2.1.2.1,ou=objectClasses,cn=other,ou=schema +objectClass: metaObjectClass +objectClass: metaTop +objectClass: top +m-description: Tufts schema extensions for people directory entries +m-may: tuftsEduDisplayNameLF +m-supobjectclass: top +m-name: tuftsEduPerson +m-oid: 1.3.6.1.4.1.6940.1.1.1.1.2.1.2.1 +m-typeobjectclass: ABSTRACT diff --git a/lib/tasks/ladle.rake b/lib/tasks/ladle.rake index e6c3e845..20030522 100644 --- a/lib/tasks/ladle.rake +++ b/lib/tasks/ladle.rake @@ -8,6 +8,7 @@ task :ladle do server = Ladle::Server.new( port: ldap_port, quiet: false, + custom_schemas: conf_path.join('tufts_schema.ldif').to_s, ldif: conf_path.join('ldap_seed_users.ldif').to_s ) From 8e240764d57c143e6080e8b0cbd320264aed4810 Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Sat, 6 Jan 2018 15:00:10 -0500 Subject: [PATCH 17/18] Fixup to work with latest master branch --- README.md | 14 +++++++------- .../hyrax/workflow/mira_workflow_notification.rb | 2 +- spec/features/login_out_spec.rb | 7 +++++-- spec/features/publication_workflow_spec.rb | 6 ------ 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 77d90d88..370d6b57 100644 --- a/README.md +++ b/README.md @@ -44,22 +44,23 @@ bundle exec hydra:server #start the development server, fedora, and solr in a # visit http://localhost:3000 ``` -The applicaiton is configured to use LDAP for authentication. The development and test +The application is configured to use LDAP for authentication. The development and test environments use the [ladle](https://github.com/NUBIC/ladle) gem to launch a self-contained LDAP server. LDAP users are seeded from the file at `config/ldap_seed_users.ldif`, so you can login -using either `user@example.org` or `admin@example.org` with the password 'password'. +using either `user` or `admin` with the password 'password'. Note that the system is configured to expect +a username, not an email address. ### making an admin user First, you'll need to start your development server and login as one of the LDAP users. -We'll assume you logged in as `admin@example.org` +We'll assume you logged in as `admin` ```sh bundle exec rails c -> u = User.find_by(email: 'admin@example.org') +> u = User.find_by_user_key('admin') > u.add_role('admin') > exit ``` -If you go back and refresh your browser where `admin@example.org` is logged in, you -should now have access to the administator dashboard. +If you go back and refresh your browser where `admin` is logged in, you +should now have access to the administrator dashboard. ### seeding deposit types MIRA supports a number of configurable deposit types. A seed configuration is checked into the repository at @@ -141,4 +142,3 @@ Notifications are defined in `app/services/hyrax/workflow`. There are three kind The `/contribute` forms deposit works into specific collections. In order to ensure that the expected collections exist, they are created at application deploy time and (if necessary) at deposit time via the `Tufts::ContributeCollections` class. To change the names or identifiers of these Collection objects, edit the `app/lib/tufts/contribute_collections.rb` file. To create the collections explicitly, run `rake tufts:create_contribute_collections`. - diff --git a/app/services/hyrax/workflow/mira_workflow_notification.rb b/app/services/hyrax/workflow/mira_workflow_notification.rb index 570c32a8..7279515f 100644 --- a/app/services/hyrax/workflow/mira_workflow_notification.rb +++ b/app/services/hyrax/workflow/mira_workflow_notification.rb @@ -20,7 +20,7 @@ def admins # The Hyrax::User who desposited the work # @return [Hyrax::User] def depositor - ::User.find_by(email: document.depositor) + ::User.find_by_user_key(document.depositor) end ## diff --git a/spec/features/login_out_spec.rb b/spec/features/login_out_spec.rb index 41590a35..ee01c171 100644 --- a/spec/features/login_out_spec.rb +++ b/spec/features/login_out_spec.rb @@ -6,14 +6,17 @@ context 'logging in' do scenario 'provide a login and password' do - u = User.create(email: 'admin@example.org', display_name: 'Admin, Example', password: 'password') + skip "This test will only work if Ladle (or other LDAP) is running. Disabled for CI." + # It's a good way to test that LDAP authentication is working as expected, + # but we don't need to load LDAP auth every time we run our CI tests. + u = User.create(email: 'admin@example.org', username: 'admin', display_name: 'Admin, Example', password: 'password') u.add_role('admin') u.save visit '/dashboard' expect(current_path).to eq "/contribute" find('a.btn-primary').click expect(current_path).to eq "/users/sign_in" - fill_in 'user_email', with: u.user_key + fill_in 'user_username', with: u.user_key fill_in 'user_password', with: u.password click_on 'Log in' expect(current_path).to eq "/dashboard" diff --git a/spec/features/publication_workflow_spec.rb b/spec/features/publication_workflow_spec.rb index d1ebefaa..1628a799 100644 --- a/spec/features/publication_workflow_spec.rb +++ b/spec/features/publication_workflow_spec.rb @@ -69,12 +69,6 @@ visit("/notifications") expect(page).to have_content "Comment about #{work.title.first}" - # Check notifications for depositor again - logout - login_as depositing_user - visit("/notifications") - expect(page).to have_content "#{work.title.first} (#{work.id}) has been published by #{publishing_user.display_name} (#{publishing_user.user_key}). Published in publication_workflow_spec.rb" - # After publication, an admin can unpublish a work. Tufts::WorkflowStatus.unpublish(work: work, current_user: publishing_user, comment: "Unpublished in publication_workflow_spec.rb") expect(work.to_sipity_entity.reload.workflow_state_name).to eq "unpublished" From eee9ab04fedf8c68cdaa44455a1b457f351c20fb Mon Sep 17 00:00:00 2001 From: Bess Sadler Date: Sat, 6 Jan 2018 15:03:00 -0500 Subject: [PATCH 18/18] Fix README --- README.md | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/README.md b/README.md index 83e5538c..370d6b57 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,6 @@ bundle exec hydra:server #start the development server, fedora, and solr in a # visit http://localhost:3000 ``` -<<<<<<< HEAD The application is configured to use LDAP for authentication. The development and test environments use the [ladle](https://github.com/NUBIC/ladle) gem to launch a self-contained LDAP server. LDAP users are seeded from the file at `config/ldap_seed_users.ldif`, so you can login @@ -62,24 +61,6 @@ bundle exec rails c ``` If you go back and refresh your browser where `admin` is logged in, you should now have access to the administrator dashboard. -======= -The applicaiton is configured to use LDAP for authentication. The development and test -environments use the [ladle](https://github.com/NUBIC/ladle) gem to launch a self-contained LDAP server. -LDAP users are seeded from the file at `config/ldap_seed_users.ldif`, so you can login -using either `user@example.org` or `admin@example.org` with the password 'password'. - -### making an admin user -First, you'll need to start your development server and login as one of the LDAP users. -We'll assume you logged in as `admin@example.org` -```sh -bundle exec rails c -> u = User.find_by(email: 'admin@example.org') -> u.add_role('admin') -> exit -``` -If you go back and refresh your browser where `admin@example.org` is logged in, you -should now have access to the administator dashboard. ->>>>>>> e0abbf30716417b193ffafd8c95c51fb30e14878 ### seeding deposit types MIRA supports a number of configurable deposit types. A seed configuration is checked into the repository at