ldap_fluff 0.1.1

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.

@@ -0,0 +1,9 @@
1
+ ---
2
+ host: ## ip address or hostname
3
+ encryption: ## blank or :start_tls
4
+ base_dn: ## baseDN for ldap auth, eg dc=redhat,dc=com
5
+ group_base: ##baseDN for your ldap groups, eg ou=Groups,dc=redhat,dc=com
6
+ server_type: ## type of server. default == posix. :active_directory, :posix, :free_ipa
7
+ ad_domain: ## domain for your users if using active directory, eg redhat.com
8
+ ad_service_user: ## service account for authenticating ldap calls in active directory
9
+ ad_service_pass: ## service password for authenticating ldap calls in active directory
@@ -0,0 +1,63 @@
1
+ class LdapFluff::ActiveDirectory
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
+ @group_base = config.group_base
10
+ @group_base ||= config.base_dn
11
+ @ad_domain = config.domain
12
+ @bind_user = config.service_user
13
+ @bind_pass = config.service_pass
14
+ @anon = config.ad_anon_queries
15
+
16
+ @member_service = MemberService.new(@ldap,@group_base)
17
+ end
18
+
19
+ def bind?(uid=nil, password=nil)
20
+ @ldap.auth "#{uid}@#{@ad_domain}", password
21
+ @ldap.bind
22
+ end
23
+
24
+ # AD generally does not support un-authenticated searching
25
+ # Typically AD admins configure a public user for searching
26
+ def service_bind
27
+ unless @anon || bind?(@bind_user, @bind_pass)
28
+ raise UnauthenticatedActiveDirectoryException, "Could not bind to AD Service User"
29
+ end
30
+ end
31
+
32
+ # returns the list of groups to which a user belongs
33
+ # this query is simpler in active directory
34
+ def groups_for_uid(uid)
35
+ service_bind
36
+ begin
37
+ @member_service.find_user_groups(uid)
38
+ rescue MemberService::UIDNotFoundException
39
+ return []
40
+ end
41
+ end
42
+
43
+ # active directory stores group membership on a users model
44
+ # TODO query by group individually not like this
45
+ def is_in_groups(uid, gids = [], all = false)
46
+ service_bind
47
+ return true if gids == []
48
+ begin
49
+ groups = @member_service.find_user_groups(uid)
50
+ intersection = gids & groups
51
+ if all
52
+ return intersection == gids
53
+ else
54
+ return intersection.size > 0
55
+ end
56
+ rescue MemberService::UIDNotFoundException
57
+ return false
58
+ end
59
+ end
60
+
61
+ class UnauthenticatedActiveDirectoryException < StandardError
62
+ end
63
+ end
@@ -0,0 +1,75 @@
1
+ require 'net/ldap'
2
+
3
+ # Naughty bits of active directory ldap queries
4
+ class LdapFluff::ActiveDirectory::MemberService
5
+
6
+ attr_accessor :ldap
7
+
8
+ def initialize(ldap,group_base)
9
+ @ldap = ldap
10
+ @group_base = group_base
11
+ end
12
+
13
+ # get a list [] of ldap groups for a given user
14
+ # in active directory, this means a recursive lookup
15
+ def find_user_groups(uid)
16
+ data = @ldap.search(:filter => name_filter(uid))
17
+ raise UIDNotFoundException if (data == nil || data.empty?)
18
+ _groups_from_ldap_data(data.first)
19
+ end
20
+
21
+ # return the :memberof attrs + parents, recursively
22
+ def _groups_from_ldap_data(payload)
23
+ data = []
24
+ if payload != nil
25
+ first_level = _group_names_from_cn(payload[:memberof])
26
+ total_groups = _walk_group_ancestry(first_level)
27
+ data = (first_level + total_groups).uniq
28
+ end
29
+ data
30
+ end
31
+
32
+ # recursively loop over the parent list
33
+ def _walk_group_ancestry(gids=[])
34
+ set = []
35
+ gids.each do |g|
36
+ filter = group_filter(g) & class_filter
37
+ search = @ldap.search(:filter => filter, :base => @group_base)
38
+ if search != nil && search.first != nil
39
+ group = search.first
40
+ set += _group_names_from_cn(group[:memberof])
41
+ set += _walk_group_ancestry(set)
42
+ end
43
+ end
44
+ set
45
+ end
46
+
47
+ def group_filter(gid)
48
+ Net::LDAP::Filter.eq("cn", gid)
49
+ end
50
+
51
+ def class_filter
52
+ Net::LDAP::Filter.eq("objectclass","group")
53
+ end
54
+
55
+ def name_filter(uid)
56
+ Net::LDAP::Filter.eq("samaccountname",uid)
57
+ end
58
+
59
+ # extract the group names from the LDAP style response,
60
+ # return string will be something like
61
+ # CN=bros,OU=bropeeps,DC=jomara,DC=redhat,DC=com
62
+ #
63
+ # AD group proc from
64
+ # http://erniemiller.org/2008/04/04/simplified-active-directory-authentication/
65
+ #
66
+ # I think we would normally want to just do the collect at the end,
67
+ # but we need the individual names for recursive queries
68
+ def _group_names_from_cn(grouplist)
69
+ p = Proc.new { |g| g.sub(/.*?CN=(.*?),.*/, '\1') }
70
+ grouplist.collect(&p)
71
+ end
72
+
73
+ class UIDNotFoundException < StandardError
74
+ end
75
+ end
@@ -0,0 +1,51 @@
1
+ require 'singleton'
2
+ require 'yaml'
3
+
4
+ class LdapFluff
5
+ ####################################################################
6
+ # Module constants
7
+ ####################################################################
8
+ CONFIG = "/etc/ldap_fluff.yml"
9
+ ####################################################################
10
+ # Module class definitions
11
+ ####################################################################
12
+ class Config
13
+ include Singleton
14
+ attr_accessor :host,
15
+ :port,
16
+ :encryption,
17
+ :base_dn,
18
+ :group_base,
19
+ :server_type,
20
+ :ad_domain,
21
+ :service_user,
22
+ :service_pass,
23
+ :anon_queries
24
+
25
+ def initialize
26
+ begin
27
+ config = YAML.load_file(LdapFluff::CONFIG)
28
+ @host = config["host"]
29
+ @port = config["port"]
30
+ if config["encryption"].respond_to? :to_sym
31
+ @encryption = config["encryption"].to_sym
32
+ else
33
+ @encryption = nil
34
+ end
35
+ @base_dn = config["base_dn"]
36
+ @group_base = config["group_base"]
37
+ @ad_domain = config["ad_domain"]
38
+ @service_user = config["service_user"]
39
+ @service_pass = config["service_pass"]
40
+ @anon_queries = config["anon_queries"]
41
+ @server_type = config["server_type"]
42
+ rescue Errno::ENOENT
43
+ $stderr.puts("The #{LdapFluff::CONFIG} config file you specified was not found")
44
+ exit
45
+ rescue Errno::EACCES
46
+ $stderr.puts("The #{LdapFluff::CONFIG} config file you specified is not readable")
47
+ exit
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,65 @@
1
+ class LdapFluff::FreeIPA
2
+
3
+ attr_accessor :ldap, :member_service
4
+
5
+ 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
11
+ @group_base ||= config.base
12
+ @base = config.base_dn
13
+ @bind_user = config.service_user
14
+ @bind_pass = config.service_pass
15
+ @anon = config.anon_queries
16
+
17
+ @member_service = MemberService.new(@ldap,@group_base)
18
+ end
19
+
20
+ def bind?(uid=nil, password=nil)
21
+ @ldap.auth "uid=#{uid},cn=users,cn=accounts,#{@base}", password
22
+ @ldap.bind
23
+ end
24
+
25
+ def groups_for_uid(uid)
26
+ service_bind
27
+ begin
28
+ @member_service.find_user_groups(uid)
29
+ rescue MemberService::UIDNotFoundException
30
+ return []
31
+ rescue MemberService::InsufficientQueryPrivilegesException
32
+ raise UnauthenticatedFreeIPAException, "Insufficient Privileges to query groups data"
33
+ end
34
+ end
35
+
36
+ # AD generally does not support un-authenticated searching
37
+ # Typically AD admins configure a public user for searching
38
+ def service_bind
39
+ unless @anon || bind?(@bind_user, @bind_pass)
40
+ raise UnauthenticatedFreeIPAException, "Could not bind to FreeIPA Query User"
41
+ end
42
+ end
43
+
44
+ # In freeipa, a simple user query returns a full set
45
+ # of nested groups! yipee
46
+ #
47
+ # gids should be an array of group common names
48
+ #
49
+ # returns true if owner is in ALL of the groups if all=true, otherwise
50
+ # returns true if owner is in ANY of the groups
51
+ def is_in_groups(uid, gids = [], all=true)
52
+ service_bind
53
+ groups = @member_service.find_user_groups(uid)
54
+ if all
55
+ return groups & gids == gids
56
+ else
57
+ return groups & gids != []
58
+ end
59
+ end
60
+
61
+ class UnauthenticatedFreeIPAException < StandardError
62
+ end
63
+
64
+ end
65
+
@@ -0,0 +1,39 @@
1
+ require 'net/ldap'
2
+
3
+ # handles the naughty bits of posix ldap
4
+ class LdapFluff::FreeIPA::MemberService
5
+
6
+ attr_accessor :ldap
7
+
8
+ def initialize(ldap,group_base)
9
+ @ldap = ldap
10
+ @group_base = group_base
11
+ end
12
+
13
+ # return an ldap user with groups attached
14
+ # note : this method is not particularly fast for large ldap systems
15
+ def find_user_groups(uid)
16
+ user = @ldap.search(:filter => name_filter(uid))
17
+ raise UIDNotFoundException if (user == nil || user.empty?)
18
+ # if group data is missing, they aren't querying with a user
19
+ # with enough privileges
20
+ raise InsufficientQueryPrivilegesException if user.size <= 1
21
+ _group_names_from_cn(user[1][:memberof])
22
+ end
23
+
24
+ def name_filter(uid)
25
+ Net::LDAP::Filter.eq("uid",uid)
26
+ end
27
+
28
+ def _group_names_from_cn(grouplist)
29
+ p = Proc.new { |g| g.sub(/.*?cn=(.*?),.*/, '\1') }
30
+ grouplist.collect(&p)
31
+ end
32
+
33
+ class UIDNotFoundException < StandardError
34
+ end
35
+
36
+ class InsufficientQueryPrivilegesException < StandardError
37
+ end
38
+ end
39
+
@@ -0,0 +1,40 @@
1
+ require 'net/ldap'
2
+
3
+ class LdapFluff
4
+
5
+ attr_accessor :ldap
6
+
7
+ def initialize(config=nil)
8
+ config ||= LdapFluff::Config.instance
9
+ type = config.server_type
10
+ if type.respond_to? :to_sym
11
+ if type.to_sym == :posix
12
+ @ldap = Posix.new(config)
13
+ elsif type.to_sym == :active_directory
14
+ @ldap = ActiveDirectory.new(config)
15
+ elsif type.to_sym == :free_ipa
16
+ @ldap = FreeIPA.new(config)
17
+ else
18
+ raise Exception, "Unsupported connection type. Supported types = :active_directory, :posix, :free_ipa"
19
+ end
20
+ end
21
+ end
22
+
23
+ # return true if the user password combination
24
+ # authenticates the user, otherwise false
25
+ def authenticate?(uid, password)
26
+ @ldap.bind? uid, password
27
+ end
28
+
29
+ # return a list[] of groups for a given uid
30
+ def group_list(uid)
31
+ @ldap.groups_for_uid(uid)
32
+ end
33
+
34
+ # return true if a user is in all of the groups
35
+ # in grouplist
36
+ def is_in_groups?(uid, grouplist)
37
+ @ldap.is_in_groups(uid, grouplist, true)
38
+ end
39
+
40
+ end
@@ -0,0 +1,36 @@
1
+ class LdapFluff::Posix
2
+
3
+ attr_accessor :ldap, :member_service
4
+
5
+ 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
11
+ @group_base ||= config.base
12
+ @base = config.base_dn
13
+ @member_service = MemberService.new(@ldap,@group_base)
14
+ end
15
+
16
+ def bind?(uid=nil, password=nil)
17
+ @ldap.auth "uid=#{uid},#{@base}", password
18
+ @ldap.bind
19
+ end
20
+
21
+ def groups_for_uid(uid)
22
+ @member_service.find_user_groups(uid)
23
+ end
24
+
25
+ # returns whether a user is a member of ALL or ANY particular groups
26
+ # note: this method is much faster than groups_for_uid
27
+ #
28
+ # gids should be an array of group common names
29
+ #
30
+ # returns true if owner is in ALL of the groups if all=true, otherwise
31
+ # returns true if owner is in ANY of the groups
32
+ def is_in_groups(uid, gids = [], all=true)
33
+ (gids.empty? || @member_service.times_in_groups(uid, gids, all) > 0)
34
+ end
35
+
36
+ end
@@ -0,0 +1,56 @@
1
+ require 'net/ldap'
2
+
3
+ # handles the naughty bits of posix ldap
4
+ class LdapFluff::Posix::MemberService
5
+
6
+ attr_accessor :ldap
7
+
8
+ def initialize(ldap,group_base)
9
+ @ldap = ldap
10
+ @group_base = group_base
11
+ end
12
+
13
+ # return an ldap user with groups attached
14
+ # note : this method is not particularly fast for large ldap systems
15
+ def find_user_groups(uid)
16
+ groups = []
17
+ @ldap.search(:filter => name_filter(uid), :base => @group_base).each do |entry|
18
+ groups << entry[:cn][0]
19
+ end
20
+ groups
21
+ end
22
+
23
+ def times_in_groups(uid, gids, all)
24
+ matches = 0
25
+ filters = []
26
+ gids.each do |cn|
27
+ filters << group_filter(cn)
28
+ end
29
+ group_filters = merge_filters(filters,all)
30
+ filter = name_filter(uid) & group_filters
31
+ @ldap.search(:base => @group_base, :filter => filter).size
32
+ end
33
+
34
+ def name_filter(uid)
35
+ Net::LDAP::Filter.eq("memberUid",uid)
36
+ end
37
+
38
+ def group_filter(cn)
39
+ Net::LDAP::Filter.eq("cn", cn)
40
+ end
41
+
42
+ # AND or OR all of the filters together
43
+ def merge_filters(filters = [], all=false)
44
+ if filters != nil && filters.size >= 1
45
+ filter = filters[0]
46
+ filters[1..filters.size-1].each do |gfilter|
47
+ if all
48
+ filter = filter & gfilter
49
+ else
50
+ filter = filter | gfilter
51
+ end
52
+ end
53
+ return filter
54
+ end
55
+ end
56
+ end
data/lib/ldap_fluff.rb ADDED
@@ -0,0 +1,8 @@
1
+ require 'ldap_fluff/config'
2
+ require 'ldap_fluff/ldap_fluff'
3
+ require 'ldap_fluff/active_directory'
4
+ require 'ldap_fluff/ad_member_service'
5
+ require 'ldap_fluff/posix'
6
+ require 'ldap_fluff/posix_member_service'
7
+ require 'ldap_fluff/freeipa'
8
+ require 'ldap_fluff/freeipa_member_service'
@@ -0,0 +1,85 @@
1
+ require 'minitest/autorun'
2
+
3
+ class TestADMemberService < MiniTest::Unit::TestCase
4
+ include LdapTestHelper
5
+
6
+ def setup
7
+ config
8
+ @ldap = MiniTest::Mock.new
9
+ @adms = LdapFluff::ActiveDirectory::MemberService.new(@ldap,@config.group_base)
10
+ @gfilter = group_filter('group') & group_class_filter
11
+ end
12
+
13
+ def basic_user
14
+ @ldap.expect(:search, ad_user_payload, [:filter => ad_name_filter("john")])
15
+ @ldap.expect(:search, ad_parent_payload(1), [:filter => @gfilter, :base => @config.group_base])
16
+ end
17
+
18
+ def nest_deep(n)
19
+ # add all the expects
20
+ for i in 1..(n-1)
21
+ gfilter_bros = group_filter("bros#{i}") & group_class_filter
22
+ @ldap.expect(:search, ad_parent_payload(i+1), [:filter => gfilter_bros, :base => @config.group_base])
23
+ end
24
+ # terminate or we loop FOREVER
25
+ @ldap.expect(:search,[], [:filter => group_filter("bros#{n}") & group_class_filter, :base => @config.group_base])
26
+ end
27
+
28
+ def double_nested(n)
29
+ # add all the expects
30
+ for i in 1..(n-1)
31
+ gfilter_bros = group_filter("bros#{i}") & group_class_filter
32
+ @ldap.expect(:search, ad_double_payload(i+1), [:filter => gfilter_bros, :base => @config.group_base])
33
+ end
34
+ # terminate or we loop FOREVER
35
+ @ldap.expect(:search,[], [:filter => group_filter("bros#{n}") & group_class_filter, :base => @config.group_base])
36
+ (n-1).downto(1) do |i|
37
+ gfilter_bros = group_filter("broskies#{i+1}") & group_class_filter
38
+ @ldap.expect(:search,[], [:filter => gfilter_bros, :base => @config.group_base])
39
+ end
40
+ end
41
+
42
+ def test_find_user
43
+ basic_user
44
+ gfilter_bros = group_filter('bros1') & group_class_filter
45
+ @ldap.expect(:search, [], [:filter => gfilter_bros, :base => @config.group_base])
46
+ @adms.ldap = @ldap
47
+ assert_equal ['group', 'bros1'], @adms.find_user_groups("john")
48
+ @ldap.verify
49
+ end
50
+
51
+ def test_missing_user
52
+ @ldap.expect(:search, nil, [:filter => ad_name_filter("john")])
53
+ @adms.ldap = @ldap
54
+ assert_raises(LdapFluff::ActiveDirectory::MemberService::UIDNotFoundException) { @adms.find_user_groups("john").data }
55
+ @ldap.verify
56
+ end
57
+
58
+ def test_some_deep_recursion
59
+ basic_user
60
+ nest_deep(25)
61
+ @adms.ldap = @ldap
62
+ assert_equal 26, @adms.find_user_groups('john').size
63
+ @ldap.verify
64
+ end
65
+
66
+ def test_complex_recursion
67
+ basic_user
68
+ double_nested(5)
69
+ @adms.ldap = @ldap
70
+ assert_equal 10, @adms.find_user_groups('john').size
71
+ @ldap.verify
72
+ end
73
+
74
+ def test_nil_payload
75
+ assert_equal [], @adms._groups_from_ldap_data(nil)
76
+ end
77
+
78
+ def test_empty_user
79
+ @ldap.expect(:search, [], [:filter => ad_name_filter("john")])
80
+ @adms.ldap = @ldap
81
+ assert_raises(LdapFluff::ActiveDirectory::MemberService::UIDNotFoundException) { @adms.find_user_groups("john").data }
82
+ @ldap.verify
83
+ end
84
+
85
+ end
data/test/ad_test.rb ADDED
@@ -0,0 +1,100 @@
1
+ require 'minitest/autorun'
2
+
3
+ class TestAD < MiniTest::Unit::TestCase
4
+ include LdapTestHelper
5
+
6
+ def setup
7
+ config
8
+ @ad = LdapFluff::ActiveDirectory.new(@config)
9
+ @ldap = MiniTest::Mock.new
10
+ end
11
+
12
+ # default setup for service bind users
13
+ def service_bind
14
+ @ldap.expect(:auth, nil, ["service@internet.com","pass"])
15
+ @ldap.expect(:bind, true)
16
+ @ad.ldap = @ldap
17
+ end
18
+
19
+ def basic_user
20
+ @md = MiniTest::Mock.new
21
+ @md.expect(:find_user_groups, ['bros'], ["john"])
22
+ @ad.member_service = @md
23
+ end
24
+
25
+ def bigtime_user
26
+ @md = MiniTest::Mock.new
27
+ @md.expect(:find_user_groups, ['bros','broskies'], ["john"])
28
+ @ad.member_service = @md
29
+ end
30
+
31
+ def test_good_bind
32
+ @ldap.expect(:auth, nil, ["internet@internet.com","password"])
33
+ @ldap.expect(:bind, true)
34
+ @ad.ldap = @ldap
35
+ assert_equal @ad.bind?("internet", "password"), true
36
+ @ldap.verify
37
+ end
38
+
39
+ def test_bad_bind
40
+ @ldap.expect(:auth, nil, ["internet@internet.com","password"])
41
+ @ldap.expect(:bind, false)
42
+ @ad.ldap = @ldap
43
+ assert_equal @ad.bind?("internet", "password"), false
44
+ @ldap.verify
45
+ end
46
+
47
+ def test_groups
48
+ service_bind
49
+ basic_user
50
+ assert_equal @ad.groups_for_uid('john'), ['bros']
51
+ end
52
+
53
+ def test_bad_user
54
+ service_bind
55
+ @md = MiniTest::Mock.new
56
+ @md.expect(:find_user_groups, nil, ["john"])
57
+ def @md.find_user_groups(*args)
58
+ raise LdapFluff::ActiveDirectory::MemberService::UIDNotFoundException
59
+ end
60
+ @ad.member_service = @md
61
+ assert_equal @ad.groups_for_uid('john'), []
62
+ end
63
+
64
+ def test_bad_service_user
65
+ @ldap.expect(:auth, nil, ["service@internet.com","pass"])
66
+ @ldap.expect(:bind, false)
67
+ @ad.ldap = @ldap
68
+ assert_raises(LdapFluff::ActiveDirectory::UnauthenticatedActiveDirectoryException) { @ad.groups_for_uid('john') }
69
+ end
70
+
71
+ def test_is_in_groups
72
+ service_bind
73
+ basic_user
74
+ assert_equal @ad.is_in_groups("john",["bros"],false), true
75
+ end
76
+
77
+ def test_is_some_groups
78
+ service_bind
79
+ basic_user
80
+ assert_equal @ad.is_in_groups("john",["bros","buds"],false), true
81
+ end
82
+
83
+ def test_isnt_in_all_groups
84
+ service_bind
85
+ basic_user
86
+ assert_equal @ad.is_in_groups("john",["bros","buds"],true), false
87
+ end
88
+
89
+ def test_isnt_in_groups
90
+ service_bind
91
+ basic_user
92
+ assert_equal @ad.is_in_groups("john", ["broskies"],false), false
93
+ end
94
+
95
+ def test_group_subset
96
+ service_bind
97
+ bigtime_user
98
+ assert_equal @ad.is_in_groups("john", ["broskies"],true), true
99
+ end
100
+ end
@@ -0,0 +1,34 @@
1
+ require 'minitest/autorun'
2
+ require 'ldap_fluff'
3
+
4
+ class ConfigTest < MiniTest::Unit::TestCase
5
+ include LdapTestHelper
6
+
7
+ def setup
8
+ config
9
+ end
10
+
11
+ def test_unsupported_type
12
+ @config.server_type = "inactive_directory"
13
+ assert_raises(Exception) { LdapFluff.new(@config) }
14
+ end
15
+
16
+ def test_load_posix
17
+ @config.server_type = "posix"
18
+ l = LdapFluff.new(@config)
19
+ assert_instance_of LdapFluff::Posix, l.ldap
20
+ end
21
+
22
+ def test_load_ad
23
+ @config.server_type = "active_directory"
24
+ l = LdapFluff.new(@config)
25
+ assert_instance_of LdapFluff::ActiveDirectory, l.ldap
26
+ end
27
+
28
+ def test_load_ad
29
+ @config.server_type = "free_ipa"
30
+ l = LdapFluff.new(@config)
31
+ assert_instance_of LdapFluff::FreeIPA, l.ldap
32
+ end
33
+
34
+ end
@@ -0,0 +1,36 @@
1
+ require 'minitest/autorun'
2
+
3
+ class TestIPAMemberService < MiniTest::Unit::TestCase
4
+ include LdapTestHelper
5
+
6
+ def setup
7
+ config
8
+ @ldap = MiniTest::Mock.new
9
+ @ipams = LdapFluff::FreeIPA::MemberService.new(@ldap,@config.group_base)
10
+ end
11
+
12
+ def basic_user
13
+ @ldap.expect(:search, ipa_user_payload, [:filter => ipa_name_filter("john")])
14
+ end
15
+
16
+ def test_find_user
17
+ basic_user
18
+ @ipams.ldap = @ldap
19
+ assert_equal ['group', 'bros'], @ipams.find_user_groups("john")
20
+ @ldap.verify
21
+ end
22
+
23
+ def test_missing_user
24
+ @ldap.expect(:search, nil, [:filter => ipa_name_filter("john")])
25
+ @ipams.ldap = @ldap
26
+ assert_raises(LdapFluff::FreeIPA::MemberService::UIDNotFoundException) { @ipams.find_user_groups("john").data }
27
+ @ldap.verify
28
+ end
29
+
30
+ def test_no_groups
31
+ @ldap.expect(:search, ['',{:memberof=>[]}], [:filter => ipa_name_filter("john")])
32
+ @ipams.ldap = @ldap
33
+ assert_equal [], @ipams.find_user_groups('john')
34
+ @ldap.verify
35
+ end
36
+ end
data/test/ipa_test.rb ADDED
@@ -0,0 +1,101 @@
1
+ require 'minitest/autorun'
2
+
3
+ class TestIPA < MiniTest::Unit::TestCase
4
+ include LdapTestHelper
5
+
6
+ def setup
7
+ config
8
+ @ipa = LdapFluff::FreeIPA.new(@config)
9
+ @ldap = MiniTest::Mock.new
10
+ end
11
+
12
+ # default setup for service bind users
13
+ def service_bind
14
+ @ldap.expect(:auth, nil, [ipa_user_bind('service'),"pass"])
15
+ @ldap.expect(:bind, true)
16
+ @ipa.ldap = @ldap
17
+ end
18
+
19
+ def basic_user
20
+ @md = MiniTest::Mock.new
21
+ @md.expect(:find_user_groups, ['bros'], ["john"])
22
+ @ipa.member_service = @md
23
+ end
24
+
25
+ def bigtime_user
26
+ @md = MiniTest::Mock.new
27
+ @md.expect(:find_user_groups, ['bros','broskies'], ["john"])
28
+ @ipa.member_service = @md
29
+ end
30
+
31
+ def test_good_bind
32
+ @ldap.expect(:auth, nil, [ipa_user_bind('internet'),"password"])
33
+ @ldap.expect(:bind, true)
34
+ @ipa.ldap = @ldap
35
+ assert_equal @ipa.bind?("internet", "password"), true
36
+ @ldap.verify
37
+ end
38
+
39
+ def test_bad_bind
40
+ @ldap.expect(:auth, nil, [ipa_user_bind('internet'),"password"])
41
+ @ldap.expect(:bind, false)
42
+ @ipa.ldap = @ldap
43
+ assert_equal @ipa.bind?("internet", "password"), false
44
+ @ldap.verify
45
+ end
46
+
47
+ def test_groups
48
+ service_bind
49
+ basic_user
50
+ assert_equal @ipa.groups_for_uid('john'), ['bros']
51
+ end
52
+
53
+ def test_bad_user
54
+ service_bind
55
+ @md = MiniTest::Mock.new
56
+ @md.expect(:find_user_groups, nil, ["john"])
57
+ def @md.find_user_groups(*args)
58
+ raise LdapFluff::FreeIPA::MemberService::UIDNotFoundException
59
+ end
60
+ @ipa.member_service = @md
61
+ assert_equal @ipa.groups_for_uid('john'), []
62
+ end
63
+
64
+ def test_bad_service_user
65
+ @ldap.expect(:auth, nil, [ipa_user_bind('service'),"pass"])
66
+ @ldap.expect(:bind, false)
67
+ @ipa.ldap = @ldap
68
+ assert_raises(LdapFluff::FreeIPA::UnauthenticatedFreeIPAException) { @ipa.groups_for_uid('john') }
69
+ end
70
+
71
+ def test_is_in_groups
72
+ service_bind
73
+ basic_user
74
+ assert_equal @ipa.is_in_groups("john",["bros"],false), true
75
+ end
76
+
77
+ def test_is_some_groups
78
+ service_bind
79
+ basic_user
80
+ assert_equal @ipa.is_in_groups("john",["bros","buds"],false), true
81
+ end
82
+
83
+ def test_isnt_in_all_groups
84
+ service_bind
85
+ basic_user
86
+ assert_equal @ipa.is_in_groups("john",["bros","buds"],true), false
87
+ end
88
+
89
+ def test_isnt_in_groups
90
+ service_bind
91
+ basic_user
92
+ assert_equal @ipa.is_in_groups("john", ["broskies"],false), false
93
+ end
94
+
95
+ def test_group_subset
96
+ service_bind
97
+ bigtime_user
98
+ assert_equal @ipa.is_in_groups('john',["broskies"],true), true
99
+ end
100
+ end
101
+
data/test/ldap_test.rb ADDED
@@ -0,0 +1,34 @@
1
+ require 'minitest/autorun'
2
+
3
+ class TestLDAP < MiniTest::Unit::TestCase
4
+ include LdapTestHelper
5
+
6
+ def setup
7
+ config
8
+ @ldap = MiniTest::Mock.new
9
+ @fluff = LdapFluff.new(@config)
10
+ end
11
+
12
+ def test_bind
13
+ @ldap.expect(:bind?, true, ['john','password'])
14
+ @fluff.ldap = @ldap
15
+ assert_equal @fluff.authenticate?("john","password"), true
16
+ @ldap.verify
17
+ end
18
+
19
+ def test_groups
20
+ @ldap.expect(:groups_for_uid, ['bros'], ['john'])
21
+ @fluff.ldap = @ldap
22
+ assert_equal @fluff.group_list('john'), ['bros']
23
+ @ldap.verify
24
+ end
25
+
26
+ def test_group_membership
27
+ @ldap.expect(:is_in_groups, false, ['john',['broskies','girlfriends'],true])
28
+ @fluff.ldap = @ldap
29
+ assert_equal @fluff.is_in_groups?('john',['broskies','girlfriends']), false
30
+ @ldap.verify
31
+ end
32
+ end
33
+
34
+
@@ -0,0 +1,59 @@
1
+ require 'net/ldap'
2
+ require 'ostruct'
3
+
4
+ module LdapTestHelper
5
+ attr_accessor :group_base, :class_filter, :user
6
+
7
+ def config
8
+ @config = OpenStruct.new(
9
+ :host => "internet.com",
10
+ :port => "387",
11
+ :encryption => :start_tls,
12
+ :base_dn => "dc=internet,dc=com",
13
+ :group_base => "ou=group,dc=internet,dc=com",
14
+ :service_user => "service",
15
+ :service_pass => "pass",
16
+ :domain => "internet.com"
17
+ )
18
+ end
19
+
20
+ def ad_name_filter(name)
21
+ Net::LDAP::Filter.eq("samaccountname",name)
22
+ end
23
+
24
+ def ipa_name_filter(name)
25
+ Net::LDAP::Filter.eq("uid",name)
26
+ end
27
+
28
+ def group_filter(g)
29
+ Net::LDAP::Filter.eq("cn", g)
30
+ end
31
+
32
+ def group_class_filter
33
+ Net::LDAP::Filter.eq("objectclass","group")
34
+ end
35
+
36
+ def ipa_user_bind(uid)
37
+ "uid=#{uid},cn=users,cn=accounts,#{@config.base_dn}"
38
+ end
39
+
40
+ def ad_user_payload
41
+ [{ :memberof => ["CN=group,dc=internet,dc=com"] }]
42
+ end
43
+
44
+ def ad_parent_payload(num)
45
+ [{ :memberof => ["CN=bros#{num},dc=internet,dc=com"] }]
46
+ end
47
+
48
+ def ad_double_payload(num)
49
+ [{ :memberof => ["CN=bros#{num},dc=internet,dc=com", "CN=broskies#{num},dc=internet,dc=com"] }]
50
+ end
51
+
52
+ def posix_user_payload
53
+ [{:cn => ["bros"]}]
54
+ end
55
+
56
+ def ipa_user_payload
57
+ [{:cn => 'user'},{:memberof => ['cn=group,dc=internet,dc=com','cn=bros,dc=internet,dc=com']}]
58
+ end
59
+ end
@@ -0,0 +1,25 @@
1
+ require 'minitest/autorun'
2
+
3
+ class TestPosixMemberService < MiniTest::Unit::TestCase
4
+ include LdapTestHelper
5
+
6
+ def setup
7
+ config
8
+ @ldap = MiniTest::Mock.new
9
+ @ms = LdapFluff::Posix::MemberService.new(@ldap, @config.group_base)
10
+ end
11
+
12
+ def test_find_user
13
+ user = posix_user_payload
14
+ @ldap.expect(:search,
15
+ user,
16
+ [
17
+ :filter => @ms.name_filter('john'),
18
+ :base =>config.group_base
19
+ ]
20
+ )
21
+ @ms.ldap = @ldap
22
+ assert_equal ['bros'], @ms.find_user_groups('john')
23
+ @ldap.verify
24
+ end
25
+ end
@@ -0,0 +1,64 @@
1
+ require 'minitest/autorun'
2
+
3
+ class TestPosix < MiniTest::Unit::TestCase
4
+ include LdapTestHelper
5
+
6
+ def setup
7
+ config
8
+ @posix = LdapFluff::Posix.new(@config)
9
+ @ldap = MiniTest::Mock.new
10
+ end
11
+
12
+ def basic_user
13
+ @md = MiniTest::Mock.new
14
+ @md.expect(:find_user_groups, ['bros'], ["john"])
15
+ @posix.member_service = @md
16
+ end
17
+
18
+ def test_groups
19
+ basic_user
20
+ assert_equal @posix.groups_for_uid("john"), ['bros']
21
+ end
22
+
23
+ def test_missing_user
24
+ @md = MiniTest::Mock.new
25
+ @md.expect(:find_user_groups, [], ['john'])
26
+ @posix.member_service = @md
27
+ assert_equal [], @posix.groups_for_uid('john')
28
+ end
29
+
30
+ def test_isnt_in_groups
31
+ basic_user
32
+ @md = MiniTest::Mock.new
33
+ @md.expect(:times_in_groups, 0, ['john', ['bros'], true])
34
+ @posix.member_service = @md
35
+ assert_equal @posix.is_in_groups('john', ['bros'], true), false
36
+ end
37
+
38
+ def test_is_in_groups
39
+ basic_user
40
+ @md = MiniTest::Mock.new
41
+ @md.expect(:times_in_groups, 1, ['john', ['bros'], true])
42
+ @posix.member_service = @md
43
+ assert_equal @posix.is_in_groups('john', ['bros'], true), true
44
+ end
45
+
46
+ def test_is_in_no_groups
47
+ basic_user
48
+ assert_equal @posix.is_in_groups('john', [], true), true
49
+ end
50
+
51
+ def test_good_bind
52
+ @ldap.expect(:auth, nil, ["uid=internet,dc=internet,dc=com","password"])
53
+ @ldap.expect(:bind, true)
54
+ @posix.ldap = @ldap
55
+ assert_equal @posix.bind?("internet", "password"), true
56
+ end
57
+
58
+ def test_bad_bind
59
+ @ldap.expect(:auth, nil, ["uid=internet,dc=internet,dc=com","password"])
60
+ @ldap.expect(:bind, false)
61
+ @posix.ldap = @ldap
62
+ assert_equal @posix.bind?("internet", "password"), false
63
+ end
64
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ldap_fluff
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jordan OMara
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-09 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: net-ldap
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: minitest
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ description: ! 'Simple library for binding & group querying on top of various ldap
47
+ implementations
48
+
49
+ '
50
+ email: jomara@redhat.com
51
+ executables: []
52
+ extensions: []
53
+ extra_rdoc_files: []
54
+ files:
55
+ - etc/ldap_fluff.yml
56
+ - lib/ldap_fluff.rb
57
+ - lib/ldap_fluff/active_directory.rb
58
+ - lib/ldap_fluff/posix.rb
59
+ - lib/ldap_fluff/freeipa.rb
60
+ - lib/ldap_fluff/ldap_fluff.rb
61
+ - lib/ldap_fluff/config.rb
62
+ - lib/ldap_fluff/ad_member_service.rb
63
+ - lib/ldap_fluff/posix_member_service.rb
64
+ - lib/ldap_fluff/freeipa_member_service.rb
65
+ - test/ldap_test.rb
66
+ - test/ipa_member_services_test.rb
67
+ - test/posix_test.rb
68
+ - test/config_test.rb
69
+ - test/ipa_test.rb
70
+ - test/ad_test.rb
71
+ - test/ad_member_services_test.rb
72
+ - test/posix_member_services_test.rb
73
+ - test/lib/ldap_test_helper.rb
74
+ homepage: http://www.redhat.com
75
+ licenses: []
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ! '>='
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 1.8.24
95
+ signing_key:
96
+ specification_version: 3
97
+ summary: LDAP Querying tools for Active Directory, FreeIPA and Posix-style
98
+ test_files: []