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,93 +0,0 @@
|
|
1
|
-
require 'prefork' # <http://raa.ruby-lang.org/project/prefork/>
|
2
|
-
require 'socket'
|
3
|
-
|
4
|
-
module LDAP
|
5
|
-
class Server
|
6
|
-
|
7
|
-
# Accept connections on a port, and for each one run the given block
|
8
|
-
# in one of N pre-forked children. Returns a Thread object for the
|
9
|
-
# listener.
|
10
|
-
#
|
11
|
-
# Options:
|
12
|
-
# :port=>port number [required]
|
13
|
-
# :bindaddr=>"IP address"
|
14
|
-
# :user=>"username" - drop privileges after bind
|
15
|
-
# :group=>"groupname" - ditto
|
16
|
-
# :logger=>object - implements << method
|
17
|
-
# :listen=>number - listen queue depth
|
18
|
-
# :nodelay=>true - set TCP_NODELAY option
|
19
|
-
# :min_servers=>N - prefork parameters
|
20
|
-
# :max_servers=>N
|
21
|
-
# :max_requests_per_child=>N
|
22
|
-
# :max_idle=>N - seconds
|
23
|
-
|
24
|
-
def self.preforkserver(opt, &blk)
|
25
|
-
logger = opt[:logger] || $stderr
|
26
|
-
server = PreFork.new(opt[:bindaddr] || "0.0.0.0", opt[:port])
|
27
|
-
|
28
|
-
# Drop privileges if requested
|
29
|
-
if opt[:group] or opt[:user]
|
30
|
-
require 'etc'
|
31
|
-
gid = Etc.getgrnam(opt[:group]).gid if opt[:group]
|
32
|
-
uid = Etc.getpwnam(opt[:user]).uid if opt[:user]
|
33
|
-
File.chown(uid, gid, server.instance_eval {@lockf})
|
34
|
-
Process.gid = Process.egid = gid if gid
|
35
|
-
Process.uid = Process.euid = uid if uid
|
36
|
-
end
|
37
|
-
|
38
|
-
# Typically the O/S will buffer response data for 100ms before sending.
|
39
|
-
# If the response is sent as a single write() then there's no need for it.
|
40
|
-
if opt[:nodelay]
|
41
|
-
begin
|
42
|
-
server.sock.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
43
|
-
rescue Exception
|
44
|
-
end
|
45
|
-
end
|
46
|
-
# set queue size for incoming connections (default is 5)
|
47
|
-
server.sock.listen(opt[:listen]) if opt[:listen]
|
48
|
-
|
49
|
-
# Set prefork server parameters
|
50
|
-
server.min_servers = opt[:min_servers] if opt[:min_servers]
|
51
|
-
server.max_servers = opt[:max_servers] if opt[:max_servers]
|
52
|
-
server.max_request_per_child = opt[:max_request_per_child] if opt[:max_request_per_child]
|
53
|
-
server.max_idle = opt[:max_idle] if opt[:max_idle]
|
54
|
-
|
55
|
-
Thread.new do
|
56
|
-
server.start do |s|
|
57
|
-
begin
|
58
|
-
s.instance_eval(&blk)
|
59
|
-
rescue Interrupt
|
60
|
-
# This exception can be raised to shut the server down
|
61
|
-
server.stop
|
62
|
-
rescue Exception => e
|
63
|
-
logger << "[#{s.peeraddr[3]}]: #{e}: #{e.backtrace[0]}\n"
|
64
|
-
ensure
|
65
|
-
s.close
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
end # class Server
|
72
|
-
end # module LDAP
|
73
|
-
|
74
|
-
if __FILE__ == $0
|
75
|
-
# simple test
|
76
|
-
puts "Running a test POP3 server on port 1110"
|
77
|
-
t = LDAP::Server.preforkserver(:port=>1110) do
|
78
|
-
print "+OK I am a fake POP3 server (pid #{$$})\r\n"
|
79
|
-
while line = gets
|
80
|
-
case line
|
81
|
-
when /^quit/i
|
82
|
-
break
|
83
|
-
when /^crash/i
|
84
|
-
raise Errno::EPERM, "dammit!"
|
85
|
-
else
|
86
|
-
print "-ERR I don't understand #{line}"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
print "+OK bye\r\n"
|
90
|
-
end
|
91
|
-
#sleep 10; t.raise Interrupt # uncomment to run for fixed time period
|
92
|
-
t.join
|
93
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
module LDAP
|
2
|
-
|
3
|
-
# compatible with ruby-ldap
|
4
|
-
class Error < StandardError
|
5
|
-
end
|
6
|
-
|
7
|
-
class ResultError < Error
|
8
|
-
end
|
9
|
-
|
10
|
-
# This exception is raised when we need to kill an existing Operation
|
11
|
-
# thread because of a received abandonRequest or bindRequest
|
12
|
-
class Abandon < Interrupt
|
13
|
-
end
|
14
|
-
|
15
|
-
# ResultError constants from RFC 2251 4.1.10; these are all exceptions
|
16
|
-
# which can be raised
|
17
|
-
|
18
|
-
class ResultError
|
19
|
-
class Success < self; def to_i; 0; end; end
|
20
|
-
class OperationsError < self; def to_i; 1; end; end
|
21
|
-
class ProtocolError < self; def to_i; 2; end; end
|
22
|
-
class TimeLimitExceeded < self; def to_i; 3; end; end
|
23
|
-
class SizeLimitExceeded < self; def to_i; 4; end; end
|
24
|
-
class CompareFalse < self; def to_i; 5; end; end
|
25
|
-
class CompareTrue < self; def to_i; 6; end; end
|
26
|
-
class AuthMethodNotSupported < self; def to_i; 7; end; end
|
27
|
-
class StrongAuthRequired < self; def to_i; 8; end; end
|
28
|
-
class Referral < self; def to_i; 10; end; end
|
29
|
-
class AdminLimitExceeded < self; def to_i; 11; end; end
|
30
|
-
class UnavailableCriticalExtension < self; def to_i; 12; end; end
|
31
|
-
class ConfidentialityRequired < self; def to_i; 13; end; end
|
32
|
-
class SaslBindInProgress < self; def to_i; 14; end; end
|
33
|
-
class NoSuchAttribute < self; def to_i; 16; end; end
|
34
|
-
class UndefinedAttributeType < self; def to_i; 17; end; end
|
35
|
-
class InappropriateMatching < self; def to_i; 18; end; end
|
36
|
-
class ConstraintViolation < self; def to_i; 19; end; end
|
37
|
-
class AttributeOrValueExists < self; def to_i; 20; end; end
|
38
|
-
class InvalidAttributeSyntax < self; def to_i; 21; end; end
|
39
|
-
class NoSuchObject < self; def to_i; 32; end; end
|
40
|
-
class AliasProblem < self; def to_i; 33; end; end
|
41
|
-
class InvalidDNSyntax < self; def to_i; 34; end; end
|
42
|
-
class IsLeaf < self; def to_i; 35; end; end
|
43
|
-
class AliasDereferencingProblem < self; def to_i; 36; end; end
|
44
|
-
class InappropriateAuthentication < self; def to_i; 48; end; end
|
45
|
-
class InvalidCredentials < self; def to_i; 49; end; end
|
46
|
-
class InsufficientAccessRights < self; def to_i; 50; end; end
|
47
|
-
class Busy < self; def to_i; 51; end; end
|
48
|
-
class Unavailable < self; def to_i; 52; end; end
|
49
|
-
class UnwillingToPerform < self; def to_i; 53; end; end
|
50
|
-
class LoopDetect < self; def to_i; 54; end; end
|
51
|
-
class NamingViolation < self; def to_i; 64; end; end
|
52
|
-
class ObjectClassViolation < self; def to_i; 65; end; end
|
53
|
-
class NotAllowedOnNonLeaf < self; def to_i; 66; end; end
|
54
|
-
class NotAllowedOnRDN < self; def to_i; 67; end; end
|
55
|
-
class EntryAlreadyExists < self; def to_i; 68; end; end
|
56
|
-
class ObjectClassModsProhibited < self; def to_i; 69; end; end
|
57
|
-
class AffectsMultipleDSAs < self; def to_i; 71; end; end
|
58
|
-
class Other < self; def to_i; 80; end; end
|
59
|
-
|
60
|
-
# Reverse lookup: so you can do raise LDAP::ResultError[53]
|
61
|
-
|
62
|
-
N_TO_CLASS = {
|
63
|
-
53 => UnwillingToPerform,
|
64
|
-
# FIXME: please fill in the rest
|
65
|
-
}
|
66
|
-
def self.[] (n)
|
67
|
-
return N_TO_CLASS[n] || self
|
68
|
-
end
|
69
|
-
end # class ResultError
|
70
|
-
|
71
|
-
end # module LDAP
|
@@ -1,592 +0,0 @@
|
|
1
|
-
require 'ldap/server/syntax'
|
2
|
-
require 'ldap/server/result'
|
3
|
-
|
4
|
-
module LDAP
|
5
|
-
class Server
|
6
|
-
|
7
|
-
# This object represents an LDAP schema: that is, a collection of
|
8
|
-
# objectclasses and attributetypes. Methods are provided for loading
|
9
|
-
# the schema (from a string or a disk file), and validating an av-hash
|
10
|
-
# against it.
|
11
|
-
|
12
|
-
class Schema
|
13
|
-
|
14
|
-
SUBSCHEMA_ENTRY_ATTR = 'cn'
|
15
|
-
SUBSCHEMA_ENTRY_VALUE = 'Subschema'
|
16
|
-
|
17
|
-
def initialize
|
18
|
-
@attrtypes = {} # name/alias/oid => AttributeType instance
|
19
|
-
@objectclasses = {} # name/alias/oid => ObjectClass instance
|
20
|
-
@subschema_cache = nil
|
21
|
-
end
|
22
|
-
|
23
|
-
# return the DN of the subschema subentry
|
24
|
-
|
25
|
-
def subschema_dn
|
26
|
-
"#{SUBSCHEMA_ENTRY_ATTR}=#{SUBSCHEMA_ENTRY_VALUE}"
|
27
|
-
end
|
28
|
-
|
29
|
-
# Return an av hash object giving the subschema subentry. This is cached, so
|
30
|
-
# call Schema#changed if it needs to be rebuilt
|
31
|
-
|
32
|
-
def subschema_subentry
|
33
|
-
@subschema_cache ||= {
|
34
|
-
'objectClass' => ['top','subschema','extensibleObject'],
|
35
|
-
SUBSCHEMA_ENTRY_ATTR => [SUBSCHEMA_ENTRY_VALUE],
|
36
|
-
'objectClasses' => all_objectclasses.collect { |s| s.to_def },
|
37
|
-
'attributeTypes' => all_attrtypes.collect { |s| s.to_def },
|
38
|
-
'ldapSyntaxes' => LDAP::Server::Syntax.all_syntaxes.collect { |s| s.to_def },
|
39
|
-
#'matchingRules' =>
|
40
|
-
#'matchingRuleUse' =>
|
41
|
-
}
|
42
|
-
end
|
43
|
-
|
44
|
-
# Clear the subschema subentry cache, so the next time someone requests
|
45
|
-
# it, it will be rebuilt
|
46
|
-
|
47
|
-
def changed
|
48
|
-
@subschema_cache = nil
|
49
|
-
end
|
50
|
-
|
51
|
-
# Add an AttributeType to the schema
|
52
|
-
|
53
|
-
def add_attrtype(str)
|
54
|
-
a = AttributeType.new(str)
|
55
|
-
@attrtypes[a.oid] = a if a.oid
|
56
|
-
a.names.each do |n|
|
57
|
-
@attrtypes[n.downcase] = a
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# Locate an attributetype object by name/alias/oid (or raise exception)
|
62
|
-
|
63
|
-
def find_attrtype(n)
|
64
|
-
return n if n.nil? or n.is_a?(LDAP::Server::Schema::AttributeType)
|
65
|
-
r = @attrtypes[n.downcase]
|
66
|
-
raise LDAP::ResultError::UndefinedAttributeType, "Unknown AttributeType #{n.inspect}" unless r
|
67
|
-
r
|
68
|
-
end
|
69
|
-
|
70
|
-
# Return array of all AttributeType objects in this schema
|
71
|
-
|
72
|
-
def all_attrtypes
|
73
|
-
@attrtypes.values.uniq
|
74
|
-
end
|
75
|
-
|
76
|
-
# Add an ObjectClass to the schema
|
77
|
-
|
78
|
-
def add_objectclass(str)
|
79
|
-
o = ObjectClass.new(str)
|
80
|
-
@objectclasses[o.oid] = o if o.oid
|
81
|
-
o.names.each do |n|
|
82
|
-
@objectclasses[n.downcase] = o
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# Locate an objectclass object by name/alias/oid (or raise exception)
|
87
|
-
|
88
|
-
def find_objectclass(n)
|
89
|
-
return n if n.nil? or n.is_a?(LDAP::Server::Schema::ObjectClass)
|
90
|
-
r = @objectclasses[n.downcase]
|
91
|
-
raise LDAP::ResultError::ObjectClassViolation, "Unknown ObjectClass #{n.inspect}" unless r
|
92
|
-
r
|
93
|
-
end
|
94
|
-
|
95
|
-
# Return array of all ObjectClass objects in this schema
|
96
|
-
|
97
|
-
def all_objectclasses
|
98
|
-
@objectclasses.values.uniq
|
99
|
-
end
|
100
|
-
|
101
|
-
# Load an OpenLDAP-format schema from a named file (see notes under 'load')
|
102
|
-
|
103
|
-
def load_file(filename)
|
104
|
-
File.open(filename) { |f| load(f) }
|
105
|
-
end
|
106
|
-
|
107
|
-
# Load an OpenLDAP-format schema from a string or IO object (anything
|
108
|
-
# which responds to 'each_line'). Lines starting 'attributetype'
|
109
|
-
# or 'objectclass' contain one of those objects. Does not implement
|
110
|
-
# named objectIdentifier prefixes (used in the dyngroup.schema file
|
111
|
-
# supplied with openldap, but not documented in RFC2252)
|
112
|
-
#
|
113
|
-
# Note: RFC2252 is strict about the order in which the elements appear,
|
114
|
-
# and so are we, but OpenLDAP is not. This means that a schema which
|
115
|
-
# works in OpenLDAP might not load here. For example, RFC2252 says
|
116
|
-
# that in an objectclass description, "SUP" must come before "MAY";
|
117
|
-
# if they are the other way round, our regexp-based parser will not
|
118
|
-
# accept it. The solution is simply to modify the definition so that
|
119
|
-
# the elements appear in the correct order.
|
120
|
-
|
121
|
-
def load(str_or_io)
|
122
|
-
meth = :junk_line
|
123
|
-
data = ""
|
124
|
-
str_or_io.each_line do |line|
|
125
|
-
case line
|
126
|
-
when /^\s*#/, /^\s*$/
|
127
|
-
next
|
128
|
-
when /^objectclass\s*(.*)$/i
|
129
|
-
m = $~
|
130
|
-
send(meth, data)
|
131
|
-
meth, data = :add_objectclass, m[1]
|
132
|
-
when /^attributetype\s*(.*)$/i
|
133
|
-
m = $~
|
134
|
-
send(meth, data)
|
135
|
-
meth, data = :add_attrtype, m[1]
|
136
|
-
else
|
137
|
-
data << line
|
138
|
-
end
|
139
|
-
end
|
140
|
-
send(meth,data)
|
141
|
-
self
|
142
|
-
end
|
143
|
-
|
144
|
-
def junk_line(data)
|
145
|
-
return if data.empty?
|
146
|
-
raise LDAP::ResultError::InvalidAttributeSyntax,
|
147
|
-
"Expected 'attributetype' or 'objectclass', got #{data}"
|
148
|
-
end
|
149
|
-
private :junk_line
|
150
|
-
|
151
|
-
# Load in the base set of objectclasses and attributetypes, being
|
152
|
-
# the same set as OpenLDAP preloads internally. Includes objectclasses
|
153
|
-
# 'top', 'objectclass'; attributetypes 'objectclass' , 'cn',
|
154
|
-
# 'userPassword' and 'distinguishedName'; common operational attributes
|
155
|
-
# such as 'modifyTimestamp'; plus extras needed for publishing a v3
|
156
|
-
# schema via LDAP
|
157
|
-
|
158
|
-
def load_system
|
159
|
-
load(<<EOS)
|
160
|
-
attributetype ( 1.3.6.1.4.1.250.1.57 NAME 'labeledURI' DESC 'RFC2079: Uniform Resource Identifier with optional label' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
|
161
|
-
attributetype ( 2.5.4.35 NAME 'userPassword' DESC 'RFC2256/2307: password of user' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} )
|
162
|
-
attributetype ( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'RFC2256: common name(s) for which the entity is known by' SUP name )
|
163
|
-
attributetype ( 2.5.4.41 NAME 'name' DESC 'RFC2256: common supertype of name attributes' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
|
164
|
-
attributetype ( 2.5.4.49 NAME 'distinguishedName' DESC 'RFC2256: common supertype of DN attributes' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )
|
165
|
-
attributetype ( 2.16.840.1.113730.3.1.34 NAME 'ref' DESC 'namedref: subordinate referral URL' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE distributedOperation )
|
166
|
-
attributetype ( 2.5.4.1 NAME ( 'aliasedObjectName' 'aliasedEntryName' ) DESC 'RFC2256: name of aliased object' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE )
|
167
|
-
attributetype ( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes' DESC 'RFC2252: LDAP syntaxes' EQUALITY objectIdentifierFirstComponentMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.54 USAGE directoryOperation )
|
168
|
-
attributetype ( 2.5.21.8 NAME 'matchingRuleUse' DESC 'RFC2252: matching rule uses' EQUALITY objectIdentifierFirstComponentMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.31 USAGE directoryOperation )
|
169
|
-
attributetype ( 2.5.21.6 NAME 'objectClasses' DESC 'RFC2252: object classes' EQUALITY objectIdentifierFirstComponentMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.37 USAGE directoryOperation )
|
170
|
-
attributetype ( 2.5.21.5 NAME 'attributeTypes' DESC 'RFC2252: attribute types' EQUALITY objectIdentifierFirstComponentMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.3 USAGE directoryOperation )
|
171
|
-
attributetype ( 2.5.21.4 NAME 'matchingRules' DESC 'RFC2252: matching rules' EQUALITY objectIdentifierFirstComponentMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.30 USAGE directoryOperation )
|
172
|
-
attributetype ( 1.3.6.1.1.5 NAME 'vendorVersion' DESC 'RFC3045: version of implementation' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )
|
173
|
-
attributetype ( 1.3.6.1.1.4 NAME 'vendorName' DESC 'RFC3045: name of implementation vendor' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation )
|
174
|
-
attributetype ( 1.3.6.1.4.1.4203.1.3.5 NAME 'supportedFeatures' DESC 'features supported by the server' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )
|
175
|
-
attributetype ( 1.3.6.1.4.1.1466.101.120.14 NAME 'supportedSASLMechanisms' DESC 'RFC2252: supported SASL mechanisms' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE dSAOperation )
|
176
|
-
attributetype ( 1.3.6.1.4.1.1466.101.120.15 NAME 'supportedLDAPVersion' DESC 'RFC2252: supported LDAP versions' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 USAGE dSAOperation )
|
177
|
-
attributetype ( 1.3.6.1.4.1.1466.101.120.7 NAME 'supportedExtension' DESC 'RFC2252: supported extended operations' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )
|
178
|
-
attributetype ( 1.3.6.1.4.1.1466.101.120.13 NAME 'supportedControl' DESC 'RFC2252: supported controls' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )
|
179
|
-
attributetype ( 1.3.6.1.4.1.1466.101.120.5 NAME 'namingContexts' DESC 'RFC2252: naming contexts' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 USAGE dSAOperation )
|
180
|
-
attributetype ( 1.3.6.1.4.1.1466.101.120.6 NAME 'altServer' DESC 'RFC2252: alternative servers' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 USAGE dSAOperation )
|
181
|
-
attributetype ( 2.5.18.10 NAME 'subschemaSubentry' DESC 'RFC2252: name of controlling subschema entry' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
|
182
|
-
attributetype ( 2.5.18.9 NAME 'hasSubordinates' DESC 'X.501: entry has children' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
|
183
|
-
attributetype ( 2.5.18.4 NAME 'modifiersName' DESC 'RFC2252: name of last modifier' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
|
184
|
-
attributetype ( 2.5.18.3 NAME 'creatorsName' DESC 'RFC2252: name of creator' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
|
185
|
-
attributetype ( 2.5.18.2 NAME 'modifyTimestamp' DESC 'RFC2252: time which object was last modified' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
|
186
|
-
attributetype ( 2.5.18.1 NAME 'createTimestamp' DESC 'RFC2252: time which object was created' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
|
187
|
-
attributetype ( 2.5.21.9 NAME 'structuralObjectClass' DESC 'X.500(93): structural object class of entry' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation )
|
188
|
-
attributetype ( 2.5.4.0 NAME 'objectClass' DESC 'RFC2256: object classes of the entity' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )
|
189
|
-
# These ones aren't published by OpenLDAP, but are referenced by the 'subschema' objectclass
|
190
|
-
attributetype ( 2.5.21.1 NAME 'dITStructureRules' EQUALITY integerFirstComponentMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.17 USAGE directoryOperation )
|
191
|
-
attributetype ( 2.5.21.7 NAME 'nameForms' EQUALITY objectIdentifierFirstComponentMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.35 USAGE directoryOperation )
|
192
|
-
attributetype ( 2.5.21.2 NAME 'dITContentRules' EQUALITY objectIdentifierFirstComponentMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.16 USAGE directoryOperation )
|
193
|
-
|
194
|
-
objectclass ( 2.5.20.1 NAME 'subschema' DESC 'RFC2252: controlling subschema (sub)entry' AUXILIARY MAY ( dITStructureRules $ nameForms $ ditContentRules $ objectClasses $ attributeTypes $ matchingRules $ matchingRuleUse ) )
|
195
|
-
#Don't have definition for subtreeSpecification:
|
196
|
-
#objectClass ( 2.5.17.0 NAME 'subentry' SUP top STRUCTURAL MUST ( cn $ subtreeSpecification ) )
|
197
|
-
objectClass ( 1.3.6.1.4.1.4203.1.4.1 NAME ( 'OpenLDAProotDSE' 'LDAProotDSE' ) DESC 'OpenLDAP Root DSE object' SUP top STRUCTURAL MAY cn )
|
198
|
-
objectClass ( 2.16.840.1.113730.3.2.6 NAME 'referral' DESC 'namedref: named subordinate referral' SUP top STRUCTURAL MUST ref )
|
199
|
-
objectClass ( 2.5.6.1 NAME 'alias' DESC 'RFC2256: an alias' SUP top STRUCTURAL MUST aliasedObjectName )
|
200
|
-
objectClass ( 1.3.6.1.4.1.1466.101.120.111 NAME 'extensibleObject' DESC 'RFC2252: extensible object' SUP top AUXILIARY )
|
201
|
-
objectClass ( 2.5.6.0 NAME 'top' DESC 'top of the superclass chain' ABSTRACT MUST objectClass )
|
202
|
-
EOS
|
203
|
-
end
|
204
|
-
|
205
|
-
# After loading object classes and attr types: resolve oid strings to point
|
206
|
-
# to objects. This will expose schema inconsistencies (e.g. objectclass
|
207
|
-
# has unknown SUP class or points to unknown attributeType). However,
|
208
|
-
# unknown Syntaxes just create new Syntax objects.
|
209
|
-
|
210
|
-
def resolve_oids
|
211
|
-
|
212
|
-
all_attrtypes.each do |a|
|
213
|
-
if a.sup
|
214
|
-
s = find_attrtype(a.sup)
|
215
|
-
a.instance_eval {
|
216
|
-
@sup = s
|
217
|
-
# inherit properties (FIXME: This breaks to_def)
|
218
|
-
@equality ||= s.equality
|
219
|
-
@ordering ||= s.ordering
|
220
|
-
@substr ||= s.substr
|
221
|
-
@syntax ||= s.syntax
|
222
|
-
@maxlen ||= s.maxlen
|
223
|
-
@singlevalue ||= s.singlevalue
|
224
|
-
@collective ||= s.collective
|
225
|
-
@nousermod ||= s.nousermod
|
226
|
-
@usage ||= s.usage
|
227
|
-
}
|
228
|
-
end
|
229
|
-
a.instance_eval do
|
230
|
-
@syntax = LDAP::Server::Syntax.find(@syntax) if @syntax
|
231
|
-
@equality = LDAP::Server::MatchingRule.find(@equality) if @equality
|
232
|
-
@ordering = LDAP::Server::MatchingRule.find(@ordering) if @ordering
|
233
|
-
@substr = LDAP::Server::MatchingRule.find(@substr) if @substr
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
all_objectclasses.each do |o|
|
238
|
-
if o.sup
|
239
|
-
s = o.sup.collect { |ss| find_objectclass(ss) }
|
240
|
-
o.instance_eval { @sup = s }
|
241
|
-
end
|
242
|
-
if o.must
|
243
|
-
s = o.must.collect { |ss| find_attrtype(ss) }
|
244
|
-
o.instance_eval { @must = s }
|
245
|
-
end
|
246
|
-
if o.may
|
247
|
-
s = o.may.collect { |ss| find_attrtype(ss) }
|
248
|
-
o.instance_eval { @may = s }
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
end
|
253
|
-
|
254
|
-
# Validate a new entry or update. For a new entry, just pass a hash
|
255
|
-
# of attr=>[val, val, ...]; for an update, the first parameter is
|
256
|
-
# a hash of attr=>[:modtype, val, val...] and the second parameter
|
257
|
-
# is the existing entry, where it is assumed that the attribute names
|
258
|
-
# are already in their standard string forms (as returned by attr#name)
|
259
|
-
#
|
260
|
-
# Returns a hash containing the updated entry.
|
261
|
-
#
|
262
|
-
# If a block is given, it is called to decide whether the user is
|
263
|
-
# allowed to update an attribute; parameter is the attr *object*
|
264
|
-
# (not name; use #name if you need its name instead). Return false
|
265
|
-
# if the update is not permitted. Otherwise, the only restriction
|
266
|
-
# will be that updates to attributes declared 'nousermod' are forbidden.
|
267
|
-
#
|
268
|
-
# No DN checks are done here, since we don't know the DN.
|
269
|
-
# Checking that the entry contains an attribute for the RDN is the
|
270
|
-
# responsibility of the caller.
|
271
|
-
|
272
|
-
def validate(mods, entry={})
|
273
|
-
|
274
|
-
# Run through the mods, make the normalized names, and perform any
|
275
|
-
# updates
|
276
|
-
|
277
|
-
# FIXME: I don't know if these are the right results to return
|
278
|
-
# for the various types of validation errors
|
279
|
-
|
280
|
-
oc_changed = false
|
281
|
-
res = entry.dup
|
282
|
-
mods.each do |attrname, nv|
|
283
|
-
attr = find_attrtype(attrname)
|
284
|
-
attrname = attr.to_s
|
285
|
-
raise LDAP::ResultError::ConstraintViolation,
|
286
|
-
"Cannot modify #{attrname}" if attr.nousermod or
|
287
|
-
(block_given? and !yield(attr))
|
288
|
-
# Perform the update
|
289
|
-
vals = res[attrname] || []
|
290
|
-
checkvals = []
|
291
|
-
nv = [nv] unless nv.is_a?(Array)
|
292
|
-
|
293
|
-
case nv.first
|
294
|
-
when :add
|
295
|
-
checkvals = nv[1..-1]
|
296
|
-
vals += checkvals
|
297
|
-
vals.uniq! # FIXME: ?? error if duplicate values
|
298
|
-
# FIXME: normalize values? e.g. c: gb and c: GB are same value.
|
299
|
-
when :delete
|
300
|
-
nv = nv[1..-1]
|
301
|
-
if nv.empty?
|
302
|
-
vals = [] # ?? error if does not exist
|
303
|
-
else
|
304
|
-
nv.each { |v| vals.delete(v) } # ?? error if value missing
|
305
|
-
end
|
306
|
-
when :replace
|
307
|
-
vals = checkvals = nv[1..-1]
|
308
|
-
else
|
309
|
-
vals = checkvals = nv
|
310
|
-
end
|
311
|
-
if vals == []
|
312
|
-
res.delete(attrname)
|
313
|
-
else
|
314
|
-
res[attrname] = vals
|
315
|
-
end
|
316
|
-
|
317
|
-
# Attribute validation
|
318
|
-
raise LDAP::ResultError::ObjectClassViolation,
|
319
|
-
"Attribute #{attr} is SINGLE-VALUE" if attr.singlevalue and vals.size > 1
|
320
|
-
|
321
|
-
checkvals.each do |val|
|
322
|
-
raise LDAP::ResultError::InvalidAttributeSyntax,
|
323
|
-
"Nil or empty value for attribute #{attr}" if val.nil? or val.empty?
|
324
|
-
raise LDAP::ResultError::InvalidAttributeSyntax,
|
325
|
-
"Bad value for #{attr}: #{val.inspect}" if attr.syntax and ! attr.syntax.match(val)
|
326
|
-
raise LDAP::ResultError::InvalidAttributeSyntax,
|
327
|
-
"Value too long for #{attr} (max #{attr.maxlen})" if attr.maxlen and val.length > attr.maxlen
|
328
|
-
end
|
329
|
-
|
330
|
-
oc_changed = true if attrname == 'objectClass'
|
331
|
-
end
|
332
|
-
|
333
|
-
# Now do objectClass checks
|
334
|
-
oc = res['objectClass']
|
335
|
-
unless oc
|
336
|
-
raise LDAP::ResultError::ObjectClassViolation,
|
337
|
-
"objectClass attribute missing"
|
338
|
-
end
|
339
|
-
oc = oc.collect { |val| find_objectclass(val) }
|
340
|
-
|
341
|
-
if oc_changed
|
342
|
-
# Add superior objectClasses (note: growing an array while you
|
343
|
-
# iterate over it seems to work, in ruby-1.8.2 anyway!)
|
344
|
-
oc.each do |objectclass|
|
345
|
-
objectclass.sup.each do |s|
|
346
|
-
oc.push(s) unless oc.include?(s)
|
347
|
-
end
|
348
|
-
end
|
349
|
-
res['objectClass'] = oc.collect { |oo| oo.to_s }
|
350
|
-
|
351
|
-
# Check that exactly one structural objectClass is present
|
352
|
-
unless oc.find_all { |s| s.struct == :structural }.size >= 1
|
353
|
-
raise LDAP::ResultError::ObjectClassViolation,
|
354
|
-
"Entry must have at least one structural objectClass"
|
355
|
-
# Exactly one? But you have to sort out the inheritance problem
|
356
|
-
# (e.g. both person and organizationalPerson are declared
|
357
|
-
# structural)
|
358
|
-
end
|
359
|
-
end
|
360
|
-
|
361
|
-
# Ensure that all MUST attributes are present
|
362
|
-
allow_attr = {}
|
363
|
-
oc.each do |objectclass|
|
364
|
-
objectclass.must.each do |m|
|
365
|
-
unless res[m.name] and res[m.name] != []
|
366
|
-
raise LDAP::ResultError::ObjectClassViolation, "Missing attribute #{m} required by objectClass #{objectclass}"
|
367
|
-
end
|
368
|
-
allow_attr[m.name] = true
|
369
|
-
end
|
370
|
-
objectclass.may.each do |m|
|
371
|
-
allow_attr[m.name] = true
|
372
|
-
end
|
373
|
-
end
|
374
|
-
|
375
|
-
unless oc.find { |objectclass| objectclass.name == 'extensibleObject' }
|
376
|
-
# Now check all the attributes given are permitted by MUST or MAY
|
377
|
-
res.each_key do |attr|
|
378
|
-
unless allow_attr[attr] or find_attrtype(attr).usage == :directoryOperation
|
379
|
-
raise LDAP::ResultError::ObjectClassViolation, "Attribute #{attr} not permitted by objectClass"
|
380
|
-
end
|
381
|
-
end
|
382
|
-
end
|
383
|
-
|
384
|
-
return res
|
385
|
-
end
|
386
|
-
|
387
|
-
# Hopefully backwards-compatible API for ruby-ldap's LDAP::Schema.
|
388
|
-
# Since MUST/MAY/SUP may point to schema objects, convert them back
|
389
|
-
# to strings.
|
390
|
-
|
391
|
-
def names(key)
|
392
|
-
case key
|
393
|
-
when 'objectClasses'
|
394
|
-
return all_objectclasses.collect { |e| e.name }
|
395
|
-
when 'attributeTypes'
|
396
|
-
return all_attrtypes.collect { |e| e.name }
|
397
|
-
when 'ldapSyntaxes'
|
398
|
-
return LDAP::Server::Syntax.all_syntaxes.collect { |e| e.name }
|
399
|
-
when 'matchingRules'
|
400
|
-
return LDAP::Server::MatchingRule.all_matching_rules.collect { |e| e.name }
|
401
|
-
# TODO: matchingRuleUse
|
402
|
-
end
|
403
|
-
return nil
|
404
|
-
end
|
405
|
-
|
406
|
-
# Backwards-compatible for ruby-ldap LDAP::Schema
|
407
|
-
|
408
|
-
def attr(oc,at)
|
409
|
-
o = find_objectclass(oc)
|
410
|
-
case at.upcase
|
411
|
-
when 'MUST'
|
412
|
-
return o.must.collect { |e| e.to_s }
|
413
|
-
when 'MAY'
|
414
|
-
return o.may.collect { |e| e.to_s }
|
415
|
-
when 'SUP'
|
416
|
-
return o.sup.collect { |e| e.to_s }
|
417
|
-
when 'NAME'
|
418
|
-
return o.names.collect { |e| e.to_s }
|
419
|
-
when 'DESC'
|
420
|
-
return [o.desc]
|
421
|
-
end
|
422
|
-
return nil
|
423
|
-
rescue LDAP::ResultError
|
424
|
-
return nil
|
425
|
-
end
|
426
|
-
|
427
|
-
# Backwards-compatible for ruby-ldap LDAP::Schema
|
428
|
-
|
429
|
-
def must(oc)
|
430
|
-
attr(oc, "MUST")
|
431
|
-
end
|
432
|
-
|
433
|
-
# Backwards-compatible for ruby-ldap LDAP::Schema
|
434
|
-
|
435
|
-
def may(oc)
|
436
|
-
attr(oc, "MAY")
|
437
|
-
end
|
438
|
-
|
439
|
-
# Backwards-compatible for ruby-ldap LDAP::Schema
|
440
|
-
|
441
|
-
def sup(oc)
|
442
|
-
attr(oc, "SUP")
|
443
|
-
end
|
444
|
-
|
445
|
-
#####################################################################
|
446
|
-
|
447
|
-
# Class holding an instance of an AttributeTypeDescription (RFC2252 4.2)
|
448
|
-
|
449
|
-
class AttributeType
|
450
|
-
|
451
|
-
attr_reader :oid, :names, :desc, :obsolete, :sup, :equality, :ordering
|
452
|
-
attr_reader :substr, :syntax, :maxlen, :singlevalue, :collective
|
453
|
-
attr_reader :nousermod, :usage
|
454
|
-
|
455
|
-
def initialize(str)
|
456
|
-
m = LDAP::Server::Syntax::AttributeTypeDescription.match(str)
|
457
|
-
raise LDAP::ResultError::InvalidAttributeSyntax,
|
458
|
-
"Bad AttributeTypeDescription #{str.inspect}" unless m
|
459
|
-
@oid = m[1]
|
460
|
-
@names = (m[2]||"").scan(/'(.*?)'/).flatten
|
461
|
-
@desc = m[3]
|
462
|
-
@obsolete = ! m[4].nil?
|
463
|
-
@sup = m[5]
|
464
|
-
@equality = m[6]
|
465
|
-
@ordering = m[7]
|
466
|
-
@substr = m[8]
|
467
|
-
@syntax = m[9]
|
468
|
-
@maxlen = m[10] && m[10].to_i
|
469
|
-
@singlevalue = ! m[11].nil?
|
470
|
-
@collective = ! m[12].nil?
|
471
|
-
@nousermod = ! m[13].nil?
|
472
|
-
@usage = m[14] && m[14].intern
|
473
|
-
# This is the cache of the stringified version. Rather than
|
474
|
-
# initialize to str, we set nil to force it to be rebuilt
|
475
|
-
@def = nil
|
476
|
-
end
|
477
|
-
|
478
|
-
def name
|
479
|
-
@names.first
|
480
|
-
end
|
481
|
-
|
482
|
-
def to_s
|
483
|
-
(@names && @names.first) || @oid
|
484
|
-
end
|
485
|
-
|
486
|
-
def changed
|
487
|
-
@def = nil
|
488
|
-
end
|
489
|
-
|
490
|
-
def to_def
|
491
|
-
return @def if @def
|
492
|
-
ans = "( #{@oid} "
|
493
|
-
if @names.nil? or @names.empty?
|
494
|
-
# nothing
|
495
|
-
elsif @names.size == 1
|
496
|
-
ans << "NAME '#{@names.first}' "
|
497
|
-
else
|
498
|
-
ans << "NAME ( "
|
499
|
-
@names.each { |n| ans << "'#{n}' " }
|
500
|
-
ans << ") "
|
501
|
-
end
|
502
|
-
ans << "DESC '#{@desc}' " if @desc
|
503
|
-
ans << "OBSOLETE " if @obsolete
|
504
|
-
ans << "SUP #{@sup} " if @sup # oid
|
505
|
-
ans << "EQUALITY #{@equality} " if @equality # oid
|
506
|
-
ans << "ORDERING #{@ordering} " if @ordering # oid
|
507
|
-
ans << "SUBSTR #{@substr} " if @substr # oid
|
508
|
-
ans << "SYNTAX #{@syntax}#{@maxlen && "{#{@maxlen}}"} " if @syntax
|
509
|
-
ans << "SINGLE-VALUE " if @singlevalue
|
510
|
-
ans << "COLLECTIVE " if @collective
|
511
|
-
ans << "NO-USER-MODIFICATION " if @nousermod
|
512
|
-
ans << "USAGE #{@usage} " if @usage
|
513
|
-
ans << ")"
|
514
|
-
@def = ans
|
515
|
-
end
|
516
|
-
end # class AttributeType
|
517
|
-
|
518
|
-
#####################################################################
|
519
|
-
|
520
|
-
# Class holding an instance of an ObjectClassDescription (RFC2252 4.4)
|
521
|
-
|
522
|
-
class ObjectClass
|
523
|
-
|
524
|
-
attr_reader :oid, :names, :desc, :obsolete, :sup, :struct, :must, :may
|
525
|
-
|
526
|
-
SCAN_WOID = /#{LDAP::Server::Syntax::WOID}/x
|
527
|
-
|
528
|
-
def initialize(str)
|
529
|
-
m = LDAP::Server::Syntax::ObjectClassDescription.match(str)
|
530
|
-
raise LDAP::ResultError::InvalidAttributeSyntax,
|
531
|
-
"Bad ObjectClassDescription #{str.inspect}" unless m
|
532
|
-
@oid = m[1]
|
533
|
-
@names = (m[2]||"").scan(/'(.*?)'/).flatten
|
534
|
-
@desc = m[3]
|
535
|
-
@obsolete = ! m[4].nil?
|
536
|
-
@sup = (m[5]||"").scan(SCAN_WOID).flatten
|
537
|
-
@struct = m[6] ? m[6].downcase.intern : :structural
|
538
|
-
@must = (m[7]||"").scan(SCAN_WOID).flatten
|
539
|
-
@may = (m[8]||"").scan(SCAN_WOID).flatten
|
540
|
-
@def = nil
|
541
|
-
end
|
542
|
-
|
543
|
-
def name
|
544
|
-
@names.first
|
545
|
-
end
|
546
|
-
|
547
|
-
def to_s
|
548
|
-
(@names && @names.first) || @oid
|
549
|
-
end
|
550
|
-
|
551
|
-
def changed
|
552
|
-
@def = nil
|
553
|
-
end
|
554
|
-
|
555
|
-
def to_def
|
556
|
-
return @def if @def
|
557
|
-
ans = "( #{@oid} "
|
558
|
-
if @names.nil? or @names.empty?
|
559
|
-
# nothing
|
560
|
-
elsif @names.size == 1
|
561
|
-
ans << "NAME '#{@names.first}' "
|
562
|
-
else
|
563
|
-
ans << "NAME ( "
|
564
|
-
@names.each { |n| ans << "'#{n}' " }
|
565
|
-
ans << ") "
|
566
|
-
end
|
567
|
-
ans << "DESC '#{@desc}' " if @desc
|
568
|
-
ans << "OBSOLETE " if @obsolete
|
569
|
-
ans << joinoids("SUP ",@sup," ")
|
570
|
-
ans << "#{@struct.to_s.upcase} " if @struct
|
571
|
-
ans << joinoids("MUST ",@must," ")
|
572
|
-
ans << joinoids("MAY ",@may," ")
|
573
|
-
ans << ")"
|
574
|
-
@def = ans
|
575
|
-
end
|
576
|
-
|
577
|
-
def joinoids(pfx,arr,sfx)
|
578
|
-
return "" unless arr and !arr.empty?
|
579
|
-
return "#{pfx}#{arr}#{sfx}" unless arr.is_a?(Array)
|
580
|
-
a = arr.collect { |elem| elem.to_s }
|
581
|
-
if a.size == 1
|
582
|
-
return "#{pfx}#{a.first}#{sfx}"
|
583
|
-
else
|
584
|
-
return "#{pfx}( #{a.join(" $ ")} )#{sfx}"
|
585
|
-
end
|
586
|
-
end
|
587
|
-
end # class ObjectClass
|
588
|
-
|
589
|
-
end # class Schema
|
590
|
-
|
591
|
-
end # class Server
|
592
|
-
end # module LDAP
|