/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2013-2015 ForgeRock AS. */ package org.forgerock.opendj.adapter.server3x; import java.net.InetAddress; import java.net.UnknownHostException; import org.forgerock.opendj.ldap.AbstractSynchronousConnection; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.Connection; import org.forgerock.opendj.ldap.ConnectionEventListener; import org.forgerock.opendj.ldap.ConnectionFactory; import org.forgerock.opendj.ldap.DN; import org.forgerock.opendj.ldap.DecodeException; import org.forgerock.opendj.ldap.DecodeOptions; import org.forgerock.opendj.ldap.IntermediateResponseHandler; import org.forgerock.opendj.ldap.LdapException; import org.forgerock.opendj.ldap.ResultCode; import org.forgerock.opendj.ldap.SearchResultHandler; import org.forgerock.opendj.ldap.controls.Control; import org.forgerock.opendj.ldap.requests.AddRequest; import org.forgerock.opendj.ldap.requests.BindClient; import org.forgerock.opendj.ldap.requests.BindRequest; import org.forgerock.opendj.ldap.requests.CompareRequest; import org.forgerock.opendj.ldap.requests.DeleteRequest; import org.forgerock.opendj.ldap.requests.ExtendedRequest; import org.forgerock.opendj.ldap.requests.GenericBindRequest; import org.forgerock.opendj.ldap.requests.ModifyDNRequest; import org.forgerock.opendj.ldap.requests.ModifyRequest; import org.forgerock.opendj.ldap.requests.SASLBindRequest; import org.forgerock.opendj.ldap.requests.SearchRequest; import org.forgerock.opendj.ldap.requests.SimpleBindRequest; import org.forgerock.opendj.ldap.requests.UnbindRequest; import org.forgerock.opendj.ldap.responses.BindResult; import org.forgerock.opendj.ldap.responses.CompareResult; import org.forgerock.opendj.ldap.responses.ExtendedResult; import org.forgerock.opendj.ldap.responses.GenericExtendedResult; import org.forgerock.opendj.ldap.responses.Responses; import org.forgerock.opendj.ldap.responses.Result; import org.forgerock.util.promise.Promise; import org.opends.server.core.AddOperation; import org.opends.server.core.BindOperation; import org.opends.server.core.CompareOperation; import org.opends.server.core.DeleteOperation; import org.opends.server.core.ExtendedOperation; import org.opends.server.core.ModifyDNOperation; import org.opends.server.core.ModifyOperation; import org.opends.server.protocols.internal.InternalClientConnection; import org.opends.server.protocols.internal.InternalSearchListener; import org.opends.server.protocols.internal.InternalSearchOperation; import org.opends.server.protocols.internal.Requests; import org.opends.server.types.AuthenticationInfo; import org.opends.server.types.DirectoryException; import org.opends.server.types.SearchFilter; import org.opends.server.types.SearchResultEntry; import org.opends.server.types.SearchResultReference; import static org.forgerock.opendj.adapter.server3x.Converters.*; import static org.forgerock.opendj.ldap.ByteString.*; import static org.forgerock.opendj.ldap.LdapException.*; import static org.forgerock.util.promise.Promises.*; /** * This class provides a connection factory and an adapter for the OpenDJ 2.x * server. */ public final class Adapters { /** * Constructor. */ private Adapters() { // No implementation required. } /** * Returns a new root connection factory. * * @return A new root connection factory. */ public static ConnectionFactory newRootConnectionFactory() { InternalClientConnection icc = InternalClientConnection.getRootConnection(); return newConnectionFactory(icc); } /** * Returns a new anonymous connection factory. * * @return A new anonymous connection factory. */ public static ConnectionFactory newAnonymousConnectionFactory() { InternalClientConnection icc = new InternalClientConnection(new AuthenticationInfo()); return newConnectionFactory(icc); } /** * Returns a new connection factory for a specified user. * * @param userDN * The specified user's DN. * @return a new connection factory. */ public static ConnectionFactory newConnectionFactoryForUser(final DN userDN) { InternalClientConnection icc = null; try { icc = new InternalClientConnection(to(userDN)); } catch (DirectoryException e) { throw new IllegalStateException(e.getMessage(), e); } return newConnectionFactory(icc); } /** * Returns a new connection factory. * * @param icc * The internal client connection from server side. * @return A new SDK connection factory. */ public static ConnectionFactory newConnectionFactory(final InternalClientConnection icc) { return new ConnectionFactory() { @Override public void close() { // Nothing to do. } @Override public Promise<Connection, LdapException> getConnectionAsync() { // TODO change the path... return newResultPromise(newConnection(icc)); } @Override public Connection getConnection() throws LdapException { return newConnection(icc); } }; } /** * Returns a new root connection. * * @return A new root connection. */ public static Connection newRootConnection() { return newConnection(InternalClientConnection.getRootConnection()); } /** * Returns a new connection for an anonymous user. * * @return A new connection. */ public static Connection newAnonymousConnection() { return newConnection(new InternalClientConnection(new AuthenticationInfo())); } /** * Returns a new connection for a specified user. * * @param dn * The DN of the user. * @return A new connection for a specified user. * @throws LdapException * If no such object. */ public static Connection newConnectionForUser(final DN dn) throws LdapException { try { return newConnection(new InternalClientConnection(to(dn))); } catch (DirectoryException e) { throw newLdapException(Responses.newResult(ResultCode.NO_SUCH_OBJECT)); } } private static Connection newConnection(final InternalClientConnection icc) { return new AbstractSynchronousConnection() { @Override public Result search(final SearchRequest request, final SearchResultHandler handler) throws LdapException { InternalSearchListener internalSearchListener = new InternalSearchListener() { @Override public void handleInternalSearchReference( InternalSearchOperation searchOperation, SearchResultReference searchReference) throws DirectoryException { handler.handleReference(from(searchReference)); } @Override public void handleInternalSearchEntry(InternalSearchOperation searchOperation, SearchResultEntry searchEntry) throws DirectoryException { handler.handleEntry(from(searchEntry)); } }; final SearchFilter filter = toSearchFilter(request.getFilter()); final org.opends.server.protocols.internal.SearchRequest sr = Requests.newSearchRequest(to(request.getName()), request.getScope(), filter) .setDereferenceAliasesPolicy(request.getDereferenceAliasesPolicy()) .setSizeLimit(request.getSizeLimit()) .setTimeLimit(request.getTimeLimit()) .setTypesOnly(request.isTypesOnly()) .addAttribute(request.getAttributes()) .addControl(to(request.getControls())); return getResponseResult(icc.processSearch(sr, internalSearchListener)); } @Override public void removeConnectionEventListener(ConnectionEventListener listener) { // Internal client connection don't have any connection events. } @Override public Result modifyDN(final ModifyDNRequest request) throws LdapException { final ModifyDNOperation modifyDNOperation = icc.processModifyDN(valueOfObject(request.getName()), valueOfObject(request.getNewRDN()), request.isDeleteOldRDN(), request.getNewSuperior() != null ? valueOfObject(request.getNewSuperior()) : null, to(request.getControls())); return getResponseResult(modifyDNOperation); } @Override public Result modify(final ModifyRequest request) throws LdapException { final ModifyOperation modifyOperation = icc.processModify(valueOfObject(request.getName()), toRawModifications(request .getModifications()), to(request.getControls())); return getResponseResult(modifyOperation); } @Override public boolean isValid() { // Always true. return true; } @Override public boolean isClosed() { return false; } @Override public <R extends ExtendedResult> R extendedRequest(final ExtendedRequest<R> request, final IntermediateResponseHandler handler) throws LdapException { final ExtendedOperation extendedOperation = icc.processExtendedOperation(request.getOID(), request.getValue(), to(request.getControls())); final Result result = getResponseResult(extendedOperation); final GenericExtendedResult genericExtendedResult = Responses.newGenericExtendedResult(result.getResultCode()) .setDiagnosticMessage(result.getDiagnosticMessage()).setMatchedDN( result.getMatchedDN()).setValue( extendedOperation.getResponseValue().toByteString()); try { R extendedResult = request.getResultDecoder().decodeExtendedResult(genericExtendedResult, new DecodeOptions()); for (final Control control : result.getControls()) { extendedResult.addControl(control); } return extendedResult; } catch (DecodeException e) { org.opends.server.types.DN matchedDN = extendedOperation.getMatchedDN(); return request.getResultDecoder().newExtendedErrorResult( extendedOperation.getResultCode(), matchedDN != null ? matchedDN.toString() : null, extendedOperation.getErrorMessage().toString()); } } @Override public Result delete(final DeleteRequest request) throws LdapException { final DeleteOperation deleteOperation = icc.processDelete(valueOfObject(request.getName()), to(request.getControls())); return getResponseResult(deleteOperation); } @Override public CompareResult compare(final CompareRequest request) throws LdapException { final CompareOperation compareOperation = icc.processCompare(valueOfObject(request.getName()), request.getAttributeDescription().toString(), request.getAssertionValue(), to(request.getControls())); CompareResult result = Responses.newCompareResult(compareOperation.getResultCode()); return getResponseResult(compareOperation, result); } @Override public void close(final UnbindRequest request, final String reason) { // no implementation in open-ds. } @Override public BindResult bind(final BindRequest request) throws LdapException { BindOperation bindOperation = null; if (request instanceof SimpleBindRequest) { bindOperation = icc.processSimpleBind(valueOfUtf8(request.getName()), ByteString.wrap(((SimpleBindRequest) request).getPassword()), to(request.getControls())); } else if (request instanceof SASLBindRequest) { String serverName = null; try { serverName = InetAddress.getByName(null).getCanonicalHostName(); } catch (UnknownHostException e) { // nothing to do. } BindClient bindClient = request.createBindClient(serverName); do { final GenericBindRequest genericBindRequest = bindClient.nextBindRequest(); bindOperation = icc.processSASLBind( valueOfUtf8(request.getName()), ((SASLBindRequest) request).getSASLMechanism(), getCredentials(genericBindRequest.getAuthenticationValue()), to(request.getControls())); } while (bindOperation.getResultCode() == ResultCode.SASL_BIND_IN_PROGRESS); bindClient.dispose(); } else { // not supported throw newLdapException(Responses.newResult(ResultCode.AUTH_METHOD_NOT_SUPPORTED)); } BindResult result = Responses.newBindResult(bindOperation.getResultCode()); result.setServerSASLCredentials(bindOperation.getSASLCredentials()); if (result.isSuccess()) { return result; } else { throw newLdapException(result); } } @Override public void addConnectionEventListener(ConnectionEventListener listener) { // Internal client connection don't have any connection events. } @Override public Result add(final AddRequest request) throws LdapException { final AddOperation addOperation = icc.processAdd(valueOfObject(request.getName()), to(request .getAllAttributes()), to(request.getControls())); return getResponseResult(addOperation); } @Override public String toString() { return icc.toString(); } }; } }