1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.server.core.normalization;
21
22
23 import java.util.ArrayList;
24 import java.util.List;
25
26 import javax.naming.InvalidNameException;
27 import javax.naming.NamingException;
28
29 import org.apache.directory.server.schema.registries.Registries;
30 import org.apache.directory.shared.ldap.entry.Value;
31 import org.apache.directory.shared.ldap.entry.client.ClientBinaryValue;
32 import org.apache.directory.shared.ldap.entry.client.ClientStringValue;
33 import org.apache.directory.shared.ldap.filter.AndNode;
34 import org.apache.directory.shared.ldap.filter.BranchNode;
35 import org.apache.directory.shared.ldap.filter.ExprNode;
36 import org.apache.directory.shared.ldap.filter.ExtensibleNode;
37 import org.apache.directory.shared.ldap.filter.FilterVisitor;
38 import org.apache.directory.shared.ldap.filter.LeafNode;
39 import org.apache.directory.shared.ldap.filter.NotNode;
40 import org.apache.directory.shared.ldap.filter.PresenceNode;
41 import org.apache.directory.shared.ldap.filter.SimpleNode;
42 import org.apache.directory.shared.ldap.filter.SubstringNode;
43 import org.apache.directory.shared.ldap.name.NameComponentNormalizer;
44 import org.apache.directory.shared.ldap.schema.AttributeType;
45 import org.apache.directory.shared.ldap.util.ByteBuffer;
46 import org.apache.directory.shared.ldap.util.StringTools;
47
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69 public class NormalizingVisitor implements FilterVisitor
70 {
71
72 private static final Logger log = LoggerFactory.getLogger( NormalizingVisitor.class );
73
74
75 private final NameComponentNormalizer ncn;
76
77
78 private final Registries registries;
79
80
81
82
83
84
85 private static final boolean[] FILTER_CHAR =
86 {
87 true, false, false, false, false, false, false, false,
88 false, false, false, false, false, false, false, false,
89 false, false, false, false, false, false, false, false,
90 false, false, false, false, false, false, false, false,
91 false, false, false, false, false, false, false, false,
92 true, true, true, false, false, false, false, false,
93 false, false, false, false, false, false, false, false,
94 false, false, false, false, false, false, false, false,
95 false, false, false, false, false, false, false, false,
96 false, false, false, false, false, false, false, false,
97 false, false, false, false, false, false, false, false,
98 false, false, false, false, true, false, false, false,
99 false, false, false, false, false, false, false, false,
100 false, false, false, false, false, false, false, false,
101 false, false, false, false, false, false, false, false,
102 false, false, false, false, false, false, false, false
103 };
104
105
106
107
108
109
110
111
112 public static boolean isFilterChar( char c )
113 {
114 return ( ( ( c | 0x7F ) == 0x7F ) && FILTER_CHAR[c & 0x7f] );
115 }
116
117
118
119
120
121
122
123
124
125 private static final String decodeEscapedHex( String str ) throws InvalidNameException
126 {
127
128 StringBuffer buf = new StringBuffer();
129 ByteBuffer bb = new ByteBuffer();
130 boolean escaped = false;
131
132
133 for ( int ii = 0; ii < str.length(); ii++ )
134 {
135 char c = str.charAt( ii );
136
137 if ( c == '\\' )
138 {
139
140 if ( StringTools.isHex( str, ii+1 ) && StringTools.isHex ( str, ii+2 ) )
141 {
142 bb.clear();
143 int advancedBy = StringTools.collectEscapedHexBytes( bb, str, ii );
144 ii+=advancedBy-1;
145 buf.append( StringTools.utf8ToString( bb.buffer(), bb.position() ) );
146 escaped = false;
147 continue;
148 }
149 else if ( !escaped )
150 {
151
152 escaped = true;
153 continue;
154 }
155 }
156
157
158 if ( escaped )
159 {
160 if ( isFilterChar( c ) )
161 {
162
163
164 escaped = false;
165 buf.append( c );
166 continue;
167 }
168 else
169 {
170 throw new InvalidNameException( "The value must contain valid escaped characters." );
171 }
172 }
173 else
174 {
175 buf.append( str.charAt( ii ) );
176 }
177 }
178
179 if ( escaped )
180 {
181
182 throw new InvalidNameException( "The value must not ends with a '\\'." );
183 }
184
185 return buf.toString();
186 }
187
188
189
190
191
192 private void unescapeValue( Value<?> value )
193 {
194 if ( !value.isBinary() )
195 {
196 String valStr = (String)value.getNormalizedValue();
197
198 if ( StringTools.isEmpty( valStr ) )
199 {
200 return;
201 }
202
203 try
204 {
205 String newStr= decodeEscapedHex( valStr );
206 ((ClientStringValue)value).set( newStr );
207 return;
208 }
209 catch ( InvalidNameException ine )
210 {
211 value.set( null );
212 return;
213 }
214 }
215 }
216
217
218
219
220
221
222
223
224
225 public NormalizingVisitor( NameComponentNormalizer ncn, Registries registries )
226 {
227 this.ncn = ncn;
228 this.registries = registries;
229 }
230
231
232
233
234
235
236
237
238
239 private Value<?> normalizeValue( String attribute, Value<?> value )
240 {
241 try
242 {
243 Value<?> normalized = null;
244
245 AttributeType attributeType = registries.getAttributeTypeRegistry().lookup( attribute );
246
247 if ( attributeType.getSyntax().isHumanReadable() )
248 {
249 if ( value.isBinary() )
250 {
251 normalized = new ClientStringValue( ( String ) ncn.normalizeByName( attribute, StringTools
252 .utf8ToString( ( byte[] ) value.get() ) ) );
253
254 unescapeValue( normalized );
255 }
256 else
257 {
258 normalized = new ClientStringValue( ( String ) ncn.normalizeByName( attribute, ( String ) value
259 .get() ) );
260
261 unescapeValue( normalized );
262 }
263 }
264 else
265 {
266 if ( value.isBinary() )
267 {
268 normalized = new ClientBinaryValue( ( byte[] ) ncn.normalizeByName( attribute, ( byte[] ) value
269 .get() ) );
270 }
271 else
272 {
273 normalized = new ClientBinaryValue( ( byte[] ) ncn.normalizeByName( attribute, ( String ) value
274 .get() ) );
275
276 }
277 }
278
279 return normalized;
280 }
281 catch ( NamingException ne )
282 {
283 log.warn( "Failed to normalize filter value: {}", ne.getMessage(), ne );
284 return null;
285 }
286
287 }
288
289
290
291
292
293
294
295
296
297 private ExprNode visitPresenceNode( PresenceNode node )
298 {
299 try
300 {
301 node.setAttribute( registries.getOidRegistry().getOid( node.getAttribute() ) );
302 return node;
303 }
304 catch ( NamingException ne )
305 {
306 log.warn( "Failed to normalize filter node attribute: {}, error: {}", node.getAttribute(), ne.getMessage() );
307 return null;
308 }
309 }
310
311
312
313
314
315
316
317
318
319
320
321
322
323 private ExprNode visitSimpleNode( SimpleNode node )
324 {
325
326
327 if ( !ncn.isDefined( node.getAttribute() ) )
328 {
329 return null;
330 }
331
332 Value<?> normalized = normalizeValue( node.getAttribute(), node.getValue() );
333
334 if ( normalized == null )
335 {
336 return null;
337 }
338
339 try
340 {
341 node.setAttribute( registries.getOidRegistry().getOid( node.getAttribute() ) );
342 node.setValue( normalized );
343 return node;
344 }
345 catch ( NamingException ne )
346 {
347 log.warn( "Failed to normalize filter node attribute: {}, error: {}", node.getAttribute(), ne.getMessage() );
348 return null;
349 }
350 }
351
352
353
354
355
356
357
358
359
360
361
362 private ExprNode visitSubstringNode( SubstringNode node )
363 {
364
365
366 if ( !ncn.isDefined( node.getAttribute() ) )
367 {
368 return null;
369 }
370
371 Value<?> normInitial = null;
372
373 if ( node.getInitial() != null )
374 {
375 normInitial = normalizeValue( node.getAttribute(), new ClientStringValue( node.getInitial() ) );
376
377 if ( normInitial == null )
378 {
379 return null;
380 }
381 }
382
383 List<String> normAnys = null;
384
385 if ( ( node.getAny() != null ) && ( node.getAny().size() != 0 ) )
386 {
387 normAnys = new ArrayList<String>( node.getAny().size() );
388
389 for ( String any : node.getAny() )
390 {
391 Value<?> normAny = normalizeValue( node.getAttribute(), new ClientStringValue( any ) );
392
393 if ( normAny != null )
394 {
395 normAnys.add( ( String ) normAny.get() );
396 }
397 }
398
399 if ( normAnys.size() == 0 )
400 {
401 return null;
402 }
403 }
404
405 Value<?> normFinal = null;
406
407 if ( node.getFinal() != null )
408 {
409 normFinal = normalizeValue( node.getAttribute(), new ClientStringValue( node.getFinal() ) );
410
411 if ( normFinal == null )
412 {
413 return null;
414 }
415 }
416
417 try
418 {
419 node.setAttribute( registries.getOidRegistry().getOid( node.getAttribute() ) );
420
421 if ( normInitial != null )
422 {
423 node.setInitial( ( String ) normInitial.get() );
424 }
425 else
426 {
427 node.setInitial( null );
428 }
429
430 node.setAny( normAnys );
431
432 if ( normFinal != null )
433 {
434 node.setFinal( ( String ) normFinal.get() );
435 }
436 else
437 {
438 node.setFinal( null );
439 }
440
441 return node;
442 }
443 catch ( NamingException ne )
444 {
445 log.warn( "Failed to normalize filter node attribute: {}, error: {}", node.getAttribute(), ne.getMessage() );
446 return null;
447 }
448 }
449
450
451
452
453
454
455
456
457
458
459
460 private ExprNode visitExtensibleNode( ExtensibleNode node )
461 {
462 try
463 {
464 node.setAttribute( registries.getOidRegistry().getOid( node.getAttribute() ) );
465 return node;
466 }
467 catch ( NamingException ne )
468 {
469 log.warn( "Failed to normalize filter node attribute: {}, error: {}", node.getAttribute(), ne.getMessage() );
470 return null;
471 }
472 }
473
474
475
476
477
478
479
480
481
482
483
484 private ExprNode visitBranchNode( BranchNode node )
485 {
486
487
488
489
490 if ( node instanceof NotNode )
491 {
492
493 ExprNode child = node.getFirstChild();
494
495 ExprNode result = ( ExprNode ) visit( child );
496
497 if ( result == null )
498 {
499 return result;
500 }
501 else if ( result instanceof BranchNode )
502 {
503 node.setChildren( ( ( BranchNode ) result ).getChildren() );
504 return node;
505 }
506 else if ( result instanceof LeafNode )
507 {
508 List<ExprNode> newChildren = new ArrayList<ExprNode>( 1 );
509 newChildren.add( result );
510 node.setChildren( newChildren );
511 return node;
512 }
513 }
514 else
515 {
516
517 BranchNode branchNode = node;
518 List<ExprNode> children = node.getChildren();
519
520
521
522
523 List<ExprNode> newChildren = new ArrayList<ExprNode>( children.size() );
524
525
526 for ( int i = 0; i < children.size(); i++ )
527 {
528 ExprNode child = children.get( i );
529
530 ExprNode result = ( ExprNode ) visit( child );
531
532 if ( result != null )
533 {
534
535
536 newChildren.add( result );
537 }
538 }
539
540 if ( ( branchNode instanceof AndNode ) && ( newChildren.size() != children.size() ) )
541 {
542 return null;
543 }
544
545 if ( newChildren.size() == 0 )
546 {
547
548 return null;
549 }
550 else if ( newChildren.size() == 1 )
551 {
552
553
554 return newChildren.get( 0 );
555 }
556 else
557 {
558 branchNode.setChildren( newChildren );
559 }
560 }
561
562 return node;
563 }
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584 public Object visit( ExprNode node )
585 {
586
587
588
589
590 if ( node instanceof PresenceNode )
591 {
592 return visitPresenceNode( ( PresenceNode ) node );
593 }
594
595
596
597
598
599 else if ( node instanceof BranchNode )
600 {
601 return visitBranchNode( ( BranchNode ) node );
602 }
603
604
605
606
607
608
609 else if ( node instanceof SimpleNode )
610 {
611 return visitSimpleNode( ( SimpleNode ) node );
612 }
613 else if ( node instanceof ExtensibleNode )
614 {
615 return visitExtensibleNode( ( ExtensibleNode ) node );
616 }
617 else if ( node instanceof SubstringNode )
618 {
619 return visitSubstringNode( ( SubstringNode ) node );
620 }
621 else
622 {
623 return null;
624 }
625 }
626
627
628 public boolean canVisit( ExprNode node )
629 {
630 return true;
631 }
632
633
634 public boolean isPrefix()
635 {
636 return false;
637 }
638
639
640 public List<ExprNode> getOrder( BranchNode node, List<ExprNode> children )
641 {
642 return children;
643 }
644 }