View Javadoc
1   /*
2    *   Licensed to the Apache Software Foundation (ASF) under one
3    *   or more contributor license agreements.  See the NOTICE file
4    *   distributed with this work for additional information
5    *   regarding copyright ownership.  The ASF licenses this file
6    *   to you under the Apache License, Version 2.0 (the
7    *   "License"); you may not use this file except in compliance
8    *   with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing,
13   *   software distributed under the License is distributed on an
14   *   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *   KIND, either express or implied.  See the License for the
16   *   specific language governing permissions and limitations
17   *   under the License.
18   *
19   */
20  
21  package org.apache.directory.api.ldap.model.ldif.anonymizer;
22  
23  import java.util.Arrays;
24  import java.util.HashMap;
25  import java.util.Map;
26  
27  import org.apache.directory.api.ldap.model.schema.SchemaManager;
28  
29  /**
30   * An abstract class implementing the default behavior of an Anonymizer instance
31   * 
32   * @param <K> The type of object being anonymized
33   *
34   * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
35   */
36  public abstract class AbstractAnonymizer<K> implements Anonymizer<K>
37  {
38      /** The SchemaManager instance */
39      protected SchemaManager schemaManager;
40      
41      /** The map of AttributeType'sOID we want to anonymize. They are all associated with anonymizers */
42      protected Map<String, Anonymizer<K>> attributeAnonymizers = new HashMap<>();
43      
44      /** A flag set to <tt>true</tt> if the AttributeType is case sensitive */
45      protected boolean caseSensitive = false;
46      
47      /** Map of chars to use in the anonymized values 0    5    10   15   20   25   30   35   40*/
48      private static final char[] NOT_SENSITIVE_MAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'()-./".toCharArray();
49      private static final char[] SENSITIVE_MAP =     "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'()-./abcdefghijklmnopqrstuvwxyz".toCharArray();
50      
51      /** A table containing booleans when the corresponding char is printable */
52      private static final int[] CHAR_MAP =
53          {
54              // ---, ---, ---, ---, ---, ---, ---, ---
55                  0,   0,   0,   0,   0,   0,   0,   0, 
56              // ---, ---, ---, ---, ---, ---, ---, ---
57                  0,   0,   0,   0,   0,   0,   0,   0, 
58              // ---, ---, ---, ---, ---, ---, ---, ---
59                  0,   0,   0,   0,   0,   0,   0,   0, 
60              // ---, ---, ---, ---, ---, ---, ---, ---
61                  0,   0,   0,   0,   0,   0,   0,   0, 
62              // ---, ---, ---, ---, ---, ---, ---, "'"
63                  0,   0,   0,   0,   0,   0,   0,  36, 
64              // '(', ')', ---, '+', ',', '-', '.', '/'
65                 37,  38,   0,   0,   0,  39,  40,  41, 
66              // '0', '1', '2', '3', '4', '5', '6', '7',
67                 26,  27,  28,  29,  30,  31,  32,  33, 
68              // '8', '9', ':', ---, ---, '=', ---, '?'
69                 34,  35,   0,   0,   0,   0,   0,  26, 
70              // ---, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
71                  0,   0,   1,   2,   3,   4,   5,   6, 
72              // 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'
73                  7,   8,   9,  10,  11,  12,  13,  14, 
74              // 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W'
75                 15,  16,  17,  18,  19,  20,  21,  22, 
76              // 'X', 'Y', 'Z', ---, ---, ---, ---, ---
77                 23,  24,  25,   0,   0,   0,   0,   0, 
78              // ---, 'a', 'b', 'c', 'd', 'e', 'f', 'g'
79                  0,  42,  43,  44,  45,  46,  47,  48, 
80              // 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o'
81                 49,  50,  51,  52,  53,  54,  55,  56, 
82              // 'p', 'q', 'r', 's', 't', 'u', 'v', 'w'
83                 57,  58,  59,  60,  61,  62,  63,  64, 
84              // 'x', 'y', 'z', ---, ---, ---, ---, ---
85                 65,  66,  67,   0,   0,   0,   0,   0, 
86      };
87  
88      /**
89       * {@inheritDoc}
90       */
91      @Override
92      public void setSchemaManager( SchemaManager schemaManager )
93      {
94          this.schemaManager = schemaManager;
95      }
96      
97      
98      /**
99       * Set the list of existing anonymizers
100      *
101      * @param attributeAnonymizers The list of existing anonymizers
102      */
103     @Override
104     public void setAnonymizers( Map<String, Anonymizer<K>> attributeAnonymizers )
105     {
106         this.attributeAnonymizers = attributeAnonymizers;
107     }
108 
109     
110     /**
111      * {@inheritDoc}
112      */
113     @Override
114     public Map<Integer, String> getLatestStringMap()
115     {
116         return null;
117     }
118 
119     
120     /**
121      * {@inheritDoc}
122      */
123     @Override
124     public void setLatestStringMap( Map<Integer, String> latestStringMap )
125     {
126         // Do nothing
127     }
128 
129     
130     /**
131      * {@inheritDoc}
132      */
133     @Override
134     public Map<Integer, byte[]> getLatestBytesMap()
135     {
136         return null;
137     }
138     
139     
140     /**
141      * {@inheritDoc}
142      */
143     @Override
144     public void setLatestBytesMap( Map<Integer, byte[]> latestBytesMap )
145     {
146         // Do nothing
147     }
148     
149     
150     /**
151      * Compute the next String value
152      *
153      * @param valStr The original value
154      * @return The anonymized value
155      */
156     protected String computeNewValue( String valStr )
157     {
158         int length = valStr.length();
159         String latestString = getLatestStringMap().get( length );
160         char[] charMap;
161         
162         if ( caseSensitive )
163         {
164             charMap = SENSITIVE_MAP;
165         }
166         else
167         {
168             charMap = NOT_SENSITIVE_MAP;
169         }
170         
171         int lastMapChar = charMap.length - 1;
172 
173         if ( latestString == null )
174         {
175             // No previous value : create a new one
176             char[] newValue = new char[length];
177             
178             Arrays.fill( newValue, charMap[0] );
179             
180             String anonymizedValue = new String( newValue );
181             getLatestStringMap().put( length, anonymizedValue );
182             
183             return anonymizedValue;
184         }
185         else
186         {
187             // Compute a new value
188             char[] latest = latestString.toCharArray();
189             boolean overflow = true;
190             
191             for ( int i = length - 1; i >= 0; i-- )
192             {
193                 if ( latest[i] == charMap[lastMapChar] )
194                 {
195                     latest[i] = charMap[0];
196                 }
197                 else
198                 {
199                     latest[i] = charMap[CHAR_MAP[latest[i]] + 1];
200                     overflow = false;
201                     break;
202                 }
203             }
204             
205             String anonymizedValue = new String( latest );
206             
207             if ( overflow )
208             {
209                 // We have exhausted all the possible values...
210                 throw new RuntimeException( "Cannot compute a new value for " + anonymizedValue );
211             }
212             
213             getLatestStringMap().put( length, anonymizedValue );
214             
215             return anonymizedValue;
216         }
217     }
218     
219     
220     /**
221      * Compute the next byte[] value
222      *
223      * @param valBytes The original value
224      * @return The anonymized value
225      */
226     protected byte[] computeNewValue( byte[] valBytes )
227     {
228         int length = valBytes.length;
229         byte[] latestBytes = getLatestBytesMap().get( length );
230         
231         if ( latestBytes == null )
232         {
233             // No previous value : create a new one
234             byte[] newValue = new byte[length];
235             
236             Arrays.fill( newValue, ( byte ) 'A' );
237             
238             getLatestBytesMap().put( length, newValue );
239             
240             return newValue;
241         }
242         else
243         {
244             // Compute a new value
245             boolean overflow = true;
246             
247             for ( int i = length - 1; i >= 0; i-- )
248             {
249                 if ( latestBytes[i] == ( byte ) 'Z' )
250                 {
251                     latestBytes[i] = ( byte ) 'A';
252                 }
253                 else
254                 {
255                     latestBytes[i]++;
256                     overflow = false;
257                     break;
258                 }
259             }
260             
261             if ( overflow )
262             {
263                 // We have exhausted all the possible values...
264                 throw new RuntimeException( "Cannot compute a new value for " + latestBytes );
265             }
266             
267             return latestBytes;
268         }
269     }
270 }