/*
|
* 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 Copyright [year] [name of copyright owner]".
|
*
|
* Copyright 2013-2016 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.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 {
|
return getResponseResult(icc.processModify(request));
|
}
|
|
@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();
|
}
|
};
|
}
|
}
|