fakeldap 0.0.1 → 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +7 -1
- data/lib/fakeldap.rb +133 -10
- data/lib/fakeldap/version.rb +1 -1
- metadata +50 -191
- data/vendor/ruby-ldapserver/COPYING +0 -27
- data/vendor/ruby-ldapserver/ChangeLog +0 -83
- data/vendor/ruby-ldapserver/Manifest.txt +0 -32
- data/vendor/ruby-ldapserver/README +0 -222
- data/vendor/ruby-ldapserver/Rakefile +0 -22
- data/vendor/ruby-ldapserver/doc/LDAP.html +0 -104
- data/vendor/ruby-ldapserver/doc/LDAP/Abandon.html +0 -112
- data/vendor/ruby-ldapserver/doc/LDAP/Error.html +0 -115
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError.html +0 -241
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/AdminLimitExceeded.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/AffectsMultipleDSAs.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/AliasDereferencingProblem.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/AliasProblem.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/AttributeOrValueExists.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/AuthMethodNotSupported.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/Busy.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/CompareFalse.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/CompareTrue.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/ConfidentialityRequired.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/ConstraintViolation.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/EntryAlreadyExists.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/InappropriateAuthentication.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/InappropriateMatching.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/InsufficientAccessRights.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/InvalidAttributeSyntax.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/InvalidCredentials.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/InvalidDNSyntax.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/IsLeaf.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/LoopDetect.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/NamingViolation.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/NoSuchAttribute.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/NoSuchObject.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/NotAllowedOnNonLeaf.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/NotAllowedOnRDN.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/ObjectClassModsProhibited.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/ObjectClassViolation.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/OperationsError.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/Other.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/ProtocolError.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/Referral.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/SaslBindInProgress.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/SizeLimitExceeded.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/StrongAuthRequired.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/Success.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/TimeLimitExceeded.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/Unavailable.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/UnavailableCriticalExtension.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/UndefinedAttributeType.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/ResultError/UnwillingToPerform.html +0 -158
- data/vendor/ruby-ldapserver/doc/LDAP/Server.html +0 -1056
- data/vendor/ruby-ldapserver/doc/LDAP/Server/Connection.html +0 -1353
- data/vendor/ruby-ldapserver/doc/LDAP/Server/Filter.html +0 -634
- data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule.html +0 -1132
- data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/DefaultMatchingClass.html +0 -219
- data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/Equality.html +0 -170
- data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/IA5Downcase.html +0 -143
- data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/IA5Trim.html +0 -155
- data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/Integer.html +0 -143
- data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/Ordering.html +0 -212
- data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/StringDowncase.html +0 -143
- data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/StringTrim.html +0 -154
- data/vendor/ruby-ldapserver/doc/LDAP/Server/MatchingRule/Substrings.html +0 -177
- data/vendor/ruby-ldapserver/doc/LDAP/Server/Operation.html +0 -2994
- data/vendor/ruby-ldapserver/doc/LDAP/Server/Schema.html +0 -2024
- data/vendor/ruby-ldapserver/doc/LDAP/Server/Schema/AttributeType.html +0 -1462
- data/vendor/ruby-ldapserver/doc/LDAP/Server/Schema/ObjectClass.html +0 -1097
- data/vendor/ruby-ldapserver/doc/LDAP/Server/Syntax.html +0 -1254
- data/vendor/ruby-ldapserver/doc/LDAP/Server/VERSION.html +0 -134
- data/vendor/ruby-ldapserver/doc/_index.html +0 -662
- data/vendor/ruby-ldapserver/doc/class_list.html +0 -36
- data/vendor/ruby-ldapserver/doc/css/common.css +0 -1
- data/vendor/ruby-ldapserver/doc/css/full_list.css +0 -50
- data/vendor/ruby-ldapserver/doc/css/style.css +0 -303
- data/vendor/ruby-ldapserver/doc/file.README.html +0 -399
- data/vendor/ruby-ldapserver/doc/file_list.html +0 -38
- data/vendor/ruby-ldapserver/doc/frames.html +0 -13
- data/vendor/ruby-ldapserver/doc/index.html +0 -399
- data/vendor/ruby-ldapserver/doc/js/app.js +0 -204
- data/vendor/ruby-ldapserver/doc/js/full_list.js +0 -112
- data/vendor/ruby-ldapserver/doc/js/jquery.js +0 -154
- data/vendor/ruby-ldapserver/doc/method_list.html +0 -1571
- data/vendor/ruby-ldapserver/doc/top-level-namespace.html +0 -88
- data/vendor/ruby-ldapserver/examples/README +0 -89
- data/vendor/ruby-ldapserver/examples/mkcert.rb +0 -31
- data/vendor/ruby-ldapserver/examples/rbslapd1.rb +0 -111
- data/vendor/ruby-ldapserver/examples/rbslapd2.rb +0 -161
- data/vendor/ruby-ldapserver/examples/rbslapd3.rb +0 -172
- data/vendor/ruby-ldapserver/examples/speedtest.rb +0 -37
- data/vendor/ruby-ldapserver/lib/ldap/server.rb +0 -4
- data/vendor/ruby-ldapserver/lib/ldap/server/connection.rb +0 -276
- data/vendor/ruby-ldapserver/lib/ldap/server/filter.rb +0 -223
- data/vendor/ruby-ldapserver/lib/ldap/server/match.rb +0 -283
- data/vendor/ruby-ldapserver/lib/ldap/server/operation.rb +0 -487
- data/vendor/ruby-ldapserver/lib/ldap/server/preforkserver.rb +0 -93
- data/vendor/ruby-ldapserver/lib/ldap/server/result.rb +0 -71
- data/vendor/ruby-ldapserver/lib/ldap/server/schema.rb +0 -592
- data/vendor/ruby-ldapserver/lib/ldap/server/server.rb +0 -89
- data/vendor/ruby-ldapserver/lib/ldap/server/syntax.rb +0 -235
- data/vendor/ruby-ldapserver/lib/ldap/server/tcpserver.rb +0 -91
- data/vendor/ruby-ldapserver/lib/ldap/server/util.rb +0 -88
- data/vendor/ruby-ldapserver/lib/ldap/server/version.rb +0 -11
- data/vendor/ruby-ldapserver/test/core.schema +0 -582
- data/vendor/ruby-ldapserver/test/encoding_test.rb +0 -279
- data/vendor/ruby-ldapserver/test/filter_test.rb +0 -107
- data/vendor/ruby-ldapserver/test/match_test.rb +0 -59
- data/vendor/ruby-ldapserver/test/schema_test.rb +0 -113
- data/vendor/ruby-ldapserver/test/syntax_test.rb +0 -40
- data/vendor/ruby-ldapserver/test/test_helper.rb +0 -2
- data/vendor/ruby-ldapserver/test/util_test.rb +0 -51
@@ -1,88 +0,0 @@
|
|
1
|
-
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
|
-
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
4
|
-
<head>
|
5
|
-
<meta name="Content-Type" content="text/html; charset=utf-8" />
|
6
|
-
<title>Top Level Namespace</title>
|
7
|
-
<link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8" />
|
8
|
-
<link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
|
9
|
-
|
10
|
-
<script type="text/javascript" charset="utf-8">
|
11
|
-
relpath = '';
|
12
|
-
if (relpath != '') relpath += '/';
|
13
|
-
</script>
|
14
|
-
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
15
|
-
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
16
|
-
|
17
|
-
</head>
|
18
|
-
<body>
|
19
|
-
<script type="text/javascript" charset="utf-8">
|
20
|
-
if (window.top.frames.main) document.body.className = 'frames';
|
21
|
-
</script>
|
22
|
-
|
23
|
-
<div id="header">
|
24
|
-
<div id="menu">
|
25
|
-
|
26
|
-
<a href="_index.html">Index</a> »
|
27
|
-
|
28
|
-
|
29
|
-
<span class="title">Top Level Namespace</span>
|
30
|
-
|
31
|
-
|
32
|
-
<div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
|
33
|
-
</div>
|
34
|
-
|
35
|
-
<div id="search">
|
36
|
-
<a id="class_list_link" href="#">Class List</a>
|
37
|
-
<a id="method_list_link" href="#">Method List</a>
|
38
|
-
<a id ="file_list_link" href="#">File List</a>
|
39
|
-
</div>
|
40
|
-
|
41
|
-
<div class="clear"></div>
|
42
|
-
</div>
|
43
|
-
|
44
|
-
<iframe id="search_frame"></iframe>
|
45
|
-
|
46
|
-
<div id="content"><h1>Top Level Namespace
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
</h1>
|
51
|
-
|
52
|
-
<dl class="box">
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
</dl>
|
62
|
-
<div class="clear"></div>
|
63
|
-
|
64
|
-
<h2>Defined Under Namespace</h2>
|
65
|
-
<p class="children">
|
66
|
-
|
67
|
-
|
68
|
-
<strong class="modules">Modules:</strong> <span class='object_link'><a href="LDAP.html" title="LDAP (module)">LDAP</a></span>
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
</p>
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
</div>
|
80
|
-
|
81
|
-
<div id="footer">
|
82
|
-
Generated on Mon Sep 13 13:27:18 2010 by
|
83
|
-
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
84
|
-
0.6.0 (ruby-1.9.2).
|
85
|
-
</div>
|
86
|
-
|
87
|
-
</body>
|
88
|
-
</html>
|
@@ -1,89 +0,0 @@
|
|
1
|
-
Using the example programs
|
2
|
-
==========================
|
3
|
-
|
4
|
-
These servers all listen on port 1389 by default, so that they don't have to
|
5
|
-
be run as root.
|
6
|
-
|
7
|
-
Example 1: trivial server using RAM hash
|
8
|
-
----------------------------------------
|
9
|
-
|
10
|
-
$ ruby rbslapd1.rb
|
11
|
-
|
12
|
-
In another window:
|
13
|
-
|
14
|
-
$ ldapadd -H ldap://127.0.0.1:1389/
|
15
|
-
dn: dc=example,dc=com
|
16
|
-
cn: Top object
|
17
|
-
|
18
|
-
dn: cn=Fred Flintstone,dc=example,dc=com
|
19
|
-
cn: Fred Flintstone
|
20
|
-
sn: Flintstone
|
21
|
-
mail: fred@bedrock.org
|
22
|
-
mail: fred.flintstone@bedrock.org
|
23
|
-
|
24
|
-
dn: cn=Wilma Flintstone,dc=example,dc=com
|
25
|
-
cn: Wilma Flintstone
|
26
|
-
mail: wilma@bedrock.org
|
27
|
-
^D
|
28
|
-
|
29
|
-
Try these queries:
|
30
|
-
|
31
|
-
$ ldapsearch -H ldap://127.0.0.1:1389/ -b "" "(objectclass=*)"
|
32
|
-
$ ldapsearch -H ldap://127.0.0.1:1389/ -b "dc=example,dc=com" -s base "(objectclass=*)"
|
33
|
-
$ ldapsearch -H ldap://127.0.0.1:1389/ -b "dc=example,dc=com" "(mail=fred*)"
|
34
|
-
|
35
|
-
If you terminate the server with Ctrl-C, its contents should be written
|
36
|
-
to disk as a YAML file.
|
37
|
-
|
38
|
-
A fairly complete set of the filter language is implemented. However, this
|
39
|
-
simple server works by simply scanning the entire database and applying the
|
40
|
-
filter to each entry, so it won't scale to large applications. No validation
|
41
|
-
of DN or attributes against any sort of schema is done.
|
42
|
-
|
43
|
-
Example 1a: with SSL
|
44
|
-
--------------------
|
45
|
-
|
46
|
-
In rbslapd1.rb, uncomment
|
47
|
-
|
48
|
-
:ssl_key_file => "key.pem",
|
49
|
-
:ssl_cert_file => "cert.pem",
|
50
|
-
:ssl_on_connect => true,
|
51
|
-
|
52
|
-
and run mkcert.rb. Since this is a self-signed certificate, you'll have to
|
53
|
-
turn off certificate verification in the client too. For example:
|
54
|
-
|
55
|
-
$ env LDAPTLS_REQCERT="allow" ldapsearch -H ldaps://127.0.0.1:1389/
|
56
|
-
|
57
|
-
Making your own CA and installing its certificate in the client, or
|
58
|
-
generating a Certificate Signing Request and sending it to a known CA, is
|
59
|
-
beyond the scope of this documentation.
|
60
|
-
|
61
|
-
Example 2: simple LDAP to SQL mapping
|
62
|
-
-------------------------------------
|
63
|
-
|
64
|
-
You will need to set up a MySQL database with a table conforming to the
|
65
|
-
schema given within the code. Once done, LDAP gives a read-only view of the
|
66
|
-
database with only the filter "(uid=<foo>)" supported.
|
67
|
-
|
68
|
-
Example 3: preforking server and schema
|
69
|
-
---------------------------------------
|
70
|
-
|
71
|
-
This functions in the same way as rbslapd1.rb. However, since each query is
|
72
|
-
answered in a separate process, the YAML file on disk is used as the master
|
73
|
-
repository. Update operations re-write this file each time.
|
74
|
-
|
75
|
-
Also, the schema is read from file 'core.schema'. Attempting to insert the
|
76
|
-
above entries will fail, due to schema violations. Insert a valid entry,
|
77
|
-
e.g.
|
78
|
-
|
79
|
-
dn: cn=Fred Flintstone,dc=example,dc=com
|
80
|
-
objectClass: organizationalPerson
|
81
|
-
cn: Fred Flintstone
|
82
|
-
sn: Flintstone
|
83
|
-
telephoneNumber: +1 555 1234
|
84
|
-
telephoneNumber: +1 555 5432
|
85
|
-
|
86
|
-
Schema validation takes place for the attribute values and that attributes
|
87
|
-
are allowed/required by the objectclass(es); however, the DN itself is not
|
88
|
-
validated, nor any checks made that the RDN is present as an attribute
|
89
|
-
(since this is one of the more stupid parts of the LDAP/X500 data model)
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'openssl'
|
2
|
-
|
3
|
-
# Taken directly from echo_svr.rb in the Ruby openssl examples
|
4
|
-
|
5
|
-
key = OpenSSL::PKey::RSA.new(1024){ print "."; $stdout.flush }
|
6
|
-
puts
|
7
|
-
cert = OpenSSL::X509::Certificate.new
|
8
|
-
cert.version = 2
|
9
|
-
cert.serial = 0
|
10
|
-
name = OpenSSL::X509::Name.new([["C","JP"],["O","TEST"],["CN","localhost"]])
|
11
|
-
cert.subject = name
|
12
|
-
cert.issuer = name
|
13
|
-
cert.not_before = Time.now
|
14
|
-
cert.not_after = Time.now + 3600
|
15
|
-
cert.public_key = key.public_key
|
16
|
-
ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
|
17
|
-
cert.extensions = [
|
18
|
-
ef.create_extension("basicConstraints","CA:FALSE"),
|
19
|
-
ef.create_extension("subjectKeyIdentifier","hash"),
|
20
|
-
ef.create_extension("extendedKeyUsage","serverAuth"),
|
21
|
-
ef.create_extension("keyUsage",
|
22
|
-
"keyEncipherment,dataEncipherment,digitalSignature")
|
23
|
-
]
|
24
|
-
ef.issuer_certificate = cert
|
25
|
-
cert.add_extension ef.create_extension("authorityKeyIdentifier",
|
26
|
-
"keyid:always,issuer:always")
|
27
|
-
cert.sign(key, OpenSSL::Digest::SHA1.new)
|
28
|
-
|
29
|
-
# Write to disk
|
30
|
-
File.open("key.pem","w",0600) { |f| f << key.to_pem }
|
31
|
-
File.open("cert.pem","w",0644) { |f| f << cert.to_pem }
|
@@ -1,111 +0,0 @@
|
|
1
|
-
#!/usr/local/bin/ruby -w
|
2
|
-
|
3
|
-
# This is a trivial LDAP server which just stores directory entries in RAM.
|
4
|
-
# It does no validation or authentication. This is intended just to
|
5
|
-
# demonstrate the API, it's not for real-world use!!
|
6
|
-
|
7
|
-
$:.unshift('../lib')
|
8
|
-
$debug = true
|
9
|
-
|
10
|
-
require 'ldap/server'
|
11
|
-
|
12
|
-
# We subclass the Operation class, overriding the methods to do what we need
|
13
|
-
|
14
|
-
class HashOperation < LDAP::Server::Operation
|
15
|
-
def initialize(connection, messageID, hash)
|
16
|
-
super(connection, messageID)
|
17
|
-
@hash = hash # an object reference to our directory data
|
18
|
-
end
|
19
|
-
|
20
|
-
def search(basedn, scope, deref, filter)
|
21
|
-
basedn.downcase!
|
22
|
-
|
23
|
-
case scope
|
24
|
-
when LDAP::Server::BaseObject
|
25
|
-
# client asked for single object by DN
|
26
|
-
obj = @hash[basedn]
|
27
|
-
raise LDAP::ResultError::NoSuchObject unless obj
|
28
|
-
send_SearchResultEntry(basedn, obj) if LDAP::Server::Filter.run(filter, obj)
|
29
|
-
|
30
|
-
when LDAP::Server::WholeSubtree
|
31
|
-
@hash.each do |dn, av|
|
32
|
-
next unless dn.index(basedn, -basedn.length) # under basedn?
|
33
|
-
next unless LDAP::Server::Filter.run(filter, av) # attribute filter?
|
34
|
-
send_SearchResultEntry(dn, av)
|
35
|
-
end
|
36
|
-
|
37
|
-
else
|
38
|
-
raise LDAP::ResultError::UnwillingToPerform, "OneLevel not implemented"
|
39
|
-
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def add(dn, av)
|
44
|
-
dn.downcase!
|
45
|
-
raise LDAP::ResultError::EntryAlreadyExists if @hash[dn]
|
46
|
-
@hash[dn] = av
|
47
|
-
end
|
48
|
-
|
49
|
-
def del(dn)
|
50
|
-
dn.downcase!
|
51
|
-
raise LDAP::ResultError::NoSuchObject unless @hash.has_key?(dn)
|
52
|
-
@hash.delete(dn)
|
53
|
-
end
|
54
|
-
|
55
|
-
def modify(dn, ops)
|
56
|
-
entry = @hash[dn]
|
57
|
-
raise LDAP::ResultError::NoSuchObject unless entry
|
58
|
-
ops.each do |attr, vals|
|
59
|
-
op = vals.shift
|
60
|
-
case op
|
61
|
-
when :add
|
62
|
-
entry[attr] ||= []
|
63
|
-
entry[attr] += vals
|
64
|
-
entry[attr].uniq!
|
65
|
-
when :delete
|
66
|
-
if vals == []
|
67
|
-
entry.delete(attr)
|
68
|
-
else
|
69
|
-
vals.each { |v| entry[attr].delete(v) }
|
70
|
-
end
|
71
|
-
when :replace
|
72
|
-
entry[attr] = vals
|
73
|
-
end
|
74
|
-
entry.delete(attr) if entry[attr] == []
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# This is the shared object which carries our actual directory entries.
|
80
|
-
# It's just a hash of {dn=>entry}, where each entry is {attr=>[val,val,...]}
|
81
|
-
|
82
|
-
directory = {}
|
83
|
-
|
84
|
-
# Let's put some backing store on it
|
85
|
-
|
86
|
-
require 'yaml'
|
87
|
-
begin
|
88
|
-
File.open("ldapdb.yaml") { |f| directory = YAML::load(f.read) }
|
89
|
-
rescue Errno::ENOENT
|
90
|
-
end
|
91
|
-
|
92
|
-
at_exit do
|
93
|
-
File.open("ldapdb.new","w") { |f| f.write(YAML::dump(directory)) }
|
94
|
-
File.rename("ldapdb.new","ldapdb.yaml")
|
95
|
-
end
|
96
|
-
|
97
|
-
# Listen for incoming LDAP connections. For each one, create a Connection
|
98
|
-
# object, which will invoke a HashOperation object for each request.
|
99
|
-
|
100
|
-
s = LDAP::Server.new(
|
101
|
-
:port => 1389,
|
102
|
-
:nodelay => true,
|
103
|
-
:listen => 10,
|
104
|
-
# :ssl_key_file => "key.pem",
|
105
|
-
# :ssl_cert_file => "cert.pem",
|
106
|
-
# :ssl_on_connect => true,
|
107
|
-
:operation_class => HashOperation,
|
108
|
-
:operation_args => [directory]
|
109
|
-
)
|
110
|
-
s.run_tcpserver
|
111
|
-
s.join
|
@@ -1,161 +0,0 @@
|
|
1
|
-
#!/usr/local/bin/ruby -w
|
2
|
-
|
3
|
-
$:.unshift('../lib')
|
4
|
-
require 'ldap/server'
|
5
|
-
require 'mysql' # <http://www.tmtm.org/en/ruby/mysql/>
|
6
|
-
require 'thread'
|
7
|
-
require 'resolv-replace' # ruby threading DNS client
|
8
|
-
|
9
|
-
# An example of an LDAP to SQL gateway. We have a MySQL table which
|
10
|
-
# contains (login_id,login,passwd) combinations, e.g.
|
11
|
-
#
|
12
|
-
# +----------+----------+--------+
|
13
|
-
# | login_id | login | passwd |
|
14
|
-
# +----------+----------+--------+
|
15
|
-
# | 1 | brian | foobar |
|
16
|
-
# | 2 | caroline | boing |
|
17
|
-
# +----------+----------+--------+
|
18
|
-
#
|
19
|
-
# We support LDAP searches for (uid=login), returning a synthesised DN and
|
20
|
-
# Maildir attribute, and we support LDAP binds to validate passwords. We
|
21
|
-
# keep a cache of recent lookups so that a bind to validate a password
|
22
|
-
# doesn't cause a second SQL query. Since we're multi-threaded, this should
|
23
|
-
# work even if the bind occurs on a different client connection to the search.
|
24
|
-
#
|
25
|
-
# To test:
|
26
|
-
# ldapsearch -H ldap://127.0.0.1:1389/ -b "dc=example,dc=com" "(uid=brian)"
|
27
|
-
#
|
28
|
-
# ldapsearch -H ldap://127.0.0.1:1389/ -b "dc=example,dc=com" \
|
29
|
-
# -D "id=1,dc=example,dc=com" -W "(uid=brian)"
|
30
|
-
|
31
|
-
$debug = true
|
32
|
-
SQL_CONNECT = ["1.2.3.4", "myuser", "mypass", "mydb"]
|
33
|
-
TABLE = "logins"
|
34
|
-
SQL_POOL_SIZE = 5
|
35
|
-
PW_CACHE_SIZE = 100
|
36
|
-
BASEDN = "dc=example,dc=com"
|
37
|
-
LDAP_PORT = 1389
|
38
|
-
|
39
|
-
# A thread-safe pool of persistent MySQL connections
|
40
|
-
|
41
|
-
class SQLPool
|
42
|
-
def initialize(n, *args)
|
43
|
-
@args = args
|
44
|
-
@pool = Queue.new # this is a thread-safe queue
|
45
|
-
n.times { @pool.push nil } # create connections on demand
|
46
|
-
end
|
47
|
-
|
48
|
-
def borrow
|
49
|
-
conn = @pool.pop || Mysql::new(*@args)
|
50
|
-
yield conn
|
51
|
-
rescue Exception
|
52
|
-
conn = nil # put 'nil' back into the pool
|
53
|
-
raise
|
54
|
-
ensure
|
55
|
-
@pool.push conn
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
# An simple LRU cache of username->password. It's linearly searched
|
60
|
-
# so don't make it too big.
|
61
|
-
|
62
|
-
class LRUCache
|
63
|
-
def initialize(size)
|
64
|
-
@size = size
|
65
|
-
@cache = [] # [[key,val],[key,val],...]
|
66
|
-
@mutex = Mutex.new
|
67
|
-
end
|
68
|
-
|
69
|
-
def add(id,data)
|
70
|
-
@mutex.synchronize do
|
71
|
-
@cache.delete_if { |k,v| k == id }
|
72
|
-
@cache.unshift [id,data]
|
73
|
-
@cache.pop while @cache.size > @size
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def find(id)
|
78
|
-
@mutex.synchronize do
|
79
|
-
index = entry = nil
|
80
|
-
@cache.each_with_index do |e, i|
|
81
|
-
if e[0] == id
|
82
|
-
entry = e
|
83
|
-
index = i
|
84
|
-
break
|
85
|
-
end
|
86
|
-
end
|
87
|
-
return nil unless index
|
88
|
-
@cache.delete_at(index)
|
89
|
-
@cache.unshift entry
|
90
|
-
return entry[1]
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
|
96
|
-
class SQLOperation < LDAP::Server::Operation
|
97
|
-
def self.setcache(cache,pool)
|
98
|
-
@@cache = cache
|
99
|
-
@@pool = pool
|
100
|
-
end
|
101
|
-
|
102
|
-
# Handle searches of the form "(uid=<foo>)" using SQL backend
|
103
|
-
# (uid=foo) => [:eq, "uid", matchobj, "foo"]
|
104
|
-
|
105
|
-
def search(basedn, scope, deref, filter)
|
106
|
-
raise LDAP::ResultError::UnwillingToPerform, "Bad base DN" unless basedn == BASEDN
|
107
|
-
raise LDAP::ResultError::UnwillingToPerform, "Bad filter" unless filter[0..1] == [:eq, "uid"]
|
108
|
-
uid = filter[3]
|
109
|
-
@@pool.borrow do |sql|
|
110
|
-
q = "select login_id,passwd from #{TABLE} where login='#{sql.quote(uid)}'"
|
111
|
-
puts "SQL Query #{sql.object_id}: #{q}" if $debug
|
112
|
-
res = sql.query(q)
|
113
|
-
res.each do |login_id,passwd|
|
114
|
-
@@cache.add(login_id, passwd)
|
115
|
-
send_SearchResultEntry("id=#{login_id},#{BASEDN}", {
|
116
|
-
"maildir"=>["/netapp/#{uid}/"],
|
117
|
-
})
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
# Validate passwords
|
123
|
-
|
124
|
-
def simple_bind(version, dn, password)
|
125
|
-
return if dn.nil? # accept anonymous
|
126
|
-
|
127
|
-
raise LDAP::ResultError::UnwillingToPerform unless dn =~ /\Aid=(\d+),#{BASEDN}\z/
|
128
|
-
login_id = $1
|
129
|
-
dbpw = @@cache.find(login_id)
|
130
|
-
unless dbpw
|
131
|
-
@@pool.borrow do |sql|
|
132
|
-
q = "select passwd from #{TABLE} where login_id=#{login_id}"
|
133
|
-
puts "SQL Query #{sql.object_id}: #{q}" if $debug
|
134
|
-
res = sql.query(q)
|
135
|
-
if res.num_rows == 1
|
136
|
-
dbpw = res.fetch_row[0]
|
137
|
-
@@cache.add(login_id, dbpw)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
raise LDAP::ResultError::InvalidCredentials unless dbpw and dbpw != "" and dbpw == password
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
# Build the objects we need
|
146
|
-
|
147
|
-
cache = LRUCache.new(PW_CACHE_SIZE)
|
148
|
-
pool = SQLPool.new(SQL_POOL_SIZE, *SQL_CONNECT)
|
149
|
-
SQLOperation.setcache(cache,pool)
|
150
|
-
|
151
|
-
s = LDAP::Server.new(
|
152
|
-
:port => LDAP_PORT,
|
153
|
-
:nodelay => true,
|
154
|
-
:listen => 10,
|
155
|
-
# :ssl_key_file => "key.pem",
|
156
|
-
# :ssl_cert_file => "cert.pem",
|
157
|
-
# :ssl_on_connect => true,
|
158
|
-
:operation_class => SQLOperation
|
159
|
-
)
|
160
|
-
s.run_tcpserver
|
161
|
-
s.join
|