opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapper.java
@@ -16,7 +16,6 @@ package org.forgerock.opendj.rest2ldap; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -25,7 +24,6 @@ import org.forgerock.json.fluent.JsonValue; import org.forgerock.opendj.ldap.Attribute; import org.forgerock.opendj.ldap.Entry; import org.forgerock.opendj.ldap.ResultHandler; import org.forgerock.resource.provider.Context; /** @@ -34,30 +32,33 @@ public interface AttributeMapper { /** * Returns an unmodifiable collection containing the names of the LDAP * attributes required by this attribute mapper. The returned collection * should only contain the names of attributes found in the LDAP entry * directly associated with the resource. * * @return An unmodifiable collection containing the names of the LDAP * attributes required by this attribute mapper. */ Collection<String> getAllLDAPAttributes(); /** * Adds the names of the LDAP attributes required by this attribute mapper * which are associated with the provided resource attribute. * Adds the names of the all the LDAP attributes required by this attribute * mapper to the provided set. * <p> * Implementations should only add the names of attributes found in the LDAP * entry directly associated with the resource. * * @param resourceAttribute * The name of the resource attribute requested by the client. * @param ldapAttributes * The set into which the required LDAP attribute names should be * put. */ void getLDAPAttributesFor(JsonPointer resourceAttribute, Set<String> ldapAttributes); void getLDAPAttributes(Set<String> ldapAttributes); /** * Adds the names of the LDAP attributes required by this attribute mapper * which are associated with the provided resource attribute to the provided * set. * <p> * Implementations should only add the names of attributes found in the LDAP * entry directly associated with the resource. * * @param ldapAttributes * The set into which the required LDAP attribute names should be * put. * @param resourceAttribute * The name of the resource attribute requested by the client. */ void getLDAPAttributes(Set<String> ldapAttributes, JsonPointer resourceAttribute); /** * Transforms attributes contained in the provided LDAP entry to JSON @@ -72,7 +73,7 @@ * @param e * @param h */ void toJson(Context c, Entry e, ResultHandler<Map<String, Object>> h); void toJson(Context c, Entry e, AttributeMapperCompletionHandler<Map<String, Object>> h); /** * Transforms JSON content in the provided JSON value to LDAP attributes, @@ -86,7 +87,7 @@ * @param v * @param h */ void toLDAP(Context c, JsonValue v, ResultHandler<List<Attribute>> h); void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h); // TODO: methods for obtaining schema information (e.g. name, description, // type information). opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AttributeMapperCompletionHandler.java
New file @@ -0,0 +1,29 @@ /* * The contents of this file are subject to the terms of the Common Development and * Distribution License (the License). You may not use this file except in compliance with the * License. * * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the * specific language governing permission and limitations under the License. * * When distributing Covered Software, include this CDDL Header Notice in each file and include * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL * Header, with the fields enclosed by brackets [] replaced by your own identifying * information: "Portions Copyrighted [year] [name of copyright owner]". * * Copyright 2012 ForgeRock AS. All rights reserved. */ package org.forgerock.opendj.rest2ldap; import org.forgerock.resource.exception.ResourceException; /** * */ public interface AttributeMapperCompletionHandler<T> { void onSuccess(T result); void onFailure(ResourceException e); } opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/CompositeAttributeMapper.java
@@ -29,8 +29,7 @@ import org.forgerock.json.fluent.JsonValue; import org.forgerock.opendj.ldap.Attribute; import org.forgerock.opendj.ldap.Entry; import org.forgerock.opendj.ldap.ErrorResultException; import org.forgerock.opendj.ldap.ResultHandler; import org.forgerock.resource.exception.ResourceException; import org.forgerock.resource.provider.Context; /** @@ -50,7 +49,7 @@ this.attributeMappers = new ArrayList<AttributeMapper>(attributeMappers); Set<String> tmp = new LinkedHashSet<String>(attributeMappers.size()); for (final AttributeMapper mapper : attributeMappers) { tmp.addAll(mapper.getAllLDAPAttributes()); mapper.getLDAPAttributes(tmp); } allLDAPAttributes = Collections.unmodifiableSet(tmp); } @@ -58,37 +57,38 @@ /** * {@inheritDoc} */ public Set<String> getAllLDAPAttributes() { return allLDAPAttributes; public void getLDAPAttributes(Set<String> ldapAttributes) { ldapAttributes.addAll(allLDAPAttributes); } /** * {@inheritDoc} */ public void getLDAPAttributesFor(JsonPointer resourceAttribute, Set<String> ldapAttributes) { public void getLDAPAttributes(Set<String> ldapAttributes, JsonPointer resourceAttribute) { for (AttributeMapper attribute : attributeMappers) { attribute.getLDAPAttributesFor(resourceAttribute, ldapAttributes); attribute.getLDAPAttributes(ldapAttributes, resourceAttribute); } } /** * {@inheritDoc} */ public void toJson(Context c, Entry e, final ResultHandler<Map<String, Object>> h) { ResultHandler<Map<String, Object>> resultAccumulater = new ResultHandler<Map<String, Object>>() { public void toJson(Context c, Entry e, final AttributeMapperCompletionHandler<Map<String, Object>> h) { AttributeMapperCompletionHandler<Map<String, Object>> resultAccumulater = new AttributeMapperCompletionHandler<Map<String, Object>>() { private final AtomicInteger latch = new AtomicInteger(attributeMappers.size()); private final List<Map<String, Object>> results = new ArrayList<Map<String, Object>>(latch.get()); public void handleErrorResult(ErrorResultException error) { public void onFailure(ResourceException e) { // Ensure that handler is only invoked once. if (latch.getAndSet(0) > 0) { h.handleErrorResult(error); h.onFailure(e); } } public void handleResult(Map<String, Object> result) { public void onSuccess(Map<String, Object> result) { synchronized (this) { results.add(result); } @@ -106,7 +106,7 @@ mergeJsonValues(results, mergeResult); break; } h.handleResult(mergeResult); h.onSuccess(mergeResult); } } }; @@ -119,7 +119,7 @@ /** * {@inheritDoc} */ public void toLDAP(Context c, JsonValue v, ResultHandler<List<Attribute>> h) { public void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h) { // TODO Auto-generated method stub } opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Example.java
@@ -16,10 +16,6 @@ package org.forgerock.opendj.rest2ldap; import java.util.HashMap; import java.util.Map; import org.forgerock.json.fluent.JsonValue; import org.forgerock.json.resource.restlet.JsonResourceRestlet; import org.forgerock.opendj.ldap.ConnectionFactory; import org.forgerock.opendj.ldap.Connections; @@ -30,7 +26,6 @@ import org.forgerock.resource.framework.impl.ResourceInvoker; import org.restlet.Application; import org.restlet.Component; import org.restlet.Request; import org.restlet.Restlet; import org.restlet.data.Protocol; import org.restlet.routing.Router; @@ -41,115 +36,53 @@ */ public class Example { private static final String PATH_PROPERTY = "rest2ldap.restlet.path"; private Application application = new Application(); private final Router router = new Router(); private HashMap<JsonResourceProvider, Restlet> restlets = new HashMap<JsonResourceProvider, Restlet>(); protected synchronized void bindRestlet(Restlet restlet, Map<String, Object> properties) { Object path = properties.get(PATH_PROPERTY); if (path != null && path instanceof String) { // service is specified as // internally routable attach((String) path, restlet); } } protected synchronized void unbindRestlet(Restlet restlet, Map<String, Object> properties) { Object path = properties.get(PATH_PROPERTY); if (path != null && path instanceof String) { // service is specified as // internally routable detach(restlet); } } /** * Attaches a target Restlet to the Restlet router based on a given URI * prefix. * * @param path * the path to attach it to. * @param restlet * the restlet to route to if path matches. * @throws IllegalArgumentException * if path does not begin with a '/' character. */ public void attach(String path, Restlet restlet) { private void bindJsonResource(JsonResourceProvider resource, String path) { Restlet restlet = new JsonResourceRestlet(resource); restlet.setContext(application.getContext()); router.attach(path, restlet, Template.MODE_EQUALS); router.attach(path + (path.equals("/") ? "" : "/"), restlet, Template.MODE_STARTS_WITH); } /** * Remove a restlet from restlet router * * @param restlet * the restlet to remove */ public void detach(Restlet restlet) { router.detach(restlet); // all routes to restlet are removed } protected synchronized void bindJsonResource(JsonResourceProvider resource, Map<String, Object> properties) { Restlet restlet = new CustomRestlet(resource); restlets.put(resource, restlet); bindRestlet(restlet, properties); } protected synchronized void unbindJsonResource(JsonResourceProvider resource, Map<String, Object> properties) { Restlet restlet = restlets.get(resource); if (restlet != null) { unbindRestlet(restlet, properties); restlets.remove(resource); } } private class CustomRestlet extends JsonResourceRestlet { public CustomRestlet(JsonResourceProvider resource) { super(resource); } @Override public JsonValue newContext(Request request) { JsonValue result = super.newContext(request); JsonValue security = result.get("security"); security.put("openidm-roles", request.getAttributes().get("openidm.roles")); return result; } } public void start() throws Exception { Component component = new Component(); // Add http listener component.getServers().add(Protocol.HTTP, 8080); application.getTunnelService().setQueryTunnel(false); // query string // purism application.setInboundRoot(router); // Attach the json resource at the root path Map<String, Object> props = new HashMap<String, Object>(); props.put(PATH_PROPERTY, ""); AttributeMapper mapper = new IdentityAttributeMapper().excludeAttribute("entryUUID", "etag"); // All LDAP resources will use this connection factory. ConnectionFactory factory = Connections.newAuthenticatedConnectionFactory(new LDAPConnectionFactory( "localhost", 1389), Requests.newSimpleBindRequest("cn=directory manager", "password".toCharArray())); EntryContainer container = // Create two entry containers whose members reference each other. EntryContainer userContainer = new EntryContainer(DN.valueOf("ou=people,dc=example,dc=com"), factory); LDAPResource resource = new LDAPResource(container, mapper); ResourceInvoker invoker = new ResourceInvoker(); invoker.resource = resource; bindJsonResource(invoker, props); EntryContainer groupContainer = new EntryContainer(DN.valueOf("ou=groups,dc=example,dc=com"), factory); // Attach the sample application. component.getDefaultHost().attach("/example", application); // Create user resource. AttributeMapper userMapper = new SimpleAttributeMapper().includeAttribute("uid", "cn", "sn", "mail", "isMemberOf", "modifyTimestamp"); LDAPResource userResource = new LDAPResource(userContainer, userMapper); ResourceInvoker userResourceInvoker = new ResourceInvoker(); userResourceInvoker.resource = userResource; // FIXME: Yuk! bindJsonResource(userResourceInvoker, "/users"); // Start the component. // Create group resource. AttributeMapper groupMapper = new SimpleAttributeMapper().includeAttribute("cn", "ou", "description", "uniquemember"); LDAPResource groupResource = new LDAPResource(groupContainer, groupMapper); ResourceInvoker groupResourceInvoker = new ResourceInvoker(); groupResourceInvoker.resource = groupResource; // FIXME: Yuk! bindJsonResource(groupResourceInvoker, "/groups"); // Configure and start the application. application.getTunnelService().setQueryTunnel(false); application.setInboundRoot(router); Component component = new Component(); component.getServers().add(Protocol.HTTP, 8080); component.getDefaultHost().attach("", application); component.start(); } opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPResource.java
@@ -160,14 +160,13 @@ public void handleResult(final SearchResultEntry entry) { final String revision = entryContainer.getEtagFromEntry(entry); final ResultHandler<Map<String, Object>> mapHandler = new ResultHandler<Map<String, Object>>() { public void handleErrorResult( final ErrorResultException error) { out.setFailure(adaptErrorResult(error)); final AttributeMapperCompletionHandler<Map<String, Object>> mapHandler = new AttributeMapperCompletionHandler<Map<String, Object>>() { public void onFailure(final ResourceException e) { out.setFailure(e); } public void handleResult(final Map<String, Object> result) { public void onSuccess(final Map<String, Object> result) { out.setResult(id, revision, new JsonValue(result)); } }; @@ -227,18 +226,19 @@ * attributes. */ private Collection<String> getRequestedLDAPAttributes(final Set<JsonPointer> requestedAttributes) { final Set<String> requestedLDAPAttributes; if (requestedAttributes.isEmpty()) { // Full read. return attributeMapper.getAllLDAPAttributes(); requestedLDAPAttributes = new LinkedHashSet<String>(); attributeMapper.getLDAPAttributes(requestedLDAPAttributes); } else { // Partial read. final Set<String> requestedLDAPAttributes = new LinkedHashSet<String>(requestedAttributes.size()); requestedLDAPAttributes = new LinkedHashSet<String>(requestedAttributes.size()); for (final JsonPointer requestedAttribute : requestedAttributes) { attributeMapper.getLDAPAttributesFor(requestedAttribute, requestedLDAPAttributes); attributeMapper.getLDAPAttributes(requestedLDAPAttributes, requestedAttribute); } } return requestedLDAPAttributes; } } } opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SimpleAttributeMapper.java
File was renamed from opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/IdentityAttributeMapper.java @@ -19,8 +19,6 @@ import static org.forgerock.opendj.rest2ldap.Utils.getAttributeName; import static org.forgerock.opendj.rest2ldap.Utils.toLowerCase; import java.util.Collection; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -30,46 +28,45 @@ import org.forgerock.json.fluent.JsonValue; import org.forgerock.opendj.ldap.Attribute; import org.forgerock.opendj.ldap.Entry; import org.forgerock.opendj.ldap.ResultHandler; import org.forgerock.resource.provider.Context; /** * */ public final class IdentityAttributeMapper implements AttributeMapper { public final class SimpleAttributeMapper implements AttributeMapper { // All user attributes by default. private final Map<String, String> includedAttributes = new LinkedHashMap<String, String>(); private final Map<String, String> excludedAttributes = new LinkedHashMap<String, String>(); public IdentityAttributeMapper() { public SimpleAttributeMapper() { // No implementation required. } public IdentityAttributeMapper includeAttribute(String... attributes) { public SimpleAttributeMapper includeAttribute(String... attributes) { for (String attribute : attributes) { includedAttributes.put(toLowerCase(attribute), attribute); } return this; } public IdentityAttributeMapper excludeAttribute(String... attributes) { public SimpleAttributeMapper excludeAttribute(String... attributes) { for (String attribute : attributes) { excludedAttributes.put(toLowerCase(attribute), attribute); } return this; } public Collection<String> getAllLDAPAttributes() { public void getLDAPAttributes(Set<String> ldapAttributes) { if (!includedAttributes.isEmpty()) { return includedAttributes.values(); ldapAttributes.addAll(includedAttributes.values()); } else { // All user attributes. return Collections.singleton("*"); ldapAttributes.add("*"); } } public void getLDAPAttributesFor(JsonPointer resourceAttribute, Set<String> ldapAttributes) { public void getLDAPAttributes(Set<String> ldapAttributes, JsonPointer resourceAttribute) { String name = resourceAttribute.leaf(); if (name != null) { if (isIncludedAttribute(name)) { @@ -80,7 +77,7 @@ } } public void toJson(Context c, Entry e, ResultHandler<Map<String, Object>> h) { public void toJson(Context c, Entry e, AttributeMapperCompletionHandler<Map<String, Object>> h) { Map<String, Object> result = new LinkedHashMap<String, Object>(e.getAttributeCount()); for (Attribute a : e.getAllAttributes()) { String name = getAttributeName(a); @@ -88,7 +85,7 @@ result.put(name, Utils.attributeToJson(a)); } } h.handleResult(result); h.onSuccess(result); } private boolean isIncludedAttribute(String name) { @@ -107,7 +104,7 @@ return false; } public void toLDAP(Context c, JsonValue v, ResultHandler<List<Attribute>> h) { public void toLDAP(Context c, JsonValue v, AttributeMapperCompletionHandler<List<Attribute>> h) { // TODO: } }