MOB-710: LDAP queries now performed with RFC 2696 paging and a configurable page size, defaulting to 1000 (the AD default maximum)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@14648 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2009-06-11 09:04:24 +00:00
parent b76f5fe5e1
commit a4b283068c
5 changed files with 406 additions and 243 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
* Copyright (C) 2005-2009 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -18,7 +18,7 @@
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* FLOSS exception. You should have received a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing"
*/
@@ -26,6 +26,7 @@ package org.alfresco.repo.security.authentication.ldap;
import java.util.Map;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import org.alfresco.repo.security.authentication.AuthenticationException;
@@ -44,6 +45,19 @@ public interface LDAPInitialDirContextFactory
*/
public void setInitialDirContextEnvironment(Map<String, String> environment);
/**
* Use the environment properties and connect to the LDAP server, optionally configuring RFC 2696 paged results.
* Used to obtain read only access to the LDAP server.
*
* @param pageSize
* if a positive value, indicates that a LDAP v3 RFC 2696 paged results control should be used. The
* results of a search operation should be returned by the LDAP server in batches of the specified size.
* @return the default intial dir context
* @throws AuthenticationException
* the authentication exception
*/
public InitialDirContext getDefaultIntialDirContext(int pageSize) throws AuthenticationException;
/**
* Use the environment properties and connect to the LDAP server.
* Used to obtain read only access to the LDAP server.
@@ -53,6 +67,19 @@ public interface LDAPInitialDirContextFactory
*/
public InitialDirContext getDefaultIntialDirContext() throws AuthenticationException;
/**
* Determines whether there is another page to fetch from the last search to be run in this context. Also prepares
* the request controls so that the appropriate cookie will be passed in the next search.
*
* @param ctx
* the context
* @param pageSize
* if a positive value, indicates that a LDAP v3 RFC 2696 paged results control should be used. The
* results of a search operation should be returned by the LDAP server in batches of the specified size.
* @return true, if is ready for next page
*/
public boolean hasNextPage(DirContext ctx, int pageSize);
/**
* Augment the connection environment with the identity and credentials and bind to the ldap server.
* Mainly used to validate a user's credentials during authentication.

View File

@@ -24,6 +24,7 @@
*/
package org.alfresco.repo.security.authentication.ldap;
import java.io.IOException;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Map;
@@ -35,7 +36,13 @@ import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.ldap.Control;
import javax.naming.ldap.InitialLdapContext;
import javax.naming.ldap.LdapContext;
import javax.naming.ldap.PagedResultsControl;
import javax.naming.ldap.PagedResultsResponseControl;
import org.alfresco.repo.security.authentication.AuthenticationException;
import org.alfresco.util.ApplicationContextHelper;
@@ -71,18 +78,37 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
}
public InitialDirContext getDefaultIntialDirContext() throws AuthenticationException
{
return getDefaultIntialDirContext(0);
}
public InitialDirContext getDefaultIntialDirContext(int pageSize) throws AuthenticationException
{
Hashtable<String, String> env = new Hashtable<String, String>(initialDirContextEnvironment.size());
env.putAll(initialDirContextEnvironment);
env.put("javax.security.auth.useSubjectCredsOnly", "false");
return buildInitialDirContext(env);
return buildInitialDirContext(env, pageSize);
}
private InitialDirContext buildInitialDirContext(Hashtable<String, String> env) throws AuthenticationException
private InitialDirContext buildInitialDirContext(Hashtable<String, String> env, int pageSize)
throws AuthenticationException
{
try
{
return new InitialDirContext(env);
// If a page size has been requested, use LDAP v3 paging
if (pageSize > 0)
{
InitialLdapContext ctx = new InitialLdapContext(env, null);
ctx.setRequestControls(new Control[]
{
new PagedResultsControl(pageSize, Control.CRITICAL)
});
return ctx;
}
else
{
return new InitialDirContext(env);
}
}
catch (javax.naming.AuthenticationException ax)
{
@@ -92,6 +118,54 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
throw new AuthenticationException("Unable to connect to LDAP Server; check LDAP configuration", nx);
}
catch (IOException e)
{
throw new AuthenticationException("Unable to encode LDAP v3 request controls; check LDAP configuration", e);
}
}
public boolean hasNextPage(DirContext ctx, int pageSize)
{
if (pageSize > 0)
{
try
{
LdapContext ldapContext = (LdapContext) ctx;
Control[] controls = ldapContext.getResponseControls();
// Retrieve the paged result cookie if there is one
if (controls != null)
{
for (Control control : controls)
{
if (control instanceof PagedResultsResponseControl)
{
byte[] cookie = ((PagedResultsResponseControl) control).getCookie();
if (cookie != null)
{
// Prepare for next page
ldapContext.setRequestControls(new Control[]
{
new PagedResultsControl(pageSize, cookie, Control.CRITICAL)
});
return true;
}
}
}
}
}
catch (NamingException nx)
{
throw new AuthenticationException("Unable to connect to LDAP Server; check LDAP configuration", nx);
}
catch (IOException e)
{
throw new AuthenticationException(
"Unable to encode LDAP v3 request controls; check LDAP configuration", e);
}
}
return false;
}
public InitialDirContext getInitialDirContext(String principal, String credentials) throws AuthenticationException
@@ -100,7 +174,7 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
throw new AuthenticationException("Null user name provided.");
}
if (principal.length() == 0)
{
throw new AuthenticationException("Empty user name provided.");
@@ -110,18 +184,18 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
throw new AuthenticationException("No credentials provided.");
}
if (credentials.length() == 0)
{
throw new AuthenticationException("Empty credentials provided.");
}
Hashtable<String, String> env = new Hashtable<String, String>(initialDirContextEnvironment.size());
env.putAll(initialDirContextEnvironment);
env.put(Context.SECURITY_PRINCIPAL, principal);
env.put(Context.SECURITY_CREDENTIALS, credentials);
return buildInitialDirContext(env);
return buildInitialDirContext(env, 0);
}
public static void main(String[] args)
@@ -214,7 +288,7 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
public void afterPropertiesSet() throws Exception
{
// Check Anonymous bind
Hashtable<String, String> env = new Hashtable<String, String>(initialDirContextEnvironment.size());
env.putAll(initialDirContextEnvironment);
env.remove(Context.SECURITY_PRINCIPAL);
@@ -229,18 +303,18 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
}
catch(AuthenticationNotSupportedException e)
catch (AuthenticationNotSupportedException e)
{
}
catch (NamingException nx)
{
logger.error("Unable to connect to LDAP Server; check LDAP configuration", nx);
return;
}
// Simple DN and password
env = new Hashtable<String, String>(initialDirContextEnvironment.size());
env.putAll(initialDirContextEnvironment);
env.put(Context.SECURITY_PRINCIPAL, "daftAsABrush");
@@ -259,7 +333,7 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
logger.info("LDAP server does not fall back to anonymous bind for a string uid and password at " + env.get(Context.PROVIDER_URL));
}
catch(AuthenticationNotSupportedException e)
catch (AuthenticationNotSupportedException e)
{
logger.info("LDAP server does not fall back to anonymous bind for a string uid and password at " + env.get(Context.PROVIDER_URL));
}
@@ -267,9 +341,9 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
logger.info("LDAP server does not support simple string user ids and invalid credentials at "+ env.get(Context.PROVIDER_URL));
}
// DN and password
env = new Hashtable<String, String>(initialDirContextEnvironment.size());
env.putAll(initialDirContextEnvironment);
env.put(Context.SECURITY_PRINCIPAL, "cn=daftAsABrush,dc=woof");
@@ -288,7 +362,7 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
logger.info("LDAP server does not fall back to anonymous bind for a simple dn and password at " + env.get(Context.PROVIDER_URL));
}
catch(AuthenticationNotSupportedException e)
catch (AuthenticationNotSupportedException e)
{
logger.info("LDAP server does not fall back to anonymous bind for a simple dn and password at " + env.get(Context.PROVIDER_URL));
}
@@ -298,13 +372,13 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
}
// Check more if we have a real principal we expect to work
env = new Hashtable<String, String>(initialDirContextEnvironment.size());
env.putAll(initialDirContextEnvironment);
if(env.get(Context.SECURITY_PRINCIPAL) != null)
if (env.get(Context.SECURITY_PRINCIPAL) != null)
{
// Correct principal invalid password
env = new Hashtable<String, String>(initialDirContextEnvironment.size());
env.putAll(initialDirContextEnvironment);
env.put(Context.SECURITY_CREDENTIALS, "sdasdasdasdasd123123123");
@@ -322,7 +396,7 @@ public class LDAPInitialDirContextFactoryImpl implements LDAPInitialDirContextFa
{
logger.info("LDAP server does not fall back to anonymous bind for known principal and invalid credentials at " + env.get(Context.PROVIDER_URL));
}
catch(AuthenticationNotSupportedException e)
catch (AuthenticationNotSupportedException e)
{
logger.info("LDAP server does not support the required authentication mechanism");
}

View File

@@ -120,6 +120,12 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
/** The attribute defaults. */
private Map<String, String> attributeDefaults;
/**
* The query batch size. If positive, indicates that RFC 2696 paged results should be used to split query results
* into batches of the specified size. Overcomes any size limits imposed by the LDAP server.
*/
private int queryBatchSize;
/** Should we error on missing group members? */
private boolean errorOnMissingMembers;
@@ -377,6 +383,18 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
this.attributeMapping = attributeMapping;
}
/**
* Sets the query batch size.
*
* @param queryBatchSize
* If positive, indicates that RFC 2696 paged results should be used to split query results into batches
* of the specified size. Overcomes any size limits imposed by the LDAP server.
*/
public void setQueryBatchSize(int queryBatchSize)
{
this.queryBatchSize = queryBatchSize;
}
/*
* (non-Javadoc)
* @see org.alfresco.repo.management.subsystems.ActivateableBean#isActive()
@@ -426,183 +444,187 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
public Iterator<NodeDescription> getGroups(Date modifiedSince)
{
Map<String, NodeDescription> lookup = new TreeMap<String, NodeDescription>();
SearchControls userSearchCtls = new SearchControls();
userSearchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
userSearchCtls.setReturningAttributes(this.groupAttributeNames);
InitialDirContext ctx = null;
try
{
ctx = this.ldapInitialContextFactory.getDefaultIntialDirContext();
SearchControls userSearchCtls = new SearchControls();
userSearchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
userSearchCtls.setReturningAttributes(this.groupAttributeNames);
NamingEnumeration<SearchResult> searchResults;
if (modifiedSince == null)
ctx = this.ldapInitialContextFactory.getDefaultIntialDirContext(this.queryBatchSize);
do
{
searchResults = ctx.search(this.groupSearchBase, this.groupQuery, userSearchCtls);
}
else
{
searchResults = ctx.search(this.groupSearchBase, this.groupDifferentialQuery, new Object[]
{
LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT.format(modifiedSince)
}, userSearchCtls);
}
NamingEnumeration<SearchResult> searchResults;
LdapName groupDistinguishedNamePrefix = new LdapName(this.groupSearchBase);
LdapName userDistinguishedNamePrefix = new LdapName(this.userSearchBase);
while (searchResults.hasMoreElements())
{
SearchResult result = searchResults.next();
Attributes attributes = result.getAttributes();
Attribute gidAttribute = attributes.get(this.groupIdAttributeName);
if (gidAttribute == null)
if (modifiedSince == null)
{
if (this.errorOnMissingGID)
{
throw new AlfrescoRuntimeException(
"NodeDescription returned by group search does not have mandatory group id attribute "
+ attributes);
}
else
{
LDAPUserRegistry.logger.warn("Missing GID on " + attributes);
continue;
}
}
String gid = "GROUP_" + gidAttribute.get(0);
NodeDescription group = lookup.get(gid);
if (group == null)
{
group = new NodeDescription();
group.getProperties().put(ContentModel.PROP_AUTHORITY_NAME, gid);
lookup.put(gid, group);
}
else if (this.errorOnDuplicateGID)
{
throw new AlfrescoRuntimeException("Duplicate group id found for " + gid);
searchResults = ctx.search(this.groupSearchBase, this.groupQuery, userSearchCtls);
}
else
{
LDAPUserRegistry.logger.warn("Duplicate gid found for " + gid + " -> merging definitions");
}
Attribute modifyTimestamp = attributes.get(this.modifyTimestampAttributeName);
if (modifyTimestamp != null)
{
group.setLastModified(LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT.parse(modifyTimestamp.get()
.toString()));
}
Set<String> childAssocs = group.getChildAssociations();
Attribute memAttribute = attributes.get(this.memberAttributeName);
// check for null
if (memAttribute != null)
{
for (int i = 0; i < memAttribute.size(); i++)
searchResults = ctx.search(this.groupSearchBase, this.groupDifferentialQuery, new Object[]
{
String attribute = (String) memAttribute.get(i);
if (attribute != null)
LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT.format(modifiedSince)
}, userSearchCtls);
}
LdapName groupDistinguishedNamePrefix = new LdapName(this.groupSearchBase);
LdapName userDistinguishedNamePrefix = new LdapName(this.userSearchBase);
while (searchResults.hasMoreElements())
{
SearchResult result = searchResults.next();
Attributes attributes = result.getAttributes();
Attribute gidAttribute = attributes.get(this.groupIdAttributeName);
if (gidAttribute == null)
{
if (this.errorOnMissingGID)
{
LdapName distinguishedName = new LdapName(attribute);
Attribute nameAttribute;
throw new AlfrescoRuntimeException(
"NodeDescription returned by group search does not have mandatory group id attribute "
+ attributes);
}
else
{
LDAPUserRegistry.logger.warn("Missing GID on " + attributes);
continue;
}
}
String gid = "GROUP_" + gidAttribute.get(0);
// If the user and group search bases are different we may be able to recognise user and
// group DNs without a secondary lookup
if (!this.userSearchBase.equals(this.groupSearchBase))
NodeDescription group = lookup.get(gid);
if (group == null)
{
group = new NodeDescription();
group.getProperties().put(ContentModel.PROP_AUTHORITY_NAME, gid);
lookup.put(gid, group);
}
else if (this.errorOnDuplicateGID)
{
throw new AlfrescoRuntimeException("Duplicate group id found for " + gid);
}
else
{
LDAPUserRegistry.logger.warn("Duplicate gid found for " + gid + " -> merging definitions");
}
Attribute modifyTimestamp = attributes.get(this.modifyTimestampAttributeName);
if (modifyTimestamp != null)
{
group.setLastModified(LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT.parse(modifyTimestamp.get()
.toString()));
}
Set<String> childAssocs = group.getChildAssociations();
Attribute memAttribute = attributes.get(this.memberAttributeName);
// check for null
if (memAttribute != null)
{
for (int i = 0; i < memAttribute.size(); i++)
{
String attribute = (String) memAttribute.get(i);
if (attribute != null)
{
Attributes nameAttributes = distinguishedName.getRdn(distinguishedName.size() - 1)
.toAttributes();
LdapName distinguishedName = new LdapName(attribute);
Attribute nameAttribute;
// Recognise user DNs
if (distinguishedName.startsWith(userDistinguishedNamePrefix)
&& (nameAttribute = nameAttributes.get(this.userIdAttributeName)) != null)
// If the user and group search bases are different we may be able to recognise user and
// group DNs without a secondary lookup
if (!this.userSearchBase.equalsIgnoreCase(this.groupSearchBase))
{
childAssocs.add((String) nameAttribute.get());
continue;
}
Attributes nameAttributes = distinguishedName.getRdn(distinguishedName.size() - 1)
.toAttributes();
// Recognise group DNs
if (distinguishedName.startsWith(groupDistinguishedNamePrefix)
&& (nameAttribute = nameAttributes.get(this.groupIdAttributeName)) != null)
{
childAssocs.add("GROUP_" + nameAttribute.get());
continue;
}
}
// If we can't determine the name and type from the DN alone, try a directory lookup
if (distinguishedName.startsWith(userDistinguishedNamePrefix)
|| distinguishedName.startsWith(groupDistinguishedNamePrefix))
{
try
{
Attributes childAttributes = ctx.getAttributes(attribute, new String[]
// Recognise user DNs
if (distinguishedName.startsWith(userDistinguishedNamePrefix)
&& (nameAttribute = nameAttributes.get(this.userIdAttributeName)) != null)
{
"objectclass", this.groupIdAttributeName, this.userIdAttributeName
});
String objectclass = (String) childAttributes.get("objectclass").get();
if (objectclass.equals(this.personType))
{
nameAttribute = childAttributes.get(this.userIdAttributeName);
if (nameAttribute == null)
{
if (this.errorOnMissingUID)
{
throw new AlfrescoRuntimeException(
"User missing user id attribute DN =" + attribute + " att = "
+ this.userIdAttributeName);
}
else
{
LDAPUserRegistry.logger.warn("User missing user id attribute DN ="
+ attribute + " att = " + this.userIdAttributeName);
continue;
}
}
childAssocs.add((String) nameAttribute.get());
continue;
}
else if (objectclass.equals(this.groupType))
{
nameAttribute = childAttributes.get(this.groupIdAttributeName);
if (nameAttribute == null)
{
if (this.errorOnMissingGID)
{
throw new AlfrescoRuntimeException(
"Group returned by group search does not have mandatory group id attribute "
+ attributes);
}
else
{
LDAPUserRegistry.logger.warn("Missing GID on " + childAttributes);
continue;
}
}
// Recognise group DNs
if (distinguishedName.startsWith(groupDistinguishedNamePrefix)
&& (nameAttribute = nameAttributes.get(this.groupIdAttributeName)) != null)
{
childAssocs.add("GROUP_" + nameAttribute.get());
continue;
}
}
catch (NamingException e)
// If we can't determine the name and type from the DN alone, try a directory lookup
if (distinguishedName.startsWith(userDistinguishedNamePrefix)
|| distinguishedName.startsWith(groupDistinguishedNamePrefix))
{
// Unresolvable name
try
{
Attributes childAttributes = ctx.getAttributes(attribute, new String[]
{
"objectclass", this.groupIdAttributeName, this.userIdAttributeName
});
String objectclass = (String) childAttributes.get("objectclass").get();
if (objectclass.equalsIgnoreCase(this.personType))
{
nameAttribute = childAttributes.get(this.userIdAttributeName);
if (nameAttribute == null)
{
if (this.errorOnMissingUID)
{
throw new AlfrescoRuntimeException(
"User missing user id attribute DN =" + attribute
+ " att = " + this.userIdAttributeName);
}
else
{
LDAPUserRegistry.logger.warn("User missing user id attribute DN ="
+ attribute + " att = " + this.userIdAttributeName);
continue;
}
}
childAssocs.add((String) nameAttribute.get());
continue;
}
else if (objectclass.equalsIgnoreCase(this.groupType))
{
nameAttribute = childAttributes.get(this.groupIdAttributeName);
if (nameAttribute == null)
{
if (this.errorOnMissingGID)
{
throw new AlfrescoRuntimeException(
"Group returned by group search does not have mandatory group id attribute "
+ attributes);
}
else
{
LDAPUserRegistry.logger.warn("Missing GID on " + childAttributes);
continue;
}
}
childAssocs.add("GROUP_" + nameAttribute.get());
continue;
}
}
catch (NamingException e)
{
// Unresolvable name
}
}
if (this.errorOnMissingMembers)
{
throw new AlfrescoRuntimeException("Failed to resolve distinguished name: "
+ attribute);
}
LDAPUserRegistry.logger.warn("Failed to resolve distinguished name: " + attribute);
}
if (this.errorOnMissingMembers)
{
throw new AlfrescoRuntimeException("Failed to resolve distinguished name: " + attribute);
}
LDAPUserRegistry.logger.warn("Failed to resolve distinguished name: " + attribute);
}
}
}
}
while (this.ldapInitialContextFactory.hasNextPage(ctx, this.queryBatchSize));
if (LDAPUserRegistry.logger.isDebugEnabled())
{
@@ -643,6 +665,10 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
/** The directory context. */
private InitialDirContext ctx;
private SearchControls userSearchCtls;
private Date modifiedSince;
/** The search results. */
private NamingEnumeration<SearchResult> searchResults;
@@ -663,29 +689,18 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
{
try
{
this.ctx = LDAPUserRegistry.this.ldapInitialContextFactory.getDefaultIntialDirContext();
this.ctx = LDAPUserRegistry.this.ldapInitialContextFactory
.getDefaultIntialDirContext(LDAPUserRegistry.this.queryBatchSize);
// Authentication has been successful.
// Set the current user, they are now authenticated.
SearchControls userSearchCtls = new SearchControls();
userSearchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
userSearchCtls.setCountLimit(Integer.MAX_VALUE);
userSearchCtls.setReturningAttributes(LDAPUserRegistry.this.userAttributeNames);
this.userSearchCtls = new SearchControls();
this.userSearchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
this.userSearchCtls.setReturningAttributes(LDAPUserRegistry.this.userAttributeNames);
this.modifiedSince = modifiedSince;
if (modifiedSince == null)
{
this.searchResults = this.ctx.search(LDAPUserRegistry.this.userSearchBase,
LDAPUserRegistry.this.personQuery, userSearchCtls);
}
else
{
this.searchResults = this.ctx.search(LDAPUserRegistry.this.userSearchBase,
LDAPUserRegistry.this.personDifferentialQuery, new Object[]
{
LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT.format(modifiedSince)
}, userSearchCtls);
}
this.next = fetchNext();
}
catch (NamingException e)
@@ -748,74 +763,88 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
*/
private NodeDescription fetchNext() throws NamingException
{
while (this.searchResults.hasMoreElements())
boolean readyForNextPage;
do
{
SearchResult result = this.searchResults.next();
Attributes attributes = result.getAttributes();
Attribute uidAttribute = attributes.get(LDAPUserRegistry.this.userIdAttributeName);
if (uidAttribute == null)
readyForNextPage = this.searchResults == null;
while (!readyForNextPage && this.searchResults.hasMoreElements())
{
if (LDAPUserRegistry.this.errorOnMissingUID)
SearchResult result = this.searchResults.next();
Attributes attributes = result.getAttributes();
Attribute uidAttribute = attributes.get(LDAPUserRegistry.this.userIdAttributeName);
if (uidAttribute == null)
{
throw new AlfrescoRuntimeException(
"User returned by user search does not have mandatory user id attribute " + attributes);
if (LDAPUserRegistry.this.errorOnMissingUID)
{
throw new AlfrescoRuntimeException(
"User returned by user search does not have mandatory user id attribute "
+ attributes);
}
else
{
LDAPUserRegistry.logger
.warn("User returned by user search does not have mandatory user id attribute "
+ attributes);
continue;
}
}
else
String uid = (String) uidAttribute.get(0);
if (this.uids.contains(uid))
{
LDAPUserRegistry.logger
.warn("User returned by user search does not have mandatory user id attribute "
+ attributes);
continue;
.warn("Duplicate uid found - there will be more than one person object for this user - "
+ uid);
}
}
String uid = (String) uidAttribute.get(0);
if (this.uids.contains(uid))
{
LDAPUserRegistry.logger
.warn("Duplicate uid found - there will be more than one person object for this user - "
+ uid);
}
this.uids.add(uid);
this.uids.add(uid);
if (LDAPUserRegistry.logger.isDebugEnabled())
{
LDAPUserRegistry.logger.debug("Adding user for " + uid);
}
NodeDescription person = new NodeDescription();
Attribute modifyTimestamp = attributes.get(LDAPUserRegistry.this.modifyTimestampAttributeName);
if (modifyTimestamp != null)
{
try
if (LDAPUserRegistry.logger.isDebugEnabled())
{
person.setLastModified(LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT.parse(modifyTimestamp
.get().toString()));
LDAPUserRegistry.logger.debug("Adding user for " + uid);
}
catch (ParseException e)
{
throw new AlfrescoRuntimeException("Failed to import people.", e);
}
}
PropertyMap properties = person.getProperties();
for (String key : LDAPUserRegistry.this.attributeMapping.keySet())
{
QName keyQName = QName.createQName(key, LDAPUserRegistry.this.namespaceService);
NodeDescription person = new NodeDescription();
// cater for null
String attributeName = LDAPUserRegistry.this.attributeMapping.get(key);
if (attributeName != null)
Attribute modifyTimestamp = attributes.get(LDAPUserRegistry.this.modifyTimestampAttributeName);
if (modifyTimestamp != null)
{
Attribute attribute = attributes.get(attributeName);
if (attribute != null)
try
{
String value = (String) attribute.get(0);
if (value != null)
person.setLastModified(LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT.parse(modifyTimestamp
.get().toString()));
}
catch (ParseException e)
{
throw new AlfrescoRuntimeException("Failed to import people.", e);
}
}
PropertyMap properties = person.getProperties();
for (String key : LDAPUserRegistry.this.attributeMapping.keySet())
{
QName keyQName = QName.createQName(key, LDAPUserRegistry.this.namespaceService);
// cater for null
String attributeName = LDAPUserRegistry.this.attributeMapping.get(key);
if (attributeName != null)
{
Attribute attribute = attributes.get(attributeName);
if (attribute != null)
{
properties.put(keyQName, value);
String value = (String) attribute.get(0);
if (value != null)
{
properties.put(keyQName, value);
}
}
else
{
String defaultValue = LDAPUserRegistry.this.attributeDefaults.get(key);
if (defaultValue != null)
{
properties.put(keyQName, defaultValue);
}
}
}
else
@@ -827,17 +856,35 @@ public class LDAPUserRegistry implements UserRegistry, InitializingBean, Activat
}
}
}
return person;
}
// Examine the paged results control response for an indication that another page is available
if (!readyForNextPage)
{
readyForNextPage = LDAPUserRegistry.this.ldapInitialContextFactory.hasNextPage(this.ctx,
LDAPUserRegistry.this.queryBatchSize);
}
// Fetch the next page if there is one
if (readyForNextPage)
{
if (this.modifiedSince == null)
{
this.searchResults = this.ctx.search(LDAPUserRegistry.this.userSearchBase,
LDAPUserRegistry.this.personQuery, this.userSearchCtls);
}
else
{
String defaultValue = LDAPUserRegistry.this.attributeDefaults.get(key);
if (defaultValue != null)
{
properties.put(keyQName, defaultValue);
}
this.searchResults = this.ctx.search(LDAPUserRegistry.this.userSearchBase,
LDAPUserRegistry.this.personDifferentialQuery, new Object[]
{
LDAPUserRegistry.LDAP_GENERALIZED_TIME_FORMAT.format(this.modifiedSince)
}, this.userSearchCtls);
}
}
return person;
}
while (readyForNextPage);
this.searchResults.close();
this.searchResults = null;
this.ctx.close();