001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.directory.server.core.integ; 020 021 022import java.io.File; 023import java.io.IOException; 024import java.util.ArrayList; 025import java.util.List; 026 027import javax.naming.NamingException; 028import javax.naming.ldap.LdapContext; 029import javax.naming.ldap.LdapName; 030 031import org.apache.directory.api.ldap.model.constants.AuthenticationLevel; 032import org.apache.directory.api.ldap.model.constants.SchemaConstants; 033import org.apache.directory.api.ldap.model.entry.Attribute; 034import org.apache.directory.api.ldap.model.entry.DefaultAttribute; 035import org.apache.directory.api.ldap.model.entry.DefaultEntry; 036import org.apache.directory.api.ldap.model.entry.DefaultModification; 037import org.apache.directory.api.ldap.model.entry.Modification; 038import org.apache.directory.api.ldap.model.entry.ModificationOperation; 039import org.apache.directory.api.ldap.model.exception.LdapException; 040import org.apache.directory.api.ldap.model.ldif.ChangeType; 041import org.apache.directory.api.ldap.model.ldif.LdifEntry; 042import org.apache.directory.api.ldap.model.ldif.LdifReader; 043import org.apache.directory.api.ldap.model.name.Dn; 044import org.apache.directory.api.ldap.model.name.Rdn; 045import org.apache.directory.api.ldap.model.schema.registries.Schema; 046import org.apache.directory.api.util.FileUtils; 047import org.apache.directory.api.util.Network; 048import org.apache.directory.api.util.Strings; 049import org.apache.directory.ldap.client.api.LdapConnection; 050import org.apache.directory.ldap.client.api.LdapNetworkConnection; 051import org.apache.directory.server.constants.ServerDNConstants; 052import org.apache.directory.server.core.api.CoreSession; 053import org.apache.directory.server.core.api.DirectoryService; 054import org.apache.directory.server.core.api.LdapCoreSessionConnection; 055import org.apache.directory.server.core.api.LdapPrincipal; 056import org.apache.directory.server.core.jndi.ServerLdapContext; 057import org.apache.directory.server.i18n.I18n; 058import org.apache.directory.server.ldap.LdapServer; 059import org.slf4j.Logger; 060import org.slf4j.LoggerFactory; 061 062 063/** 064 * Integration test utility methods. 065 * 066 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 067 */ 068public class IntegrationUtils 069{ 070 /** The class logger */ 071 private static final Logger LOG = LoggerFactory.getLogger( IntegrationUtils.class ); 072 073 private static final List<LdapConnection> OPEN_CONNECTIONS = new ArrayList<>(); 074 075 076 /** 077 * Deletes the working directory. 078 * 079 * @param wkdir the working directory to delete 080 * @throws IOException if the working directory cannot be deleted 081 */ 082 public static void doDelete( File wkdir ) throws IOException 083 { 084 if ( wkdir.exists() ) 085 { 086 try 087 { 088 FileUtils.deleteDirectory( wkdir ); 089 } 090 catch ( IOException e ) 091 { 092 LOG.error( I18n.err( I18n.ERR_115 ), e ); 093 } 094 } 095 if ( wkdir.exists() ) 096 { 097 throw new IOException( I18n.err( I18n.ERR_116, wkdir ) ); 098 } 099 } 100 101 102 /** 103 * Inject an ldif String into the server. Dn must be relative to the 104 * root. 105 * 106 * @param service the directory service to use 107 * @param ldif the ldif containing entries to add to the server. 108 * @throws NamingException if there is a problem adding the entries from the LDIF 109 */ 110 public static void injectEntries( DirectoryService service, String ldif ) throws Exception 111 { 112 try ( LdifReader reader = new LdifReader() ) 113 { 114 List<LdifEntry> entries = reader.parseLdif( ldif ); 115 116 for ( LdifEntry entry : entries ) 117 { 118 if ( entry.isEntry() ) 119 { 120 service.getAdminSession().add( 121 new DefaultEntry( service.getSchemaManager(), entry.getEntry() ) ); 122 } 123 else if ( entry.isChangeModify() ) 124 { 125 service.getAdminSession().modify( 126 entry.getDn(), entry.getModifications() ); 127 } 128 else 129 { 130 String message = I18n.err( I18n.ERR_117, entry.getChangeType() ); 131 LOG.error( message ); 132 throw new NamingException( message ); 133 } 134 } 135 } 136 } 137 138 139 public static LdifEntry getUserAddLdif() throws LdapException 140 { 141 return getUserAddLdif( "uid=akarasulu,ou=users,ou=system", Strings.getBytesUtf8( "test" ), 142 "Alex Karasulu", "Karasulu" ); 143 } 144 145 146 public static LdapContext getContext( String principalDn, DirectoryService service, String dn ) 147 throws Exception 148 { 149 if ( principalDn == null ) 150 { 151 principalDn = ""; 152 } 153 154 Dn userDn = new Dn( service.getSchemaManager(), principalDn ); 155 LdapPrincipal principal = new LdapPrincipal( service.getSchemaManager(), userDn, AuthenticationLevel.SIMPLE ); 156 157 if ( dn == null ) 158 { 159 dn = ""; 160 } 161 162 CoreSession session = service.getSession( principal ); 163 164 return new ServerLdapContext( service, session, new LdapName( dn ) ); 165 } 166 167 168 public static CoreSession getCoreSession( String principalDn, DirectoryService service, String dn ) 169 throws LdapException 170 { 171 if ( principalDn == null ) 172 { 173 principalDn = ""; 174 } 175 176 Dn userDn = new Dn( service.getSchemaManager(), principalDn ); 177 LdapPrincipal principal = new LdapPrincipal( service.getSchemaManager(), userDn, AuthenticationLevel.SIMPLE ); 178 179 return service.getSession( principal ); 180 } 181 182 183 public static LdapContext getSystemContext( DirectoryService service ) throws Exception 184 { 185 return getContext( ServerDNConstants.ADMIN_SYSTEM_DN, service, ServerDNConstants.SYSTEM_DN ); 186 } 187 188 189 public static LdapContext getSchemaContext( DirectoryService service ) throws Exception 190 { 191 return getContext( ServerDNConstants.ADMIN_SYSTEM_DN, service, SchemaConstants.OU_SCHEMA ); 192 } 193 194 195 public static LdapContext getRootContext( DirectoryService service ) throws Exception 196 { 197 return getContext( ServerDNConstants.ADMIN_SYSTEM_DN, service, "" ); 198 } 199 200 201 public static void apply( DirectoryService service, LdifEntry entry ) throws LdapException 202 { 203 Dn dn = entry.getDn(); 204 CoreSession session = service.getAdminSession(); 205 206 switch ( entry.getChangeType().getChangeType() ) 207 { 208 case ( ChangeType.ADD_ORDINAL ): 209 session.add( 210 new DefaultEntry( service.getSchemaManager(), entry.getEntry() ) ); 211 break; 212 213 case ( ChangeType.DELETE_ORDINAL ): 214 session.delete( dn ); 215 break; 216 217 case ( ChangeType.MODDN_ORDINAL ): 218 case ( ChangeType.MODRDN_ORDINAL ): 219 Rdn newRdn = new Rdn( entry.getNewRdn() ); 220 221 if ( entry.getNewSuperior() != null ) 222 { 223 // It's a move. The superior have changed 224 // Let's see if it's a rename too 225 Rdn oldRdn = dn.getRdn(); 226 Dn newSuperior = new Dn( entry.getNewSuperior() ); 227 228 if ( dn.size() == 0 ) 229 { 230 throw new IllegalStateException( I18n.err( I18n.ERR_475 ) ); 231 } 232 else if ( oldRdn.equals( newRdn ) ) 233 { 234 // Same rdn : it's a move 235 session.move( dn, newSuperior ); 236 } 237 else 238 { 239 // it's a move and rename 240 session.moveAndRename( dn, newSuperior, newRdn, entry.isDeleteOldRdn() ); 241 } 242 } 243 else 244 { 245 // it's a rename 246 session.rename( dn, newRdn, entry.isDeleteOldRdn() ); 247 } 248 249 break; 250 251 case ( ChangeType.MODIFY_ORDINAL ): 252 session.modify( dn, entry.getModifications() ); 253 break; 254 255 default: 256 throw new IllegalStateException( I18n.err( I18n.ERR_476, entry.getChangeType() ) ); 257 } 258 } 259 260 261 public static LdifEntry getUserAddLdif( String dnstr, byte[] password, String cn, String sn ) 262 throws LdapException 263 { 264 Dn dn = new Dn( dnstr ); 265 LdifEntry ldif = new LdifEntry(); 266 ldif.setDn( dnstr ); 267 ldif.setChangeType( ChangeType.Add ); 268 269 Attribute attr = new DefaultAttribute( "objectClass", 270 "top", "person", "organizationalPerson", "inetOrgPerson" ); 271 ldif.addAttribute( attr ); 272 273 attr = new DefaultAttribute( "ou", "Engineering", "People" ); 274 ldif.addAttribute( attr ); 275 276 String uid = dn.getRdn().getValue(); 277 ldif.putAttribute( "uid", uid ); 278 279 ldif.putAttribute( "l", "Bogusville" ); 280 ldif.putAttribute( "cn", cn ); 281 ldif.putAttribute( "sn", sn ); 282 ldif.putAttribute( "mail", uid + "@apache.org" ); 283 ldif.putAttribute( "telephoneNumber", "+1 408 555 4798" ); 284 ldif.putAttribute( "facsimileTelephoneNumber", "+1 408 555 9751" ); 285 ldif.putAttribute( "roomnumber", "4612" ); 286 ldif.putAttribute( "userPassword", password ); 287 288 String givenName = cn.split( " " )[0]; 289 ldif.putAttribute( "givenName", givenName ); 290 291 return ldif; 292 } 293 294 295 // ----------------------------------------------------------------------- 296 // Enable/Disable Schema Tests 297 // ----------------------------------------------------------------------- 298 299 public static void enableSchema( DirectoryService service, String schemaName ) throws LdapException 300 { 301 LdapConnection connection = getAdminConnection( service ); 302 303 // now enable the test schema 304 connection.modify( "cn=" + schemaName + ",ou=schema", 305 new DefaultModification( 306 ModificationOperation.REPLACE_ATTRIBUTE, "m-disabled", "FALSE" ) ); 307 } 308 309 310 public static void disableSchema( DirectoryService service, String schemaName ) throws LdapException 311 { 312 LdapConnection connection = getAdminConnection( service ); 313 314 // now enable the test schema 315 Modification mod = new DefaultModification( 316 ModificationOperation.REPLACE_ATTRIBUTE, "m-disabled", "TRUE" ); 317 318 connection.modify( "cn=" + schemaName + ",ou=schema", mod ); 319 } 320 321 322 /** 323 * A helper method which tells if a schema is disabled. 324 * 325 * @param service The Directory Service 326 * @param schemaName The name of the Schema to check 327 * @return <tt>true</tt> if the schema is enabled 328 */ 329 public static boolean isDisabled( DirectoryService service, String schemaName ) 330 { 331 Schema schema = service.getSchemaManager().getLoadedSchema( schemaName ); 332 333 return ( schema == null ) || schema.isDisabled(); 334 } 335 336 337 /** 338 * A helper method which tells if a schema is loaded. 339 * 340 * @param service The Directory Service 341 * @param schemaName The schema to check 342 * @return <tt>true</tt> if the schema is loaded 343 */ 344 public static boolean isLoaded( DirectoryService service, String schemaName ) 345 { 346 Schema schema = service.getSchemaManager().getLoadedSchema( schemaName ); 347 348 return ( schema != null ); 349 } 350 351 352 /** 353 * A helper method which tells if a schema is enabled. A shema must be 354 * loaded and enabled. 355 * 356 * @param service The Directory Service 357 * @param schemaName The name of the Schema to check 358 * @return <tt>true</tt> if the schema is enabled 359 */ 360 public static boolean isEnabled( DirectoryService service, String schemaName ) 361 { 362 Schema schema = service.getSchemaManager().getLoadedSchema( schemaName ); 363 364 return ( schema != null ) && schema.isEnabled(); 365 } 366 367 368 /** 369 * Gets a LdapCoreSessionConnection bound using the default admin Dn uid=admin,ou=system and password "secret" 370 * 371 * @param dirService The Directory Service to be connected to 372 * @return A LdapCoreSessionConnection instance 373 * @exception LdapException If the connection could not be established. 374 */ 375 public static LdapConnection getAdminConnection( DirectoryService dirService ) throws LdapException 376 { 377 return getConnectionAs( dirService, ServerDNConstants.ADMIN_SYSTEM_DN, "secret" ); 378 } 379 380 381 /** 382 * Gets a LdapCoreSessionConnection bound using a user's DN and a password. We will bind using those 383 * credentials. 384 * 385 * @param dirService The Directory Service to be connected to 386 * @param dn The User's DN as a String 387 * @param password The User's password as a String 388 * @return A LdapCoreSessionConnection instance 389 * @exception LdapException If the connection could not be established. 390 */ 391 public static LdapConnection getConnectionAs( DirectoryService dirService, String dn, String password ) 392 throws LdapException 393 { 394 return getConnectionAs( dirService, new Dn( dn ), password ); 395 } 396 397 398 /** 399 * Gets a LdapCoreSessionConnection bound using a user's DN and a password. We will bind using those 400 * credentials. 401 * 402 * @param dirService The Directory Service to be connected to 403 * @param dn The User's DN 404 * @param password The User's password as a String 405 * @return A LdapCoreSessionConnection instance 406 * @exception LdapException If the connection could not be established. 407 */ 408 public static LdapConnection getConnectionAs( DirectoryService dirService, Dn dn, String password ) 409 throws LdapException 410 { 411 LdapCoreSessionConnection connection = new LdapCoreSessionConnection(); 412 413 connection.setDirectoryService( dirService ); 414 415 connection.bind( dn, password ); 416 417 return connection; 418 } 419 420 421 /** 422 * Gets a LdapNetworkConnection bound using a user's DN and a password. We will bind using those 423 * credentials. 424 * 425 * @param host The server to connect to 426 * @param port The port to connect on 427 * @param dn The User's DN as a String 428 * @param password The User's password as a String 429 * @return A LdapNetworkConnection instance 430 * @exception LdapException If the connection could not be established. 431 */ 432 public static LdapConnection getNetworkConnectionAs( String host, int port, String dn, String password ) 433 throws LdapException 434 { 435 LdapConnection connection = new LdapNetworkConnection( host, port ); 436 437 connection.bind( dn, password ); 438 OPEN_CONNECTIONS.add( connection ); 439 440 return connection; 441 } 442 443 444 /** 445 * Gets an anonymous LdapNetworkConnection 446 * 447 * @param ldapServer The LdapServer to be connected to 448 * @return A LdapNetworkConnection instance 449 * @exception LdapException If the connection could not be established. 450 */ 451 public static LdapConnection getAnonymousNetworkConnection( LdapServer ldapServer ) throws LdapException 452 { 453 return getAnonymousNetworkConnection( Network.LOOPBACK_HOSTNAME, ldapServer.getPort() ); 454 } 455 456 457 /** 458 * Gets an anonymous LdapNetworkConnection 459 * 460 * @param host The server to connect to 461 * @param port The port to connect on 462 * @return A LdapNetworkConnection instance 463 * @exception LdapException If the connection could not be established. 464 */ 465 public static LdapConnection getAnonymousNetworkConnection( String host, int port ) throws LdapException 466 { 467 LdapConnection connection = new LdapNetworkConnection( host, port ); 468 connection.bind(); 469 470 OPEN_CONNECTIONS.add( connection ); 471 472 return connection; 473 } 474 475 476 /** 477 * Gets a LdapNetworkConnection bound to the Admin user (uid=admin,ou=system). 478 * 479 * @param ldapServer The LdapServer to be connected to 480 * @return A LdapNetworkConnection instance 481 * @exception LdapException If the connection could not be established. 482 */ 483 public static LdapConnection getAdminNetworkConnection( LdapServer ldapServer ) throws LdapException 484 { 485 LdapConnection connection = new LdapNetworkConnection( Network.LOOPBACK_HOSTNAME, ldapServer.getPort() ); 486 487 connection.setTimeOut( 30000L ); 488 connection.bind( ServerDNConstants.ADMIN_SYSTEM_DN, "secret" ); 489 490 OPEN_CONNECTIONS.add( connection ); 491 492 return connection; 493 } 494 495 496 /** 497 * Gets a LdapNetworkConnection bound using a user's DN and a password. We will bind using those 498 * credentials. We specify a LdapServer instance too. 499 * 500 * @param ldapServer The LdapServer to be connected to 501 * @param userDn The User's DN as a String 502 * @param password The User's password as a String 503 * @return A LdapNetworkConnection instance 504 * @exception LdapException If the connection could not be established. 505 */ 506 public static LdapConnection getNetworkConnectionAs( LdapServer ldapServer, String userDn, String password ) 507 throws LdapException 508 { 509 return getNetworkConnectionAs( Network.LOOPBACK_HOSTNAME, ldapServer.getPort(), userDn, password ); 510 } 511 512 513 public static void closeConnections() 514 { 515 516 for ( LdapConnection con : OPEN_CONNECTIONS ) 517 { 518 if ( con == null ) 519 { 520 continue; 521 } 522 523 try 524 { 525 if ( con.isConnected() ) 526 { 527 con.close(); 528 } 529 } 530 catch ( Exception e ) 531 { 532 // shouldn't happen, but print the stacktrace so that less pain during development to find the cause 533 e.printStackTrace(); 534 } 535 } 536 537 OPEN_CONNECTIONS.clear(); 538 } 539}