jruby-ldap-patched 0.0.3
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 +7 -0
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/History.txt +7 -0
- data/LICENSE +20 -0
- data/README +14 -0
- data/Rakefile +14 -0
- data/jruby-ldap.gemspec +20 -0
- data/lib/jruby-ldap.rb +7 -0
- data/lib/jruby-ldap/version.rb +5 -0
- data/lib/ldap.rb +83 -0
- data/lib/ldap/conn.rb +285 -0
- data/lib/ldap/constants.rb +126 -0
- data/lib/ldap/control.rb +48 -0
- data/lib/ldap/entry.rb +64 -0
- data/lib/ldap/error.rb +14 -0
- data/lib/ldap/ldif.rb +567 -0
- data/lib/ldap/mod.rb +74 -0
- data/lib/ldap/schema.rb +131 -0
- data/test/setup.rb +52 -0
- data/test/test_add.rb +21 -0
- data/test/test_connection.rb +52 -0
- data/test/test_delete.rb +21 -0
- data/test/test_search.rb +87 -0
- data/test/test_ssl.rb +21 -0
- metadata +88 -0
data/lib/ldap/mod.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
module LDAP
|
2
|
+
class << self
|
3
|
+
def mod(mod_type, attr, vals)
|
4
|
+
Mod.new(mod_type, attr, vals)
|
5
|
+
end
|
6
|
+
|
7
|
+
def hash2mods(mod_type, hash)
|
8
|
+
hash.map do |key, value|
|
9
|
+
mod(mod_type, key, value)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Mod
|
15
|
+
BasicAttributes = javax.naming.directory.BasicAttributes
|
16
|
+
BasicAttribute = javax.naming.directory.BasicAttribute
|
17
|
+
ModificationItem = javax.naming.directory.ModificationItem
|
18
|
+
DirContext = javax.naming.directory.DirContext
|
19
|
+
class << self
|
20
|
+
def to_java_attributes(*attrs)
|
21
|
+
attrs.inject(BasicAttributes.new) do |res, attr|
|
22
|
+
res.put(attr.to_java_attribute)
|
23
|
+
res
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def ruby_mod_to_java(mod_op)
|
28
|
+
case (mod_op&~LDAP::LDAP_MOD_BVALUES)
|
29
|
+
when LDAP::LDAP_MOD_ADD then DirContext::ADD_ATTRIBUTE
|
30
|
+
when LDAP::LDAP_MOD_REPLACE then DirContext::REPLACE_ATTRIBUTE
|
31
|
+
when LDAP::LDAP_MOD_DELETE then DirContext::REMOVE_ATTRIBUTE
|
32
|
+
else raise LDAP::Error, "can't handle operation #{mod_op}"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_java_modification_items(*attrs)
|
37
|
+
attrs.map do |val|
|
38
|
+
ModificationItem.new(ruby_mod_to_java(val.mod_op), val.to_java_attribute)
|
39
|
+
end.to_java ModificationItem
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def initialize(mod_type, attr, vals)
|
44
|
+
@type, @attr, @vals = mod_type, attr, vals
|
45
|
+
end
|
46
|
+
|
47
|
+
def mod_op #should be mod_type
|
48
|
+
@type
|
49
|
+
end
|
50
|
+
|
51
|
+
def mod_type #should be attr
|
52
|
+
@attr
|
53
|
+
end
|
54
|
+
|
55
|
+
def mod_vals
|
56
|
+
@vals
|
57
|
+
end
|
58
|
+
|
59
|
+
def to_java_attribute
|
60
|
+
v = BasicAttribute.new(self.mod_type)
|
61
|
+
binary = mod_op & LDAP::LDAP_MOD_BVALUES
|
62
|
+
if binary != 0
|
63
|
+
self.mod_vals.each do |val|
|
64
|
+
v.add(val.to_java_bytes)
|
65
|
+
end
|
66
|
+
else
|
67
|
+
self.mod_vals.each do |val|
|
68
|
+
v.add(val)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
v
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/ldap/schema.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
# Manipulation of LDAP schema data.
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# $Id: schema.rb,v 1.9 2006/02/08 23:15:17 ianmacd Exp $
|
5
|
+
#++
|
6
|
+
|
7
|
+
# The LDAP module encapsulates the various LDAP-related classes in their own
|
8
|
+
# namespace.
|
9
|
+
#
|
10
|
+
module LDAP
|
11
|
+
|
12
|
+
# Retrieve and process information pertaining to LDAP schemas.
|
13
|
+
#
|
14
|
+
class Schema < Hash
|
15
|
+
|
16
|
+
def initialize(entry)
|
17
|
+
if( entry )
|
18
|
+
entry.each{|key,vals|
|
19
|
+
self[key] = vals
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Return the list of values related to the schema component given in
|
25
|
+
# +key+. See LDAP::Conn#schema for common values of +key+.
|
26
|
+
#
|
27
|
+
def names(key)
|
28
|
+
self[key].collect{|val| val =~ /NAME\s+'([\w\d_-]+)'/; $1}
|
29
|
+
end
|
30
|
+
|
31
|
+
# Return the list of attributes in object class +oc+ that are of category
|
32
|
+
# +at+. +at+ may be the string *MUST*, *MAY* or *SUP*.
|
33
|
+
#
|
34
|
+
def attr(oc,at)
|
35
|
+
self['objectClasses'].each{|s|
|
36
|
+
if( s =~ /NAME\s+'#{oc}'/ )
|
37
|
+
case s
|
38
|
+
when /#{at}\s+\(([\w\d_-\s\$]+)\)/i
|
39
|
+
return $1.split("$").collect{|attr| attr.strip}
|
40
|
+
when /#{at}\s+([\w\d_-]+)/i
|
41
|
+
return $1.split("$").collect{|attr| attr.strip}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
}
|
45
|
+
return nil
|
46
|
+
end
|
47
|
+
|
48
|
+
# Return the list of attributes that an entry with object class +oc+
|
49
|
+
# _must_ possess.
|
50
|
+
#
|
51
|
+
def must(oc)
|
52
|
+
attr(oc, "MUST")
|
53
|
+
end
|
54
|
+
|
55
|
+
# Return the list of attributes that an entry with object class +oc+
|
56
|
+
# _may_ possess.
|
57
|
+
#
|
58
|
+
def may(oc)
|
59
|
+
attr(oc, "MAY")
|
60
|
+
end
|
61
|
+
|
62
|
+
# Return the superior object class of object class +oc+.
|
63
|
+
#
|
64
|
+
def sup(oc)
|
65
|
+
attr(oc, "SUP")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Conn
|
70
|
+
|
71
|
+
# Fetch the schema data for the connection.
|
72
|
+
#
|
73
|
+
# If +base+ is given, it gives the base DN for the search. +attrs+, if
|
74
|
+
# given, is an array of attributes that should be returned from the
|
75
|
+
# server. The default list is *objectClasses*, *attributeTypes*,
|
76
|
+
# *matchingRules*, *matchingRuleUse*, *dITStructureRules*,
|
77
|
+
# *dITContentRules*, *nameForms* and *ldapSyntaxes*.
|
78
|
+
#
|
79
|
+
# +sec+ and +usec+ can be used to specify a time-out for the search in
|
80
|
+
# seconds and microseconds, respectively.
|
81
|
+
#
|
82
|
+
def schema(base = nil, attrs = nil, sec = 0, usec = 0)
|
83
|
+
attrs ||= [
|
84
|
+
'objectClasses',
|
85
|
+
'attributeTypes',
|
86
|
+
'matchingRules',
|
87
|
+
'matchingRuleUse',
|
88
|
+
'dITStructureRules',
|
89
|
+
'dITContentRules',
|
90
|
+
'nameForms',
|
91
|
+
'ldapSyntaxes',
|
92
|
+
]
|
93
|
+
base ||= root_dse(['subschemaSubentry'], sec, usec)[0]['subschemaSubentry'][0]
|
94
|
+
base ||= 'cn=schema'
|
95
|
+
ent = search2(base, LDAP_SCOPE_BASE, '(objectClass=subschema)',
|
96
|
+
attrs, false, sec, usec)
|
97
|
+
return Schema.new(ent[0])
|
98
|
+
end
|
99
|
+
|
100
|
+
# Fetch the root DSE (DSA-specific Entry) for the connection. DSA stands
|
101
|
+
# for Directory System Agent and simply refers to the LDAP server you are
|
102
|
+
# using.
|
103
|
+
#
|
104
|
+
# +attrs+, if given, is an array of attributes that should be returned
|
105
|
+
# from the server. The default list is *subschemaSubentry*,
|
106
|
+
# *namingContexts*, *monitorContext*, *altServer*, *supportedControl*,
|
107
|
+
# *supportedExtension*, *supportedFeatures*, *supportedSASLMechanisms*
|
108
|
+
# and *supportedLDAPVersion*.
|
109
|
+
#
|
110
|
+
# +sec+ and +usec+ can be used to specify a time-out for the search in
|
111
|
+
# seconds and microseconds, respectively.
|
112
|
+
#
|
113
|
+
def root_dse(attrs = nil, sec = 0, usec = 0)
|
114
|
+
attrs ||= [
|
115
|
+
'subschemaSubentry',
|
116
|
+
'namingContexts',
|
117
|
+
'monitorContext',
|
118
|
+
'altServer',
|
119
|
+
'supportedControl',
|
120
|
+
'supportedExtension',
|
121
|
+
'supportedFeatures',
|
122
|
+
'supportedSASLMechanisms',
|
123
|
+
'supportedLDAPVersion',
|
124
|
+
]
|
125
|
+
|
126
|
+
entries = search2('', LDAP_SCOPE_BASE, '(objectClass=*)',
|
127
|
+
attrs, false, sec, usec)
|
128
|
+
return entries
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
data/test/setup.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
require 'ldap'
|
4
|
+
require './username_and_password'
|
5
|
+
|
6
|
+
$LDAP_test_host = 'localhost'
|
7
|
+
$LDAP_test_port = LDAP::LDAP_PORT
|
8
|
+
|
9
|
+
def delete_tree(c, name)
|
10
|
+
c.search(name, LDAP::LDAP_SCOPE_ONELEVEL, "(objectClass=*)", ['dn']) do |v|
|
11
|
+
delete_tree c, v.get_dn
|
12
|
+
end rescue nil
|
13
|
+
c.delete(name)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
c = LDAP::Conn.new($LDAP_test_host, $LDAP_test_port)
|
18
|
+
c.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
|
19
|
+
c.bind($LDAP_test_username, $LDAP_test_password) do
|
20
|
+
# just clean out and create our tree
|
21
|
+
|
22
|
+
delete_tree(c, 'o=ruby_ldap_test_tree')
|
23
|
+
|
24
|
+
c.add('o=ruby_ldap_test_tree', {'objectClass' => ['organization'], 'o' => ['ruby_ldap_test_tree']})
|
25
|
+
c.add('o=sub_tree, o=ruby_ldap_test_tree', {'objectClass' => ['organization'], 'o' => ['sub_tree']})
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
module Test::Unit::Assertions
|
30
|
+
def assert_exists_in_ldap dn, attrs = {}
|
31
|
+
found = 0
|
32
|
+
@conn.search(dn, LDAP::LDAP_SCOPE_BASE, "(objectClass=*)", attrs.keys) do |entry|
|
33
|
+
found += 1
|
34
|
+
|
35
|
+
assert_equal dn, entry.get_dn
|
36
|
+
assert_equal attrs.keys.sort, entry.get_attributes.sort unless attrs == { }
|
37
|
+
attrs.each do |k,v|
|
38
|
+
assert_equal v, entry[k]
|
39
|
+
assert_equal v, entry[k.downcase]
|
40
|
+
assert_equal v, entry[k.upcase]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
assert_equal 1,found
|
45
|
+
end
|
46
|
+
|
47
|
+
def assert_dont_exists_in_ldap dn
|
48
|
+
assert_raises(LDAP::ResultError) do
|
49
|
+
@conn.search(dn, LDAP::LDAP_SCOPE_BASE, "(objectClass=*)", []) { }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/test/test_add.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'setup'
|
3
|
+
|
4
|
+
class TestAdd < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@conn = LDAP::Conn.new($LDAP_test_host, $LDAP_test_port)
|
7
|
+
@conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
|
8
|
+
@conn.bind($LDAP_test_username, $LDAP_test_password)
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@conn.unbind rescue nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_simple_add
|
16
|
+
@conn.add("o=fox3,o=ruby_ldap_test_tree", {'o' => ["fox3"], 'objectClass' => ['organization']})
|
17
|
+
assert_exists_in_ldap "o=fox3,o=ruby_ldap_test_tree", {'o' => ["fox3"]}
|
18
|
+
ensure
|
19
|
+
@conn.delete("o=fox3,o=ruby_ldap_test_tree") rescue nil
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'setup'
|
3
|
+
|
4
|
+
class TestConnection < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@conn = LDAP::Conn.new($LDAP_test_host, $LDAP_test_port)
|
7
|
+
@conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
|
8
|
+
@conn.bind($LDAP_test_username, $LDAP_test_password)
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@conn.unbind rescue nil
|
13
|
+
end
|
14
|
+
|
15
|
+
if defined?(JRUBY_VERSION)
|
16
|
+
def test_rebind
|
17
|
+
id = @conn.object_id
|
18
|
+
|
19
|
+
assert_nothing_raised do
|
20
|
+
@conn.unbind
|
21
|
+
@conn.bind
|
22
|
+
end
|
23
|
+
|
24
|
+
id2 = @conn.object_id
|
25
|
+
assert_equal( id, id2 )
|
26
|
+
|
27
|
+
assert_nothing_raised do
|
28
|
+
@conn.unbind
|
29
|
+
@conn.simple_bind
|
30
|
+
end
|
31
|
+
|
32
|
+
id2 = @conn.object_id
|
33
|
+
assert_equal( id, id2 )
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_double_bind
|
38
|
+
assert_raises( LDAP::Error ) { @conn.bind }
|
39
|
+
assert_raises( LDAP::Error ) { @conn.simple_bind }
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_double_unbind
|
43
|
+
assert_nothing_raised { @conn.unbind }
|
44
|
+
assert_raises( LDAP::InvalidDataError ) { @conn.unbind }
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_bound?
|
48
|
+
assert( @conn.bound? )
|
49
|
+
@conn.unbind
|
50
|
+
assert( ! @conn.bound? )
|
51
|
+
end
|
52
|
+
end
|
data/test/test_delete.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'setup'
|
3
|
+
|
4
|
+
class TestDelete < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@conn = LDAP::Conn.new($LDAP_test_host, $LDAP_test_port)
|
7
|
+
@conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
|
8
|
+
@conn.bind($LDAP_test_username, $LDAP_test_password)
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@conn.unbind rescue nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_simple_delete
|
16
|
+
@conn.add("o=fox3,o=ruby_ldap_test_tree", {'o' => ["fox3"], 'objectClass' => ['organization']})
|
17
|
+
assert_exists_in_ldap "o=fox3,o=ruby_ldap_test_tree"
|
18
|
+
@conn.delete("o=fox3,o=ruby_ldap_test_tree")
|
19
|
+
assert_dont_exists_in_ldap "o=fox3,o=ruby_ldap_test_tree"
|
20
|
+
end
|
21
|
+
end
|
data/test/test_search.rb
ADDED
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'setup'
|
3
|
+
|
4
|
+
class TestSearch < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@conn = LDAP::Conn.new($LDAP_test_host, $LDAP_test_port)
|
7
|
+
@conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
|
8
|
+
@conn.bind($LDAP_test_username, $LDAP_test_password)
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@conn.unbind rescue nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_simple_base_search
|
16
|
+
found = 0
|
17
|
+
@conn.search('o=ruby_ldap_test_tree', LDAP::LDAP_SCOPE_BASE, "(objectClass=*)", []) do |v|
|
18
|
+
found += 1
|
19
|
+
|
20
|
+
assert_equal 'o=ruby_ldap_test_tree', v.get_dn
|
21
|
+
assert_equal ['o', 'objectClass'].sort, v.get_attributes.sort
|
22
|
+
assert_equal ['ruby_ldap_test_tree'], v['o']
|
23
|
+
assert_equal ['organization'], v['objectClass']
|
24
|
+
assert_equal ['organization'], v['OBJECTCLASS']
|
25
|
+
end
|
26
|
+
|
27
|
+
assert_equal 1,found
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_simple_one_level_search
|
31
|
+
found = 0
|
32
|
+
@conn.search('o=ruby_ldap_test_tree', LDAP::LDAP_SCOPE_ONELEVEL, "(objectClass=*)", []) do |v|
|
33
|
+
found += 1
|
34
|
+
|
35
|
+
assert_equal 'o=sub_tree,o=ruby_ldap_test_tree', v.get_dn
|
36
|
+
assert_equal ['o', 'objectClass'].sort, v.get_attributes.sort
|
37
|
+
assert_equal ['sub_tree'], v['o']
|
38
|
+
assert_equal ['organization'], v['objectClass']
|
39
|
+
assert_equal ['organization'], v['OBJECTCLASS']
|
40
|
+
end
|
41
|
+
|
42
|
+
assert_equal 1,found
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_simple_subtree_search
|
46
|
+
found = 0
|
47
|
+
|
48
|
+
@conn.search('o=ruby_ldap_test_tree', LDAP::LDAP_SCOPE_SUBTREE, "(objectClass=*)", []) do |v|
|
49
|
+
found += 1
|
50
|
+
if v.get_dn =~ /sub_tree/
|
51
|
+
assert_equal 'o=sub_tree,o=ruby_ldap_test_tree', v.get_dn
|
52
|
+
assert_equal ['o', 'objectClass'].sort, v.get_attributes.sort
|
53
|
+
assert_equal ['sub_tree'], v['o']
|
54
|
+
assert_equal ['organization'], v['objectClass']
|
55
|
+
assert_equal ['organization'], v['OBJECTCLASS']
|
56
|
+
else
|
57
|
+
assert_equal 'o=ruby_ldap_test_tree', v.get_dn
|
58
|
+
assert_equal ['o', 'objectClass'].sort, v.get_attributes.sort
|
59
|
+
assert_equal ['ruby_ldap_test_tree'], v['o']
|
60
|
+
assert_equal ['organization'], v['objectClass']
|
61
|
+
assert_equal ['organization'], v['OBJECTCLASS']
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
assert_equal 2,found
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_filter
|
69
|
+
found = 0
|
70
|
+
|
71
|
+
@conn.search('o=ruby_ldap_test_tree', LDAP::LDAP_SCOPE_SUBTREE, "(o=sub_tree)", []) do |v|
|
72
|
+
found += 1
|
73
|
+
|
74
|
+
assert_equal 'o=sub_tree,o=ruby_ldap_test_tree', v.get_dn
|
75
|
+
assert_equal ['o', 'objectClass'].sort, v.get_attributes.sort
|
76
|
+
assert_equal ['sub_tree'], v['o']
|
77
|
+
assert_equal ['organization'], v['objectClass']
|
78
|
+
assert_equal ['organization'], v['OBJECTCLASS']
|
79
|
+
end
|
80
|
+
|
81
|
+
assert_equal 1,found
|
82
|
+
end
|
83
|
+
|
84
|
+
def test_attributes
|
85
|
+
assert_exists_in_ldap 'o=sub_tree,o=ruby_ldap_test_tree', {'objectClass' => ['organization'] }
|
86
|
+
end
|
87
|
+
end
|
data/test/test_ssl.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'setup'
|
3
|
+
|
4
|
+
class TestSSLAdd# < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@conn = LDAP::SSLConn.new($LDAP_test_host, LDAP::LDAPS_PORT)
|
7
|
+
@conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
|
8
|
+
@conn.bind($LDAP_test_username, $LDAP_test_password)
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@conn.unbind rescue nil
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_simple_add
|
16
|
+
@conn.add("o=fox3,o=ruby_ldap_test_tree", {'o' => ["fox3"], 'objectClass' => ['organization']})
|
17
|
+
assert_exists_in_ldap "o=fox3,o=ruby_ldap_test_tree", {'o' => ["fox3"]}
|
18
|
+
ensure
|
19
|
+
@conn.delete("o=fox3,o=ruby_ldap_test_tree") rescue nil
|
20
|
+
end
|
21
|
+
end
|