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.schema;
21
22
23 import org.apache.directory.server.constants.MetaSchemaConstants;
24 import org.apache.directory.server.core.DirectoryService;
25 import org.apache.directory.server.core.integ.CiRunner;
26 import static org.apache.directory.server.core.integ.IntegrationUtils.getRootContext;
27 import static org.apache.directory.server.core.integ.IntegrationUtils.getSchemaContext;
28 import org.apache.directory.server.schema.registries.MatchingRuleRegistry;
29 import org.apache.directory.server.schema.registries.SyntaxRegistry;
30 import org.apache.directory.shared.ldap.constants.SchemaConstants;
31 import org.apache.directory.shared.ldap.exception.LdapInvalidNameException;
32 import org.apache.directory.shared.ldap.exception.LdapOperationNotSupportedException;
33 import org.apache.directory.shared.ldap.message.ResultCodeEnum;
34 import org.apache.directory.shared.ldap.name.LdapDN;
35 import org.apache.directory.shared.ldap.schema.Syntax;
36 import org.apache.directory.shared.ldap.schema.syntax.AcceptAllSyntaxChecker;
37 import static org.junit.Assert.assertEquals;
38 import static org.junit.Assert.assertTrue;
39 import static org.junit.Assert.assertFalse;
40 import static org.junit.Assert.fail;
41 import org.junit.Test;
42 import org.junit.runner.RunWith;
43
44 import javax.naming.NamingEnumeration;
45 import javax.naming.NamingException;
46 import javax.naming.directory.Attribute;
47 import javax.naming.directory.Attributes;
48 import javax.naming.directory.BasicAttribute;
49 import javax.naming.directory.BasicAttributes;
50 import javax.naming.directory.DirContext;
51 import javax.naming.directory.ModificationItem;
52 import javax.naming.directory.SearchControls;
53 import javax.naming.directory.SearchResult;
54
55 import java.util.ArrayList;
56 import java.util.List;
57
58
59
60
61
62
63
64
65
66 @RunWith ( CiRunner.class )
67 public class MetaSyntaxHandlerIT
68 {
69 private static final String DESCRIPTION0 = "A test normalizer";
70 private static final String DESCRIPTION1 = "An alternate description";
71
72 private static final String OID = "1.3.6.1.4.1.18060.0.4.0.0.100000";
73 private static final String NEW_OID = "1.3.6.1.4.1.18060.0.4.0.0.100001";
74
75 private static final String MR_OID = "1.3.6.1.4.1.18060.0.4.0.1.100000";
76 private static final String MR_DESCRIPTION = "A test matchingRule";
77
78 private static final String SUBSCHEMA_SUBENTRY = "subschemaSubentry";
79
80
81 public static DirectoryService service;
82
83
84 private static SyntaxRegistry getSyntaxRegistry()
85 {
86 return service.getRegistries().getSyntaxRegistry();
87 }
88
89
90 private static MatchingRuleRegistry getMatchingRuleRegistry()
91 {
92 return service.getRegistries().getMatchingRuleRegistry();
93 }
94
95
96
97
98
99
100
101
102
103 private LdapDN getSyntaxContainer( String schemaName ) throws Exception
104 {
105 return new LdapDN( "ou=syntaxes,cn=" + schemaName );
106 }
107
108
109
110
111
112
113
114 @Test
115 public void testAddSyntax() throws Exception
116 {
117 Attributes attrs = new BasicAttributes( true );
118 Attribute oc = new BasicAttribute( SchemaConstants.OBJECT_CLASS_AT, "top" );
119 oc.add( MetaSchemaConstants.META_TOP_OC );
120 oc.add( MetaSchemaConstants.META_SYNTAX_OC );
121 attrs.put( oc );
122 attrs.put( MetaSchemaConstants.M_OID_AT, OID );
123 attrs.put( MetaSchemaConstants.M_DESCRIPTION_AT, DESCRIPTION0 );
124
125 LdapDN dn = getSyntaxContainer( "apachemeta" );
126 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
127 createDummySyntaxChecker( OID, "apachemeta" );
128 getSchemaContext( service ).createSubcontext( dn, attrs );
129
130 assertTrue( getSyntaxRegistry().hasSyntax( OID ) );
131 assertEquals( getSyntaxRegistry().getSchemaName( OID ), "apachemeta" );
132 }
133
134
135 @Test
136 public void testDeleteSyntax() throws Exception
137 {
138 LdapDN dn = getSyntaxContainer( "apachemeta" );
139 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
140 testAddSyntax();
141
142 getSchemaContext( service ).destroySubcontext( dn );
143
144 assertFalse( "syntax should be removed from the registry after being deleted",
145 getSyntaxRegistry().hasSyntax( OID ) );
146
147
148 try
149 {
150 getSyntaxRegistry().lookup( OID );
151 fail( "syntax lookup should fail after deleting it" );
152 }
153 catch( NamingException e )
154 {
155 }
156 }
157
158
159 @Test
160 public void testRenameSyntax() throws Exception
161 {
162 LdapDN dn = getSyntaxContainer( "apachemeta" );
163 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
164 testAddSyntax();
165
166 LdapDN newdn = getSyntaxContainer( "apachemeta" );
167 newdn.add( MetaSchemaConstants.M_OID_AT + "=" + NEW_OID );
168 getSchemaContext( service ).rename( dn, newdn );
169
170 assertFalse( "old syntax OID should be removed from the registry after being renamed",
171 getSyntaxRegistry().hasSyntax( OID ) );
172
173
174 try
175 {
176 getSyntaxRegistry().lookup( OID );
177 fail( "syntax lookup should fail after deleting the syntax" );
178 }
179 catch( NamingException e )
180 {
181 }
182
183 assertTrue( getSyntaxRegistry().hasSyntax( NEW_OID ) );
184 }
185
186
187 @Test
188 public void testMoveSyntax() throws Exception
189 {
190 testAddSyntax();
191
192 LdapDN dn = getSyntaxContainer( "apachemeta" );
193 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
194
195 LdapDN newdn = getSyntaxContainer( "apache" );
196 newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
197
198 getSchemaContext( service ).rename( dn, newdn );
199
200 assertTrue( "syntax OID should still be present",
201 getSyntaxRegistry().hasSyntax( OID ) );
202
203 assertEquals( "syntax schema should be set to apache not apachemeta",
204 getSyntaxRegistry().getSchemaName( OID ), "apache" );
205 }
206
207
208 @Test
209 public void testMoveSyntaxAndChangeRdn() throws Exception
210 {
211 testAddSyntax();
212
213 LdapDN dn = getSyntaxContainer( "apachemeta" );
214 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
215
216 LdapDN newdn = getSyntaxContainer( "apache" );
217 newdn.add( MetaSchemaConstants.M_OID_AT + "=" + NEW_OID );
218
219 getSchemaContext( service ).rename( dn, newdn );
220
221 assertFalse( "old syntax OID should NOT be present",
222 getSyntaxRegistry().hasSyntax( OID ) );
223
224 assertTrue( "new syntax OID should be present",
225 getSyntaxRegistry().hasSyntax( NEW_OID ) );
226
227 assertEquals( "syntax with new oid should have schema set to apache NOT apachemeta",
228 getSyntaxRegistry().getSchemaName( NEW_OID ), "apache" );
229 }
230
231
232 @Test
233 public void testModifySyntaxWithModificationItems() throws Exception
234 {
235 testAddSyntax();
236
237 Syntax syntax = getSyntaxRegistry().lookup( OID );
238 assertEquals( syntax.getDescription(), DESCRIPTION0 );
239
240 LdapDN dn = getSyntaxContainer( "apachemeta" );
241 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
242
243 ModificationItem[] mods = new ModificationItem[1];
244 Attribute attr = new BasicAttribute( MetaSchemaConstants.M_DESCRIPTION_AT, DESCRIPTION1 );
245 mods[0] = new ModificationItem( DirContext.REPLACE_ATTRIBUTE, attr );
246 getSchemaContext( service ).modifyAttributes( dn, mods );
247
248 assertTrue( "syntax OID should still be present",
249 getSyntaxRegistry().hasSyntax( OID ) );
250
251 assertEquals( "syntax schema should be set to apachemeta",
252 getSyntaxRegistry().getSchemaName( OID ), "apachemeta" );
253
254 syntax = getSyntaxRegistry().lookup( OID );
255 assertEquals( syntax.getDescription(), DESCRIPTION1 );
256 }
257
258
259 @Test
260 public void testModifySyntaxWithAttributes() throws Exception
261 {
262 testAddSyntax();
263
264 Syntax syntax = getSyntaxRegistry().lookup( OID );
265 assertEquals( syntax.getDescription(), DESCRIPTION0 );
266
267 LdapDN dn = getSyntaxContainer( "apachemeta" );
268 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
269
270 Attributes mods = new BasicAttributes( true );
271 mods.put( MetaSchemaConstants.M_DESCRIPTION_AT, DESCRIPTION1 );
272 getSchemaContext( service ).modifyAttributes( dn, DirContext.REPLACE_ATTRIBUTE, mods );
273
274 assertTrue( "syntax OID should still be present",
275 getSyntaxRegistry().hasSyntax( OID ) );
276
277 assertEquals( "syntax schema should be set to apachemeta",
278 getSyntaxRegistry().getSchemaName( OID ), "apachemeta" );
279
280 syntax = getSyntaxRegistry().lookup( OID );
281 assertEquals( syntax.getDescription(), DESCRIPTION1 );
282 }
283
284
285
286
287
288
289
290 @Test
291 public void testDeleteSyntaxWhenInUse() throws Exception
292 {
293 LdapDN dn = getSyntaxContainer( "apachemeta" );
294 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
295 testAddSyntax();
296 addDependeeMatchingRule( OID );
297
298 try
299 {
300 getSchemaContext( service ).destroySubcontext( dn );
301 fail( "should not be able to delete a syntax in use" );
302 }
303 catch( LdapOperationNotSupportedException e )
304 {
305 assertEquals( e.getResultCode(), ResultCodeEnum.UNWILLING_TO_PERFORM );
306 }
307
308 assertTrue( "syntax should still be in the registry after delete failure",
309 getSyntaxRegistry().hasSyntax( OID ) );
310 }
311
312
313 @Test
314 public void testMoveSyntaxWhenInUse() throws Exception
315 {
316 testAddSyntax();
317 addDependeeMatchingRule( OID );
318
319 LdapDN dn = getSyntaxContainer( "apachemeta" );
320 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
321
322 LdapDN newdn = getSyntaxContainer( "apache" );
323 newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
324
325 try
326 {
327 getSchemaContext( service ).rename( dn, newdn );
328 fail( "should not be able to move a syntax in use" );
329 }
330 catch( LdapOperationNotSupportedException e )
331 {
332 assertEquals( e.getResultCode(), ResultCodeEnum.UNWILLING_TO_PERFORM );
333 }
334
335 assertTrue( "syntax should still be in the registry after move failure",
336 getSyntaxRegistry().hasSyntax( OID ) );
337 }
338
339
340 @Test
341 public void testMoveSyntaxAndChangeRdnWhenInUse() throws Exception
342 {
343 testAddSyntax();
344 addDependeeMatchingRule( OID );
345
346 LdapDN dn = getSyntaxContainer( "apachemeta" );
347 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
348
349 LdapDN newdn = getSyntaxContainer( "apache" );
350 newdn.add( MetaSchemaConstants.M_OID_AT + "=" + NEW_OID );
351
352 try
353 {
354 getSchemaContext( service ).rename( dn, newdn );
355 fail( "should not be able to move a syntax in use" );
356 }
357 catch( LdapOperationNotSupportedException e )
358 {
359 assertEquals( e.getResultCode(), ResultCodeEnum.UNWILLING_TO_PERFORM );
360 }
361
362 assertTrue( "syntax should still be in the registry after move failure",
363 getSyntaxRegistry().hasSyntax( OID ) );
364 }
365
366
367
368
369
370
371
372
373
374 private LdapDN getMatchingRuleContainer( String schemaName ) throws Exception
375 {
376 return new LdapDN( "ou=matchingRules,cn=" + schemaName );
377 }
378
379
380 private void addDependeeMatchingRule( String oid ) throws Exception
381 {
382 Attributes attrs = new BasicAttributes( true );
383 Attribute oc = new BasicAttribute( SchemaConstants.OBJECT_CLASS_AT, "top" );
384 oc.add( MetaSchemaConstants.META_TOP_OC );
385 oc.add( MetaSchemaConstants.META_MATCHING_RULE_OC );
386 attrs.put( oc );
387 attrs.put( MetaSchemaConstants.M_OID_AT, MR_OID );
388 attrs.put( MetaSchemaConstants.M_SYNTAX_AT, OID );
389 attrs.put( MetaSchemaConstants.M_DESCRIPTION_AT, MR_DESCRIPTION );
390
391 LdapDN dn = getMatchingRuleContainer( "apachemeta" );
392 dn.add( MetaSchemaConstants.M_OID_AT + "=" + MR_OID );
393 getSchemaContext( service ).createSubcontext( dn, attrs );
394
395 assertTrue( getMatchingRuleRegistry().hasMatchingRule( MR_OID ) );
396 assertEquals( getMatchingRuleRegistry().getSchemaName( MR_OID ), "apachemeta" );
397 }
398
399
400 @Test
401 public void testRenameNormalizerWhenInUse() throws Exception
402 {
403 LdapDN dn = getSyntaxContainer( "apachemeta" );
404 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
405 testAddSyntax();
406 addDependeeMatchingRule( OID );
407
408 LdapDN newdn = getSyntaxContainer( "apachemeta" );
409 newdn.add( MetaSchemaConstants.M_OID_AT + "=" + NEW_OID );
410
411 try
412 {
413 getSchemaContext( service ).rename( dn, newdn );
414 fail( "should not be able to rename a syntax in use" );
415 }
416 catch( LdapOperationNotSupportedException e )
417 {
418 assertEquals( e.getResultCode(), ResultCodeEnum.UNWILLING_TO_PERFORM );
419 }
420
421 assertTrue( "syntax should still be in the registry after rename failure",
422 getSyntaxRegistry().hasSyntax( OID ) );
423 }
424
425
426
427
428
429
430
431 @Test
432 public void testMoveSyntaxToTop() throws Exception
433 {
434 testAddSyntax();
435
436 LdapDN dn = getSyntaxContainer( "apachemeta" );
437 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
438
439 LdapDN top = new LdapDN();
440 top.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
441
442 try
443 {
444 getSchemaContext( service ).rename( dn, top );
445 fail( "should not be able to move a syntax up to ou=schema" );
446 }
447 catch( LdapInvalidNameException e )
448 {
449 assertEquals( e.getResultCode(), ResultCodeEnum.NAMING_VIOLATION );
450 }
451
452 assertTrue( "syntax should still be in the registry after move failure",
453 getSyntaxRegistry().hasSyntax( OID ) );
454 }
455
456
457 @Test
458 public void testMoveSyntaxToComparatorContainer() throws Exception
459 {
460 testAddSyntax();
461
462 LdapDN dn = getSyntaxContainer( "apachemeta" );
463 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
464
465 LdapDN newdn = new LdapDN( "ou=comparators,cn=apachemeta" );
466 newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
467
468 try
469 {
470 getSchemaContext( service ).rename( dn, newdn );
471 fail( "should not be able to move a syntax into comparators container" );
472 }
473 catch( LdapInvalidNameException e )
474 {
475 assertEquals( e.getResultCode(), ResultCodeEnum.NAMING_VIOLATION );
476 }
477
478 assertTrue( "syntax should still be in the registry after move failure",
479 getSyntaxRegistry().hasSyntax( OID ) );
480 }
481
482
483 @Test
484 public void testAddSyntaxToDisabledSchema() throws Exception
485 {
486 Attributes attrs = new BasicAttributes( true );
487 Attribute oc = new BasicAttribute( SchemaConstants.OBJECT_CLASS_AT, "top" );
488 oc.add( MetaSchemaConstants.META_TOP_OC );
489 oc.add( MetaSchemaConstants.META_SYNTAX_OC );
490 attrs.put( oc );
491 attrs.put( MetaSchemaConstants.M_OID_AT, OID );
492 attrs.put( MetaSchemaConstants.M_DESCRIPTION_AT, DESCRIPTION0 );
493
494
495 LdapDN dn = getSyntaxContainer( "nis" );
496 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
497 createDummySyntaxChecker( OID, "nis" );
498 getSchemaContext( service ).createSubcontext( dn, attrs );
499
500 assertFalse( "adding new syntax to disabled schema should not register it into the registries",
501 getSyntaxRegistry().hasSyntax( OID ) );
502 }
503
504
505 @Test
506 public void testMoveSyntaxToDisabledSchema() throws Exception
507 {
508 testAddSyntax();
509
510 LdapDN dn = getSyntaxContainer( "apachemeta" );
511 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
512
513
514 LdapDN newdn = getSyntaxContainer( "nis" );
515 newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
516
517 getSchemaContext( service ).rename( dn, newdn );
518
519 assertFalse( "syntax OID should no longer be present",
520 getSyntaxRegistry().hasSyntax( OID ) );
521 }
522
523
524 @Test
525 public void testMoveSyntaxToEnabledSchema() throws Exception
526 {
527 testAddSyntaxToDisabledSchema();
528
529
530 LdapDN dn = getSyntaxContainer( "nis" );
531 dn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
532
533 assertFalse( "syntax OID should NOT be present when added to disabled nis schema",
534 getSyntaxRegistry().hasSyntax( OID ) );
535
536 LdapDN newdn = getSyntaxContainer( "apachemeta" );
537 newdn.add( MetaSchemaConstants.M_OID_AT + "=" + OID );
538
539 getSchemaContext( service ).rename( dn, newdn );
540
541 assertTrue( "syntax OID should be present when moved to enabled schema",
542 getSyntaxRegistry().hasSyntax( OID ) );
543
544 assertEquals( "syntax should be in apachemeta schema after move",
545 getSyntaxRegistry().getSchemaName( OID ), "apachemeta" );
546 }
547
548
549 private void createDummySyntaxChecker( String oid, String schema ) throws Exception
550 {
551 List<String> descriptions = new ArrayList<String>();
552 descriptions.add( "( " + oid + " DESC 'bogus desc' FQCN " + AcceptAllSyntaxChecker.class.getName()
553 + " X-SCHEMA '" + schema + "' )" );
554 modify( DirContext.ADD_ATTRIBUTE, descriptions, "syntaxCheckers" );
555 }
556
557
558 private void modify( int op, List<String> descriptions, String opAttr ) throws Exception
559 {
560 LdapDN dn = new LdapDN( getSubschemaSubentryDN() );
561 Attribute attr = new BasicAttribute( opAttr );
562 for ( String description : descriptions )
563 {
564 attr.add( description );
565 }
566
567 Attributes mods = new BasicAttributes( true );
568 mods.put( attr );
569
570 getRootContext( service ).modifyAttributes( dn, op, mods );
571 }
572
573
574
575
576
577
578
579
580 private String getSubschemaSubentryDN() throws Exception
581 {
582 SearchControls controls = new SearchControls();
583 controls.setSearchScope( SearchControls.OBJECT_SCOPE );
584 controls.setReturningAttributes( new String[]{ SUBSCHEMA_SUBENTRY } );
585
586 NamingEnumeration<SearchResult> results = getRootContext( service ).search(
587 "", "(objectClass=*)", controls );
588 SearchResult result = results.next();
589 results.close();
590 Attribute subschemaSubentry = result.getAttributes().get( SUBSCHEMA_SUBENTRY );
591 return ( String ) subschemaSubentry.get();
592 }
593 }