ldap_fluff 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
|