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