ldap_fluff 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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