1 19 20 package com.sslexplorer.activedirectory; 21 22 import java.security.PrivilegedAction ; 23 import java.util.ArrayList ; 24 import java.util.Collection ; 25 import java.util.Collections ; 26 import java.util.Date ; 27 import java.util.HashMap ; 28 import java.util.LinkedList ; 29 import java.util.List ; 30 import java.util.Map ; 31 import java.util.Properties ; 32 import java.util.StringTokenizer ; 33 34 import javax.management.relation.RoleNotFoundException ; 35 import javax.naming.Context ; 36 import javax.naming.NamingException ; 37 import javax.naming.directory.Attribute ; 38 import javax.naming.directory.Attributes ; 39 import javax.naming.directory.SearchResult ; 40 import javax.naming.ldap.InitialLdapContext ; 41 import javax.security.auth.login.AppConfigurationEntry ; 42 import javax.security.auth.login.Configuration ; 43 import javax.security.auth.login.LoginContext ; 44 45 import org.apache.commons.logging.Log; 46 import org.apache.commons.logging.LogFactory; 47 48 import com.sslexplorer.boot.ContextHolder; 49 import com.sslexplorer.core.CoreEvent; 50 import com.sslexplorer.core.CoreJAASConfiguration; 51 import com.sslexplorer.core.CoreListener; 52 import com.sslexplorer.core.CoreServlet; 53 import com.sslexplorer.policyframework.Principal; 54 import com.sslexplorer.properties.Property; 55 import com.sslexplorer.properties.PropertyChangeEvent; 56 import com.sslexplorer.properties.impl.userattributes.UserAttributeKey; 57 import com.sslexplorer.realms.Realm; 58 import com.sslexplorer.security.DefaultUserDatabase; 59 import com.sslexplorer.security.InvalidLoginCredentialsException; 60 import com.sslexplorer.security.Role; 61 import com.sslexplorer.security.User; 62 import com.sslexplorer.security.UserDatabaseException; 63 import com.sslexplorer.security.UserNotFoundException; 64 65 71 public class ActiveDirectoryUserDatabase extends DefaultUserDatabase implements CoreListener { 72 private static final String OBJECT_SID_ATTRIBUTE = "objectSID"; 73 private static final String HOME_DIRECTORY_ATTRIBUTE = "homeDirectory"; 74 private static final String HOME_DRIVE_ATTRIBUTE = "homeDrive"; 75 private static final String MEMBER_OF_ATTIBUTE = "memberOf"; 76 private static final String PWD_LAST_SET_ATTRIBUTE = "pwdLastSet"; 77 private static final String GROUPNAME_FILTER_ATTRIBUTE = "%GROUPNAME%"; 78 private static final String USERNAME_FILTER_PARAMETER = "%USERNAME%"; 79 80 public static final String SAM_ACCOUNT_NAME_ATTRIBUTE = "sAMAccountName"; 81 public static final String COMMON_NAME_ATTRIBUTE = "cn"; 82 public static final String DISPLAY_NAME_ATTRIBUTE = "displayName"; 83 public static final String USER_PRINCIPAL_NAME_ATTRIBUTE = "userPrincipalName"; 84 public static final String MAIL_ATTRIBUTE = "mail"; 85 public static final String USER_ACCOUNT_CONTROL_ATTRIBUTE = "userAccountControl"; 86 public static final String PRIMARY_GROUP_ID_ATTRIBUTE = "primaryGroupId"; 87 public static final String OBJECT_CLASS_ATTRIBUTE = "objectClass"; 88 89 private static final String USER_FILTER = "(&(!(" + OBJECT_CLASS_ATTRIBUTE + "=computer))(" + OBJECT_CLASS_ATTRIBUTE + "=user)(|(" + SAM_ACCOUNT_NAME_ATTRIBUTE + "=" + USERNAME_FILTER_PARAMETER + ")(" + USER_PRINCIPAL_NAME_ATTRIBUTE + "=" + USERNAME_FILTER_PARAMETER + ")))"; 90 private static final String GROUP_FILTER = "(&(" + OBJECT_CLASS_ATTRIBUTE + "=group)(" + COMMON_NAME_ATTRIBUTE + "=" + GROUPNAME_FILTER_ATTRIBUTE + "))"; 91 private static final String USER_ATTRS[] = {SAM_ACCOUNT_NAME_ATTRIBUTE, USER_PRINCIPAL_NAME_ATTRIBUTE, DISPLAY_NAME_ATTRIBUTE, MAIL_ATTRIBUTE, HOME_DIRECTORY_ATTRIBUTE, HOME_DRIVE_ATTRIBUTE, MEMBER_OF_ATTIBUTE, PRIMARY_GROUP_ID_ATTRIBUTE, PWD_LAST_SET_ATTRIBUTE, USER_ACCOUNT_CONTROL_ATTRIBUTE}; 92 private static final String GROUP_ATTRS[] = {COMMON_NAME_ATTRIBUTE, OBJECT_SID_ATTRIBUTE, MEMBER_OF_ATTIBUTE}; 93 private static final String WILDCARD_SEARCH = "*"; 94 private static final Log logger = LogFactory.getLog(ActiveDirectoryUserDatabase.class); 95 96 private ActiveDirectoryUserDatabaseConfiguration configuration; 97 private UserContainer userContainer = UserContainer.EMPTY_CACHE; 98 private GroupContainer groupContainer = GroupContainer.EMPTY_CACHE; 99 private ThreadRunner threadRunner; 100 101 102 public ActiveDirectoryUserDatabase() { 103 super("Active Directory", false, false); 104 addJAASConfiguration(); 105 } 106 107 private void addJAASConfiguration() { 108 Map <String , String > parameters = new HashMap <String , String >(); 109 parameters.put("client", "TRUE"); 110 parameters.put("debug", String.valueOf(logger.isDebugEnabled()).toUpperCase()); 111 parameters.put("useSubjectCredsOnly", "FALSE"); 112 parameters.put("useTicketCache", "FALSE"); 113 parameters.put("refreshKrb5Config", "TRUE"); 114 115 AppConfigurationEntry entry = new AppConfigurationEntry ("com.sun.security.auth.module.Krb5LoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, parameters); 116 CoreJAASConfiguration config = (CoreJAASConfiguration) Configuration.getConfiguration(); 117 config.addAppConfigurationEntry(ActiveDirectoryUserDatabase.class.getName(), entry); 118 } 119 120 protected ActiveDirectoryUserDatabaseConfiguration getConfiguration() { 121 return configuration; 122 } 123 124 protected UserContainer getUserContainer() { 125 return userContainer; 126 } 127 128 protected GroupContainer getGroupContainer() { 129 return groupContainer; 130 } 131 132 136 public User logon(String username, String password) throws UserDatabaseException, InvalidLoginCredentialsException { 137 ActiveDirectoryUser user = null; 138 try { 139 user = (ActiveDirectoryUser) getAccount(username); 140 } catch (Exception e) { 141 logger.error("Failed to logon", e); 142 throw new UserDatabaseException("Failed to logon", e); 143 } 144 assertValidCredentials(user, password); 146 return user; 147 } 148 149 private void assertValidCredentials(ActiveDirectoryUser user, String password) throws InvalidLoginCredentialsException { 150 if (!areCredentialsValid(user, password)) { 151 throw new InvalidLoginCredentialsException("Invalid username or password."); 152 } 153 } 154 155 159 public User[] listAllUsers(String filter) throws Exception { 160 if (logger.isDebugEnabled()) { 161 logger.debug("List all users with filter '" + filter + "'"); 162 } 163 Collection <ActiveDirectoryUser> users = userContainer.retrievePrincipals(filter); 164 return users.toArray(new User[users.size()]); 165 } 166 167 171 public User getAccount(String username) throws UserNotFoundException, Exception { 172 if (logger.isDebugEnabled()) { 173 logger.debug("Getting account " + username); 174 } 175 176 username = configuration.isUsernamesAreCaseSensitive() ? username : username.toLowerCase(); 177 if (!userContainer.containsPrincipal(username)) { 178 loadUsers(username, false); 179 } 180 if (!userContainer.containsPrincipal(username)) { 181 throw new UserNotFoundException(username + " is not a valid user!"); 182 } 183 return userContainer.retrievePrincipal(username); 184 } 185 186 190 public Role getRole(String groupName) throws Exception { 191 if (logger.isDebugEnabled()) { 192 logger.debug("Getting group " + groupName); 193 } 194 195 if (!groupContainer.containsPrincipal(groupName)) { 196 loadRoles(groupName, false); 197 } 198 if (!groupContainer.containsPrincipal(groupName)) { 199 throw new RoleNotFoundException (groupName + " is not a valid group!"); 200 } 201 202 ActiveDirectoryGroup group = groupContainer.retrievePrincipal(groupName); 203 groupContainer.buildHierarchy(group.getOriginalDn()); 204 return group; 205 } 206 207 211 public Role[] listAllRoles(String filter) throws UserDatabaseException { 212 if (logger.isDebugEnabled()) { 213 logger.debug("List all groups with filter '" + filter + "'"); 214 } 215 Collection <ActiveDirectoryGroup> groups = groupContainer.retrievePrincipals(filter); 216 return groups.toArray(new Role[groups.size()]); 217 } 218 219 223 public boolean checkPassword(String username, String password) throws UserDatabaseException, InvalidLoginCredentialsException { 224 try { 225 ActiveDirectoryUser user = (ActiveDirectoryUser) getAccount(username); 226 return areCredentialsValid(user, password); 227 } catch (UserNotFoundException e) { 228 throw new UserDatabaseException("Failed to check password", e); 229 } catch (Exception e) { 230 throw new UserDatabaseException("Failed to check password", e); 231 } 232 } 233 234 238 public Principal[] listAvailablePrincipals() throws Exception { 239 if (logger.isDebugEnabled()) { 240 logger.debug("Listing available principals"); 241 } 242 return listAllUsers(WILDCARD_SEARCH); 243 } 244 245 private void loadUsers(final String filter, final boolean removeMissingEntries) throws UserDatabaseException { 246 configuration.doAs(new RetryPrivilegedAction() { 247 protected Object doIt(InitialLdapContext context) throws Exception { 248 loadUsers(filter, context, removeMissingEntries); 249 return null; 250 } 251 }); 252 } 253 254 private void loadUsers(String filter, InitialLdapContext context, boolean removeMissingEntries) throws Exception { 255 final Collection <String > usernames = userContainer.retrievePrincipalNames(); 256 final LinkedList <Exception > exceptions = new LinkedList <Exception >(); 257 PagedResultMapper mapper = new PagedResultMapper () 258 { 259 public void mapSearchResult(SearchResult searchResult) throws Exception { 260 String dn = searchResult.getNameInNamespace(); 261 ActiveDirectoryUser user = populateActiveDirectoryUser(dn, searchResult.getAttributes()); 262 String key = userContainer.storePrincipal(user); 263 usernames.remove(key); 264 if (logger.isDebugEnabled()) { 265 logger.debug("Found user " + user); 266 } 267 } 268 269 public void processSearchResultException(SearchResult searchResult, Exception e) { 270 String dn = searchResult.getNameInNamespace(); 271 logger.error("Problem retrieving user " + dn, e); 272 } 273 274 public void processException(Exception e) { 275 logger.error("Problem retrieving users", e); 276 exceptions.add(e); 277 } 278 }; 279 String escapedFilter = ActiveDirectoryUserDatabaseConfiguration.getEscapedDn(filter, true); 280 String replacedFilter = USER_FILTER.replaceAll(USERNAME_FILTER_PARAMETER, escapedFilter); 281 configuration.search(context, replacedFilter, USER_ATTRS, mapper); 282 283 if (removeMissingEntries) { 284 userContainer.updateRemovedPrincipals(usernames); 285 } 286 287 if (!exceptions.isEmpty()) { 288 Exception e = exceptions.getLast(); 289 logger.error(exceptions.size() + " exceptions occurred, throwing the last one", e); 290 throw e; 291 } 292 } 293 294 private void loadRoles(final String filter, final boolean removeMissingEntries) throws UserDatabaseException { 295 configuration.doAs(new RetryPrivilegedAction() { 296 @Override 297 protected Object doIt(InitialLdapContext context) throws Exception { 298 loadRoles(filter, context, removeMissingEntries); 299 return null; 300 } 301 302 @Override 303 protected InitialLdapContext getContext(String url) throws Exception { 304 Map <String , String > extraProperties = Collections.<String , String > singletonMap("java.naming.ldap.attributes.binary", OBJECT_SID_ATTRIBUTE); 305 return configuration.getAuthenticatedContext(url, extraProperties); 306 } 307 }); 308 groupContainer.buildHierarchy(); 309 } 310 311 private void loadRoles(String filter, InitialLdapContext context, boolean removeMissingEntries) throws Exception { 312 final Collection <String > groupNames = groupContainer.retrievePrincipalNames(); 313 final LinkedList <Exception > exceptions = new LinkedList <Exception >(); 314 PagedResultMapper mapper = new PagedResultMapper () 315 { 316 public void mapSearchResult(SearchResult searchResult) throws Exception { 317 String dn = searchResult.getNameInNamespace(); 318 Attributes attributes = searchResult.getAttributes(); 319 String commonName = getAttributeValue(attributes, COMMON_NAME_ATTRIBUTE); 320 if (commonName.length() != 0) { 321 Long rid = ActiveDirectoryGroup.getRIDFromSID((byte[]) attributes.get(OBJECT_SID_ATTRIBUTE).get()); 322 ActiveDirectoryGroup group = new ActiveDirectoryGroup(commonName, dn, getEscapedDn(dn), rid, getRealm()); 323 String [] parents = getParents(attributes); 324 String key = groupContainer.storeGroup(group, parents); 325 groupNames.remove(key); 326 } 327 } 328 329 private String [] getParents(Attributes attributes) throws NamingException { 330 List <String > parents = new ArrayList <String >(); 331 Attribute memberOfAttribute = attributes.get(MEMBER_OF_ATTIBUTE); 332 if (memberOfAttribute != null) { 333 for (int index = 0; index < memberOfAttribute.size(); index++) { 334 String parentDn = (String ) memberOfAttribute.get(index); 335 if (configuration.isDnValid(parentDn)) { 336 parents.add(parentDn); } 338 } 339 } 340 return parents.toArray(new String [parents.size()]); 341 } 342 343 public void processSearchResultException(SearchResult searchResult, Exception e) { 344 String dn = searchResult.getNameInNamespace(); 345 logger.error("Problem retrieving group " + dn, e); 346 } 347 348 public void processException(Exception e) { 349 logger.error("Problem retrieving groups", e); 350 exceptions.add(e); 351 } 352 }; 353 String escapedFilter = ActiveDirectoryUserDatabaseConfiguration.getEscapedDn(filter, true); 354 String replacedFilter = GROUP_FILTER.replaceAll(GROUPNAME_FILTER_ATTRIBUTE, escapedFilter); 355 configuration.search(context, replacedFilter, GROUP_ATTRS, mapper); 356 357 if (removeMissingEntries) { 358 groupContainer.updateRemovedGroups(groupNames); 359 } 360 361 if (!exceptions.isEmpty()) { 362 Exception e = exceptions.getLast(); 363 logger.error(exceptions.size() + " exceptions occurred, throwing the last one", e); 364 throw e; 365 } 366 } 367 368 private boolean areCredentialsValid(ActiveDirectoryUser user, String password) { 369 if (logger.isDebugEnabled()) { 370 logger.debug("Authenticating with user " + user + " and password = '********'"); 371 } 372 373 try { 374 if (configuration.isUserAuthenticationGssApi()) { 375 LoginContext context = configuration.createLoginContext(user.getUserPrincipalName(), password); 376 ActiveDirectoryUserDatabaseConfiguration.logoutContext(context); 377 } else { 378 return areSimpleCredentialsValid(user.getPrincipalName(), password); 379 } 380 return true; 381 } catch (Exception e) { 382 logger.error("Failure to authenticate user", e); 383 return false; 384 } 385 } 386 387 private boolean areSimpleCredentialsValid(final String username, final String password) { 388 RetryPrivilegedAction action = new RetryPrivilegedAction() { 389 protected Object doIt(InitialLdapContext context) throws Exception { 390 return null; 391 } 392 393 protected InitialLdapContext getContext(String url) throws Exception { 394 String userDn = ((ActiveDirectoryUser) getAccount(username)).getOriginalDn(); 395 Map <String , String > variables = new HashMap <String , String >(3); 396 variables.put(Context.SECURITY_AUTHENTICATION, configuration.getUserAuthenticationType()); 397 variables.put(Context.SECURITY_PRINCIPAL, userDn); 398 variables.put(Context.SECURITY_CREDENTIALS, password); 399 return configuration.getInitialContext(url, variables); 400 } 401 }; 402 Object result = action.run(); 403 boolean isThrowable = (result instanceof Throwable ); 404 if (isThrowable && logger.isErrorEnabled()) { 405 logger.error("Failure to authenticate user", (Throwable ) result); 406 } 407 return !isThrowable; 408 } 409 410 416 public User getAccountFromDN(final String dn) throws Exception { 417 if (dn.indexOf("CN") > -1 && dn.indexOf("DC") > -1) { 418 if (logger.isDebugEnabled()) { 420 logger.debug("Looking up account using DN: " + dn); 421 } 422 423 return (User) configuration.doAs(new RetryPrivilegedAction(false) { 424 protected Object doIt(InitialLdapContext context) throws Exception { 425 return getAccountFromDN(dn, context); 426 } 427 }); 428 } 429 430 throw new Exception ("Certificate requires subject to be DN of Active Directory user"); 431 } 432 433 private User getAccountFromDN(String dn, InitialLdapContext context) throws NamingException { 434 String actualDN = null; 435 for (StringTokenizer tokens = new StringTokenizer (dn, ","); tokens.hasMoreTokens();) { 436 String elm = tokens.nextToken().trim(); 437 if (elm.toUpperCase().startsWith("CN") || elm.toUpperCase().startsWith("OU") || elm.toUpperCase().startsWith("DC")) { 438 actualDN = (actualDN == null ? "" : actualDN + ",") + elm; 439 } 440 } 441 442 try { 443 Attributes attributes = context.getAttributes(actualDN, USER_ATTRS); 444 return populateActiveDirectoryUser(dn, attributes); 445 } catch (Exception e) { 446 logger.error("Cannot locate user for DN " + dn, e); 447 throw new NamingException ("User not found for DN " + dn); 448 } 449 } 450 451 private ActiveDirectoryUser populateActiveDirectoryUser(String dn, Attributes attributes) throws NamingException , UserDatabaseException { 452 if (attributes == null) { 453 throw new NamingException ("No attributes for " + dn); 454 } 455 456 String username = getAttributeValue(attributes, SAM_ACCOUNT_NAME_ATTRIBUTE); 457 String userPrincipalName = getAttributeValue(attributes, USER_PRINCIPAL_NAME_ATTRIBUTE); 458 String email = getAttributeValue(attributes, MAIL_ATTRIBUTE); 459 String fullName = getAttributeValue(attributes, DISPLAY_NAME_ATTRIBUTE); 460 Date lastPasswordChange = isPasswordChangeAllowed(attributes) ? getPasswordLastSetDate(attributes) : new Date (); 461 ActiveDirectoryUser user = new ActiveDirectoryUser(username, userPrincipalName, email, fullName, dn, getEscapedDn(dn), lastPasswordChange, getRealm()); 462 463 String homeDirectory = getAttributeValue(attributes, User.USER_ATTR_HOME_DIRECTORY); 464 if (homeDirectory.length() != 0) { 465 Property.setProperty(new UserAttributeKey(user, User.USER_ATTR_HOME_DIRECTORY), homeDirectory, null); 466 } 467 468 String homeDrive = getAttributeValue(attributes, User.USER_ATTR_HOME_DRIVE); 469 if (homeDrive.length() != 0) { 470 Property.setProperty(new UserAttributeKey(user, User.USER_ATTR_HOME_DRIVE), homeDrive, null); 471 } 472 473 ActiveDirectoryGroup[] groups = getGroups(attributes); 474 if (logger.isDebugEnabled()) { 475 logger.debug("User belongs to " + groups.length + " groups"); 476 } 477 user.setRoles(groups); 478 return user; 479 } 480 481 private static Date getPasswordLastSetDate(Attributes attributes) throws NamingException { 482 try { 483 String attributeValue = getAttributeValue(attributes, PWD_LAST_SET_ATTRIBUTE); 484 long parseLong = Long.parseLong(attributeValue); 485 return ActiveDirectoryUser.adTimeToJavaDate(parseLong); 486 } catch (NumberFormatException e) { 487 return new Date (); 488 } 489 } 490 491 496 protected boolean isPasswordChangeAllowed(Attributes attributes) throws NamingException { 497 return false; 498 } 499 500 private ActiveDirectoryGroup[] getGroups(Attributes attributes) throws NamingException { 501 Collection <ActiveDirectoryGroup> groups = new ArrayList <ActiveDirectoryGroup>(); 502 String primaryGroupId = getAttributeValue(attributes, PRIMARY_GROUP_ID_ATTRIBUTE); 503 if (primaryGroupId.length() != 0) { 504 Long rid = new Long (Long.parseLong(primaryGroupId)); 505 506 if (logger.isDebugEnabled()) { 507 logger.debug("Users primaryGroupId is " + rid.toString()); 508 } 509 510 ActiveDirectoryGroup group = groupContainer.getByRid(rid); 511 if (group != null) { 512 if (logger.isDebugEnabled()) { 513 logger.debug("Users primary group is " + group.getOriginalDn()); 514 } 515 groups.add(group); 516 } else { 517 if (logger.isDebugEnabled()) { 518 logger.debug("Could not find primary group " + rid.toString()); 519 } 520 } 521 } 522 523 Attribute memberOfAttribute = attributes.get(MEMBER_OF_ATTIBUTE); 524 if (memberOfAttribute != null) { 525 for (int index = 0; index < memberOfAttribute.size(); index++) { 526 String groupDn = (String ) memberOfAttribute.get(index); 527 if (logger.isDebugEnabled()) { 528 logger.debug("Checking if user is a member of " + groupDn + " a valid group"); 529 } 530 531 if (groupContainer.containsDn(groupDn)) { 532 ActiveDirectoryGroup group = (ActiveDirectoryGroup) groupContainer.getGroupByDn(groupDn); 533 if (group != null && !groups.contains(group)) { 534 groups.add(group); 535 536 if (logger.isDebugEnabled()) { 537 logger.debug("Member of " + groupDn + " [" + group.getPrincipalName() + "]"); 538 } 539 540 544 if (group.getParents() != null) { 545 for (int parentIndex = 0; parentIndex < group.getParents().length; parentIndex++) { 546 ActiveDirectoryGroup parentGroup = group.getParents()[parentIndex]; 547 if (parentGroup == null) { 548 if (logger.isDebugEnabled()) { 549 logger.debug("Found NULL parent group"); 550 } 551 } else if (!groups.contains(parentGroup)) { 552 groups.add(parentGroup); 553 } 554 } 555 } 556 } else { 557 if (logger.isInfoEnabled()) { 558 logger.info("Could not find group " + groupDn); 559 } 560 } 561 } 562 } 563 } 564 return groups.toArray(new ActiveDirectoryGroup[groups.size()]); 565 } 566 567 571 public void coreEvent(CoreEvent event) { 572 if (!ContextHolder.getContext().isSetupMode() && event instanceof PropertyChangeEvent) { 574 PropertyChangeEvent changeEvent = (PropertyChangeEvent) event; 575 if (changeEvent.getDefinition().getName().startsWith("activeDirectory.")) { 576 if (logger.isInfoEnabled()) { 577 logger.info("Active Directory configuration changed. Re-initialising"); 578 } 579 try { 580 configuration.refresh(); 581 initialise(); 582 } catch (Exception e) { 583 logger.error("Failed to re-initialise Active Directory.", e); 584 } 585 } 586 } 587 } 588 589 public void open(CoreServlet controllingServlet, Realm realm) throws Exception { 590 try { 591 super.open(controllingServlet, realm); 592 CoreServlet.getServlet().addCoreListener(this); 593 initConfiguration(); 594 threadRunner = new ThreadRunner("CacheUpdater", getCacheUpdaterJob(), configuration.getTimeToLive()); 595 threadRunner.start(); 596 initialise(); 597 } catch (Exception e) { 598 close(); 599 throw e; 600 } 601 } 602 603 private void initConfiguration() throws Exception { 604 configuration = buildConfiguration(); 605 configuration.postInitialize(); 606 userContainer = configuration.createUserContainer(); 607 groupContainer = configuration.createRoleContainer(); 608 } 609 610 protected ActiveDirectoryUserDatabaseConfiguration buildConfiguration() throws IllegalArgumentException , Exception { 611 ActiveDirectoryUserDatabaseConfiguration configuration = new ActiveDirectoryUserDatabaseConfiguration(getRealm(), new Properties ()); 612 configuration.setProtocolType(ActiveDirectoryUserDatabaseConfiguration.PLAIN_PROTOCOL); 613 configuration.setServiceAuthenticationType(ActiveDirectoryUserDatabaseConfiguration.GSSAPI_AUTHENTICATION_METHOD); 614 return configuration; 615 } 616 617 private Runnable getCacheUpdaterJob() { 618 return new Runnable (){ 619 public void run() { 620 if (logger.isInfoEnabled()) { 621 logger.info("Caching items"); 622 logger.info("Caching roles"); 623 } 624 625 try { 626 loadRoles(WILDCARD_SEARCH, true); 627 } catch (UserDatabaseException e) { 628 logger.error("Error updating cached roles", e); 629 } 630 631 if (logger.isInfoEnabled()) { 632 logger.info("Finished caching roles"); 633 logger.info("Caching users"); 634 } 635 636 638 try { 639 loadUsers(WILDCARD_SEARCH, true); 640 } catch (UserDatabaseException e) { 641 logger.error("Error updating cached users", e); 642 } 643 644 if (logger.isInfoEnabled()) { 645 logger.info("Finished caching users"); 646 logger.info("Finished caching items"); 647 } 648 } 649 }; 650 } 651 652 657 private void initialise() throws Exception { 658 try { 659 String serviceAccountName = configuration.getServiceAccountName(); 660 if (configuration.isServiceAuthenticationGssApi()) { 661 getAccount(serviceAccountName); 662 } else { 663 getAttributeValue(serviceAccountName, SAM_ACCOUNT_NAME_ATTRIBUTE); 664 } 665 } catch (Exception e) { 666 logger.error("Could not get the service account login context. All Active Directory features will be unavailable. You should check your Service Account Username and Password settings.", e); 667 close(); throw e; 669 } 670 } 671 672 676 public void close() throws Exception { 677 super.close(); 678 CoreServlet.getServlet().removeCoreListener(this); 679 if (threadRunner != null) { 680 threadRunner.stop(); 681 } 682 userContainer.close(); 683 groupContainer.close(); 684 } 685 686 690 public void logout(User user) { 691 } 692 693 697 protected abstract class RetryPrivilegedAction implements PrivilegedAction { 698 private final boolean returnExceptionNotNull; 699 private final String hosts; 700 701 protected RetryPrivilegedAction() { 702 this(true); 703 } 704 705 protected RetryPrivilegedAction(boolean returnExceptionNotNull) { 706 this.returnExceptionNotNull = returnExceptionNotNull; 707 hosts = configuration.getContactableActiveDirectories(); 708 } 709 710 public final Object run() { 711 long startTime = System.currentTimeMillis(); 712 if (logger.isDebugEnabled()) { 713 logger.debug("Starting Timed Operation"); 714 } 715 716 InitialLdapContext context = null; 717 try { 718 context = getContext(hosts); 719 Object doIt = doIt(context); 720 return doIt; 721 } catch (Exception e) { 722 logger.error("Failed to run action.", e); 723 return returnExceptionNotNull ? e : null; 724 } finally { 725 close(context); 726 727 long finishTime = System.currentTimeMillis(); 728 if(logger.isDebugEnabled()) { 729 logger.debug("Finished Timed Operation in " + ((finishTime - startTime) / 1000) + " seconds"); 730 } 731 } 732 } 733 734 protected InitialLdapContext getContext(String url) throws Exception { 735 return configuration.getAuthenticatedContext(url); 736 } 737 738 protected abstract Object doIt(InitialLdapContext context) throws Exception ; 739 } 740 741 protected String getAttributeValue(String dn, String attributeName) throws NamingException , UserDatabaseException { 742 Attributes attributes = getAttributes(dn, new String []{attributeName}); 743 return getAttributeValue(attributes, attributeName); 744 } 745 746 private Attributes getAttributes(final String dn, final String [] attributes) throws UserDatabaseException { 747 return (Attributes ) configuration.doAs(new RetryPrivilegedAction(){ 748 protected Object doIt(InitialLdapContext context) throws Exception { 749 return context.getAttributes(dn, attributes); 750 } 751 }); 752 } 753 754 protected static String getAttributeValue(Attributes attributes, String attributeName) throws NamingException { 755 if (attributes == null) { 756 return null; 757 } 758 Attribute attribute = attributes.get(attributeName); 759 return attribute == null ? "" : (String ) attribute.get(); 760 } 761 762 768 private static String getEscapedDn(String dn) { 769 String escapeDn = dn.replaceAll("\\\\", "\\\\\\\\"); 770 String escapeForwardSlash = escapeDn.replaceAll("/", "\\\\/"); 771 return escapeForwardSlash; 772 } 773 774 protected static void close(InitialLdapContext context) { 775 if (context != null) { 776 try { 777 context.close(); 778 } catch (NamingException e) { 779 } 781 } 782 } 783 } | Popular Tags |