Class: LDAP::Server
- Inherits:
-
Object
- Object
- LDAP::Server
- Defined in:
- lib/ldap/server/version.rb,
lib/ldap/server/util.rb,
lib/ldap/server/match.rb,
lib/ldap/server/syntax.rb,
lib/ldap/server/filter.rb,
lib/ldap/server/server.rb,
lib/ldap/server/schema.rb,
lib/ldap/server/tcpserver.rb,
lib/ldap/server/operation.rb,
lib/ldap/server/connection.rb,
lib/ldap/server/preforkserver.rb
Overview
:nodoc:
Defined Under Namespace
Classes: Connection, Filter, MatchingRule, Operation, Schema, Syntax, VERSION
Constant Summary
- DEFAULT_OPT =
{ :port=>389, :nodelay=>true, }
- BaseObject =
Scope
0
- SingleLevel =
1
- WholeSubtree =
2
- NeverDerefAliases =
DerefAliases
0
- DerefInSearching =
1
- DerefFindingBaseObj =
2
- DerefAlways =
3
Instance Attribute Summary (collapse)
-
- (Object) root_dse
Returns the value of attribute root_dse.
Class Method Summary (collapse)
-
+ (Object) preforkserver(opt, &blk)
Accept connections on a port, and for each one run the given block in one of N pre-forked children.
-
+ (Object) ssl_prepare(opt)
create opt[:ssl_ctx] from the other ssl options.
-
+ (Object) tcpserver(opt, &blk)
Accept connections on a port, and for each one start a new thread and run the given block.
Instance Method Summary (collapse)
-
- (Server) initialize(opt = DEFAULT_OPT)
constructor
Create a new server.
- - (Object) join
- - (Object) run_prefork
- - (Object) run_tcpserver
- - (Object) stop
Constructor Details
- (Server) initialize(opt = DEFAULT_OPT)
Create a new server. Options include all those to tcpserver/preforkserver plus:
:operation_class=>Class - set Operation handler class :operation_args=>[...] - args to Operation.new :ssl_key_file=>pem, :ssl_cert_file=>pem - enable SSL :ssl_ca_path=>directory - verify peer certificates :schema=>Schema - Schema object :namingContexts=>[dn, ...] - base DN(s) we answer
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/ldap/server/server.rb', line 24 def initialize(opt = DEFAULT_OPT) @opt = opt @opt[:server] = self @opt[:operation_class] ||= LDAP::Server::Operation @opt[:operation_args] ||= [] LDAP::Server.ssl_prepare(@opt) @schema = opt[:schema] # may be nil @root_dse = Hash.new { |h,k| h[k] = [] }.merge({ 'objectClass' => ['top','openLDAProotDSE','extensibleObject'], 'supportedLDAPVersion' => ['3'], #'altServer' => #'supportedExtension' => #'supportedControl' => #'supportedSASLMechanisms' => }) @root_dse['subschemaSubentry'] = [@schema.subschema_dn] if @schema @root_dse['namingContexts'] = opt[:namingContexts] if opt[:namingContexts] end |
Instance Attribute Details
- (Object) root_dse
Returns the value of attribute root_dse
8 9 10 |
# File 'lib/ldap/server/server.rb', line 8 def root_dse @root_dse end |
Class Method Details
+ (Object) preforkserver(opt, &blk)
Accept connections on a port, and for each one run the given block in one of N pre-forked children. Returns a Thread object for the listener.
Options:
:port=>port number [required] :bindaddr=>"IP address" :user=>"username" - drop privileges after bind :group=>"groupname" - ditto :logger=>object - implements << method :listen=>number - listen queue depth :nodelay=>true - set TCP_NODELAY option :min_servers=>N - prefork parameters :max_servers=>N :max_requests_per_child=>N :max_idle=>N - seconds
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/ldap/server/preforkserver.rb', line 24 def self.preforkserver(opt, &blk) logger = opt[:logger] || $stderr server = PreFork.new(opt[:bindaddr] || "0.0.0.0", opt[:port]) # Drop privileges if requested if opt[:group] or opt[:user] require 'etc' gid = Etc.getgrnam(opt[:group]).gid if opt[:group] uid = Etc.getpwnam(opt[:user]).uid if opt[:user] File.chown(uid, gid, server.instance_eval {@lockf}) Process.gid = Process.egid = gid if gid Process.uid = Process.euid = uid if uid end # Typically the O/S will buffer response data for 100ms before sending. # If the response is sent as a single write() then there's no need for it. if opt[:nodelay] begin server.sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) rescue Exception end end # set queue size for incoming connections (default is 5) server.sock.listen(opt[:listen]) if opt[:listen] # Set prefork server parameters server.min_servers = opt[:min_servers] if opt[:min_servers] server.max_servers = opt[:max_servers] if opt[:max_servers] server.max_request_per_child = opt[:max_request_per_child] if opt[:max_request_per_child] server.max_idle = opt[:max_idle] if opt[:max_idle] Thread.new do server.start do |s| begin s.instance_eval(&blk) rescue Interrupt # This exception can be raised to shut the server down server.stop rescue Exception => e logger << "[#{s.peeraddr[3]}]: #{e}: #{e.backtrace[0]}\n" ensure s.close end end end end |
+ (Object) ssl_prepare(opt)
create opt[:ssl_ctx] from the other ssl options
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/ldap/server/server.rb', line 45 def self.ssl_prepare(opt) # :nodoc: if opt[:ssl_key_file] and opt[:ssl_cert_file] ctx = OpenSSL::SSL::SSLContext.new ctx.key = OpenSSL::PKey::RSA.new(File::read(opt[:ssl_key_file])) ctx.cert = OpenSSL::X509::Certificate.new(File::read(opt[:ssl_cert_file])) if opt[:ssl_ca_path] ctx.ca_path = opt[:ssl_ca_path] ctx.verify_mode = OpenSSL::SSL::VERIFY_PEER|OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT else $stderr.puts "Warning: SSL peer certificate won't be verified" end opt[:ssl_ctx] = ctx end end |
+ (Object) tcpserver(opt, &blk)
Accept connections on a port, and for each one start a new thread and run the given block. Returns the Thread object for the listener.
FIXME:
have a limit on total number of concurrent connects
have a limit on connections from a single IP, or from a /24 (to avoid the trivial DoS that the first limit creates)
ACL using source IP address (or perhaps that belongs in application)
Options:
:port=>port number [required] :bindaddr=>"IP address" :user=>"username" - drop privileges after bind :group=>"groupname" - ditto :logger=>object - implements << method :listen=>number - listen queue depth :nodelay=>true - set TCP_NODELAY option
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/ldap/server/tcpserver.rb', line 24 def self.tcpserver(opt, &blk) logger = opt[:logger] || $stderr server = TCPServer.new(opt[:bindaddr] || "0.0.0.0", opt[:port]) # Drop privileges if requested require 'etc' if opt[:group] or opt[:user] Process.gid = Process.egid = Etc.getgrnam(opt[:group]).gid if opt[:group] Process.uid = Process.euid = Etc.getpwnam(opt[:user]).uid if opt[:user] # Typically the O/S will buffer response data for 100ms before sending. # If the response is sent as a single write() then there's no need for it. if opt[:nodelay] begin server.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) rescue Exception end end # set queue size for incoming connections (default is 5) server.listen(opt[:listen]) if opt[:listen] Thread.new do while true begin session = server.accept # subtlety: copy 'session' into a block-local variable because # it will change when the next session is accepted Thread.new(session) do |s| begin s.instance_eval(&blk) rescue Exception => e logger << "[#{s.peeraddr[3]}]: #{e}: #{e.backtrace[0]}\n" #logger << "[#{s.peeraddr[3]}]: #{e}: #{e.backtrace.join("\n\tfrom ")}\n" ensure s.close end end rescue Interrupt # This exception can be raised to shut the server down server.close if server and not server.closed? break end end end end |
Instance Method Details
- (Object) join
79 80 81 |
# File 'lib/ldap/server/server.rb', line 79 def join @thread.join end |
- (Object) run_prefork
70 71 72 73 74 75 76 77 |
# File 'lib/ldap/server/server.rb', line 70 def run_prefork require 'ldap/server/preforkserver' opt = @opt @thread = LDAP::Server.preforkserver(@opt) do LDAP::Server::Connection::new(self,opt).handle_requests end end |
- (Object) run_tcpserver
61 62 63 64 65 66 67 68 |
# File 'lib/ldap/server/server.rb', line 61 def run_tcpserver require 'ldap/server/tcpserver' opt = @opt @thread = LDAP::Server.tcpserver(@opt) do LDAP::Server::Connection::new(self,opt).handle_requests end end |
- (Object) stop
83 84 85 86 |
# File 'lib/ldap/server/server.rb', line 83 def stop @thread.raise Interrupt, "" # <= temporary fix for 1.8.6 @thread.join end |