ldap_fluff 0.2.5 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ldap_fluff might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/lib/ldap_fluff/active_directory.rb +28 -39
- data/lib/ldap_fluff/ad_member_service.rb +8 -44
- data/lib/ldap_fluff/config.rb +63 -68
- data/lib/ldap_fluff/error.rb +5 -0
- data/lib/ldap_fluff/freeipa.rb +25 -39
- data/lib/ldap_fluff/freeipa_member_service.rb +8 -35
- data/lib/ldap_fluff/generic.rb +75 -0
- data/lib/ldap_fluff/generic_member_service.rb +62 -0
- data/lib/ldap_fluff/ldap_fluff.rb +20 -5
- data/lib/ldap_fluff/posix.rb +18 -28
- data/lib/ldap_fluff/posix_member_service.rb +12 -28
- data/lib/ldap_fluff.rb +3 -0
- data/test/ad_member_services_test.rb +2 -3
- data/test/ad_test.rb +48 -42
- data/test/config_test.rb +1 -1
- data/test/ipa_member_services_test.rb +2 -3
- data/test/ipa_test.rb +24 -22
- data/test/ldap_test.rb +1 -2
- data/test/lib/ldap_test_helper.rb +42 -13
- data/test/posix_member_services_test.rb +10 -3
- data/test/posix_test.rb +47 -31
- metadata +32 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 37c4eced1c338a71de90a9bfd06ad6fcf77f2680
|
4
|
+
data.tar.gz: 073cb1a0c739a9a1fc49ff9d32defbd202956504
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3169fd42b66606a9f94761fbec81689d60891d1b6eb7e70a1225fe1305b79342da68422d5a910d838ce8317ece64ecd17787f1617f6d1c602ca64d4597318eb2
|
7
|
+
data.tar.gz: cae46d73863511bf0f69b99f0bc839728e89b500cfa6338a6de3fedf5c3fc902d1678f42f2eff378df50dd19de11fc15c9fa43b7d8de47afb82034ffd8525b66
|
@@ -1,42 +1,22 @@
|
|
1
|
-
class LdapFluff::ActiveDirectory
|
2
|
-
attr_accessor :ldap, :member_service
|
1
|
+
class LdapFluff::ActiveDirectory < LdapFluff::Generic
|
3
2
|
|
4
3
|
def initialize(config = {})
|
5
|
-
@ldap = Net::LDAP.new(:host => config.host,
|
6
|
-
:base => config.base_dn,
|
7
|
-
:port => config.port,
|
8
|
-
:encryption => config.encryption)
|
9
|
-
@group_base = config.group_base || config.base_dn
|
10
|
-
@ad_domain = config.ad_domain
|
11
4
|
@bind_user = config.service_user
|
12
5
|
@bind_pass = config.service_pass
|
13
6
|
@anon = config.anon_queries
|
14
|
-
|
15
|
-
@member_service = MemberService.new(@ldap, @group_base)
|
7
|
+
super
|
16
8
|
end
|
17
9
|
|
18
10
|
def bind?(uid = nil, password = nil)
|
19
|
-
@ldap.auth(
|
11
|
+
@ldap.auth(uid, password)
|
20
12
|
@ldap.bind
|
21
13
|
end
|
22
14
|
|
23
|
-
# AD generally does not support un-authenticated searching
|
24
|
-
# Typically AD admins configure a public user for searching
|
25
|
-
def service_bind
|
26
|
-
unless @anon || bind?(@bind_user, @bind_pass)
|
27
|
-
raise UnauthenticatedActiveDirectoryException, "Could not bind to AD Service User"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
15
|
# returns the list of groups to which a user belongs
|
32
16
|
# this query is simpler in active directory
|
33
17
|
def groups_for_uid(uid)
|
34
18
|
service_bind
|
35
|
-
|
36
|
-
@member_service.find_user_groups(uid)
|
37
|
-
rescue MemberService::UIDNotFoundException
|
38
|
-
return []
|
39
|
-
end
|
19
|
+
super
|
40
20
|
end
|
41
21
|
|
42
22
|
# active directory stores group membership on a users model
|
@@ -54,25 +34,34 @@ class LdapFluff::ActiveDirectory
|
|
54
34
|
end
|
55
35
|
|
56
36
|
def user_exists?(uid)
|
57
|
-
|
58
|
-
|
59
|
-
@member_service.find_user(uid)
|
60
|
-
rescue MemberService::UIDNotFoundException
|
61
|
-
return false
|
62
|
-
end
|
63
|
-
return true
|
37
|
+
service_bind
|
38
|
+
super
|
64
39
|
end
|
65
40
|
|
66
41
|
def group_exists?(gid)
|
67
|
-
|
68
|
-
|
69
|
-
@member_service.find_group(gid)
|
70
|
-
rescue MemberService::GIDNotFoundException
|
71
|
-
return false
|
72
|
-
end
|
73
|
-
return true
|
42
|
+
service_bind
|
43
|
+
super
|
74
44
|
end
|
75
45
|
|
76
|
-
|
46
|
+
private
|
47
|
+
|
48
|
+
def users_from_search_results(search, method)
|
49
|
+
users = []
|
50
|
+
|
51
|
+
search.send(method).each do |member|
|
52
|
+
cn = member.downcase.split(',')[0].split('=')[1]
|
53
|
+
entry = @member_service.find_user(cn).first
|
54
|
+
|
55
|
+
objectclasses = entry.objectclass.map(&:downcase)
|
56
|
+
|
57
|
+
if (%w(organizationalperson person) & objectclasses).present?
|
58
|
+
users << @member_service.get_logins([member])
|
59
|
+
elsif (%w(organizationalunit group) & objectclasses).present?
|
60
|
+
users << users_for_gid(cn)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
users.flatten.uniq
|
77
65
|
end
|
66
|
+
|
78
67
|
end
|
@@ -1,13 +1,11 @@
|
|
1
1
|
require 'net/ldap'
|
2
2
|
|
3
3
|
# Naughty bits of active directory ldap queries
|
4
|
-
class LdapFluff::ActiveDirectory::MemberService
|
4
|
+
class LdapFluff::ActiveDirectory::MemberService < LdapFluff::GenericMemberService
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
@ldap = ldap
|
10
|
-
@group_base = group_base
|
6
|
+
def initialize(ldap, config)
|
7
|
+
@attr_login = (config.attr_login || 'samaccountname')
|
8
|
+
super
|
11
9
|
end
|
12
10
|
|
13
11
|
# get a list [] of ldap groups for a given user
|
@@ -17,23 +15,11 @@ class LdapFluff::ActiveDirectory::MemberService
|
|
17
15
|
_groups_from_ldap_data(data.first)
|
18
16
|
end
|
19
17
|
|
20
|
-
def find_user(uid)
|
21
|
-
data = @ldap.search(:filter => name_filter(uid))
|
22
|
-
raise UIDNotFoundException if (data.nil? || data.empty?)
|
23
|
-
data
|
24
|
-
end
|
25
|
-
|
26
|
-
def find_group(gid)
|
27
|
-
data = @ldap.search(:filter => group_filter(gid), :base => @group_base)
|
28
|
-
raise GIDNotFoundException if (data.nil? || data.empty?)
|
29
|
-
data
|
30
|
-
end
|
31
|
-
|
32
18
|
# return the :memberof attrs + parents, recursively
|
33
19
|
def _groups_from_ldap_data(payload)
|
34
20
|
data = []
|
35
21
|
if !payload.nil?
|
36
|
-
first_level =
|
22
|
+
first_level = get_groups(payload[:memberof])
|
37
23
|
total_groups = _walk_group_ancestry(first_level)
|
38
24
|
data = (first_level + total_groups).uniq
|
39
25
|
end
|
@@ -48,42 +34,20 @@ class LdapFluff::ActiveDirectory::MemberService
|
|
48
34
|
search = @ldap.search(:filter => filter, :base => @group_base)
|
49
35
|
if !search.nil? && !search.first.nil?
|
50
36
|
group = search.first
|
51
|
-
set +=
|
37
|
+
set += get_groups(group[:memberof])
|
52
38
|
set += _walk_group_ancestry(set)
|
53
39
|
end
|
54
40
|
end
|
55
41
|
set
|
56
42
|
end
|
57
43
|
|
58
|
-
def group_filter(gid)
|
59
|
-
Net::LDAP::Filter.eq("cn", gid)
|
60
|
-
end
|
61
|
-
|
62
44
|
def class_filter
|
63
45
|
Net::LDAP::Filter.eq("objectclass", "group")
|
64
46
|
end
|
65
47
|
|
66
|
-
|
67
|
-
Net::LDAP::Filter.eq("samaccountname", uid)
|
68
|
-
end
|
69
|
-
|
70
|
-
# extract the group names from the LDAP style response,
|
71
|
-
# return string will be something like
|
72
|
-
# CN=bros,OU=bropeeps,DC=jomara,DC=redhat,DC=com
|
73
|
-
#
|
74
|
-
# AD group proc from
|
75
|
-
# http://erniemiller.org/2008/04/04/simplified-active-directory-authentication/
|
76
|
-
#
|
77
|
-
# I think we would normally want to just do the collect at the end,
|
78
|
-
# but we need the individual names for recursive queries
|
79
|
-
def _group_names_from_cn(grouplist)
|
80
|
-
p = proc { |g| g.sub(/.*?CN=(.*?),.*/, '\1') }
|
81
|
-
grouplist.collect(&p)
|
82
|
-
end
|
83
|
-
|
84
|
-
class UIDNotFoundException < StandardError
|
48
|
+
class UIDNotFoundException < LdapFluff::Error
|
85
49
|
end
|
86
50
|
|
87
|
-
class GIDNotFoundException <
|
51
|
+
class GIDNotFoundException < LdapFluff::Error
|
88
52
|
end
|
89
53
|
end
|
data/lib/ldap_fluff/config.rb
CHANGED
@@ -1,90 +1,85 @@
|
|
1
1
|
require 'yaml'
|
2
2
|
require 'active_support/core_ext/hash'
|
3
3
|
|
4
|
-
class LdapFluff
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
raise ArgumentError unless config.respond_to?(:to_hash)
|
23
|
-
config = validate(convert(config))
|
24
|
-
|
25
|
-
ATTRIBUTES.each do |attr|
|
26
|
-
instance_variable_set(:"@#{attr}", config[attr])
|
27
|
-
end
|
4
|
+
class LdapFluff::Config
|
5
|
+
ATTRIBUTES = %w[host port encryption base_dn group_base server_type service_user
|
6
|
+
service_pass anon_queries attr_login search_filter]
|
7
|
+
ATTRIBUTES.each { |attr| attr_reader attr.to_sym }
|
8
|
+
|
9
|
+
DEFAULT_CONFIG = { 'port' => 389,
|
10
|
+
'encryption' => nil,
|
11
|
+
'base_dn' => 'dc=company,dc=com',
|
12
|
+
'group_base' => 'dc=company,dc=com',
|
13
|
+
'server_type' => :free_ipa,
|
14
|
+
'anon_queries' => false }
|
15
|
+
|
16
|
+
def initialize(config)
|
17
|
+
raise ArgumentError unless config.respond_to?(:to_hash)
|
18
|
+
config = validate(convert(config))
|
19
|
+
|
20
|
+
ATTRIBUTES.each do |attr|
|
21
|
+
instance_variable_set(:"@#{attr}", config[attr])
|
28
22
|
end
|
23
|
+
end
|
29
24
|
|
30
|
-
|
25
|
+
private
|
31
26
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
27
|
+
# @param [#to_hash] config
|
28
|
+
def convert(config)
|
29
|
+
config.to_hash.with_indifferent_access.tap do |conf|
|
30
|
+
%w[encryption server_type].each do |key|
|
31
|
+
conf[key] = conf[key].to_sym if conf[key]
|
38
32
|
end
|
39
33
|
end
|
34
|
+
end
|
40
35
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
def unknown_keys?(config)
|
47
|
-
unknown_keys = config.keys - ATTRIBUTES
|
48
|
-
raise ConfigError, "unknown configuration keys: #{unknown_keys.join(',')}" unless unknown_keys.empty?
|
49
|
-
end
|
36
|
+
def missing_keys?(config)
|
37
|
+
missing_keys = ATTRIBUTES - config.keys
|
38
|
+
raise ConfigError, "missing configuration for keys: #{missing_keys.join(',')}" unless missing_keys.empty?
|
39
|
+
end
|
50
40
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
41
|
+
def unknown_keys?(config)
|
42
|
+
unknown_keys = config.keys - ATTRIBUTES
|
43
|
+
raise ConfigError, "unknown configuration keys: #{unknown_keys.join(',')}" unless unknown_keys.empty?
|
44
|
+
end
|
55
45
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
60
|
-
end
|
46
|
+
def all_required_keys?(config)
|
47
|
+
%w[host port base_dn group_base server_type].all? do |key|
|
48
|
+
raise ConfigError, "config key #{key} has to be set, it was nil" if config[key].nil?
|
61
49
|
end
|
62
50
|
|
63
|
-
|
64
|
-
|
65
|
-
raise ConfigError, "config key
|
51
|
+
%w[service_user service_pass].all? do |key|
|
52
|
+
if !config['anon_queries'] && config['server_type'] != :posix && config[key].nil?
|
53
|
+
raise ConfigError, "config key #{key} has to be set, it was nil"
|
66
54
|
end
|
67
55
|
end
|
56
|
+
end
|
68
57
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
"but was #{config['server_type']}"
|
73
|
-
end
|
58
|
+
def anon_queries_set?(config)
|
59
|
+
unless [false, true].include?(config['anon_queries'])
|
60
|
+
raise ConfigError, "config key anon_queries has to be true or false but was #{config['anon_queries']}"
|
74
61
|
end
|
62
|
+
end
|
75
63
|
|
76
|
-
|
77
|
-
|
64
|
+
def correct_server_type?(config)
|
65
|
+
unless [:posix, :active_directory, :free_ipa].include?(config['server_type'])
|
66
|
+
raise ConfigError, 'config key server_type has to be :active_directory, :posix, :free_ipa ' +
|
67
|
+
"but was #{config['server_type']}"
|
68
|
+
end
|
69
|
+
end
|
78
70
|
|
79
|
-
|
80
|
-
|
81
|
-
unknown_keys?(config)
|
82
|
-
all_required_keys?(config)
|
83
|
-
anon_queries_set?(config)
|
71
|
+
def validate(config)
|
72
|
+
config = DEFAULT_CONFIG.merge(config)
|
84
73
|
|
85
|
-
|
86
|
-
|
74
|
+
correct_server_type?(config)
|
75
|
+
missing_keys?(config)
|
76
|
+
unknown_keys?(config)
|
77
|
+
all_required_keys?(config)
|
78
|
+
anon_queries_set?(config)
|
87
79
|
|
88
|
-
|
80
|
+
config
|
81
|
+
end
|
89
82
|
|
90
|
-
|
83
|
+
class ConfigError < LdapFluff::Error
|
84
|
+
end
|
85
|
+
end
|
data/lib/ldap_fluff/freeipa.rb
CHANGED
@@ -1,19 +1,11 @@
|
|
1
|
-
class LdapFluff::FreeIPA
|
2
|
-
|
3
|
-
attr_accessor :ldap, :member_service
|
1
|
+
class LdapFluff::FreeIPA < LdapFluff::Generic
|
4
2
|
|
5
3
|
def initialize(config = {})
|
6
|
-
@ldap = Net::LDAP.new(:host => config.host,
|
7
|
-
:base => config.base_dn,
|
8
|
-
:port => config.port,
|
9
|
-
:encryption => config.encryption)
|
10
|
-
@group_base = config.group_base || config.base_dn
|
11
4
|
@base = config.base_dn
|
12
5
|
@bind_user = config.service_user
|
13
6
|
@bind_pass = config.service_pass
|
14
7
|
@anon = config.anon_queries
|
15
|
-
|
16
|
-
@member_service = MemberService.new(@ldap, @group_base)
|
8
|
+
super
|
17
9
|
end
|
18
10
|
|
19
11
|
def bind?(uid = nil, password = nil)
|
@@ -22,21 +14,11 @@ class LdapFluff::FreeIPA
|
|
22
14
|
end
|
23
15
|
|
24
16
|
def groups_for_uid(uid)
|
25
|
-
service_bind
|
26
17
|
begin
|
27
|
-
|
28
|
-
|
29
|
-
return []
|
18
|
+
service_bind
|
19
|
+
super
|
30
20
|
rescue MemberService::InsufficientQueryPrivilegesException
|
31
|
-
raise
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# AD generally does not support un-authenticated searching
|
36
|
-
# Typically AD admins configure a public user for searching
|
37
|
-
def service_bind
|
38
|
-
unless @anon || bind?(@bind_user, @bind_pass)
|
39
|
-
raise UnauthenticatedFreeIPAException, "Could not bind to FreeIPA Query User"
|
21
|
+
raise UnauthenticatedException, "Insufficient Privileges to query groups data"
|
40
22
|
end
|
41
23
|
end
|
42
24
|
|
@@ -58,26 +40,30 @@ class LdapFluff::FreeIPA
|
|
58
40
|
end
|
59
41
|
|
60
42
|
def user_exists?(uid)
|
61
|
-
|
62
|
-
|
63
|
-
@member_service.find_user(uid)
|
64
|
-
rescue MemberService::UIDNotFoundException
|
65
|
-
return false
|
66
|
-
end
|
67
|
-
return true
|
43
|
+
service_bind
|
44
|
+
super
|
68
45
|
end
|
69
46
|
|
70
47
|
def group_exists?(gid)
|
71
|
-
|
72
|
-
|
73
|
-
@member_service.find_group(gid)
|
74
|
-
rescue MemberService::GIDNotFoundException
|
75
|
-
return false
|
76
|
-
end
|
77
|
-
return true
|
48
|
+
service_bind
|
49
|
+
super
|
78
50
|
end
|
79
51
|
|
80
|
-
|
81
|
-
end
|
52
|
+
private
|
82
53
|
|
54
|
+
def users_from_search_results(search, method)
|
55
|
+
# Member results come in the form uid=sampleuser,cn=users, etc.. or gid=samplegroup,cn=groups
|
56
|
+
users = []
|
57
|
+
|
58
|
+
search.send(method).each do |member|
|
59
|
+
type = member.downcase.split(',')[1]
|
60
|
+
if type == 'cn=users'
|
61
|
+
users << @member_service.get_logins([member])
|
62
|
+
elsif type == 'cn=groups'
|
63
|
+
users << users_for_gid(member.split(',')[0].split('=')[1])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
users.flatten.uniq
|
68
|
+
end
|
83
69
|
end
|
@@ -1,13 +1,11 @@
|
|
1
1
|
require 'net/ldap'
|
2
2
|
|
3
3
|
# handles the naughty bits of posix ldap
|
4
|
-
class LdapFluff::FreeIPA::MemberService
|
4
|
+
class LdapFluff::FreeIPA::MemberService < LdapFluff::GenericMemberService
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
@ldap = ldap
|
10
|
-
@group_base = group_base
|
6
|
+
def initialize(ldap, config)
|
7
|
+
@attr_login = (config.attr_login || 'uid')
|
8
|
+
super
|
11
9
|
end
|
12
10
|
|
13
11
|
# return an ldap user with groups attached
|
@@ -17,41 +15,16 @@ class LdapFluff::FreeIPA::MemberService
|
|
17
15
|
# if group data is missing, they aren't querying with a user
|
18
16
|
# with enough privileges
|
19
17
|
raise InsufficientQueryPrivilegesException if user.size <= 1
|
20
|
-
|
21
|
-
end
|
22
|
-
|
23
|
-
def find_user(uid)
|
24
|
-
user = @ldap.search(:filter => name_filter(uid))
|
25
|
-
raise UIDNotFoundException if (user.nil? || user.empty?)
|
26
|
-
user
|
27
|
-
end
|
28
|
-
|
29
|
-
def find_group(gid)
|
30
|
-
group = @ldap.search(:filter => group_filter(gid), :base => @group_base)
|
31
|
-
raise GIDNotFoundException if (group.nil? || group.empty?)
|
32
|
-
group
|
33
|
-
end
|
34
|
-
|
35
|
-
def name_filter(uid)
|
36
|
-
Net::LDAP::Filter.eq("uid", uid)
|
37
|
-
end
|
38
|
-
|
39
|
-
def group_filter(gid)
|
40
|
-
Net::LDAP::Filter.eq("cn", gid)
|
41
|
-
end
|
42
|
-
|
43
|
-
def _group_names_from_cn(grouplist)
|
44
|
-
p = proc { |g| g.sub(/.*?cn=(.*?),.*/, '\1') }
|
45
|
-
grouplist.collect(&p)
|
18
|
+
get_groups(user[1][:memberof])
|
46
19
|
end
|
47
20
|
|
48
|
-
class UIDNotFoundException <
|
21
|
+
class UIDNotFoundException < LdapFluff::Error
|
49
22
|
end
|
50
23
|
|
51
|
-
class GIDNotFoundException <
|
24
|
+
class GIDNotFoundException < LdapFluff::Error
|
52
25
|
end
|
53
26
|
|
54
|
-
class InsufficientQueryPrivilegesException <
|
27
|
+
class InsufficientQueryPrivilegesException < LdapFluff::Error
|
55
28
|
end
|
56
29
|
|
57
30
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
class LdapFluff::Generic
|
2
|
+
attr_accessor :ldap, :member_service
|
3
|
+
|
4
|
+
def initialize(config = {})
|
5
|
+
@ldap = Net::LDAP.new(:host => config.host,
|
6
|
+
:base => config.base_dn,
|
7
|
+
:port => config.port,
|
8
|
+
:encryption => config.encryption)
|
9
|
+
@attr_login = config.attr_login
|
10
|
+
@group_base = (config.group_base.empty? ? config.base_dn : config.group_base)
|
11
|
+
@member_service = self.class::MemberService.new(@ldap, config)
|
12
|
+
end
|
13
|
+
|
14
|
+
def user_exists?(uid)
|
15
|
+
@member_service.find_user(uid)
|
16
|
+
true
|
17
|
+
rescue self.class::MemberService::UIDNotFoundException
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def group_exists?(gid)
|
22
|
+
@member_service.find_group(gid)
|
23
|
+
true
|
24
|
+
rescue self.class::MemberService::GIDNotFoundException
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def groups_for_uid(uid)
|
29
|
+
@member_service.find_user_groups(uid)
|
30
|
+
rescue self.class::MemberService::UIDNotFoundException
|
31
|
+
return []
|
32
|
+
end
|
33
|
+
|
34
|
+
def users_for_gid(gid)
|
35
|
+
return [] unless group_exists?(gid)
|
36
|
+
search = @member_service.find_group(gid).last
|
37
|
+
|
38
|
+
method = [:member, :ismemberof,
|
39
|
+
:memberof, :memberuid].find { |m| search.respond_to? m } or
|
40
|
+
raise 'Group does not have any members'
|
41
|
+
|
42
|
+
users_from_search_results(search, method)
|
43
|
+
end
|
44
|
+
|
45
|
+
def includes_cn?(cn)
|
46
|
+
filter = Net::LDAP::Filter.eq('cn', cn)
|
47
|
+
@ldap.search(:base => @ldap.base, :filter => filter).present?
|
48
|
+
end
|
49
|
+
|
50
|
+
def service_bind
|
51
|
+
unless @anon || bind?(@bind_user, @bind_pass)
|
52
|
+
raise UnauthenticatedException,
|
53
|
+
"Could not bind to #{class_name} user #{@bind_user}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
def class_name
|
59
|
+
self.class.name.split('::').last
|
60
|
+
end
|
61
|
+
|
62
|
+
def users_from_search_results(search, method)
|
63
|
+
members = search.send method
|
64
|
+
if method == :memberuid
|
65
|
+
# memberuid contains an array ['user1','user2'], no need to parse it
|
66
|
+
members
|
67
|
+
else
|
68
|
+
@member_service.get_logins(members)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class UnauthenticatedException < LdapFluff::Error
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'net/ldap'
|
2
|
+
|
3
|
+
class LdapFluff::GenericMemberService
|
4
|
+
|
5
|
+
attr_accessor :ldap
|
6
|
+
|
7
|
+
def initialize(ldap, config)
|
8
|
+
@ldap = ldap
|
9
|
+
@group_base = (config.group_base.empty? ? config.base_dn : config.group_base)
|
10
|
+
begin
|
11
|
+
@search_filter = Net::LDAP::Filter.construct(config.search_filter) unless (config.search_filter.nil? || config.search_filter.empty?)
|
12
|
+
rescue Net::LDAP::LdapError => error
|
13
|
+
puts "Search filter unavailable - #{error}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def find_user(uid)
|
18
|
+
user = @ldap.search(:filter => name_filter(uid))
|
19
|
+
raise self.class::UIDNotFoundException if (user.nil? || user.empty?)
|
20
|
+
user
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_group(gid)
|
24
|
+
group = @ldap.search(:filter => group_filter(gid), :base => @group_base)
|
25
|
+
raise self.class::GIDNotFoundException if (group.nil? || group.empty?)
|
26
|
+
group
|
27
|
+
end
|
28
|
+
|
29
|
+
def name_filter(uid)
|
30
|
+
filter = Net::LDAP::Filter.eq(@attr_login, uid)
|
31
|
+
|
32
|
+
if @search_filter.nil?
|
33
|
+
filter
|
34
|
+
else
|
35
|
+
filter & @search_filter
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def group_filter(gid)
|
40
|
+
Net::LDAP::Filter.eq("cn", gid)
|
41
|
+
end
|
42
|
+
|
43
|
+
# extract the group names from the LDAP style response,
|
44
|
+
# return string will be something like
|
45
|
+
# CN=bros,OU=bropeeps,DC=jomara,DC=redhat,DC=com
|
46
|
+
def get_groups(grouplist)
|
47
|
+
grouplist.map(&:downcase).collect { |g| g.sub(/.*?cn=(.*?),.*/, '\1') }
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_logins(userlist)
|
51
|
+
userlist.map(&:downcase!)
|
52
|
+
[@attr_login, 'uid', 'cn'].map do |attribute|
|
53
|
+
logins = userlist.collect { |g| g.sub(/.*?#{attribute}=(.*?),.*/, '\1') }
|
54
|
+
if logins == userlist
|
55
|
+
nil
|
56
|
+
else
|
57
|
+
logins
|
58
|
+
end
|
59
|
+
end.compact.flatten
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|