1 15 16 package org.apache.lenya.ac.ldap; 17 18 import java.io.File ; 19 import java.io.FileInputStream ; 20 import java.io.IOException ; 21 import java.util.Hashtable ; 22 import java.util.Properties ; 23 24 import javax.naming.AuthenticationException ; 25 import javax.naming.Context ; 26 import javax.naming.NamingEnumeration ; 27 import javax.naming.NamingException ; 28 import javax.naming.directory.Attribute ; 29 import javax.naming.directory.Attributes ; 30 import javax.naming.directory.DirContext ; 31 import javax.naming.directory.SearchControls ; 32 import javax.naming.directory.SearchResult ; 33 import javax.naming.ldap.InitialLdapContext ; 34 35 import org.apache.avalon.framework.configuration.Configuration; 36 import org.apache.avalon.framework.configuration.ConfigurationException; 37 import org.apache.avalon.framework.configuration.DefaultConfiguration; 38 import org.apache.lenya.ac.AccessControlException; 39 import org.apache.lenya.ac.file.FileUser; 40 import org.apache.log4j.Category; 41 import org.apache.log4j.Logger; 42 43 import com.sun.jndi.ldap.LdapCtxFactory; 44 45 49 public class LDAPUser extends FileUser { 50 private static Properties defaultProperties = null; 51 private static Category log = Logger.getLogger(LDAPUser.class); 52 53 public static final String LDAP_ID = "ldapid"; 54 private static String LDAP_PROPERTIES_FILE = "ldap.properties"; 55 private static String PROVIDER_URL_PROP = "provider-url"; 56 private static String MGR_DN_PROP = "mgr-dn"; 57 private static String MGR_PW_PROP = "mgr-pw"; 58 private static String KEY_STORE_PROP = "key-store"; 59 private static String SECURITY_PROTOCOL_PROP = "security-protocol"; 60 private static String SECURITY_AUTHENTICATION_PROP = "security-authentication"; 61 private static String USR_ATTR_PROP = "usr-attr"; 62 private static String USR_ATTR_DEFAULT = "uid"; 63 private static String USR_NAME_ATTR_PROP = "usr-name-attr"; 64 private static String USR_NAME_ATTR_DEFAULT = "gecos"; 65 private static String USR_BRANCH_PROP = "usr-branch"; 66 private static String USR_BRANCH_DEFAULT = "ou=People"; 67 private static String USR_AUTH_TYPE_PROP = "usr-authentication"; 68 private static String USR_AUTH_TYPE_DEFAULT = "simple"; 69 private static String BASE_DN_PROP = "base-dn"; 70 private static String DOMAIN_NAME_PROP = "domain-name"; 71 72 private String ldapId; 73 private String ldapName; 74 75 private static String PARTIAL_USER_DN_PROP = "partial-user-dn"; 77 78 81 public LDAPUser() { 82 } 83 84 88 public LDAPUser(File configurationDirectory) { 89 setConfigurationDirectory(configurationDirectory); 90 } 91 92 101 public LDAPUser(File configurationDirectory, String id, String email, String ldapId) 102 throws ConfigurationException { 103 super(configurationDirectory, id, null, email, null); 104 this.ldapId = ldapId; 105 106 initialize(); 107 } 108 109 115 public void configure(Configuration config) throws ConfigurationException { 116 super.configure(config); 117 ldapId = config.getChild(LDAP_ID).getValue(); 118 119 initialize(); 120 } 121 122 129 public boolean existsUser(String ldapId) throws AccessControlException { 130 131 if (log.isDebugEnabled()) 132 log.debug("existsUser() checking id " + ldapId); 133 134 boolean exists = false; 135 136 try { 137 readProperties(); 138 SearchResult entry = getDirectoryEntry(ldapId); 139 140 exists = (entry != null); 141 142 } catch (Exception e) { 143 if (log.isDebugEnabled()) 144 log.debug("existsUser() for id " + ldapId + " got exception: " + e); 145 throw new AccessControlException("Exception during search: ", e); 146 } 147 148 return exists; 149 } 150 151 165 protected void initialize() throws ConfigurationException { 166 DirContext context = null; 167 try { 168 if (log.isDebugEnabled()) 169 log.debug("initialize() getting entry ..."); 170 171 SearchResult entry = getDirectoryEntry(ldapId); 172 StringBuffer name = new StringBuffer (); 173 174 if (entry != null) { 175 176 String usrNameAttr = 177 defaultProperties.getProperty(USR_NAME_ATTR_PROP, USR_NAME_ATTR_DEFAULT); 178 179 if (log.isDebugEnabled()) 180 log.debug("initialize() got entry, going to look for attribute " + usrNameAttr + " in entry, which is: " + entry); 181 182 Attributes attributes = entry.getAttributes(); 183 if (attributes != null) { 184 Attribute userNames = attributes.get(usrNameAttr); 185 if (userNames != null) { 186 for (NamingEnumeration nenum = userNames.getAll(); nenum.hasMore(); nenum.next()) { 187 name.append((String )userNames.get()); 188 } 189 } 190 } 191 } 192 ldapName = name.toString(); 193 if (log.isDebugEnabled()) 194 log.debug("initialize() set name to " + ldapName); 195 196 } catch (Exception e) { 197 throw new ConfigurationException("Could not read properties", e); 198 } finally { 199 try { 200 if (context != null) { 201 close(context); 202 } 203 } catch (NamingException e) { 204 throw new ConfigurationException("Closing context failed: ", e); 205 } 206 } 207 } 208 209 212 protected Configuration createConfiguration() { 213 DefaultConfiguration config = (DefaultConfiguration) super.createConfiguration(); 214 215 DefaultConfiguration child = new DefaultConfiguration(LDAP_ID); 217 child.setValue(ldapId); 218 config.addChild(child); 219 220 return config; 221 } 222 223 228 public String getLdapId() { 229 return ldapId; 230 } 231 232 237 public void setLdapId(String string) { 238 ldapId = string; 239 } 240 241 251 public boolean authenticate(String password) { 252 253 boolean authenticated = false; 254 String principal = ""; 255 Context ctx = null; 256 257 try { 258 principal = getPrincipal(); 259 260 if (log.isDebugEnabled()) 261 log.debug("Authenticating with principal [" + principal + "]"); 262 263 ctx = bind(principal, password, 264 defaultProperties.getProperty(USR_AUTH_TYPE_PROP, 265 USR_AUTH_TYPE_DEFAULT)); 266 authenticated = true; 267 close(ctx); 268 if (log.isDebugEnabled()) { 269 log.debug("Context closed."); 270 } 271 } catch (IOException e) { 272 log.warn("authenticate handling IOException, check your setup: " + e); 273 } catch (AuthenticationException e) { 274 log.info("authenticate failed for principal " + principal + ", exception " + e); 275 } catch (NamingException e) { 276 if (log.isInfoEnabled()) { 280 log.info("Bind for user " + principal + " to Ldap server failed: ", e); 281 } 282 } 283 284 return authenticated; 285 286 } 287 288 291 public String getName() { 292 return ldapName; 293 } 294 295 302 public void setName(String string) { 303 } 306 307 312 public void setPassword(String plainTextPassword) { 313 setEncryptedPassword(null); 314 } 315 316 321 protected void setEncryptedPassword(String encryptedPassword) { 322 encryptedPassword = null; 323 } 324 325 334 private DirContext bind(String principal, String credentials, 335 String authMethod) throws NamingException { 336 337 log.info("Binding principal: [" + principal + "]"); 338 339 Hashtable env = new Hashtable (); 340 341 System.setProperty("javax.net.ssl.trustStore", getConfigurationDirectory() 342 .getAbsolutePath() 343 + File.separator + defaultProperties.getProperty(KEY_STORE_PROP)); 344 345 env.put(Context.INITIAL_CONTEXT_FACTORY, LdapCtxFactory.class.getName()); 346 347 String prop = defaultProperties.getProperty(PROVIDER_URL_PROP); 348 if (prop == null) 349 throw new RuntimeException ("LDAP configuration error: property " + 350 PROVIDER_URL_PROP + 351 " is not set in property file " + 352 LDAP_PROPERTIES_FILE); 353 env.put(Context.PROVIDER_URL, prop); 354 355 prop = defaultProperties.getProperty(SECURITY_PROTOCOL_PROP); 356 if (prop == null) 357 throw new RuntimeException ("LDAP configuration error: property " + 358 SECURITY_PROTOCOL_PROP + 359 " is not set in property file " + 360 LDAP_PROPERTIES_FILE); 361 env.put(Context.SECURITY_PROTOCOL, prop); 362 363 env.put(Context.SECURITY_AUTHENTICATION, authMethod); 364 if (authMethod != null && ! authMethod.equals("none")) { 365 env.put(Context.SECURITY_PRINCIPAL, principal); 366 env.put(Context.SECURITY_CREDENTIALS, credentials); 367 } 368 369 DirContext ctx = new InitialLdapContext (env, null); 370 371 log.info("Finished binding principal."); 372 373 return ctx; 374 } 375 376 382 private void close(Context ctx) throws NamingException { 383 ctx.close(); 384 } 385 386 391 private void readProperties() throws IOException { 392 File propertiesFile = new File (getConfigurationDirectory(), LDAP_PROPERTIES_FILE); 394 395 if (defaultProperties == null) { 396 defaultProperties = new Properties (); 397 398 FileInputStream in = null; 399 try { 400 in = new FileInputStream (propertiesFile); 401 defaultProperties.load(in); 402 } finally { 403 if (in != null) { 404 in.close(); 405 } 406 } 407 } 408 } 409 410 418 private boolean isSubtreeSearch() { 419 boolean recurse = false; 420 String usrBranchProp = defaultProperties.getProperty(USR_BRANCH_PROP); 421 if (usrBranchProp != null) 422 if (usrBranchProp.trim().length() == 0) 423 recurse = true; 424 425 return recurse; 426 } 427 428 429 private SearchResult getDirectoryEntry(String userId) 430 throws NamingException , IOException 431 { 432 DirContext context = null; 433 String searchFilter = ""; 434 String objectName = ""; 435 boolean recursiveSearch; 436 SearchResult result = null; 437 438 try { 439 readProperties(); 440 441 context = bind(defaultProperties.getProperty(MGR_DN_PROP), 442 defaultProperties.getProperty(MGR_PW_PROP), 443 defaultProperties.getProperty(SECURITY_AUTHENTICATION_PROP)); 444 445 String userAttribute = 448 defaultProperties.getProperty(USR_ATTR_PROP, USR_ATTR_DEFAULT); 449 searchFilter = "(" + userAttribute + "=" + userId + ")"; 450 SearchControls scope = new SearchControls (); 451 NamingEnumeration results; 452 453 recursiveSearch = isSubtreeSearch(); 454 if (recursiveSearch) { 455 scope.setSearchScope(SearchControls.SUBTREE_SCOPE); 456 objectName = defaultProperties.getProperty(PROVIDER_URL_PROP); 457 } 458 else { 459 scope.setSearchScope(SearchControls.ONELEVEL_SCOPE); 460 objectName = 461 defaultProperties.getProperty(USR_BRANCH_PROP, USR_BRANCH_DEFAULT); 462 } 463 464 if (log.isDebugEnabled()) 465 log.debug("searching object " + objectName + " filtering with " + searchFilter + ", recursive search ? " + recursiveSearch); 466 467 results = context.search(objectName, searchFilter, scope); 468 469 if (results != null && results.hasMore()) { 470 result = (SearchResult )results.next(); 471 472 488 } 489 } 490 catch (NamingException e) { 491 if (log.isDebugEnabled()) 492 log.debug("NamingException caught when searching on objectName = " + objectName + " and searchFilter=" + searchFilter + ", this exception will be propagated: " + e); 493 throw e; 494 } 495 finally { 496 try { 497 if (context != null) { 498 close(context); 499 } 500 } catch (NamingException e) { 501 log.warn("this should not happen: exception closing context " + e); 502 } 503 } 504 return result; 505 } 506 507 519 private String getPrincipal() throws IOException , NamingException { 520 521 String principal; 522 523 String domainProp = defaultProperties.getProperty(DOMAIN_NAME_PROP); 525 if (domainProp != null && domainProp.trim().length() > 0) { 526 principal = domainProp + "\\" + getLdapId(); 527 } 528 else { 529 if (isSubtreeSearch()) { 530 SearchResult entry = getDirectoryEntry(getLdapId()); 532 principal = entry.getName(); 533 if (entry.isRelative()) { 534 if (principal.length()>0){ 535 principal = principal +","+ defaultProperties.getProperty(BASE_DN_PROP); 536 } 537 } 538 } 539 else { 540 principal = constructPrincipal(getLdapId()); 542 } 543 } 544 545 return principal; 546 } 547 548 553 private String constructPrincipal(String userId) { 554 StringBuffer principal = new StringBuffer (); 555 principal 556 .append(defaultProperties.getProperty(USR_ATTR_PROP, USR_ATTR_DEFAULT)) 557 .append("=") 558 .append(userId) 559 .append(","); 560 561 String baseDn = defaultProperties.getProperty(BASE_DN_PROP); 562 if (baseDn != null && baseDn.length() > 0) { 563 String usrBranch = defaultProperties.getProperty(USR_BRANCH_PROP); 565 if (usrBranch != null) { 566 if (usrBranch.trim().length() > 0) 567 principal.append(usrBranch).append(","); 568 } 569 else 570 principal.append(USR_BRANCH_DEFAULT).append(","); 571 572 principal.append(defaultProperties.getProperty(BASE_DN_PROP)); 573 } 574 else { 575 log.warn("getPrincipal() read a deprecated format in ldap properties, please update"); 577 principal.append(defaultProperties.getProperty(PARTIAL_USER_DN_PROP)); 578 } 579 580 if (log.isDebugEnabled()) 581 log.debug("getPrincipal() returning " + principal.toString()); 582 583 return principal.toString(); 584 } 585 586 587 } 588 | Popular Tags |