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