Skip to content

Commit

Permalink
LDAP enhancements
Browse files Browse the repository at this point in the history
  • Loading branch information
vicvega committed Apr 1, 2019
1 parent 369b086 commit 2b0d817
Show file tree
Hide file tree
Showing 24 changed files with 434 additions and 85 deletions.
10 changes: 5 additions & 5 deletions app/controllers/chaltron/ldap_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ def multi_new
userid = params[:userid]
if userid.present?
entry = Chaltron::LDAP::Person.find_by_uid(userid)
@entries << entry unless entry.nil?
@entries << entry
else
res = Chaltron::LDAP::Person.find_by_fields(find_options)
@entries = res
@entries = Chaltron::LDAP::Person.find_by_fields(find_options)
end
@entries.compact!
end

def multi_create
Expand All @@ -41,12 +41,12 @@ def multi_create
private
def find_options
department = params[:department]
name = params[:fullname]
name = params[:lastname]
limit = params[:limit].to_i

ret = {}
ret[:department] = "*#{department}*" unless department.blank?
ret[:cn] = "*#{name}*" unless name.blank?
ret[:last_name] = "*#{name}*" unless name.blank?
ret[:limit] = limit.zero? ? default_limit : limit
ret
end
Expand Down
1 change: 1 addition & 0 deletions app/controllers/chaltron/omniauth_callbacks_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ def ldap
# We only find ourselves here
# if the authentication to LDAP was successful.
user = Chaltron::LDAP::User.find_or_create(oauth, Chaltron.ldap_allow_all)
user = Chaltron.ldap_after_authenticate.call(user, Chaltron::LDAP::Connection.new)
if user.nil?
redirect_to root_url, alert: I18n.t('chaltron.not_allowed_to_sign_in')
else
Expand Down
3 changes: 3 additions & 0 deletions app/controllers/chaltron/sessions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require 'chaltron/ldap/connection'

class Chaltron::SessionsController < Devise::SessionsController
after_action :after_login, only: :create
before_action :before_logout, only: :destroy
Expand All @@ -9,6 +11,7 @@ def after_login
end

def before_logout
Chaltron.ldap_before_logout.call(current_user, Chaltron::LDAP::Connection.new) if current_user.ldap_user?
info I18n.t('chaltron.logs.logout', user: current_user.display_name)
end
end
4 changes: 4 additions & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,8 @@ def self.find_for_database_authentication(warden_conditions)
end
end

def ldap_user?
provider == 'ldap'
end

end
2 changes: 1 addition & 1 deletion app/views/chaltron/ldap/search.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<%= bootstrap_form_tag(url: ldap_multi_new_path, method: :post, layout: :horizontal) do |f| %>
<%= f.text_field :userid, label: t('.name_label'), help: t('.name_help') %>
<%= f.text_field :fullname, label: t('.fullname_label'), help: t('.fullname_help') %>
<%= f.text_field :lastname, label: t('.lastname_label'), help: t('.lastname_help') %>
<%= f.text_field :department, label: t('.department_label'), help: t('.department_help') %>
<%= f.text_field :limit, label: t('.limit_label'), help: t('.limit_help'), value: @limit %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/chaltron/users/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<%= render partial: 'side_filters', locals: { filters: @filters } %>
<hr>

<% if ldap_enabled? %>
<% if ldap_enabled? and !Chaltron.ldap_allow_all %>
<div class='btn-group'>
<%= content_tag :button, type: 'button', class: 'btn btn-primary dropdown-toggle',
data: {toggle: 'dropdown'}, aria: {expanded: false} do %>
Expand Down
4 changes: 2 additions & 2 deletions app/views/chaltron/users/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@
<div class='pull-right'>
<%= link_to edit_user_path(@user), class: 'btn btn-default' do %>
<%= icon :edit, t('.edit') %>
<% end %>
<% end if can? :edit, @user %>
<%= link_to @user, method: :delete, class: 'btn btn-danger',
disabled: current_user == @user,
data: { confirm: t('.destroy_confirm', user: @user.username) } do %>
<%= icon :trash, t('.destroy') %>
<% end %>
<% end if can? :destroy, @user %>
</div>
</div>
8 changes: 4 additions & 4 deletions app/views/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,11 @@ en:
title: Search for LDAP sers
submit_text: Search
name_label: User
name_help: Search for user-id (exact match)
fullname_label: Fullname
fullname_help: Search for first name or surname (also partial match)
name_help: Search by user-id (exact match)
lastname_label: Last name
lastname_help: Search by last name or surname (also partial match)
department_label: Department
department_help: Search for department (also partial match)
department_help: Search by department (also partial match)
limit_label: Limit
limit_help: Max shown results
multi_new:
Expand Down
4 changes: 2 additions & 2 deletions app/views/locales/it.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ it:
submit_text: Cerca
name_label: Utente
name_help: Ricerca per user-id (match esatto)
fullname_label: Nome
fullname_help: Ricerca per nome o cognome (anche match parziale)
lastname_label: Nome
lastname_help: Ricerca per cognome (anche match parziale)
department_label: Funzione
department_help: Ricerca per sigla di funzione (anche match parziale)
limit_label: Limite
Expand Down
4 changes: 2 additions & 2 deletions config/chaltron_navigation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@
admin.item :users,
{ icon: 'fa fa-fw fa-users',
text: I18n.t('chaltron.menu.users')
}, users_path, highlights_on: /\/(users|ldap)(?!\/self_(show|edit|update))/ if can?(:manage, User)
}, users_path, highlights_on: /\/(users|ldap)(?!\/self_(show|edit|update))/ if can?(:read, User)
admin.item :logs,
{ icon: 'fa fa-fw fa-book',
text: I18n.t('chaltron.menu.logs')
}, logs_path, highlights_on: /\/logs/ if can?(:read, Log)
end if can?(:manage, User) or can?(:read, Log)
end if can?(:read, User) or can?(:read, Log)
primary.item :logged, current_user.display_name.html_safe, nil do |user|
user.dom_class = 'dropdown-menu-right'
user.item :self_edit, { icon: 'fa fa-fw fa-user',
Expand Down
9 changes: 5 additions & 4 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
resources :logs, controller: 'chaltron/logs', only: [:index, :show]

# search and create LDAP users
get 'ldap/search' => 'chaltron/ldap#search'
post 'ldap/multi_new' => 'chaltron/ldap#multi_new'
post 'ldap/multi_create' => 'chaltron/ldap#multi_create'

if Devise.omniauth_providers.include?(:ldap) and !Chaltron.ldap_allow_all
get 'ldap/search' => 'chaltron/ldap#search'
post 'ldap/multi_new' => 'chaltron/ldap#multi_new'
post 'ldap/multi_create' => 'chaltron/ldap#multi_create'
end
end
25 changes: 24 additions & 1 deletion lib/chaltron.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,37 @@ module Controllers
@@default_roles = []

mattr_accessor :ldap_allow_all
@@ldap_allow_all = false
@@ldap_allow_all = true

mattr_accessor :enable_syslog
@@enable_syslog = false

mattr_accessor :syslog_facility
@@syslog_facility = Syslog::LOG_SYSLOG

mattr_accessor :ldap_field_mappings
@@ldap_field_mappings = {
first_name: 'givenname',
last_name: 'cn',
department: 'department',
email: 'mail'
}

mattr_accessor :ldap_group_base
@@ldap_group_base = nil

mattr_accessor :ldap_group_member_filter
@@ldap_group_member_filter = -> (entry) { "uniquemember=#{entry.dn}" }

mattr_accessor :ldap_role_mappings
@@ldap_role_mappings = {}

mattr_accessor :ldap_after_authenticate
@@ldap_after_authenticate = -> (user, ldap) { user }

mattr_accessor :ldap_before_logout
@@ldap_before_logout = -> (user, ldap) { }

def self.setup
yield self
end
Expand Down
129 changes: 94 additions & 35 deletions lib/chaltron/ldap/connection.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
module Chaltron
module LDAP
class Connection
NET_LDAP_ENCRYPTION_METHOD = {
simple_tls: :simple_tls,
start_tls: :start_tls,
plain: nil
}.freeze

attr_reader :ldap

def initialize(params = {})
Expand All @@ -16,7 +22,9 @@ def auth(login, password)
end

def find_by_uid(id)
find_user(uid: id)
opts = {}
opts[uid.to_sym] = id
ret = find_user(opts)
end

def find_user(*args)
Expand Down Expand Up @@ -47,35 +55,31 @@ def find_users(args)
scope: Net::LDAP::SearchScope_BaseObject
}
else
filters = []
fields.each do |field|
filters << Net::LDAP::Filter.eq(field, args[field])
filters = fields.map do |field|
f = translate_field(field)
Net::LDAP::Filter.eq(f, args[field]) if f
end
options = {
base: base,
filter: filters.inject { |sum, n| Net::LDAP::Filter.join(sum, n) }
}
end
options.merge!(size: limit) unless limit.nil?
ldap_search(options).map do |entry|
Chaltron::LDAP::Person.new(entry, uid) if entry.respond_to? uid
end.compact
end

# if config.user_filter.present?
# user_filter = Net::LDAP::Filter.construct(config.user_filter)

# options[:filter] = if options[:filter]
# Net::LDAP::Filter.join(options[:filter], user_filter)
# else
# user_filter
# end
# end

options.merge!(size: limit) if limit.present?

entries = ldap_search(options).select do |entry|
entry.respond_to? uid
end
def find_groups_by_member(entry)
options = {
base: Chaltron.ldap_group_base || base,
filter: Chaltron.ldap_group_member_filter.call(entry)
}
ldap_search(options)
end

entries.map do |entry|
Chaltron::LDAP::Person.new(entry, uid)
end
def update_attributes(dn, args)
ldap.modify dn: dn, operations: args.map { |k,v| [:replace, k, v] }
end

private
Expand All @@ -84,15 +88,21 @@ def options
Devise.omniauth_configs[:ldap].options
end

def translate_field field
return uid if field.to_sym == :uid
return Chaltron.ldap_field_mappings[field.to_sym] unless Chaltron.ldap_field_mappings[field.to_sym].nil?
field
end

def adapter_options
{
opts = {
host: options[:host],
port: options[:port],
encryption: encryption,
encryption: encryption_options,
verbose: true
}.tap do |options|
options.merge!(auth_options) if has_auth?
end
}
opts.merge!(auth_options) if has_auth?
opts
end

def base
Expand All @@ -103,15 +113,64 @@ def uid
options[:uid]
end

def encryption
case options[:method].to_s
when 'ssl'
:simple_tls
when 'tls'
:start_tls
else
nil
def encryption_options
method = translate_method
return unless method
{
method: method,
tls_options: tls_options
}
end

def translate_method
NET_LDAP_ENCRYPTION_METHOD[options[:encryption]&.to_sym]
end

def tls_options
return @tls_options if defined?(@tls_options)

method = translate_method
return unless method

opts = if options[:verify_certificates] && method != 'plain'
# Dup so we don't accidentally overwrite the constant
OpenSSL::SSL::SSLContext::DEFAULT_PARAMS.dup
else
# It is important to explicitly set verify_mode for two reasons:
# 1. The behavior of OpenSSL is undefined when verify_mode is not set.
# 2. The net-ldap gem implementation verifies the certificate hostname
# unless verify_mode is set to VERIFY_NONE.
{ verify_mode: OpenSSL::SSL::VERIFY_NONE }
end

opts.merge!(custom_tls_options)

@tls_options = opts
end

def custom_tls_options
return {} unless options['tls_options']

# Dup so we don't overwrite the original value
custom_options = options['tls_options'].dup.delete_if { |_, value| value.nil? || value.blank? }
custom_options.symbolize_keys!

if custom_options[:cert]
begin
custom_options[:cert] = OpenSSL::X509::Certificate.new(custom_options[:cert])
rescue OpenSSL::X509::CertificateError => e
Rails.logger.error "LDAP TLS Options 'cert' is invalid for provider #{provider}: #{e.message}"
end
end

if custom_options[:key]
begin
custom_options[:key] = OpenSSL::PKey.read(custom_options[:key])
rescue OpenSSL::PKey::PKeyError => e
Rails.logger.error "LDAP TLS Options 'key' is invalid for provider #{provider}: #{e.message}"
end
end
custom_options
end

def auth_options
Expand Down
Loading

0 comments on commit 2b0d817

Please sign in to comment.