| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * https://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| */ |
| |
| package org.apache.directory.ldap.client.api; |
| |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.PrintStream; |
| import java.io.Writer; |
| import java.nio.charset.Charset; |
| import java.nio.file.Files; |
| import java.nio.file.Paths; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.apache.directory.api.ldap.model.constants.SchemaConstants; |
| import org.apache.directory.api.ldap.model.entry.Attribute; |
| import org.apache.directory.api.ldap.model.entry.DefaultAttribute; |
| import org.apache.directory.api.ldap.model.entry.DefaultEntry; |
| import org.apache.directory.api.ldap.model.entry.DefaultModification; |
| import org.apache.directory.api.ldap.model.entry.Entry; |
| import org.apache.directory.api.ldap.model.entry.Modification; |
| import org.apache.directory.api.ldap.model.entry.Value; |
| import org.apache.directory.api.ldap.model.exception.LdapException; |
| import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException; |
| import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException; |
| import org.apache.directory.api.ldap.model.ldif.ChangeType; |
| import org.apache.directory.api.ldap.model.ldif.LdifEntry; |
| import org.apache.directory.api.ldap.model.ldif.LdifReader; |
| import org.apache.directory.api.ldap.model.ldif.LdifUtils; |
| import org.apache.directory.api.ldap.model.ldif.anonymizer.Anonymizer; |
| import org.apache.directory.api.ldap.model.ldif.anonymizer.BinaryAnonymizer; |
| import org.apache.directory.api.ldap.model.ldif.anonymizer.CaseSensitiveStringAnonymizer; |
| import org.apache.directory.api.ldap.model.ldif.anonymizer.IntegerAnonymizer; |
| import org.apache.directory.api.ldap.model.ldif.anonymizer.StringAnonymizer; |
| import org.apache.directory.api.ldap.model.ldif.anonymizer.TelephoneNumberAnonymizer; |
| import org.apache.directory.api.ldap.model.name.Ava; |
| import org.apache.directory.api.ldap.model.name.Dn; |
| import org.apache.directory.api.ldap.model.name.Rdn; |
| import org.apache.directory.api.ldap.model.schema.AttributeType; |
| import org.apache.directory.api.ldap.model.schema.LdapSyntax; |
| import org.apache.directory.api.ldap.model.schema.SchemaManager; |
| import org.apache.directory.api.ldap.model.schema.syntaxCheckers.DnSyntaxChecker; |
| import org.apache.directory.api.ldap.model.schema.syntaxCheckers.NameAndOptionalUIDSyntaxChecker; |
| import org.apache.directory.api.ldap.schema.manager.impl.DefaultSchemaManager; |
| |
| |
| /** |
| * Anonymize the content of a LDIF file. |
| * |
| * We will replace the values of the defined attributes with random chars. There are a default |
| * list of attributes that are going to be anonymized : |
| * <ul> |
| * <li>userPassword</li> |
| * <li>displayName</li> |
| * <li>givenName</li> |
| * <li>surName</li> |
| * <li>homePhone</li> |
| * <li>homePostalAddress</li> |
| * <li>jpegPhoto</li> |
| * <li>labeledURI</li> |
| * <li>mail</li> |
| * <li>manager</li> |
| * <li>mobile</li> |
| * <li>organizationName</li> |
| * <li>pager</li> |
| * <li>photo</li> |
| * <li>secretary</li> |
| * <li>uid</li> |
| * <li>userCertificate</li> |
| * <li>userPKCS12</li> |
| * <li>userSMIMECertificate</li> |
| * <li>x500UniqueIdentifier</li> |
| * <li>carLicense</li> |
| * <li>host</li> |
| * <li>locality</li> |
| * <li>organizationName</li> |
| * <li>organizationalUnitName</li> |
| * <li>seelAlso</li> |
| * <li>homeDirectory</li> |
| * <li>uidNumber</li> |
| * <li>gidNumber</li> |
| * <li>commonName</li> |
| * <li>gecos</li> |
| * <li>description</li> |
| * <li>memberUid</li> |
| * </ul> |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| public class LdifAnonymizer |
| { |
| /** The map that stores the anonymized values associated to the original value */ |
| private Map<Value, Value> valueMap = new HashMap<>(); |
| |
| /** The set that contains all the values we already have anonymized */ |
| private Set<Value> valueSet = new HashSet<>(); |
| |
| /** The latest anonymized String value Map */ |
| private Map<Integer, String> latestStringMap; |
| |
| /** The latest anonymized byte[] value Map */ |
| private Map<Integer, byte[]> latestBytesMap; |
| |
| /** The map of AttributeType'sOID we want to anonymize. They are all associated with anonymizers */ |
| private Map<String, Anonymizer> attributeAnonymizers = new HashMap<>(); |
| |
| /** The list of existing NamingContexts */ |
| private Set<Dn> namingContexts = new HashSet<>(); |
| |
| /** The schemaManager */ |
| private SchemaManager schemaManager; |
| |
| /** The PrintStream used to write informations about the processing */ |
| private PrintStream out = null; |
| |
| /** |
| * Creates a default instance of LdifAnonymizer. The list of anonymized attribute |
| * is set to a default value. |
| * |
| */ |
| public LdifAnonymizer() |
| { |
| try |
| { |
| schemaManager = new DefaultSchemaManager(); |
| } |
| catch ( Exception e ) |
| { |
| println( "Missing a SchemaManager !" ); |
| System.exit( -1 ); |
| } |
| |
| init( null, null, null, null ); |
| } |
| |
| |
| /** |
| * Creates a default instance of LdifAnonymizer. The list of anonymized attribute |
| * is set to a default value. |
| * |
| * @param schemaManager The SchemaManager instance we will use |
| */ |
| public LdifAnonymizer( SchemaManager schemaManager ) |
| { |
| this.schemaManager = schemaManager; |
| |
| init( null, null, null, null ); |
| } |
| |
| |
| /** |
| * Set the PrintStream to use to print information about the processing |
| * |
| * @param out The PrintStream to use |
| */ |
| public void setOut( PrintStream out ) |
| { |
| this.out = out; |
| } |
| |
| |
| /** |
| * Print the string into the PrintStream, with a NL at the end |
| * |
| * @param str The string to print |
| */ |
| private void println( String str ) |
| { |
| if ( out != null ) |
| { |
| out.println( str ); |
| } |
| } |
| |
| |
| /** |
| * Print a nl into the PrintStream |
| */ |
| private void println() |
| { |
| if ( out != null ) |
| { |
| out.println(); |
| } |
| } |
| |
| |
| /** |
| * Initialize the anonymizer, filling the maps we use. |
| * |
| * @param stringLatestValueMap The map of already seen Strings |
| * @param binaryLatestValueMap The map of already seen byte[] |
| * @param integerLatestValueMap The map of already seen Integers |
| * @param telephoneNumberLatestValueMap The map of already seen telephone numbers |
| */ |
| private void init( Map<Integer, String> stringLatestValueMap, Map<Integer, byte[]> binaryLatestValueMap, |
| Map<Integer, String> integerLatestValueMap, Map<Integer, String> telephoneNumberLatestValueMap ) |
| { |
| // Load the anonymizers |
| attributeAnonymizers.put( SchemaConstants.CAR_LICENSE_AT_OID, |
| new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.DOMAIN_COMPONENT_AT_OID, |
| new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.CN_AT_OID, new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.DESCRIPTION_AT_OID, |
| new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.DISPLAY_NAME_AT_OID, |
| new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.GECOS_AT_OID, new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.GID_NUMBER_AT_OID, |
| new IntegerAnonymizer( integerLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.GIVENNAME_AT_OID, |
| new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.HOME_DIRECTORY_AT_OID, |
| new CaseSensitiveStringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.HOME_PHONE_AT_OID, |
| new TelephoneNumberAnonymizer() ); |
| attributeAnonymizers.put( SchemaConstants.HOME_POSTAL_ADDRESS_AT_OID, |
| new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.HOST_AT_OID, new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.HOUSE_IDENTIFIER_AT_OID, |
| new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.JPEG_PHOTO_AT_OID, |
| new BinaryAnonymizer( binaryLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.LABELED_URI_AT_OID, |
| new CaseSensitiveStringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.LOCALITY_NAME_AT_OID, |
| new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.MAIL_AT_OID, new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.MANAGER_AT_OID, new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.MEMBER_UID_AT_OID, |
| new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.MOBILE_AT_OID, new TelephoneNumberAnonymizer() ); |
| attributeAnonymizers.put( SchemaConstants.ORGANIZATION_NAME_AT_OID, |
| new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.ORGANIZATIONAL_UNIT_NAME_AT_OID, |
| new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.PAGER_AT_OID, new TelephoneNumberAnonymizer() ); |
| attributeAnonymizers.put( SchemaConstants.POSTAL_ADDRESS_AT_OID, |
| new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.PHOTO_AT_OID, new BinaryAnonymizer( binaryLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.SECRETARY_AT_OID, |
| new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers |
| .put( SchemaConstants.SEE_ALSO_AT_OID, new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.SN_AT_OID, new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.TELEPHONE_NUMBER_AT_OID, |
| new TelephoneNumberAnonymizer( telephoneNumberLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.UID_AT_OID, new StringAnonymizer( stringLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.UID_NUMBER_AT_OID, |
| new IntegerAnonymizer( integerLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.USER_CERTIFICATE_AT_OID, |
| new BinaryAnonymizer( binaryLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.USER_PASSWORD_AT_OID, |
| new BinaryAnonymizer( binaryLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.USER_PKCS12_AT_OID, |
| new BinaryAnonymizer( binaryLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.USER_SMIME_CERTIFICATE_AT_OID, |
| new BinaryAnonymizer( binaryLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.X500_UNIQUE_IDENTIFIER_AT_OID, |
| new BinaryAnonymizer( binaryLatestValueMap ) ); |
| attributeAnonymizers.put( SchemaConstants.FACSIMILE_TELEPHONE_NUMBER_AT_OID, |
| new TelephoneNumberAnonymizer( telephoneNumberLatestValueMap ) ); |
| } |
| |
| |
| /** |
| * Set the latest value map to a defined anonymizer - if it exists -. |
| * |
| * @param attributeType The AttributeType we are targetting |
| * @param latestValueMap The latest value map for this attribute |
| */ |
| public void setAttributeLatestValueMap( AttributeType attributeType, Map<Integer, ?> latestValueMap ) |
| { |
| Anonymizer anonymizer = attributeAnonymizers.get( attributeType.getOid() ); |
| |
| if ( anonymizer != null ) |
| { |
| if ( attributeType.getSyntax().isHumanReadable() ) |
| { |
| anonymizer.setLatestStringMap( latestValueMap ); |
| } |
| else |
| { |
| anonymizer.setLatestBytesMap( latestValueMap ); |
| } |
| } |
| } |
| |
| |
| /** |
| * Add an attributeType that has to be anonymized |
| * |
| * @param attributeType the AttributeType that has to be anonymized |
| * @throws LdapException If the attributeType cannot be added |
| */ |
| public void addAnonAttributeType( AttributeType attributeType ) throws LdapException |
| { |
| schemaManager.add( attributeType ); |
| LdapSyntax syntax = attributeType.getSyntax(); |
| |
| if ( syntax.isHumanReadable() ) |
| { |
| if ( syntax.getOid().equals( SchemaConstants.INTEGER_SYNTAX ) ) |
| { |
| attributeAnonymizers.put( attributeType.getOid(), new IntegerAnonymizer() ); |
| } |
| else if ( syntax.getOid().equals( SchemaConstants.DIRECTORY_STRING_SYNTAX ) ) |
| { |
| attributeAnonymizers.put( attributeType.getOid(), new StringAnonymizer() ); |
| } |
| else if ( syntax.getOid().equals( SchemaConstants.TELEPHONE_NUMBER_SYNTAX ) ) |
| { |
| attributeAnonymizers.put( attributeType.getOid(), new TelephoneNumberAnonymizer() ); |
| } |
| } |
| else |
| { |
| attributeAnonymizers.put( attributeType.getOid(), new BinaryAnonymizer() ); |
| } |
| } |
| |
| |
| /** |
| * Add an attributeType that has to be anonymized, with its associated anonymizer. |
| * |
| * @param attributeType the AttributeType that has to be anonymized |
| * @param anonymizer the instance of anonymizer to use with this AttributeType |
| * @throws LdapException If the attributeType cannot be added |
| */ |
| public void addAnonAttributeType( AttributeType attributeType, Anonymizer<?> anonymizer ) throws LdapException |
| { |
| schemaManager.add( attributeType ); |
| attributeAnonymizers.put( attributeType.getOid(), anonymizer ); |
| } |
| |
| |
| /** |
| * Remove an attributeType that has to be anonymized |
| * |
| * @param attributeType the AttributeType that we don't want to be anonymized |
| */ |
| public void removeAnonAttributeType( AttributeType attributeType ) |
| { |
| attributeAnonymizers.remove( attributeType.getOid() ); |
| } |
| |
| |
| /** |
| * @return The list of configured anonymizers |
| */ |
| public Map<String, Anonymizer> getAttributeAnonymizers() |
| { |
| return attributeAnonymizers; |
| } |
| |
| /** |
| * Add a new NamingContext |
| * |
| * @param dn The naming context to add |
| * @throws LdapInvalidDnException if it's an invalid naming context |
| */ |
| public void addNamingContext( String dn ) throws LdapInvalidDnException |
| { |
| Dn namingContext = new Dn( schemaManager, dn ); |
| namingContexts.add( namingContext ); |
| } |
| |
| |
| /** |
| * Anonymize an AVA |
| * |
| * @param ava The AVA to anonymize |
| * @return The anonymized AVA |
| * @throws LdapInvalidDnException If the Ava is invalid |
| * @throws LdapInvalidAttributeValueException If teh Ava content is invalid |
| */ |
| private Ava anonymizeAva( Ava ava ) throws LdapInvalidDnException, LdapInvalidAttributeValueException |
| { |
| Value value = ava.getValue(); |
| AttributeType attributeType = ava.getAttributeType(); |
| Value anonymizedValue = valueMap.get( value ); |
| Ava anonymizedAva; |
| |
| if ( anonymizedValue == null ) |
| { |
| Attribute attribute = new DefaultAttribute( attributeType ); |
| attribute.add( value ); |
| Anonymizer anonymizer = attributeAnonymizers.get( attribute.getAttributeType().getOid() ); |
| |
| if ( value.isHumanReadable() ) |
| { |
| if ( anonymizer == null ) |
| { |
| anonymizedAva = new Ava( schemaManager, ava.getType(), value.getString() ); |
| } |
| else |
| { |
| Attribute anonymizedAttribute = anonymizer.anonymize( valueMap, valueSet, attribute ); |
| anonymizedAva = new Ava( schemaManager, ava.getType(), anonymizedAttribute.getString() ); |
| } |
| } |
| else |
| { |
| if ( anonymizer == null ) |
| { |
| anonymizedAva = new Ava( schemaManager, ava.getType(), value.getBytes() ); |
| } |
| else |
| { |
| Attribute anonymizedAttribute = anonymizer.anonymize( valueMap, valueSet, attribute ); |
| |
| anonymizedAva = new Ava( schemaManager, ava.getType(), anonymizedAttribute.getBytes() ); |
| } |
| } |
| } |
| else |
| { |
| if ( value.isHumanReadable() ) |
| { |
| anonymizedAva = new Ava( schemaManager, ava.getType(), anonymizedValue.getString() ); |
| } |
| else |
| { |
| anonymizedAva = new Ava( schemaManager, ava.getType(), anonymizedValue.getBytes() ); |
| } |
| } |
| |
| return anonymizedAva; |
| } |
| |
| |
| /** |
| * Anonymize the entry's DN |
| * |
| * @param entryDn The DN to anonymize |
| * @return The anonymized DN |
| * @throws LdapException If the anonymization failed |
| */ |
| private Dn anonymizeDn( Dn entryDn ) throws LdapException |
| { |
| // Search for the naming context |
| Dn descendant = entryDn; |
| Dn namingContext = null; |
| |
| for ( Dn nc : namingContexts ) |
| { |
| if ( entryDn.isDescendantOf( nc ) ) |
| { |
| descendant = entryDn.getDescendantOf( nc ); |
| namingContext = nc; |
| break; |
| } |
| } |
| |
| Rdn[] anonymizedRdns = new Rdn[entryDn.size()]; |
| int rdnPos = entryDn.size() - 1; |
| |
| if ( namingContext != null ) |
| { |
| // Copy the naming contex |
| for ( Rdn ncRdn : namingContext ) |
| { |
| anonymizedRdns[rdnPos] = ncRdn; |
| rdnPos--; |
| } |
| } |
| |
| // Iterate on all the RDN |
| for ( Rdn rdn : descendant ) |
| { |
| Ava[] anonymizedAvas = new Ava[rdn.size()]; |
| int pos = 0; |
| |
| // Iterate on the AVAs |
| for ( Ava ava : rdn ) |
| { |
| Ava anonymizedAva = anonymizeAva( ava ); |
| anonymizedAvas[pos] = anonymizedAva; |
| pos++; |
| } |
| |
| Rdn anonymizedRdn = new Rdn( schemaManager, anonymizedAvas ); |
| anonymizedRdns[rdnPos] = anonymizedRdn; |
| rdnPos--; |
| } |
| |
| return new Dn( schemaManager, anonymizedRdns ); |
| } |
| |
| |
| /** |
| * Anonymize a LDIF |
| * |
| * @param ldifFile The ldif file to anonymize |
| * @param writer The Writer to use to write the result |
| * @throws LdapException If we got some LDAP related exception |
| * @throws IOException If we had some issue during some IO operations |
| */ |
| public void anonymizeFile( String ldifFile, Writer writer ) throws LdapException, IOException |
| { |
| File inputFile = new File( ldifFile ); |
| |
| if ( !inputFile.exists() ) |
| { |
| println( "Cannot open file " + ldifFile ); |
| return; |
| } |
| |
| try ( LdifReader ldifReader = new LdifReader( inputFile, schemaManager ) ) |
| { |
| int count = 0; |
| List<LdifEntry> errors = new ArrayList<>(); |
| List<String> errorTexts = new ArrayList<>(); |
| |
| try |
| { |
| for ( LdifEntry ldifEntry : ldifReader ) |
| { |
| count++; |
| |
| try |
| { |
| if ( ldifEntry.isEntry() && !ldifEntry.isChangeAdd() ) |
| { |
| // process a full entry. Add changes aren't processed here. |
| Entry newEntry = anonymizeEntry( ldifEntry ); |
| |
| writer.write( LdifUtils.convertToLdif( newEntry ) ); |
| writer.write( "\n" ); |
| } |
| else if ( ldifEntry.isChangeDelete() ) |
| { |
| // A Delete operation |
| LdifEntry newLdifEntry = anonymizeChangeDelete( ldifEntry ); |
| |
| if ( ldifEntry != null ) |
| { |
| writer.write( newLdifEntry.toString() ); |
| writer.write( "\n" ); |
| } |
| } |
| else if ( ldifEntry.isChangeAdd() ) |
| { |
| // A Add operation |
| LdifEntry newLdifEntry = anonymizeChangeAdd( ldifEntry ); |
| |
| if ( ldifEntry != null ) |
| { |
| writer.write( newLdifEntry.toString() ); |
| writer.write( "\n" ); |
| } |
| } |
| else if ( ldifEntry.isChangeModify() ) |
| { |
| // A Modify operation |
| LdifEntry newLdifEntry = anonymizeChangeModify( ldifEntry ); |
| |
| if ( ldifEntry != null ) |
| { |
| writer.write( newLdifEntry.toString() ); |
| writer.write( "\n" ); |
| } |
| } |
| else if ( ldifEntry.isChangeModDn() || ldifEntry.isChangeModRdn() ) |
| { |
| // A MODDN operation |
| LdifEntry newLdifEntry = anonymizeChangeModDn( ldifEntry ); |
| |
| if ( ldifEntry != null ) |
| { |
| writer.write( newLdifEntry.toString() ); |
| writer.write( "\n" ); |
| } |
| } |
| |
| System.out.print( '.' ); |
| |
| if ( count % 100 == 0 ) |
| { |
| println(); |
| } |
| } |
| catch ( Exception e ) |
| { |
| System.out.print( '*' ); |
| |
| if ( count % 100 == 0 ) |
| { |
| println(); |
| } |
| |
| errors.add( ldifEntry ); |
| errorTexts.add( e.getMessage() ); |
| } |
| } |
| |
| println(); |
| |
| if ( !errors.isEmpty() ) |
| { |
| println( "There are " + errors.size() + " bad entries" ); |
| int i = 0; |
| |
| for ( LdifEntry ldifEntry : errors ) |
| { |
| println( "---------------------------------------------------" ); |
| println( "error : " + errorTexts.get( i ) ); |
| println( ldifEntry.getDn().toString() ); |
| i++; |
| } |
| } |
| } |
| finally |
| { |
| println(); |
| |
| if ( !errors.isEmpty() ) |
| { |
| println( "There are " + errors.size() + " bad entries" ); |
| } |
| |
| println( "Nb entries : " + count ); |
| } |
| } |
| } |
| |
| |
| /** |
| * Anonymize a Modify change |
| * |
| * @param ldifEntry The entry to anonymize |
| * @return The anonymized entry |
| * @throws LdapException If the anonymization failed |
| */ |
| private LdifEntry anonymizeChangeModify( LdifEntry ldifEntry ) throws LdapException |
| { |
| Dn entryDn = ldifEntry.getDn(); |
| LdifEntry newLdifEntry = new LdifEntry( schemaManager ); |
| newLdifEntry.setChangeType( ChangeType.Modify ); |
| |
| // Process the DN first |
| Dn anonymizedDn = anonymizeDn( entryDn ); |
| |
| newLdifEntry.setDn( anonymizedDn ); |
| |
| // Now, process the entry's attributes |
| for ( Modification modification : ldifEntry.getModifications() ) |
| { |
| Attribute attribute = modification.getAttribute(); |
| AttributeType attributeType = schemaManager.getAttributeType( attribute.getId() ); |
| |
| if ( attributeType == null ) |
| { |
| System.out.println( "\nUnknown AttributeType : " + attribute.getId() + " for entry " + entryDn ); |
| |
| return null; |
| } |
| |
| attribute.apply( attributeType ); |
| |
| // Deal with the special case of a DN syntax |
| if ( attributeType.getSyntax().getSyntaxChecker() instanceof DnSyntaxChecker ) |
| { |
| Value[] anonymizedValues = new Value[ attribute.size()]; |
| int pos = 0; |
| |
| for ( Value dnValue : modification.getAttribute() ) |
| { |
| Dn dn = new Dn( schemaManager, dnValue.getString() ); |
| Dn newdDn = anonymizeDn( dn ); |
| anonymizedValues[pos++] = new Value( newdDn.toString() ); |
| } |
| |
| Modification anonymizedModification = new DefaultModification( modification.getOperation(), attributeType, anonymizedValues ); |
| newLdifEntry.addModification( anonymizedModification ); |
| } |
| else |
| { |
| Anonymizer anonymizer = attributeAnonymizers.get( attributeType.getOid() ); |
| |
| if ( anonymizer == null ) |
| { |
| newLdifEntry.addModification( modification ); |
| } |
| else |
| { |
| Attribute anonymizedAttribute = anonymizer.anonymize( valueMap, valueSet, attribute ); |
| |
| Modification anonymizedModification = new DefaultModification( modification.getOperation(), anonymizedAttribute ); |
| newLdifEntry.addModification( anonymizedModification ); |
| } |
| } |
| } |
| |
| return newLdifEntry; |
| } |
| |
| |
| /** |
| * Anonymize a Add change |
| * |
| * @param ldifEntry The entry to anonymize |
| * @return The anonymized entry |
| * @throws LdapException If the anonymization failed |
| */ |
| private LdifEntry anonymizeChangeAdd( LdifEntry ldifEntry ) throws LdapException |
| { |
| Dn entryDn = ldifEntry.getDn(); |
| LdifEntry newLdifEntry = new LdifEntry( schemaManager ); |
| newLdifEntry.setChangeType( ChangeType.Add ); |
| |
| // Process the DN first |
| Dn anonymizedDn = anonymizeDn( entryDn ); |
| |
| newLdifEntry.setDn( anonymizedDn ); |
| |
| // Now, process the entry's attributes |
| for ( Attribute attribute : ldifEntry ) |
| { |
| AttributeType attributeType = attribute.getAttributeType(); |
| Attribute anonymizedAttribute = new DefaultAttribute( attributeType ); |
| |
| // Deal with the special case of a DN syntax |
| |
| if ( attributeType.getSyntax().getSyntaxChecker() instanceof DnSyntaxChecker ) |
| { |
| for ( Value dnValue : attribute ) |
| { |
| Dn dn = new Dn( schemaManager, dnValue.getString() ); |
| Dn newdDn = anonymizeDn( dn ); |
| anonymizedAttribute.add( newdDn.toString() ); |
| } |
| |
| newLdifEntry.addAttribute( attribute ); |
| } |
| else |
| { |
| Anonymizer anonymizer = attributeAnonymizers.get( attribute.getAttributeType().getOid() ); |
| |
| if ( anonymizer == null ) |
| { |
| newLdifEntry.addAttribute( attribute ); |
| } |
| else |
| { |
| anonymizedAttribute = anonymizer.anonymize( valueMap, valueSet, attribute ); |
| |
| if ( anonymizedAttribute != null ) |
| { |
| newLdifEntry.addAttribute( anonymizedAttribute ); |
| } |
| } |
| } |
| } |
| |
| return newLdifEntry; |
| } |
| |
| |
| /** |
| * Anonymize a Delete change |
| * |
| * @param ldifEntry The entry to anonymize |
| * @return The anonymized entry |
| * @throws LdapException If the anonymization failed |
| */ |
| private LdifEntry anonymizeChangeDelete( LdifEntry ldifEntry ) throws LdapException |
| { |
| Dn entryDn = ldifEntry.getDn(); |
| |
| // Process the DN, there is nothing more in the entry |
| Dn anonymizedDn = anonymizeDn( entryDn ); |
| |
| ldifEntry.setDn( anonymizedDn ); |
| |
| return ldifEntry; |
| } |
| |
| |
| /** |
| * Anonymize a Delete change |
| * |
| * @param ldifEntry The entry to anonymize |
| * @return The anonymized entry |
| * @throws LdapException If the anonymization failed |
| */ |
| private LdifEntry anonymizeChangeModDn( LdifEntry ldifEntry ) throws LdapException |
| { |
| Dn entryDn = ldifEntry.getDn(); |
| |
| // Process the DN |
| Dn anonymizedDn = anonymizeDn( entryDn ); |
| |
| ldifEntry.setDn( anonymizedDn ); |
| |
| // Anonymize the newRdn if any |
| String newRdnStr = ldifEntry.getNewRdn(); |
| |
| if ( newRdnStr != null ) |
| { |
| Dn newRdn = new Dn( schemaManager, newRdnStr ); |
| Dn anonymizedRdn = anonymizeDn( newRdn ); |
| |
| ldifEntry.setNewRdn( anonymizedRdn.toString() ); |
| } |
| |
| // Anonymize the neSuperior if any |
| String newSuperiorStr = ldifEntry.getNewSuperior(); |
| |
| if ( newSuperiorStr != null ) |
| { |
| Dn newSuperior = new Dn( schemaManager, newSuperiorStr ); |
| |
| Dn anonymizedSuperior = anonymizeDn( newSuperior ); |
| |
| ldifEntry.setNewSuperior( anonymizedSuperior.toString() ); |
| } |
| |
| return ldifEntry; |
| } |
| |
| |
| /** |
| * Anonymize the full entry |
| * |
| * @param ldifEntry The entry to anonymize |
| * @return The anonymized entry |
| * @throws LdapException If the anonymization failed |
| */ |
| private Entry anonymizeEntry( LdifEntry ldifEntry ) throws LdapException |
| { |
| Entry entry = ldifEntry.getEntry(); |
| Entry newEntry = new DefaultEntry( schemaManager ); |
| |
| // Process the DN first |
| Dn entryDn = entry.getDn(); |
| |
| Dn anonymizedDn = anonymizeDn( entryDn ); |
| |
| // Now, process the entry's attributes |
| for ( Attribute attribute : entry ) |
| { |
| AttributeType attributeType = attribute.getAttributeType(); |
| |
| // Deal with the special case of DN |
| if ( attributeType.getSyntax().getSyntaxChecker() instanceof DnSyntaxChecker ) |
| { |
| for ( Value dnValue : attribute ) |
| { |
| Dn dn = new Dn( schemaManager, dnValue.getString() ); |
| Dn newdDn = anonymizeDn( dn ); |
| newEntry.add( attributeType, newdDn.toString() ); |
| } |
| } |
| // Deal with the special case of a NameAndOptionalUID |
| else if ( attributeType.getSyntax().getSyntaxChecker() instanceof NameAndOptionalUIDSyntaxChecker ) |
| { |
| for ( Value dnValue : attribute ) |
| { |
| // Get rid of the # part (UID) |
| String valueStr = dnValue.getString(); |
| int uidPos = valueStr.indexOf( '#' ); |
| String uid = null; |
| |
| if ( uidPos != -1 ) |
| { |
| uid = valueStr.substring( uidPos + 1 ); |
| valueStr = valueStr.substring( 0, uidPos ); |
| } |
| |
| Dn dn = new Dn( schemaManager, valueStr ); |
| Dn newDn = anonymizeDn( dn ); |
| String newDnStr = newDn.toString(); |
| |
| if ( uid != null ) |
| { |
| newDnStr = newDnStr + '#' + uid; |
| } |
| |
| newEntry.add( attributeType, newDnStr ); |
| } |
| } |
| else |
| { |
| Anonymizer anonymizer = attributeAnonymizers.get( attribute.getAttributeType().getOid() ); |
| |
| if ( anonymizer == null ) |
| { |
| newEntry.add( attribute ); |
| } |
| else |
| { |
| Attribute anonymizedAttribute = anonymizer.anonymize( valueMap, valueSet, attribute ); |
| |
| if ( anonymizedAttribute != null ) |
| { |
| newEntry.add( anonymizedAttribute ); |
| } |
| } |
| } |
| } |
| |
| newEntry.setDn( anonymizedDn ); |
| |
| return newEntry; |
| } |
| |
| |
| /** |
| * Anonymize a LDIF |
| * |
| * @param ldif The ldif content to anonymize |
| * @return an anonymized version of the given ldif |
| * @throws LdapException If we got some LDAP related exception |
| * @throws IOException If we had some issue during some IO operations |
| */ |
| public String anonymize( String ldif ) throws LdapException, IOException |
| { |
| LdifReader ldifReader = new LdifReader( schemaManager ); |
| |
| try |
| { |
| List<LdifEntry> entries = ldifReader.parseLdif( ldif ); |
| StringBuilder result = new StringBuilder(); |
| |
| for ( LdifEntry ldifEntry : entries ) |
| { |
| if ( ldifEntry.isEntry() && !ldifEntry.isChangeAdd() ) |
| { |
| // process a full entry. Add changes aren't preocessed ghere. |
| Entry newEntry = anonymizeEntry( ldifEntry ); |
| |
| result.append( LdifUtils.convertToLdif( newEntry ) ); |
| result.append( "\n" ); |
| } |
| else if ( ldifEntry.isChangeDelete() ) |
| { |
| // A Delete operation |
| LdifEntry newLdifEntry = anonymizeChangeDelete( ldifEntry ); |
| |
| if ( newLdifEntry != null ) |
| { |
| result.append( newLdifEntry ); |
| result.append( "\n" ); |
| } |
| } |
| else if ( ldifEntry.isChangeAdd() ) |
| { |
| // A Add operation |
| LdifEntry newLdifEntry = anonymizeChangeAdd( ldifEntry ); |
| |
| if ( newLdifEntry != null ) |
| { |
| result.append( newLdifEntry ); |
| result.append( "\n" ); |
| } |
| } |
| else if ( ldifEntry.isChangeModify() ) |
| { |
| // A Modify operation |
| LdifEntry newLdifEntry = anonymizeChangeModify( ldifEntry ); |
| |
| if ( newLdifEntry != null ) |
| { |
| result.append( newLdifEntry ); |
| result.append( "\n" ); |
| } |
| } |
| else if ( ldifEntry.isChangeModDn() || ldifEntry.isChangeModRdn() ) |
| { |
| // A MODDN operation |
| LdifEntry newLdifEntry = anonymizeChangeModDn( ldifEntry ); |
| |
| if ( newLdifEntry != null ) |
| { |
| result.append( newLdifEntry ); |
| result.append( "\n" ); |
| } |
| } |
| } |
| |
| return result.toString(); |
| } |
| catch ( Exception e ) |
| { |
| println( "Error :" + e.getMessage() ); |
| return null; |
| } |
| finally |
| { |
| ldifReader.close(); |
| } |
| } |
| |
| |
| /** |
| * @return the valueMap |
| */ |
| public Map<Value, Value> getValueMap() |
| { |
| return valueMap; |
| } |
| |
| |
| /** |
| * @param valueMap the valueMap to set |
| */ |
| public void setValueMap( Map<Value, Value> valueMap ) |
| { |
| this.valueMap = valueMap; |
| } |
| |
| |
| /** |
| * @return the latest String Value Map |
| */ |
| public Map<Integer, String> getLatestStringMap() |
| { |
| return latestStringMap; |
| } |
| |
| |
| /** |
| * @param latestStringMap the latest String Value Map to set |
| */ |
| public void setLatestStringMap( Map<Integer, String> latestStringMap ) |
| { |
| this.latestStringMap = latestStringMap; |
| } |
| |
| |
| /** |
| * @return the latest byte[] Value Map |
| */ |
| public Map<Integer, byte[]> getLatestBytesMap() |
| { |
| return latestBytesMap; |
| } |
| |
| |
| /** |
| * @param latestBytesMap the latest byte[] Value Map to set |
| */ |
| public void setLatestBytesMap( Map<Integer, byte[]> latestBytesMap ) |
| { |
| this.latestBytesMap = latestBytesMap; |
| } |
| |
| |
| /** |
| * The entry point, when used as a standalone application. |
| * |
| * @param args Contains the arguments : the file to convert. The anonymized |
| * LDIF will be printed on stdout |
| * @throws IOException If we had an issue opening the file to anonymise ot writing the result |
| * @throws LdapException If we had some issue while processing the LDAP data |
| */ |
| public static void main( String[] args ) throws IOException, LdapException |
| { |
| if ( ( args == null ) || ( args.length < 1 ) ) |
| { |
| System.out.println( "No file to anonymize" ); |
| return; |
| } |
| |
| LdifAnonymizer anonymizer = new LdifAnonymizer(); |
| |
| String ldifString = null; |
| |
| try ( InputStream fis = Files.newInputStream( Paths.get( args[0] ) ) ) |
| { |
| try ( BufferedReader br = new BufferedReader( new InputStreamReader( fis, Charset.defaultCharset() ) ) ) |
| { |
| StringBuilder sb = new StringBuilder(); |
| String line = br.readLine(); |
| |
| while ( line != null ) |
| { |
| sb.append( line ); |
| sb.append( System.lineSeparator() ); |
| line = br.readLine(); |
| } |
| |
| ldifString = sb.toString(); |
| } |
| } |
| |
| String result = anonymizer.anonymize( ldifString ); |
| |
| System.out.println( result ); |
| } |
| } |