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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba638e83446c1328ec6d7880ccf1528f1a42db4dab9a8884bbd4c8974512632c
4
- data.tar.gz: 69c6c3752b330047a953b9e8c4a2c7441f39edb28bccaef32b49fef56b0d21c4
3
+ metadata.gz: 8c3b572c980fa3c48ede92f936858eb045cf54f6b507e6c7767de0751f85d9cc
4
+ data.tar.gz: 9280821c5a7ecc20c2300421d9a5947820de407da3480143b08c6ec146675dcb
5
5
  SHA512:
6
- metadata.gz: b108ae2845030a2e3ea119716b11e7023cd52f4afad32cc48945c8d455a3cf3608755b82bb583373892a6ba0255b030a3750d9f367840e4912860d93e1f8e900
7
- data.tar.gz: 315aebba32f13f1f8a62c4f7ce7dd5f49c395fc4950e197029c7818a43eb94fd8ec04c8cb7626c717db4fcb60b1dd61ff8d2d87332140a3c2ecf7a081b7ec682
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
- === License
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 && user.first
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
- return (all ? intersection == gids : intersection.size > 0)
20
+ (all ? intersection == gids : intersection.size > 0)
22
21
  rescue MemberService::UIDNotFoundException
23
- return false
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(organizationalperson person userproxy) & objectclasses).present?
39
+ if (%w[organizationalperson person userproxy] & objectclasses).present?
41
40
  users << @member_service.get_login_from_entry(entry)
42
- elsif (%w(organizationalunit group) & objectclasses).present?
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
- # in active directory, this means a recursive lookup
11
+ # try to use msds-memberOfTransitive if it is supported, otherwise do a recursive loop
13
12
  def find_user_groups(uid)
14
- data = find_user(uid)
15
- _groups_from_ldap_data(data.first)
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
- if !payload.nil?
22
- first_level = payload[:memberof]
23
- total_groups, _ = _walk_group_ancestry(first_level, first_level)
24
- data = (get_groups(first_level + total_groups)).uniq
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
- if !search.nil? && !search.first.nil?
35
- groups = search.first[:memberof] - known_groups
36
- known_groups += groups
37
- next_level, new_known_groups = _walk_group_ancestry(groups, known_groups)
38
- set += next_level
39
- set += groups
40
- known_groups += next_level
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
@@ -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
- service_pass anon_queries attr_login search_filter
7
- instrumentation_service use_netgroups]
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 [:posix, :active_directory, :free_ipa].include?(config['server_type'])
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
- "but was #{config['server_type']}"
70
+ "but was #{config['server_type']}"
71
71
  end
72
72
  end
73
73
 
@@ -2,4 +2,3 @@ class LdapFluff
2
2
  class Error < StandardError
3
3
  end
4
4
  end
5
-
@@ -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 && user.first ? user.first.dn : "uid=#{uid},cn=users,cn=accounts,#{@base}"
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
- begin
17
- super
18
- rescue MemberService::InsufficientQueryPrivilegesException
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 g.match(/.*?ipauniqueid=(.*?)/)
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
-
@@ -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 = config.service_user
11
- @bind_pass = config.service_pass
12
- @anon = config.anon_queries
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
- return []
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
- return groups & gids == gids
63
+ groups & gids == gids
64
64
  else
65
- return (groups & gids).any?
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
- "Could not bind to #{class_name} user #{@bind_user}"
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
- [:member, :memberuid, :uniquemember].find { |m| search_result.respond_to? m }
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 => error
15
- puts "Search filter unavailable - #{error}"
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 |payload|
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 |payload|
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 |payload|
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 |payload|
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 |payload|
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 |payload|
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 |payload|
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 |payload|
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 |payload|
83
+ instrument('find_group.ldap_fluff', :gid => gid) do |_payload|
84
84
  @ldap.member_service.find_group(gid)
85
85
  end
86
86
  end
@@ -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 && user.first
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
- filter = Net::LDAP::Filter.eq('objectClass', 'nisNetgroup')
22
- else
23
- filter = Net::LDAP::Filter.eq('objectClass','posixGroup') |
24
- Net::LDAP::Filter.eq('objectClass', 'organizationalunit') |
25
- Net::LDAP::Filter.eq('objectClass', 'groupOfUniqueNames') |
26
- Net::LDAP::Filter.eq('objectClass', 'groupOfNames')
27
- end
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