1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.directory.server.core.changelog;
20
21
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import org.apache.directory.api.ldap.model.constants.SchemaConstants;
26 import org.apache.directory.api.ldap.model.entry.Attribute;
27 import org.apache.directory.api.ldap.model.entry.DefaultEntry;
28 import org.apache.directory.api.ldap.model.entry.Entry;
29 import org.apache.directory.api.ldap.model.entry.Modification;
30 import org.apache.directory.api.ldap.model.exception.LdapException;
31 import org.apache.directory.api.ldap.model.ldif.ChangeType;
32 import org.apache.directory.api.ldap.model.ldif.LdifEntry;
33 import org.apache.directory.api.ldap.model.ldif.LdifRevertor;
34 import org.apache.directory.api.ldap.model.message.controls.ManageDsaITImpl;
35 import org.apache.directory.api.ldap.model.name.Dn;
36 import org.apache.directory.api.ldap.model.schema.AttributeType;
37 import org.apache.directory.server.constants.ApacheSchemaConstants;
38 import org.apache.directory.server.constants.ServerDNConstants;
39 import org.apache.directory.server.core.api.CoreSession;
40 import org.apache.directory.server.core.api.DirectoryService;
41 import org.apache.directory.server.core.api.InterceptorEnum;
42 import org.apache.directory.server.core.api.changelog.ChangeLog;
43 import org.apache.directory.server.core.api.entry.ClonedServerEntry;
44 import org.apache.directory.server.core.api.entry.ServerEntryUtils;
45 import org.apache.directory.server.core.api.interceptor.BaseInterceptor;
46 import org.apache.directory.server.core.api.interceptor.context.AddOperationContext;
47 import org.apache.directory.server.core.api.interceptor.context.DeleteOperationContext;
48 import org.apache.directory.server.core.api.interceptor.context.LookupOperationContext;
49 import org.apache.directory.server.core.api.interceptor.context.ModifyOperationContext;
50 import org.apache.directory.server.core.api.interceptor.context.MoveAndRenameOperationContext;
51 import org.apache.directory.server.core.api.interceptor.context.MoveOperationContext;
52 import org.apache.directory.server.core.api.interceptor.context.OperationContext;
53 import org.apache.directory.server.core.api.interceptor.context.RenameOperationContext;
54 import org.apache.directory.server.core.shared.SchemaService;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58
59
60
61
62
63
64 public class ChangeLogInterceptor extends BaseInterceptor
65 {
66
67 private static final Logger LOG = LoggerFactory.getLogger( ChangeLogInterceptor.class );
68
69
70 private AttributeType entryDeleted;
71
72
73 private ChangeLog changeLog;
74
75
76 private static final String REV_AT_OID = "1.3.6.1.4.1.18060.0.4.1.2.47";
77
78
79
80
81
82 public ChangeLogInterceptor()
83 {
84 super( InterceptorEnum.CHANGE_LOG_INTERCEPTOR );
85 }
86
87
88
89
90
91
92
93
94
95 @Override
96 public void init( DirectoryService directoryService ) throws LdapException
97 {
98 super.init( directoryService );
99
100 changeLog = directoryService.getChangeLog();
101 entryDeleted = directoryService.getSchemaManager()
102 .getAttributeType( ApacheSchemaConstants.ENTRY_DELETED_AT_OID );
103 }
104
105
106
107
108
109
110
111
112 @Override
113 public void add( AddOperationContext addContext ) throws LdapException
114 {
115 next( addContext );
116
117 if ( !changeLog.isEnabled() )
118 {
119 return;
120 }
121
122 Entry addEntry = addContext.getEntry();
123
124
125 if ( addEntry.get( REV_AT_OID ) != null )
126 {
127 return;
128 }
129
130 LdifEntry forward = new LdifEntry();
131 forward.setChangeType( ChangeType.Add );
132 forward.setDn( addContext.getDn() );
133
134 for ( Attribute attribute : addEntry.getAttributes() )
135 {
136 AttributeType attributeType = attribute.getAttributeType();
137 forward.addAttribute( addEntry.get( attributeType ).clone() );
138 }
139
140 LdifEntry reverse = LdifRevertor.reverseAdd( addContext.getDn() );
141 addContext.setChangeLogEvent( changeLog.log( getPrincipal( addContext ), forward, reverse ) );
142 }
143
144
145
146
147
148
149
150
151
152 @Override
153 public void delete( DeleteOperationContext deleteContext ) throws LdapException
154 {
155
156
157 Entry serverEntry = null;
158
159 if ( changeLog.isEnabled() )
160 {
161 serverEntry = getAttributes( deleteContext );
162 }
163
164 next( deleteContext );
165
166 if ( !changeLog.isEnabled() )
167 {
168 return;
169 }
170
171
172 if ( serverEntry.get( REV_AT_OID ) != null )
173 {
174 return;
175 }
176
177 LdifEntry forward = new LdifEntry();
178 forward.setChangeType( ChangeType.Delete );
179 forward.setDn( deleteContext.getDn() );
180
181 Entry reverseEntry = new DefaultEntry( serverEntry.getDn() );
182
183 boolean isCollectiveSubentry = serverEntry.hasObjectClass( SchemaConstants.COLLECTIVE_ATTRIBUTE_SUBENTRY_OC );
184
185 for ( Attribute attribute : serverEntry )
186 {
187
188 AttributeType at = schemaManager.lookupAttributeTypeRegistry( attribute.getId() );
189
190 if ( !at.isCollective() || isCollectiveSubentry )
191 {
192 reverseEntry.add( attribute.clone() );
193 }
194 }
195
196 LdifEntry reverse = LdifRevertor.reverseDel( deleteContext.getDn(), reverseEntry );
197 deleteContext.setChangeLogEvent( changeLog.log( getPrincipal( deleteContext ), forward, reverse ) );
198 }
199
200
201
202
203
204 @Override
205 public void modify( ModifyOperationContext modifyContext ) throws LdapException
206 {
207 Entry serverEntry = null;
208 Modification modification = ServerEntryUtils.getModificationItem( modifyContext.getModItems(), entryDeleted );
209 boolean isDelete = modification != null;
210
211 if ( !isDelete && ( changeLog.isEnabled() ) )
212 {
213
214 serverEntry = getAttributes( modifyContext );
215 }
216
217
218 List<Modification> clonedMods = new ArrayList<>();
219
220 for ( Modification mod : modifyContext.getModItems() )
221 {
222 clonedMods.add( mod.clone() );
223 }
224
225
226 next( modifyContext );
227
228
229
230 if ( isDelete
231 || !changeLog.isEnabled()
232
233
234
235
236
237 || modifyContext.getModItems().isEmpty() )
238 {
239 if ( isDelete )
240 {
241 LOG.debug( "Bypassing changelog on modify of entryDeleted attribute." );
242 }
243
244 return;
245 }
246
247 LdifEntry forward = new LdifEntry();
248 forward.setChangeType( ChangeType.Modify );
249 forward.setDn( modifyContext.getDn() );
250
251 List<Modification> mods = new ArrayList<>( clonedMods.size() );
252
253 for ( Modification modItem : clonedMods )
254 {
255
256 mods.add( modItem );
257
258 forward.addModification( modItem );
259 }
260
261 Entry clientEntry = new DefaultEntry( serverEntry.getDn() );
262
263 for ( Attribute attribute : serverEntry )
264 {
265 clientEntry.add( attribute.clone() );
266 }
267
268 LdifEntry reverse = LdifRevertor.reverseModify(
269 modifyContext.getDn(),
270 mods,
271 clientEntry );
272
273 modifyContext.setChangeLogEvent( changeLog.log( getPrincipal( modifyContext ), forward, reverse ) );
274 }
275
276
277
278
279
280 @Override
281 public void move( MoveOperationContext moveContext ) throws LdapException
282 {
283 next( moveContext );
284
285 if ( !changeLog.isEnabled() )
286 {
287 return;
288 }
289
290 LdifEntry forward = new LdifEntry();
291 forward.setChangeType( ChangeType.ModDn );
292 forward.setDn( moveContext.getDn() );
293 forward.setNewSuperior( moveContext.getNewSuperior().getName() );
294
295 LdifEntry reverse = LdifRevertor.reverseMove( moveContext.getNewSuperior(), moveContext.getDn() );
296 moveContext.setChangeLogEvent( changeLog.log( getPrincipal( moveContext ), forward, reverse ) );
297 }
298
299
300
301
302
303 @Override
304 public void moveAndRename( MoveAndRenameOperationContext moveAndRenameContext ) throws LdapException
305 {
306 Entry serverEntry = null;
307
308 if ( changeLog.isEnabled() )
309 {
310
311 serverEntry = moveAndRenameContext.getOriginalEntry();
312 }
313
314 next( moveAndRenameContext );
315
316 if ( !changeLog.isEnabled() )
317 {
318 return;
319 }
320
321 LdifEntry forward = new LdifEntry();
322 forward.setChangeType( ChangeType.ModDn );
323 forward.setDn( moveAndRenameContext.getDn() );
324 forward.setDeleteOldRdn( moveAndRenameContext.getDeleteOldRdn() );
325 forward.setNewRdn( moveAndRenameContext.getNewRdn().getName() );
326 forward.setNewSuperior( moveAndRenameContext.getNewSuperiorDn().getName() );
327
328 List<LdifEntry> reverses = LdifRevertor.reverseMoveAndRename(
329 serverEntry, moveAndRenameContext.getNewSuperiorDn(), moveAndRenameContext.getNewRdn(), false );
330
331 if ( moveAndRenameContext.isReferralIgnored() )
332 {
333 forward.addControl( new ManageDsaITImpl() );
334 LdifEntry reversedEntry = reverses.get( 0 );
335 reversedEntry.addControl( new ManageDsaITImpl() );
336 }
337
338 moveAndRenameContext
339 .setChangeLogEvent( changeLog.log( getPrincipal( moveAndRenameContext ), forward, reverses ) );
340 }
341
342
343
344
345
346 @Override
347 public void rename( RenameOperationContext renameContext ) throws LdapException
348 {
349 Entry serverEntry = null;
350
351 if ( renameContext.getEntry() != null )
352 {
353 serverEntry = ( ( ClonedServerEntry ) renameContext.getEntry() ).getOriginalEntry();
354 }
355
356 next( renameContext );
357
358
359
360
361 if ( !changeLog.isEnabled() )
362 {
363 return;
364 }
365
366 LdifEntry forward = new LdifEntry();
367 forward.setChangeType( ChangeType.ModRdn );
368 forward.setDn( renameContext.getDn() );
369 forward.setNewRdn( renameContext.getNewRdn().getName() );
370 forward.setDeleteOldRdn( renameContext.getDeleteOldRdn() );
371
372 List<LdifEntry> reverses = LdifRevertor.reverseRename(
373 serverEntry, renameContext.getNewRdn(), renameContext.getDeleteOldRdn() );
374
375 renameContext.setChangeLogEvent( changeLog.log( getPrincipal( renameContext ), forward, reverses ) );
376 }
377
378
379
380
381
382
383
384
385
386 private Entry getAttributes( OperationContext opContext ) throws LdapException
387 {
388 Dn dn = opContext.getDn();
389 Entry serverEntry;
390
391
392 if ( dn.equals( ServerDNConstants.CN_SCHEMA_DN ) )
393 {
394 return SchemaService.getSubschemaEntryCloned( directoryService );
395 }
396 else
397 {
398 CoreSession session = opContext.getSession();
399 LookupOperationContexttor/context/LookupOperationContext.html#LookupOperationContext">LookupOperationContext lookupContext = new LookupOperationContext( session, dn, SchemaConstants.ALL_ATTRIBUTES_ARRAY );
400 lookupContext.setPartition( opContext.getPartition() );
401 lookupContext.setTransaction( opContext.getTransaction() );
402
403 serverEntry = directoryService.getPartitionNexus().lookup( lookupContext );
404 }
405
406 return serverEntry;
407 }
408 }