treequel 1.0.1 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/ChangeLog +176 -14
- data/LICENSE +1 -1
- data/Rakefile +61 -45
- data/Rakefile.local +20 -0
- data/bin/treequel +502 -269
- data/examples/ldap-rack-auth.rb +2 -0
- data/lib/treequel.rb +221 -18
- data/lib/treequel/branch.rb +410 -201
- data/lib/treequel/branchcollection.rb +25 -13
- data/lib/treequel/branchset.rb +42 -40
- data/lib/treequel/constants.rb +233 -3
- data/lib/treequel/control.rb +95 -0
- data/lib/treequel/controls/contentsync.rb +138 -0
- data/lib/treequel/controls/pagedresults.rb +162 -0
- data/lib/treequel/controls/sortedresults.rb +216 -0
- data/lib/treequel/directory.rb +212 -65
- data/lib/treequel/exceptions.rb +11 -12
- data/lib/treequel/filter.rb +1 -12
- data/lib/treequel/mixins.rb +83 -47
- data/lib/treequel/monkeypatches.rb +29 -0
- data/lib/treequel/schema.rb +23 -19
- data/lib/treequel/schema/attributetype.rb +33 -3
- data/lib/treequel/schema/ldapsyntax.rb +0 -11
- data/lib/treequel/schema/matchingrule.rb +0 -11
- data/lib/treequel/schema/matchingruleuse.rb +0 -11
- data/lib/treequel/schema/objectclass.rb +36 -10
- data/lib/treequel/schema/table.rb +159 -0
- data/lib/treequel/sequel_integration.rb +7 -7
- data/lib/treequel/utils.rb +4 -66
- data/rake/documentation.rb +89 -0
- data/rake/helpers.rb +375 -307
- data/rake/hg.rb +16 -2
- data/rake/manual.rb +11 -6
- data/rake/packaging.rb +20 -35
- data/rake/publishing.rb +22 -62
- data/spec/lib/constants.rb +20 -0
- data/spec/lib/control_behavior.rb +44 -0
- data/spec/lib/matchers.rb +51 -0
- data/spec/treequel/branch_spec.rb +88 -29
- data/spec/treequel/branchcollection_spec.rb +24 -1
- data/spec/treequel/branchset_spec.rb +123 -51
- data/spec/treequel/control_spec.rb +48 -0
- data/spec/treequel/controls/contentsync_spec.rb +38 -0
- data/spec/treequel/controls/pagedresults_spec.rb +138 -0
- data/spec/treequel/controls/sortedresults_spec.rb +171 -0
- data/spec/treequel/directory_spec.rb +186 -16
- data/spec/treequel/mixins_spec.rb +42 -3
- data/spec/treequel/schema/attributetype_spec.rb +22 -20
- data/spec/treequel/schema/objectclass_spec.rb +67 -46
- data/spec/treequel/schema/table_spec.rb +134 -0
- data/spec/treequel_spec.rb +277 -15
- metadata +89 -108
- data/bin/treequel.orig +0 -963
- data/examples/ldap-monitor.rb +0 -143
- data/examples/ldap-monitor/public/css/master.css +0 -328
- data/examples/ldap-monitor/public/images/card_small.png +0 -0
- data/examples/ldap-monitor/public/images/chain_small.png +0 -0
- data/examples/ldap-monitor/public/images/globe_small.png +0 -0
- data/examples/ldap-monitor/public/images/globe_small_green.png +0 -0
- data/examples/ldap-monitor/public/images/plug.png +0 -0
- data/examples/ldap-monitor/public/images/shadows/large-30-down.png +0 -0
- data/examples/ldap-monitor/public/images/tick.png +0 -0
- data/examples/ldap-monitor/public/images/tick_circle.png +0 -0
- data/examples/ldap-monitor/public/images/treequel-favicon.png +0 -0
- data/examples/ldap-monitor/views/backends.erb +0 -41
- data/examples/ldap-monitor/views/connections.erb +0 -74
- data/examples/ldap-monitor/views/databases.erb +0 -39
- data/examples/ldap-monitor/views/dump_subsystem.erb +0 -14
- data/examples/ldap-monitor/views/index.erb +0 -14
- data/examples/ldap-monitor/views/layout.erb +0 -35
- data/examples/ldap-monitor/views/listeners.erb +0 -30
- data/rake/rdoc.rb +0 -30
- data/rake/win32.rb +0 -190
@@ -29,17 +29,6 @@ require 'treequel/branch'
|
|
29
29
|
#
|
30
30
|
# Note that you could accomplish most of what BranchCollection does
|
31
31
|
# using filters, but some people might find this a bit more readable.
|
32
|
-
#
|
33
|
-
# == Authors
|
34
|
-
#
|
35
|
-
# * Michael Granger <ged@FaerieMUD.org>
|
36
|
-
#
|
37
|
-
# :include: LICENSE
|
38
|
-
#
|
39
|
-
#--
|
40
|
-
#
|
41
|
-
# Please see the file LICENSE in the base directory for licensing details.
|
42
|
-
#
|
43
32
|
class Treequel::BranchCollection
|
44
33
|
include Enumerable,
|
45
34
|
Treequel::Loggable,
|
@@ -52,12 +41,21 @@ class Treequel::BranchCollection
|
|
52
41
|
### C L A S S M E T H O D S
|
53
42
|
#################################################################
|
54
43
|
|
55
|
-
### Create a delegator that will return an instance of the receiver
|
56
|
-
### iterating over the branchsets and calling
|
44
|
+
### Create a delegator that will return an instance of the receiver
|
45
|
+
### created with the results of iterating over the branchsets and calling
|
46
|
+
### the delegated method.
|
47
|
+
### @param [Array<Symbol>] symbols The methods to define
|
57
48
|
def self::def_cloning_delegators( *symbols )
|
58
49
|
symbols.each do |methname|
|
59
50
|
# Create the method body
|
60
51
|
methodbody = Proc.new {|*args|
|
52
|
+
|
53
|
+
# Check to be sure the mutator version of the method is being called
|
54
|
+
arity = self.branchsets.first.method( methname ).arity
|
55
|
+
if arity.nonzero? && args.empty?
|
56
|
+
raise ArgumentError, "wrong number of arguments: (0 for %d)" % [ arity.abs ]
|
57
|
+
end
|
58
|
+
|
61
59
|
mutated_branchsets = self.branchsets.
|
62
60
|
collect {|bs| bs.send(methname, *args) }.flatten
|
63
61
|
self.class.new( *mutated_branchsets )
|
@@ -75,6 +73,8 @@ class Treequel::BranchCollection
|
|
75
73
|
#################################################################
|
76
74
|
|
77
75
|
### Create a new Treequel::BranchCollection that will operate on the given +branchsets+.
|
76
|
+
### @param [Array<Treequel::Branchset, #each>] branchsets the objects that will be
|
77
|
+
### combined in the BranchCollection.
|
78
78
|
def initialize( *branchsets )
|
79
79
|
@branchsets = branchsets.flatten.collect do |obj|
|
80
80
|
if obj.respond_to?( :each )
|
@@ -107,6 +107,7 @@ class Treequel::BranchCollection
|
|
107
107
|
|
108
108
|
|
109
109
|
### Return a human-readable string representation of the object suitable for debugging.
|
110
|
+
### @return [String]
|
110
111
|
def inspect
|
111
112
|
"#<%s:0x%0x %d branchsets: %p>" % [
|
112
113
|
self.class.name,
|
@@ -119,6 +120,7 @@ class Treequel::BranchCollection
|
|
119
120
|
|
120
121
|
### Iterate over the Treequel::Branches found by each member branchset, yielding each
|
121
122
|
### one in turn.
|
123
|
+
### @yield [Treequel::Branch]
|
122
124
|
def each( &block )
|
123
125
|
raise LocalJumpError, "no block given" unless block
|
124
126
|
self.branchsets.each do |bs|
|
@@ -128,6 +130,7 @@ class Treequel::BranchCollection
|
|
128
130
|
|
129
131
|
|
130
132
|
### Return the first Treequel::Branch that is returned from the collection's branchsets.
|
133
|
+
### @return [Treequel::Branch]
|
131
134
|
def first
|
132
135
|
branch = nil
|
133
136
|
|
@@ -138,7 +141,16 @@ class Treequel::BranchCollection
|
|
138
141
|
return branch
|
139
142
|
end
|
140
143
|
|
144
|
+
|
145
|
+
### Return +true+ if none of the collection's branches match any entries.
|
146
|
+
### @return [Boolean]
|
147
|
+
def empty?
|
148
|
+
return self.branchsets.all? {|bs| bs.empty? } ? true : false
|
149
|
+
end
|
150
|
+
|
151
|
+
|
141
152
|
### Overridden to support Branchset#map
|
153
|
+
### @param (see Treequel::Branchset#map)
|
142
154
|
def map( attribute=nil, &block )
|
143
155
|
if attribute
|
144
156
|
if block
|
data/lib/treequel/branchset.rb
CHANGED
@@ -10,6 +10,7 @@ require 'treequel/constants'
|
|
10
10
|
require 'treequel/branch'
|
11
11
|
require 'treequel/filter'
|
12
12
|
require 'treequel/sequel_integration'
|
13
|
+
require 'treequel/control'
|
13
14
|
|
14
15
|
|
15
16
|
# A branchset represents an abstract set of LDAP records returned by
|
@@ -41,21 +42,11 @@ require 'treequel/sequel_integration'
|
|
41
42
|
#
|
42
43
|
# Branchsets are Enumerable objects, so they can be manipulated using any of the
|
43
44
|
# Enumerable methods, such as map, inject, etc.
|
44
|
-
#
|
45
|
-
# == Authors
|
46
|
-
#
|
47
|
-
# * Michael Granger <ged@FaerieMUD.org>
|
48
|
-
#
|
49
|
-
# :include: LICENSE
|
50
|
-
#
|
51
|
-
#--
|
52
|
-
#
|
53
|
-
# Please see the file LICENSE in the base directory for licensing details.
|
54
|
-
#
|
55
45
|
class Treequel::Branchset
|
56
46
|
include Enumerable,
|
57
47
|
Treequel::Loggable,
|
58
|
-
Treequel::Constants
|
48
|
+
Treequel::Constants,
|
49
|
+
Treequel::Control
|
59
50
|
|
60
51
|
# The default scope to use when searching if none is specified
|
61
52
|
DEFAULT_SCOPE = :subtree
|
@@ -84,9 +75,13 @@ class Treequel::Branchset
|
|
84
75
|
### Create a new Branchset for a search from the DN of the specified +branch+ (a
|
85
76
|
### Treequel::Branch), with the given +options+.
|
86
77
|
def initialize( branch, options={} )
|
87
|
-
super()
|
88
78
|
@branch = branch
|
89
79
|
@options = DEFAULT_OPTIONS.merge( options )
|
80
|
+
|
81
|
+
self.extend( *@branch.directory.registered_controls ) unless
|
82
|
+
@branch.directory.registered_controls.empty?
|
83
|
+
|
84
|
+
super()
|
90
85
|
end
|
91
86
|
|
92
87
|
|
@@ -103,6 +98,17 @@ class Treequel::Branchset
|
|
103
98
|
attr_accessor :branch
|
104
99
|
|
105
100
|
|
101
|
+
### Extend the Branchset with one or more modules. Overridden to also call the modules'
|
102
|
+
### initializers if they have them.
|
103
|
+
def extend( *modules )
|
104
|
+
super
|
105
|
+
modules.each do |mod|
|
106
|
+
mod.instance_method( :initialize ).bind( self ).call if
|
107
|
+
mod.private_instance_methods.map( &:to_sym ).include?( :initialize )
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
|
106
112
|
### Returns the DN of the Branchset's branch.
|
107
113
|
def base_dn
|
108
114
|
return self.branch.dn
|
@@ -166,7 +172,16 @@ class Treequel::Branchset
|
|
166
172
|
|
167
173
|
### Create a BranchCollection from the results of the Branchset and return it.
|
168
174
|
def collection
|
169
|
-
Treequel::BranchCollection.new( self.all )
|
175
|
+
return Treequel::BranchCollection.new( self.all )
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
### Create a BranchCollection from the receiver and the +other_branchset+ and return
|
180
|
+
### it.
|
181
|
+
### @param [Treequel::Branchset] other_branchset the branchset to combine with
|
182
|
+
### @return [Treequel::BranchCollection] the resulting collection object
|
183
|
+
def +( other_branchset )
|
184
|
+
return Treequel::BranchCollection.new( self, other_branchset )
|
170
185
|
end
|
171
186
|
|
172
187
|
|
@@ -174,29 +189,39 @@ class Treequel::Branchset
|
|
174
189
|
### as Treequel::Branch objects to the supplied block.
|
175
190
|
def each( &block )
|
176
191
|
raise LocalJumpError, "no block given" unless block
|
177
|
-
directory = self.branch.directory
|
178
192
|
|
179
|
-
|
193
|
+
self.branch.search( self.scope, self.filter,
|
180
194
|
:selectattrs => self.select,
|
181
195
|
:timeout => self.timeout,
|
182
196
|
# :sortby => self.order,
|
183
197
|
:limit => self.limit,
|
198
|
+
:client_controls => self.get_client_controls,
|
199
|
+
:server_controls => self.get_server_controls,
|
184
200
|
&block
|
185
201
|
)
|
186
202
|
end
|
187
203
|
|
204
|
+
|
188
205
|
### Fetch the first entry which matches the current criteria and return it as an instance of
|
189
206
|
### the object that is set as the +branch+ (e.g., Treequel::Branch).
|
190
207
|
def first
|
191
|
-
self.branch.
|
208
|
+
self.branch.search( self.scope, self.filter,
|
192
209
|
:selectattrs => self.select,
|
193
210
|
:timeout => self.timeout,
|
194
211
|
# :sortby => self.order,
|
212
|
+
:client_controls => self.get_client_controls,
|
213
|
+
:server_controls => self.get_server_controls,
|
195
214
|
:limit => 1
|
196
215
|
).first
|
197
216
|
end
|
198
217
|
|
199
218
|
|
219
|
+
### Return +true+ if no entries match the Branchset's current criteria.
|
220
|
+
def empty?
|
221
|
+
return self.first.nil? ? true : false
|
222
|
+
end
|
223
|
+
|
224
|
+
|
200
225
|
### Either maps entries which match the current criteria into an Array of the given
|
201
226
|
### +attribute+, or falls back to the block form if no +attribute+ is specified. If both an
|
202
227
|
### +attribute+ and a +block+ are given, the +block+ is called once for each +attribute+ value
|
@@ -341,29 +366,6 @@ class Treequel::Branchset
|
|
341
366
|
newset.branch = branchclass.new( self.branch.directory, self.branch.dn )
|
342
367
|
return newset
|
343
368
|
end
|
344
|
-
|
345
|
-
|
346
|
-
# Hiding this until we figure out how to do server-side ordering (i.e.,
|
347
|
-
# http://tools.ietf.org/html/rfc2891)
|
348
|
-
|
349
|
-
### Return a clone of the receiving Branchsest that will order its results by the
|
350
|
-
### +attributes+ specified.
|
351
|
-
def __order( attribute=:__default__ ) # :nodoc:
|
352
|
-
if attribute == :__default__
|
353
|
-
if block_given?
|
354
|
-
sort_func = Proc.new
|
355
|
-
return self.clone( :order => sort_func )
|
356
|
-
else
|
357
|
-
return self.options[:order]
|
358
|
-
end
|
359
|
-
elsif attribute.nil?
|
360
|
-
self.log.debug "cloning %p with no order" % [ self ]
|
361
|
-
return self.clone( :order => nil )
|
362
|
-
else
|
363
|
-
self.log.debug "cloning %p with new order: %p" % [ self, attribute ]
|
364
|
-
return self.clone( :order => attribute.to_sym )
|
365
|
-
end
|
366
|
-
end
|
367
369
|
|
368
370
|
|
369
371
|
end # class Treequel::Branchset
|
data/lib/treequel/constants.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
2
|
|
3
|
+
require 'uri'
|
3
4
|
require 'ldap'
|
4
5
|
require 'treequel'
|
5
6
|
|
@@ -27,6 +28,118 @@ module Treequel::Constants
|
|
27
28
|
LDAP::LDAP_SCOPE_SUBTREE => 'subtree',
|
28
29
|
}
|
29
30
|
|
31
|
+
### Names and OIDs of various controls, in OID order
|
32
|
+
CONTROL_OIDS = {
|
33
|
+
:valuesreturnfilter => '1.2.826.0.1.334810.2.3',
|
34
|
+
:matchedvals => '1.2.826.0.1.3344810.2.2',
|
35
|
+
:matchedvalues => '1.2.826.0.1.3344810.2.3',
|
36
|
+
|
37
|
+
# MS Active Directory controls, from various MSDN references, most
|
38
|
+
# notably:
|
39
|
+
# http://msdn.microsoft.com/en-us/library/cc223320%28PROT.10%29.aspx
|
40
|
+
:paged => '1.2.840.113556.1.4.319',
|
41
|
+
:server_show_deleted => '1.2.840.113556.1.4.417',
|
42
|
+
:sortrequest => '1.2.840.113556.1.4.473',
|
43
|
+
:sortresult => '1.2.840.113556.1.4.474',
|
44
|
+
:crossdom_move_target => '1.2.840.113556.1.4.521',
|
45
|
+
:server_notification => '1.2.840.113556.1.4.528',
|
46
|
+
:extended_dn => '1.2.840.113556.1.4.529',
|
47
|
+
:referrals => '1.2.840.113556.1.4.616',
|
48
|
+
:server_lazy_commit => '1.2.840.113556.1.4.619',
|
49
|
+
:server_sd_flags => '1.2.840.113556.1.4.801',
|
50
|
+
:incremental_values => '1.2.840.113556.1.4.802',
|
51
|
+
:tree_delete => '1.2.840.113556.1.4.805',
|
52
|
+
:server_dirsync => '1.2.840.113556.1.4.841',
|
53
|
+
:get_stats => '1.2.840.113556.1.4.970',
|
54
|
+
:verify_name => '1.2.840.113556.1.4.1338',
|
55
|
+
:domain_scope => '1.2.840.113556.1.4.1339',
|
56
|
+
:search_options => '1.2.840.113556.1.4.1340',
|
57
|
+
:rodc_dcpromo => '1.2.840.113556.1.4.1341',
|
58
|
+
:permissive_modify => '1.2.840.113556.1.4.1413',
|
59
|
+
:asq => '1.2.840.113556.1.4.1504',
|
60
|
+
:fast_bind => '1.2.840.113556.1.4.1781',
|
61
|
+
:quota_control => '1.2.840.113556.1.4.1852',
|
62
|
+
:shutdown_notify => '1.2.840.113556.1.4.1907',
|
63
|
+
:range_retrieval_noerr => '1.2.840.113556.1.4.1948',
|
64
|
+
:force_update => '1.2.840.113556.1.4.1974',
|
65
|
+
:input_dn => '1.2.840.113556.1.4.2026',
|
66
|
+
|
67
|
+
# RFC 4527
|
68
|
+
:preread => '1.3.6.1.1.13.1',
|
69
|
+
:postread => '1.3.6.1.1.13.2',
|
70
|
+
|
71
|
+
:assertion => '1.3.6.1.1.12',
|
72
|
+
|
73
|
+
:passwordpolicy => '1.3.6.1.4.1.42.2.27.8.5.1',
|
74
|
+
|
75
|
+
:ttl_refresh => '1.3.6.1.4.1.1466.101.119.1',
|
76
|
+
:start_tls => '1.3.6.1.4.1.1466.20037',
|
77
|
+
|
78
|
+
:sync => '1.3.6.1.4.1.4203.1.9.1.1',
|
79
|
+
:sync_state => '1.3.6.1.4.1.4203.1.9.1.2',
|
80
|
+
:sync_done => '1.3.6.1.4.1.4203.1.9.1.3',
|
81
|
+
:subentries => '1.3.6.1.4.1.4203.1.10.1',
|
82
|
+
|
83
|
+
# OpenLDAP "devil made me do it" OID arc
|
84
|
+
:noop => "1.3.6.1.4.1.4203.666.5.2",
|
85
|
+
:no_subordinates => "1.3.6.1.4.1.4203.666.5.11",
|
86
|
+
:relax => "1.3.6.1.4.1.4203.666.5.12",
|
87
|
+
:managedit => "1.3.6.1.4.1.4203.666.5.12",
|
88
|
+
:slurp => "1.3.6.1.4.1.4203.666.5.13",
|
89
|
+
:valsort => "1.3.6.1.4.1.4203.666.5.14",
|
90
|
+
:dontusecopy => "1.3.6.1.4.1.4203.666.5.15",
|
91
|
+
:x_deref => "1.3.6.1.4.1.4203.666.5.16",
|
92
|
+
:x_whatfailed => "1.3.6.1.4.1.4203.666.5.17",
|
93
|
+
:x_chaining_behavior => "1.3.6.1.4.1.4203.666.11.3",
|
94
|
+
|
95
|
+
# LDAP Duplicated Entry Control Extension
|
96
|
+
:dupent_request => '2.16.840.1.113719.1.27.101.1',
|
97
|
+
:dupent_response => '2.16.840.1.113719.1.27.101.2',
|
98
|
+
:dupent_entry => '2.16.840.1.113719.1.27.101.3',
|
99
|
+
|
100
|
+
:managedsait => '2.16.840.1.113730.3.4.2',
|
101
|
+
:persistentsearch => '2.16.840.1.113730.3.4.3',
|
102
|
+
:pwexpired => '2.16.840.1.113730.3.4.4',
|
103
|
+
:pwexpiring => '2.16.840.1.113730.3.4.5',
|
104
|
+
:entrychange => '2.16.840.1.113730.3.4.7',
|
105
|
+
:vlvrequest => '2.16.840.1.113730.3.4.9',
|
106
|
+
:vlvresponse => '2.16.840.1.113730.3.4.10',
|
107
|
+
:proxyauthentication => '2.16.840.1.113730.3.4.18',
|
108
|
+
|
109
|
+
}.freeze
|
110
|
+
CONTROL_NAMES = CONTROL_OIDS.invert.freeze
|
111
|
+
|
112
|
+
|
113
|
+
### Names and OIDs of LDAP extensions, in OID order
|
114
|
+
EXTENSION_OIDS = {
|
115
|
+
# Borrowed from OpenLDAP's ldap.h
|
116
|
+
:cancel => '1.3.6.1.1.8', # RFC 3909
|
117
|
+
:turn => '1.3.6.1.1.19', # RFC 4531
|
118
|
+
|
119
|
+
:refresh => '1.3.6.1.4.1.1466.101.119.1', # RFC 2589
|
120
|
+
:start_tls => '1.3.6.1.4.1.1466.20037', # RFC 4511
|
121
|
+
|
122
|
+
:modify_passwd => '1.3.6.1.4.1.4203.1.11.1', # RFC 3062
|
123
|
+
:who_am_i => '1.3.6.1.4.1.4203.1.11.3', # RFC 4532
|
124
|
+
}.freeze
|
125
|
+
EXTENSION_NAMES = EXTENSION_OIDS.invert.freeze
|
126
|
+
|
127
|
+
|
128
|
+
### Names and OIDs of LDAP features, in OID order
|
129
|
+
FEATURE_OIDS = {
|
130
|
+
# Borrowed from OpenLDAP's ldap.h
|
131
|
+
:modify_increment => '1.3.6.1.1.14',
|
132
|
+
|
133
|
+
:all_op_attrs => '1.3.6.1.4.1.4203.1.5.1', # RFC 3673
|
134
|
+
:objectclass_attrs => '1.3.6.1.4.1.4203.1.5.2',
|
135
|
+
:absolute_filters => '1.3.6.1.4.1.4203.1.5.3',
|
136
|
+
:language_tag_options => '1.3.6.1.4.1.4203.1.5.4',
|
137
|
+
:language_range_options => '1.3.6.1.4.1.4203.1.5.5',
|
138
|
+
|
139
|
+
:subordinate_scope => '1.3.6.1.4.1.4203.666.8.1',
|
140
|
+
}.freeze
|
141
|
+
FEATURE_NAMES = FEATURE_OIDS.invert.freeze
|
142
|
+
|
30
143
|
|
31
144
|
### OIDs of RFC values
|
32
145
|
module OIDS
|
@@ -80,6 +193,16 @@ module Treequel::Constants
|
|
80
193
|
### A collection of Regexps to match various LDAP values
|
81
194
|
module Patterns
|
82
195
|
|
196
|
+
# Steal the URIREF regexp from the URI library. We have to look in
|
197
|
+
# both places to support both 1.9.1 and 1.8.x.
|
198
|
+
URI_REF = if URI::REGEXP.const_defined?( :PATTERN )
|
199
|
+
/#{URI::REGEXP::PATTERN::URI_REF}/
|
200
|
+
elsif URI::REGEXP.const_defined?( :URI_REF )
|
201
|
+
/#{URI::REGEXP::URI_REF}/
|
202
|
+
else
|
203
|
+
raise "Couldn't find the URI_REF constant in the URI library!"
|
204
|
+
end
|
205
|
+
|
83
206
|
# :stopdoc:
|
84
207
|
|
85
208
|
# Schema-parsing patterns based on the BNF in
|
@@ -228,26 +351,34 @@ module Treequel::Constants
|
|
228
351
|
# numericoid = number 1*( DOT number )
|
229
352
|
NUMERICOID = /#{NUMBER}(?: #{DOT} #{NUMBER} )+/x
|
230
353
|
|
354
|
+
# ActiveDirectory quotes its numeric OIDs (sometimes)
|
355
|
+
QUOTED_NUMERICOID = /#{SQUOTE} #{NUMERICOID} #{SQUOTE}/x
|
231
356
|
|
232
|
-
# Short names, also known as
|
357
|
+
# Short names, also known as descriptors, are used as more readable
|
233
358
|
# aliases for object identifiers. Short names are case insensitive and
|
234
359
|
# conform to the ABNF:
|
235
360
|
|
236
361
|
# descr = keystring
|
237
362
|
DESCR = KEYSTRING
|
238
363
|
|
364
|
+
# ActiveDirectory quotes its descriptors (sometimes)
|
365
|
+
QUOTED_DESCR = / #{SQUOTE} #{DESCR} #{SQUOTE} /x
|
366
|
+
|
239
367
|
# Where either an object identifier or a short name may be specified,
|
240
368
|
# the following production is used:
|
241
369
|
|
242
370
|
# oid = descr / numericoid
|
243
|
-
|
371
|
+
# NOTE: Added QUOTED_NUMERICOID and QUOTED_DESCR to support ActiveDirectory
|
372
|
+
OID = / #{DESCR} | #{QUOTED_DESCR} | #{NUMERICOID} | #{QUOTED_NUMERICOID} /x
|
244
373
|
|
245
374
|
|
246
375
|
# len = number
|
247
376
|
LEN = NUMBER
|
248
377
|
|
249
378
|
# noidlen = numericoid [ LCURLY len RCURLY ]
|
250
|
-
|
379
|
+
# NOTE: I changed this from NUMERICOID to OID to support ActiveDirectory schema
|
380
|
+
# entries
|
381
|
+
NOIDLEN = /#{OID} (?:#{LCURLY} #{LEN} #{RCURLY})?/x
|
251
382
|
|
252
383
|
# oidlist = oid *( WSP DOLLAR WSP oid )
|
253
384
|
OIDLIST = /#{OID} (?: #{WSP} #{DOLLAR} #{WSP} #{OID} )*/x
|
@@ -595,6 +726,105 @@ module Treequel::Constants
|
|
595
726
|
}x
|
596
727
|
|
597
728
|
|
729
|
+
#
|
730
|
+
# LDIF (RFC 2849)
|
731
|
+
#
|
732
|
+
|
733
|
+
# attr-type-chars = ALPHA / DIGIT / "-"
|
734
|
+
# opt-char = attr-type-chars
|
735
|
+
# same as KEYCHAR
|
736
|
+
LDIF_ATTR_TYPE_CHARS = KEYCHAR
|
737
|
+
LDIF_OPT_CHAR = KEYCHAR
|
738
|
+
|
739
|
+
# option = 1*opt-char
|
740
|
+
LDIF_ATTRTYPE_OPTION = %r{ #{LDIF_OPT_CHAR}+ }x
|
741
|
+
|
742
|
+
# options = option / (option ";" options)
|
743
|
+
LDIF_ATTRTYPE_OPTIONS = %r{
|
744
|
+
#{LDIF_ATTRTYPE_OPTION}
|
745
|
+
(?: ; #{LDIF_ATTRTYPE_OPTION} )*
|
746
|
+
}x
|
747
|
+
|
748
|
+
# AttributeType = ldap-oid / (ALPHA *(attr-type-chars))
|
749
|
+
LDIF_ATTRIBUTE_TYPE = %r{
|
750
|
+
#{NUMERICOID}
|
751
|
+
|
|
752
|
+
[#{ALPHA}] #{LDIF_ATTR_TYPE_CHARS}*
|
753
|
+
}x
|
754
|
+
|
755
|
+
# AttributeDescription = AttributeType [";" options]
|
756
|
+
# ; Definition taken from [4]
|
757
|
+
LDIF_ATTRIBUTE_DESCRIPTION = %r{
|
758
|
+
#{LDIF_ATTRIBUTE_TYPE}
|
759
|
+
(?: ; #{LDIF_ATTRTYPE_OPTIONS} )?
|
760
|
+
}x
|
761
|
+
|
762
|
+
# SPACE = %x20 ; ASCII SP, space
|
763
|
+
# FILL = *SPACE
|
764
|
+
FILL = '\x20+'
|
765
|
+
|
766
|
+
# SAFE-CHAR = %x01-09 / %x0B-0C / %x0E-7F
|
767
|
+
# ; any value <= 127 decimal except NUL, LF,
|
768
|
+
# ; and CR
|
769
|
+
LDIF_SAFE_CHAR = %r{[\x01-\x09\x0b-\x0c\x0e-\x7f]}
|
770
|
+
|
771
|
+
# SAFE-INIT-CHAR = %x01-09 / %x0B-0C / %x0E-1F /
|
772
|
+
# %x21-39 / %x3B / %x3D-7F
|
773
|
+
# ; any value <= 127 except NUL, LF, CR,
|
774
|
+
# ; SPACE, colon (":", ASCII 58 decimal)
|
775
|
+
# ; and less-than ("<" , ASCII 60 decimal)
|
776
|
+
LDIF_SAFE_INIT_CHAR = %r{[\x01-\x09\x0B-\x0C\x0E-\x1F\x21-\x39\x3B\x3D-\x7F]}
|
777
|
+
|
778
|
+
# SAFE-STRING = [SAFE-INIT-CHAR *SAFE-CHAR]
|
779
|
+
LDIF_SAFE_STRING = %r{
|
780
|
+
#{LDIF_SAFE_INIT_CHAR}
|
781
|
+
#{LDIF_SAFE_CHAR}*
|
782
|
+
}x
|
783
|
+
|
784
|
+
|
785
|
+
# BASE64-CHAR = %x2B / %x2F / %x30-39 / %x3D / %x41-5A /
|
786
|
+
# %x61-7A
|
787
|
+
# ; +, /, 0-9, =, A-Z, and a-z
|
788
|
+
# ; as specified in [5]
|
789
|
+
BASE64_CHAR = %r{[\x2B\x2F\x30-\x39\x3D\x41-\x5A\x61-\x7A]}
|
790
|
+
|
791
|
+
# BASE64-STRING = [*(BASE64-CHAR)]
|
792
|
+
BASE64_STRING = %r{ #{BASE64_CHAR}* }x
|
793
|
+
|
794
|
+
# SEP = (CR LF / LF)
|
795
|
+
SEP = %r{\r?\n}
|
796
|
+
|
797
|
+
# Any non-empty line, including comment lines, in an LDIF file
|
798
|
+
# MAY be folded by inserting a line separator (SEP) and a SPACE.
|
799
|
+
FOLD = %r{ #{SEP} #{SPACE} }x
|
800
|
+
|
801
|
+
# value-spec = ":" ( FILL 0*1(SAFE-STRING) /
|
802
|
+
# ":" FILL (BASE64-STRING) /
|
803
|
+
# "<" FILL url)
|
804
|
+
LDIF_VALUE_SPEC = %r{
|
805
|
+
:
|
806
|
+
(
|
807
|
+
#{FILL} #{LDIF_SAFE_STRING}+ (?: #{FOLD} #{LDIF_SAFE_CHAR}* )*
|
808
|
+
|
|
809
|
+
: #{FILL} #{BASE64_STRING} (?: #{FOLD} #{BASE64_STRING} )*
|
810
|
+
|
|
811
|
+
< #{FILL} #{URI_REF}
|
812
|
+
)
|
813
|
+
}x
|
814
|
+
|
815
|
+
# attrval-spec = AttributeDescription value-spec SEP
|
816
|
+
LDIF_ATTRVAL_SPEC = %r{
|
817
|
+
(#{LDIF_ATTRIBUTE_DESCRIPTION})
|
818
|
+
#{LDIF_VALUE_SPEC}
|
819
|
+
#{SEP}
|
820
|
+
}xm
|
821
|
+
|
822
|
+
|
823
|
+
# Freeze all the pattern constants so they don't get clobbered
|
824
|
+
constants.each do |const|
|
825
|
+
const_get( const ).freeze
|
826
|
+
end
|
827
|
+
|
598
828
|
end # module Patterns
|
599
829
|
|
600
830
|
end # module Treequel::Constants
|