1 11 12 package org.jivesoftware.messenger.ldap; 13 14 import org.jivesoftware.messenger.user.UserNotFoundException; 15 import org.jivesoftware.util.JiveGlobals; 16 import org.jivesoftware.util.Log; 17 18 import javax.naming.Context ; 19 import javax.naming.NamingEnumeration ; 20 import javax.naming.NamingException ; 21 import javax.naming.directory.DirContext ; 22 import javax.naming.directory.InitialDirContext ; 23 import javax.naming.directory.SearchControls ; 24 import javax.naming.directory.SearchResult ; 25 import javax.naming.ldap.InitialLdapContext ; 26 import javax.naming.ldap.LdapContext ; 27 import java.net.URLEncoder ; 28 import java.util.Hashtable ; 29 30 59 public class LdapManager { 60 61 private String host; 62 private int port = 389; 63 private String usernameField = "uid"; 64 private String nameField = "cn"; 65 private String emailField = "mail"; 66 private String baseDN = ""; 67 private String alternateBaseDN = null; 68 private String adminDN = null; 69 private String adminPassword; 70 private boolean ldapDebugEnabled = false; 71 private boolean sslEnabled = false; 72 private String initialContextFactory; 73 private boolean followReferrals = false; 74 private boolean connectionPoolEnabled = true; 75 private String searchFilter = null; 76 77 private String groupNameField = "cn"; 78 private String groupMemberField = "member"; 79 private String groupDescriptionField = "description"; 80 private boolean posixEnabled = false; 81 private String groupSearchFilter = null; 82 83 private static LdapManager instance = new LdapManager(); 84 85 90 public static LdapManager getInstance() { 91 return instance; 92 } 93 94 98 private LdapManager() { 99 this.host = JiveGlobals.getXMLProperty("ldap.host"); 100 String portStr = JiveGlobals.getXMLProperty("ldap.port"); 101 if (portStr != null) { 102 try { 103 this.port = Integer.parseInt(portStr); 104 } 105 catch (NumberFormatException nfe) { } 106 } 107 if (JiveGlobals.getXMLProperty("ldap.usernameField") != null) { 108 this.usernameField = JiveGlobals.getXMLProperty("ldap.usernameField"); 109 } 110 if (JiveGlobals.getXMLProperty("ldap.baseDN") != null) { 111 this.baseDN = JiveGlobals.getXMLProperty("ldap.baseDN"); 112 } 113 if (JiveGlobals.getXMLProperty("ldap.alternateBaseDN") != null) { 114 this.alternateBaseDN = JiveGlobals.getXMLProperty("ldap.alternateBaseDN"); 115 } 116 if (JiveGlobals.getXMLProperty("ldap.nameField") != null) { 117 this.nameField = JiveGlobals.getXMLProperty("ldap.nameField"); 118 } 119 if (JiveGlobals.getXMLProperty("ldap.emailField") != null) { 120 this.emailField = JiveGlobals.getXMLProperty("ldap.emailField"); 121 } 122 if (JiveGlobals.getXMLProperty("ldap.connectionPoolEnabled") != null) { 123 this.connectionPoolEnabled = Boolean.valueOf( 124 JiveGlobals.getXMLProperty("ldap.connectionPoolEnabled")).booleanValue(); 125 } 126 if (JiveGlobals.getXMLProperty("ldap.searchFilter") != null) { 127 this.searchFilter = JiveGlobals.getXMLProperty("ldap.searchFilter"); 128 } 129 else { 130 StringBuilder filter = new StringBuilder (); 131 filter.append("(").append(usernameField).append("={0})"); 132 this.searchFilter = filter.toString(); 133 } 134 if (JiveGlobals.getXMLProperty("ldap.groupNameField") != null) { 135 this.groupNameField = JiveGlobals.getXMLProperty("ldap.groupNameField"); 136 } 137 if (JiveGlobals.getXMLProperty("ldap.groupMemberField") != null) { 138 this.groupMemberField = JiveGlobals.getXMLProperty("ldap.groupMemberField"); 139 } 140 if (JiveGlobals.getXMLProperty("ldap.groupDescriptionField") != null) { 141 this.groupDescriptionField = JiveGlobals.getXMLProperty("ldap.groupDescriptionField"); 142 } 143 if (JiveGlobals.getXMLProperty("ldap.posixEnabled") != null) { 144 this.posixEnabled = Boolean.valueOf(JiveGlobals.getXMLProperty("ldap.posixEnabled")); 145 } 146 if (JiveGlobals.getXMLProperty("ldap.groupSearchFilter") != null) { 147 this.groupSearchFilter = JiveGlobals.getXMLProperty("ldap.groupSearchFilter"); 148 } 149 else { 150 this.groupSearchFilter = "("+groupMemberField+"={0})"; 151 } 152 153 this.adminDN = JiveGlobals.getXMLProperty("ldap.adminDN"); 154 if (adminDN != null && adminDN.trim().equals("")) { 155 adminDN = null; 156 } 157 this.adminPassword = JiveGlobals.getXMLProperty("ldap.adminPassword"); 158 this.ldapDebugEnabled = Boolean.valueOf(JiveGlobals.getXMLProperty( 159 "ldap.debugEnabled")).booleanValue(); 160 this.sslEnabled = Boolean.valueOf(JiveGlobals.getXMLProperty( 161 "ldap.sslEnabled")).booleanValue(); 162 this.followReferrals = Boolean.valueOf(JiveGlobals.getXMLProperty( 163 "ldap.autoFollowReferrals")).booleanValue(); 164 this.initialContextFactory = JiveGlobals.getXMLProperty("ldap.initialContextFactory"); 165 if (initialContextFactory != null) { 166 try { 167 Class.forName(initialContextFactory); 168 } 169 catch (ClassNotFoundException cnfe) { 170 Log.error("Initial context factory class failed to load: " + initialContextFactory + 171 ". Using default initial context factory class instead."); 172 initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory"; 173 } 174 } 175 else { 177 initialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory"; 178 } 179 180 if (Log.isDebugEnabled()) { 181 Log.debug("Created new LdapManager() instance, fields:"); 182 Log.debug("\t host: " + host); 183 Log.debug("\t port: " + port); 184 Log.debug("\t usernamefield: " + usernameField); 185 Log.debug("\t baseDN: " + baseDN); 186 Log.debug("\t alternateBaseDN: " + alternateBaseDN); 187 Log.debug("\t nameField: " + nameField); 188 Log.debug("\t emailField: " + emailField); 189 Log.debug("\t adminDN: " + adminDN); 190 Log.debug("\t adminPassword: " + adminPassword); 191 Log.debug("\t searchFilter: " + searchFilter); 192 Log.debug("\t ldapDebugEnabled: " + ldapDebugEnabled); 193 Log.debug("\t sslEnabled: " + sslEnabled); 194 Log.debug("\t initialContextFactory: " + initialContextFactory); 195 Log.debug("\t connectionPoolEnabled: " + connectionPoolEnabled); 196 Log.debug("\t autoFollowReferrals: " + followReferrals); 197 Log.debug("\t groupNameField: " + groupNameField); 198 Log.debug("\t groupMemberField: " + groupMemberField); 199 Log.debug("\t groupDescriptionField: " + groupDescriptionField); 200 Log.debug("\t posixEnabled: " + posixEnabled); 201 Log.debug("\t groupSearchFilter: " + groupSearchFilter); 202 } 203 } 204 205 213 public LdapContext getContext() throws NamingException { 214 return getContext(baseDN); 215 } 216 217 226 public LdapContext getContext(String baseDN) throws NamingException { 227 boolean debug = Log.isDebugEnabled(); 228 if (debug) { 229 Log.debug("Creating a DirContext in LdapManager.getContext()..."); 230 } 231 232 Hashtable env = new Hashtable (); 234 env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory); 235 env.put(Context.PROVIDER_URL, getProviderURL(baseDN)); 236 if (sslEnabled) { 237 env.put("java.naming.ldap.factory.socket", 238 "org.jivesoftware.util.SimpleSSLSocketFactory"); 239 env.put(Context.SECURITY_PROTOCOL, "ssl"); 240 } 241 242 if (adminDN != null) { 244 env.put(Context.SECURITY_AUTHENTICATION, "simple"); 245 env.put(Context.SECURITY_PRINCIPAL, adminDN); 246 if (adminPassword != null) { 247 env.put(Context.SECURITY_CREDENTIALS, adminPassword); 248 } 249 } 250 else { 252 env.put(Context.SECURITY_AUTHENTICATION, "none"); 253 } 254 255 if (ldapDebugEnabled) { 256 env.put("com.sun.jndi.ldap.trace.ber", System.err); 257 } 258 if (connectionPoolEnabled) { 259 env.put("com.sun.jndi.ldap.connect.pool", "true"); 260 } 261 if (followReferrals) { 262 env.put(Context.REFERRAL, "follow"); 263 } 264 265 if (debug) { 266 Log.debug("Created hashtable with context values, attempting to create context..."); 267 } 268 LdapContext context = new InitialLdapContext (env, null); 270 if (debug) { 271 Log.debug("... context created successfully, returning."); 272 } 273 return context; 274 } 275 276 284 public boolean checkAuthentication(String userDN, String password) { 285 boolean debug = Log.isDebugEnabled(); 286 if (debug) { 287 Log.debug("In LdapManager.checkAuthentication(userDN, password), userDN is: " + userDN + "..."); 288 } 289 290 DirContext ctx = null; 291 try { 292 Hashtable env = new Hashtable (); 294 env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory); 295 env.put(Context.PROVIDER_URL, getProviderURL(baseDN)); 296 if (sslEnabled) { 297 env.put("java.naming.ldap.factory.socket", 298 "org.jivesoftware.util.SimpleSSLSocketFactory"); 299 env.put(Context.SECURITY_PROTOCOL, "ssl"); 300 } 301 env.put(Context.SECURITY_AUTHENTICATION, "simple"); 302 env.put(Context.SECURITY_PRINCIPAL, userDN + "," + baseDN); 303 env.put(Context.SECURITY_CREDENTIALS, password); 304 if (!sslEnabled) { 307 env.put("com.sun.jndi.ldap.connect.timeout", "10000"); 308 } 309 if (ldapDebugEnabled) { 310 env.put("com.sun.jndi.ldap.trace.ber", System.err); 311 } 312 if (debug) { 313 Log.debug("Created context values, attempting to create context..."); 314 } 315 ctx = new InitialDirContext (env); 316 if (debug) { 317 Log.debug("... context created successfully, returning."); 318 } 319 } 320 catch (NamingException ne) { 321 if (alternateBaseDN != null) { 323 try { ctx.close(); } 324 catch (Exception ignored) { } 325 try { 326 Hashtable env = new Hashtable (); 328 env.put(Context.INITIAL_CONTEXT_FACTORY, initialContextFactory); 330 env.put(Context.PROVIDER_URL, getProviderURL(alternateBaseDN)); 331 if (sslEnabled) { 332 env.put("java.naming.ldap.factory.socket", "org.jivesoftware.util.SimpleSSLSocketFactory"); 333 env.put(Context.SECURITY_PROTOCOL, "ssl"); 334 } 335 env.put(Context.SECURITY_AUTHENTICATION, "simple"); 336 env.put(Context.SECURITY_PRINCIPAL, userDN + "," + alternateBaseDN); 337 env.put(Context.SECURITY_CREDENTIALS, password); 338 if (!sslEnabled) { 341 env.put("com.sun.jndi.ldap.connect.timeout", "10000"); 342 } 343 if (ldapDebugEnabled) { 344 env.put("com.sun.jndi.ldap.trace.ber", System.err); 345 } 346 if (debug) { 347 Log.debug("Created context values, attempting to create context..."); 348 } 349 ctx = new InitialDirContext (env); 350 } 351 catch (NamingException e) { 352 if (debug) { 353 Log.debug("Caught a naming exception when creating InitialContext", ne); 354 } 355 return false; 356 } 357 } 358 else { 359 if (debug) { 360 Log.debug("Caught a naming exception when creating InitialContext", ne); 361 } 362 return false; 363 } 364 } 365 finally { 366 try { ctx.close(); } 367 catch (Exception ignored) { } 368 } 369 return true; 370 } 371 372 396 public String findUserDN(String username) throws Exception { 397 try { 398 return findUserDN(username, baseDN); 399 } 400 catch (Exception e) { 401 if (alternateBaseDN != null) { 402 return findUserDN(username, alternateBaseDN); 403 } 404 else { 405 throw e; 406 } 407 } 408 } 409 410 435 public String findUserDN(String username, String baseDN) throws Exception { 436 boolean debug = Log.isDebugEnabled(); 437 if (debug) { 438 Log.debug("Trying to find a user's DN based on their username. " + usernameField + ": " + username 439 + ", Base DN: " + baseDN + "..."); 440 } 441 DirContext ctx = null; 442 try { 443 ctx = getContext(baseDN); 444 if (debug) { 445 Log.debug("Starting LDAP search..."); 446 } 447 SearchControls constraints = new SearchControls (); 449 constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); 450 constraints.setReturningAttributes(new String [] { usernameField }); 451 452 NamingEnumeration answer = ctx.search("", searchFilter, new String [] {username}, 453 constraints); 454 455 if (debug) { 456 Log.debug("... search finished"); 457 } 458 459 if (answer == null || !answer.hasMoreElements()) { 460 if (debug) { 461 Log.debug("User DN based on username '" + username + "' not found."); 462 } 463 throw new UserNotFoundException("Username " + username + " not found"); 464 } 465 String userDN = ((SearchResult )answer.next()).getName(); 466 if (answer.hasMoreElements()) { 472 if (debug) { 473 Log.debug("Search for userDN based on username '" + username + "' found multiple " + 474 "responses, throwing exception."); 475 } 476 throw new UserNotFoundException("LDAP username lookup for " + username + 477 " matched multiple entries."); 478 } 479 return userDN; 480 } 481 catch (Exception e) { 482 if (debug) { 483 Log.debug("Exception thrown when searching for userDN based on username '" + username + "'", e); 484 } 485 throw e; 486 } 487 finally { 488 try { ctx.close(); } 489 catch (Exception ignored) { } 490 } 491 } 492 493 500 private String getProviderURL(String baseDN) { 501 String ldapURL = ""; 502 try { 503 ldapURL = "ldap://" + host + ":" + port + "/" + 505 URLEncoder.encode(baseDN, "UTF-8"); 506 ldapURL = ldapURL.replaceAll("\\+", "%20"); 508 } 509 catch (java.io.UnsupportedEncodingException e) { 510 ldapURL = "ldap://" + host + ":" + port + "/" + baseDN; 512 } 513 return ldapURL; 514 } 515 516 523 public String getHost() { 524 return host; 525 } 526 527 534 public void setHost(String host) { 535 this.host = host; 536 JiveGlobals.setXMLProperty("ldap.host", host); 537 } 538 539 545 public int getPort() { 546 return port; 547 } 548 549 555 public void setPort(int port) { 556 this.port = port; 557 JiveGlobals.setXMLProperty("ldap.port", ""+port); 558 } 559 560 567 public boolean isDebugEnabled() { 568 return ldapDebugEnabled; 569 } 570 571 578 public void setDebugEnabled(boolean debugEnabled) { 579 this.ldapDebugEnabled = debugEnabled; 580 JiveGlobals.setXMLProperty("ldap.ldapDebugEnabled", ""+debugEnabled); 581 } 582 583 588 public boolean isSslEnabled() { 589 return sslEnabled; 590 } 591 592 597 public void setSslEnabled(boolean sslEnabled) { 598 this.sslEnabled = sslEnabled; 599 JiveGlobals.setXMLProperty("ldap.sslEnabled", ""+sslEnabled); 600 } 601 602 608 public String getUsernameField() { 609 return usernameField; 610 } 611 612 619 public void setUsernameField(String usernameField) { 620 this.usernameField = usernameField; 621 if (usernameField == null) { 622 JiveGlobals.deleteXMLProperty("ldap.usernameField"); 623 } 624 else { 625 JiveGlobals.setXMLProperty("ldap.usernameField", usernameField); 626 } 627 } 628 629 635 public String getNameField() { 636 return nameField; 637 } 638 639 645 public void setNameField(String nameField) { 646 this.nameField = nameField; 647 if (nameField == null) { 648 JiveGlobals.deleteXMLProperty("ldap.nameField"); 649 } 650 else { 651 JiveGlobals.setXMLProperty("ldap.nameField", nameField); 652 } 653 } 654 655 662 public String getEmailField() { 663 return emailField; 664 } 665 666 673 public void setEmailField(String emailField) { 674 this.emailField = emailField; 675 if (emailField == null) { 676 JiveGlobals.deleteXMLProperty("ldap.emailField"); 677 } 678 else { 679 JiveGlobals.setXMLProperty("ldap.emailField", emailField); 680 } 681 } 682 683 689 public String getBaseDN() { 690 return baseDN; 691 } 692 693 699 public void setBaseDN(String baseDN) { 700 this.baseDN = baseDN; 701 JiveGlobals.setXMLProperty("ldap.baseDN", baseDN); 702 } 703 704 712 public String getAlternateBaseDN() { 713 return alternateBaseDN; 714 } 715 716 723 public void setAlternateBaseDN(String alternateBaseDN) { 724 this.alternateBaseDN = alternateBaseDN; 725 if (alternateBaseDN == null) { 726 JiveGlobals.deleteXMLProperty("ldap.alternateBaseDN"); 727 } 728 else { 729 JiveGlobals.setXMLProperty("ldap.alternateBaseDN", alternateBaseDN); 730 } 731 } 732 733 739 public String getAdminDN() { 740 return adminDN; 741 } 742 743 749 public void setAdminDN(String adminDN) { 750 this.adminDN = adminDN; 751 JiveGlobals.setXMLProperty("ldap.adminDN", adminDN); 752 } 753 754 760 public String getAdminPassword() { 761 return adminPassword; 762 } 763 764 770 public void setAdminPassword(String adminPassword) { 771 this.adminPassword = adminPassword; 772 JiveGlobals.setXMLProperty("ldap.adminPassword", adminPassword); 773 } 774 775 780 public String getSearchFilter() { 781 return searchFilter; 782 } 783 784 791 public void setSearchFilter(String searchFilter) { 792 if (searchFilter == null || "".equals(searchFilter)) { 793 StringBuilder filter = new StringBuilder (); 794 filter.append("(").append(usernameField).append("={0})"); 795 this.searchFilter = filter.toString(); 796 JiveGlobals.deleteXMLProperty("ldap.searchFilter"); 797 } 798 else { 799 this.searchFilter = searchFilter; 800 JiveGlobals.setXMLProperty("ldap.searchFilter", searchFilter); 801 } 802 } 803 804 810 public String getGroupNameField() { 811 return groupNameField; 812 } 813 814 819 public void setGroupNameField(String groupNameField) { 820 this.groupNameField = groupNameField; 821 JiveGlobals.setXMLProperty("ldap.groupNameField", groupNameField); 822 } 823 824 830 public String getGroupMemberField() { 831 return groupMemberField; 832 } 833 834 840 public void setGroupmemberField(String groupMemberField) { 841 this.groupMemberField = groupMemberField; 842 JiveGlobals.setXMLProperty("ldap.groupMemberField", groupMemberField); 843 } 844 845 851 public String getGroupDescriptionField() { 852 return groupDescriptionField; 853 } 854 855 861 public void setGroupDescriptionField(String groupDescriptionField) { 862 this.groupDescriptionField = groupDescriptionField; 863 JiveGlobals.setXMLProperty("ldap.groupDescriptionField", groupDescriptionField); 864 } 865 866 872 public boolean getPosixEnabled() { 873 return posixEnabled; 874 } 875 876 882 public void setPosixEnabled(boolean posixEnabled) { 883 this.posixEnabled = posixEnabled; 884 Boolean b = new Boolean (posixEnabled); 885 JiveGlobals.setXMLProperty("ldap.posixEnabled", b.toString()); 886 } 887 888 894 public String getGroupSearchFilter() { 895 return groupSearchFilter; 896 } 897 898 904 public void setGroupSearchFilter(String groupSearchFilter) { 905 this.groupSearchFilter = groupSearchFilter; 906 JiveGlobals.setXMLProperty("ldap.groupSearchFilter", groupSearchFilter); 907 } 908 } | Popular Tags |