Author: bdaw
Date: 2008-12-15 04:53:22 -0500 (Mon, 15 Dec 2008)
New Revision: 163
Modified:
trunk/identity-impl/src/main/java/org/jboss/identity/impl/helper/Tools.java
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/hibernate/HibernateIdentityStoreImpl.java
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/ldap/LDAPIdentityObjectTypeConfiguration.java
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/ldap/LDAPIdentityStoreImpl.java
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/ldap/SimpleLDAPIdentityObjectTypeConfiguration.java
trunk/identity-impl/src/test/java/org/jboss/identity/impl/store/CommonIdentityStoreTest.java
trunk/identity-impl/src/test/java/org/jboss/identity/impl/store/ldap/LDAPIdentityStoreTestCase.java
trunk/identity-impl/src/test/resources/organization-test-config.xml
trunk/identity-impl/src/test/resources/store-test-config.xml
Log:
LDAP store updates
Modified: trunk/identity-impl/src/main/java/org/jboss/identity/impl/helper/Tools.java
===================================================================
--- trunk/identity-impl/src/main/java/org/jboss/identity/impl/helper/Tools.java 2008-12-12
22:43:45 UTC (rev 162)
+++ trunk/identity-impl/src/main/java/org/jboss/identity/impl/helper/Tools.java 2008-12-15
09:53:22 UTC (rev 163)
@@ -47,5 +47,57 @@
return list;
}
+ public static String wildcardToRegex(String wildcard){
+ StringBuffer s = new StringBuffer(wildcard.length());
+ s.append('^');
+ for (int i = 0, is = wildcard.length(); i < is; i++) {
+ char c = wildcard.charAt(i);
+ switch(c) {
+ case '*':
+ s.append(".*");
+ break;
+// case '?':
+// s.append(".");
+// break;
+ // escape special regexp-characters
+ case '(': case ')': case '[': case ']':
case '$':
+ case '^': case '.': case '{': case '}':
case '|':
+ case '\\':
+ s.append("\\");
+ s.append(c);
+ break;
+ default:
+ s.append(c);
+ break;
+ }
+ }
+ s.append('$');
+ return(s.toString());
+ }
+ /**
+ * Process dn and retrieves a part from it:
+ * uid=xxx,dc=example,dc=org - retrieves xxx
+ *
+ * @param dn
+ * @return
+ */
+ public static String stripDnToName(String dn)
+ {
+ if (dn == null || dn.length() == 0)
+ {
+ throw new IllegalArgumentException("Cannot process empty dn");
+ }
+ String name = null;
+
+ String[] parts = dn.split(",");
+
+ parts = parts[0].split("=");
+ if (parts.length != 2)
+ {
+ throw new IllegalArgumentException("Wrong dn format: " + dn);
+ }
+
+ return parts[1];
+ }
}
Modified:
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/hibernate/HibernateIdentityStoreImpl.java
===================================================================
---
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/hibernate/HibernateIdentityStoreImpl.java 2008-12-12
22:43:45 UTC (rev 162)
+++
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/hibernate/HibernateIdentityStoreImpl.java 2008-12-15
09:53:22 UTC (rev 163)
@@ -1222,6 +1222,10 @@
{
throw new IdentityException("Cannot assigned multiply values to
single valued attribute: " + entry.getKey());
}
+ if (amd != null && amd.isReadonly())
+ {
+ throw new IdentityException("Cannot update readonly attribute: "
+ entry.getKey());
+ }
}
}
@@ -1258,6 +1262,10 @@
{
throw new IdentityException("Cannot assigned multiply values to
single valued attribute: " + entry.getKey());
}
+ if (amd != null && amd.isReadonly())
+ {
+ throw new IdentityException("Cannot update readonly attribute: "
+ entry.getKey());
+ }
}
}
@@ -1334,6 +1342,7 @@
}
else
{
+ //TODO: support for empty password should be configurable
value = credential.getValue();
}
@@ -1392,6 +1401,7 @@
}
else
{
+ //TODO: support for empty password should be configurable
value = credential.getValue();
}
Modified:
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/ldap/LDAPIdentityObjectTypeConfiguration.java
===================================================================
---
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/ldap/LDAPIdentityObjectTypeConfiguration.java 2008-12-12
22:43:45 UTC (rev 162)
+++
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/ldap/LDAPIdentityObjectTypeConfiguration.java 2008-12-15
09:53:22 UTC (rev 163)
@@ -34,6 +34,8 @@
{
String getIdAttributeName();
+ String getPasswordAttributeName();
+
String[] getCtxDNs();
String getEntrySearchFilter();
Modified:
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/ldap/LDAPIdentityStoreImpl.java
===================================================================
---
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/ldap/LDAPIdentityStoreImpl.java 2008-12-12
22:43:45 UTC (rev 162)
+++
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/ldap/LDAPIdentityStoreImpl.java 2008-12-15
09:53:22 UTC (rev 163)
@@ -33,13 +33,16 @@
import org.jboss.identity.spi.model.IdentityObjectRelationship;
import org.jboss.identity.spi.exception.OperationNotSupportedException;
import org.jboss.identity.spi.configuration.metadata.IdentityStoreConfigurationMetaData;
+import org.jboss.identity.spi.configuration.metadata.IdentityObjectTypeMetaData;
import org.jboss.identity.spi.credential.IdentityObjectCredential;
+import org.jboss.identity.spi.attribute.AttributeMetaData;
import org.jboss.identity.exception.IdentityException;
import org.jboss.identity.impl.store.FeaturesMetaDataImpl;
import org.jboss.identity.impl.model.ldap.LDAPIdentityObjectImpl;
import org.jboss.identity.impl.model.ldap.LDAPIdentityObjectRelationshipImpl;
import org.jboss.identity.impl.helper.Tools;
import org.jboss.identity.impl.NotYetImplementedException;
+import org.jboss.identity.impl.types.SimpleIdentityObjectType;
import org.jboss.identity.impl.api.SortByNameSearchControl;
import org.jboss.identity.impl.api.PageSearchControl;
import org.jboss.identity.impl.api.AttributeFilterSearchControl;
@@ -49,6 +52,7 @@
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Control;
import javax.naming.ldap.SortControl;
+import javax.naming.ldap.InitialLdapContext;
import javax.naming.directory.Attributes;
import javax.naming.directory.Attribute;
import javax.naming.directory.SearchControls;
@@ -59,6 +63,7 @@
import javax.naming.NamingException;
import javax.naming.NamingEnumeration;
import javax.naming.Context;
+import javax.naming.InitialContext;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
@@ -70,6 +75,9 @@
import java.util.HashSet;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Hashtable;
+import java.util.Comparator;
+import java.util.regex.Pattern;
import java.util.logging.Logger;
import java.util.logging.Level;
@@ -88,14 +96,20 @@
LDAPIdentityStoreConfiguration configuration;
+ IdentityStoreConfigurationMetaData configurationMD;
+
private static Set<Class> supportedSearchControls = new HashSet<Class>();
+ // <IdentityObjectType name, <Attribute name, MD>
+ private Map<String, Map<String, AttributeMetaData>> attributesMetaData =
new HashMap<String, Map<String, AttributeMetaData>>();
+
static {
// List all supported controls classes
//TODO:
supportedSearchControls.add(SortByNameSearchControl.class);
- //supportedSearchControls.add(PageSearchControl.class);
+ supportedSearchControls.add(PageSearchControl.class);
+ supportedSearchControls.add(NameFilterSearchControl.class);
//supportedSearchControls.add(AttributeFilterSearchControl.class);
}
@@ -111,9 +125,25 @@
throw new IllegalArgumentException("Configuration is null");
}
+ this.configurationMD = configurationMD;
+
configuration = new SimpleLDAPIdentityStoreConfiguration(configurationMD);
supportedFeatures = new FeaturesMetaDataImpl(configurationMD,
supportedSearchControls);
+
+ // Attribute mappings - helper structures
+
+ for (IdentityObjectTypeMetaData identityObjectTypeMetaData :
configurationMD.getSupportedIdentityTypes())
+ {
+ Map<String, AttributeMetaData> metadataMap = new HashMap<String,
AttributeMetaData>();
+ for (AttributeMetaData attributeMetaData :
identityObjectTypeMetaData.getAttributes())
+ {
+ metadataMap.put(attributeMetaData.getName(), attributeMetaData);
+ }
+
+ attributesMetaData.put(identityObjectTypeMetaData.getName(), metadataMap);
+
+ }
}
public IdentityStoreSession createIdentityStoreSession()
@@ -300,7 +330,7 @@
if (filter != null && filter.length() > 0)
{
- //* chars are escaped in filterArgs so we must replace it manually
+ // chars are escaped in filterArgs so we must replace it manually
filter = filter.replaceAll("\\{0\\}", "*");
}
else
@@ -309,9 +339,12 @@
filter = "(".concat(getTypeConfiguration(ctx,
identityType).getIdAttributeName()).concat("=").concat("*").concat(")");
}
+
+ String[] entryCtxs = getTypeConfiguration(ctx, identityType).getCtxDNs();
+
//log.debug("Search filter: " + filter);
List sr = searchIdentityObjects(ctx,
- identityType,
+ entryCtxs,
filter,
null,
new String[]{getTypeConfiguration(ctx, identityType).getIdAttributeName()},
@@ -353,11 +386,15 @@
String filter = getTypeConfiguration(invocationCtx,
type).getEntrySearchFilter();
List sr = null;
+
+ String[] entryCtxs = getTypeConfiguration(invocationCtx, type).getCtxDNs();
+
+
if (filter != null && filter.length() > 0)
{
Object[] filterArgs = {name};
sr = searchIdentityObjects(invocationCtx,
- type,
+ entryCtxs,
filter,
filterArgs,
new String[]{getTypeConfiguration(invocationCtx,
type).getIdAttributeName()},
@@ -368,7 +405,7 @@
//search all entries
filter = "(".concat(getTypeConfiguration(invocationCtx,
type).getIdAttributeName()).concat("=").concat(name).concat(")");
sr = searchIdentityObjects(invocationCtx,
- type,
+ entryCtxs,
filter,
null,
new String[]{getTypeConfiguration(invocationCtx,
type).getIdAttributeName()},
@@ -499,20 +536,10 @@
public Collection<IdentityObject>
findIdentityObject(IdentityStoreInvocationContext invocationCtx, IdentityObjectType type,
IdentityObjectSearchControl[] controls) throws IdentityException
{
-// if (log.isLoggable(Level.FINER))
-// {
-// log.finer(toString() + ".findIdentityObject with type: " + type
-// + "; nameFilter: " + nameFilter
-// + "; offset: " + offset
-// + "; limit: " + limit
-// + "; orderByName: " + orderByName
-// + "; ascending: " + ascending
-// );
-// }
checkControls(controls);
- //TODO: paged control
+ //TODO: page control with LDAP request control
PageSearchControl pageSearchControl = null;
SortByNameSearchControl sortSearchControl = null;
@@ -552,8 +579,6 @@
}
- //TODO: handle paged results
-
LdapContext ctx = getLDAPContext(invocationCtx);
@@ -601,12 +626,14 @@
String filter = getTypeConfiguration(invocationCtx,
type).getEntrySearchFilter();
List<SearchResult> sr = null;
+ String[] entryCtxs = getTypeConfiguration(invocationCtx, type).getCtxDNs();
+
if (filter != null && filter.length() > 0)
{
Object[] filterArgs = {nameFilter};
sr = searchIdentityObjects(invocationCtx,
- type,
+ entryCtxs,
"(&(" + filter + ")" + af.toString() +
")",
filterArgs,
new String[]{typeConfiguration.getIdAttributeName()},
@@ -616,7 +643,7 @@
{
filter =
"(".concat(typeConfiguration.getIdAttributeName()).concat("=").concat(nameFilter).concat(")");
sr = searchIdentityObjects(invocationCtx,
- type,
+ entryCtxs,
"(&(" + filter + ")" + af.toString() +
")",
null,
new String[]{typeConfiguration.getIdAttributeName()},
@@ -630,7 +657,8 @@
String dn = ctx.getNameInNamespace();
if (sortSearchControl != null)
{
- //TODO: It seams that sort control returns entries in descending order by
default...
+ // It seams that the sort order is not configurable and
+ // sort control returns entries in descending order by default...
if (!sortSearchControl.isAscending())
{
objects.addFirst(createIdentityObjectInstance(invocationCtx, type,
res.getAttributes(), dn));
@@ -648,7 +676,6 @@
ctx.close();
- return objects;
}
catch (NoSuchElementException e)
@@ -674,6 +701,11 @@
}
}
+ if (pageSearchControl != null)
+ {
+ objects = (LinkedList)cutPageFromResults(objects, pageSearchControl);
+ }
+
return objects;
}
@@ -685,25 +717,13 @@
public Collection<IdentityObject>
findIdentityObject(IdentityStoreInvocationContext ctx, IdentityObject identity,
IdentityObjectRelationshipType relationshipType, boolean parent,
IdentityObjectSearchControl[] controls) throws IdentityException
{
- // relationshipType is ignored for now
-// if (log.isLoggable(Level.FINER))
-// {
-// log.finer(toString() + ".findIdentityObject with identity: " +
identity
-// + "; relationshipType: " + relationshipType
-// + "; offset: " + offset
-// + "; limit: " + limit
-// + "; orderByName: " + orderByName
-// + "; ascending: " + ascending
-// );
-// }
-
- //TODO: handle paged results and sort
-
checkControls(controls);
PageSearchControl pageSearchControl = null;
SortByNameSearchControl sortSearchControl = null;
+ AttributeFilterSearchControl attributeFilterSearchControl = null;
+ NameFilterSearchControl nameFilterSearchControl = null;
if (controls != null)
{
@@ -717,11 +737,18 @@
{
sortSearchControl = (SortByNameSearchControl)control;
}
+ else if (control instanceof AttributeFilterSearchControl)
+ {
+ attributeFilterSearchControl = (AttributeFilterSearchControl)control;
+ }
+ else if (control instanceof NameFilterSearchControl)
+ {
+ nameFilterSearchControl = (NameFilterSearchControl)control;
+ }
+
}
}
- Set<IdentityObjectRelationship> relationships = new
HashSet<IdentityObjectRelationship>();
-
LDAPIdentityObjectImpl ldapFromIO = getSafeLDAPIO(ctx, identity);
LDAPIdentityObjectTypeConfiguration typeConfig = getTypeConfiguration(ctx,
identity.getIdentityType());
@@ -748,27 +775,139 @@
if (typeConfig.isMembershipAttributeDN())
{
- //TODO: improve
- objects.add(findIdentityObject(ctx, memberRef));
+ //TODO: use direct LDAP query instaed of other find method and add
attributesFilter
+
+ if (nameFilterSearchControl != null)
+ {
+ String name = Tools.stripDnToName(memberRef);
+ String regex =
Tools.wildcardToRegex(nameFilterSearchControl.getFilter());
+
+ if (Pattern.matches(regex, name))
+ {
+ objects.add(findIdentityObject(ctx, memberRef));
+ }
+ }
+ else
+ {
+ objects.add(findIdentityObject(ctx, memberRef));
+ }
}
else
{
- //TODO:
- throw new NotYetImplementedException();
+ //TODO: if relationships are not refered with DNs and only names its
not possible to map
+ //TODO: them to proper IdentityType and keep name uniqnes per type.
Workaround needed
+ throw new NotYetImplementedException("LDAP limitation. If
relationship targets are not refered with FQDNs " +
+ "and only names, it's not possible to map them to proper
IdentityType and keep name uniqnes per type. " +
+ "Workaround needed");
}
- break;
+ //break;
}
}
-
- //TODO: need to be sorted/paginated manually
}
// if not parent then all parent entries need to be found
else
{
- //TODO:
- //TODO: apply sort/pagination ldap control
- throw new NotYetImplementedException();
+ // Search in all other type contexts
+ for (IdentityObjectType parentType : configuration.getConfiguredTypes())
+ {
+ checkIOType(parentType);
+
+ LDAPIdentityObjectTypeConfiguration parentTypeConfiguration =
getTypeConfiguration(ctx, parentType);
+
+ List<String> allowedTypes =
Arrays.asList(parentTypeConfiguration.getAllowedMembershipTypes());
+
+ // Check if given identity type can be parent
+ if (!allowedTypes.contains(identity.getIdentityType().getName()))
+ {
+ continue;
+ }
+
+ String nameFilter = "*";
+
+ //Filter by name
+ if (nameFilterSearchControl != null)
+ {
+ nameFilter = nameFilterSearchControl.getFilter();
+ }
+
+ Control[] requestControls = null;
+
+ StringBuilder af = new StringBuilder();
+
+ // Filter by attribute values
+ if (attributeFilterSearchControl != null)
+ {
+ af.append("(&");
+
+ for (Map.Entry<String, String[]> stringEntry :
attributeFilterSearchControl.getValues().entrySet())
+ {
+ for (String value : stringEntry.getValue())
+ {
+ af.append("(")
+ .append(stringEntry.getKey())
+ .append("=")
+ .append(value)
+ .append(")");
+ }
+ }
+
+ af.append(")");
+ }
+
+ // Add filter to search only parents of the given entry
+ af.append("(")
+ .append(parentTypeConfiguration.getMembershipAttributeName())
+ .append("=");
+ if (parentTypeConfiguration.isMembershipAttributeDN())
+ {
+ af.append(ldapFromIO.getDn());
+ }
+ else
+ {
+ //TODO: this doesn't make much sense unless parent/child are same
identity types and resides in the same LDAP context
+ af.append(ldapFromIO.getName());
+ }
+ af.append(")");
+
+
+ String filter = parentTypeConfiguration.getEntrySearchFilter();
+ List<SearchResult> sr = null;
+
+ String[] entryCtxs = parentTypeConfiguration.getCtxDNs();
+
+ if (filter != null && filter.length() > 0)
+ {
+
+ Object[] filterArgs = {nameFilter};
+ sr = searchIdentityObjects(ctx,
+ entryCtxs,
+ "(&(" + filter + ")" + af.toString() +
")",
+ filterArgs,
+ new String[]{parentTypeConfiguration.getIdAttributeName()},
+ requestControls);
+ }
+ else
+ {
+ filter =
"(".concat(parentTypeConfiguration.getIdAttributeName()).concat("=").concat(nameFilter).concat(")");
+ sr = searchIdentityObjects(ctx,
+ entryCtxs,
+ "(&(" + filter + ")" + af.toString() +
")",
+ null,
+ new String[]{parentTypeConfiguration.getIdAttributeName()},
+ requestControls);
+ }
+
+ for (SearchResult res : sr)
+ {
+ LdapContext ldapCtx = (LdapContext)res.getObject();
+ String dn = ldapCtx.getNameInNamespace();
+
+ objects.add(createIdentityObjectInstance(ctx, parentType,
res.getAttributes(), dn));
+ }
+ }
+
+
}
}
@@ -787,6 +926,18 @@
throw new IdentityException("Failed to close LDAP connection", e);
}
}
+
+ if (sortSearchControl != null)
+ {
+ sortByName(objects, sortSearchControl.isAscending());
+ }
+
+ if (pageSearchControl != null)
+ {
+ objects = cutPageFromResults(objects, pageSearchControl);
+ }
+
+
return objects;
}
@@ -848,7 +999,7 @@
attrs.put(member);
- ldapContext.modifyAttributes(ldapFromIO.getDn(), DirContext.REPLACE_ATTRIBUTE,
attrs);
+ ldapContext.modifyAttributes(ldapFromIO.getDn(), DirContext.ADD_ATTRIBUTE,
attrs);
relationship = new LDAPIdentityObjectRelationshipImpl(name, ldapFromIO,
ldapToIO);
@@ -984,6 +1135,7 @@
// If relationship is not allowed return empty set
//TODO: use features description instead
+
if
(!Arrays.asList(fromTypeConfig.getAllowedMembershipTypes()).contains(ldapToIO.getIdentityType().getName()))
{
return relationships;
@@ -1065,14 +1217,142 @@
public boolean validateCredential(IdentityStoreInvocationContext ctx, IdentityObject
identityObject, IdentityObjectCredential credential) throws IdentityException
{
- //TODO: NYI
- throw new NotYetImplementedException();
+ if (credential == null)
+ {
+ throw new IllegalArgumentException();
+ }
+
+ LDAPIdentityObjectImpl ldapIO = getSafeLDAPIO(ctx, identityObject);
+
+ if
(supportedFeatures.isCredentialSupported(ldapIO.getIdentityType(),credential.getType()))
+ {
+
+ String passwordString = null;
+
+ // Handle generic impl
+
+ if (credential.getValue() != null)
+ {
+ //TODO: support for empty password should be configurable
+ passwordString = credential.getValue().toString();
+ }
+ else
+ {
+ throw new IdentityException("Null password value");
+ }
+
+ LdapContext ldapContext = getLDAPContext(ctx);
+
+ try
+ {
+
+ Hashtable env = ldapContext.getEnvironment();
+
+ env.put(Context.SECURITY_PRINCIPAL, ldapIO.getDn());
+ env.put(Context.SECURITY_CREDENTIALS, passwordString);
+
+ InitialContext initialCtx = new InitialLdapContext(env, null);
+
+ if (initialCtx != null)
+ {
+ initialCtx.close();
+ return true;
+ }
+
+ }
+ catch (NamingException e)
+ {
+ //
+ }
+ finally
+ {
+ try
+ {
+ ldapContext.close();
+ }
+ catch (NamingException e)
+ {
+ throw new IdentityException("Failed to close LDAP connection",
e);
+ }
+ }
+ return false;
+
+
+ }
+ else
+ {
+ throw new IdentityException("CredentialType not supported for a given
IdentityObjectType");
+ }
}
public void updateCredential(IdentityStoreInvocationContext ctx, IdentityObject
identityObject, IdentityObjectCredential credential) throws IdentityException
{
- //TODO: NYI
- throw new NotYetImplementedException();
+ if (credential == null)
+ {
+ throw new IllegalArgumentException();
+ }
+
+ LDAPIdentityObjectImpl ldapIO = getSafeLDAPIO(ctx, identityObject);
+
+ if
(supportedFeatures.isCredentialSupported(ldapIO.getIdentityType(),credential.getType()))
+ {
+
+ String passwordString = null;
+
+ // Handle generic impl
+
+ if (credential.getValue() != null)
+ {
+ //TODO: support for empty password should be configurable
+ passwordString = credential.getValue().toString();
+ }
+ else
+ {
+ throw new IdentityException("Null password value");
+ }
+
+ String attributeName = getTypeConfiguration(ctx,
ldapIO.getIdentityType()).getPasswordAttributeName();
+
+ if (attributeName == null)
+ {
+ throw new IdentityException("IdentityType doesn't have
passwordAttributeName option set: "
+ + ldapIO.getIdentityType().getName());
+ }
+
+ LdapContext ldapContext = getLDAPContext(ctx);
+
+ try
+ {
+ //TODO: maybe perform a schema check if this attribute is allowed for such
entry
+
+ Attributes attrs = new BasicAttributes(true);
+ Attribute attr = new BasicAttribute(attributeName);
+ attr.add(passwordString);
+ attrs.put(attr);
+
+ ldapContext.modifyAttributes(ldapIO.getDn(),
DirContext.REPLACE_ATTRIBUTE,attrs);
+ }
+ catch (NamingException e)
+ {
+ throw new IdentityException("Cannot set identity password value.",
e);
+ }
+ finally
+ {
+ try
+ {
+ ldapContext.close();
+ }
+ catch (NamingException e)
+ {
+ throw new IdentityException("Failed to close LDAP connection",
e);
+ }
+ }
+
+ }
+ else
+ {
+ throw new IdentityException("CredentialType not supported for a given
IdentityObjectType");
+ }
}
@@ -1211,7 +1491,21 @@
String[] values = attributes.get(name);
+ Map<String, AttributeMetaData> mdMap =
attributesMetaData.get(identity.getIdentityType().getName());
+ if (mdMap != null)
+ {
+ AttributeMetaData amd = mdMap.get(attributeName);
+ if (amd != null && !amd.isMultivalued() && values.length
> 1)
+ {
+ throw new IdentityException("Cannot assigned multiply values to
single valued attribute: " + attributeName);
+ }
+ if (amd != null && amd.isReadonly())
+ {
+ throw new IdentityException("Cannot update readonly attribute:
" + attributeName);
+ }
+ }
+
if (values != null)
{
for (String value : values)
@@ -1291,7 +1585,22 @@
String[] values = attributes.get(name);
+ Map<String, AttributeMetaData> mdMap =
attributesMetaData.get(identity.getIdentityType().getName());
+ if (mdMap != null)
+ {
+ AttributeMetaData amd = mdMap.get(attributeName);
+ if (amd != null && !amd.isMultivalued() && values.length
> 1)
+ {
+ throw new IdentityException("Cannot assigned multiply values to
single valued attribute: " + attributeName);
+ }
+ if (amd != null && amd.isReadonly())
+ {
+ throw new IdentityException("Cannot update readonly attribute:
" + attributeName);
+ }
+ }
+
+
if (values != null)
{
for (String value : values)
@@ -1362,8 +1671,20 @@
continue;
}
- //TODO: maybe perform a schema check if this attribute is not required
+ Map<String, AttributeMetaData> mdMap =
attributesMetaData.get(identity.getIdentityType().getName());
+ if (mdMap != null)
+ {
+ //TODO: maybe perform a schema check if this attribute is not required on
the LDAP level
+ AttributeMetaData amd = mdMap.get(name);
+ if (amd != null && amd.isRequired())
+ {
+ throw new IdentityException("Cannot remove required attribute:
" + name);
+ }
+ }
+
+
+
Attributes attrs = new BasicAttributes(true);
Attribute attr = new BasicAttribute(attributeName);
attrs.put(attr);
@@ -1420,7 +1741,7 @@
}
public List<SearchResult> searchIdentityObjects(IdentityStoreInvocationContext
ctx,
- IdentityObjectType type,
+ String[] entryCtxs,
String filter,
Object[] filterArgs,
String[] returningAttributes,
@@ -1451,8 +1772,6 @@
}
- String[] entryCtxs = getTypeConfiguration(ctx, type).getCtxDNs();
-
if (entryCtxs.length == 1)
{
if (filterArgs == null)
@@ -1579,5 +1898,36 @@
}
}
}
-
+
+ private void sortByName(List<IdentityObject> objects, final boolean ascending)
+ {
+ Collections.sort(objects, new Comparator<IdentityObject>(){
+ public int compare(IdentityObject o1, IdentityObject o2)
+ {
+ if (ascending)
+ {
+ return o1.getName().compareTo(o2.getName());
+ }
+ else
+ {
+ return o2.getName().compareTo(o1.getName());
+ }
+ }
+ });
+ }
+
+ //TODO: dummy and inefficient temporary workaround. Need to be implemented with ldap
request control
+ private List<IdentityObject> cutPageFromResults(List<IdentityObject>
objects, PageSearchControl pageControl)
+ {
+ List<IdentityObject> results = new LinkedList<IdentityObject>();
+ for (int i = pageControl.getOffset(); i < pageControl.getOffset() +
pageControl.getLimit(); i++)
+ {
+ if (i < objects.size())
+ {
+ results.add(objects.get(i));
+ }
+ }
+ return results;
+ }
+
}
Modified:
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/ldap/SimpleLDAPIdentityObjectTypeConfiguration.java
===================================================================
---
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/ldap/SimpleLDAPIdentityObjectTypeConfiguration.java 2008-12-12
22:43:45 UTC (rev 162)
+++
trunk/identity-impl/src/main/java/org/jboss/identity/impl/store/ldap/SimpleLDAPIdentityObjectTypeConfiguration.java 2008-12-15
09:53:22 UTC (rev 163)
@@ -41,6 +41,8 @@
{
private final String idAttributeName;
+ private final String passwordAttributeName;
+
private final String[] ctxDNs;
private final String entrySearchFilter;
@@ -64,6 +66,8 @@
public static final String ID_ATTRIBUTE_NAME = "idAttributeName";
+ public static final String PASSWORD_ATTRIBUTE_NAME =
"passwordAttributeName";
+
public static final String CTX_DNS = "ctxDNs";
public static final String ENTRY_SEARCH_FILTER = "entrySearchFilter";
@@ -83,6 +87,7 @@
public SimpleLDAPIdentityObjectTypeConfiguration(IdentityObjectTypeMetaData
objectTypeMD)
{
this.idAttributeName = objectTypeMD.getOptionSingleValue(ID_ATTRIBUTE_NAME);
+ this.passwordAttributeName =
objectTypeMD.getOptionSingleValue(PASSWORD_ATTRIBUTE_NAME);
this.entrySearchFilter = objectTypeMD.getOptionSingleValue(ENTRY_SEARCH_FILTER);
this.membershipAttributeName =
objectTypeMD.getOptionSingleValue(MEMBERSHIP_ATTRIBUTE_NAME);
String allowCreateEntry = objectTypeMD.getOptionSingleValue(ALLOW_CREATE_ENTRY);
@@ -196,6 +201,7 @@
}
public SimpleLDAPIdentityObjectTypeConfiguration(String idAttributeName,
+ String passwordAttributeName,
String[] ctxDNs,
String entrySearchFilter,
boolean allowCreateEntry,
@@ -207,6 +213,7 @@
Map<String, String>
attributeNames)
{
this.idAttributeName = idAttributeName;
+ this.passwordAttributeName = passwordAttributeName;
this.ctxDNs = ctxDNs;
this.entrySearchFilter = entrySearchFilter;
this.allowCreateEntry = allowCreateEntry;
@@ -270,7 +277,12 @@
return attributeNames.get(name);
}
-// public void setIdAttributeName(String idAttributeName)
+ public String getPasswordAttributeName()
+ {
+ return passwordAttributeName;
+ }
+
+ // public void setIdAttributeName(String idAttributeName)
// {
// this.idAttributeName = idAttributeName;
// }
Modified:
trunk/identity-impl/src/test/java/org/jboss/identity/impl/store/CommonIdentityStoreTest.java
===================================================================
---
trunk/identity-impl/src/test/java/org/jboss/identity/impl/store/CommonIdentityStoreTest.java 2008-12-12
22:43:45 UTC (rev 162)
+++
trunk/identity-impl/src/test/java/org/jboss/identity/impl/store/CommonIdentityStoreTest.java 2008-12-15
09:53:22 UTC (rev 163)
@@ -277,7 +277,22 @@
assertEquals(0, testContext.getStore().resolveRelationships(testContext.getCtx(),
group2, user1).size());
assertEquals(0, testContext.getStore().resolveRelationships(testContext.getCtx(),
user1, group2).size());
+ testContext.flush();
+ // test find methods with relationships
+
+ testContext.getStore().createRelationship(testContext.getCtx(), group1, user1,
RelationshipTypeEnum.JBOSS_IDENTITY_MEMBERSHIP, null, false);
+ testContext.getStore().createRelationship(testContext.getCtx(), group1, user2,
RelationshipTypeEnum.JBOSS_IDENTITY_MEMBERSHIP, null, false);
+
+ testContext.flush();
+
+ assertEquals(2, testContext.getStore().findIdentityObject(testContext.getCtx(),
group1, RelationshipTypeEnum.JBOSS_IDENTITY_MEMBERSHIP, true, null).size());
+ assertEquals(0, testContext.getStore().findIdentityObject(testContext.getCtx(),
group1, RelationshipTypeEnum.JBOSS_IDENTITY_MEMBERSHIP, false, null).size());
+ assertEquals(1, testContext.getStore().findIdentityObject(testContext.getCtx(),
user1, RelationshipTypeEnum.JBOSS_IDENTITY_MEMBERSHIP, false, null).size());
+ assertEquals(1, testContext.getStore().findIdentityObject(testContext.getCtx(),
user2, RelationshipTypeEnum.JBOSS_IDENTITY_MEMBERSHIP, false, null).size());
+ assertEquals(0, testContext.getStore().findIdentityObject(testContext.getCtx(),
group2, RelationshipTypeEnum.JBOSS_IDENTITY_MEMBERSHIP, false, null).size());
+ assertEquals(0, testContext.getStore().findIdentityObject(testContext.getCtx(),
group2, RelationshipTypeEnum.JBOSS_IDENTITY_MEMBERSHIP, true, null).size());
+
testContext.commit();
}
Modified:
trunk/identity-impl/src/test/java/org/jboss/identity/impl/store/ldap/LDAPIdentityStoreTestCase.java
===================================================================
---
trunk/identity-impl/src/test/java/org/jboss/identity/impl/store/ldap/LDAPIdentityStoreTestCase.java 2008-12-12
22:43:45 UTC (rev 162)
+++
trunk/identity-impl/src/test/java/org/jboss/identity/impl/store/ldap/LDAPIdentityStoreTestCase.java 2008-12-15
09:53:22 UTC (rev 163)
@@ -58,7 +58,8 @@
* @author <a href="mailto:boleslaw.dawidowicz at redhat.com">Boleslaw
Dawidowicz</a>
* @version : 0.1 $
*/
-public class LDAPIdentityStoreTestCase extends TestCase implements
IdentityStoreTestContext
+public class
+ LDAPIdentityStoreTestCase extends TestCase implements IdentityStoreTestContext
{
public static final String LDAP_HOST = "localhost";
@@ -507,4 +508,12 @@
commonTest.testControls();
}
+
+ public void testCredentials() throws Exception
+ {
+ populateClean();
+
+ commonTest.testPasswordCredential();
+ }
+
}
Modified: trunk/identity-impl/src/test/resources/organization-test-config.xml
===================================================================
--- trunk/identity-impl/src/test/resources/organization-test-config.xml 2008-12-12
22:43:45 UTC (rev 162)
+++ trunk/identity-impl/src/test/resources/organization-test-config.xml 2008-12-15
09:53:22 UTC (rev 163)
@@ -305,6 +305,10 @@
<value>uid</value>
</option>
<option>
+ <name>passwordAttributeName</name>
+ <value>password</value>
+ </option>
+ <option>
<name>ctxDNs</name>
<value>ou=People,o=test,dc=portal,dc=example,dc=com</value>
</option>
Modified: trunk/identity-impl/src/test/resources/store-test-config.xml
===================================================================
--- trunk/identity-impl/src/test/resources/store-test-config.xml 2008-12-12 22:43:45 UTC
(rev 162)
+++ trunk/identity-impl/src/test/resources/store-test-config.xml 2008-12-15 09:53:22 UTC
(rev 163)
@@ -176,21 +176,21 @@
<name>phone</name>
<mapping>telephoneNumber</mapping>
<isRequired/>
- <isMultivalued/>
+ <isMultivalued>true</isMultivalued>
<isReadOnly/>
</attribute>
<attribute>
<name>description</name>
<mapping>description</mapping>
<isRequired/>
- <isMultivalued/>
+ <isMultivalued>true</isMultivalued>
<isReadOnly/>
</attribute>
<attribute>
<name>carLicense</name>
<mapping>carLicense</mapping>
<isRequired/>
- <isMultivalued/>
+ <isMultivalued>true</isMultivalued>
<isReadOnly/>
</attribute>
</attributes>
@@ -200,6 +200,10 @@
<value>uid</value>
</option>
<option>
+ <name>passwordAttributeName</name>
+ <value>userPassword</value>
+ </option>
+ <option>
<name>ctxDNs</name>
<value>ou=People,o=test,dc=portal,dc=example,dc=com</value>
</option>