001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2013-2016 ForgeRock AS. 015 */ 016package org.forgerock.opendj.adapter.server3x; 017 018import java.net.InetAddress; 019import java.net.UnknownHostException; 020 021import org.forgerock.opendj.ldap.AbstractSynchronousConnection; 022import org.forgerock.opendj.ldap.ByteString; 023import org.forgerock.opendj.ldap.Connection; 024import org.forgerock.opendj.ldap.ConnectionEventListener; 025import org.forgerock.opendj.ldap.ConnectionFactory; 026import org.forgerock.opendj.ldap.DN; 027import org.forgerock.opendj.ldap.DecodeException; 028import org.forgerock.opendj.ldap.DecodeOptions; 029import org.forgerock.opendj.ldap.IntermediateResponseHandler; 030import org.forgerock.opendj.ldap.LdapException; 031import org.forgerock.opendj.ldap.ResultCode; 032import org.forgerock.opendj.ldap.SearchResultHandler; 033import org.forgerock.opendj.ldap.controls.Control; 034import org.forgerock.opendj.ldap.requests.AddRequest; 035import org.forgerock.opendj.ldap.requests.BindClient; 036import org.forgerock.opendj.ldap.requests.BindRequest; 037import org.forgerock.opendj.ldap.requests.CompareRequest; 038import org.forgerock.opendj.ldap.requests.DeleteRequest; 039import org.forgerock.opendj.ldap.requests.ExtendedRequest; 040import org.forgerock.opendj.ldap.requests.GenericBindRequest; 041import org.forgerock.opendj.ldap.requests.ModifyDNRequest; 042import org.forgerock.opendj.ldap.requests.ModifyRequest; 043import org.forgerock.opendj.ldap.requests.SASLBindRequest; 044import org.forgerock.opendj.ldap.requests.SearchRequest; 045import org.forgerock.opendj.ldap.requests.SimpleBindRequest; 046import org.forgerock.opendj.ldap.requests.UnbindRequest; 047import org.forgerock.opendj.ldap.responses.BindResult; 048import org.forgerock.opendj.ldap.responses.CompareResult; 049import org.forgerock.opendj.ldap.responses.ExtendedResult; 050import org.forgerock.opendj.ldap.responses.GenericExtendedResult; 051import org.forgerock.opendj.ldap.responses.Responses; 052import org.forgerock.opendj.ldap.responses.Result; 053import org.forgerock.util.promise.Promise; 054import org.opends.server.core.AddOperation; 055import org.opends.server.core.BindOperation; 056import org.opends.server.core.CompareOperation; 057import org.opends.server.core.DeleteOperation; 058import org.opends.server.core.ExtendedOperation; 059import org.opends.server.protocols.internal.InternalClientConnection; 060import org.opends.server.protocols.internal.InternalSearchListener; 061import org.opends.server.protocols.internal.InternalSearchOperation; 062import org.opends.server.protocols.internal.Requests; 063import org.opends.server.types.DirectoryException; 064import org.opends.server.types.SearchFilter; 065import org.opends.server.types.SearchResultEntry; 066import org.opends.server.types.SearchResultReference; 067 068import static org.forgerock.opendj.adapter.server3x.Converters.*; 069import static org.forgerock.opendj.ldap.ByteString.*; 070import static org.forgerock.opendj.ldap.LdapException.*; 071import static org.forgerock.util.promise.Promises.*; 072 073/** This class provides a connection factory and an adapter for the OpenDJ 2.x server. */ 074public final class Adapters { 075 076 /** Constructor. */ 077 private Adapters() { 078 // No implementation required. 079 } 080 081 /** 082 * Returns a new root connection factory. 083 * 084 * @return A new root connection factory. 085 */ 086 public static ConnectionFactory newRootConnectionFactory() { 087 InternalClientConnection icc = InternalClientConnection.getRootConnection(); 088 return newConnectionFactory(icc); 089 } 090 091 /** 092 * Returns a new connection factory. 093 * 094 * @param icc 095 * The internal client connection from server side. 096 * @return A new SDK connection factory. 097 */ 098 public static ConnectionFactory newConnectionFactory(final InternalClientConnection icc) { 099 return new ConnectionFactory() { 100 @Override 101 public Promise<Connection, LdapException> getConnectionAsync() { 102 try 103 { 104 return newResultPromise(getConnection()); 105 } 106 catch (LdapException e) 107 { 108 return newExceptionPromise(e); 109 } 110 } 111 112 @Override 113 public Connection getConnection() throws LdapException { 114 return newConnection(icc); 115 } 116 117 @Override 118 public void close() { 119 // Nothing to do. 120 } 121 }; 122 } 123 124 /** 125 * Returns a new connection. 126 * 127 * @param icc 128 * The internal client connection from server side. 129 * @return A new SDK connection. 130 */ 131 public static Connection newConnection(final InternalClientConnection icc) { 132 return new AbstractSynchronousConnection() { 133 134 @Override 135 public Result search(final SearchRequest request, final SearchResultHandler handler) 136 throws LdapException { 137 InternalSearchListener internalSearchListener = new InternalSearchListener() { 138 139 @Override 140 public void handleInternalSearchReference( 141 InternalSearchOperation searchOperation, 142 SearchResultReference searchReference) throws DirectoryException { 143 handler.handleReference(from(searchReference)); 144 } 145 146 @Override 147 public void handleInternalSearchEntry(InternalSearchOperation searchOperation, 148 SearchResultEntry searchEntry) throws DirectoryException { 149 handler.handleEntry(from(searchEntry)); 150 } 151 }; 152 153 final SearchFilter filter = toSearchFilter(request.getFilter()); 154 final org.opends.server.protocols.internal.SearchRequest sr = 155 Requests.newSearchRequest(request.getName(), request.getScope(), filter) 156 .setDereferenceAliasesPolicy(request.getDereferenceAliasesPolicy()) 157 .setSizeLimit(request.getSizeLimit()) 158 .setTimeLimit(request.getTimeLimit()) 159 .setTypesOnly(request.isTypesOnly()) 160 .addAttribute(request.getAttributes()) 161 .addControl(to(request.getControls())); 162 return getResponseResult(icc.processSearch(sr, internalSearchListener)); 163 } 164 165 @Override 166 public void removeConnectionEventListener(ConnectionEventListener listener) { 167 // Internal client connection don't have any connection events. 168 } 169 170 @Override 171 public Result modifyDN(final ModifyDNRequest request) throws LdapException { 172 return getResponseResult(icc.processModifyDN(request)); 173 } 174 175 @Override 176 public Result modify(final ModifyRequest request) throws LdapException { 177 return getResponseResult(icc.processModify(request)); 178 } 179 180 @Override 181 public boolean isValid() { 182 // Always true. 183 return true; 184 } 185 186 @Override 187 public boolean isClosed() { 188 return false; 189 } 190 191 @Override 192 public <R extends ExtendedResult> R extendedRequest(final ExtendedRequest<R> request, 193 final IntermediateResponseHandler handler) throws LdapException { 194 195 final ExtendedOperation extendedOperation = 196 icc.processExtendedOperation(request.getOID(), request.getValue(), 197 to(request.getControls())); 198 199 final Result result = getResponseResult(extendedOperation); 200 final GenericExtendedResult genericExtendedResult = 201 Responses.newGenericExtendedResult(result.getResultCode()) 202 .setDiagnosticMessage(result.getDiagnosticMessage()) 203 .setMatchedDN(result.getMatchedDN()) 204 .setValue(extendedOperation.getResponseValue()); 205 try { 206 R extendedResult = 207 request.getResultDecoder().decodeExtendedResult(genericExtendedResult, 208 new DecodeOptions()); 209 for (final Control control : result.getControls()) { 210 extendedResult.addControl(control); 211 } 212 return extendedResult; 213 214 } catch (DecodeException e) { 215 DN matchedDN = extendedOperation.getMatchedDN(); 216 return request.getResultDecoder().newExtendedErrorResult( 217 extendedOperation.getResultCode(), 218 matchedDN != null ? matchedDN.toString() : null, 219 extendedOperation.getErrorMessage().toString()); 220 } 221 } 222 223 @Override 224 public Result delete(final DeleteRequest request) throws LdapException { 225 final DeleteOperation deleteOperation = 226 icc.processDelete(valueOfObject(request.getName()), to(request.getControls())); 227 return getResponseResult(deleteOperation); 228 } 229 230 @Override 231 public CompareResult compare(final CompareRequest request) throws LdapException { 232 final CompareOperation compareOperation = 233 icc.processCompare(valueOfObject(request.getName()), 234 request.getAttributeDescription().toString(), 235 request.getAssertionValue(), to(request.getControls())); 236 237 CompareResult result = Responses.newCompareResult(compareOperation.getResultCode()); 238 return getResponseResult(compareOperation, result); 239 } 240 241 @Override 242 public void close(final UnbindRequest request, final String reason) { 243 // no implementation in open-ds. 244 } 245 246 @Override 247 public BindResult bind(final BindRequest request) throws LdapException { 248 BindOperation bindOperation = null; 249 if (request instanceof SimpleBindRequest) { 250 bindOperation = 251 icc.processSimpleBind(valueOfUtf8(request.getName()), 252 ByteString.wrap(((SimpleBindRequest) request).getPassword()), 253 to(request.getControls())); 254 } else if (request instanceof SASLBindRequest) { 255 String serverName = null; 256 try { 257 serverName = InetAddress.getByName(null).getCanonicalHostName(); 258 } catch (UnknownHostException e) { 259 // nothing to do. 260 } 261 BindClient bindClient = request.createBindClient(serverName); 262 do { 263 final GenericBindRequest genericBindRequest = bindClient.nextBindRequest(); 264 bindOperation = 265 icc.processSASLBind( 266 valueOfUtf8(request.getName()), 267 ((SASLBindRequest) request).getSASLMechanism(), 268 getCredentials(genericBindRequest.getAuthenticationValue()), 269 to(request.getControls())); 270 } while (bindOperation.getResultCode() == ResultCode.SASL_BIND_IN_PROGRESS); 271 272 bindClient.dispose(); 273 274 } else { // not supported 275 throw newLdapException(Responses.newResult(ResultCode.AUTH_METHOD_NOT_SUPPORTED)); 276 } 277 BindResult result = Responses.newBindResult(bindOperation.getResultCode()); 278 result.setServerSASLCredentials(bindOperation.getSASLCredentials()); 279 280 if (result.isSuccess()) { 281 return result; 282 } else { 283 throw newLdapException(result); 284 } 285 } 286 287 @Override 288 public void addConnectionEventListener(ConnectionEventListener listener) { 289 // Internal client connection don't have any connection events. 290 } 291 292 @Override 293 public Result add(final AddRequest request) throws LdapException { 294 final AddOperation addOperation = 295 icc.processAdd(valueOfObject(request.getName()), to(request 296 .getAllAttributes()), to(request.getControls())); 297 return getResponseResult(addOperation); 298 } 299 300 @Override 301 public String toString() { 302 return icc.toString(); 303 } 304 }; 305 } 306 307}