socialcast-net-ldap 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/COPYING +272 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +29 -0
- data/Hacking.rdoc +16 -0
- data/History.txt +137 -0
- data/LICENSE +56 -0
- data/Manifest.txt +45 -0
- data/README.txt +70 -0
- data/Rakefile +124 -0
- data/lib/net-ldap.rb +1 -0
- data/lib/net/ber.rb +341 -0
- data/lib/net/ber/ber_parser.rb +168 -0
- data/lib/net/ber/core_ext.rb +72 -0
- data/lib/net/ber/core_ext/array.rb +79 -0
- data/lib/net/ber/core_ext/bignum.rb +19 -0
- data/lib/net/ber/core_ext/false_class.rb +7 -0
- data/lib/net/ber/core_ext/fixnum.rb +63 -0
- data/lib/net/ber/core_ext/string.rb +57 -0
- data/lib/net/ber/core_ext/true_class.rb +9 -0
- data/lib/net/ldap.rb +1539 -0
- data/lib/net/ldap/dataset.rb +174 -0
- data/lib/net/ldap/entry.rb +208 -0
- data/lib/net/ldap/filter.rb +781 -0
- data/lib/net/ldap/password.rb +52 -0
- data/lib/net/ldap/pdu.rb +279 -0
- data/lib/net/ldif.rb +34 -0
- data/lib/net/snmp.rb +295 -0
- data/spec/integration/ssl_ber_spec.rb +33 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +5 -0
- data/spec/unit/ber/ber_spec.rb +109 -0
- data/spec/unit/ber/core_ext/string_spec.rb +51 -0
- data/spec/unit/ldap/entry_spec.rb +51 -0
- data/spec/unit/ldap/filter_spec.rb +83 -0
- data/spec/unit/ldap_spec.rb +48 -0
- data/test/common.rb +3 -0
- data/test/test_entry.rb +59 -0
- data/test/test_filter.rb +115 -0
- data/test/test_ldif.rb +68 -0
- data/test/test_password.rb +17 -0
- data/test/test_rename.rb +79 -0
- data/test/test_snmp.rb +114 -0
- data/test/testdata.ldif +101 -0
- data/testserver/ldapserver.rb +210 -0
- data/testserver/testdata.ldif +101 -0
- metadata +178 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'net/ldap'
|
4
|
+
|
5
|
+
describe "BER serialisation (SSL)" do
|
6
|
+
# Transmits str to #to and reads it back from #from.
|
7
|
+
#
|
8
|
+
def transmit(str)
|
9
|
+
to.write(str)
|
10
|
+
to.close
|
11
|
+
|
12
|
+
from.read
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :to, :from
|
16
|
+
before(:each) do
|
17
|
+
@from, @to = IO.pipe
|
18
|
+
|
19
|
+
flexmock(OpenSSL::SSL::SSLSocket).
|
20
|
+
new_instances.should_receive(:connect => nil)
|
21
|
+
|
22
|
+
@to = Net::LDAP::Connection.wrap_with_ssl(to)
|
23
|
+
@from = Net::LDAP::Connection.wrap_with_ssl(from)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should transmit strings" do
|
27
|
+
transmit('foo').should == 'foo'
|
28
|
+
end
|
29
|
+
it "should correctly transmit numbers" do
|
30
|
+
to.write 1234.to_ber
|
31
|
+
from.read_ber.should == 1234
|
32
|
+
end
|
33
|
+
end
|
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'net/ber'
|
4
|
+
require 'net/ldap'
|
5
|
+
|
6
|
+
describe "BER encoding of" do
|
7
|
+
|
8
|
+
RSpec::Matchers.define :properly_encode_and_decode do
|
9
|
+
match do |given|
|
10
|
+
given.to_ber.read_ber.should == given
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
context "arrays" do
|
15
|
+
it "should properly encode/decode []" do
|
16
|
+
[].should properly_encode_and_decode
|
17
|
+
end
|
18
|
+
it "should properly encode/decode [1,2,3]" do
|
19
|
+
ary = [1,2,3]
|
20
|
+
encoded_ary = ary.map { |el| el.to_ber }.to_ber
|
21
|
+
|
22
|
+
encoded_ary.read_ber.should == ary
|
23
|
+
end
|
24
|
+
end
|
25
|
+
context "booleans" do
|
26
|
+
it "should encode true" do
|
27
|
+
true.to_ber.should == "\x01\x01\x01"
|
28
|
+
end
|
29
|
+
it "should encode false" do
|
30
|
+
false.to_ber.should == "\x01\x01\x00"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
context "numbers" do
|
34
|
+
# Sample based
|
35
|
+
{
|
36
|
+
0 => "\x02\x01\x00",
|
37
|
+
1 => "\x02\x01\x01",
|
38
|
+
127 => "\x02\x01\x7F",
|
39
|
+
128 => "\x02\x01\x80",
|
40
|
+
255 => "\x02\x01\xFF",
|
41
|
+
256 => "\x02\x02\x01\x00",
|
42
|
+
65535 => "\x02\x02\xFF\xFF",
|
43
|
+
65536 => "\x02\x03\x01\x00\x00",
|
44
|
+
16_777_215 => "\x02\x03\xFF\xFF\xFF",
|
45
|
+
0x01000000 => "\x02\x04\x01\x00\x00\x00",
|
46
|
+
0x3FFFFFFF => "\x02\x04\x3F\xFF\xFF\xFF",
|
47
|
+
0x4FFFFFFF => "\x02\x04\x4F\xFF\xFF\xFF",
|
48
|
+
|
49
|
+
# Some odd samples...
|
50
|
+
5 => "\002\001\005",
|
51
|
+
500 => "\002\002\001\364",
|
52
|
+
50_000 => "\x02\x02\xC3P",
|
53
|
+
5_000_000_000 => "\002\005\001*\005\362\000"
|
54
|
+
}.each do |number, expected_encoding|
|
55
|
+
it "should encode #{number} as #{expected_encoding.inspect}" do
|
56
|
+
number.to_ber.should == expected_encoding
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Round-trip encoding: This is mostly to be sure to cover Bignums well.
|
61
|
+
context "when decoding with #read_ber" do
|
62
|
+
it "should correctly handle powers of two" do
|
63
|
+
100.times do |p|
|
64
|
+
n = 2 << p
|
65
|
+
|
66
|
+
n.should properly_encode_and_decode
|
67
|
+
end
|
68
|
+
end
|
69
|
+
it "should correctly handle powers of ten" do
|
70
|
+
100.times do |p|
|
71
|
+
n = 5 * 10**p
|
72
|
+
|
73
|
+
n.should properly_encode_and_decode
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
if "Ruby 1.9".respond_to?(:encoding)
|
79
|
+
context "strings" do
|
80
|
+
it "should properly encode UTF-8 strings" do
|
81
|
+
"\u00e5".force_encoding("UTF-8").to_ber.should ==
|
82
|
+
"\x04\x02\xC3\xA5"
|
83
|
+
end
|
84
|
+
it "should properly encode strings encodable as UTF-8" do
|
85
|
+
"teststring".encode("US-ASCII").to_ber.should == "\x04\nteststring"
|
86
|
+
end
|
87
|
+
it "should fail on strings that can not be converted to UTF-8" do
|
88
|
+
error = Encoding::UndefinedConversionError
|
89
|
+
lambda {"\x81".to_ber }.should raise_exception(error)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "BER decoding of" do
|
96
|
+
context "numbers" do
|
97
|
+
it "should decode #{"\002\001\006".inspect} (6)" do
|
98
|
+
"\002\001\006".read_ber(Net::LDAP::AsnSyntax).should == 6
|
99
|
+
end
|
100
|
+
it "should decode #{"\004\007testing".inspect} ('testing')" do
|
101
|
+
"\004\007testing".read_ber(Net::LDAP::AsnSyntax).should == 'testing'
|
102
|
+
end
|
103
|
+
it "should decode an ldap bind request" do
|
104
|
+
"0$\002\001\001`\037\002\001\003\004\rAdministrator\200\vad_is_bogus".
|
105
|
+
read_ber(Net::LDAP::AsnSyntax).should ==
|
106
|
+
[1, [3, "Administrator", "ad_is_bogus"]]
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'metaid'
|
3
|
+
|
4
|
+
describe String, "when extended with BER core extensions" do
|
5
|
+
describe "<- #read_ber! (consuming read_ber method)" do
|
6
|
+
context "when passed an ldap bind request and some extra data" do
|
7
|
+
attr_reader :str, :result
|
8
|
+
before(:each) do
|
9
|
+
@str = "0$\002\001\001`\037\002\001\003\004\rAdministrator\200\vad_is_bogus UNCONSUMED"
|
10
|
+
@result = str.read_ber!(Net::LDAP::AsnSyntax)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should correctly parse the ber message" do
|
14
|
+
result.should == [1, [3, "Administrator", "ad_is_bogus"]]
|
15
|
+
end
|
16
|
+
it "should leave unconsumed part of message in place" do
|
17
|
+
str.should == " UNCONSUMED"
|
18
|
+
end
|
19
|
+
|
20
|
+
context "if an exception occurs during #read_ber" do
|
21
|
+
attr_reader :initial_value
|
22
|
+
before(:each) do
|
23
|
+
stub_exception_class = Class.new(StandardError)
|
24
|
+
|
25
|
+
@initial_value = "0$\002\001\001`\037\002\001\003\004\rAdministrator\200\vad_is_bogus"
|
26
|
+
@str = initial_value.dup
|
27
|
+
|
28
|
+
# Defines a string
|
29
|
+
io = StringIO.new(initial_value)
|
30
|
+
io.meta_def :read_ber do |syntax|
|
31
|
+
read
|
32
|
+
raise stub_exception_class
|
33
|
+
end
|
34
|
+
flexmock(StringIO).should_receive(:new).and_return(io)
|
35
|
+
|
36
|
+
begin
|
37
|
+
str.read_ber!(Net::LDAP::AsnSyntax)
|
38
|
+
rescue stub_exception_class
|
39
|
+
# EMPTY ON PURPOSE
|
40
|
+
else
|
41
|
+
raise "The stub code should raise an exception!"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should not modify string" do
|
46
|
+
str.should == initial_value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Net::LDAP::Entry do
|
4
|
+
attr_reader :entry
|
5
|
+
before(:each) do
|
6
|
+
@entry = Net::LDAP::Entry.from_single_ldif_string(
|
7
|
+
%Q{dn: something
|
8
|
+
foo: foo
|
9
|
+
barAttribute: bar
|
10
|
+
}
|
11
|
+
)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "entry access" do
|
15
|
+
it "should always respond to #dn" do
|
16
|
+
entry.should respond_to(:dn)
|
17
|
+
end
|
18
|
+
|
19
|
+
context "<- #foo" do
|
20
|
+
it "should respond_to?" do
|
21
|
+
entry.should respond_to(:foo)
|
22
|
+
end
|
23
|
+
it "should return 'foo'" do
|
24
|
+
entry.foo.should == ['foo']
|
25
|
+
end
|
26
|
+
end
|
27
|
+
context "<- #Foo" do
|
28
|
+
it "should respond_to?" do
|
29
|
+
entry.should respond_to(:Foo)
|
30
|
+
end
|
31
|
+
it "should return 'foo'" do
|
32
|
+
entry.foo.should == ['foo']
|
33
|
+
end
|
34
|
+
end
|
35
|
+
context "<- #foo=" do
|
36
|
+
it "should respond_to?" do
|
37
|
+
entry.should respond_to(:foo=)
|
38
|
+
end
|
39
|
+
it "should set 'foo'" do
|
40
|
+
entry.foo= 'bar'
|
41
|
+
entry.foo.should == ['bar']
|
42
|
+
end
|
43
|
+
end
|
44
|
+
context "<- #fOo=" do
|
45
|
+
it "should return 'foo'" do
|
46
|
+
entry.fOo= 'bar'
|
47
|
+
entry.fOo.should == ['bar']
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Net::LDAP::Filter do
|
4
|
+
describe "<- .ex(attr, value)" do
|
5
|
+
context "('foo', 'bar')" do
|
6
|
+
attr_reader :filter
|
7
|
+
before(:each) do
|
8
|
+
@filter = Net::LDAP::Filter.ex('foo', 'bar')
|
9
|
+
end
|
10
|
+
it "should convert to 'foo:=bar'" do
|
11
|
+
filter.to_s.should == '(foo:=bar)'
|
12
|
+
end
|
13
|
+
it "should survive roundtrip via to_s/from_rfc2254" do
|
14
|
+
Net::LDAP::Filter.from_rfc2254(filter.to_s).should == filter
|
15
|
+
end
|
16
|
+
it "should survive roundtrip conversion to/from ber" do
|
17
|
+
ber = filter.to_ber
|
18
|
+
Net::LDAP::Filter.parse_ber(ber.read_ber(Net::LDAP::AsnSyntax)).should ==
|
19
|
+
filter
|
20
|
+
end
|
21
|
+
end
|
22
|
+
context "various legal inputs" do
|
23
|
+
[
|
24
|
+
'(o:dn:=Ace Industry)',
|
25
|
+
'(:dn:2.4.8.10:=Dino)',
|
26
|
+
'(cn:dn:1.2.3.4.5:=John Smith)',
|
27
|
+
'(sn:dn:2.4.6.8.10:=Barbara Jones)',
|
28
|
+
].each do |filter_str|
|
29
|
+
context "from_rfc2254(#{filter_str.inspect})" do
|
30
|
+
attr_reader :filter
|
31
|
+
before(:each) do
|
32
|
+
@filter = Net::LDAP::Filter.from_rfc2254(filter_str)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should decode into a Net::LDAP::Filter" do
|
36
|
+
filter.should be_an_instance_of(Net::LDAP::Filter)
|
37
|
+
end
|
38
|
+
it "should survive roundtrip conversion to/from ber" do
|
39
|
+
ber = filter.to_ber
|
40
|
+
Net::LDAP::Filter.parse_ber(ber.read_ber(Net::LDAP::AsnSyntax)).should ==
|
41
|
+
filter
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
describe "<- .construct" do
|
48
|
+
it "should accept apostrophes in filters (regression)" do
|
49
|
+
Net::LDAP::Filter.construct("uid=O'Keefe").to_rfc2254.should == "(uid=O'Keefe)"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "convenience filter constructors" do
|
54
|
+
def eq(attribute, value)
|
55
|
+
described_class.eq(attribute, value)
|
56
|
+
end
|
57
|
+
describe "<- .equals(attr, val)" do
|
58
|
+
it "should delegate to .eq with escaping" do
|
59
|
+
described_class.equals('dn', 'f*oo').should == eq('dn', 'f\2Aoo')
|
60
|
+
end
|
61
|
+
end
|
62
|
+
describe "<- .begins(attr, val)" do
|
63
|
+
it "should delegate to .eq with escaping" do
|
64
|
+
described_class.begins('dn', 'f*oo').should == eq('dn', 'f\2Aoo*')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
describe "<- .ends(attr, val)" do
|
68
|
+
it "should delegate to .eq with escaping" do
|
69
|
+
described_class.ends('dn', 'f*oo').should == eq('dn', '*f\2Aoo')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
describe "<- .contains(attr, val)" do
|
73
|
+
it "should delegate to .eq with escaping" do
|
74
|
+
described_class.contains('dn', 'f*oo').should == eq('dn', '*f\2Aoo*')
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
describe "<- .escape(str)" do
|
79
|
+
it "should escape !, &, *, :, | and ~" do
|
80
|
+
Net::LDAP::Filter.escape('!&*:|~').should == "\\21\\26\\2A\\3A\\7C\\7E"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Net::LDAP::Connection do
|
4
|
+
describe "initialize" do
|
5
|
+
context "when host is not responding" do
|
6
|
+
before(:each) do
|
7
|
+
flexmock(TCPSocket).
|
8
|
+
should_receive(:new).and_raise(Errno::ECONNREFUSED)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should raise LdapError" do
|
12
|
+
lambda {
|
13
|
+
Net::LDAP::Connection.new(
|
14
|
+
:server => 'test.mocked.com',
|
15
|
+
:port => 636)
|
16
|
+
}.should raise_error(Net::LDAP::LdapError)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
context "when host is blocking the port" do
|
20
|
+
before(:each) do
|
21
|
+
flexmock(TCPSocket).
|
22
|
+
should_receive(:new).and_raise(SocketError)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should raise LdapError" do
|
26
|
+
lambda {
|
27
|
+
Net::LDAP::Connection.new(
|
28
|
+
:server => 'test.mocked.com',
|
29
|
+
:port => 636)
|
30
|
+
}.should raise_error(Net::LDAP::LdapError)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
context "on other exceptions" do
|
34
|
+
before(:each) do
|
35
|
+
flexmock(TCPSocket).
|
36
|
+
should_receive(:new).and_raise(NameError)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should rethrow the exception" do
|
40
|
+
lambda {
|
41
|
+
Net::LDAP::Connection.new(
|
42
|
+
:server => 'test.mocked.com',
|
43
|
+
:port => 636)
|
44
|
+
}.should raise_error(NameError)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/test/common.rb
ADDED
data/test/test_entry.rb
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'common'
|
2
|
+
|
3
|
+
=begin
|
4
|
+
class TestEntry < Test::Unit::TestCase
|
5
|
+
Commented out until I can make it a spec.
|
6
|
+
context "An instance of Entry" do
|
7
|
+
setup do
|
8
|
+
@entry = Net::LDAP::Entry.new 'cn=Barbara,o=corp'
|
9
|
+
end
|
10
|
+
|
11
|
+
should "be initialized with the DN" do
|
12
|
+
assert_equal 'cn=Barbara,o=corp', @entry.dn
|
13
|
+
end
|
14
|
+
|
15
|
+
should 'return an empty array when accessing a nonexistent attribute (index lookup)' do
|
16
|
+
assert_equal [], @entry['sn']
|
17
|
+
end
|
18
|
+
|
19
|
+
should 'return an empty array when accessing a nonexistent attribute (method call)' do
|
20
|
+
assert_equal [], @entry.sn
|
21
|
+
end
|
22
|
+
|
23
|
+
should 'create an attribute on assignment (index lookup)' do
|
24
|
+
@entry['sn'] = 'Jensen'
|
25
|
+
assert_equal ['Jensen'], @entry['sn']
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'create an attribute on assignment (method call)' do
|
29
|
+
@entry.sn = 'Jensen'
|
30
|
+
assert_equal ['Jensen'], @entry.sn
|
31
|
+
end
|
32
|
+
|
33
|
+
should 'have attributes accessible by index lookup' do
|
34
|
+
@entry['sn'] = 'Jensen'
|
35
|
+
assert_equal ['Jensen'], @entry['sn']
|
36
|
+
end
|
37
|
+
|
38
|
+
should 'have attributes accessible using a Symbol as the index' do
|
39
|
+
@entry[:sn] = 'Jensen'
|
40
|
+
assert_equal ['Jensen'], @entry[:sn]
|
41
|
+
end
|
42
|
+
|
43
|
+
should 'have attributes accessible by method call' do
|
44
|
+
@entry['sn'] = 'Jensen'
|
45
|
+
assert_equal ['Jensen'], @entry.sn
|
46
|
+
end
|
47
|
+
|
48
|
+
should 'ignore case of attribute names' do
|
49
|
+
@entry['sn'] = 'Jensen'
|
50
|
+
assert_equal ['Jensen'], @entry.sn
|
51
|
+
assert_equal ['Jensen'], @entry.Sn
|
52
|
+
assert_equal ['Jensen'], @entry.SN
|
53
|
+
assert_equal ['Jensen'], @entry['sn']
|
54
|
+
assert_equal ['Jensen'], @entry['Sn']
|
55
|
+
assert_equal ['Jensen'], @entry['SN']
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
=end
|