Skip to content

Commit

Permalink
WIP - PImplement basic LDAP authentication
Browse files Browse the repository at this point in the history
Add devise_ldap_authenticatable - see
https://github.com/cschiewek/devise_ldap_authenticatable#usage
* Add gem to gemfile
* Run devise_ldap_authenticatable generator
* Add username to User model
* Authenticate against username instead of email

Add ladle wrapper for ApacheDS LDAP server
* Add gem to gemfile
* Add rake task to launch LDAP server
* Add minimal ldap user setup file
  • Loading branch information
mark-dce committed Dec 7, 2017
1 parent fa784e4 commit 64c3481
Show file tree
Hide file tree
Showing 11 changed files with 152 additions and 6 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Expand Up @@ -66,8 +66,10 @@ gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

gem 'active_job_status', '~> 1.2.1'
gem 'devise'
gem 'devise_ldap_authenticatable'
gem 'devise-guests', '~> 0.6'
gem 'handle-system', '0.1.1'
gem 'ladle'
gem 'mysql2'
gem 'react-rails'
gem 'redis-activesupport'
Expand Down
9 changes: 9 additions & 0 deletions Gemfile.lock
Expand Up @@ -219,6 +219,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)
Expand Down Expand Up @@ -449,6 +452,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)
Expand Down Expand Up @@ -523,6 +528,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)
Expand All @@ -545,6 +551,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)
Expand Down Expand Up @@ -874,6 +881,7 @@ DEPENDENCIES
database_cleaner
devise
devise-guests (~> 0.6)
devise_ldap_authenticatable
dotenv-rails
factory_girl_rails
fcrepo_wrapper
Expand All @@ -884,6 +892,7 @@ DEPENDENCIES
hyrax (= 2.0.0)
jbuilder (~> 2.5)
jquery-rails
ladle
listen (~> 3.0.5)
mysql2
nokogiri (>= 1.8.1)
Expand Down
3 changes: 3 additions & 0 deletions 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
Expand Down
6 changes: 5 additions & 1 deletion app/models/user.rb
Expand Up @@ -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

# Method added by Blacklight; Blacklight uses #to_s on your
Expand Down Expand Up @@ -49,4 +49,8 @@ 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
2 changes: 1 addition & 1 deletion app/views/devise/sessions/new.html.erb
Expand Up @@ -3,7 +3,7 @@
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<div class="field">
<%= f.label 'Tufts Username' %><br />
<%= f.email_field :email, autofocus: true %>
<%= f.text_field :username, autofocus: true %>
</div>

<div class="field">
Expand Down
17 changes: 14 additions & 3 deletions 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.
Expand Down Expand Up @@ -34,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
Expand All @@ -46,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
Expand Down
53 changes: 53 additions & 0 deletions config/ldap.yml
@@ -0,0 +1,53 @@
## 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
require_attribute_presence:
mail: true

## Environment

development:
host: localhost
port: 3389
attribute: cn
base: ou=people,dc=example,dc=org
admin_user: cn=admin,dc=test,dc=com
admin_password: admin_password
ssl: false
# <<: *AUTHORIZATIONS

test:
host: localhost
port: 3389
attribute: cn
base: ou=people,dc=example,dc=com
admin_user: cn=admin,dc=test,dc=com
admin_password: admin_password
ssl: false
# <<: *AUTHORIZATIONS

production:
host: localhost
port: 636
attribute: cn
base: ou=people,dc=test,dc=com
admin_user: cn=admin,dc=test,dc=com
admin_password: admin_password
ssl: start_tls
# <<: *AUTHORIZATIONS
34 changes: 34 additions & 0 deletions config/ldap_data_dev.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
6 changes: 6 additions & 0 deletions db/migrate/20171207021357_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
4 changes: 3 additions & 1 deletion db/schema.rb
Expand Up @@ -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: 20171207021357) do

create_table "batch_tasks", force: :cascade, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8" do |t|
t.string "batch_type"
Expand Down Expand Up @@ -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|
Expand Down
22 changes: 22 additions & 0 deletions lib/tasks/ladle.rake
@@ -0,0 +1,22 @@
require 'ladle'

'Start a ladle server'
task :ladle do
conf_path = Rails.root.join('config')

server = Ladle::Server.new(
port: Rails.application.config_for(:ldap)['port'],
quiet: false,
ldif: conf_path.join('ldap_data_dev.ldif').to_s
)

begin
puts 'Starting LDAP server on port 3398'
server.start
sleep
rescue Interrupt
puts 'Stopping server'
ensure
server.stop
end
end

0 comments on commit 64c3481

Please sign in to comment.