ldap_fluff 0.1.1

Sign up to get free protection for your applications and to get access to all the features.

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: []