ldap_fluff 0.5.0 → 0.6.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.
- checksums.yaml +4 -4
- data/README.rdoc +7 -1
- data/lib/ldap_fluff/active_directory.rb +5 -7
- data/lib/ldap_fluff/ad_member_service.rb +38 -16
- data/lib/ldap_fluff/config.rb +5 -5
- data/lib/ldap_fluff/error.rb +0 -1
- data/lib/ldap_fluff/freeipa.rb +4 -7
- data/lib/ldap_fluff/freeipa_member_service.rb +1 -4
- data/lib/ldap_fluff/freeipa_netgroup_member_service.rb +0 -2
- data/lib/ldap_fluff/generic.rb +9 -9
- data/lib/ldap_fluff/generic_member_service.rb +2 -4
- data/lib/ldap_fluff/ldap_fluff.rb +9 -9
- data/lib/ldap_fluff/posix.rb +9 -10
- data/lib/ldap_fluff/posix_member_service.rb +1 -3
- data/lib/ldap_fluff/posix_netgroup_member_service.rb +0 -2
- data/test/ad_member_services_test.rb +19 -4
- data/test/ad_test.rb +22 -23
- data/test/config_test.rb +5 -5
- data/test/ipa_member_services_test.rb +2 -3
- data/test/ipa_netgroup_member_services_test.rb +0 -1
- data/test/ipa_test.rb +16 -18
- data/test/ldap_test.rb +8 -11
- data/test/lib/ldap_test_helper.rb +21 -18
- data/test/posix_member_services_test.rb +5 -5
- data/test/posix_netgroup_member_services_test.rb +5 -5
- data/test/posix_test.rb +17 -17
- metadata +13 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8c3b572c980fa3c48ede92f936858eb045cf54f6b507e6c7767de0751f85d9cc
|
4
|
+
data.tar.gz: 9280821c5a7ecc20c2300421d9a5947820de407da3480143b08c6ec146675dcb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4d74d42c9156af61cc485d6e8c1a99d1945aa97157659e627323f60e5b09807ea2c860fd10c62e9ce209d393200a5b57ef20205e8fc66eecf7762af7be56ee22
|
7
|
+
data.tar.gz: 1228b0a8730546ec3e38658bb3a86166bc10cb2af607a8d6e3ee77e3dd8c9ee465c0bbd2383ff1d8f5cdeed3053fd6a649dbdc8b145ccb29e47321ec7ef3e973
|
data/README.rdoc
CHANGED
@@ -83,6 +83,8 @@ ldap_fluff does not support searching/binding global catalogs
|
|
83
83
|
|
84
84
|
service_user (formatted as "ad_domain/username") and service_pass OR anon_queries are required for AD support
|
85
85
|
|
86
|
+
Group membership searches will use "msds-memberOfTransitive" where possible, and will fall back to a recursive lookup
|
87
|
+
|
86
88
|
=== A note on FreeIPA
|
87
89
|
|
88
90
|
ldap_fluff appends cn=groups,cn=accounts to the beginning of all BIND calls. You do not need to
|
@@ -99,6 +101,10 @@ ActiveSupport::Notifications. ldap_fluff will use this and also pass it to net-
|
|
99
101
|
When using Rails, pass `:instrumentation_service => ActiveSupport::Notifications` and then subscribe to, and
|
100
102
|
optionally log events (e.g. https://gist.github.com/mnutt/566725).
|
101
103
|
|
102
|
-
|
104
|
+
== Contributing
|
105
|
+
|
106
|
+
Feel free to file PR against our github repository.
|
107
|
+
|
108
|
+
== License
|
103
109
|
|
104
110
|
ldap_fluff is licensed under the GPLv2. Please read LICENSE for more information.
|
@@ -1,10 +1,9 @@
|
|
1
1
|
class LdapFluff::ActiveDirectory < LdapFluff::Generic
|
2
|
-
|
3
2
|
def bind?(uid = nil, password = nil, opts = {})
|
4
3
|
unless uid.include?(',') || uid.include?('\\') || opts[:search] == false
|
5
4
|
service_bind
|
6
5
|
user = @member_service.find_user(uid)
|
7
|
-
uid = user.first.dn if user
|
6
|
+
uid = user.first.dn if user&.first
|
8
7
|
end
|
9
8
|
@ldap.auth(uid, password)
|
10
9
|
@ldap.bind
|
@@ -18,9 +17,9 @@ class LdapFluff::ActiveDirectory < LdapFluff::Generic
|
|
18
17
|
begin
|
19
18
|
groups = @member_service.find_user_groups(uid)
|
20
19
|
intersection = gids & groups
|
21
|
-
|
20
|
+
(all ? intersection == gids : intersection.size > 0)
|
22
21
|
rescue MemberService::UIDNotFoundException
|
23
|
-
|
22
|
+
false
|
24
23
|
end
|
25
24
|
end
|
26
25
|
|
@@ -37,14 +36,13 @@ class LdapFluff::ActiveDirectory < LdapFluff::Generic
|
|
37
36
|
end
|
38
37
|
objectclasses = entry.objectclass.map(&:downcase)
|
39
38
|
|
40
|
-
if (%w
|
39
|
+
if (%w[organizationalperson person userproxy] & objectclasses).present?
|
41
40
|
users << @member_service.get_login_from_entry(entry)
|
42
|
-
elsif (%w
|
41
|
+
elsif (%w[organizationalunit group] & objectclasses).present?
|
43
42
|
users << users_for_gid(entry.cn.first)
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
47
46
|
users.flatten.uniq
|
48
47
|
end
|
49
|
-
|
50
48
|
end
|
@@ -2,26 +2,49 @@ require 'net/ldap'
|
|
2
2
|
|
3
3
|
# Naughty bits of active directory ldap queries
|
4
4
|
class LdapFluff::ActiveDirectory::MemberService < LdapFluff::GenericMemberService
|
5
|
-
|
6
5
|
def initialize(ldap, config)
|
7
6
|
@attr_login = (config.attr_login || 'samaccountname')
|
8
7
|
super
|
9
8
|
end
|
10
9
|
|
11
10
|
# get a list [] of ldap groups for a given user
|
12
|
-
#
|
11
|
+
# try to use msds-memberOfTransitive if it is supported, otherwise do a recursive loop
|
13
12
|
def find_user_groups(uid)
|
14
|
-
|
15
|
-
|
13
|
+
user_data = find_user(uid).first
|
14
|
+
|
15
|
+
if _get_domain_func_level >= 6
|
16
|
+
user_dn = user_data[:distinguishedname].first
|
17
|
+
search = @ldap.search(:base => user_dn, :scope => Net::LDAP::SearchScope_BaseObject, :attributes => ['msds-memberOfTransitive'])
|
18
|
+
if !search.nil? && !search.first.nil?
|
19
|
+
return get_groups(search.first['msds-memberoftransitive'])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Fall back to recursive lookup
|
24
|
+
_groups_from_ldap_data(user_data)
|
25
|
+
end
|
26
|
+
|
27
|
+
# return the domain functionality level, default to 0
|
28
|
+
def _get_domain_func_level
|
29
|
+
return @domain_functionality unless @domain_functionality.nil?
|
30
|
+
|
31
|
+
@domain_functionality = 0
|
32
|
+
|
33
|
+
search = @ldap.search(:base => "", :scope => Net::LDAP::SearchScope_BaseObject, :attributes => ['domainFunctionality'])
|
34
|
+
if !search.nil? && !search.first.nil?
|
35
|
+
@domain_functionality = search.first[:domainfunctionality].first.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
@domain_functionality
|
16
39
|
end
|
17
40
|
|
18
41
|
# return the :memberof attrs + parents, recursively
|
19
42
|
def _groups_from_ldap_data(payload)
|
20
43
|
data = []
|
21
|
-
|
22
|
-
first_level
|
23
|
-
total_groups,
|
24
|
-
data
|
44
|
+
unless payload.nil?
|
45
|
+
first_level = payload[:memberof]
|
46
|
+
total_groups, = _walk_group_ancestry(first_level, first_level)
|
47
|
+
data = get_groups(first_level + total_groups).uniq
|
25
48
|
end
|
26
49
|
data
|
27
50
|
end
|
@@ -31,14 +54,13 @@ class LdapFluff::ActiveDirectory::MemberService < LdapFluff::GenericMemberServic
|
|
31
54
|
set = []
|
32
55
|
group_dns.each do |group_dn|
|
33
56
|
search = @ldap.search(:base => group_dn, :scope => Net::LDAP::SearchScope_BaseObject, :attributes => ['memberof'])
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
57
|
+
next unless !search.nil? && !search.first.nil?
|
58
|
+
groups = search.first[:memberof] - known_groups
|
59
|
+
known_groups += groups
|
60
|
+
next_level, new_known_groups = _walk_group_ancestry(groups, known_groups)
|
61
|
+
set += next_level
|
62
|
+
set += groups
|
63
|
+
known_groups += next_level
|
42
64
|
end
|
43
65
|
[set, known_groups]
|
44
66
|
end
|
data/lib/ldap_fluff/config.rb
CHANGED
@@ -3,8 +3,8 @@ require 'active_support/core_ext/hash'
|
|
3
3
|
|
4
4
|
class LdapFluff::Config
|
5
5
|
ATTRIBUTES = %w[host port encryption base_dn group_base server_type service_user
|
6
|
-
|
7
|
-
|
6
|
+
service_pass anon_queries attr_login search_filter
|
7
|
+
instrumentation_service use_netgroups].freeze
|
8
8
|
ATTRIBUTES.each { |attr| attr_reader attr.to_sym }
|
9
9
|
|
10
10
|
DEFAULT_CONFIG = { 'port' => 389,
|
@@ -14,7 +14,7 @@ class LdapFluff::Config
|
|
14
14
|
'server_type' => :free_ipa,
|
15
15
|
'anon_queries' => false,
|
16
16
|
'instrumentation_service' => nil,
|
17
|
-
'use_netgroups' => false }
|
17
|
+
'use_netgroups' => false }.freeze
|
18
18
|
|
19
19
|
def initialize(config)
|
20
20
|
raise ArgumentError unless config.respond_to?(:to_hash)
|
@@ -65,9 +65,9 @@ class LdapFluff::Config
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def correct_server_type?(config)
|
68
|
-
unless [
|
68
|
+
unless %i[posix active_directory free_ipa].include?(config['server_type'])
|
69
69
|
raise ConfigError, 'config key server_type has to be :active_directory, :posix, :free_ipa ' +
|
70
|
-
|
70
|
+
"but was #{config['server_type']}"
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
data/lib/ldap_fluff/error.rb
CHANGED
data/lib/ldap_fluff/freeipa.rb
CHANGED
@@ -1,23 +1,20 @@
|
|
1
1
|
class LdapFluff::FreeIPA < LdapFluff::Generic
|
2
|
-
|
3
2
|
def bind?(uid = nil, password = nil, opts = {})
|
4
3
|
unless uid.include?(',')
|
5
4
|
unless opts[:search] == false
|
6
5
|
service_bind
|
7
6
|
user = @member_service.find_user(uid)
|
8
7
|
end
|
9
|
-
uid = user
|
8
|
+
uid = user&.first ? user.first.dn : "uid=#{uid},cn=users,cn=accounts,#{@base}"
|
10
9
|
end
|
11
10
|
@ldap.auth(uid, password)
|
12
11
|
@ldap.bind
|
13
12
|
end
|
14
13
|
|
15
14
|
def groups_for_uid(uid)
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
raise UnauthenticatedException, "Insufficient Privileges to query groups data"
|
20
|
-
end
|
15
|
+
super
|
16
|
+
rescue MemberService::InsufficientQueryPrivilegesException
|
17
|
+
raise UnauthenticatedException, "Insufficient Privileges to query groups data"
|
21
18
|
end
|
22
19
|
|
23
20
|
private
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'net/ldap'
|
2
2
|
|
3
3
|
class LdapFluff::FreeIPA::MemberService < LdapFluff::GenericMemberService
|
4
|
-
|
5
4
|
def initialize(ldap, config)
|
6
5
|
@attr_login = (config.attr_login || 'uid')
|
7
6
|
super
|
@@ -23,7 +22,7 @@ class LdapFluff::FreeIPA::MemberService < LdapFluff::GenericMemberService
|
|
23
22
|
# CN=bros,OU=bropeeps,DC=jomara,DC=redhat,DC=com
|
24
23
|
def get_groups(grouplist)
|
25
24
|
grouplist.map(&:downcase).collect do |g|
|
26
|
-
if
|
25
|
+
if /.*?ipauniqueid=(.*?)/.match?(g)
|
27
26
|
@ldap.search(:base => g)[0][:cn][0]
|
28
27
|
else
|
29
28
|
g.sub(/.*?cn=(.*?),.*/, '\1')
|
@@ -39,6 +38,4 @@ class LdapFluff::FreeIPA::MemberService < LdapFluff::GenericMemberService
|
|
39
38
|
|
40
39
|
class InsufficientQueryPrivilegesException < LdapFluff::Error
|
41
40
|
end
|
42
|
-
|
43
41
|
end
|
44
|
-
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'net/ldap'
|
2
2
|
|
3
3
|
class LdapFluff::FreeIPA::NetgroupMemberService < LdapFluff::FreeIPA::MemberService
|
4
|
-
|
5
4
|
def find_user_groups(uid)
|
6
5
|
groups = []
|
7
6
|
@ldap.search(:filter => Net::LDAP::Filter.eq('objectClass', 'nisNetgroup'), :base => @group_base).each do |entry|
|
@@ -11,4 +10,3 @@ class LdapFluff::FreeIPA::NetgroupMemberService < LdapFluff::FreeIPA::MemberServ
|
|
11
10
|
groups
|
12
11
|
end
|
13
12
|
end
|
14
|
-
|
data/lib/ldap_fluff/generic.rb
CHANGED
@@ -7,9 +7,9 @@ class LdapFluff::Generic
|
|
7
7
|
:port => config.port,
|
8
8
|
:encryption => config.encryption,
|
9
9
|
:instrumentation_service => config.instrumentation_service)
|
10
|
-
@bind_user
|
11
|
-
@bind_pass
|
12
|
-
@anon
|
10
|
+
@bind_user = config.service_user
|
11
|
+
@bind_pass = config.service_pass
|
12
|
+
@anon = config.anon_queries
|
13
13
|
@attr_login = config.attr_login
|
14
14
|
@base = config.base_dn
|
15
15
|
@group_base = (config.group_base.empty? ? config.base_dn : config.group_base)
|
@@ -37,7 +37,7 @@ class LdapFluff::Generic
|
|
37
37
|
service_bind
|
38
38
|
@member_service.find_user_groups(uid)
|
39
39
|
rescue self.class::MemberService::UIDNotFoundException
|
40
|
-
|
40
|
+
[]
|
41
41
|
end
|
42
42
|
|
43
43
|
def users_for_gid(gid)
|
@@ -60,9 +60,9 @@ class LdapFluff::Generic
|
|
60
60
|
groups = @member_service.find_user_groups(uid).sort
|
61
61
|
gids = gids.sort
|
62
62
|
if all
|
63
|
-
|
63
|
+
groups & gids == gids
|
64
64
|
else
|
65
|
-
|
65
|
+
(groups & gids).any?
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
@@ -74,16 +74,17 @@ class LdapFluff::Generic
|
|
74
74
|
def service_bind
|
75
75
|
unless @anon || bind?(@bind_user, @bind_pass, :search => false)
|
76
76
|
raise UnauthenticatedException,
|
77
|
-
|
77
|
+
"Could not bind to #{class_name} user #{@bind_user}"
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
81
|
private
|
82
|
+
|
82
83
|
def select_member_method(search_result)
|
83
84
|
if @use_netgroups
|
84
85
|
:nisnetgrouptriple
|
85
86
|
else
|
86
|
-
[
|
87
|
+
%i[member memberuid uniquemember].find { |m| search_result.respond_to? m }
|
87
88
|
end
|
88
89
|
end
|
89
90
|
|
@@ -114,4 +115,3 @@ class LdapFluff::Generic
|
|
114
115
|
class UnauthenticatedException < LdapFluff::Error
|
115
116
|
end
|
116
117
|
end
|
117
|
-
|
@@ -1,7 +1,6 @@
|
|
1
1
|
require 'net/ldap'
|
2
2
|
|
3
3
|
class LdapFluff::GenericMemberService
|
4
|
-
|
5
4
|
attr_accessor :ldap
|
6
5
|
|
7
6
|
def initialize(ldap, config)
|
@@ -11,8 +10,8 @@ class LdapFluff::GenericMemberService
|
|
11
10
|
@search_filter = nil
|
12
11
|
begin
|
13
12
|
@search_filter = Net::LDAP::Filter.construct(config.search_filter) unless (config.search_filter.nil? || config.search_filter.empty?)
|
14
|
-
rescue Net::LDAP::Error =>
|
15
|
-
puts "Search filter unavailable - #{
|
13
|
+
rescue Net::LDAP::Error => e
|
14
|
+
puts "Search filter unavailable - #{e}"
|
16
15
|
end
|
17
16
|
end
|
18
17
|
|
@@ -81,5 +80,4 @@ class LdapFluff::GenericMemberService
|
|
81
80
|
end
|
82
81
|
nil
|
83
82
|
end
|
84
|
-
|
85
83
|
end
|
@@ -20,7 +20,7 @@ class LdapFluff
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def authenticate?(uid, password)
|
23
|
-
instrument('authenticate.ldap_fluff', :uid => uid) do |
|
23
|
+
instrument('authenticate.ldap_fluff', :uid => uid) do |_payload|
|
24
24
|
if password.nil? || password.empty?
|
25
25
|
false
|
26
26
|
else
|
@@ -30,21 +30,21 @@ class LdapFluff
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def test
|
33
|
-
instrument('test.ldap_fluff') do |
|
33
|
+
instrument('test.ldap_fluff') do |_payload|
|
34
34
|
@ldap.ldap.open {}
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
38
|
# return a list[] of users for a given gid
|
39
39
|
def user_list(gid)
|
40
|
-
instrument('user_list.ldap_fluff', :gid => gid) do |
|
40
|
+
instrument('user_list.ldap_fluff', :gid => gid) do |_payload|
|
41
41
|
@ldap.users_for_gid(gid)
|
42
42
|
end
|
43
43
|
end
|
44
44
|
|
45
45
|
# return a list[] of groups for a given uid
|
46
46
|
def group_list(uid)
|
47
|
-
instrument('group_list.ldap_fluff', :uid => uid) do |
|
47
|
+
instrument('group_list.ldap_fluff', :uid => uid) do |_payload|
|
48
48
|
@ldap.groups_for_uid(uid)
|
49
49
|
end
|
50
50
|
end
|
@@ -52,35 +52,35 @@ class LdapFluff
|
|
52
52
|
# return true if a user is in all of the groups
|
53
53
|
# in grouplist
|
54
54
|
def is_in_groups?(uid, grouplist)
|
55
|
-
instrument('is_in_groups?.ldap_fluff', :uid => uid, :grouplist => grouplist) do |
|
55
|
+
instrument('is_in_groups?.ldap_fluff', :uid => uid, :grouplist => grouplist) do |_payload|
|
56
56
|
@ldap.is_in_groups(uid, grouplist, true)
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
60
|
# return true if uid exists
|
61
61
|
def valid_user?(uid)
|
62
|
-
instrument('valid_user?.ldap_fluff', :uid => uid) do |
|
62
|
+
instrument('valid_user?.ldap_fluff', :uid => uid) do |_payload|
|
63
63
|
@ldap.user_exists? uid
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
67
|
# return true if group exists
|
68
68
|
def valid_group?(gid)
|
69
|
-
instrument('valid_group?.ldap_fluff', :gid => gid) do |
|
69
|
+
instrument('valid_group?.ldap_fluff', :gid => gid) do |_payload|
|
70
70
|
@ldap.group_exists? gid
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
74
|
# return ldap entry
|
75
75
|
def find_user(uid)
|
76
|
-
instrument('find_user.ldap_fluff', :uid => uid) do |
|
76
|
+
instrument('find_user.ldap_fluff', :uid => uid) do |_payload|
|
77
77
|
@ldap.member_service.find_user(uid)
|
78
78
|
end
|
79
79
|
end
|
80
80
|
|
81
81
|
# return ldap entry
|
82
82
|
def find_group(gid)
|
83
|
-
instrument('find_group.ldap_fluff', :gid => gid) do |
|
83
|
+
instrument('find_group.ldap_fluff', :gid => gid) do |_payload|
|
84
84
|
@ldap.member_service.find_group(gid)
|
85
85
|
end
|
86
86
|
end
|
data/lib/ldap_fluff/posix.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
class LdapFluff::Posix < LdapFluff::Generic
|
2
|
-
|
3
2
|
def bind?(uid = nil, password = nil, opts = {})
|
4
3
|
unless uid.include?(',') || opts[:search] == false
|
5
4
|
service_bind
|
6
5
|
user = @member_service.find_user(uid)
|
7
|
-
uid = user.first.dn if user
|
6
|
+
uid = user.first.dn if user&.first
|
8
7
|
end
|
9
8
|
@ldap.auth(uid, password)
|
10
9
|
@ldap.bind
|
@@ -17,14 +16,14 @@ class LdapFluff::Posix < LdapFluff::Generic
|
|
17
16
|
# we have to look for OUs or posixGroups within the current group scope,
|
18
17
|
# i.e: cn=ldapusers,ou=groups,dc=example,dc=com -> cn=myusers,cn=ldapusers,ou=gr...
|
19
18
|
|
20
|
-
if @use_netgroups
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
19
|
+
filter = if @use_netgroups
|
20
|
+
Net::LDAP::Filter.eq('objectClass', 'nisNetgroup')
|
21
|
+
else
|
22
|
+
Net::LDAP::Filter.eq('objectClass', 'posixGroup') |
|
23
|
+
Net::LDAP::Filter.eq('objectClass', 'organizationalunit') |
|
24
|
+
Net::LDAP::Filter.eq('objectClass', 'groupOfUniqueNames') |
|
25
|
+
Net::LDAP::Filter.eq('objectClass', 'groupOfNames')
|
26
|
+
end
|
28
27
|
groups = @ldap.search(:base => search.dn, :filter => filter)
|
29
28
|
members = groups.map { |group| group.send(method) }.flatten.uniq
|
30
29
|
|