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.core.ModifyDNOperation; 060import org.opends.server.protocols.internal.InternalClientConnection; 061import org.opends.server.protocols.internal.InternalSearchListener; 062import org.opends.server.protocols.internal.InternalSearchOperation; 063import org.opends.server.protocols.internal.Requests; 064import org.opends.server.types.AuthenticationInfo; 065import org.opends.server.types.DirectoryException; 066import org.opends.server.types.SearchFilter; 067import org.opends.server.types.SearchResultEntry; 068import org.opends.server.types.SearchResultReference; 069 070import static org.forgerock.opendj.adapter.server3x.Converters.*; 071import static org.forgerock.opendj.ldap.ByteString.*; 072import static org.forgerock.opendj.ldap.LdapException.*; 073import static org.forgerock.util.promise.Promises.*; 074 075/** 076 * This class provides a connection factory and an adapter for the OpenDJ 2.x 077 * server. 078 */ 079public final class Adapters { 080 081 /** 082 * Constructor. 083 */ 084 private Adapters() { 085 // No implementation required. 086 } 087 088 /** 089 * Returns a new root connection factory. 090 * 091 * @return A new root connection factory. 092 */ 093 public static ConnectionFactory newRootConnectionFactory() { 094 InternalClientConnection icc = InternalClientConnection.getRootConnection(); 095 return newConnectionFactory(icc); 096 } 097 098 /** 099 * Returns a new anonymous connection factory. 100 * 101 * @return A new anonymous connection factory. 102 */ 103 public static ConnectionFactory newAnonymousConnectionFactory() { 104 InternalClientConnection icc = new InternalClientConnection(new AuthenticationInfo()); 105 return newConnectionFactory(icc); 106 } 107 108 /** 109 * Returns a new connection factory for a specified user. 110 * 111 * @param userDN 112 * The specified user's DN. 113 * @return a new connection factory. 114 */ 115 public static ConnectionFactory newConnectionFactoryForUser(final DN userDN) { 116 InternalClientConnection icc = null; 117 try { 118 icc = new InternalClientConnection(userDN); 119 } catch (DirectoryException e) { 120 throw new IllegalStateException(e.getMessage(), e); 121 } 122 return newConnectionFactory(icc); 123 } 124 125 /** 126 * Returns a new connection factory. 127 * 128 * @param icc 129 * The internal client connection from server side. 130 * @return A new SDK connection factory. 131 */ 132 public static ConnectionFactory newConnectionFactory(final InternalClientConnection icc) { 133 return new ConnectionFactory() { 134 135 @Override 136 public void close() { 137 // Nothing to do. 138 } 139 140 @Override 141 public Promise<Connection, LdapException> getConnectionAsync() { 142 // TODO change the path... 143 return newResultPromise(newConnection(icc)); 144 } 145 146 @Override 147 public Connection getConnection() throws LdapException { 148 return newConnection(icc); 149 } 150 }; 151 } 152 153 /** 154 * Returns a new root connection. 155 * 156 * @return A new root connection. 157 */ 158 public static Connection newRootConnection() { 159 return newConnection(InternalClientConnection.getRootConnection()); 160 } 161 162 /** 163 * Returns a new connection for an anonymous user. 164 * 165 * @return A new connection. 166 */ 167 public static Connection newAnonymousConnection() { 168 return newConnection(new InternalClientConnection(new AuthenticationInfo())); 169 } 170 171 /** 172 * Returns a new connection for a specified user. 173 * 174 * @param dn 175 * The DN of the user. 176 * @return A new connection for a specified user. 177 * @throws LdapException 178 * If no such object. 179 */ 180 public static Connection newConnectionForUser(final DN dn) throws LdapException { 181 try { 182 return newConnection(new InternalClientConnection(dn)); 183 } catch (DirectoryException e) { 184 throw newLdapException(Responses.newResult(ResultCode.NO_SUCH_OBJECT)); 185 } 186 } 187 188 private static Connection newConnection(final InternalClientConnection icc) { 189 return new AbstractSynchronousConnection() { 190 191 @Override 192 public Result search(final SearchRequest request, final SearchResultHandler handler) 193 throws LdapException { 194 InternalSearchListener internalSearchListener = new InternalSearchListener() { 195 196 @Override 197 public void handleInternalSearchReference( 198 InternalSearchOperation searchOperation, 199 SearchResultReference searchReference) throws DirectoryException { 200 handler.handleReference(from(searchReference)); 201 } 202 203 @Override 204 public void handleInternalSearchEntry(InternalSearchOperation searchOperation, 205 SearchResultEntry searchEntry) throws DirectoryException { 206 handler.handleEntry(from(searchEntry)); 207 } 208 }; 209 210 final SearchFilter filter = toSearchFilter(request.getFilter()); 211 final org.opends.server.protocols.internal.SearchRequest sr = 212 Requests.newSearchRequest(request.getName(), request.getScope(), filter) 213 .setDereferenceAliasesPolicy(request.getDereferenceAliasesPolicy()) 214 .setSizeLimit(request.getSizeLimit()) 215 .setTimeLimit(request.getTimeLimit()) 216 .setTypesOnly(request.isTypesOnly()) 217 .addAttribute(request.getAttributes()) 218 .addControl(to(request.getControls())); 219 return getResponseResult(icc.processSearch(sr, internalSearchListener)); 220 } 221 222 @Override 223 public void removeConnectionEventListener(ConnectionEventListener listener) { 224 // Internal client connection don't have any connection events. 225 } 226 227 @Override 228 public Result modifyDN(final ModifyDNRequest request) throws LdapException { 229 final ModifyDNOperation modifyDNOperation = 230 icc.processModifyDN(valueOfObject(request.getName()), 231 valueOfObject(request.getNewRDN()), 232 request.isDeleteOldRDN(), 233 request.getNewSuperior() != null ? valueOfObject(request.getNewSuperior()) : null, 234 to(request.getControls())); 235 return getResponseResult(modifyDNOperation); 236 } 237 238 @Override 239 public Result modify(final ModifyRequest request) throws LdapException { 240 return getResponseResult(icc.processModify(request)); 241 } 242 243 @Override 244 public boolean isValid() { 245 // Always true. 246 return true; 247 } 248 249 @Override 250 public boolean isClosed() { 251 return false; 252 } 253 254 @Override 255 public <R extends ExtendedResult> R extendedRequest(final ExtendedRequest<R> request, 256 final IntermediateResponseHandler handler) throws LdapException { 257 258 final ExtendedOperation extendedOperation = 259 icc.processExtendedOperation(request.getOID(), request.getValue(), 260 to(request.getControls())); 261 262 final Result result = getResponseResult(extendedOperation); 263 final GenericExtendedResult genericExtendedResult = 264 Responses.newGenericExtendedResult(result.getResultCode()) 265 .setDiagnosticMessage(result.getDiagnosticMessage()).setMatchedDN( 266 result.getMatchedDN()).setValue( 267 extendedOperation.getResponseValue().toByteString()); 268 try { 269 R extendedResult = 270 request.getResultDecoder().decodeExtendedResult(genericExtendedResult, 271 new DecodeOptions()); 272 for (final Control control : result.getControls()) { 273 extendedResult.addControl(control); 274 } 275 return extendedResult; 276 277 } catch (DecodeException e) { 278 DN matchedDN = extendedOperation.getMatchedDN(); 279 return request.getResultDecoder().newExtendedErrorResult( 280 extendedOperation.getResultCode(), 281 matchedDN != null ? matchedDN.toString() : null, 282 extendedOperation.getErrorMessage().toString()); 283 } 284 } 285 286 @Override 287 public Result delete(final DeleteRequest request) throws LdapException { 288 final DeleteOperation deleteOperation = 289 icc.processDelete(valueOfObject(request.getName()), to(request.getControls())); 290 return getResponseResult(deleteOperation); 291 } 292 293 @Override 294 public CompareResult compare(final CompareRequest request) throws LdapException { 295 final CompareOperation compareOperation = 296 icc.processCompare(valueOfObject(request.getName()), 297 request.getAttributeDescription().toString(), 298 request.getAssertionValue(), to(request.getControls())); 299 300 CompareResult result = Responses.newCompareResult(compareOperation.getResultCode()); 301 return getResponseResult(compareOperation, result); 302 } 303 304 @Override 305 public void close(final UnbindRequest request, final String reason) { 306 // no implementation in open-ds. 307 } 308 309 @Override 310 public BindResult bind(final BindRequest request) throws LdapException { 311 BindOperation bindOperation = null; 312 if (request instanceof SimpleBindRequest) { 313 bindOperation = 314 icc.processSimpleBind(valueOfUtf8(request.getName()), 315 ByteString.wrap(((SimpleBindRequest) request).getPassword()), 316 to(request.getControls())); 317 } else if (request instanceof SASLBindRequest) { 318 String serverName = null; 319 try { 320 serverName = InetAddress.getByName(null).getCanonicalHostName(); 321 } catch (UnknownHostException e) { 322 // nothing to do. 323 } 324 BindClient bindClient = request.createBindClient(serverName); 325 do { 326 final GenericBindRequest genericBindRequest = bindClient.nextBindRequest(); 327 bindOperation = 328 icc.processSASLBind( 329 valueOfUtf8(request.getName()), 330 ((SASLBindRequest) request).getSASLMechanism(), 331 getCredentials(genericBindRequest.getAuthenticationValue()), 332 to(request.getControls())); 333 } while (bindOperation.getResultCode() == ResultCode.SASL_BIND_IN_PROGRESS); 334 335 bindClient.dispose(); 336 337 } else { // not supported 338 throw newLdapException(Responses.newResult(ResultCode.AUTH_METHOD_NOT_SUPPORTED)); 339 } 340 BindResult result = Responses.newBindResult(bindOperation.getResultCode()); 341 result.setServerSASLCredentials(bindOperation.getSASLCredentials()); 342 343 if (result.isSuccess()) { 344 return result; 345 } else { 346 throw newLdapException(result); 347 } 348 } 349 350 @Override 351 public void addConnectionEventListener(ConnectionEventListener listener) { 352 // Internal client connection don't have any connection events. 353 } 354 355 @Override 356 public Result add(final AddRequest request) throws LdapException { 357 final AddOperation addOperation = 358 icc.processAdd(valueOfObject(request.getName()), to(request 359 .getAllAttributes()), to(request.getControls())); 360 return getResponseResult(addOperation); 361 } 362 363 @Override 364 public String toString() { 365 return icc.toString(); 366 } 367 }; 368 } 369}