Init version of ldap auth/sync.

This commit is contained in:
Martin Edenhofer 2013-02-07 22:24:03 +01:00
parent 579e1dcfb3
commit 409dbe31d1
7 changed files with 170 additions and 30 deletions

View file

@ -46,6 +46,8 @@ gem 'simple-rss'
gem 'mysql2'
#gem 'sqlite3'
gem 'net-ldap'
# Use unicorn as the web server
# gem 'unicorn'

View file

@ -43,15 +43,17 @@ class User < ApplicationModel
return if !password || password == ''
# try to find user based on login
user = User.where( :login => username, :active => true ).first
user = User.where( :login => username.downcase, :active => true ).first
# try second lookup with email
if !user
user = User.where( :email => username, :active => true ).first
user = User.where( :email => username.downcase, :active => true ).first
end
# no user found
return nil if !user
# check failed logins
if user
# return if user.faild_login > 10
end
# use auth backends
config = {
@ -65,12 +67,22 @@ class User < ApplicationModel
:adapter => 'env',
},
:ldap => {
:adapter => 'ldap',
:host => 'somehost',
:port => '3333',
:base_dn => 'some base dn',
:bind_user => 'some bind user',
:bind_pw => 'some pw',
:adapter => 'ldap',
:host => 'localhost',
:port => 389,
:bind_dn => 'cn=Manager,dc=example,dc=org',
:bind_pw => 'example',
:uid => 'mail',
:base => 'dc=example,dc=org',
:always_filter => '',
:always_roles => ['Admin', 'Agent'],
:always_groups => ['Users'],
:sync_params => {
:firstname => 'givenName',
:lastname => 'sn',
:email => 'mail',
:login => 'mail',
},
},
:otrs => {
:adapter => 'otrs',
@ -87,15 +99,33 @@ class User < ApplicationModel
},
},
}
# try to login against configure auth backends
user_auth = nil
config.each {|key, c|
file = "auth/#{c[:adapter]}"
require file
user_auth = Auth.const_get("#{c[:adapter].to_s.upcase}").check( user, username, password, c )
return user_auth if user_auth
user_auth = Auth.const_get("#{c[:adapter].to_s.upcase}").check( username, password, c, user )
# auth ok
if user_auth
# update last login
# reset login failed
return user_auth
end
}
# set login failed +1
# auth failed
return false
sleep 1
return user_auth
end
def self.create_from_hash!(hash)
@ -113,7 +143,8 @@ class User < ApplicationModel
:note => hash['info']['description'],
:source => hash['provider'],
:roles => roles,
:created_by_id => 1
:updated_by_id => 1,
:created_by_id => 1,
)
end
@ -122,11 +153,11 @@ class User < ApplicationModel
return if !username || username == ''
# try to find user based on login
user = User.where( :login => username, :active => true ).first
user = User.where( :login => username.downcase, :active => true ).first
# try second lookup with email
if !user
user = User.where( :email => username, :active => true ).first
user = User.where( :email => username.downcase, :active => true ).first
end
# check if email address exists

View file

@ -1,7 +1,7 @@
module Auth
end
module Auth::ENV
def self.check( user, username, password, config )
def self.check( username, password, config, user )
# try to find user based on login
if ENV['REMOTE_USER']

View file

@ -1,8 +1,11 @@
module Auth
end
module Auth::INTERNAL
def self.check( user, username, password, config )
def self.check( username, password, config, user )
# return if no user exists
return nil if !user
# sha auth check
if user.password =~ /^\{sha2\}/
crypted = Digest::SHA2.hexdigest( password )

View file

@ -1,15 +1,119 @@
require 'net/ldap'
module Auth
end
module Auth::LDAP
def self.check( user, username, password, config )
# ldap connect
# ldap bind
# sync roles / groups
# return user
def self.check( username, password, config, user )
return false
scope = Net::LDAP::SearchScope_WholeSubtree
# ldap connect
ldap = Net::LDAP.new( :host => config[:host], :port => config[:port] )
# set auth data if needed
if config[:bind_dn] && config[:bind_pw]
ldap.auth config[:bind_dn], config[:bind_pw]
end
# ldap bind
if !ldap.bind
puts "NOTICE: Can't connect/bind to '#{host}', #{ldap.get_operation_result.code}, #{ldap.get_operation_result.message}"
return
end
# search user
filter = "(#{config[:uid]}=#{username})"
if config[:always_filter]
filter = "(&#{filter}#{config[:always_filter]})"
end
user_dn = nil
user_data = {}
ldap.search( :base => config[:base], :filter => filter, :scope => scope ) do |entry|
user_data = {}
user_dn = entry.dn
# remember attributes for :sync_params
entry.each do |attribute, values|
user_data[ attribute.to_sym ] = ''
values.each do |value|
user_data[ attribute.to_sym ] = value
end
end
end
if user_dn == nil
puts "NOTICE: ldap entry found for user '#{username}' with filter #{filter} failed!"
return nil
end
# try ldap bind with user credentals
auth = ldap.authenticate user_dn, password
if !ldap.bind( auth )
puts "NOTICE: ldap bind with '#{user_dn}' failed!"
return false
end
# create/update user
if config[:sync_params]
user_attributes = {
:source => 'ldap',
:updated_by_id => 1,
}
config[:sync_params].each {| local_data, ldap_data |
if user_data[ ldap_data.to_sym ]
user_attributes[ local_data.to_sym] = user_data[ ldap_data.to_sym ]
end
}
if !user
user_attributes[:created_by_id] = 1
user = User.create( user_attributes )
puts "NOTICE: user created '#{user.login}'"
else
user.update_attributes( user_attributes )
puts "NOTICE: user updated '#{user.login}'"
end
end
# return if it was not possible to create user
return if !user
# sync roles
# FIXME
# sync groups
# FIXME
# set always roles
if config[:always_roles]
role_ids = user.role_ids
config[:always_roles].each {|role_name|
role = Role.where( :name => role_name ).first
next if !role
if !role_ids.include?( role.id )
role_ids.push role.id
end
}
user.role_ids = role_ids
user.save
end
# set always groups
if config[:always_groups]
group_ids = user.group_ids
config[:always_groups].each {|group_name|
group = Group.where( :name => group_name ).first
next if !group
if !group_ids.include?( group.id )
group_ids.push group.id
end
}
user.group_ids = group_ids
user.save
end
# take session down
# - not needed, done by Net::LDAP -
return user
end
end

View file

@ -1,7 +1,7 @@
module Auth
end
module Auth::OTRS
def self.check( user, username, password, config )
def self.check( username, password, config, user )
endpoint = Setting.get('import_otrs_endpoint')
return false if !endpoint || endpoint.empty?

View file

@ -1,7 +1,7 @@
module Auth
end
module Auth::TEST
def self.check( user, username, password, config )
def self.check( username, password, config, user )
# development systems
if !ENV['RAILS_ENV'] || ENV['RAILS_ENV'] == 'development'