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 final Logger LOG = LoggerFactory.getLogger( LdapConnectionTemplate.class );
67 private static final EntryMapper<Dn> DN_ENTRY_MAPPER = 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 LOG.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, DN_ENTRY_MAPPER );
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 )
442 {
443 return modelFactory.newAttribute( name );
444 }
445
446
447 @Override
448 public Attribute newAttribute( String name, byte[]... values )
449 {
450 return modelFactory.newAttribute( name, values );
451 }
452
453
454 @Override
455 public Attribute newAttribute( String name, String... values )
456 {
457 return modelFactory.newAttribute( name, values );
458 }
459
460
461 @Override
462 public Attribute newAttribute( String name, Value<?>... values )
463 {
464 return modelFactory.newAttribute( name, values );
465 }
466
467
468 @Override
469 public DeleteRequest newDeleteRequest( Dn dn )
470 {
471 return modelFactory.newDeleteRequest( dn );
472 }
473
474
475 @Override
476 public Dn newDn( String dn )
477 {
478 return modelFactory.newDn( dn );
479 }
480
481
482 @Override
483 public Entry newEntry( String dn )
484 {
485 return modelFactory.newEntry( dn );
486 }
487
488
489 @Override
490 public Entry newEntry( Dn dn )
491 {
492 return modelFactory.newEntry( dn );
493 }
494
495
496 @Override
497 public ModifyRequest newModifyRequest( String dn )
498 {
499 return modelFactory.newModifyRequest( dn );
500 }
501
502
503 @Override
504 public ModifyRequest newModifyRequest( Dn dn )
505 {
506 return modelFactory.newModifyRequest( dn );
507 }
508
509
510 @Override
511 public SearchRequest newSearchRequest( String baseDn, FilterBuilder filter, SearchScope scope )
512 {
513 return modelFactory.newSearchRequest( baseDn, filter, scope );
514 }
515
516
517 @Override
518 public SearchRequest newSearchRequest( String baseDn, String filter, SearchScope scope )
519 {
520 return modelFactory.newSearchRequest( baseDn, filter, scope );
521 }
522
523
524 @Override
525 public SearchRequest newSearchRequest( Dn baseDn, FilterBuilder filter, SearchScope scope )
526 {
527 return modelFactory.newSearchRequest( baseDn, filter, scope );
528 }
529
530
531 @Override
532 public SearchRequest newSearchRequest( Dn baseDn, String filter, SearchScope scope )
533 {
534 return modelFactory.newSearchRequest( baseDn, filter, scope );
535 }
536
537
538 @Override
539 public SearchRequest newSearchRequest( String baseDn, FilterBuilder filter, SearchScope scope, String... attributes )
540 {
541 return modelFactory.newSearchRequest( baseDn, filter, scope, attributes );
542 }
543
544
545 @Override
546 public SearchRequest newSearchRequest( String baseDn, String 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, FilterBuilder filter, SearchScope scope, String... attributes )
554 {
555 return modelFactory.newSearchRequest( baseDn, filter, scope, attributes );
556 }
557
558
559 @Override
560 public SearchRequest newSearchRequest( Dn baseDn, String filter, SearchScope scope, String... attributes )
561 {
562 return modelFactory.newSearchRequest( baseDn, filter, scope, attributes );
563 }
564
565
566 @Override
567 public <T extends ResultResponse> T responseOrException( T response )
568 {
569 if ( ResultCodeEnum.SUCCESS != response.getLdapResult().getResultCode() )
570 {
571 throw new LdapRequestUnsuccessfulException( response );
572 }
573 return response;
574 }
575
576
577 private void returnLdapConnection( LdapConnection connection )
578 {
579 if ( connection != null )
580 {
581 try
582 {
583 connectionPool.releaseConnection( connection );
584 }
585 catch ( LdapException e )
586 {
587 throw new LdapRuntimeException( e );
588 }
589 }
590 }
591
592
593 @Override
594 public <T> List<T> search( String baseDn, FilterBuilder filter, SearchScope scope,
595 EntryMapper<T> entryMapper )
596 {
597 return search(
598 modelFactory.newSearchRequest( baseDn, filter, scope ),
599 entryMapper );
600 }
601
602
603 @Override
604 public <T> List<T> search( String baseDn, String filter, SearchScope scope,
605 EntryMapper<T> entryMapper )
606 {
607 return search(
608 modelFactory.newSearchRequest( baseDn, filter, scope ),
609 entryMapper );
610 }
611
612
613 @Override
614 public <T> List<T> search( Dn baseDn, FilterBuilder filter, SearchScope scope,
615 EntryMapper<T> entryMapper )
616 {
617 return search(
618 modelFactory.newSearchRequest( baseDn, filter, scope ),
619 entryMapper );
620 }
621
622
623 @Override
624 public <T> List<T> search( Dn baseDn, String filter, SearchScope scope,
625 EntryMapper<T> entryMapper )
626 {
627 return search(
628 modelFactory.newSearchRequest( baseDn, filter, scope ),
629 entryMapper );
630 }
631
632
633 @Override
634 public <T> List<T> search( String baseDn, FilterBuilder filter, SearchScope scope,
635 String[] attributes, EntryMapper<T> entryMapper )
636 {
637 return search(
638 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
639 entryMapper );
640 }
641
642
643 @Override
644 public <T> List<T> search( String baseDn, String filter, SearchScope scope,
645 String[] attributes, EntryMapper<T> entryMapper )
646 {
647 return search(
648 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
649 entryMapper );
650 }
651
652
653 @Override
654 public <T> List<T> search( Dn baseDn, FilterBuilder filter, SearchScope scope,
655 String[] attributes, EntryMapper<T> entryMapper )
656 {
657 return search(
658 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
659 entryMapper );
660 }
661
662
663 @Override
664 public <T> List<T> search( Dn baseDn, String filter, SearchScope scope,
665 String[] attributes, EntryMapper<T> entryMapper )
666 {
667 return search(
668 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
669 entryMapper );
670 }
671
672
673 @Override
674 public <T> List<T> search( SearchRequest searchRequest,
675 EntryMapper<T> entryMapper )
676 {
677 List<T> entries = new ArrayList<>();
678
679 LdapConnection connection = null;
680 try
681 {
682 connection = connectionPool.getConnection();
683
684 for ( Entry entry : new EntryCursorImpl( connection.search( searchRequest ) ) )
685 {
686 entries.add( entryMapper.map( entry ) );
687 }
688 }
689 catch ( LdapException e )
690 {
691 throw new LdapRuntimeException( e );
692 }
693 finally
694 {
695 returnLdapConnection( connection );
696 }
697
698 return entries;
699 }
700
701
702 @Override
703 public <T> T searchFirst( String baseDn, FilterBuilder filter, SearchScope scope,
704 EntryMapper<T> entryMapper )
705 {
706 return searchFirst(
707 modelFactory.newSearchRequest( baseDn, filter, scope ),
708 entryMapper );
709 }
710
711
712 @Override
713 public <T> T searchFirst( String baseDn, String filter, SearchScope scope,
714 EntryMapper<T> entryMapper )
715 {
716 return searchFirst(
717 modelFactory.newSearchRequest( baseDn, filter, scope ),
718 entryMapper );
719 }
720
721
722 @Override
723 public <T> T searchFirst( Dn baseDn, FilterBuilder filter, SearchScope scope,
724 EntryMapper<T> entryMapper )
725 {
726 return searchFirst(
727 modelFactory.newSearchRequest( baseDn, filter, scope ),
728 entryMapper );
729 }
730
731
732 @Override
733 public <T> T searchFirst( Dn baseDn, String filter, SearchScope scope,
734 EntryMapper<T> entryMapper )
735 {
736 return searchFirst(
737 modelFactory.newSearchRequest( baseDn, filter, scope ),
738 entryMapper );
739 }
740
741
742 @Override
743 public <T> T searchFirst( String baseDn, FilterBuilder filter, SearchScope scope,
744 String[] attributes, EntryMapper<T> entryMapper )
745 {
746 return searchFirst(
747 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
748 entryMapper );
749 }
750
751
752 @Override
753 public <T> T searchFirst( String baseDn, String filter, SearchScope scope,
754 String[] attributes, EntryMapper<T> entryMapper )
755 {
756 return searchFirst(
757 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
758 entryMapper );
759 }
760
761
762 @Override
763 public <T> T searchFirst( Dn baseDn, FilterBuilder filter, SearchScope scope,
764 String[] attributes, EntryMapper<T> entryMapper )
765 {
766 return searchFirst(
767 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
768 entryMapper );
769 }
770
771
772 @Override
773 public <T> T searchFirst( Dn baseDn, String filter, SearchScope scope,
774 String[] attributes, EntryMapper<T> entryMapper )
775 {
776 return searchFirst(
777 modelFactory.newSearchRequest( baseDn, filter, scope, attributes ),
778 entryMapper );
779 }
780
781
782 @Override
783 public <T> T searchFirst( SearchRequest searchRequest,
784 EntryMapper<T> entryMapper )
785 {
786
787
788 long originalSizeLimit = searchRequest.getSizeLimit();
789 try
790 {
791 searchRequest.setSizeLimit( 1 );
792 List<T> entries = search( searchRequest, entryMapper );
793 return entries.isEmpty() ? null : entries.get( 0 );
794 }
795 finally
796 {
797 searchRequest.setSizeLimit( originalSizeLimit );
798 }
799 }
800
801
802
803
804
805
806
807 public void setModelFactory( ModelFactory modelFactory )
808 {
809 this.modelFactory = modelFactory;
810 }
811
812
813
814
815
816
817
818
819
820 public void setPasswordPolicyResponder( PasswordPolicyResponder passwordPolicyResponder )
821 {
822 this.passwordPolicyResponder = passwordPolicyResponder;
823 }
824 }