ruby-ldapserver 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ldap-server-primitive.gemspec
4
+ gemspec
data/Rakefile CHANGED
@@ -1,22 +1 @@
1
- require 'rubygems'
2
- require 'hoe'
3
- require File.join(File.dirname(__FILE__), 'lib', 'ldap', 'server', 'version')
4
-
5
- RDOC_OPTS = ['--quiet', '--title', "ruby-ldapserver",
6
- "--opname", "index.html",
7
- "--line-numbers",
8
- "--main", "README",
9
- "--inline-source"]
10
-
11
- # Generate all the Rake tasks
12
- hoe = Hoe.new('ruby-ldapserver', ENV['VERSION'] || LDAP::Server::VERSION::STRING) do |p|
13
- p.rubyforge_name = 'ruby-ldapserver'
14
- p.summary = "A pure-Ruby framework for building LDAP servers"
15
- p.description = "ruby-ldapserver is a lightweight, pure-Ruby skeleton for implementing LDAP
16
- server applications."
17
- p.author = 'Brian Candler'
18
- p.email = 'B.Candler@pobox.com'
19
- p.url = 'http://rubyforge.org/projects/ruby-ldapserver'
20
- p.test_globs = ["test/**/*_test.rb"]
21
- p.changes = p.paragraphs_of('ChangeLog', 0..1).join("\n\n")
22
- end
1
+ require "bundler/gem_tasks"
@@ -19,22 +19,30 @@ class Server
19
19
  @io = io
20
20
  @opt = opt
21
21
  @mutex = Mutex.new
22
- @active_reqs = {} # map message ID to thread object
22
+ @threadgroup = ThreadGroup.new
23
23
  @binddn = nil
24
24
  @version = 3
25
- @logger = @opt[:logger] || $stderr
25
+ @logger = @opt[:logger]
26
26
  @ssl = false
27
27
 
28
28
  startssl if @opt[:ssl_on_connect]
29
29
  end
30
30
 
31
- def log(msg)
32
- @logger << "[#{@io.peeraddr[3]}]: #{msg}\n"
31
+ def log(msg, severity = Logger::INFO)
32
+ @logger.add(severity, msg, @io.peeraddr[3])
33
+ end
34
+
35
+ def debug msg
36
+ log msg, Logger::DEBUG
37
+ end
38
+
39
+ def log_exception(e)
40
+ log "#{e}: #{e.backtrace.join("\n\tfrom ")}", Logger::ERROR
33
41
  end
34
42
 
35
43
  def startssl # :yields:
36
44
  @mutex.synchronize do
37
- raise LDAP::ResultError::OperationsError if @ssl or @active_reqs.size > 0
45
+ raise LDAP::ResultError::OperationsError if @ssl or @threadgroup.list.size > 0
38
46
  yield if block_given?
39
47
  @io = OpenSSL::SSL::SSLSocket.new(@io, @opt[:ssl_ctx])
40
48
  @io.sync_close = true
@@ -49,8 +57,11 @@ class Server
49
57
  def ber_read(io)
50
58
  blk = io.read(2) # minimum: short tag, short length
51
59
  throw(:close) if blk.nil?
52
- tag = blk[0] & 0x1f
53
- len = blk[1]
60
+
61
+ codepoints = blk.respond_to?(:codepoints) ? blk.codepoints.to_a : blk
62
+
63
+ tag = codepoints[0] & 0x1f
64
+ len = codepoints[1]
54
65
 
55
66
  if tag == 0x1f # long form
56
67
  tag = 0
@@ -116,78 +127,22 @@ class Server
116
127
  throw(:close)
117
128
 
118
129
  when 3 # SearchRequest
119
- # Note: RFC 2251 4.4.4.1 says behaviour is undefined if
120
- # client sends an overlapping request with same message ID,
121
- # so we don't have to worry about the case where there is
122
- # already a thread with this id in @active_reqs.
123
- # However, to avoid a race we copy messageId/
124
- # protocolOp/controls into thread-local variables, because
125
- # they will change when the next request comes in.
126
- #
127
- # There is a theoretical race condition here: a client could
128
- # send an abandon request before Thread.current is assigned to
129
- # @active_reqs[thrm]. It's not a problem, because abandon isn't
130
- # guaranteed to work anyway. Doing it this way ensures that
131
- # @active_reqs does not leak memory on a long-lived connection.
132
-
133
- Thread.new(messageId,protocolOp,controls) do |thrm,thrp,thrc|
134
- begin
135
- @active_reqs[thrm] = Thread.current
136
- operationClass.new(self,thrm,*ocArgs).do_search(thrp, thrc)
137
- ensure
138
- @active_reqs.delete(thrm)
139
- end
140
- end
130
+ start_op(messageId,protocolOp,controls,:do_search)
141
131
 
142
132
  when 6 # ModifyRequest
143
- Thread.new(messageId,protocolOp,controls) do |thrm,thrp,thrc|
144
- begin
145
- @active_reqs[thrm] = Thread.current
146
- operationClass.new(self,thrm,*ocArgs).do_modify(thrp, thrc)
147
- ensure
148
- @active_reqs.delete(thrm)
149
- end
150
- end
133
+ start_op(messageId,protocolOp,controls,:do_modify)
151
134
 
152
135
  when 8 # AddRequest
153
- Thread.new(messageId,protocolOp,controls) do |thrm,thrp,thrc|
154
- begin
155
- @active_reqs[thrm] = Thread.current
156
- operationClass.new(self,thrm,*ocArgs).do_add(thrp, thrc)
157
- ensure
158
- @active_reqs.delete(thrm)
159
- end
160
- end
136
+ start_op(messageId,protocolOp,controls,:do_add)
161
137
 
162
138
  when 10 # DelRequest
163
- Thread.new(messageId,protocolOp,controls) do |thrm,thrp,thrc|
164
- begin
165
- @active_reqs[thrm] = Thread.current
166
- operationClass.new(self,thrm,*ocArgs).do_del(thrp, thrc)
167
- ensure
168
- @active_reqs.delete(thrm)
169
- end
170
- end
139
+ start_op(messageId,protocolOp,controls,:do_del)
171
140
 
172
141
  when 12 # ModifyDNRequest
173
- Thread.new(messageId,protocolOp,controls) do |thrm,thrp,thrc|
174
- begin
175
- @active_reqs[thrm] = Thread.current
176
- operationClass.new(self,thrm,*ocArgs).do_modifydn(thrp, thrc)
177
- ensure
178
- @active_reqs.delete(thrm)
179
- end
180
- end
142
+ start_op(messageId,protocolOp,controls,:do_modifydn)
181
143
 
182
144
  when 14 # CompareRequest
183
- Thread.new(messageId,protocolOp,controls) do |thrm,thrp,thrc|
184
- begin
185
- @active_reqs[thrm] = Thread.current
186
- operationClass.new(self,thrm,*ocArgs).do_compare(thrp, thrc)
187
- ensure
188
- @active_reqs.delete(thrm)
189
- end
190
- end
145
+ start_op(messageId,protocolOp,controls,:do_compare)
191
146
 
192
147
  when 16 # AbandonRequest
193
148
  abandon(protocolOp.value)
@@ -207,6 +162,31 @@ class Server
207
162
  abandon_all
208
163
  end
209
164
 
165
+ # Start an operation in a Thread. Add this to a ThreadGroup to allow
166
+ # the operation to be abandoned later.
167
+ #
168
+ # When the thread terminates, it automatically drops out of the group.
169
+ #
170
+ # Note: RFC 2251 4.4.4.1 says behaviour is undefined if
171
+ # client sends an overlapping request with same message ID,
172
+ # so we don't have to worry about the case where there is
173
+ # already a thread with this messageId in @threadgroup.
174
+
175
+ def start_op(messageId,protocolOp,controls,meth)
176
+ operationClass = @opt[:operation_class]
177
+ ocArgs = @opt[:operation_args] || []
178
+ thr = Thread.new do
179
+ begin
180
+ operationClass.new(self,messageId,*ocArgs).
181
+ send(meth,protocolOp,controls)
182
+ rescue Exception => e
183
+ log_exception e
184
+ end
185
+ end
186
+ thr[:messageId] = messageId
187
+ @threadgroup.add(thr)
188
+ end
189
+
210
190
  def write(data)
211
191
  @mutex.synchronize do
212
192
  @io.write(data)
@@ -223,18 +203,16 @@ class Server
223
203
 
224
204
  def abandon(messageID)
225
205
  @mutex.synchronize do
226
- thread = @active_reqs.delete(messageID)
227
- thread.raise LDAP::Abandon if thread and thread.alive?
206
+ thread = @threadgroup.list.find { |t| t[:messageId] == messageID }
207
+ thread.raise LDAP::Abandon if thread
228
208
  end
229
209
  end
230
210
 
231
211
  def abandon_all
232
- return if @active_reqs.size == 0
233
212
  @mutex.synchronize do
234
- @active_reqs.each do |id, thread|
235
- thread.raise LDAP::Abandon if thread.alive?
213
+ @threadgroup.list.each do |thread|
214
+ thread.raise LDAP::Abandon
236
215
  end
237
- @active_reqs = {}
238
216
  end
239
217
  end
240
218
 
@@ -38,16 +38,14 @@ class Server
38
38
  @server = @connection.opt[:server]
39
39
  end
40
40
 
41
- # Send a log message
42
-
43
- def log(*args)
44
- @connection.log(*args)
45
- end
46
-
47
41
  # Send an exception report to the log
48
42
 
49
- def log_exception(e)
50
- @connection.log "#{e}: #{e.backtrace.join("\n\tfrom ")}"
43
+ def debug msg
44
+ @connection.debug msg
45
+ end
46
+
47
+ def log_exception
48
+ @connection.log_exception msg
51
49
  end
52
50
 
53
51
  ##################################################
@@ -298,7 +296,7 @@ class Server
298
296
  attr = @schema.find_attrtype(attr).to_s
299
297
  end
300
298
  vals = seq.value[1].value[1].value.collect { |v| v.value }
301
- case seq.value[0].value
299
+ case seq.value[0].value.to_i
302
300
  when 0
303
301
  modinfo[attr] = [:add] + vals
304
302
  when 1
@@ -436,7 +434,8 @@ class Server
436
434
  # care of, but you need to perform all authorisation checks yourself,
437
435
  # using @connection.binddn
438
436
 
439
- def search(basedn, scope, deref, filter, attrs)
437
+ def search(basedn, scope, deref, filter)
438
+ debug "search(#{basedn}, #{scope}, #{deref}, #{filter})"
440
439
  raise LDAP::ResultError::UnwillingToPerform, "search not implemented"
441
440
  end
442
441
 
@@ -22,7 +22,6 @@ class Server
22
22
  # :max_idle=>N - seconds
23
23
 
24
24
  def self.preforkserver(opt, &blk)
25
- logger = opt[:logger] || $stderr
26
25
  server = PreFork.new(opt[:bindaddr] || "0.0.0.0", opt[:port])
27
26
 
28
27
  # Drop privileges if requested
@@ -60,7 +59,7 @@ class Server
60
59
  # This exception can be raised to shut the server down
61
60
  server.stop
62
61
  rescue Exception => e
63
- logger << "[#{s.peeraddr[3]}]: #{e}: #{e.backtrace[0]}\n"
62
+ opt[:logger].error(s.peeraddr[3]) { "#{e}: #{e.backtrace[0]}" }
64
63
  ensure
65
64
  s.close
66
65
  end
@@ -1,6 +1,7 @@
1
1
  require 'ldap/server/connection'
2
2
  require 'ldap/server/operation'
3
3
  require 'openssl'
4
+ require 'logger'
4
5
 
5
6
  module LDAP
6
7
  class Server
@@ -20,12 +21,19 @@ class Server
20
21
  # :ssl_ca_path=>directory - verify peer certificates
21
22
  # :schema=>Schema - Schema object
22
23
  # :namingContexts=>[dn, ...] - base DN(s) we answer
24
+
25
+ attr_reader :logger
23
26
 
24
27
  def initialize(opt = DEFAULT_OPT)
25
28
  @opt = opt
26
29
  @opt[:server] = self
27
30
  @opt[:operation_class] ||= LDAP::Server::Operation
28
31
  @opt[:operation_args] ||= []
32
+ unless @opt[:logger]
33
+ @opt[:logger] ||= Logger.new($stderr)
34
+ @opt[:logger].level = Logger::INFO
35
+ end
36
+ @logger = @opt[:logger]
29
37
  LDAP::Server.ssl_prepare(@opt)
30
38
  @schema = opt[:schema] # may be nil
31
39
  @root_dse = Hash.new { |h,k| h[k] = [] }.merge({
@@ -47,12 +55,19 @@ class Server
47
55
  ctx = OpenSSL::SSL::SSLContext.new
48
56
  ctx.key = OpenSSL::PKey::RSA.new(File::read(opt[:ssl_key_file]))
49
57
  ctx.cert = OpenSSL::X509::Certificate.new(File::read(opt[:ssl_cert_file]))
58
+ if opt[:ssl_dhparams]
59
+ ctx.tmp_dh_callback = proc { |*args|
60
+ OpenSSL::PKey::DH.new(
61
+ File.read(opt[:ssl_dhparams])
62
+ )
63
+ }
64
+ end
50
65
  if opt[:ssl_ca_path]
51
66
  ctx.ca_path = opt[:ssl_ca_path]
52
- ctx.verify_mode =
67
+ ctx.verify_mode = opt[:ssl_verify_mode] ||
53
68
  OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
54
- else
55
- $stderr.puts "Warning: SSL peer certificate won't be verified"
69
+ elsif opt[:ssl_verify_mode] != 0
70
+ $stderr.puts "Warning: No ssl_ca_path, peer certificate won't be verified"
56
71
  end
57
72
  opt[:ssl_ctx] = ctx
58
73
  end
@@ -22,7 +22,6 @@ class Server
22
22
  # :nodelay=>true - set TCP_NODELAY option
23
23
 
24
24
  def self.tcpserver(opt, &blk)
25
- logger = opt[:logger] || $stderr
26
25
  server = TCPServer.new(opt[:bindaddr] || "0.0.0.0", opt[:port])
27
26
 
28
27
  # Drop privileges if requested
@@ -51,8 +50,7 @@ class Server
51
50
  begin
52
51
  s.instance_eval(&blk)
53
52
  rescue Exception => e
54
- logger << "[#{s.peeraddr[3]}]: #{e}: #{e.backtrace[0]}\n"
55
- #logger << "[#{s.peeraddr[3]}]: #{e}: #{e.backtrace.join("\n\tfrom ")}\n"
53
+ opt[:logger].error(s.peeraddr[3]) {"#{e}: #{e.backtrace[0]}"}
56
54
  ensure
57
55
  s.close
58
56
  end
@@ -1,11 +1,5 @@
1
1
  module LDAP #:nodoc:
2
2
  class Server #:nodoc:
3
- class VERSION #:nodoc:
4
- MAJOR = 0
5
- MINOR = 3
6
- TINY = 1
7
-
8
- STRING = [MAJOR, MINOR, TINY].join('.')
9
- end
3
+ VERSION = '0.4.0'
10
4
  end
11
5
  end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ldap/server/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ruby-ldapserver}
8
+ s.version = LDAP::Server::VERSION
9
+
10
+ s.authors = ["Brian Candler"]
11
+ s.description = %q{ruby-ldapserver is a lightweight, pure-Ruby skeleton for implementing LDAP server applications.}
12
+ s.email = %q{B.Candler@pobox.com}
13
+ s.files = `git ls-files`.split($/)
14
+ s.homepage = %q{https://github.com/inscitiv/ruby-ldapserver}
15
+ s.rdoc_options = ["--main", "README.txt"]
16
+ s.require_paths = ["lib"]
17
+ s.summary = %q{A pure-Ruby framework for building LDAP servers}
18
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
19
+
20
+ s.add_development_dependency 'bundler', '~> 1.3'
21
+ s.add_development_dependency 'rake', '~> 10.0'
22
+ end
metadata CHANGED
@@ -1,38 +1,59 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: ruby-ldapserver
3
- version: !ruby/object:Gem::Version
4
- version: 0.3.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ prerelease:
5
6
  platform: ruby
6
- authors:
7
+ authors:
7
8
  - Brian Candler
8
9
  autorequire:
9
10
  bindir: bin
10
11
  cert_chain: []
11
-
12
- date: 2008-01-16 00:00:00 -05:00
13
- default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: hoe
17
- version_requirement:
18
- version_requirements: !ruby/object:Gem::Requirement
19
- requirements:
20
- - - ">="
21
- - !ruby/object:Gem::Version
22
- version: 1.4.0
23
- version:
24
- description: ruby-ldapserver is a lightweight, pure-Ruby skeleton for implementing LDAP server applications.
12
+ date: 2013-03-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.3'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '1.3'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rake
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '10.0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '10.0'
46
+ description: ruby-ldapserver is a lightweight, pure-Ruby skeleton for implementing
47
+ LDAP server applications.
25
48
  email: B.Candler@pobox.com
26
49
  executables: []
27
-
28
50
  extensions: []
29
-
30
- extra_rdoc_files:
31
- - Manifest.txt
32
- files:
51
+ extra_rdoc_files: []
52
+ files:
53
+ - .gitignore
33
54
  - COPYING
34
55
  - ChangeLog
35
- - Manifest.txt
56
+ - Gemfile
36
57
  - README
37
58
  - Rakefile
38
59
  - examples/README
@@ -54,6 +75,7 @@ files:
54
75
  - lib/ldap/server/tcpserver.rb
55
76
  - lib/ldap/server/util.rb
56
77
  - lib/ldap/server/version.rb
78
+ - ruby-ldapserver.gemspec
57
79
  - test/core.schema
58
80
  - test/encoding_test.rb
59
81
  - test/filter_test.rb
@@ -62,37 +84,44 @@ files:
62
84
  - test/syntax_test.rb
63
85
  - test/test_helper.rb
64
86
  - test/util_test.rb
65
- has_rdoc: true
66
- homepage: http://rubyforge.org/projects/ruby-ldapserver
87
+ homepage: https://github.com/inscitiv/ruby-ldapserver
88
+ licenses: []
67
89
  post_install_message:
68
- rdoc_options:
90
+ rdoc_options:
69
91
  - --main
70
92
  - README.txt
71
- require_paths:
93
+ require_paths:
72
94
  - lib
73
- required_ruby_version: !ruby/object:Gem::Requirement
74
- requirements:
75
- - - ">="
76
- - !ruby/object:Gem::Version
77
- version: "0"
78
- version:
79
- required_rubygems_version: !ruby/object:Gem::Requirement
80
- requirements:
81
- - - ">="
82
- - !ruby/object:Gem::Version
83
- version: "0"
84
- version:
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ! '>='
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ segments:
102
+ - 0
103
+ hash: 2115768966675035117
104
+ required_rubygems_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ segments:
111
+ - 0
112
+ hash: 2115768966675035117
85
113
  requirements: []
86
-
87
- rubyforge_project: ruby-ldapserver
88
- rubygems_version: 1.0.1
114
+ rubyforge_project:
115
+ rubygems_version: 1.8.25
89
116
  signing_key:
90
- specification_version: 2
117
+ specification_version: 3
91
118
  summary: A pure-Ruby framework for building LDAP servers
92
- test_files:
119
+ test_files:
120
+ - test/core.schema
93
121
  - test/encoding_test.rb
94
122
  - test/filter_test.rb
95
123
  - test/match_test.rb
96
124
  - test/schema_test.rb
97
125
  - test/syntax_test.rb
126
+ - test/test_helper.rb
98
127
  - test/util_test.rb
data/Manifest.txt DELETED
@@ -1,32 +0,0 @@
1
- COPYING
2
- ChangeLog
3
- Manifest.txt
4
- README
5
- Rakefile
6
- examples/README
7
- examples/mkcert.rb
8
- examples/rbslapd1.rb
9
- examples/rbslapd2.rb
10
- examples/rbslapd3.rb
11
- examples/speedtest.rb
12
- lib/ldap/server.rb
13
- lib/ldap/server/connection.rb
14
- lib/ldap/server/filter.rb
15
- lib/ldap/server/match.rb
16
- lib/ldap/server/operation.rb
17
- lib/ldap/server/preforkserver.rb
18
- lib/ldap/server/result.rb
19
- lib/ldap/server/schema.rb
20
- lib/ldap/server/server.rb
21
- lib/ldap/server/syntax.rb
22
- lib/ldap/server/tcpserver.rb
23
- lib/ldap/server/util.rb
24
- lib/ldap/server/version.rb
25
- test/core.schema
26
- test/encoding_test.rb
27
- test/filter_test.rb
28
- test/match_test.rb
29
- test/schema_test.rb
30
- test/syntax_test.rb
31
- test/test_helper.rb
32
- test/util_test.rb