/*
* Adito
*
* Copyright (C) 2003-2006 3SP LTD. All Rights Reserved
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package com.adito.activedirectory;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.naming.Context;
import javax.naming.NamingException;
import javax.naming.ldap.InitialLdapContext;
import javax.security.auth.Subject;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.adito.boot.PropertyList;
import com.adito.properties.Property;
import com.adito.properties.impl.realms.RealmKey;
import com.adito.realms.Realm;
import com.adito.security.UserDatabaseException;
public final class ActiveDirectoryUserDatabaseConfiguration {
private static final Log logger = LogFactory.getLog(ActiveDirectoryUserDatabaseConfiguration.class);
private static final String COMMON_NAME = "CN=";
private static final String CN_USERS = COMMON_NAME + "Users";
private static final String CN_BUILTIN = COMMON_NAME + "Builtin";
private static final String LDAP_PROTOCOL = "ldap://";
private static final String PORT_SEPARATOR = ":";
private static final String ESCAPE_BACKSLASH = "\\\\";
private static final String ESCAPE_QUOTE = "\"";
private static final String[] ESCAPED_CHARACTERS = {ESCAPE_BACKSLASH, "/", "#", ",,", "\\+", ESCAPE_QUOTE, "<", ">", ";"};
private static final int SSL_SECURED_PORT = 636;
private static final int CLEAR_TEXT_PORT = 389;
/** The Kerberos GSSAPI authentication type. */
public static final String GSSAPI_AUTHENTICATION_METHOD = "GSSAPI";
/** The JNDI simple bind authentication type. */
public static final String SIMPLE_AUTHENTICATION_METHOD = "simple";
/** The plain text protocol. */
public static final String PLAIN_PROTOCOL = "plain";
/** The SSL protocol. */
public static final String SSL_PROTOCOL = "ssl";
private final Realm realm;
private final ActiveDirectoryPropertyManager propertyManager;
private String domain;
private String controllerHost;
private Collection<String> backupControllerHosts;
private String serviceAuthenticationType;
private String userAuthenticationType;
private String serviceAccountName;
private String serviceAccountPassword;
private String baseDn;
private String protocolType;
private boolean followReferrals;
private int userCacheSize;
private int groupCacheSize;
private boolean inMemoryCache;
private int timeToLive;
private final List<String> includedOuBasesList = new ArrayList<String>();
private final List<String> excludedOuBasesList = new ArrayList<String>();
private boolean hasFilteredOus;
private boolean includeDistributionGroups;
private boolean memberOfSupported;
private boolean usernamesAreCaseSensitive;
private final Collection<URI> activeDirectoryUrls = new ArrayList<URI>();
private URI lastContactedActiveDirectoryUrl;
private int pageSize;
private int timeOut;
private PagedResultTemplate template;
public ActiveDirectoryUserDatabaseConfiguration(Realm realm, Properties propertyNames) throws IllegalArgumentException, Exception {
this.realm = realm;
propertyManager = new ActiveDirectoryPropertyManager(realm, propertyNames);
initialize(propertyNames);
}
private void initialize(Properties propertyNames) throws Exception {
// Get the domain and active directory root
setControllerHost(getProperty("activeDirectory.controllerHost", propertyNames));
setBackupControllerHosts(getPropertyList("activeDirectory.backupControllerHosts", propertyNames));
setDomain(getProperty("activeDirectory.domain", propertyNames));
setServiceAuthenticationType(getProperty("activeDirectory.serviceAuthenticationType", propertyNames));
setUserAuthenticationType(getProperty("activeDirectory.userAuthenticationType", propertyNames));
setServiceAccountName(getProperty("activeDirectory.serviceAccountUsername", propertyNames));
setServiceAccountPassword(getProperty("activeDirectory.serviceAccountPassword", propertyNames));
setFollowReferrals(getPropertyBoolean("activeDirectory.followReferrals", propertyNames));
setUserCacheSize(getPropertyInt("activeDirectory.cacheUserMaxObjects", propertyNames));
setGroupCacheSize(getPropertyInt("activeDirectory.cacheGroupMaxObjects", propertyNames));
setInMemoryCache(getPropertyBoolean("activeDirectory.cacheInMemory", propertyNames));
setTimeToLive(getPropertyInt("activeDirectory.userCacheTTL", propertyNames));
Collection<String> includedOuFilterList = getPropertyList("activeDirectory.organizationalUnitFilter", propertyNames);
Collection<String> excludedOuFilterList = getPropertyList("activeDirectory.excludedOrganizationalUnitFilter", propertyNames);
setValidOus(baseDn, includedOuFilterList, excludedOuFilterList);
setIncludeStandardUsers(getPropertyBoolean("activeDirectory.includeStandardUsers", propertyNames));
setIncludeBuiltInGroups(getPropertyBoolean("activeDirectory.includeBuiltInGroups", propertyNames));
setIncludeDistributionGroups(getPropertyBoolean("activeDirectory.includeDistributionGroups", propertyNames));
setMemberOfSupported(getPropertyBoolean("activeDirectory.memberOfSupported", propertyNames));
setUsernamesAreCaseSensitive(getPropertyBoolean("activeDirectory.usernamesAreCaseSensitive", propertyNames));
setPageSize(getPropertyInt("activeDirectory.pageSize", propertyNames));
setTimeOut(getPropertyInt("activeDirectory.connection.timeout", propertyNames));
}
private String getProperty(String key, Properties propertyNames) {
return Property.getProperty(getRealmKey(key, propertyNames));
}
private boolean getPropertyBoolean(String key, Properties propertyNames) {
return Property.getPropertyBoolean(getRealmKey(key, propertyNames));
}
private int getPropertyInt(String key, Properties propertyNames) {
return Property.getPropertyInt(getRealmKey(key, propertyNames));
}
private Collection<String> getPropertyList(String key, Properties propertyNames) {
return Property.getPropertyList(getRealmKey(key, propertyNames));
}
private RealmKey getRealmKey(String key, Properties propertyNames) {
String propertyOrDefault = propertyNames.getProperty(key, key);
return new RealmKey(propertyOrDefault, realm);
}
void postInitialize() throws URISyntaxException {
setActiveDirectoryUrls();
if(!isServiceAuthenticationGssApi() && !serviceAccountName.toLowerCase().endsWith(baseDn)) {
serviceAccountName = appendBaseDn(formatUsername(serviceAccountName));
}
includedOuBasesList.removeAll(excludedOuBasesList); // just to make sure
Collection<String> escapedIncludedOuBasesList = getEscapedDns(includedOuBasesList, false);
Collection<String> escapedExcludedOuBasesList = getEscapedDns(excludedOuBasesList, false);
Collection<String> escapedOuSearchBase = getEscapedDns(includedOuBasesList, true);
template = new PagedResultTemplate(escapedIncludedOuBasesList, escapedExcludedOuBasesList, escapedOuSearchBase, pageSize);
refresh();
}
private static Collection<String> getEscapedDns(Collection<String> toEscapeDns, boolean requiresSecondEscape) {
Collection<String> escapedDns = new HashSet<String>(toEscapeDns.size());
for (String toEscapeDn : toEscapeDns) {
String escapedDn = getEscapedDn(toEscapeDn, requiresSecondEscape);
escapedDns.add(escapedDn);
}
return Collections.unmodifiableCollection(escapedDns);
}
static String getEscapedDn(String toEscape, boolean requiresSecondEscape) {
for (int index = 0; index < ESCAPED_CHARACTERS.length; index++) {
String character = ESCAPED_CHARACTERS[index];
if (requiresSecondEscape) {
if(character.equals(ESCAPE_BACKSLASH)) {
toEscape = toEscape.replaceAll(character, ESCAPE_BACKSLASH + ESCAPE_BACKSLASH + ESCAPE_BACKSLASH + ESCAPE_BACKSLASH);
} else if(character.equals(ESCAPE_QUOTE)) {
toEscape = toEscape.replaceAll(character, ESCAPE_BACKSLASH + ESCAPE_BACKSLASH + ESCAPE_QUOTE);
} else {
toEscape = toEscape.replaceAll(character, ESCAPE_BACKSLASH + character);
}
} else {
toEscape = toEscape.replaceAll(character, ESCAPE_BACKSLASH + character);
}
}
return toEscape;
}
private static String formatUsername(String username) {
return username.toUpperCase().startsWith(COMMON_NAME) ? username : COMMON_NAME + username;
}
public String appendBaseDn(String commonName) {
if (commonName.toLowerCase().endsWith(baseDn.toLowerCase())) {
return commonName;
} else {
return commonName.endsWith(",") ? commonName : commonName + "," + baseDn;
}
}
void refresh() {
propertyManager.refresh();
}
public String getDomain() {
return domain;
}
private void setDomain(String domain) throws Exception {
this.domain = domain.toUpperCase().trim();
if (this.domain.equals("")) {
throw new IllegalArgumentException("No active directory domain configured.");
}
setBaseDn(splitDomain(domain));
}
private void setControllerHost(String controllerHost) {
if (controllerHost.equals("")) {
throw new IllegalArgumentException("No active directory controller host configured.");
}
this.controllerHost = controllerHost;
}
private Collection<String> getBackupControllerHosts() {
return backupControllerHosts;
}
private void setBackupControllerHosts(Collection<String> backupControllerHosts) {
this.backupControllerHosts = backupControllerHosts;
}
String getServiceAuthenticationType() {
return serviceAuthenticationType;
}
public void setServiceAuthenticationType(String serviceAuthenticationType) {
this.serviceAuthenticationType = serviceAuthenticationType;
}
boolean isServiceAuthenticationGssApi() {
return GSSAPI_AUTHENTICATION_METHOD.equals(getServiceAuthenticationType());
}
boolean isUserAuthenticationGssApi() {
return GSSAPI_AUTHENTICATION_METHOD.equals(getUserAuthenticationType());
}
String getUserAuthenticationType() {
return userAuthenticationType;
}
public void setUserAuthenticationType(String userAuthenticationType) {
this.userAuthenticationType = userAuthenticationType;
}
public String getServiceAccountName() {
return serviceAccountName;
}
void setServiceAccountName(String serviceAccountName) {
this.serviceAccountName = serviceAccountName == null ? null : serviceAccountName.trim();
}
public String getServiceAccountPassword() {
return serviceAccountPassword;
}
void setServiceAccountPassword(String serviceAccountPassword) {
this.serviceAccountPassword = serviceAccountPassword;
}
private String getProtocolType() {
return protocolType;
}
public boolean isSslProtcolType() {
return "ssl".equals(getProtocolType());
}
public void setProtocolType(String protocolType) {
this.protocolType = protocolType;
}
private boolean isFollowReferrals() {
return followReferrals;
}
void setFollowReferrals(boolean followReferrals) {
this.followReferrals = followReferrals;
}
public String getBaseDn() {
return baseDn;
}
void setBaseDn(String baseDn) {
this.baseDn = baseDn == null ? null : baseDn.toLowerCase().trim();
}
void setUserCacheSize(int userCacheSize) {
this.userCacheSize = userCacheSize;
}
void setGroupCacheSize(int groupCacheSize) {
this.groupCacheSize = groupCacheSize;
}
void setInMemoryCache(boolean inMemoryCache) {
this.inMemoryCache = inMemoryCache;
}
int getTimeToLive() {
return timeToLive;
}
void setTimeToLive(int timeToLive) {
if (timeToLive < 1) {
logger.warn("Cache TTL is less than 1 minute. This would cause serious performance problems. The minimum value of 1 minute will now be used");
timeToLive = 1;
}
this.timeToLive = minutesToMillis(timeToLive);
}
private static int minutesToMillis(int minutes) {
return minutes * 60 * 1000;
}
UserContainer createUserContainer() {
return new UserContainer(userCacheSize, inMemoryCache, isUsernamesAreCaseSensitive(), getDomain());
}
GroupContainer createRoleContainer() {
return new GroupContainer(groupCacheSize, inMemoryCache);
}
void setValidOus(String baseDn, Collection<String> includedOuFilterList, Collection<String> excludedOuFilterList) {
includedOuBasesList.clear();
includedOuBasesList.addAll(getFormattedOuFilterList(baseDn, includedOuFilterList));
excludedOuBasesList.clear();
excludedOuBasesList.addAll(getFormattedOuFilterList(baseDn, excludedOuFilterList));
includedOuBasesList.removeAll(excludedOuBasesList);
hasFilteredOus = !includedOuBasesList.isEmpty();
if (!hasFilteredOus) {
includedOuBasesList.add(baseDn);
}
if (logger.isDebugEnabled()) {
logger.debug("Included OU Bases:");
for (String dn : includedOuBasesList) {
logger.debug(" " + dn);
}
logger.debug("Excluded OU Bases:");
for (String dn : excludedOuBasesList) {
logger.debug(" " + dn);
}
}
}
private static Collection<String> getFormattedOuFilterList(String baseDn, Collection<String> ouFilterList) {
Collection<String> formattedOuFilterList = new HashSet<String>();
for (String dn : ouFilterList) {
if (!dn.trim().toLowerCase().endsWith(baseDn.trim().toLowerCase())) {
dn = dn + "," + baseDn;
}
formattedOuFilterList.add(dn);
}
return formattedOuFilterList;
}
private void setIncludeStandardUsers(boolean includeStandardUsers) {
if (includeStandardUsers) {
if (hasFilteredOus) {
includedOuBasesList.add(0, appendBaseDn(CN_USERS));
}
} else {
excludedOuBasesList.add(0, appendBaseDn(CN_USERS));
}
}
private void setIncludeBuiltInGroups(boolean includeBuiltInGroups) {
if (includeBuiltInGroups) {
if (hasFilteredOus) {
includedOuBasesList.add(0, appendBaseDn(CN_BUILTIN));
}
} else {
excludedOuBasesList.add(0, appendBaseDn(CN_BUILTIN));
}
}
boolean isIncludeDistributionGroups() {
return includeDistributionGroups;
}
private void setIncludeDistributionGroups(boolean includeDistributionGroups) {
this.includeDistributionGroups = includeDistributionGroups;
}
boolean isMemberOfSupported() {
return memberOfSupported;
}
private void setMemberOfSupported(boolean memberOfSupported) {
this.memberOfSupported = memberOfSupported;
}
private boolean isUsernamesAreCaseSensitive() {
return usernamesAreCaseSensitive;
}
private void setUsernamesAreCaseSensitive(boolean usernamesAreCaseSensitive) {
this.usernamesAreCaseSensitive = usernamesAreCaseSensitive;
}
private void setActiveDirectoryUrls() throws URISyntaxException {
activeDirectoryUrls.clear();
lastContactedActiveDirectoryUrl = null;
int controllerPort = getControllerPort();
URI primaryUri = controllerHost.contains(PORT_SEPARATOR) ? buildURI(controllerHost) : buildURI(controllerHost, controllerPort);
activeDirectoryUrls.add(primaryUri);
for (String uri : getBackupControllerHosts()) {
if (uri.contains(PORT_SEPARATOR)) {
activeDirectoryUrls.add(buildURI(uri));
} else {
activeDirectoryUrls.add(buildURI(uri, controllerPort));
}
}
setLastContactedActiveDirectoryUrl(primaryUri);
}
private int getControllerPort() {
int indexOf = controllerHost.indexOf(PORT_SEPARATOR);
if(indexOf == -1 || indexOf == controllerHost.length() - 1) {
if(isServiceAuthenticationGssApi()) {
return CLEAR_TEXT_PORT;
}
return isSslProtcolType() ? SSL_SECURED_PORT : CLEAR_TEXT_PORT;
} else {
String port = controllerHost.substring(indexOf + 1);
Integer valueOf = Integer.valueOf(port);
return valueOf;
}
}
private static URI buildURI(String host, int port) throws URISyntaxException {
return buildURI(host + PORT_SEPARATOR + port);
}
private static URI buildURI(String url) throws URISyntaxException {
return new URI(LDAP_PROTOCOL + url);
}
String getContactableActiveDirectories() {
URI lastContactedUrl = getLastContactedActiveDirectoryUrl();
URI firstUrl = activeDirectoryUrls.isEmpty() ? null : activeDirectoryUrls.iterator().next();
boolean isDifferent = !lastContactedUrl.equals(firstUrl);
Collection<URI> hosts = new ArrayList<URI>(activeDirectoryUrls.size() + 1);
if (isDifferent) {
hosts.add(lastContactedUrl);
}
hosts.addAll(activeDirectoryUrls);
return getHosts(hosts);
}
private static String getHosts(Collection<URI> urls) {
StringBuffer buffer = new StringBuffer();
for (Iterator<URI> itr = urls.iterator(); itr.hasNext();) {
buffer.append(itr.next().toString());
if(itr.hasNext()) {
buffer.append(" ");
}
}
return buffer.toString();
}
synchronized URI getLastContactedActiveDirectoryUrl() {
return lastContactedActiveDirectoryUrl;
}
synchronized void setLastContactedActiveDirectoryUrl(String url) {
try {
setLastContactedActiveDirectoryUrl(new URI(url));
} catch (URISyntaxException e) {
// ignore
}
}
private synchronized void setLastContactedActiveDirectoryUrl(URI url) {
if (lastContactedActiveDirectoryUrl == null || !lastContactedActiveDirectoryUrl.equals(url)) {
PropertyList kerbrosControllerSettings = getKerbrosControllerSettings(url);
propertyManager.refresh(Collections.singletonMap("activeDirectory.backupControllerHosts", kerbrosControllerSettings.getAsPropertyText()));
}
lastContactedActiveDirectoryUrl = url;
}
private PropertyList getKerbrosControllerSettings(URI contactedUrl) {
PropertyList values = new PropertyList();
values.add(getKerbrosController(contactedUrl));
for (URI url : activeDirectoryUrls) {
String kerbrosController = getKerbrosController(url);
if (!values.contains(kerbrosController)) {
values.add(kerbrosController);
}
}
return values;
}
private static String getKerbrosController(URI url) {
String toParse = url.toString();
return toParse.substring(LDAP_PROTOCOL.length(), toParse.lastIndexOf(PORT_SEPARATOR));
}
void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
private int getTimeout() {
return timeOut;
}
private void setTimeOut(int timeOut) {
this.timeOut = timeOut * 1000;
}
PagedResultTemplate getPagedResultTemplate() {
return this.template;
}
public Object doAs(PrivilegedAction<?> action) throws UserDatabaseException {
Object result = null;
if (isServiceAuthenticationGssApi()) {
try {
LoginContext context = getServiceAccountLoginContext();
result = Subject.doAs(context.getSubject(), action);
logoutContext(context);
} catch (Exception e) {
logger.error("Failure to create Login Context", e);
throw new UserDatabaseException("", e);
}
} else {
result = action.run();
}
if (result instanceof Throwable) {
Throwable e = (Throwable) result;
logger.error("Failure to doAs", e);
throw new UserDatabaseException("", e);
}
return result;
}
private LoginContext getServiceAccountLoginContext() throws Exception {
/*
* Only attempt to load the service account context if it has not been
* loaded, if the username has changed or if the password has changed
*/
try {
return createLoginContext(getServiceAccountName(), getServiceAccountPassword());
} catch (LoginException e) {
Throwable cause = e.getCause();
// Check the class by name to allow non Sun Javas to compile
if (cause != null && cause.getClass().getName().equals("sun.security.krb5.KrbException")) {
throw new Exception("Failed to logon. Please check your Active Directory configuration.", e);
}
throw e;
}
}
LoginContext createLoginContext(String username, String password) throws LoginException {
if (logger.isDebugEnabled()) {
logger.debug("Creating login context for " + username);
}
UserPasswordCallbackHandler callbackHandler = new UserPasswordCallbackHandler();
callbackHandler.setUserId(username);
callbackHandler.setPassword(password);
LoginContext context = new LoginContext(ActiveDirectoryUserDatabase.class.getName(), callbackHandler);
context.login();
return context;
}
static void logoutContext(LoginContext context) {
try {
if (context != null) {
context.logout();
}
} catch (LoginException e) {
// ignore
}
}
InitialLdapContext getAuthenticatedContext(String url, Map<String, String> properties) throws NamingException {
Hashtable<String, String> variables = new Hashtable<String, String>(properties);
variables.put(Context.SECURITY_AUTHENTICATION, getServiceAuthenticationType());
if (!isServiceAuthenticationGssApi()) {
variables.put(Context.SECURITY_PRINCIPAL, getServiceAccountName());
variables.put(Context.SECURITY_CREDENTIALS, getServiceAccountPassword());
}
return getInitialContext(url, variables);
}
InitialLdapContext getAuthenticatedContext(String url) throws NamingException {
return getAuthenticatedContext(url, Collections.<String, String> emptyMap());
}
public InitialLdapContext getInitialContext(String url, Map<String, String> properties) throws NamingException {
Hashtable<String, String> variables = new Hashtable<String, String>(properties);
variables.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
variables.put(Context.PROVIDER_URL, url); // Must use fully qualified hostname
if (isSslProtcolType()) {
variables.put("java.naming.ldap.factory.socket", "com.adito.boot.CustomSSLSocketFactory");
// Add the custom socket factory
}
if (isFollowReferrals()) {
variables.put(Context.REFERRAL, "follow");
}
variables.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(getTimeout()));
variables.put("java.naming.ldap.version", "3");
variables.put("com.sun.jndi.ldap.connect.pool", "true");
variables.put("javax.security.sasl.qop", "auth-conf,auth-int,auth");
variables.put(Context.SECURITY_PROTOCOL, getProtocolType());
InitialLdapContext context = new InitialLdapContext(variables, null);
String usedUrl = (String) context.getEnvironment().get(Context.PROVIDER_URL);
setLastContactedActiveDirectoryUrl(usedUrl);
return context;
}
private static String splitDomain(String domain) {
StringBuffer buffer = new StringBuffer();
for (StringTokenizer tokenizer = new StringTokenizer(domain, "."); tokenizer.hasMoreTokens();) {
if (buffer.length() > 0) {
buffer.append(",");
}
buffer.append("DC=" + tokenizer.nextToken());
}
return buffer.toString();
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder(super.toString());
builder.append("[realm='").append(realm);
builder.append("', domain='").append(getDomain());
builder.append("', controllerHost='").append(controllerHost);
builder.append("', backupControllerHosts='").append(getBackupControllerHosts());
builder.append("', serviceAuthenticationType='").append(getServiceAuthenticationType());
builder.append("', userAuthenticationType='").append(getUserAuthenticationType());
builder.append("', serviceAccountName='").append(getServiceAccountName());
builder.append("', serviceAccountPassword='************");
builder.append("', baseDn='").append(getBaseDn());
builder.append("', protocolType='").append(getProtocolType());
builder.append("', followReferrals='").append(isFollowReferrals());
builder.append("', userCacheSize='").append(userCacheSize);
builder.append("', groupCacheSize='").append(groupCacheSize);
builder.append("', inMemoryCache='").append(inMemoryCache);
builder.append("', timeToLive='").append(timeToLive);
builder.append("', includedOuBasesList='").append(includedOuBasesList);
builder.append("', excludedOuBasesList='").append(excludedOuBasesList);
builder.append("', hasFilteredOus='").append(hasFilteredOus);
builder.append("', includeDistributionGroups='").append(includeDistributionGroups);
builder.append("', usernamesAreCaseSensitive='").append(usernamesAreCaseSensitive);
builder.append("', pageSize='").append(pageSize);
builder.append("', timeOut='").append(timeOut).append("']");
return builder.toString();
}
/**
* Converts an Active Directory long value into a
* <code>java.util.Date</code>.
*
* @param timeStamp the time to convert
* @return the <code>java.util.Date</code> representing the long
*/
public static Date adTimeToJavaDate(long timeStamp) {
Calendar calendar = Calendar.getInstance();
calendar.clear();
calendar.set(1601, 0, 1, 0, 0);
timeStamp = timeStamp / 10000 + calendar.getTime().getTime();
return new Date(timeStamp);
}
/**
* Converts an Active Directory long value into a number of days.
*
* @param timeStamp the time to convert
* @return days representing the long
*/
public static int adTimeToJavaDays(long timeStamp) {
return (int) (timeStamp / -86400) / 10000000;
}
}