1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.directory.ldap.client.template;
21
22
23 import java.util.ArrayList;
24 import java.util.List;
25
26 import org.apache.directory.api.ldap.extras.controls.ppolicy_impl.PasswordPolicyDecorator;
27 import org.apache.directory.api.ldap.model.entry.Attribute;
28 import org.apache.directory.api.ldap.model.entry.Entry;
29 import org.apache.directory.api.ldap.model.entry.Value;
30 import org.apache.directory.api.ldap.model.exception.LdapException;
31 import org.apache.directory.api.ldap.model.message.AddRequest;
32 import org.apache.directory.api.ldap.model.message.AddResponse;
33 import org.apache.directory.api.ldap.model.message.BindRequest;
34 import org.apache.directory.api.ldap.model.message.BindRequestImpl;
35 import org.apache.directory.api.ldap.model.message.DeleteRequest;
36 import org.apache.directory.api.ldap.model.message.DeleteResponse;
37 import org.apache.directory.api.ldap.model.message.ModifyRequest;
38 import org.apache.directory.api.ldap.model.message.ModifyRequestImpl;
39 import org.apache.directory.api.ldap.model.message.ModifyResponse;
40 import org.apache.directory.api.ldap.model.message.ResultCodeEnum;
41 import org.apache.directory.api.ldap.model.message.ResultResponse;
42 import org.apache.directory.api.ldap.model.message.SearchRequest;
43 import org.apache.directory.api.ldap.model.message.SearchScope;
44 import org.apache.directory.api.ldap.model.name.Dn;
45 import org.apache.directory.ldap.client.api.EntryCursorImpl;
46 import org.apache.directory.ldap.client.api.LdapConnection;
47 import org.apache.directory.ldap.client.api.LdapConnectionPool;
48 import org.apache.directory.ldap.client.api.search.FilterBuilder;
49 import org.apache.directory.ldap.client.template.exception.LdapRequestUnsuccessfulException;
50 import org.apache.directory.ldap.client.template.exception.LdapRuntimeException;
51 import org.apache.directory.ldap.client.template.exception.PasswordException;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55
56
57
58
59
60
61
62
63
64 public class LdapConnectionTemplate implements LdapConnectionOperations, ModelFactory
65 {
66 private static Logger logger = LoggerFactory.getLogger( LdapConnectionTemplate.class );
67 private static final EntryMapper<Dn> dnEntryMapper = new EntryMapper<Dn>()
68 {
69 @Override
70 public Dn map( Entry entry ) throws LdapException
71 {
72 return entry.getDn();
73 }
74 };
75
76 private LdapConnectionPool connectionPool;
77 private final PasswordPolicyDecorator passwordPolicyRequestControl;
78 private PasswordPolicyResponder passwordPolicyResponder;
79 private ModelFactory modelFactory;
80
81
82
83
84
85
86
87 public LdapConnectionTemplate( LdapConnectionPool connectionPool )
88 {
89 logger.debug( "creating new connection template from connectionPool" );
90 this.connectionPool = connectionPool;
91 this.passwordPolicyRequestControl = new PasswordPolicyDecorator(
92 connectionPool.getLdapApiService() );
93 this.passwordPolicyResponder = new PasswordPolicyResponderImpl(
94 connectionPool.getLdapApiService() );
95 this.modelFactory = new ModelFactoryImpl();
96 }
97
98
99 @Override
100 public AddResponse add( Dn dn, final Attribute... attributes )
101 {
102 return add( dn,
103 new RequestBuilder<AddRequest>()
104 {
105 @Override
106 public void buildRequest( AddRequest request ) throws LdapException
107 {
108 request.getEntry().add( attributes );
109 }
110 } );
111 }
112
113
114 @Override
115 public AddResponse add( Dn dn, RequestBuilder<AddRequest> requestBuilder )
116 {
117 AddRequest addRequest = newAddRequest( newEntry( dn ) );
118 try
119 {
120 requestBuilder.buildRequest( addRequest );
121 }
122 catch ( LdapException e )
123 {
124 throw new LdapRuntimeException( e );
125 }
126 return add( addRequest );
127 }
128
129
130 @Override
131 public AddResponse add( AddRequest addRequest )
132 {
133 LdapConnection connection = null;
134 try
135 {
136 connection = connectionPool.getConnection();
137 return connection.add( addRequest );
138 }
139 catch ( LdapException e )
140 {
141 throw new LdapRuntimeException( e );
142 }
143 finally
144 {
145 returnLdapConnection( connection );
146 }
147 }
148
149
150 @Override
151 public PasswordWarning authenticate( String baseDn, String filter, SearchScope scope, char[] password )
152 throws PasswordException
153 {
154 return authenticate( newSearchRequest( baseDn, filter, scope ), password );
155 }
156
157
158 @Override
159 public PasswordWarning authenticate( Dn baseDn, String filter, SearchScope scope, char[] password )
160 throws PasswordException
161 {
162 return authenticate( newSearchRequest( baseDn, filter, scope ), password );
163 }
164
165
166 @Override
167 public PasswordWarning authenticate( SearchRequest searchRequest, char[] password ) throws PasswordException
168 {
169 Dn userDn = searchFirst( searchRequest, dnEntryMapper );
170 if ( userDn == null )
171 {
172 throw new PasswordException().setResultCode( ResultCodeEnum.INVALID_CREDENTIALS );
173 }
174
175 return authenticate( userDn, password );
176 }
177
178
179 @Override
180 public PasswordWarning authenticate( Dn userDn, char[] password ) throws PasswordException
181 {
182 LdapConnection connection = null;
183 try
184 {
185 connection = connectionPool.getConnection();
186 return authenticateConnection( connection, userDn, password );
187 }
188 catch ( LdapException e )
189 {
190 throw new LdapRuntimeException( e );
191 }
192 finally
193 {
194 returnLdapConnection( connection );
195 }
196 }
197
198
199 private PasswordWarning authenticateConnection( final LdapConnection connection,
200 final Dn userDn, final char[] password ) throws PasswordException
201 {
202 return passwordPolicyResponder.process(
203 new PasswordPolicyOperation()
204 {
205 @Override
206 public ResultResponse process() throws LdapException
207 {
208 MemoryClearingBuffer passwordBuffer = MemoryClearingBuffer.newInstance( password );
209 try
210 {
211 BindRequest bindRequest = new BindRequestImpl()
212 .setDn( userDn )
213 .setCredentials( passwordBuffer.getBytes() )
214 .addControl( passwordPolicyRequestControl );
215
216 return connection.bind( bindRequest );
217 }
218 finally
219 {
220 passwordBuffer.clear();
221 }
222 }
223 } );
224 }
225
226
227 @Override
228 public DeleteResponse delete( Dn dn )
229 {
230 return delete( dn, null );
231 }
232
233
234 @Override
235 public DeleteResponse delete( Dn dn, RequestBuilder<DeleteRequest> requestBuilder )
236 {
237 DeleteRequest deleteRequest = newDeleteRequest( dn );
238 if ( requestBuilder != null )
239 {
240 try
241 {
242 requestBuilder.buildRequest( deleteRequest );
243 }
244 catch ( LdapException e )
245 {
246 throw new LdapRuntimeException( e );
247 }
248 }
249 return delete( deleteRequest );
250 }
251
252
253 @Override
254 public DeleteResponse delete( DeleteRequest deleteRequest )
255 {
256 LdapConnection connection = null;
257 try
258 {
259 connection = connectionPool.getConnection();
260 return connection.delete( deleteRequest );
261 }
262 catch ( LdapException e )
263 {
264 throw new LdapRuntimeException( e );
265 }
266 finally
267 {
268 returnLdapConnection( connection );
269 }
270 }
271
272
273 @Override
274 public <T> T execute( ConnectionCallback<T> connectionCallback )
275 {
276 LdapConnection connection = null;
277 try
278 {
279 connection = connectionPool.getConnection();
280 return connectionCallback.doWithConnection( connection );
281 }
282 catch ( LdapException e )
283 {
284 throw new LdapRuntimeException( e );
285 }
286 finally
287 {
288 returnLdapConnection( connection );
289 }
290 }
291
292
293 @Override
294 public <T> T lookup( Dn dn, EntryMapper<T> entryMapper )
295 {
296 return lookup( dn, null, entryMapper );
297 }
298
299
300 @Override
301 public <T> T lookup( Dn dn, String[] attributes, EntryMapper<T> entryMapper )
302 {
303 LdapConnection connection = null;
304 try
305 {
306 connection = connectionPool.getConnection();
307 Entry entry = attributes == null
308 ? connection.lookup( dn )
309 : connection.lookup( dn, attributes );
310 return entry == null ? null : entryMapper.map( entry );
311 }
312 catch ( LdapException e )
313 {
314 throw new LdapRuntimeException( e );
315 }
316 finally
317 {
318 returnLdapConnection( connection );
319 }
320 }
321
322
323 private void modifyPassword( final LdapConnection connection, final Dn userDn,
324 final char[] newPassword ) throws PasswordException
325 {
326 passwordPolicyResponder.process(
327 new PasswordPolicyOperation()
328 {
329 @Override
330 public ResultResponse process() throws PasswordException, LdapException
331 {
332
333
334
335 MemoryClearingBuffer newPasswordBuffer = MemoryClearingBuffer.newInstance( newPassword );
336 try
337 {
338 ModifyRequest modifyRequest = new ModifyRequestImpl()
339 .setName( userDn )
340 .replace( "userPassword", newPasswordBuffer.getComputedBytes() )
341 .addControl( passwordPolicyRequestControl );
342
343 return connection.modify( modifyRequest );
344 }
345 finally
346 {
347 newPasswordBuffer.clear();
348 }
349 }
350 } );
351
352 }
353
354
355 @Override
356 public void modifyPassword( Dn userDn, char[] newPassword )
357 throws PasswordException
358 {
359 modifyPassword( userDn, null, newPassword, true );
360 }
361
362
363 @Override
364 public void modifyPassword( Dn userDn, char[] oldPassword,
365 char[] newPassword ) throws PasswordException
366 {
367 modifyPassword( userDn, oldPassword, newPassword, false );
368 }
369
370
371 @Override
372 public void modifyPassword( Dn userDn, char[] oldPassword,
373 char[] newPassword, boolean asAdmin ) throws PasswordException
374 {
375 LdapConnection connection = null;
376 try
377 {
378 connection = connectionPool.getConnection();
379 if ( !asAdmin )
380 {
381 authenticateConnection( connection, userDn, oldPassword );
382 }
383
384 modifyPassword( connection, userDn, newPassword );
385 }
386 catch ( LdapException e )
387 {
388 throw new LdapRuntimeException( e );
389 }
390 finally
391 {
392 returnLdapConnection( connection );
393 }
394 }
395
396
397 @Override
398 public ModifyResponse modify( Dn dn, RequestBuilder<ModifyRequest> requestBuilder )
399 {
400 ModifyRequest modifyRequest = newModifyRequest( dn );
401 try
402 {
403 requestBuilder.buildRequest( modifyRequest );
404 }
405 catch ( LdapException e )
406 {
407 throw new LdapRuntimeException( e );
408 }
409 return modify( modifyRequest );
410 }
411
412
413 @Override
414 public ModifyResponse modify( ModifyRequest modifyRequest )
415 {
416 LdapConnection connection = null;
417 try
418 {
419 connection = connectionPool.getConnection();
420 return connection.modify( modifyRequest );
421 }
422 catch ( LdapException e )
423 {
424 throw new LdapRuntimeException( e );
425 }
426 finally
427 {
428 returnLdapConnection( connection );
429 }
430 }
431
432
433 @Override
434 public AddRequest newAddRequest( Entry entry )
435 {
436 return modelFactory.newAddRequest( entry );
437 }
438
439
440 @Override
441 public Attribute newAttribute( String name, byte[]... values )
442 {
443 return modelFactory.newAttribute( name, values );
444 }
445
446
447 @Override
448 public Attribute newAttribute( String name, String... values )
449 {
450 return modelFactory.newAttribute( name, values );
451 }
452
453
454 @Override
455 public Attribute newAttribute( String name, Value<?>... values )
456 {
457 return modelFactory.newAttribute( name, values );
458 }
459
460
461 @Override
462 public DeleteRequest newDeleteRequest( Dn dn )
463 {
464 return modelFactory.newDeleteRequest( dn );
465 }
466
467
468 @Override
469 public Dn newDn( String dn )
470 {
471 return modelFactory.newDn( dn );
472 }
473
474
475 @Override
476 public Entry newEntry( String dn )
477 {
478 return modelFactory.newEntry( dn );
479 }
480
481
482 @Override
483 public Entry newEntry( Dn dn )
484 {
485 return modelFactory.newEntry( dn );
486 }
487
488
489 @Override
490 public ModifyRequest newModifyRequest( String dn )
491 {
492 return modelFactory.newModifyRequest( dn );
493 }
494
495
496 @Override
497 public ModifyRequest newModifyRequest( Dn dn )
498 {
499 return modelFactory.newModifyRequest( dn );
500 }
501
502
503 @Override
504 public SearchRequest newSearchRequest( String baseDn, FilterBuilder filter, SearchScope scope )
505 {
506 return modelFactory.newSearchRequest( baseDn, filter, scope );
507 }
508
509
510 @Override
511 public SearchRequest newSearchRequest( String baseDn, String filter, SearchScope scope )
512 {
513 return modelFactory.newSearchRequest( baseDn, filter, scope );
514 }
515
516
517 @Override
518 public SearchRequest newSearchRequest( Dn baseDn, FilterBuilder filter, SearchScope scope )
519 {
520 return modelFactory.newSearchRequest( baseDn, filter, scope );
521 }
522
523
524 @Override
525 public SearchRequest newSearchRequest( Dn baseDn, String filter, SearchScope scope )
526 {
527 return modelFactory.newSearchRequest( baseDn, filter, scope );
528 }
529
530
531 @Override
532 public SearchRequest newSearchRequest( String baseDn, FilterBuilder filter, SearchScope scope, String... attributes )
533 {
534 return modelFactory.newSearchRequest( baseDn, filter, scope, attributes );
535 }
536
537
538 @Override
539 public SearchRequest newSearchRequest( String baseDn, String filter, SearchScope scope, String... attributes )
540 {
541 return modelFactory.newSearchRequest( baseDn, filter, scope, attributes );
542 }
543
544
545 @Override
546 public SearchRequest newSearchRequest( Dn baseDn, FilterBuilder filter, SearchScope scope, String... attributes )
547 {
548 return modelFactory.newSearchRequest( baseDn, filter, scope, attributes );
549 }
550
551
552 @Override
553 public SearchRequest newSearchRequest( Dn baseDn, String filter, SearchScope scope, String... attributes )
554 {
555 return modelFactory.newSearchRequest( baseDn, filter, scope, attributes );
556 }
557
558
559 @Override
560 public <T extends ResultResponse> T responseOrException( T response )
561 {
562 if ( ResultCodeEnum.SUCCESS != response.getLdapResult().getResultCode() )
563 {
564 throw new LdapRequestUnsuccessfulException( response );
565 }
566 return response;
567 }
568
569
570 private void returnLdapConnection( LdapConnection connection )
571 {
572 if ( connection != null )
573 {
574 try
575 {
576 connectionPool.releaseConnection( connection );
577 }
578 catch ( LdapException e )
579 {
580 throw new LdapRuntimeException( e );
581 }
582 }
583 }
584
585
586 @Override
587 public <T> List<T> search( String baseDn, FilterBuilder filter, SearchScope scope,
588 EntryMapper<T> entryMapper )
589 {
590 return search(
591 modelFactory.newSearchRequest( baseDn, filter, scope ),
592 entryMapper );
593 }
594
595
596 @Override
597 public <T> List<T> search( String baseDn, String filter, SearchScope scope,
598 EntryMapper<T> entryMapper )
599 {
600 return search(
601 modelFactory.newSearchRequest( baseDn, filter, scope ),
602 entryMapper );
603 }
604
605
606 @Override
607 public <T> List<T> search( Dn baseDn, FilterBuilder filter, SearchScope scope,
608 EntryMapper<T> entryMapper )
609 {
610 return search(
611 modelFactory.newSearchRequest( baseDn, filter, scope ),
612 entryMapper );
613 }
614
615
616 @Override
617 public <T> List<T> search( Dn baseDn, String filter, SearchScope scope,
618 EntryMapper<T> entryMapper )
619 {
620 return search(
621 modelFactory.newSearchRequest( baseDn, filter, scope ),
622 entryMapper );
623 }
624
625
626 @Override
627 public <T> List<T> search( String baseDn, FilterBuilder filter, SearchScope scope,
628 String[] attributes, EntryMapper<T> entryMapper )
629 {
630 return search(
631 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
632 entryMapper );
633 }
634
635
636 @Override
637 public <T> List<T> search( String baseDn, String filter, SearchScope scope,
638 String[] attributes, EntryMapper<T> entryMapper )
639 {
640 return search(
641 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
642 entryMapper );
643 }
644
645
646 @Override
647 public <T> List<T> search( Dn baseDn, FilterBuilder filter, SearchScope scope,
648 String[] attributes, EntryMapper<T> entryMapper )
649 {
650 return search(
651 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
652 entryMapper );
653 }
654
655
656 @Override
657 public <T> List<T> search( Dn baseDn, String filter, SearchScope scope,
658 String[] attributes, EntryMapper<T> entryMapper )
659 {
660 return search(
661 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
662 entryMapper );
663 }
664
665
666 @Override
667 public <T> List<T> search( SearchRequest searchRequest,
668 EntryMapper<T> entryMapper )
669 {
670 List<T> entries = new ArrayList<T>();
671
672 LdapConnection connection = null;
673 try
674 {
675 connection = connectionPool.getConnection();
676
677 for ( Entry entry : new EntryCursorImpl( connection.search( searchRequest ) ) )
678 {
679 entries.add( entryMapper.map( entry ) );
680 }
681 }
682 catch ( LdapException e )
683 {
684 throw new LdapRuntimeException( e );
685 }
686 finally
687 {
688 returnLdapConnection( connection );
689 }
690
691 return entries;
692 }
693
694
695 @Override
696 public <T> T searchFirst( String baseDn, FilterBuilder filter, SearchScope scope,
697 EntryMapper<T> entryMapper )
698 {
699 return searchFirst(
700 modelFactory.newSearchRequest( baseDn, filter, scope ),
701 entryMapper );
702 }
703
704
705 @Override
706 public <T> T searchFirst( String baseDn, String filter, SearchScope scope,
707 EntryMapper<T> entryMapper )
708 {
709 return searchFirst(
710 modelFactory.newSearchRequest( baseDn, filter, scope ),
711 entryMapper );
712 }
713
714
715 @Override
716 public <T> T searchFirst( Dn baseDn, FilterBuilder filter, SearchScope scope,
717 EntryMapper<T> entryMapper )
718 {
719 return searchFirst(
720 modelFactory.newSearchRequest( baseDn, filter, scope ),
721 entryMapper );
722 }
723
724
725 @Override
726 public <T> T searchFirst( Dn baseDn, String filter, SearchScope scope,
727 EntryMapper<T> entryMapper )
728 {
729 return searchFirst(
730 modelFactory.newSearchRequest( baseDn, filter, scope ),
731 entryMapper );
732 }
733
734
735 @Override
736 public <T> T searchFirst( String baseDn, FilterBuilder filter, SearchScope scope,
737 String[] attributes, EntryMapper<T> entryMapper )
738 {
739 return searchFirst(
740 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
741 entryMapper );
742 }
743
744
745 @Override
746 public <T> T searchFirst( String baseDn, String filter, SearchScope scope,
747 String[] attributes, EntryMapper<T> entryMapper )
748 {
749 return searchFirst(
750 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
751 entryMapper );
752 }
753
754
755 @Override
756 public <T> T searchFirst( Dn baseDn, FilterBuilder filter, SearchScope scope,
757 String[] attributes, EntryMapper<T> entryMapper )
758 {
759 return searchFirst(
760 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
761 entryMapper );
762 }
763
764
765 @Override
766 public <T> T searchFirst( Dn baseDn, String filter, SearchScope scope,
767 String[] attributes, EntryMapper<T> entryMapper )
768 {
769 return searchFirst(
770 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
771 entryMapper );
772 }
773
774
775 @Override
776 public <T> T searchFirst( SearchRequest searchRequest,
777 EntryMapper<T> entryMapper )
778 {
779
780
781 long originalSizeLimit = searchRequest.getSizeLimit();
782 try
783 {
784 searchRequest.setSizeLimit( 1 );
785 List<T> entries = search( searchRequest, entryMapper );
786 return entries.isEmpty() ? null : entries.get( 0 );
787 }
788 finally
789 {
790 searchRequest.setSizeLimit( originalSizeLimit );
791 }
792 }
793
794
795
796
797
798
799
800 public void setModelFactory( ModelFactory modelFactory )
801 {
802 this.modelFactory = modelFactory;
803 }
804
805
806
807
808
809
810
811
812
813 public void setPasswordPolicyResponder( PasswordPolicyResponder passwordPolicyResponder )
814 {
815 this.passwordPolicyResponder = passwordPolicyResponder;
816 }
817 }