001package com.hfg.ldap; 002 003 004import java.lang.reflect.Method; 005import java.net.URI; 006import java.security.cert.X509Certificate; 007import java.util.*; 008import java.util.logging.Level; 009import java.util.logging.Logger; 010import javax.naming.AuthenticationException; 011import javax.naming.Context; 012import javax.naming.InvalidNameException; 013import javax.naming.NamingEnumeration; 014import javax.naming.NamingException; 015import javax.naming.directory.Attribute; 016import javax.naming.directory.Attributes; 017import javax.naming.directory.DirContext; 018import javax.naming.directory.SearchControls; 019import javax.naming.directory.SearchResult; 020import javax.naming.ldap.Control; 021import javax.naming.ldap.InitialLdapContext; 022import javax.naming.ldap.LdapContext; 023import javax.naming.ldap.LdapName; 024import javax.naming.ldap.PagedResultsControl; 025import javax.naming.ldap.PagedResultsResponseControl; 026import javax.net.ssl.SSLHandshakeException; 027 028import com.hfg.cert.CertificateUtil; 029import com.hfg.exception.InvalidValueException; 030import com.hfg.html.Col; 031import com.hfg.ldap.ad.ActiveDirectory; 032import com.hfg.security.LoginCredentials; 033import com.hfg.util.StackTraceUtil; 034import com.hfg.util.StringBuilderPlus; 035import com.hfg.util.StringUtil; 036import com.hfg.util.collection.CollectionUtil; 037 038import static com.hfg.cert.CertificateUtil.geLdapCertificates; 039 040//------------------------------------------------------------------------------ 041/** 042 Simple LDAP Client. 043 <div> 044 @author J. Alex Taylor, hairyfatguy.com 045 </div> 046 */ 047//------------------------------------------------------------------------------ 048// com.hfg XML/HTML Coding Library 049// 050// This library is free software; you can redistribute it and/or 051// modify it under the terms of the GNU Lesser General Public 052// License as published by the Free Software Foundation; either 053// version 2.1 of the License, or (at your option) any later version. 054// 055// This library is distributed in the hope that it will be useful, 056// but WITHOUT ANY WARRANTY; without even the implied warranty of 057// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 058// Lesser General Public License for more details. 059// 060// You should have received a copy of the GNU Lesser General Public 061// License along with this library; if not, write to the Free Software 062// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 063// 064// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 065// jataylor@hairyfatguy.com 066//------------------------------------------------------------------------------ 067 068public class LDAPClient<U extends LDAP_User> 069{ 070 071 private static final ReferralHandling sDefaultReferralHandling = ReferralHandling.FOLLOW_REFERRALS; 072 073 private static final Logger LOGGER = Logger.getLogger(LDAPClient.class.getPackage().getName()); 074 075 076 private String mLDAP_ServerURL; 077 private LdapName mLDAP_UserContext; 078 private LdapName mLDAP_GroupContext; 079 private String mLDAP_PrincipalFieldName = "uid"; 080 private LdapName mLDAP_PrincipalContext; 081 private String mLDAP_PrincipalSuffix; 082 private LoginCredentials mLDAP_PrincipalCredentials; 083 private LDAP_UserObjFactory mUserFactory = new LDAP_UserFactory(); 084 private ReferralHandling mReferralHandling = sDefaultReferralHandling; 085 086 private Set<String> mSupportedControls; 087 088 private static final String PAGING_OID = "1.2.840.113556.1.4.319"; 089 private static final String VLV_OID = "2.16.840.1.113730.3.4.9"; 090 091 public enum ReferralHandling 092 { 093 FOLLOW_REFERRALS("follow"), 094 IGNORE_REFERRALS("ignore"), 095 THROW_REFERRALS("throw"); 096 097 private String mValue; 098 099 private ReferralHandling(String inValue) 100 { 101 mValue = inValue; 102 } 103 104 public String getValue() 105 { 106 return mValue; 107 } 108 109 @Override 110 public String toString() 111 { 112 return getValue(); 113 } 114 } 115 116 static 117 { 118 LOGGER.setLevel(Level.WARNING); 119 LOGGER.setUseParentHandlers(true); 120 } 121 122 //########################################################################### 123 // CONSTRUCTORS 124 //########################################################################### 125 126 //------------------------------------------------------------------------ 127 public LDAPClient() 128 { 129 130 } 131 132 //------------------------------------------------------------------------ 133 public LDAPClient(LDAP_Config inConfig) 134 { 135 this(); 136 137 setServerURL(inConfig.getServerURL()); 138 setUserContext(inConfig.getUserContext()); 139 setPrincipalFieldName(inConfig.getPrincipalFieldName()); 140 setPrincipalCredentials(inConfig.getPrincipalCredentials()); 141 setReferralHandling(inConfig.getReferralHandling()); 142 } 143 144 //########################################################################### 145 // PUBLIC METHODS 146 //########################################################################### 147 148 //--------------------------------------------------------------------------- 149 public static Logger getLogger() 150 { 151 return LOGGER; 152 } 153 154 //--------------------------------------------------------------------------- 155 public LDAPClient<U> setServerURL(String inValue) 156 { 157 mLDAP_ServerURL = inValue; 158 return this; 159 } 160 161 //--------------------------------------------------------------------------- 162 public String getServerURL() 163 { 164 return mLDAP_ServerURL; 165 } 166 167 //--------------------------------------------------------------------------- 168 public LDAPClient<U> setUserContext(String inValue) 169 { 170 try 171 { 172 setUserContext(inValue != null ? new LdapName(inValue) : null); 173 } 174 catch (InvalidNameException e) 175 { 176 throw new RuntimeException(e); 177 } 178 179 return this; 180 } 181 182 //--------------------------------------------------------------------------- 183 public LDAPClient<U> setReferralHandling(ReferralHandling inValue) 184 { 185 mReferralHandling = inValue; 186 return this; 187 } 188 189 //--------------------------------------------------------------------------- 190 public ReferralHandling getReferralHandling() 191 { 192 return mReferralHandling; 193 } 194 195 196 //--------------------------------------------------------------------------- 197 public LDAPClient<U> setUserContext(LdapName inValue) 198 { 199 mLDAP_UserContext = inValue; 200 return this; 201 } 202 203 204 //--------------------------------------------------------------------------- 205 public LDAPClient<U> setGroupContext(String inValue) 206 { 207 try 208 { 209 setGroupContext(inValue != null ? new LdapName(inValue) : null); 210 } 211 catch (InvalidNameException e) 212 { 213 throw new RuntimeException(e); 214 } 215 216 return this; 217 } 218 219 //--------------------------------------------------------------------------- 220 public LDAPClient<U> setGroupContext(LdapName inValue) 221 { 222 mLDAP_GroupContext = inValue; 223 return this; 224 } 225 226 227 //--------------------------------------------------------------------------- 228 public LDAPClient<U> setPrincipalContext(String inValue) 229 { 230 try 231 { 232 setPrincipalContext(inValue != null ? new LdapName(inValue) : null); 233 } 234 catch (InvalidNameException e) 235 { 236 throw new RuntimeException(e); 237 } 238 239 return this; 240 } 241 242 //--------------------------------------------------------------------------- 243 public LDAPClient<U> setPrincipalContext(LdapName inValue) 244 { 245 mLDAP_PrincipalContext = inValue; 246 return this; 247 } 248 249 //--------------------------------------------------------------------------- 250 public LDAPClient<U> setPrincipalSuffix(String inValue) 251 { 252 mLDAP_PrincipalSuffix = inValue; 253 return this; 254 } 255 256 //--------------------------------------------------------------------------- 257 /** 258 Specifies the credentials to be used to access the LDAP server. 259 * @param inValue the security principal credentials 260 * @return this LDAPClient object to facilitate method chaining 261 */ 262 public LDAPClient<U> setPrincipalCredentials(LoginCredentials inValue) 263 { 264 mLDAP_PrincipalCredentials = inValue; 265 return this; 266 } 267 268 //--------------------------------------------------------------------------- 269 public LDAPClient<U> setPrincipalFieldName(String inValue) 270 { 271 mLDAP_PrincipalFieldName = inValue; 272 return this; 273 } 274 275 //--------------------------------------------------------------------------- 276 public LDAP_UserObjFactory<U> getUserFactory() 277 { 278 return mUserFactory; 279 } 280 281 //--------------------------------------------------------------------------- 282 public LDAPClient<U> setUserFactory(LDAP_UserObjFactory<U> inValue) 283 { 284 if (null == inValue) 285 { 286 throw new InvalidValueException("The user factory cannot be set to null!"); 287 } 288 289 mUserFactory = inValue; 290 return this; 291 } 292 293 //--------------------------------------------------------------------------- 294 // TODO: Should this method return a more complex result that could contain more info about failures? 295 public boolean authenticate(LoginCredentials inCredentials) 296 { 297 crosscheck(); 298 299 boolean authenticated = false; 300 301 DirContext ctx = null; 302 try 303 { 304 // Create the initial context 305 ctx = getInitialDirContext(inCredentials); 306 if (ctx != null) 307 { 308 authenticated = true; 309 } 310/* 311 // get more attributes about this user 312 SearchControls scs = new SearchControls(); 313 scs.setSearchScope(SearchControls.SUBTREE_SCOPE); 314 String[] attrNames = { "mail", "cn" }; 315 scs.setReturningAttributes(attrNames); 316 317 NamingEnumeration nes = ctx.search(mLDAP_UserContext, "uid=" + userName, scs); 318 if(nes.hasMore()) 319 { 320 Attributes attrs = ((SearchResult) nes.next()).getAttributes(); 321 System.out.println("mail: " + attrs.get("mail").get()); 322 System.out.println("cn: " + attrs.get("cn").get()); 323 } 324*/ 325 } 326 catch (AuthenticationException e) 327 { 328 // If it looks like an Active Directory exception, try to decode it... 329 String msg = ActiveDirectory.decodeAuthenticationException(e); 330 if (StringUtil.isSet(msg)) 331 { 332 new LDAP_Exception(msg, e).printStackTrace(); 333 } 334 else 335 { 336 e.printStackTrace(); 337 } 338 } 339 catch (Exception e) 340 { 341 e.printStackTrace(); 342 } 343 finally 344 { 345 if (ctx != null) 346 { 347 try 348 { 349 ctx.close(); 350 } 351 catch (NamingException e) 352 { 353 // Ignore 354 } 355 } 356 } 357 358 return authenticated; 359 } 360 361 //--------------------------------------------------------------------------- 362 public U getInfoForUser(String inQuery) 363 { 364 return getInfoForUser(inQuery, null); 365 } 366 367 //--------------------------------------------------------------------------- 368 public U getInfoForUser(String inQuery, List<LDAP_UserField> inFields) 369 { 370 return getInfoForUser(null, inQuery, inFields); 371 } 372 373 //--------------------------------------------------------------------------- 374 public U getInfoForUser(LdapName inBaseDN, String inQuery) 375 { 376 return getInfoForUser(inBaseDN, inQuery, null); 377 } 378 379 //--------------------------------------------------------------------------- 380 public U getInfoForUser(LdapName inBaseDN, String inQuery, List<LDAP_UserField> inFields) 381 { 382 List<U> users = getInfoForUsers(inBaseDN, inQuery, inFields); 383 return (CollectionUtil.hasValues(users) ? users.get(0) : null); 384 } 385 386 //--------------------------------------------------------------------------- 387 public List<U> getInfoForUsers(String inQuery) 388 { 389 return getInfoForUsers(inQuery, null); 390 } 391 392 //--------------------------------------------------------------------------- 393 public List<U> getInfoForUsers(String inFilter, List<LDAP_UserField> inFields) 394 { 395 return getInfoForUsers(null, inFilter, inFields); 396 } 397 398 //--------------------------------------------------------------------------- 399 public List<U> getInfoForUsers(LdapName inBaseDN, String inFilter, List<LDAP_UserField> inFields) 400 { 401 List<U> users; 402 403 LdapContext ctx = null; 404 try 405 { 406 // Create the initial context 407 ctx = getInitialDirContext(mLDAP_PrincipalCredentials); 408 409 if (isPagingSupported(ctx)) 410 { 411 users = getInfoForUsersWithPaging(ctx, inBaseDN, inFilter, inFields); 412 } 413 else 414 { 415 users = getInfoForUsersWithoutPaging(ctx, inBaseDN, inFilter, inFields); 416 } 417 } 418 catch (Exception e) 419 { 420 throw composeException(e); 421 } 422 finally 423 { 424 if (ctx != null) 425 { 426 try 427 { 428 ctx.close(); 429 } 430 catch (NamingException e) 431 { 432 433 } 434 } 435 } 436 437 int numUsersFound = (CollectionUtil.hasValues(users) ? users.size() : 0); 438 LOGGER.fine(numUsersFound + " user" + (numUsersFound != 1 ? "s" : "") + " found by LDAP Query " + StringUtil.singleQuote(inFilter) + " in context " + StringUtil.singleQuote(mLDAP_GroupContext)); 439 440 return users; 441 } 442 443 //--------------------------------------------------------------------------- 444 public List<U> getInfoForUsersWithPaging(LdapContext inCtx, LdapName inBaseDN, String inFilter, List<LDAP_UserField> inFields) 445 throws Exception 446 { 447 List<U> users = null; 448 449 LdapName baseDN = inBaseDN; 450 if (null == baseDN) 451 { 452 baseDN = mLDAP_UserContext; // Use the default user context 453 } 454 455 Map<String, LDAP_UserField> fieldMap = null; 456 457 // get more attributes about this user 458 SearchControls searchControls = new SearchControls(); 459 searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); 460 461 String[] attributesToRetrieve = new String[] {"*"}; // Default to all attributes 462 if (CollectionUtil.hasValues(inFields)) 463 { 464 fieldMap = new HashMap<>(inFields.size()); 465 List<String> attrNames = new ArrayList<>(inFields.size()); 466 for (LDAP_UserField field : inFields) 467 { 468 attrNames.add(field.name()); 469 fieldMap.put(field.name(), field); 470 } 471 472 attributesToRetrieve = attrNames.toArray(new String[] {}); 473 } 474 475 476 searchControls.setReturningAttributes(attributesToRetrieve); 477 LOGGER.fine("LDAP Query " + StringUtil.singleQuote(inFilter) + " in context " + StringUtil.singleQuote(mLDAP_GroupContext)); 478 479 // Activate paged results 480 int pageSize = 1000; // 1000 entries per page 481 byte[] cookie = null; 482 int total; 483 inCtx.setRequestControls(new Control[]{ 484 new PagedResultsControl(pageSize, Control.CRITICAL) }); 485 do 486 { 487 // Perform the search 488 NamingEnumeration results = inCtx.search(baseDN, inFilter, searchControls); 489 while (results != null 490 && results.hasMore()) 491 { 492 if (null == users) 493 { 494 users = new ArrayList<>(); 495 } 496 497 U user = getUserFactory().createUserObj(); 498 users.add(user); 499 500 Attributes attrs = ((SearchResult) results.next()).getAttributes(); 501 NamingEnumeration<String> attrEnum = attrs.getIDs(); 502 while (attrEnum.hasMoreElements()) 503 { 504 String attrID = attrEnum.nextElement(); 505 if (fieldMap != null) 506 { 507 LDAP_UserField field = fieldMap.get(attrID); 508 if (field != null) 509 { 510 Method setter = field.getUserObjectSetter(); 511 if (setter != null) 512 { 513 try 514 { 515 setter.invoke(user, attrs.get(attrID) 516 .get() 517 .toString()); 518 } 519 catch (Exception e) 520 { 521 522 } 523 } 524 } 525 } 526 527 user.setField(attrID, attrs.get(attrID) 528 .get() 529 .toString()); 530 } 531 } 532 533 // Examine the paged results control response 534 Control[] controls = inCtx.getResponseControls(); 535 if (controls != null) 536 { 537 for (int i = 0; i < controls.length; i++) 538 { 539 if (controls[i] instanceof PagedResultsResponseControl) 540 { 541 PagedResultsResponseControl prrc = 542 (PagedResultsResponseControl) controls[i]; 543 total = prrc.getResultSize(); 544 cookie = prrc.getCookie(); 545 } 546 else 547 { 548 // Handle other response controls (if any) 549 } 550 } 551 } 552 553 // Re-activate paged results 554 inCtx.setRequestControls(new Control[]{new PagedResultsControl(pageSize, cookie, Control.CRITICAL)}); 555 556 } while (cookie != null); 557 558 return users; 559 } 560 561 //--------------------------------------------------------------------------- 562 private List<U> getInfoForUsersWithoutPaging(LdapContext inCtx, LdapName inBaseDN, String inFilter, List<LDAP_UserField> inFields) 563 { 564 List<U> users = null; 565 566 LdapName baseDN = inBaseDN; 567 if (null == baseDN) 568 { 569 baseDN = mLDAP_UserContext; // Use the default user context 570 } 571 572 try 573 { 574 // get more attributes about this user 575 SearchControls searchControls = new SearchControls(); 576 searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); 577 578 Map<String, LDAP_UserField> fieldMap = null; 579 580 String[] attributesToRetrieve = new String[] {"*"}; // Default to all attributes 581 if (CollectionUtil.hasValues(inFields)) 582 { 583 fieldMap = new HashMap<>(inFields.size()); 584 List<String> attrNames = new ArrayList<>(inFields.size()); 585 for (LDAP_UserField field : inFields) 586 { 587 attrNames.add(field.name()); 588 fieldMap.put(field.name(), field); 589 } 590 591 attributesToRetrieve = attrNames.toArray(new String[] {}); 592 } 593 594 searchControls.setReturningAttributes(attributesToRetrieve); 595 LOGGER.fine("LDAP Query " + StringUtil.singleQuote(inFilter) + " in context " + StringUtil.singleQuote(baseDN)); 596 597 NamingEnumeration enumeration = inCtx.search(baseDN, inFilter, searchControls); 598 while (enumeration.hasMore()) 599 { 600 if (null == users) 601 { 602 users = new ArrayList<>(); 603 } 604 605 U user = getUserFactory().createUserObj(); 606 users.add(user); 607 608 Attributes attrs = ((SearchResult) enumeration.next()).getAttributes(); 609 NamingEnumeration<String> attrEnum = attrs.getIDs(); 610 while (attrEnum.hasMoreElements()) 611 { 612 String attrID = attrEnum.nextElement(); 613 if (fieldMap != null) 614 { 615 LDAP_UserField field = fieldMap.get(attrID); 616 if (field != null) 617 { 618 Method setter = field.getUserObjectSetter(); 619 if (setter != null) 620 { 621 try 622 { 623 setter.invoke(user, attrs.get(attrID).get().toString()); 624 } 625 catch (Exception e) 626 { 627 628 } 629 } 630 } 631 } 632 633 user.setField(attrID, attrs.get(attrID).get().toString()); 634 } 635 } 636 } 637 catch (Exception e) 638 { 639 throw composeException(e); 640 } 641 finally 642 { 643 if (inCtx != null) 644 { 645 try 646 { 647 inCtx.close(); 648 } 649 catch (NamingException e) 650 { 651 652 } 653 } 654 } 655 656 return users; 657 } 658 659 //--------------------------------------------------------------------------- 660 public List<U> getUsersForGroup(String inFilter) 661 { 662 List<U> users; 663 664 LdapContext ctx = null; 665 try 666 { 667 // Create the initial context 668 ctx = getInitialDirContext(mLDAP_PrincipalCredentials); 669 670 if (isPagingSupported(ctx)) 671 { 672 users = getUsersForGroupWithPaging(ctx, inFilter); 673 } 674 else 675 { 676 users = getUsersForGroupWithoutPaging(ctx, inFilter); 677 } 678 } 679 catch (Exception e) 680 { 681 throw composeException(e); 682 } 683 finally 684 { 685 if (ctx != null) 686 { 687 try 688 { 689 ctx.close(); 690 } 691 catch (NamingException e) 692 { 693 694 } 695 } 696 } 697 698 int numUsersFound = (CollectionUtil.hasValues(users) ? users.size() : 0); 699 LOGGER.fine(numUsersFound + " user" + (numUsersFound != 1 ? "s" : "") + " found by LDAP Query " + StringUtil.singleQuote(inFilter) + " in context " + StringUtil.singleQuote(mLDAP_GroupContext)); 700 701 return users; 702 } 703 704 //--------------------------------------------------------------------------- 705 private List<U> getUsersForGroupWithPaging(LdapContext inCtx, String inFilter) 706 throws Exception 707 { 708 List<U> users = null; 709 710 // get more attributes about this user 711 SearchControls searchControls = new SearchControls(); 712 searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); 713 714 String[] attributesToRetrieve = new String[] {"*"}; // Default to all attributes 715 716 searchControls.setReturningAttributes(attributesToRetrieve); 717 LOGGER.fine("LDAP Query " + StringUtil.singleQuote(inFilter) + " in context " + StringUtil.singleQuote(mLDAP_GroupContext)); 718 719 // Activate paged results 720 int pageSize = 20; // 20 entries per page 721 byte[] cookie = null; 722 int total; 723 inCtx.setRequestControls(new Control[]{ 724 new PagedResultsControl(pageSize, Control.CRITICAL) }); 725 do 726 { 727 // Perform the search 728 NamingEnumeration results = inCtx.search(mLDAP_GroupContext, inFilter, searchControls); 729 while (results != null 730 && results.hasMore()) 731 { 732 Attributes attrs = ((SearchResult) results.next()).getAttributes(); 733 NamingEnumeration<String> attrEnum = attrs.getIDs(); 734 while (attrEnum.hasMoreElements()) 735 { 736 String attrID = attrEnum.nextElement(); 737 if (attrID.equalsIgnoreCase("member") 738 || attrID.equalsIgnoreCase("uniquemember")) 739 { 740 Attribute attr = attrs.get(attrID); 741 users = new ArrayList<>(attr.size()); 742 NamingEnumeration<String> memberEnum = (NamingEnumeration<String>) attr.getAll(); 743 while (memberEnum.hasMoreElements()) 744 { 745 LdapName userDN = new LdapName(memberEnum.nextElement()); 746 747 users.add(getInfoForUser(userDN, userDN.remove(userDN.size() - 1) 748 .toString())); 749 } 750 751 } 752 } 753 } 754 755 // Examine the paged results control response 756 Control[] controls = inCtx.getResponseControls(); 757 if (controls != null) 758 { 759 for (int i = 0; i < controls.length; i++) 760 { 761 if (controls[i] instanceof PagedResultsResponseControl) 762 { 763 PagedResultsResponseControl prrc = 764 (PagedResultsResponseControl) controls[i]; 765 total = prrc.getResultSize(); 766 cookie = prrc.getCookie(); 767 } 768 else 769 { 770 // Handle other response controls (if any) 771 } 772 } 773 } 774 775 // Re-activate paged results 776 inCtx.setRequestControls(new Control[]{ new PagedResultsControl(pageSize, cookie, Control.CRITICAL) }); 777 778 } while (cookie != null); 779 780 return users; 781 } 782 783 //--------------------------------------------------------------------------- 784 private List<U> getUsersForGroupWithoutPaging(LdapContext inCtx, String inFilter) 785 throws Exception 786 { 787 List<U> users = null; 788 789 // get more attributes about this user 790 SearchControls searchControls = new SearchControls(); 791 searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE); 792 793 String[] attributesToRetrieve = new String[] {"*"}; // Default to all attributes 794 795 searchControls.setReturningAttributes(attributesToRetrieve); 796 LOGGER.fine("LDAP Query " + StringUtil.singleQuote(inFilter) + " in context " + StringUtil.singleQuote(mLDAP_GroupContext)); 797 798 // Perform the search 799 NamingEnumeration results = inCtx.search(mLDAP_GroupContext, inFilter, searchControls); 800 while (results != null 801 && results.hasMore()) 802 { 803 Attributes attrs = ((SearchResult) results.next()).getAttributes(); 804 NamingEnumeration<String> attrEnum = attrs.getIDs(); 805 while (attrEnum.hasMoreElements()) 806 { 807 String attrID = attrEnum.nextElement(); 808 if (attrID.equalsIgnoreCase("member") 809 || attrID.equalsIgnoreCase("uniquemember")) 810 { 811 Attribute attr = attrs.get(attrID); 812 users = new ArrayList<>(attr.size()); 813 NamingEnumeration<String> memberEnum = (NamingEnumeration<String>) attr.getAll(); 814 while (memberEnum.hasMoreElements()) 815 { 816 LdapName userDN = new LdapName(memberEnum.nextElement()); 817 818 users.add(getInfoForUser(userDN, userDN.remove(userDN.size() - 1).toString())); 819 } 820 } 821 } 822 } 823 824 return users; 825 } 826 827 828 829 830 //########################################################################### 831 // PRIVATE METHODS 832 //########################################################################### 833 834 //--------------------------------------------------------------------------- 835 /** 836 Checks to run before an operation. 837 */ 838 private void crosscheck() 839 { 840 if (null == mLDAP_ServerURL) 841 { 842 throw new LDAP_Exception("No LDAP server has been specified!"); 843 } 844 } 845 846 847 //--------------------------------------------------------------------------- 848 private LdapContext getInitialDirContext(LoginCredentials inCredentials) 849 throws Exception 850 { 851 crosscheck(); 852 853 854 // creating environment for initial context 855 Hashtable<String, String> env = new Hashtable<>(); 856 env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 857 858 if (mReferralHandling != null) 859 { 860 // Set how referrals should be handled 861 env.put(Context.REFERRAL, mReferralHandling.getValue()); 862 } 863 864 LOGGER.info("Setting provider URL to " + StringUtil.singleQuote(mLDAP_ServerURL)); 865 env.put(Context.PROVIDER_URL, mLDAP_ServerURL); 866// env.put(Context.SECURITY_AUTHENTICATION, "simple"); 867 868 if (null == inCredentials) 869 { 870 throw new LDAP_Exception("No credentials specified!"); 871 } 872 873 String securityPrincipal = inCredentials.getUser(); // Active Directory may not want more than this 874 if (mLDAP_PrincipalContext != null) 875 { 876 securityPrincipal = mLDAP_PrincipalFieldName + "=" + inCredentials.getUser() + (mLDAP_PrincipalContext != null ? "," + mLDAP_PrincipalContext : ""); 877 } 878 else if (StringUtil.isSet(mLDAP_PrincipalSuffix) 879 && ! securityPrincipal.endsWith(mLDAP_PrincipalSuffix)) 880 { 881 securityPrincipal += mLDAP_PrincipalSuffix; 882 } 883 884 LOGGER.info("Setting security principal to " + StringUtil.singleQuote(securityPrincipal)); 885 env.put(Context.SECURITY_PRINCIPAL, securityPrincipal); 886 887 env.put(Context.SECURITY_CREDENTIALS, inCredentials.getPasswordString()); 888 889 LOGGER.info("Establishing LDAP connection..."); 890 891 Control[] controls = null; 892 893 // Create the initial context 894 return new InitialLdapContext(env, controls); 895 } 896 897 //--------------------------------------------------------------------------- 898 private boolean isPagingSupported(DirContext inCtx) 899 throws NamingException 900 { 901 return getSupportedControls(inCtx).contains(PAGING_OID); 902 } 903 904 //--------------------------------------------------------------------------- 905 private Set<String> getSupportedControls(DirContext inCtx) 906 throws NamingException 907 { 908 if (null == mSupportedControls) 909 { 910 Hashtable<?, ?> environment = inCtx.getEnvironment(); 911 URI uri = URI.create("" + environment.get("java.naming.provider.url")); 912 final String rootDse = uri.getScheme() + "://" + uri.getAuthority(); 913 914 mSupportedControls = new HashSet<>(10); 915 916 final Attributes attributes = inCtx.getAttributes(rootDse, new String[]{"supportedControl"}); 917 918 final NamingEnumeration attributeValues = attributes.getAll(); 919 while (attributeValues.hasMore()) 920 { 921 final Attribute attribute = (Attribute) attributeValues.next(); 922 final NamingEnumeration supportedControls = attribute.getAll(); 923 while (supportedControls.hasMore()) 924 { 925 mSupportedControls.add((String) supportedControls.next()); 926 } 927 } 928 } 929 930 return mSupportedControls; 931 } 932 933 private LDAP_Exception composeException(Exception inException) 934 { 935 StringBuilderPlus msg = new StringBuilderPlus("Problem querying " + mLDAP_ServerURL + " !"); 936 937 // If the problem was with a certificate, try to get a summary of the cert. 938 Throwable rootException = StackTraceUtil.getRootException(inException); 939 if (rootException != null 940 && rootException instanceof SSLHandshakeException) 941 { 942 try 943 { 944 Set<X509Certificate> certs = CertificateUtil.geLdapCertificates(mLDAP_ServerURL); 945 if (CollectionUtil.hasValues(certs)) 946 { 947 msg.appendln(); 948 msg.appendln(CertificateUtil.generateCertSummary(certs.iterator().next())); 949 } 950 } 951 catch (Exception e2) 952 { 953 // Ignore 954 } 955 } 956 957 return new LDAP_Exception(msg.toString(), inException); 958 } 959}