ruby-ldapserver 0.5.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 13158eb5295138dfdbb01e8cb277458235ccbab1
4
- data.tar.gz: 70edb984eda164cc752e967429a348c2370ff852
2
+ SHA256:
3
+ metadata.gz: d5209f7e7a72b098ddf53b8453101e78becafc0ca2561d3bb32f8bdb57e804ad
4
+ data.tar.gz: 1a04b501ad27a22aa8f54813ff5839196e0b50d0abfc751fd1e13b1cc75b2515
5
5
  SHA512:
6
- metadata.gz: b085680909cc6b880a148a15e343d72204ccf2833c627b293d6d803289713a9e27c661e7637b173fe86f03863e3918e2309a0e768c3386b677bbac0eec3233c4
7
- data.tar.gz: 8370ea4fade64ee468dc835aa7dd8bc0113cae914f8f9e07fa8e1e420ad875a2b2a2055eba6b6f4203361fcdf05408bbd970160e78d370b7caf44091217c867e
6
+ metadata.gz: b9c1e36a98f53e56148d5d18a9ff66dad70e923ec33458d7624fbaab8ddbdaf14eceae277cae816c15246e23c9394acc459ba7245fe1252b3a6908583d6398b3
7
+ data.tar.gz: 2392b6af8469f13771e0eac4f8545a0485f4eead94a711b0c30217ed33368c3f60300852241a2e49e0644eb0753f73a4eabcaa573283e81335846d6c87416ec4
checksums.yaml.gz.sig ADDED
@@ -0,0 +1,3 @@
1
+ �$���Uop!mW{��qGgP=IAmb�p 7�H��_d���Uc/�ƺ�fAŅ����'�PT�9B@�����z��:[X��5!�
2
+ "�,��v�a��i��Eb*�+�7� �9�"���Lp��Mm�/K���IUW�C�uk
3
+ ��B�7�a�*No&�=�|��b���ű�ڿyN��e�q�'>vXOv���C����c�e#Sp)1;���p��;��@�4� �ҽV ��Q�9 �cL��-|l�[�@�96�z
@@ -0,0 +1,43 @@
1
+ name: CI
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ job_test_gem:
7
+ name: Test in source tree
8
+ strategy:
9
+ fail-fast: false
10
+ matrix:
11
+ include:
12
+ - os: windows
13
+ ruby: "head"
14
+ - os: windows
15
+ ruby: "2.4"
16
+ - os: ubuntu
17
+ ruby: "head"
18
+ - os: ubuntu
19
+ ruby: "3.1"
20
+ - os: ubuntu
21
+ ruby: "2.3"
22
+ - os: macos
23
+ ruby: "head"
24
+
25
+ runs-on: ${{ matrix.os }}-latest
26
+
27
+ steps:
28
+ - uses: actions/checkout@v3
29
+
30
+ - uses: ruby/setup-ruby@v1
31
+ with:
32
+ ruby-version: ${{ matrix.ruby }} # passed to ruby/setup-ruby
33
+
34
+ - name: Print tool versions
35
+ run: |
36
+ ruby -v
37
+ gem env
38
+
39
+ - name: Bundle install
40
+ run: bundle install
41
+
42
+ - name: Run tests
43
+ run: bundle exec rake
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  Gemfile.lock
2
2
  pkg
3
3
  .idea
4
+ doc/
@@ -1,21 +1,36 @@
1
- 0.5.3
1
+ ## 0.7.0 / 2022-12-06
2
+
3
+ * Support optional attribute range retrieval according to
4
+ https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ldap/searching-using-range-retrieval
5
+ * Add an experimental yet incomplete request router as alternative to using OperationClass
6
+ * Add support for listening on UNIX domain sockets.
7
+ Use `LDAP::Server.new(socket: '/tmp/server.sock')`
8
+ * Add LDAP::Server::DN to work with LDAP distinguished names
9
+ * Add CI on Github
10
+ * Use net-ldap for tests instead of unmaintained ruby-ldap.
11
+
12
+
13
+ ## 0.5.3 / 2015-08-16
2
14
  * Handle BN as client_timelimit; fixes incompatibility with some LDAP
3
15
  implementations (notably Shibboleth IdP v2 and proftpd).
4
16
  (Patch by Pete Birkinshaw.)
5
17
 
6
- 0.5.2
18
+
19
+ ## 0.5.2 / 2015-06-24
7
20
  * Make sure the exception used to stop the child doesn't propagate up (patch by Kasumi Hanazuki)
8
21
 
9
- 0.3.1 - 2008-01-16
22
+
23
+ ## 0.3.1 - 2008-01-16
10
24
  * First release as a gem [Brandon Keepers]
11
25
 
12
- RELEASE_0_3
26
+
27
+ ## RELEASE_0_3
13
28
 
14
29
  Filters now return nil instead of LDAP::Server::MatchingRule::DefaultMatch
15
30
  in the case that there's no schema.
16
31
  Minor changes to syntax.rb to support OpenLDAP extensions.
17
32
 
18
- 20050722
33
+ ## 20050722
19
34
 
20
35
  Change the 'validate' API so it works for updates too.
21
36
  Change the 'modify' API so it sends a hash of attr=>[:op,data] which makes
@@ -23,14 +38,14 @@ it easier to determine which entries have been modified.
23
38
  Fix modify, add and compare to normalise attribute names using the schema if
24
39
  there is one.
25
40
 
26
- 20050721
41
+ ## 20050721
27
42
 
28
43
  Added a whole loada Schema stuff.
29
44
  Moved exceptions under LDAP::ResultError for consistency with ruby-ldap.
30
45
  Changed the parsed [filter] format to include a MatchingRule object always
31
46
  (even if no schema is present)
32
47
 
33
- 20050711
48
+ ## 20050711
34
49
 
35
50
  Changed LDAPserver to LDAP::Server and rejigged the repository to match.
36
51
  In your code you will have to change:
@@ -40,7 +55,7 @@ In your code you will have to change:
40
55
  I have added require 'ldap/server' which pulls in the things a basic server
41
56
  will need (minus schema)
42
57
 
43
- 20050626
58
+ ## 20050626
44
59
 
45
60
  Factored out the SSL stuff into Connection, which should also allow the
46
61
  STARTTLS extension to be implemented later
@@ -49,7 +64,7 @@ Added a Server class, with methods run_tcpserver and run_prefork.
49
64
 
50
65
  Created an explicit preforkserver method.
51
66
 
52
- 20050625
67
+ ## 20050625
53
68
 
54
69
  tcpserver: add ability to drop privileges
55
70
 
@@ -57,7 +72,7 @@ examples/rbslapd3.rb: make work if ldapdb.yaml does not exist. Also bind
57
72
  explicitly to 0.0.0.0; it seems that TCPSocket doesn't work properly in
58
73
  some circumstances without it (FreeBSD 5.4 with IPv6 disabled in kernel)
59
74
 
60
- 20050620
75
+ ## 20050620
61
76
 
62
77
  RELEASE_0_2
63
78
 
@@ -76,7 +91,7 @@ removes 100ms of latency in responses.
76
91
 
77
92
  Added examples/speedtest.rb
78
93
 
79
- 20050619
94
+ ## 20050619
80
95
 
81
96
  Modify connection.rb to ensure no memory leak in the event of exceptions
82
97
  being raised in operation threads.
@@ -84,8 +99,8 @@ being raised in operation threads.
84
99
  Fix examples/rbslapd2.rb SQLPool so that it always puts connections back
85
100
  into the pool (using 'ensure' this time :-)
86
101
 
87
- 20050618
102
+ ## 20050618
88
103
 
89
104
  RELEASE_0_1
90
105
 
91
- 20050616
106
+ ## 20050616
data/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # ruby-ldapserver
2
+
3
+ ruby-ldapserver is a lightweight, pure Ruby framework for implementing LDAP server applications. It is intended primarily for building a gateway from LDAP queries into some other protocol or database. It does not attempt to be a full or correct implementation of the standard LDAP data model itself (although you could build one using this as a frontend).
4
+
5
+ Since it's written entirely in Ruby, it benefits from Ruby's threading engine.
6
+
7
+ ## Target audience
8
+
9
+ Technically-savvy Ruby applications developers; the sort of people who are happy to read RFCs and read code to work out what it does :-)
10
+
11
+ The examples/ directory contains a few minimal LDAP servers which you can use as a starting point.
12
+
13
+ ## Status
14
+
15
+ This is still an early release. It works for me as an LDAP protocol layer; the Schema stuff has not been heavily tested.
16
+
17
+ ## Request router
18
+
19
+ The request router is a simple mapping of potentially parameterized routes (DNs) and actions to a *controller* action, allowing for simple, flexible and maintainable code. Alternatively the legacy `Operation` class can be used. See the `examples/` directory for more details and sample implementations.
20
+
21
+ ## Configuration
22
+
23
+ ```ruby
24
+ params = {
25
+ # Bind to address (cannot be combined with socket)
26
+ :bindaddr => '127.0.0.1', # defaults to 0.0.0.0
27
+ :port => 1389,
28
+
29
+ # Bind to socket (cannot be combined with address)
30
+ :socket => '/tmp/ldap.sock',
31
+
32
+ # Drop process and socket privileges to user and/or group (cannot be combined with uid/gid)
33
+ :user => 'ldap',
34
+ :group => 'ldap',
35
+
36
+ # Drop process and socket privileges to UID and/or GID (cannot be combined with user/group)
37
+ :uid => 1000,
38
+ :gid => 1000,
39
+
40
+ # TCP_NODELAY option
41
+ :nodelay => true,
42
+
43
+ # Socket backlog
44
+ :listen => 10,
45
+
46
+ # SSL/TLS
47
+ :ssl_key_file => 'key.pem',
48
+ :ssl_cert_file => 'cert.pem',
49
+ :ssl_on_connect => true,
50
+
51
+ # Request router (cannot be combined with legacy operation)
52
+ :router => MyAppRouter,
53
+
54
+ # Legacy Operation class (cannot be combined with request router)
55
+ :operation_class => MyAppOperation,
56
+ :operation_args => ['my', 'arguments'],
57
+
58
+ # Schema
59
+ :schema => my_schema,
60
+ :namingContexts => ['dc=example,dc=com']
61
+ }
62
+ ```
63
+
64
+ ## Libraries
65
+
66
+ ASN1 encoding and decoding is done using the 'openssl' extension, which is standard in the Ruby 1.8.2 base distribution. To check you have it, you should be able to run `ruby -ropenssl -e puts` with no error.
67
+
68
+ However, I've found in the past that Linux machines don't always build the openssl extension when compiling Ruby from source. With Red Hat 9, the solution for me was, when building Ruby itself:
69
+
70
+ ```
71
+ $ export CPPFLAGS="-I/usr/kerberos/include"
72
+ $ export LDFLAGS="-L/usr/kerberos/lib"
73
+ $ ./configure ...etc
74
+ ```
75
+
76
+ If you want to run the test suite then you'll need to install the `ruby-ldap` client library, and if you want to run `examples/rbslapd3.rb` then you'll need the `prefork` library. Both are available from <http://raa.ruby-lang.org/>.
77
+
78
+ ## Protocol implementation
79
+
80
+ ruby-ldapserver tries to be a reasonably complete implementation of the message decoding and encoding components of LDAP. However, it does not synthesise or directly enforce the LDAP data model. It will advertise a schema in the root DSE if you configure one, and it provides helper functions which allow you to validate add and modify operations against a schema; but it's up to you to use them, if you wish. If you're just using LDAP as a convenient query interface into some other database, you probably don't care about schemas.
81
+
82
+ If your clients permit it, you can violate the LDAP specification further, eliminating some of the gross design flaws of LDAP. For example, you can ditch the LDAP idea that a Distinguished Name must consist of attr=val,attr=val,attr=val... and use whatever is convenient as a primary key (e.g. "val1,val2,val3" or "id,table_name"). The 'add' operation could allocate DNs automatically from a sequence. There's no need for the data duplication where an LDAP entry must contain the same attr=val pair which is also the entry's RDN. Violations of the LDAP spec in this way are at your own risk.
83
+
84
+ ## Threading issues
85
+
86
+ The core of this library is the `LDAP::Server::Connection` object which handles communication with a single client, and the `LDAP::Server::Operation` object which handles a single request. Because the LDAP protocol allows a client to send multiple overlapping requests down the same TCP connection, I start a new Ruby thread for each Operation.
87
+
88
+ If your Operation object deals with any global shared data, then it needs to do so in a thread-safe way. If this is new to you then see
89
+
90
+ [http://www.rubycentral.com/book/tut_threads.html](http://www.rubycentral.com/book/tut_threads.html)
91
+ [http://www.rubygarden.org/ruby?MultiThreading](http://www.rubygarden.org/ruby?MultiThreading)
92
+
93
+ For incoming client connections, I have supplied a simple tcpserver method which starts a new Ruby thread for each client. This works fine, but in a multi-CPU system, all LDAP server operations will be processed on one CPU; also with a very large number of concurrent client connections, you may find you hit the a max-filedescriptors-per-process limit.
94
+
95
+ I have also provided a preforking server; see `examples/rbslapd3.rb`. In this case, your connections are handled in separate processes so they cannot share data directly in RAM.
96
+
97
+ If you are using the default threading tcpserver, then beware that a number of Ruby extension libraries block the threading interpreter. In particular, the client library `ruby-ldap` blocks when waiting for a response from a remote server, since it's a wrapper around a C library which is unaware of Ruby's threading engine. This can cause your application to 'freeze' periodically. Either choose client libraries which play well with threading, or make sure each client is handled in a different process.
98
+
99
+ For example, when talking to a MySQL database, you might want to choose `ruby-mysql` (which is a pure Ruby implementation of the MySQL protocol) rather than `mysql-ruby` (which is a wrapper around the C API, and blocks while waiting for responses from the server)
100
+
101
+ Even with something like `ruby-mysql`, beware DNS lookups: resolver libraries can block too. There is a pure Ruby resolver replacement in the standard library: if you do
102
+
103
+ ```
104
+ require 'resolv-replace'
105
+ ```
106
+
107
+ This changes TCPSocket and friends to use it instead of the default C resolver. Or you could just hard-code IP addresses, or put entries in /etc/hosts for the machines you want to contact.
108
+
109
+ Another threading issue to think about is abandoned and timed-out LDAP operations. The `Connection` object handles these by raising an `LDAP::Server::Abandon` or `LDAP::Server::TimeLimitExceeded` exception in the `Operation` thread, which you can either ignore or rescue. However, if in rescuing it you end up putting (say) a SQL connection back into a pool, you should beware that the SQL connection may still be mid-query, so it's probably better to discard it and use a fresh one next time.
110
+
111
+ ## Performance
112
+
113
+ `examples/speedtest.rb` is a simple client which forks N processes, and in each process opens an LDAP connection, binds, and sends M search requests down it.
114
+
115
+ Using speedtest.rb and rbslapd1.rb, running on the *same* machine (single-processor AMD Athlon 2500+) I achieve around 800 searches per second with N=1,M=1000 and 300-400 searches per second with N=10,M=100.
116
+
117
+ ## To-do list
118
+
119
+ - handle and test generation of LDAP referrals properly
120
+ - more cases in test suite: abandon, concurrency, performance tests, error
121
+ handling
122
+ - extensible match filters
123
+ - extended operations
124
+ RFC 2830 - Start TLS
125
+ RFC 3062 - password modify
126
+ RFC 2839 - whoami
127
+ RFC 3909 - cancel
128
+
129
+ ## References
130
+
131
+ - [RFC2251](ftp://ftp.isi.edu/in-notes/rfc2251.txt) (base protocol)
132
+ - [RFC2252](ftp://ftp.isi.edu/in-notes/rfc2252.txt) (schema)
133
+ - [RFC2253](ftp://ftp.isi.edu/in-notes/rfc2253.txt) (DN encoding)
134
+ - [X.680](http://www.itu.int/ITU-T/studygroups/com17/languages/X.680-0207.pdf)
135
+ - [X.690](http://www.itu.int/ITU-T/studygroups/com10/languages/X.690_1297.pdf)
136
+
137
+ ## Contact
138
+
139
+ You are very welcome to E-mail me with bug reports, patches, comments and suggestions for this software. However, please DON'T send me any general questions about LDAP, how LDAP works, how to apply LDAP in your particular situation, or questions about any other LDAP software. The [`ldap@umich.edu` mailing list](http://listserver.itd.umich.edu/cgi-bin/lyris.pl?enter=ldap) is probably the correct place to ask such questions.
140
+
141
+ Brian Candler <B.Candler@pobox.com>
data/examples/rbslapd1.rb CHANGED
@@ -18,7 +18,7 @@ class HashOperation < LDAP::Server::Operation
18
18
  end
19
19
 
20
20
  def search(basedn, scope, deref, filter)
21
- basedn.downcase!
21
+ basedn = basedn.downcase
22
22
 
23
23
  case scope
24
24
  when LDAP::Server::BaseObject
@@ -41,23 +41,24 @@ class HashOperation < LDAP::Server::Operation
41
41
  end
42
42
 
43
43
  def add(dn, av)
44
- dn.downcase!
44
+ dn = dn.downcase
45
45
  raise LDAP::ResultError::EntryAlreadyExists if @hash[dn]
46
46
  @hash[dn] = av
47
47
  end
48
48
 
49
49
  def del(dn)
50
- dn.downcase!
50
+ dn = dn.downcase
51
51
  raise LDAP::ResultError::NoSuchObject unless @hash.has_key?(dn)
52
52
  @hash.delete(dn)
53
53
  end
54
54
 
55
55
  def modify(dn, ops)
56
+ dn = dn.downcase
56
57
  entry = @hash[dn]
57
58
  raise LDAP::ResultError::NoSuchObject unless entry
58
59
  ops.each do |attr, vals|
59
60
  op = vals.shift
60
- case op
61
+ case op
61
62
  when :add
62
63
  entry[attr] ||= []
63
64
  entry[attr] += vals
data/examples/rbslapd2.rb CHANGED
@@ -54,7 +54,7 @@ class SQLPool
54
54
  ensure
55
55
  @pool.push conn
56
56
  end
57
- end
57
+ end
58
58
 
59
59
  # An simple LRU cache of username->password. It's linearly searched
60
60
  # so don't make it too big.
data/examples/rbslapd3.rb CHANGED
@@ -80,7 +80,7 @@ class DirOperation < LDAP::Server::Operation
80
80
 
81
81
  def search(basedn, scope, deref, filter)
82
82
  $debug << "Search: basedn=#{basedn.inspect}, scope=#{scope.inspect}, deref=#{deref.inspect}, filter=#{filter.inspect}\n" if $debug
83
- basedn.downcase!
83
+ basedn = basedn.downcase
84
84
 
85
85
  case scope
86
86
  when LDAP::Server::BaseObject
@@ -115,7 +115,7 @@ class DirOperation < LDAP::Server::Operation
115
115
  # FIXME: normalize the DN and check it's below our root DN
116
116
  # FIXME: validate that a superior object exists
117
117
  # FIXME: validate that entry contains the RDN attribute (yuk)
118
- dn.downcase!
118
+ dn = dn.downcase
119
119
  @dir.lock do
120
120
  @dir.update
121
121
  raise LDAP::ResultError::EntryAlreadyExists if @dir.data[dn]
@@ -125,7 +125,7 @@ class DirOperation < LDAP::Server::Operation
125
125
  end
126
126
 
127
127
  def del(dn)
128
- dn.downcase!
128
+ dn = dn.downcase
129
129
  @dir.lock do
130
130
  @dir.update
131
131
  raise LDAP::ResultError::NoSuchObject unless @dir.data.has_key?(dn)
@@ -135,7 +135,7 @@ class DirOperation < LDAP::Server::Operation
135
135
  end
136
136
 
137
137
  def modify(dn, ops)
138
- dn.downcase!
138
+ dn = dn.downcase
139
139
  @dir.lock do
140
140
  @dir.update
141
141
  entry = @dir.data[dn]
@@ -0,0 +1,90 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # This is a modified version of rbslapd1.rb which uses a Router instead of
4
+ # subclassing the LDAP::Server::Operation class.
5
+
6
+ # This is a trivial LDAP server which just stores directory entries in RAM.
7
+ # It does no validation or authentication. This is intended just to
8
+ # demonstrate the API, it's not for real-world use!!
9
+
10
+ $:.unshift('../lib')
11
+ $debug = true
12
+
13
+ require 'ldap/server'
14
+ require 'ldap/server/router'
15
+
16
+ $logger = Logger.new($stderr)
17
+
18
+ class LDAPController
19
+ def self.bind(request, version, dn, password, params)
20
+ $logger.debug "Catchall bind request"
21
+ raise LDAP::ResultError::UnwillingToPerform, "Invalid bind DN"
22
+ end
23
+
24
+ def self.bindUser(request, version, dn, password, params)
25
+ if params[:uid].nil? or
26
+ params[:uid] != 'admin' or
27
+ password != 'adminpassword'
28
+ $logger.warn "Denied access for user #{params[:uid]}: Invalid credentials"
29
+ raise LDAP::ResultError::InvalidCredentials, "Invalid credentials"
30
+ end
31
+
32
+ $logger.info "Authenticated user #{params[:uid]}"
33
+ end
34
+
35
+ def self.search(request, baseObject, scope, deref, filter, params)
36
+ $logger.info "Catchall search request for #{baseObject}"
37
+ raise LDAP::ResultError::UnwillingToPerform, "Invalid search DN"
38
+ end
39
+
40
+ def self.searchUsers(request, baseObject, scope, deref, filter, params)
41
+ $logger.info "Search users"
42
+ end
43
+ end
44
+
45
+ router = LDAP::Server::Router.new($logger) do
46
+ # Different syntax but same thing
47
+ bind nil => "LDAPController#bind"
48
+ route :bind, nil => "LDAPController#bind"
49
+
50
+ # Bind a route using variables. A hash with the variables will be passed
51
+ # to your function as last argument.
52
+ bind "uid=:uid,ou=Users,dc=mydomain,dc=com" => "LDAPController#bindUser"
53
+
54
+ search nil => "LDAPController#search"
55
+ search "ou=Users,dc=mydomain,dc=com" => "LDAPController#searchUsers"
56
+ end
57
+
58
+
59
+ # This is the shared object which carries our actual directory entries.
60
+ # It's just a hash of {dn=>entry}, where each entry is {attr=>[val,val,...]}
61
+
62
+ directory = {}
63
+
64
+ # Let's put some backing store on it
65
+
66
+ require 'yaml'
67
+ begin
68
+ File.open("ldapdb.yaml") { |f| directory = YAML::load(f.read) }
69
+ rescue Errno::ENOENT
70
+ end
71
+
72
+ at_exit do
73
+ File.open("ldapdb.new","w") { |f| f.write(YAML::dump(directory)) }
74
+ File.rename("ldapdb.new","ldapdb.yaml")
75
+ end
76
+
77
+ # Listen for incoming LDAP connections. For each one, create a Connection
78
+ # object, which will invoke a HashOperation object for each request.
79
+
80
+ s = LDAP::Server.new(
81
+ :port => 1389,
82
+ :nodelay => true,
83
+ :listen => 10,
84
+ # :ssl_key_file => "key.pem",
85
+ # :ssl_cert_file => "cert.pem",
86
+ # :ssl_on_connect => true,
87
+ :router => router
88
+ )
89
+ s.run_tcpserver
90
+ s.join
@@ -0,0 +1,73 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # Example server that listens on both a port and a UNIX domain socket
4
+ # Try it using:
5
+ # $ ldapsearch -LLL -H ldap://localhost:1389 -D uid=whatever -b ou=Users,dc=mydomain,dc=com
6
+ # $ ldapsearch -LLL -H ldapi://%2ftmp%2frbslapd5.sock -D uid=whatever -b ou=Users,dc=mydomain,dc=com
7
+
8
+ $:.unshift('../lib')
9
+ $debug = true
10
+
11
+ require 'fileutils'
12
+
13
+ require 'ldap/server'
14
+ require 'ldap/server/router'
15
+
16
+ $logger = Logger.new($stderr)
17
+
18
+ class LDAPController
19
+ def self.bind(request, version, dn, password, params)
20
+ $logger.info "Processing bind route for \'#{dn}\' with password \'#{password}\'"
21
+ end
22
+
23
+ def self.search(request, baseObject, scope, deref, filter, params)
24
+ $logger.info "Processing search route for #{baseObject}"
25
+
26
+ h = {
27
+ 'uid' => 'jdoe',
28
+ 'objectClass' => 'userAccount',
29
+ 'givenName' => 'John',
30
+ 'sn' => 'Doe'
31
+ }
32
+ request.send_SearchResultEntry("uid=jdoe,#{baseObject}", h)
33
+ end
34
+ end
35
+
36
+ router = LDAP::Server::Router.new($logger) do
37
+ bind nil => "LDAPController#bind"
38
+
39
+ search "ou=Users,dc=mydomain,dc=com" => "LDAPController#search"
40
+ end
41
+
42
+ params = {
43
+ :nodelay => true,
44
+ :listen => 10,
45
+ :router => router
46
+ }
47
+
48
+ # Listen on IP address and port
49
+
50
+ params[:bindaddr] = '127.0.0.1' # Leave this blank to listen on 0.0.0.0
51
+ params[:port] = 1389
52
+
53
+ addr_server = LDAP::Server.new params
54
+ addr_server.run_tcpserver
55
+
56
+ # Listen on socket
57
+
58
+ params.delete :bindaddr
59
+ params.delete :port
60
+ params[:socket] = '/tmp/rbslapd5.sock'
61
+
62
+ FileUtils::rm_f params[:socket]
63
+
64
+ socket_server = LDAP::Server.new params
65
+ socket_server.run_tcpserver
66
+
67
+ trap 'INT' do
68
+ addr_server.stop
69
+ socket_server.stop
70
+ end
71
+
72
+ addr_server.join
73
+ socket_server.join
@@ -0,0 +1,75 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ # Slightly modified version of rbslapd5.rb which demonstrates dropping
4
+ # root privileges after binding to port 389
5
+ #
6
+ # Run this script with `sudo`
7
+
8
+ $:.unshift('../lib')
9
+ $debug = true
10
+
11
+ require 'fileutils'
12
+
13
+ require 'ldap/server'
14
+ require 'ldap/server/router'
15
+
16
+ $logger = Logger.new($stderr)
17
+
18
+ class LDAPController
19
+ def self.bind(request, version, dn, password, params)
20
+ $logger.info "Processing bind route for \'#{dn}\' with password \'#{password}\'"
21
+ end
22
+
23
+ def self.search(request, baseObject, scope, deref, filter, params)
24
+ $logger.info "Processing search route for #{baseObject}"
25
+
26
+ h = {
27
+ 'uid' => 'jdoe',
28
+ 'objectClass' => 'userAccount',
29
+ 'givenName' => 'John',
30
+ 'sn' => 'Doe'
31
+ }
32
+ request.send_SearchResultEntry("uid=jdoe,#{baseObject}", h)
33
+ end
34
+ end
35
+
36
+ router = LDAP::Server::Router.new($logger) do
37
+ bind nil => "LDAPController#bind"
38
+
39
+ search "ou=Users,dc=mydomain,dc=com" => "LDAPController#search"
40
+ end
41
+
42
+ params = {
43
+ :nodelay => true,
44
+ :listen => 10,
45
+ :router => router
46
+ }
47
+
48
+ # Listen on IP address and port
49
+
50
+ params[:bindaddr] = '127.0.0.1' # Leave this blank to listen on 0.0.0.0
51
+ params[:port] = 389
52
+ params[:user] = 'ldap'
53
+ params[:group] = 'ldap'
54
+
55
+ addr_server = LDAP::Server.new params
56
+ addr_server.run_tcpserver
57
+
58
+ # Listen on socket
59
+
60
+ params.delete :bindaddr
61
+ params.delete :port
62
+ params[:socket] = '/tmp/rbslapd6.sock'
63
+
64
+ FileUtils::rm_f params[:socket]
65
+
66
+ socket_server = LDAP::Server.new params
67
+ socket_server.run_tcpserver
68
+
69
+ trap 'INT' do
70
+ addr_server.stop
71
+ socket_server.stop
72
+ end
73
+
74
+ addr_server.join
75
+ socket_server.join