1 17 18 package org.apache.james.userrepository; 19 20 import org.apache.avalon.framework.activity.Initializable; 21 import org.apache.avalon.framework.component.ComponentManager; 22 import org.apache.avalon.framework.component.Composable; 23 import org.apache.avalon.framework.configuration.Configurable; 24 import org.apache.avalon.framework.configuration.Configuration; 25 import org.apache.avalon.framework.configuration.ConfigurationException; 26 import org.apache.avalon.framework.context.Context; 27 import org.apache.avalon.framework.context.ContextException; 28 import org.apache.avalon.framework.context.Contextualizable; 29 import org.apache.avalon.framework.logger.AbstractLogEnabled; 30 import org.apache.avalon.framework.logger.LogEnabled; 31 import org.apache.avalon.framework.logger.Logger; 32 import org.apache.james.Constants; 33 import org.apache.james.services.User; 34 import org.apache.james.services.UsersRepository; 35 36 import javax.naming.AuthenticationException; 37 import javax.naming.NamingEnumeration; 38 import javax.naming.NamingException; 39 import javax.naming.directory.*; 40 import java.util.*; 41 42 49 public class UsersLDAPRepository 50 extends AbstractLogEnabled 51 implements UsersRepository, Composable, Configurable, Contextualizable, Initializable{ 52 53 private ComponentManager comp; 54 55 private Logger logger; 56 private String path; 57 private String name; 58 private String destination; 59 private String type; 60 private String model; 61 private DirContext ctx; 62 63 private String LDAPHost; 64 private String rootNodeDN; 65 private String rootURL; 66 private String serverRDN; 67 private String baseNodeDN; 68 private String baseURL; 69 private String mailAddressAttr; 70 private String identAttr; 71 private String authType; 72 private String principal; 73 private String password; 74 private String usersDomain; 75 private String membersAttr; 76 private boolean manageGroupAttr; 77 private String groupAttr; 78 private boolean managePasswordAttr; 79 private String passwordAttr; 80 81 84 public void contextualize(Context context) 85 throws ContextException { 86 Collection serverNames 87 = (Collection)context.get(Constants.SERVER_NAMES); 88 usersDomain = (String)serverNames.iterator().next(); 89 } 90 91 94 public void compose(ComponentManager compMgr) { 95 this.comp = compMgr; 96 } 97 98 101 public void configure(Configuration conf) 102 throws ConfigurationException { 103 104 LDAPHost = conf.getChild("LDAPServer").getValue(); 105 rootNodeDN = conf.getChild("LDAPRoot").getValue(); 106 serverRDN = conf.getChild("ThisServerRDN").getValue(); 107 mailAddressAttr 108 = conf.getChild("MailAddressAttribute").getValue(); 109 identAttr = conf.getChild("IdentityAttribute").getValue(); 110 authType = conf.getChild("AuthenticationType").getValue(); 111 principal = conf.getChild("Principal").getValue(); 112 password = conf.getChild("Password").getValue(); 113 114 membersAttr = conf.getChild("MembersAttribute").getValue(); 115 manageGroupAttr 116 = conf.getChild("ManageGroupAttribute").getValueAsBoolean( false ); 117 groupAttr = conf.getChild("GroupAttribute").getValue(); 118 managePasswordAttr = conf.getChild("ManagePasswordAttribute").getValueAsBoolean( false ); 119 passwordAttr = conf.getChild("PasswordAttribute").getValue(); 120 } 121 122 public void setServerRoot() { 123 StringBuffer serverRootBuffer = 124 new StringBuffer(128) 125 .append(serverRDN) 126 .append(", ") 127 .append(rootNodeDN); 128 this.setBase(serverRootBuffer.toString()); 129 } 130 131 public void setBase(String base) { 132 baseNodeDN = base; 133 } 134 135 138 public void initialize() throws Exception { 139 StringBuffer urlBuffer = 141 new StringBuffer(128) 142 .append(LDAPHost) 143 .append("/"); 144 rootURL = urlBuffer.toString() + rootNodeDN; 145 baseURL = urlBuffer.toString() + baseNodeDN; 146 147 getLogger().info("Creating initial context from " + baseURL); 148 150 Hashtable env = new Hashtable(); 151 env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, 152 "com.sun.jndi.ldap.LdapCtxFactory"); 153 env.put(javax.naming.Context.PROVIDER_URL, baseURL); 154 155 try { 156 ctx = new InitialDirContext(env); } catch (Exception e) { 158 getLogger().error("Exception creating InitialDirContext: ", e); 159 } 160 161 getLogger().info("Initial context initialized from " + baseURL); 162 } 163 164 165 166 public String getChildDestination(String childName) { 167 168 String destination = null; 169 String filter = "cn=" + childName; 170 SearchControls ctls = new SearchControls(); 171 172 try { 173 174 NamingEnumeration result = ctx.search("", filter, ctls); 175 176 if (result.hasMore()) { 177 StringBuffer destinationBuffer = 178 new StringBuffer(128) 179 .append("cn=") 180 .append(childName) 181 .append(", ") 182 .append(baseNodeDN); 183 destination = destinationBuffer.toString(); 184 getLogger().info("Pre-exisisting LDAP node: " + destination); 185 } else { 186 Attributes attrs = new BasicAttributes(true); 187 Attribute objclass = new BasicAttribute("objectclass"); 188 objclass.add("top"); 189 objclass.add("rfc822MailGroup"); 190 attrs.put(objclass); 191 Attribute cname = new BasicAttribute("cn"); 192 cname.add(childName); 193 attrs.put(cname); 194 Attribute owner = new BasicAttribute("owner"); 195 owner.add("JAMES-unassigned"); 196 attrs.put(owner); 197 198 ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType); 199 ctx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal); 200 ctx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password); 201 202 ctx.createSubcontext("cn=" + childName, attrs); 203 ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none"); 204 205 StringBuffer destinationBuffer = 206 new StringBuffer(128) 207 .append("cn=") 208 .append(childName) 209 .append(", ") 210 .append(baseNodeDN); 211 destination = destinationBuffer.toString(); 212 getLogger().info("Created new LDAP node: " + destination); 213 } 214 } catch (NamingException e) { 215 getLogger().error("Problem with child nodes " + e.getMessage(), e); 216 } 217 218 return destination; 219 } 220 221 226 public Iterator list() { 227 228 List result = new ArrayList(); 229 String filter = mailAddressAttr + "=*"; 230 String[] attrIDs = {membersAttr}; 231 232 try { 233 Attribute members 234 = ctx.getAttributes("", attrIDs).get(membersAttr); 235 if (members != null) { 236 NamingEnumeration enum = members.getAll(); 237 while (enum.hasMore()) { 238 result.add((String)enum.next()); 239 } 240 } 241 } catch (NamingException e) { 242 getLogger().error("Problem listing mailboxes. " + e ); 243 244 } 245 return result.iterator(); 246 } 247 248 250 256 public boolean addUser(User user) { 257 return false; 258 } 259 260 public User getUserByName(String name) { 261 return new DefaultUser("dummy", "dummy"); 262 } 263 264 public User getUserByNameCaseInsensitive(String name) { 265 return getUserByName(name); 266 } 267 268 public boolean containsCaseInsensitive(String name) { 269 return contains(name); 270 } 271 272 public String getRealName(String name) { 276 return null; 277 } 278 279 public boolean updateUser(User user) { 280 return false; 281 } 282 283 public boolean test(String name, String password) { 284 return false; 285 } 286 287 292 public synchronized void addUser(String userName, Object attributes) { 293 294 String[] attrIDs = {membersAttr}; 295 296 298 try { 299 Attribute members = ctx.getAttributes("", attrIDs).get(membersAttr); 300 301 302 if (members != null && members.contains(userName)) { StringBuffer infoBuffer = 304 new StringBuffer(64) 305 .append("Found ") 306 .append(userName) 307 .append(" already in mailGroup. "); 308 getLogger().info(infoBuffer.toString()); 309 311 } else { 312 ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType); 313 ctx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal); 314 ctx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password); 315 316 ModificationItem[] mods = new ModificationItem[1]; 317 mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, new BasicAttribute(membersAttr, userName)); 318 319 ctx.modifyAttributes("", mods); 320 321 ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none"); 322 StringBuffer infoBuffer = 323 new StringBuffer(128) 324 .append(userName) 325 .append(" added to mailGroup ") 326 .append(baseNodeDN); 327 getLogger().info(infoBuffer.toString()); 328 } 330 } catch (NamingException e) { 331 StringBuffer exceptionBuffer = 332 new StringBuffer(256) 333 .append("Problem adding user ") 334 .append(userName) 335 .append(" to: ") 336 .append(baseNodeDN) 337 .append(e); 338 getLogger().error(exceptionBuffer.toString()); 339 } 340 341 343 if (manageGroupAttr) { 344 addGroupToUser(userName); 345 } 346 347 if (managePasswordAttr) { 348 String userPassword = (String) attributes; } 350 } 351 352 private void addGroupToUser(String userName) { 353 String[] attrIDs = {membersAttr}; 354 355 Hashtable env = new Hashtable(); 356 env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 357 env.put(javax.naming.Context.PROVIDER_URL, rootURL); 358 359 DirContext rootCtx = null; 360 try { 361 rootCtx = new InitialDirContext(env); 362 363 String[] returnAttrs = {groupAttr}; 364 SearchControls ctls = new SearchControls(); 365 ctls.setReturningAttributes(attrIDs); 366 ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); 367 StringBuffer filterBuffer = 368 new StringBuffer(128) 369 .append(mailAddressAttr) 370 .append("=") 371 .append(userName) 372 .append("@") 373 .append(usersDomain); 374 String filter = filterBuffer.toString(); 375 376 NamingEnumeration enum = rootCtx.search("", filter, ctls); 377 378 if (enum.hasMore()) { SearchResult newSr = (SearchResult)enum.next(); 380 String userDN = newSr.getName(); 381 Attribute servers = rootCtx.getAttributes(userDN, returnAttrs).get(groupAttr); 382 383 384 if (servers != null && servers.contains(baseNodeDN)) { getLogger().info(baseNodeDN + " already in user's Groups. " ); 386 388 } else { 389 390 rootCtx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType); 391 rootCtx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal); 392 rootCtx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password); 393 394 rootCtx.modifyAttributes(userDN, DirContext.ADD_ATTRIBUTE, new BasicAttributes(groupAttr, baseNodeDN, true)); 395 396 rootCtx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none"); 397 getLogger().info(baseNodeDN + " added to user's groups "); 398 400 } 401 402 } else { 403 StringBuffer infoBuffer = 404 new StringBuffer(64) 405 .append("User ") 406 .append(userName) 407 .append(" not in directory."); 408 getLogger().info(infoBuffer.toString()); 409 411 } 412 } catch (NamingException e) { 413 getLogger().error("Problem adding group to user " + userName); 414 } finally { 418 closeDirContext(rootCtx); 419 } 420 } 421 422 public synchronized Object getAttributes(String name) { 423 return null; 424 } 425 426 427 public synchronized void removeUser(String userName) { 428 String[] attrIDs = {membersAttr}; 429 430 try { 431 Attribute members = ctx.getAttributes("", attrIDs).get(membersAttr); 432 if (members == null) { 433 System.out.println("UsersLDAPRepository - Null list attribute."); 434 435 } else if (!members.contains(userName)) { getLogger().info(userName + " missing from mailGroup. "); 437 439 } else { 440 442 ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType); 443 ctx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal); 444 ctx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password); 445 446 ModificationItem[] mods = new ModificationItem[1]; 447 mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute(membersAttr, userName)); 448 449 ctx.modifyAttributes("", mods); 450 451 452 ctx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none"); 453 getLogger().info(userName + " removed from mailGroup. "); 454 } 456 } catch (NamingException e) { 457 StringBuffer exceptionBuffer = 458 new StringBuffer(256) 459 .append("Problem removing user ") 460 .append(userName) 461 .append(": ") 462 .append(e); 463 getLogger().error(exceptionBuffer.toString()); 464 } 468 if (manageGroupAttr) { 469 removeGroupFromUser(userName); 470 } 471 472 if (managePasswordAttr) { 473 } 475 476 } 477 478 public void removeGroupFromUser(String userName) { 479 480 Hashtable env = new Hashtable(); 481 env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 482 env.put(javax.naming.Context.PROVIDER_URL, rootURL); 483 484 485 DirContext rootCtx = null; 486 try { 487 rootCtx = new InitialDirContext(env); 488 489 String[] returnAttrs = {groupAttr}; 491 SearchControls ctls = new SearchControls(); 492 ctls.setReturningAttributes(returnAttrs); 493 ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); 494 StringBuffer filterBuffer = 495 new StringBuffer(128) 496 .append(mailAddressAttr) 497 .append("=") 498 .append(userName) 499 .append("@") 500 .append(usersDomain); 501 String filter = filterBuffer.toString(); 502 503 NamingEnumeration enum = rootCtx.search("", filter, ctls); 504 505 if (enum.hasMore()) { SearchResult newSr = (SearchResult)enum.next(); 507 String userDN = newSr.getName(); 508 509 System.out.println("Found user entry: " + userDN); 510 511 Attribute servers = rootCtx.getAttributes(userDN, returnAttrs).get(groupAttr); 512 if (servers == null) { getLogger().info("GroupAttribute missing from user: " + userName); 514 516 } else if (!servers.contains(baseNodeDN)) { getLogger().info(baseNodeDN + " missing from users' Groups. " ); 518 520 } else { 521 522 rootCtx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, authType); 523 rootCtx.addToEnvironment(javax.naming.Context.SECURITY_PRINCIPAL, principal); 524 rootCtx.addToEnvironment(javax.naming.Context.SECURITY_CREDENTIALS, password); 525 526 ModificationItem[] mods = new ModificationItem[1]; 527 mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, new BasicAttribute(groupAttr, baseNodeDN)); 528 529 rootCtx.modifyAttributes(userDN, mods); 530 531 533 rootCtx.addToEnvironment(javax.naming.Context.SECURITY_AUTHENTICATION, "none"); 534 getLogger().info(baseNodeDN + " removed from users' groups " ); 535 537 } 538 539 } else { 540 StringBuffer infoBuffer = 541 new StringBuffer(64) 542 .append("User ") 543 .append(userName) 544 .append(" not in directory."); 545 getLogger().info(infoBuffer.toString()); 546 548 } 549 } catch (NamingException e) { 550 StringBuffer exceptionBuffer = 551 new StringBuffer(256) 552 .append("Problem removing user ") 553 .append(userName) 554 .append(e); 555 getLogger().error(exceptionBuffer.toString()); 556 } finally { 560 closeDirContext(rootCtx); 561 rootCtx = null; 562 } 563 } 564 565 566 public boolean contains(String name) { 567 boolean found = false; 568 String[] attrIDs = {membersAttr}; 569 570 try { 571 Attribute members = ctx.getAttributes("", attrIDs).get(membersAttr); 572 if (members != null && members.contains(name)) { 573 found = true; 574 StringBuffer infoBuffer = 575 new StringBuffer(64) 576 .append("Found ") 577 .append(name) 578 .append(" in mailGroup. "); 579 getLogger().info(infoBuffer.toString()); 580 } 582 } catch (NamingException e) { 583 StringBuffer exceptionBuffer = 584 new StringBuffer(256) 585 .append("Problem finding user ") 586 .append(name) 587 .append(" : ") 588 .append(e); 589 getLogger().error(exceptionBuffer.toString()); 590 } 592 return found; 593 } 594 595 596 public boolean test(String name, Object attributes) { 597 boolean result = false; 598 boolean foundFlag = false; 599 String testPassword = (String) attributes; 600 String userDN = null; 601 602 try { 603 String[] returnAttrs = {identAttr, passwordAttr}; 604 SearchControls ctls = new SearchControls(); 605 ctls.setReturningAttributes(returnAttrs); 606 ctls.setSearchScope(SearchControls.SUBTREE_SCOPE); 607 StringBuffer filterBuffer = 608 new StringBuffer(128) 609 .append(mailAddressAttr) 610 .append("=") 611 .append(name) 612 .append("@") 613 .append(usersDomain); 614 String filter = filterBuffer.toString(); 615 616 Hashtable env = new Hashtable(); 617 env.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 618 env.put(javax.naming.Context.PROVIDER_URL, rootURL); 619 DirContext rootCtx = null; 620 621 try { 622 rootCtx = new InitialDirContext(env); 623 624 NamingEnumeration enum = rootCtx.search("", filter, ctls); 625 if (enum.hasMore()) { SearchResult sr = (SearchResult)enum.next(); 627 String userRDN = sr.getName(); 628 StringBuffer userDNBuffer = 629 new StringBuffer(128) 630 .append(userRDN) 631 .append(", ") 632 .append(rootNodeDN); 633 userDN = userDNBuffer.toString(); 634 foundFlag = true; 635 } 637 } finally { 638 closeDirContext(rootCtx); 639 } 640 } catch (Exception e) { 641 StringBuffer exceptionBuffer = 642 new StringBuffer(256) 643 .append("Problem finding user ") 644 .append(name) 645 .append(" for password test.") 646 .append(e); 647 getLogger().error(exceptionBuffer.toString()); 648 } 651 652 if (foundFlag) { Hashtable env2 = new Hashtable(); 654 env2.put(javax.naming.Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); 655 env2.put(javax.naming.Context.PROVIDER_URL, rootURL); 656 env2.put(javax.naming.Context.SECURITY_AUTHENTICATION, "simple"); 657 env2.put(javax.naming.Context.SECURITY_PRINCIPAL, userDN); 658 env2.put(javax.naming.Context.SECURITY_CREDENTIALS, testPassword); 659 661 DirContext testCtx = null; 662 try { 663 testCtx = new InitialDirContext(env2); 664 result = true; 665 666 } catch (AuthenticationException ae) { 667 result = false; 668 StringBuffer exceptionBuffer = 669 new StringBuffer(256) 670 .append("Attempt to authenticate with incorrect password for ") 671 .append(name) 672 .append(" : ") 673 .append(ae); 674 getLogger().error(exceptionBuffer.toString()); 675 } catch (Exception e) { 679 StringBuffer exceptionBuffer = 680 new StringBuffer(256) 681 .append("Problem checking password for ") 682 .append(name) 683 .append(" : ") 684 .append(e); 685 getLogger().error(exceptionBuffer.toString()); 686 } finally { 690 closeDirContext(testCtx); 691 } 692 } 693 return result; 694 695 } 696 697 public int countUsers() { 698 699 String[] attrIDs = {membersAttr}; 700 int result = -1; 701 702 try { 703 Attribute members = ctx.getAttributes("", attrIDs).get(membersAttr); 704 if (members != null) { 705 result = members.size(); 706 } else { 707 result = 0; 708 } 709 } catch (NamingException e) { 710 getLogger().error("Problem counting users: " + e); 711 } 713 return result; 714 } 715 716 public String getDomains() { 717 return usersDomain; 718 } 719 720 725 public void dispose() throws Exception { 726 closeDirContext(ctx); 727 ctx = null; 728 } 729 730 private void closeDirContext(DirContext ctx) { 731 try { 732 if (ctx != null) { 733 ctx.close(); 734 } 735 } catch (NamingException ne) { 736 getLogger().warn("UsersLDAPRepository: Unexpected exception encountered while closing directory context: " + ne); 737 } 738 } 739 } 740 741 742 | Popular Tags |