opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPClientConnection.java
@@ -16,12 +16,24 @@ */ package org.opends.server.protocols.ldap; import static org.opends.messages.CoreMessages.*; import static org.opends.messages.ProtocolMessages.*; import static org.opends.server.core.DirectoryServer.*; import static org.opends.server.loggers.AccessLogger.*; import static org.opends.server.protocols.ldap.LDAPConstants.*; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.StaticUtils.*; import java.io.Closeable; import java.io.IOException; import java.net.InetAddress; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.*; import java.nio.channels.ByteChannel; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.security.cert.Certificate; import java.util.Collection; import java.util.Iterator; @@ -45,23 +57,38 @@ import org.forgerock.opendj.ldap.ResultCode; import org.opends.server.api.ClientConnection; import org.opends.server.api.ConnectionHandler; import org.opends.server.core.*; import org.opends.server.core.AbandonOperationBasis; import org.opends.server.core.AddOperationBasis; import org.opends.server.core.BindOperationBasis; import org.opends.server.core.CompareOperationBasis; import org.opends.server.core.DeleteOperationBasis; import org.opends.server.core.DirectoryServer; import org.opends.server.core.ExtendedOperationBasis; import org.opends.server.core.ModifyDNOperationBasis; import org.opends.server.core.ModifyOperationBasis; import org.opends.server.core.PersistentSearch; import org.opends.server.core.PluginConfigManager; import org.opends.server.core.SearchOperation; import org.opends.server.core.SearchOperationBasis; import org.opends.server.core.UnbindOperationBasis; import org.opends.server.extensions.ConnectionSecurityProvider; import org.opends.server.extensions.RedirectingByteChannel; import org.opends.server.extensions.TLSByteChannel; import org.opends.server.extensions.TLSCapableConnection; import org.opends.server.types.*; import org.opends.server.types.AuthenticationType; import org.opends.server.types.CancelRequest; import org.opends.server.types.CancelResult; import org.opends.server.types.Control; import org.opends.server.types.DirectoryException; import org.opends.server.types.DisconnectReason; import org.opends.server.types.IntermediateResponse; import org.opends.server.types.Operation; import org.opends.server.types.OperationType; import org.opends.server.types.SearchResultEntry; import org.opends.server.types.SearchResultReference; import org.opends.server.util.StaticUtils; import org.opends.server.util.TimeThread; import static org.opends.messages.CoreMessages.*; import static org.opends.messages.ProtocolMessages.*; import static org.opends.server.core.DirectoryServer.*; import static org.opends.server.loggers.AccessLogger.*; import static org.opends.server.protocols.ldap.LDAPConstants.*; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.StaticUtils.*; /** * This class defines an LDAP client connection, which is a type of * client connection that will be accepted by an instance of the LDAP @@ -231,13 +258,9 @@ // We've been blocked for too long. throw new ClosedChannelException(); } else { waitTime = stopTime - currentTime; } Iterator<SelectionKey> iterator = selector.selectedKeys() .iterator(); Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey k = iterator.next(); @@ -375,7 +398,7 @@ private final LDAPConnectionHandler connectionHandler; /** The statistics tracker associated with this client connection. */ private final LDAPStatistics statTracker; private boolean useNanoTime; private final boolean useNanoTime; /** The connection ID assigned to this connection. */ private final long connectionID; @@ -395,7 +418,7 @@ /** The string representation of the address of the server to which the client has connected. */ private final String serverAddress; private ASN1ByteChannelReader asn1Reader; private final ASN1ByteChannelReader asn1Reader; private final int bufferSize; private final RedirectingByteChannel saslChannel; private final RedirectingByteChannel tlsChannel; @@ -440,20 +463,20 @@ serverPort = socket.getLocalPort(); statTracker = this.connectionHandler.getStatTracker(); if (keepStats) { statTracker.updateConnect(); this.useNanoTime=DirectoryServer.getUseNanoTime(); } else { this.useNanoTime = false; } bufferSize = connectionHandler.getBufferSize(); tlsChannel = RedirectingByteChannel.getRedirectingByteChannel( timeoutClientChannel); saslChannel = RedirectingByteChannel.getRedirectingByteChannel(tlsChannel); tlsChannel = RedirectingByteChannel.getRedirectingByteChannel(timeoutClientChannel); saslChannel = RedirectingByteChannel.getRedirectingByteChannel(tlsChannel); this.asn1Reader = new ASN1ByteChannelReader(saslChannel, bufferSize, connectionHandler.getMaxRequestSize()); if (connectionHandler.useSSL()) @@ -981,20 +1004,20 @@ // Indicate that this connection is no longer valid. connectionValid = false; final LocalizableMessage cancelMessage; if (message != null) { LocalizableMessageBuilder msgBuilder = new LocalizableMessageBuilder(); msgBuilder.append(disconnectReason.getClosureMessage()); msgBuilder.append(": "); msgBuilder.append(message); cancelAllOperations(new CancelRequest(true, msgBuilder .toMessage())); cancelMessage = new LocalizableMessageBuilder() .append(disconnectReason.getClosureMessage()) .append(": ") .append(message) .toMessage(); } else { cancelAllOperations(new CancelRequest(true, disconnectReason .getClosureMessage())); cancelMessage = disconnectReason.getClosureMessage(); } cancelAllOperations(new CancelRequest(true, cancelMessage)); finalizeConnectionInternal(); // If there is a write selector for this connection, then close it. @@ -1008,45 +1031,8 @@ { try { int resultCode; switch (disconnectReason) { case PROTOCOL_ERROR: resultCode = LDAPResultCode.PROTOCOL_ERROR; break; case SERVER_SHUTDOWN: resultCode = LDAPResultCode.UNAVAILABLE; break; case SERVER_ERROR: resultCode = DirectoryServer.getServerErrorResultCode().intValue(); break; case ADMIN_LIMIT_EXCEEDED: case IDLE_TIME_LIMIT_EXCEEDED: case MAX_REQUEST_SIZE_EXCEEDED: case IO_TIMEOUT: resultCode = LDAPResultCode.ADMIN_LIMIT_EXCEEDED; break; case CONNECTION_REJECTED: resultCode = LDAPResultCode.CONSTRAINT_VIOLATION; break; case INVALID_CREDENTIALS: resultCode = LDAPResultCode.INVALID_CREDENTIALS; break; default: resultCode = LDAPResultCode.OTHER; break; } LocalizableMessage errMsg; if (message == null) { errMsg = INFO_LDAP_CLIENT_GENERIC_NOTICE_OF_DISCONNECTION.get(); } else { errMsg = message; } int resultCode = toResultCode(disconnectReason); LocalizableMessage errMsg = message != null ? message : INFO_LDAP_CLIENT_GENERIC_NOTICE_OF_DISCONNECTION.get(); ExtendedResponseProtocolOp notificationOp = new ExtendedResponseProtocolOp(resultCode, errMsg, null, @@ -1069,15 +1055,12 @@ // NYI -- Deregister the client connection from any server components that // might know about it. // Log a disconnect message. logDisconnect(this, disconnectReason, message); try { PluginConfigManager pluginManager = DirectoryServer.getPluginConfigManager(); pluginManager.invokePostDisconnectPlugins(this, disconnectReason, message); PluginConfigManager pluginManager = DirectoryServer.getPluginConfigManager(); pluginManager.invokePostDisconnectPlugins(this, disconnectReason, message); } catch (Exception e) { @@ -1085,6 +1068,30 @@ } } private int toResultCode(DisconnectReason disconnectReason) { switch (disconnectReason) { case PROTOCOL_ERROR: return LDAPResultCode.PROTOCOL_ERROR; case SERVER_SHUTDOWN: return LDAPResultCode.UNAVAILABLE; case SERVER_ERROR: return DirectoryServer.getServerErrorResultCode().intValue(); case ADMIN_LIMIT_EXCEEDED: case IDLE_TIME_LIMIT_EXCEEDED: case MAX_REQUEST_SIZE_EXCEEDED: case IO_TIMEOUT: return LDAPResultCode.ADMIN_LIMIT_EXCEEDED; case CONNECTION_REJECTED: return LDAPResultCode.CONSTRAINT_VIOLATION; case INVALID_CREDENTIALS: return LDAPResultCode.INVALID_CREDENTIALS; default: return LDAPResultCode.OTHER; } } /** * Retrieves the set of operations in progress for this client * connection. This list must not be altered by any caller. @@ -1235,28 +1242,24 @@ CancelRequest cancelRequest) { Operation op = operationsInProgress.get(messageID); if (op == null) if (op != null) { return op.cancel(cancelRequest); } // See if the operation is in the list of persistent searches. for (PersistentSearch ps : getPersistentSearches()) { if (ps.getMessageID() == messageID) { // We only need to find the first persistent search // associated with the provided message ID. The persistent // search will ensure that all other related persistent // searches are cancelled. // associated with the provided message ID. The persistent search // will ensure that all other related persistent searches are cancelled. return ps.cancel(); } } return new CancelResult(ResultCode.NO_SUCH_OPERATION, null); } else { return op.cancel(cancelRequest); } } /** * Attempts to cancel all operations in progress on this connection. @@ -1535,15 +1538,13 @@ switch (message.getProtocolOpType()) { case OP_TYPE_ABANDON_REQUEST: result = processAbandonRequest(message, opControls); return result; return processAbandonRequest(message, opControls); case OP_TYPE_ADD_REQUEST: result = processAddRequest(message, opControls); return result; return processAddRequest(message, opControls); case OP_TYPE_BIND_REQUEST: boolean isSaslBind = message.getBindRequestProtocolOp().getAuthenticationType() == AuthenticationType.SASL; bindInProgress.set(true); if(message.getBindRequestProtocolOp(). getAuthenticationType() == AuthenticationType.SASL) if (isSaslBind) { saslBindInProgress.set(true); } @@ -1551,45 +1552,36 @@ if(!result) { bindInProgress.set(false); if(message.getBindRequestProtocolOp(). getAuthenticationType() == AuthenticationType.SASL) if (isSaslBind) { saslBindInProgress.set(false); } } return result; case OP_TYPE_COMPARE_REQUEST: result = processCompareRequest(message, opControls); return result; return processCompareRequest(message, opControls); case OP_TYPE_DELETE_REQUEST: result = processDeleteRequest(message, opControls); return result; return processDeleteRequest(message, opControls); case OP_TYPE_EXTENDED_REQUEST: if(message.getExtendedRequestProtocolOp().getOID().equals( OID_START_TLS_REQUEST)) boolean isStartTlsRequest = OID_START_TLS_REQUEST.equals(message.getExtendedRequestProtocolOp().getOID()); if (isStartTlsRequest) { startTLSInProgress.set(true); } result = processExtendedRequest(message, opControls); if(!result && message.getExtendedRequestProtocolOp().getOID().equals( OID_START_TLS_REQUEST)) if (!result && isStartTlsRequest) { startTLSInProgress.set(false); } return result; case OP_TYPE_MODIFY_REQUEST: result = processModifyRequest(message, opControls); return result; return processModifyRequest(message, opControls); case OP_TYPE_MODIFY_DN_REQUEST: result = processModifyDNRequest(message, opControls); return result; return processModifyDNRequest(message, opControls); case OP_TYPE_SEARCH_REQUEST: result = processSearchRequest(message, opControls); return result; return processSearchRequest(message, opControls); case OP_TYPE_UNBIND_REQUEST: result = processUnbindRequest(message, opControls); return result; return processUnbindRequest(message, opControls); default: LocalizableMessage msg = ERR_LDAP_DISCONNECT_DUE_TO_INVALID_REQUEST_TYPE.get(message @@ -1626,11 +1618,9 @@ */ private boolean processAbandonRequest(LDAPMessage message, List<Control> controls) { if (ldapVersion == 2 && controls != null && !controls.isEmpty()) if (ldapVersion == 2 && !controls.isEmpty()) { // LDAPv2 clients aren't allowed to send controls. disconnect(DisconnectReason.PROTOCOL_ERROR, false, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); disconnectControlsNotAllowed(); return false; } @@ -1672,16 +1662,14 @@ */ private boolean processAddRequest(LDAPMessage message, List<Control> controls) { if (ldapVersion == 2 && controls != null && !controls.isEmpty()) if (ldapVersion == 2 && !controls.isEmpty()) { // LDAPv2 clients aren't allowed to send controls. AddResponseProtocolOp responseOp = new AddResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(new LDAPMessage(message.getMessageID(), responseOp)); disconnect(DisconnectReason.PROTOCOL_ERROR, false, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(message, responseOp); disconnectControlsNotAllowed(); return false; } @@ -1712,6 +1700,16 @@ return connectionValid; } private void sendLDAPMessage(LDAPMessage message, ProtocolOp responseOp) { sendLDAPMessage(new LDAPMessage(message.getMessageID(), responseOp)); } private void disconnectControlsNotAllowed() { disconnect(DisconnectReason.PROTOCOL_ERROR, false, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); } /** * Processes the provided LDAP message as a bind request. * @@ -1752,16 +1750,14 @@ return false; } if (controls != null && !controls.isEmpty()) if (!controls.isEmpty()) { // LDAPv2 clients aren't allowed to send controls. BindResponseProtocolOp responseOp = new BindResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(new LDAPMessage(message.getMessageID(), responseOp)); disconnect(DisconnectReason.PROTOCOL_ERROR, false, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(message, responseOp); disconnectControlsNotAllowed(); return false; } @@ -1857,16 +1853,14 @@ */ private boolean processCompareRequest(LDAPMessage message, List<Control> controls) { if (ldapVersion == 2 && controls != null && !controls.isEmpty()) if (ldapVersion == 2 && !controls.isEmpty()) { // LDAPv2 clients aren't allowed to send controls. CompareResponseProtocolOp responseOp = new CompareResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(new LDAPMessage(message.getMessageID(), responseOp)); disconnect(DisconnectReason.PROTOCOL_ERROR, false, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(message, responseOp); disconnectControlsNotAllowed(); return false; } @@ -1913,16 +1907,14 @@ */ private boolean processDeleteRequest(LDAPMessage message, List<Control> controls) { if (ldapVersion == 2 && controls != null && !controls.isEmpty()) if (ldapVersion == 2 && !controls.isEmpty()) { // LDAPv2 clients aren't allowed to send controls. DeleteResponseProtocolOp responseOp = new DeleteResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(new LDAPMessage(message.getMessageID(), responseOp)); disconnect(DisconnectReason.PROTOCOL_ERROR, false, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(message, responseOp); disconnectControlsNotAllowed(); return false; } @@ -2031,16 +2023,14 @@ */ private boolean processModifyRequest(LDAPMessage message, List<Control> controls) { if (ldapVersion == 2 && controls != null && !controls.isEmpty()) if (ldapVersion == 2 && !controls.isEmpty()) { // LDAPv2 clients aren't allowed to send controls. ModifyResponseProtocolOp responseOp = new ModifyResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(new LDAPMessage(message.getMessageID(), responseOp)); disconnect(DisconnectReason.PROTOCOL_ERROR, false, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(message, responseOp); disconnectControlsNotAllowed(); return false; } @@ -2088,16 +2078,14 @@ */ private boolean processModifyDNRequest(LDAPMessage message, List<Control> controls) { if (ldapVersion == 2 && controls != null && !controls.isEmpty()) if (ldapVersion == 2 && !controls.isEmpty()) { // LDAPv2 clients aren't allowed to send controls. ModifyDNResponseProtocolOp responseOp = new ModifyDNResponseProtocolOp(LDAPResultCode.PROTOCOL_ERROR, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(new LDAPMessage(message.getMessageID(), responseOp)); disconnect(DisconnectReason.PROTOCOL_ERROR, false, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(message, responseOp); disconnectControlsNotAllowed(); return false; } @@ -2145,16 +2133,14 @@ private boolean processSearchRequest(LDAPMessage message, List<Control> controls) { if (ldapVersion == 2 && controls != null && !controls.isEmpty()) if (ldapVersion == 2 && !controls.isEmpty()) { // LDAPv2 clients aren't allowed to send controls. SearchResultDoneProtocolOp responseOp = new SearchResultDoneProtocolOp(LDAPResultCode.PROTOCOL_ERROR, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(new LDAPMessage(message.getMessageID(), responseOp)); disconnect(DisconnectReason.PROTOCOL_ERROR, false, ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get()); sendLDAPMessage(message, responseOp); disconnectControlsNotAllowed(); return false; } opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPAuthenticationHandler.java
@@ -16,6 +16,13 @@ */ package org.opends.server.tools; import static com.forgerock.opendj.cli.ArgumentConstants.*; import static org.opends.messages.ToolMessages.*; import static org.opends.server.protocols.ldap.LDAPConstants.*; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.StaticUtils.*; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; @@ -31,6 +38,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.StringTokenizer; import java.util.concurrent.atomic.AtomicInteger; @@ -44,11 +52,10 @@ import javax.security.sasl.Sasl; import javax.security.sasl.SaslClient; import com.forgerock.opendj.cli.ClientException; import com.forgerock.opendj.cli.ConsoleApplication; import com.forgerock.opendj.cli.ReturnCode; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.i18n.LocalizableMessageDescriptor.Arg0; import org.forgerock.i18n.LocalizableMessageDescriptor.Arg1; import org.forgerock.i18n.LocalizableMessageDescriptor.Arg2; import org.forgerock.opendj.ldap.ByteSequence; import org.forgerock.opendj.ldap.ByteString; import org.forgerock.opendj.ldap.DecodeException; @@ -61,12 +68,9 @@ import org.opends.server.types.LDAPException; import org.opends.server.util.Base64; import static com.forgerock.opendj.cli.ArgumentConstants.*; import static org.opends.messages.ToolMessages.*; import static org.opends.server.protocols.ldap.LDAPConstants.*; import static org.opends.server.util.ServerConstants.*; import static org.opends.server.util.StaticUtils.*; import com.forgerock.opendj.cli.ClientException; import com.forgerock.opendj.cli.ConsoleApplication; import com.forgerock.opendj.cli.ReturnCode; /** * This class provides a generic interface that LDAP clients can use to perform @@ -88,42 +92,32 @@ public class LDAPAuthenticationHandler implements PrivilegedExceptionAction<Object>, CallbackHandler { /** The bind DN for GSSAPI authentication. */ private ByteSequence gssapiBindDN; /** The LDAP reader that will be used to read data from the server. */ private final LDAPReader reader; /** The LDAP writer that will be used to send data to the server. */ private final LDAPWriter writer; /** * The atomic integer that will be used to obtain message IDs for request * messages. */ /** The atomic integer that will be used to obtain message IDs for request messages. */ private final AtomicInteger nextMessageID; /** An array filled with the inner pad byte. */ private byte[] iPad; /** An array filled with the outer pad byte. */ private byte[] oPad; /** The authentication password for GSSAPI authentication. */ private char[] gssapiAuthPW; /** The message digest that will be used to create MD5 hashes. */ private MessageDigest md5Digest; /** The secure random number generator for use by this authentication handler. */ private SecureRandom secureRandom; /** The bind DN for GSSAPI authentication. */ private ByteSequence gssapiBindDN; /** The authentication ID for GSSAPI authentication. */ private String gssapiAuthID; /** The authorization ID for GSSAPI authentication. */ private String gssapiAuthzID; /** The authentication password for GSSAPI authentication. */ private char[] gssapiAuthPW; /** The quality of protection for GSSAPI authentication. */ private String gssapiQoP; @@ -200,36 +194,23 @@ * specified SASL mechanism, mapped from the property names to their * corresponding descriptions. */ public static LinkedHashMap<String,LocalizableMessage> getSASLProperties( String mechanism) public static Map<String, LocalizableMessage> getSASLProperties(String mechanism) { String upperName = toUpperCase(mechanism); if (upperName.equals(SASL_MECHANISM_ANONYMOUS)) switch (toUpperCase(mechanism)) { case SASL_MECHANISM_ANONYMOUS: return getSASLAnonymousProperties(); } else if (upperName.equals(SASL_MECHANISM_CRAM_MD5)) { case SASL_MECHANISM_CRAM_MD5: return getSASLCRAMMD5Properties(); } else if (upperName.equals(SASL_MECHANISM_DIGEST_MD5)) { case SASL_MECHANISM_DIGEST_MD5: return getSASLDigestMD5Properties(); } else if (upperName.equals(SASL_MECHANISM_EXTERNAL)) { case SASL_MECHANISM_EXTERNAL: return getSASLExternalProperties(); } else if (upperName.equals(SASL_MECHANISM_GSSAPI)) { case SASL_MECHANISM_GSSAPI: return getSASLGSSAPIProperties(); } else if (upperName.equals(SASL_MECHANISM_PLAIN)) { case SASL_MECHANISM_PLAIN: return getSASLPlainProperties(); } else { default: // This is an unsupported mechanism. return null; } @@ -279,21 +260,26 @@ bindPassword = ByteString.empty(); } // Make sure that critical elements aren't null. if (bindDN == null) { bindDN = ByteString.empty(); } sendSimpleBindRequest(ldapVersion, bindDN, bindPassword, requestControls); // Create the bind request and send it to the server. LDAPMessage responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE); responseControls.addAll(responseMessage.getControls()); checkConnected(responseMessage); return checkSuccessfulSimpleBind(responseMessage); } private void sendSimpleBindRequest(int ldapVersion, ByteSequence bindDN, ByteSequence bindPassword, List<Control> requestControls) throws ClientException { BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(bindDN.toByteString(), ldapVersion, bindPassword.toByteString()); LDAPMessage bindRequestMessage = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest, requestControls); new BindRequestProtocolOp(bindDN.toByteString(), ldapVersion, bindPassword.toByteString()); LDAPMessage bindRequestMessage = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest, requestControls); try { @@ -301,88 +287,45 @@ } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SIMPLE_BIND.get(getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SIMPLE_BIND.get(getExceptionMessage(ioe)); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SIMPLE_BIND.get(getExceptionMessage(e)); LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SIMPLE_BIND.get(getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e); } // Read the response from the server. LDAPMessage responseMessage; try { responseMessage = reader.readMessage(); if (responseMessage == null) { LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message); } } catch (DecodeException | LDAPException e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } // See if there are any controls in the response. If so, then add them to // the response controls list. List<Control> respControls = responseMessage.getControls(); if (respControls != null && !respControls.isEmpty()) private BindResponseProtocolOp checkSuccessfulBind(LDAPMessage responseMessage, String saslMechanism) throws LDAPException { responseControls.addAll(respControls); } // Look at the protocol op from the response. If it's a bind response, then // continue. If it's an extended response, then it could be a notice of // disconnection so check for that. Otherwise, generate an error. generateError(responseMessage); BindResponseProtocolOp bindResponse = responseMessage.getBindResponseProtocolOp(); BindResponseProtocolOp bindResponse = responseMessage.getBindResponseProtocolOp(); int resultCode = bindResponse.getResultCode(); if (resultCode == ReturnCode.SUCCESS.get()) if (resultCode != ReturnCode.SUCCESS.get()) { // FIXME -- Need to look for things like password expiration warning, // reset notice, etc. // FIXME -- Add support for referrals. LocalizableMessage message = ERR_LDAPAUTH_SASL_BIND_FAILED.get(saslMechanism); throw new LDAPException(resultCode, bindResponse.getErrorMessage(), message, bindResponse.getMatchedDN(), null); } // FIXME -- Need to look for things like password expiration warning, reset notice, etc. return bindResponse; } private String checkSuccessfulSimpleBind(LDAPMessage responseMessage) throws LDAPException { BindResponseProtocolOp bindResponse = responseMessage.getBindResponseProtocolOp(); int resultCode = bindResponse.getResultCode(); if (resultCode != ReturnCode.SUCCESS.get()) { // FIXME -- Add support for referrals. LocalizableMessage message = ERR_LDAPAUTH_SIMPLE_BIND_FAILED.get(); throw new LDAPException(resultCode, bindResponse.getErrorMessage(), message, bindResponse.getMatchedDN(), null); } // FIXME -- Need to look for things like password expiration warning, reset notice, etc. return null; } // FIXME -- Add support for referrals. LocalizableMessage message = ERR_LDAPAUTH_SIMPLE_BIND_FAILED.get(); throw new LDAPException(resultCode, bindResponse.getErrorMessage(), message, bindResponse.getMatchedDN(), null); } /** * Processes a SASL bind using the provided information. If the bind fails, * then an exception will be thrown with information about the reason for the @@ -431,49 +374,29 @@ if (mechanism == null || mechanism.length() == 0) { LocalizableMessage message = ERR_LDAPAUTH_NO_SASL_MECHANISM.get(); throw new ClientException( ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } // Look at the mechanism name and call the appropriate method to process // the request. // Look at the mechanism name and call the appropriate method to process the request. saslMechanism = toUpperCase(mechanism); if (saslMechanism.equals(SASL_MECHANISM_ANONYMOUS)) switch (saslMechanism) { return doSASLAnonymous(bindDN, saslProperties, requestControls, responseControls); } else if (saslMechanism.equals(SASL_MECHANISM_CRAM_MD5)) { return doSASLCRAMMD5(bindDN, bindPassword, saslProperties, requestControls, responseControls); } else if (saslMechanism.equals(SASL_MECHANISM_DIGEST_MD5)) { return doSASLDigestMD5(bindDN, bindPassword, saslProperties, requestControls, responseControls); } else if (saslMechanism.equals(SASL_MECHANISM_EXTERNAL)) { return doSASLExternal(bindDN, saslProperties, requestControls, responseControls); } else if (saslMechanism.equals(SASL_MECHANISM_GSSAPI)) { return doSASLGSSAPI(bindDN, bindPassword, saslProperties, requestControls, responseControls); } else if (saslMechanism.equals(SASL_MECHANISM_PLAIN)) { return doSASLPlain(bindDN, bindPassword, saslProperties, requestControls, responseControls); } else { case SASL_MECHANISM_ANONYMOUS: return doSASLAnonymous(bindDN, saslProperties, requestControls, responseControls); case SASL_MECHANISM_CRAM_MD5: return doSASLCRAMMD5(bindDN, bindPassword, saslProperties, requestControls, responseControls); case SASL_MECHANISM_DIGEST_MD5: return doSASLDigestMD5(bindDN, bindPassword, saslProperties, requestControls, responseControls); case SASL_MECHANISM_EXTERNAL: return doSASLExternal(bindDN, saslProperties, requestControls, responseControls); case SASL_MECHANISM_GSSAPI: return doSASLGSSAPI(bindDN, bindPassword, saslProperties, requestControls, responseControls); case SASL_MECHANISM_PLAIN: return doSASLPlain(bindDN, bindPassword, saslProperties, requestControls, responseControls); default: LocalizableMessage message = ERR_LDAPAUTH_UNSUPPORTED_SASL_MECHANISM.get(mechanism); throw new ClientException( ReturnCode.CLIENT_SIDE_AUTH_UNKNOWN, message); throw new ClientException(ReturnCode.CLIENT_SIDE_AUTH_UNKNOWN, message); } } @@ -502,7 +425,7 @@ * @throws LDAPException If the bind fails or some other server-side problem * occurs during processing. */ public String doSASLAnonymous(ByteSequence bindDN, private String doSASLAnonymous(ByteSequence bindDN, Map<String,List<String>> saslProperties, List<Control> requestControls, List<Control> responseControls) @@ -510,151 +433,38 @@ { String trace = null; // Evaluate the properties provided. The only one we'll allow is the trace // property, but it is not required. if (saslProperties == null || saslProperties.isEmpty()) // The only allowed property is the trace property, but it is not required. if (saslProperties != null) { // This is fine because there are no required properties for this mechanism. } else for (Entry<String, List<String>> entry : saslProperties.entrySet()) { for (String name : saslProperties.keySet()) { String name = entry.getKey(); List<String> values = entry.getValue(); if (name.equalsIgnoreCase(SASL_PROPERTY_TRACE)) { // This is acceptable, and we'll take any single value. List<String> values = saslProperties.get(name); Iterator<String> iterator = values.iterator(); if (iterator.hasNext()) { trace = iterator.next(); if (iterator.hasNext()) { LocalizableMessage message = ERR_LDAPAUTH_TRACE_SINGLE_VALUED.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } } trace = getSingleValue(values, ERR_LDAPAUTH_TRACE_SINGLE_VALUED); } else { LocalizableMessage message = ERR_LDAPAUTH_INVALID_SASL_PROPERTY.get( name, SASL_MECHANISM_ANONYMOUS); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } } } // Construct the bind request and send it to the server. ByteString saslCredentials; if (trace == null) { saslCredentials = null; } else { saslCredentials = ByteString.valueOfUtf8(trace); } ByteString saslCredentials = trace != null ? ByteString.valueOfUtf8(trace) : null; sendBindRequest(SASL_MECHANISM_ANONYMOUS, bindDN, saslCredentials, requestControls); BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(bindDN.toByteString(), SASL_MECHANISM_ANONYMOUS, saslCredentials); LDAPMessage requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest, requestControls); try { writer.writeMessage(requestMessage); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get( SASL_MECHANISM_ANONYMOUS, getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get( SASL_MECHANISM_ANONYMOUS, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e); } // Read the response from the server. LDAPMessage responseMessage; try { responseMessage = reader.readMessage(); if (responseMessage == null) { LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message); } } catch (DecodeException | LDAPException e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } // See if there are any controls in the response. If so, then add them to // the response controls list. List<Control> respControls = responseMessage.getControls(); if (respControls != null && ! respControls.isEmpty()) { responseControls.addAll(respControls); } // Look at the protocol op from the response. If it's a bind response, then // continue. If it's an extended response, then it could be a notice of // disconnection so check for that. Otherwise, generate an error. generateError(responseMessage); BindResponseProtocolOp bindResponse = responseMessage.getBindResponseProtocolOp(); int resultCode = bindResponse.getResultCode(); if (resultCode == ReturnCode.SUCCESS.get()) { // FIXME -- Need to look for things like password expiration warning, // reset notice, etc. LDAPMessage responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE); responseControls.addAll(responseMessage.getControls()); checkConnected(responseMessage); checkSuccessfulBind(responseMessage, SASL_MECHANISM_ANONYMOUS); return null; } // FIXME -- Add support for referrals. LocalizableMessage message = ERR_LDAPAUTH_SASL_BIND_FAILED.get(SASL_MECHANISM_ANONYMOUS); throw new LDAPException(resultCode, bindResponse.getErrorMessage(), message, bindResponse.getMatchedDN(), null); } /** * Retrieves the set of properties that a client may provide when performing a * SASL ANONYMOUS bind, mapped from the property names to their corresponding @@ -664,7 +474,7 @@ * SASL ANONYMOUS bind, mapped from the property names to their * corresponding descriptions. */ public static LinkedHashMap<String, LocalizableMessage> getSASLAnonymousProperties() private static LinkedHashMap<String, LocalizableMessage> getSASLAnonymousProperties() { LinkedHashMap<String,LocalizableMessage> properties = new LinkedHashMap<>(1); @@ -701,7 +511,7 @@ * @throws LDAPException If the bind fails or some other server-side problem * occurs during processing. */ public String doSASLCRAMMD5(ByteSequence bindDN, private String doSASLCRAMMD5(ByteSequence bindDN, ByteSequence bindPassword, Map<String,List<String>> saslProperties, List<Control> requestControls, @@ -721,20 +531,21 @@ ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } for (String name : saslProperties.keySet()) for (Entry<String, List<String>> entry : saslProperties.entrySet()) { String name = entry.getKey(); List<String> values = entry.getValue(); String lowerName = toLowerCase(name); if (lowerName.equals(SASL_PROPERTY_AUTHID)) { authID = getAuthID(saslProperties, authID, name); authID = getSingleValue(values, ERR_LDAPAUTH_AUTHID_SINGLE_VALUED); } else { LocalizableMessage message = ERR_LDAPAUTH_INVALID_SASL_PROPERTY.get( name, SASL_MECHANISM_CRAM_MD5); throw new ClientException( ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } } @@ -755,108 +566,13 @@ bindPassword = ByteString.empty(); } sendInitialBindRequest(SASL_MECHANISM_CRAM_MD5, bindDN); // Construct the initial bind request to send to the server. In this case, // we'll simply indicate that we want to use CRAM-MD5 so the server will // send us the challenge. BindRequestProtocolOp bindRequest1 = new BindRequestProtocolOp(bindDN.toByteString(), SASL_MECHANISM_CRAM_MD5, null); // FIXME -- Should we include request controls in both stages or just the // second stage? LDAPMessage requestMessage1 = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest1); LDAPMessage responseMessage1 = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE, SASL_MECHANISM_CRAM_MD5); checkConnected(responseMessage1); try { writer.writeMessage(requestMessage1); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_INITIAL_SASL_BIND.get( SASL_MECHANISM_CRAM_MD5, getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_INITIAL_SASL_BIND.get( SASL_MECHANISM_CRAM_MD5, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e); } // Read the response from the server. LDAPMessage responseMessage1; try { responseMessage1 = reader.readMessage(); if (responseMessage1 == null) { LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message); } } catch (DecodeException | LDAPException e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE.get( SASL_MECHANISM_CRAM_MD5, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE.get( SASL_MECHANISM_CRAM_MD5, getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE.get( SASL_MECHANISM_CRAM_MD5, getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } // Look at the protocol op from the response. If it's a bind response, then // continue. If it's an extended response, then it could be a notice of // disconnection so check for that. Otherwise, generate an error. switch (responseMessage1.getProtocolOpType()) { case OP_TYPE_BIND_RESPONSE: // We'll deal with this later. break; case OP_TYPE_EXTENDED_RESPONSE: ExtendedResponseProtocolOp extendedResponse = responseMessage1.getExtendedResponseProtocolOp(); String responseOID = extendedResponse.getOID(); if (responseOID != null && responseOID.equals(OID_NOTICE_OF_DISCONNECTION)) { LocalizableMessage message = ERR_LDAPAUTH_SERVER_DISCONNECT. get(extendedResponse.getResultCode(), extendedResponse.getErrorMessage()); throw new LDAPException(extendedResponse.getResultCode(), message); } else { LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_EXTENDED_RESPONSE.get(extendedResponse); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } default: LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_RESPONSE.get(responseMessage1.getProtocolOp()); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } // Make sure that the bind response has the "SASL bind in progress" result // code. // Make sure that the bind response has the "SASL bind in progress" result code. BindResponseProtocolOp bindResponse1 = responseMessage1.getBindResponseProtocolOp(); int resultCode1 = bindResponse1.getResultCode(); @@ -885,157 +601,75 @@ throw new LDAPException(ReturnCode.PROTOCOL_ERROR.get(), message); } // Use the provided password and credentials to generate the CRAM-MD5 response. String salsCredentials = authID + ' ' + generateCRAMMD5Digest(bindPassword, serverChallenge); sendSecondBindRequest(SASL_MECHANISM_CRAM_MD5, bindDN, salsCredentials, requestControls); // Use the provided password and credentials to generate the CRAM-MD5 // response. StringBuilder buffer = new StringBuilder(); buffer.append(authID); buffer.append(' '); buffer.append(generateCRAMMD5Digest(bindPassword, serverChallenge)); LDAPMessage responseMessage2 = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE, SASL_MECHANISM_CRAM_MD5); responseControls.addAll(responseMessage2.getControls()); checkConnected(responseMessage2); checkSuccessfulBind(responseMessage2, SASL_MECHANISM_CRAM_MD5); return null; } // Create and send the second bind request to the server. BindRequestProtocolOp bindRequest2 = new BindRequestProtocolOp(bindDN.toByteString(), SASL_MECHANISM_CRAM_MD5, ByteString.valueOfUtf8(buffer.toString())); LDAPMessage requestMessage2 = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest2, requestControls); /** * Construct the initial bind request to send to the server. We'll simply indicate the SASL * mechanism we want to use so the server will send us the challenge. */ private void sendInitialBindRequest(String saslMechanism, ByteSequence bindDN) throws ClientException { // FIXME -- Should we include request controls in both stages or just the second stage? BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(bindDN.toByteString(), saslMechanism, null); LDAPMessage requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest); try { writer.writeMessage(requestMessage2); writer.writeMessage(requestMessage); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SECOND_SASL_BIND.get( SASL_MECHANISM_CRAM_MD5, getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_INITIAL_SASL_BIND.get(saslMechanism, getExceptionMessage(ioe)); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SECOND_SASL_BIND.get( SASL_MECHANISM_CRAM_MD5, getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_INITIAL_SASL_BIND.get(saslMechanism, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e); } } // Read the response from the server. LDAPMessage responseMessage2; private LDAPMessage readBindResponse(Arg2<Object, Object> errCannotReadBindResponse, String saslMechanism) throws ClientException { try { responseMessage2 = reader.readMessage(); if (responseMessage2 == null) LDAPMessage responseMessage = reader.readMessage(); if (responseMessage != null) { LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message); return responseMessage; } LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message); } catch (DecodeException | LDAPException e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE.get( SASL_MECHANISM_CRAM_MD5, getExceptionMessage(e)); LocalizableMessage message = errCannotReadBindResponse.get(saslMechanism, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE.get( SASL_MECHANISM_CRAM_MD5, getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); LocalizableMessage message = errCannotReadBindResponse.get(saslMechanism, getExceptionMessage(ioe)); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE.get( SASL_MECHANISM_CRAM_MD5, getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } // See if there are any controls in the response. If so, then add them to // the response controls list. List<Control> respControls = responseMessage2.getControls(); if (respControls != null && ! respControls.isEmpty()) { responseControls.addAll(respControls); } // Look at the protocol op from the response. If it's a bind response, then // continue. If it's an extended response, then it could be a notice of // disconnection so check for that. Otherwise, generate an error. switch (responseMessage2.getProtocolOpType()) { case OP_TYPE_BIND_RESPONSE: // We'll deal with this later. break; case OP_TYPE_EXTENDED_RESPONSE: ExtendedResponseProtocolOp extendedResponse = responseMessage2.getExtendedResponseProtocolOp(); String responseOID = extendedResponse.getOID(); if (responseOID != null && responseOID.equals(OID_NOTICE_OF_DISCONNECTION)) { LocalizableMessage message = ERR_LDAPAUTH_SERVER_DISCONNECT. get(extendedResponse.getResultCode(), extendedResponse.getErrorMessage()); throw new LDAPException(extendedResponse.getResultCode(), message); } else { LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_EXTENDED_RESPONSE.get(extendedResponse); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } default: LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_RESPONSE.get(responseMessage2.getProtocolOp()); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } BindResponseProtocolOp bindResponse2 = responseMessage2.getBindResponseProtocolOp(); int resultCode2 = bindResponse2.getResultCode(); if (resultCode2 == ReturnCode.SUCCESS.get()) { // FIXME -- Need to look for things like password expiration warning, // reset notice, etc. return null; } // FIXME -- Add support for referrals. LocalizableMessage message = ERR_LDAPAUTH_SASL_BIND_FAILED.get(SASL_MECHANISM_CRAM_MD5); throw new LDAPException(resultCode2, bindResponse2.getErrorMessage(), message, bindResponse2.getMatchedDN(), null); } private String getAuthID(Map<String, List<String>> saslProperties, String authID, String name) throws ClientException { List<String> values = saslProperties.get(name); Iterator<String> iterator = values.iterator(); if (iterator.hasNext()) { authID = iterator.next(); if (iterator.hasNext()) { LocalizableMessage message = ERR_LDAPAUTH_AUTHID_SINGLE_VALUED.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); LocalizableMessage message = errCannotReadBindResponse.get(saslMechanism, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } } return authID; } /** * Generates the appropriate HMAC-MD5 digest for a CRAM-MD5 authentication @@ -1141,7 +775,7 @@ * SASL CRAM-MD5 bind, mapped from the property names to their * corresponding descriptions. */ public static LinkedHashMap<String,LocalizableMessage> getSASLCRAMMD5Properties() private static LinkedHashMap<String, LocalizableMessage> getSASLCRAMMD5Properties() { LinkedHashMap<String,LocalizableMessage> properties = new LinkedHashMap<>(1); @@ -1178,7 +812,7 @@ * @throws LDAPException If the bind fails or some other server-side problem * occurs during processing. */ public String doSASLDigestMD5(ByteSequence bindDN, private String doSASLDigestMD5(ByteSequence bindDN, ByteSequence bindPassword, Map<String,List<String>> saslProperties, List<Control> requestControls, @@ -1202,17 +836,18 @@ throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } for (String name : saslProperties.keySet()) for (Entry<String, List<String>> entry : saslProperties.entrySet()) { String name = entry.getKey(); List<String> values = entry.getValue(); String lowerName = toLowerCase(name); if (lowerName.equals(SASL_PROPERTY_AUTHID)) { authID = getAuthID(saslProperties, authID, name); authID = getSingleValue(values, ERR_LDAPAUTH_AUTHID_SINGLE_VALUED); } else if (lowerName.equals(SASL_PROPERTY_REALM)) { List<String> values = saslProperties.get(name); Iterator<String> iterator = values.iterator(); if (iterator.hasNext()) { @@ -1229,7 +864,6 @@ } else if (lowerName.equals(SASL_PROPERTY_QOP)) { List<String> values = saslProperties.get(name); Iterator<String> iterator = values.iterator(); if (iterator.hasNext()) { @@ -1264,42 +898,17 @@ } else if (lowerName.equals(SASL_PROPERTY_DIGEST_URI)) { List<String> values = saslProperties.get(name); Iterator<String> iterator = values.iterator(); if (iterator.hasNext()) { digestURI = toLowerCase(iterator.next()); if (iterator.hasNext()) { LocalizableMessage message = ERR_LDAPAUTH_DIGEST_URI_SINGLE_VALUED.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } } digestURI = toLowerCase(getSingleValue(values, ERR_LDAPAUTH_DIGEST_URI_SINGLE_VALUED)); } else if (lowerName.equals(SASL_PROPERTY_AUTHZID)) { List<String> values = saslProperties.get(name); Iterator<String> iterator = values.iterator(); if (iterator.hasNext()) { authzID = toLowerCase(iterator.next()); if (iterator.hasNext()) { LocalizableMessage message = ERR_LDAPAUTH_AUTHZID_SINGLE_VALUED.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } } authzID = toLowerCase(getSingleValue(values, ERR_LDAPAUTH_AUTHZID_SINGLE_VALUED)); } else { LocalizableMessage message = ERR_LDAPAUTH_INVALID_SASL_PROPERTY.get( name, SASL_MECHANISM_DIGEST_MD5); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } } @@ -1321,108 +930,13 @@ } // Construct the initial bind request to send to the server. In this case, // we'll simply indicate that we want to use DIGEST-MD5 so the server will // send us the challenge. BindRequestProtocolOp bindRequest1 = new BindRequestProtocolOp(bindDN.toByteString(), SASL_MECHANISM_DIGEST_MD5, null); // FIXME -- Should we include request controls in both stages or just the // second stage? LDAPMessage requestMessage1 = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest1); sendInitialBindRequest(SASL_MECHANISM_DIGEST_MD5, bindDN); try { writer.writeMessage(requestMessage1); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_INITIAL_SASL_BIND.get( SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_INITIAL_SASL_BIND.get( SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e); } LDAPMessage responseMessage1 = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE, SASL_MECHANISM_DIGEST_MD5); checkConnected(responseMessage1); // Read the response from the server. LDAPMessage responseMessage1; try { responseMessage1 = reader.readMessage(); if (responseMessage1 == null) { LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message); } } catch (DecodeException | LDAPException e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE.get( SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE.get( SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_INITIAL_BIND_RESPONSE.get( SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } // Look at the protocol op from the response. If it's a bind response, then // continue. If it's an extended response, then it could be a notice of // disconnection so check for that. Otherwise, generate an error. switch (responseMessage1.getProtocolOpType()) { case OP_TYPE_BIND_RESPONSE: // We'll deal with this later. break; case OP_TYPE_EXTENDED_RESPONSE: ExtendedResponseProtocolOp extendedResponse = responseMessage1.getExtendedResponseProtocolOp(); String responseOID = extendedResponse.getOID(); if (responseOID != null && responseOID.equals(OID_NOTICE_OF_DISCONNECTION)) { LocalizableMessage message = ERR_LDAPAUTH_SERVER_DISCONNECT. get(extendedResponse.getResultCode(), extendedResponse.getErrorMessage()); throw new LDAPException(extendedResponse.getResultCode(), message); } else { LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_EXTENDED_RESPONSE.get(extendedResponse); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } default: LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_RESPONSE.get(responseMessage1.getProtocolOp()); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } // Make sure that the bind response has the "SASL bind in progress" result // code. // Make sure that the bind response has the "SASL bind in progress" result code. BindResponseProtocolOp bindResponse1 = responseMessage1.getBindResponseProtocolOp(); int resultCode1 = bindResponse1.getResultCode(); @@ -1591,163 +1105,33 @@ // Generate the SASL credentials for the second bind request. StringBuilder credBuffer = new StringBuilder(); credBuffer.append("username=\""); credBuffer.append(authID); credBuffer.append("\""); credBuffer.append("username=\"").append(authID).append("\""); if (realm != null) { credBuffer.append(",realm=\""); credBuffer.append(realm); credBuffer.append("\""); credBuffer.append(",realm=\"").append(realm).append("\""); } credBuffer.append(",nonce=\""); credBuffer.append(nonce); credBuffer.append("\",cnonce=\""); credBuffer.append(cnonce); credBuffer.append("\",nc="); credBuffer.append(nonceCount); credBuffer.append(",qop="); credBuffer.append(qop); credBuffer.append(",digest-uri=\""); credBuffer.append(digestURI); credBuffer.append("\",response="); credBuffer.append(responseDigest); credBuffer.append(",nonce=\"").append(nonce); credBuffer.append("\",cnonce=\"").append(cnonce); credBuffer.append("\",nc=").append(nonceCount); credBuffer.append(",qop=").append(qop); credBuffer.append(",digest-uri=\"").append(digestURI); credBuffer.append("\",response=").append(responseDigest); if (useUTF8) { credBuffer.append(",charset=utf-8"); } if (authzID != null) { credBuffer.append(",authzid=\""); credBuffer.append(authzID); credBuffer.append("\""); credBuffer.append(",authzid=\"").append(authzID).append("\""); } sendSecondBindRequest(SASL_MECHANISM_DIGEST_MD5, bindDN, credBuffer.toString(), requestControls); // Generate and send the second bind request. BindRequestProtocolOp bindRequest2 = new BindRequestProtocolOp(bindDN.toByteString(), SASL_MECHANISM_DIGEST_MD5, ByteString.valueOfUtf8(credBuffer.toString())); LDAPMessage requestMessage2 = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest2, requestControls); try { writer.writeMessage(requestMessage2); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SECOND_SASL_BIND.get( SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SECOND_SASL_BIND.get( SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e); } // Read the response from the server. LDAPMessage responseMessage2; try { responseMessage2 = reader.readMessage(); if (responseMessage2 == null) { LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message); } } catch (DecodeException | LDAPException e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE.get( SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE.get( SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE.get( SASL_MECHANISM_DIGEST_MD5, getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } // See if there are any controls in the response. If so, then add them to // the response controls list. List<Control> respControls = responseMessage2.getControls(); if (respControls != null && ! respControls.isEmpty()) { responseControls.addAll(respControls); } // Look at the protocol op from the response. If it's a bind response, then // continue. If it's an extended response, then it could be a notice of // disconnection so check for that. Otherwise, generate an error. switch (responseMessage2.getProtocolOpType()) { case OP_TYPE_BIND_RESPONSE: // We'll deal with this later. break; case OP_TYPE_EXTENDED_RESPONSE: ExtendedResponseProtocolOp extendedResponse = responseMessage2.getExtendedResponseProtocolOp(); String responseOID = extendedResponse.getOID(); if (responseOID != null && responseOID.equals(OID_NOTICE_OF_DISCONNECTION)) { LocalizableMessage message = ERR_LDAPAUTH_SERVER_DISCONNECT. get(extendedResponse.getResultCode(), extendedResponse.getErrorMessage()); throw new LDAPException(extendedResponse.getResultCode(), message); } else { LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_EXTENDED_RESPONSE.get(extendedResponse); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } default: LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_RESPONSE.get(responseMessage2.getProtocolOp()); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } BindResponseProtocolOp bindResponse2 = responseMessage2.getBindResponseProtocolOp(); int resultCode2 = bindResponse2.getResultCode(); if (resultCode2 != ReturnCode.SUCCESS.get()) { // FIXME -- Add support for referrals. LocalizableMessage message = ERR_LDAPAUTH_SASL_BIND_FAILED.get(SASL_MECHANISM_DIGEST_MD5); throw new LDAPException(resultCode2, bindResponse2.getErrorMessage(), message, bindResponse2.getMatchedDN(), null); } LDAPMessage responseMessage2 = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_SECOND_BIND_RESPONSE, SASL_MECHANISM_DIGEST_MD5); responseControls.addAll(responseMessage2.getControls()); checkConnected(responseMessage2); BindResponseProtocolOp bindResponse2 = checkSuccessfulBind(responseMessage2, SASL_MECHANISM_DIGEST_MD5); // Make sure that the bind response included server SASL credentials with @@ -1802,12 +1186,34 @@ ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } // FIXME -- Need to look for things like password expiration warning, // reset notice, etc. // FIXME -- Need to look for things like password expiration warning, reset notice, etc. return null; } private void sendSecondBindRequest(String saslMechanism, ByteSequence bindDN, String saslCredentials, List<Control> requestControls) throws ClientException { // Generate and send the second bind request. BindRequestProtocolOp bindRequest2 = new BindRequestProtocolOp(bindDN.toByteString(), saslMechanism, ByteString.valueOfUtf8(saslCredentials)); LDAPMessage requestMessage2 = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest2, requestControls); try { writer.writeMessage(requestMessage2); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SECOND_SASL_BIND.get(saslMechanism, getExceptionMessage(ioe)); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SECOND_SASL_BIND.get(saslMechanism, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e); } } /** * Reads the next token from the provided credentials string using the @@ -1891,14 +1297,11 @@ { // If this is a quoted string, then this comma is part of the token. // Otherwise, it's the end of the token. if (isQuoted) { token.append(c); } else if (!isQuoted) { break; } token.append(c); } else if (c == '"') { @@ -1911,8 +1314,6 @@ // We have hit the end of the string, so this is fine. break; } else { char c2 = credentials.charAt(pos++); if (c2 == ',') { @@ -1921,13 +1322,9 @@ } else { // We found the closing quote before the end of the token. This // is not fine. LocalizableMessage message = ERR_LDAPAUTH_DIGESTMD5_INVALID_CLOSING_QUOTE_POS.get(pos-2); throw new LDAPException(ReturnCode.INVALID_CREDENTIALS.get(), message); } // We found the closing quote before the end of the token. This is not fine. LocalizableMessage message = ERR_LDAPAUTH_DIGESTMD5_INVALID_CLOSING_QUOTE_POS.get(pos - 2); throw new LDAPException(ReturnCode.INVALID_CREDENTIALS.get(), message); } } else @@ -2028,21 +1425,14 @@ } } // Get a hash of "username:realm:password". StringBuilder a1String1 = new StringBuilder(); a1String1.append(authID); a1String1.append(':'); a1String1.append((realm == null) ? "" : realm); a1String1.append(':'); byte[] a1Bytes1a = a1String1.toString().getBytes(charset); String a1String1 = authID + ':' + ((realm == null) ? "" : realm) + ':'; byte[] a1Bytes1a = a1String1.getBytes(charset); byte[] a1Bytes1 = new byte[a1Bytes1a.length + password.length()]; System.arraycopy(a1Bytes1a, 0, a1Bytes1, 0, a1Bytes1a.length); password.copyTo(a1Bytes1, a1Bytes1a.length); byte[] urpHash = md5Digest.digest(a1Bytes1); // Next, get a hash of "urpHash:nonce:cnonce[:authzid]". StringBuilder a1String2 = new StringBuilder(); a1String2.append(':'); @@ -2060,37 +1450,20 @@ System.arraycopy(a1Bytes2a, 0, a1Bytes2, urpHash.length, a1Bytes2a.length); byte[] a1Hash = md5Digest.digest(a1Bytes2); // Next, get a hash of "AUTHENTICATE:digesturi". byte[] a2Bytes = ("AUTHENTICATE:" + digestURI).getBytes(charset); byte[] a2Hash = md5Digest.digest(a2Bytes); // Get hex string representations of the last two hashes. String a1HashHex = getHexString(a1Hash); String a2HashHex = getHexString(a2Hash); // Put together the final string to hash, consisting of // "a1HashHex:nonce:nonceCount:cnonce:qop:a2HashHex" and get its digest. StringBuilder kdStr = new StringBuilder(); kdStr.append(a1HashHex); kdStr.append(':'); kdStr.append(nonce); kdStr.append(':'); kdStr.append(nonceCount); kdStr.append(':'); kdStr.append(cnonce); kdStr.append(':'); kdStr.append(qop); kdStr.append(':'); kdStr.append(a2HashHex); return getHexString(md5Digest.digest(kdStr.toString().getBytes(charset))); String kdStr = a1HashHex + ':' + nonce + ':' + nonceCount + ':' + cnonce + ':' + qop + ':' + a2HashHex; return getHexString(md5Digest.digest(kdStr.getBytes(charset))); } /** * Generates the appropriate DIGEST-MD5 rspauth digest using the provided * information. @@ -2118,7 +1491,7 @@ * @throws UnsupportedEncodingException If the specified character set is * invalid for some reason. */ public byte[] generateDigestMD5RspAuth(String authID, String authzID, private byte[] generateDigestMD5RspAuth(String authID, String authzID, ByteSequence password, String realm, String nonce, String cnonce, String nonceCount, String digestURI, @@ -2126,13 +1499,9 @@ throws UnsupportedEncodingException { // First, get a hash of "username:realm:password". StringBuilder a1String1 = new StringBuilder(); a1String1.append(authID); a1String1.append(':'); a1String1.append(realm); a1String1.append(':'); String a1String1 = authID + ':' + realm + ':'; byte[] a1Bytes1a = a1String1.toString().getBytes(charset); byte[] a1Bytes1a = a1String1.getBytes(charset); byte[] a1Bytes1 = new byte[a1Bytes1a.length + password.length()]; System.arraycopy(a1Bytes1a, 0, a1Bytes1, 0, a1Bytes1a.length); password.copyTo(a1Bytes1, a1Bytes1a.length); @@ -2172,26 +1541,12 @@ String a1HashHex = getHexString(a1Hash); String a2HashHex = getHexString(a2Hash); // Put together the final string to hash, consisting of // "a1HashHex:nonce:nonceCount:cnonce:qop:a2HashHex" and get its digest. StringBuilder kdStr = new StringBuilder(); kdStr.append(a1HashHex); kdStr.append(':'); kdStr.append(nonce); kdStr.append(':'); kdStr.append(nonceCount); kdStr.append(':'); kdStr.append(cnonce); kdStr.append(':'); kdStr.append(qop); kdStr.append(':'); kdStr.append(a2HashHex); return md5Digest.digest(kdStr.toString().getBytes(charset)); String kdStr = a1HashHex + ':' + nonce + ':' + nonceCount + ':' + cnonce + ':' + qop + ':' + a2HashHex; return md5Digest.digest(kdStr.getBytes(charset)); } /** * Retrieves a hexadecimal string representation of the contents of the * provided byte array. @@ -2224,7 +1579,7 @@ * SASL DIGEST-MD5 bind, mapped from the property names to their * corresponding descriptions. */ public static LinkedHashMap<String,LocalizableMessage> getSASLDigestMD5Properties() private static LinkedHashMap<String, LocalizableMessage> getSASLDigestMD5Properties() { LinkedHashMap<String,LocalizableMessage> properties = new LinkedHashMap<>(5); @@ -2285,111 +1640,11 @@ } // Construct the bind request and send it to the server. BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(bindDN.toByteString(), SASL_MECHANISM_EXTERNAL, null); LDAPMessage requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest, requestControls); sendBindRequest(SASL_MECHANISM_EXTERNAL, bindDN, null, requestControls); try { writer.writeMessage(requestMessage); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get( SASL_MECHANISM_EXTERNAL, getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get( SASL_MECHANISM_EXTERNAL, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e); } // Read the response from the server. LDAPMessage responseMessage; try { responseMessage = reader.readMessage(); if (responseMessage == null) { LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message); } } catch (DecodeException | LDAPException e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } // See if there are any controls in the response. If so, then add them to // the response controls list. List<Control> respControls = responseMessage.getControls(); if (respControls != null && ! respControls.isEmpty()) { responseControls.addAll(respControls); } // Look at the protocol op from the response. If it's a bind response, then // continue. If it's an extended response, then it could be a notice of // disconnection so check for that. Otherwise, generate an error. switch (responseMessage.getProtocolOpType()) { case OP_TYPE_BIND_RESPONSE: // We'll deal with this later. break; case OP_TYPE_EXTENDED_RESPONSE: ExtendedResponseProtocolOp extendedResponse = responseMessage.getExtendedResponseProtocolOp(); String responseOID = extendedResponse.getOID(); if (responseOID != null && responseOID.equals(OID_NOTICE_OF_DISCONNECTION)) { LocalizableMessage message = ERR_LDAPAUTH_SERVER_DISCONNECT. get(extendedResponse.getResultCode(), extendedResponse.getErrorMessage()); throw new LDAPException(extendedResponse.getResultCode(), message); } else { LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_EXTENDED_RESPONSE.get(extendedResponse); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } default: LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_RESPONSE.get(responseMessage.getProtocolOp()); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } LDAPMessage responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE); responseControls.addAll(responseMessage.getControls()); checkConnected(responseMessage); BindResponseProtocolOp bindResponse = responseMessage.getBindResponseProtocolOp(); @@ -2409,7 +1664,57 @@ message, bindResponse.getMatchedDN(), null); } private void sendBindRequest(String saslMechanism, ByteSequence bindDN, ByteString saslCredentials, List<Control> requestControls) throws ClientException { BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(bindDN.toByteString(), saslMechanism, saslCredentials); LDAPMessage requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest, requestControls); try { writer.writeMessage(requestMessage); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(saslMechanism, getExceptionMessage(ioe)); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get(saslMechanism, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e); } } private LDAPMessage readBindResponse(Arg1<Object> errCannotReadBindResponse) throws ClientException { try { LDAPMessage responseMessage = reader.readMessage(); if (responseMessage != null) { return responseMessage; } LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message); } catch (DecodeException | LDAPException e) { LocalizableMessage message = errCannotReadBindResponse.get(getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e); } catch (IOException ioe) { LocalizableMessage message = errCannotReadBindResponse.get(getExceptionMessage(ioe)); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = errCannotReadBindResponse.get(getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } } /** * Retrieves the set of properties that a client may provide when performing a @@ -2420,7 +1725,7 @@ * SASL EXTERNAL bind, mapped from the property names to their * corresponding descriptions. */ public static LinkedHashMap<String,LocalizableMessage> getSASLExternalProperties() private static LinkedHashMap<String, LocalizableMessage> getSASLExternalProperties() { // There are no properties for the SASL EXTERNAL mechanism. return new LinkedHashMap<>(0); @@ -2455,7 +1760,7 @@ * @throws LDAPException If the bind fails or some other server-side problem * occurs during processing. */ public String doSASLGSSAPI(ByteSequence bindDN, private String doSASLGSSAPI(ByteSequence bindDN, ByteSequence bindPassword, Map<String,List<String>> saslProperties, List<Control> requestControls, @@ -2469,16 +1774,7 @@ gssapiAuthID = null; gssapiAuthzID = null; gssapiQoP = "auth"; if (bindPassword == null) { gssapiAuthPW = null; } else { gssapiAuthPW = bindPassword.toString().toCharArray(); } gssapiAuthPW = bindPassword != null ? bindPassword.toString().toCharArray() : null; // Evaluate the properties provided. The authID is required. The authzID, // KDC, QoP, and realm are optional. @@ -2490,60 +1786,26 @@ ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } for (String name : saslProperties.keySet()) for (Entry<String, List<String>> entry : saslProperties.entrySet()) { String name = entry.getKey(); String lowerName = toLowerCase(name); List<String> values = entry.getValue(); if (lowerName.equals(SASL_PROPERTY_AUTHID)) { List<String> values = saslProperties.get(name); Iterator<String> iterator = values.iterator(); if (iterator.hasNext()) { gssapiAuthID = iterator.next(); if (iterator.hasNext()) { LocalizableMessage message = ERR_LDAPAUTH_AUTHID_SINGLE_VALUED.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } } gssapiAuthID = getSingleValue(values, ERR_LDAPAUTH_AUTHID_SINGLE_VALUED); } else if (lowerName.equals(SASL_PROPERTY_AUTHZID)) { List<String> values = saslProperties.get(name); Iterator<String> iterator = values.iterator(); if (iterator.hasNext()) { gssapiAuthzID = iterator.next(); if (iterator.hasNext()) { LocalizableMessage message = ERR_LDAPAUTH_AUTHZID_SINGLE_VALUED.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } } gssapiAuthzID = getSingleValue(values, ERR_LDAPAUTH_AUTHZID_SINGLE_VALUED); } else if (lowerName.equals(SASL_PROPERTY_KDC)) { List<String> values = saslProperties.get(name); Iterator<String> iterator = values.iterator(); if (iterator.hasNext()) { kdc = iterator.next(); if (iterator.hasNext()) { LocalizableMessage message = ERR_LDAPAUTH_KDC_SINGLE_VALUED.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } } kdc = getSingleValue(values, ERR_LDAPAUTH_KDC_SINGLE_VALUED); } else if (lowerName.equals(SASL_PROPERTY_QOP)) { List<String> values = saslProperties.get(name); Iterator<String> iterator = values.iterator(); if (iterator.hasNext()) { @@ -2580,19 +1842,7 @@ } else if (lowerName.equals(SASL_PROPERTY_REALM)) { List<String> values = saslProperties.get(name); Iterator<String> iterator = values.iterator(); if (iterator.hasNext()) { realm = iterator.next(); if (iterator.hasNext()) { LocalizableMessage message = ERR_LDAPAUTH_REALM_SINGLE_VALUED.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } } realm = getSingleValue(values, ERR_LDAPAUTH_REALM_SINGLE_VALUED); } else { @@ -2645,8 +1895,7 @@ File tempFile = File.createTempFile("login", "conf"); configFileName = tempFile.getAbsolutePath(); tempFile.deleteOnExit(); BufferedWriter w = new BufferedWriter(new FileWriter(tempFile, false)); try (BufferedWriter w = new BufferedWriter(new FileWriter(tempFile, false))) { w.write(getClass().getName() + " {"); w.newLine(); @@ -2656,9 +1905,7 @@ w.write("};"); w.newLine(); w.flush(); w.close(); } } catch (Exception e) { @@ -2710,13 +1957,25 @@ } // FIXME -- Need to make sure we handle request and response controls // properly, and also check for any possible message to send back to the // client. // FIXME -- Need to make sure we handle request and response controls properly, // and also check for any possible message to send back to the client. return null; } private String getSingleValue(List<String> values, Arg0 singleValuedErrMsg) throws ClientException { Iterator<String> it = values.iterator(); if (it.hasNext()) { String result = it.next(); if (it.hasNext()) { throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, singleValuedErrMsg.get()); } return result; } return null; } /** * Retrieves the set of properties that a client may provide when performing a @@ -2727,7 +1986,7 @@ * SASL EXTERNAL bind, mapped from the property names to their * corresponding descriptions. */ public static LinkedHashMap<String,LocalizableMessage> getSASLGSSAPIProperties() private static LinkedHashMap<String, LocalizableMessage> getSASLGSSAPIProperties() { LinkedHashMap<String,LocalizableMessage> properties = new LinkedHashMap<>(4); @@ -2791,29 +2050,19 @@ ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } for (String name : saslProperties.keySet()) for (Entry<String, List<String>> entry : saslProperties.entrySet()) { String name = entry.getKey(); List<String> values = entry.getValue(); String lowerName = toLowerCase(name); if (lowerName.equals(SASL_PROPERTY_AUTHID)) { authID = getAuthID(saslProperties, authID, name); authID = getSingleValue(values, ERR_LDAPAUTH_AUTHID_SINGLE_VALUED); } else if (lowerName.equals(SASL_PROPERTY_AUTHZID)) { List<String> values = saslProperties.get(name); Iterator<String> iterator = values.iterator(); if (iterator.hasNext()) { authzID = iterator.next(); if (iterator.hasNext()) { LocalizableMessage message = ERR_LDAPAUTH_AUTHZID_SINGLE_VALUED.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_PARAM_ERROR, message); } } authzID = getSingleValue(values, ERR_LDAPAUTH_AUTHZID_SINGLE_VALUED); } else { @@ -2841,116 +2090,17 @@ bindPassword = ByteString.empty(); } // Construct the bind request and send it to the server. StringBuilder credBuffer = new StringBuilder(); if (authzID != null) { credBuffer.append(authzID); } credBuffer.append('\u0000'); credBuffer.append(authID); credBuffer.append('\u0000'); credBuffer.append(bindPassword.toString()); String saslCredentials = (authzID != null ? authzID : "") + '\u0000' + authID + '\u0000' + bindPassword; sendBindRequest(SASL_MECHANISM_PLAIN, bindDN, ByteString.valueOfUtf8(saslCredentials), requestControls); ByteString saslCredentials = ByteString.valueOfUtf8(credBuffer.toString()); BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(bindDN.toByteString(), SASL_MECHANISM_PLAIN, saslCredentials); LDAPMessage requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest, requestControls); try { writer.writeMessage(requestMessage); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get( SASL_MECHANISM_PLAIN, getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get( SASL_MECHANISM_PLAIN, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e); } // Read the response from the server. LDAPMessage responseMessage; try { responseMessage = reader.readMessage(); if (responseMessage == null) { LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message); } } catch (DecodeException | LDAPException e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } // See if there are any controls in the response. If so, then add them to // the response controls list. List<Control> respControls = responseMessage.getControls(); if (respControls != null && !respControls.isEmpty()) { responseControls.addAll(respControls); } // Look at the protocol op from the response. If it's a bind response, then // continue. If it's an extended response, then it could be a notice of // disconnection so check for that. Otherwise, generate an error. generateError(responseMessage); BindResponseProtocolOp bindResponse = responseMessage.getBindResponseProtocolOp(); int resultCode = bindResponse.getResultCode(); if (resultCode == ReturnCode.SUCCESS.get()) { // FIXME -- Need to look for things like password expiration warning, // reset notice, etc. LDAPMessage responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE); responseControls.addAll(responseMessage.getControls()); checkConnected(responseMessage); checkSuccessfulBind(responseMessage, SASL_MECHANISM_PLAIN); return null; } // FIXME -- Add support for referrals. LocalizableMessage message = ERR_LDAPAUTH_SASL_BIND_FAILED.get(SASL_MECHANISM_PLAIN); throw new LDAPException(resultCode, bindResponse.getErrorMessage(), message, bindResponse.getMatchedDN(), null); } /** * Retrieves the set of properties that a client may provide when performing a * SASL PLAIN bind, mapped from the property names to their corresponding @@ -2960,7 +2110,7 @@ * SASL PLAIN bind, mapped from the property names to their * corresponding descriptions. */ public static LinkedHashMap<String,LocalizableMessage> getSASLPlainProperties() private static LinkedHashMap<String, LocalizableMessage> getSASLPlainProperties() { LinkedHashMap<String,LocalizableMessage> properties = new LinkedHashMap<>(2); @@ -2988,8 +2138,7 @@ * processing. */ @Override public Object run() throws ClientException, LDAPException public Object run() throws ClientException, LDAPException { if (saslMechanism == null) { @@ -2999,8 +2148,21 @@ } else if (saslMechanism.equals(SASL_MECHANISM_GSSAPI)) { doSASLGSSAPI2(); return null; } else { LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_RUN_INVOCATION.get( saslMechanism, getBacktrace()); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } } private void doSASLGSSAPI2() throws ClientException, LDAPException { // Create the property map that will be used by the internal SASL handler. HashMap<String,String> saslProperties = new HashMap<>(); Map<String, String> saslProperties = new HashMap<>(); saslProperties.put(Sasl.QOP, gssapiQoP); saslProperties.put(Sasl.SERVER_AUTH, "true"); @@ -3023,101 +2185,13 @@ ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } // Get the SASL credentials to include in the initial bind request. ByteString saslCredentials; if (saslClient.hasInitialResponse()) { try { byte[] credBytes = saslClient.evaluateChallenge(new byte[0]); saslCredentials = ByteString.wrap(credBytes); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_CANNOT_CREATE_INITIAL_CHALLENGE. get(getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } } else { saslCredentials = null; } BindRequestProtocolOp bindRequest = new BindRequestProtocolOp(gssapiBindDN.toByteString(), SASL_MECHANISM_GSSAPI, saslCredentials); // FIXME -- Add controls here? LDAPMessage requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest); ByteString saslCredentials = getSaslCredentialsForInitialBind(saslClient); sendBindRequest(SASL_MECHANISM_GSSAPI, gssapiBindDN, saslCredentials, null); try { writer.writeMessage(requestMessage); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get( SASL_MECHANISM_GSSAPI, getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get( SASL_MECHANISM_GSSAPI, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e); } // Read the response from the server. LDAPMessage responseMessage; try { responseMessage = reader.readMessage(); if (responseMessage == null) { LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message); } } catch (DecodeException | LDAPException e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get( getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } LDAPMessage responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE); // FIXME -- Handle response controls. // Look at the protocol op from the response. If it's a bind response, // then continue. If it's an extended response, then it could be a notice // of disconnection so check for that. Otherwise, generate an error. generateError(responseMessage); checkConnected(responseMessage); while (true) { @@ -3126,137 +2200,18 @@ int resultCode = bindResponse.getResultCode(); if (resultCode == ReturnCode.SUCCESS.get()) { // We should be done after this, but we still need to look for and // handle the server SASL credentials. ByteString serverSASLCredentials = bindResponse.getServerSASLCredentials(); if (serverSASLCredentials != null) { try { saslClient.evaluateChallenge(serverSASLCredentials.toByteArray()); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_CANNOT_VALIDATE_SERVER_CREDS. get(getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } } // Just to be sure, check that the login really is complete. if (! saslClient.isComplete()) { LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_UNEXPECTED_SUCCESS_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } evaluateGSSAPIChallenge(saslClient, bindResponse); break; } else if (resultCode == ReturnCode.SASL_BIND_IN_PROGRESS.get()) { // Read the response and process the server SASL credentials. ByteString serverSASLCredentials = bindResponse.getServerSASLCredentials(); byte[] credBytes; try { if (serverSASLCredentials == null) { credBytes = saslClient.evaluateChallenge(new byte[0]); } else { credBytes = saslClient.evaluateChallenge( serverSASLCredentials.toByteArray()); } } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_CANNOT_VALIDATE_SERVER_CREDS. get(getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } // Send the next bind in the sequence to the server. bindRequest = new BindRequestProtocolOp(gssapiBindDN.toByteString(), SASL_MECHANISM_GSSAPI, ByteString.wrap(credBytes)); // FIXME -- Add controls here? requestMessage = new LDAPMessage(nextMessageID.getAndIncrement(), bindRequest); ByteString credBytes = evaluateSaslChallenge(saslClient, bindResponse); sendBindRequest(SASL_MECHANISM_GSSAPI, gssapiBindDN, credBytes, null); try { writer.writeMessage(requestMessage); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get( SASL_MECHANISM_GSSAPI, getExceptionMessage(ioe)); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_SEND_SASL_BIND.get( SASL_MECHANISM_GSSAPI, getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_ENCODING_ERROR, message, e); } // Read the response from the server. try { responseMessage = reader.readMessage(); if (responseMessage == null) { LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message); } } catch (DecodeException | LDAPException e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get(getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get( getExceptionMessage(ioe)); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE.get( getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_BIND_RESPONSE); // FIXME -- Handle response controls. // Look at the protocol op from the response. If it's a bind // response, then continue. If it's an extended response, then it // could be a notice of disconnection so check for that. Otherwise, // generate an error. generateError(responseMessage); checkConnected(responseMessage); } else { @@ -3267,22 +2222,77 @@ null); } } // FIXME -- Need to look for things like password expiration warning, reset notice, etc. } else private void evaluateGSSAPIChallenge(SaslClient saslClient, BindResponseProtocolOp bindResponse) throws ClientException { LocalizableMessage message = ERR_LDAPAUTH_UNEXPECTED_RUN_INVOCATION.get( saslMechanism, getBacktrace()); throw new ClientException( ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); // We should be done after this, but we still need to look for and // handle the server SASL credentials. ByteString serverSASLCredentials = bindResponse.getServerSASLCredentials(); if (serverSASLCredentials != null) { try { saslClient.evaluateChallenge(serverSASLCredentials.toByteArray()); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_CANNOT_VALIDATE_SERVER_CREDS.get(getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } } // Just to be sure, check that the login really is complete. if (!saslClient.isComplete()) { LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_UNEXPECTED_SUCCESS_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message); } } // FIXME -- Need to look for things like password expiration warning, reset // notice, etc. private ByteString evaluateSaslChallenge(SaslClient saslClient, BindResponseProtocolOp bindResponse) throws ClientException { try { ByteString saslCredentials = bindResponse.getServerSASLCredentials(); byte[] bs = saslCredentials != null ? saslCredentials.toByteArray() : new byte[0]; return ByteString.wrap(saslClient.evaluateChallenge(bs)); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_CANNOT_VALIDATE_SERVER_CREDS.get(getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } } private ByteString getSaslCredentialsForInitialBind(SaslClient saslClient) throws ClientException { if (saslClient.hasInitialResponse()) { try { return ByteString.wrap(saslClient.evaluateChallenge(new byte[0])); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_GSSAPI_CANNOT_CREATE_INITIAL_CHALLENGE.get(getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } } return null; } private void generateError(LDAPMessage responseMessage) throws LDAPException, ClientException /** * Look at the protocol op from the response. * If it's a bind response, then continue. * If it's an extended response, then check it is not a notice of disconnection. * Otherwise, generate an error. */ private void checkConnected(LDAPMessage responseMessage) throws LDAPException, ClientException { switch (responseMessage.getProtocolOpType()) { @@ -3417,40 +2427,7 @@ } // Read the response from the server. LDAPMessage responseMessage; try { responseMessage = reader.readMessage(); if (responseMessage == null) { LocalizableMessage message = ERR_LDAPAUTH_CONNECTION_CLOSED_WITHOUT_BIND_RESPONSE.get(); throw new ClientException(ReturnCode.CLIENT_SIDE_SERVER_DOWN, message); } } catch (DecodeException | LDAPException e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_WHOAMI_RESPONSE.get(getExceptionMessage(e)); throw new ClientException(ReturnCode.CLIENT_SIDE_DECODING_ERROR, message, e); } catch (IOException ioe) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_WHOAMI_RESPONSE.get( getExceptionMessage(ioe)); throw new ClientException( ReturnCode.CLIENT_SIDE_SERVER_DOWN, message, ioe); } catch (Exception e) { LocalizableMessage message = ERR_LDAPAUTH_CANNOT_READ_WHOAMI_RESPONSE.get(getExceptionMessage(e)); throw new ClientException( ReturnCode.CLIENT_SIDE_LOCAL_ERROR, message, e); } LDAPMessage responseMessage = readBindResponse(ERR_LDAPAUTH_CANNOT_READ_WHOAMI_RESPONSE); // If the protocol op isn't an extended response, then that's a problem. if (responseMessage.getProtocolOpType() != OP_TYPE_EXTENDED_RESPONSE) @@ -3493,13 +2470,10 @@ return null; } String valueString = authzID.toString(); if (valueString == null || valueString.length() == 0 || valueString.equalsIgnoreCase("dn:")) if (!"dn:".equalsIgnoreCase(authzID.toString())) { return null; } return authzID; } return null; } } opendj-server-legacy/src/main/java/org/opends/server/tools/LDAPPasswordModify.java
@@ -29,7 +29,6 @@ import java.io.OutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import org.forgerock.i18n.LocalizableMessage; @@ -654,10 +653,7 @@ // See if the response included any controls that we recognize, and if so // then handle them. List<Control> responseControls = responseMessage.getControls(); if (responseControls != null) { for (Control c : responseControls) for (Control c : responseMessage.getControls()) { if (c.getOID().equals(OID_PASSWORD_POLICY_CONTROL)) { @@ -667,16 +663,14 @@ PasswordPolicyResponseControl.DECODER .decode(c.isCritical(), ((LDAPControl) c).getValue()); PasswordPolicyWarningType pwPolicyWarningType = pwPolicyControl.getWarningType(); PasswordPolicyWarningType pwPolicyWarningType = pwPolicyControl.getWarningType(); if (pwPolicyWarningType != null) { printWrappedText( out, INFO_LDAPPWMOD_PWPOLICY_WARNING.get(pwPolicyWarningType, pwPolicyControl.getWarningValue())); } PasswordPolicyErrorType pwPolicyErrorType = pwPolicyControl.getErrorType(); PasswordPolicyErrorType pwPolicyErrorType = pwPolicyControl.getErrorType(); if (pwPolicyErrorType != null) { printWrappedText(out, INFO_LDAPPWMOD_PWPOLICY_ERROR.get(pwPolicyErrorType)); @@ -688,7 +682,6 @@ } } } } // See if the response included a generated password. ByteString responseValue = extendedResponse.getValue(); opendj-server-legacy/src/test/java/org/opends/server/tools/LDAPAuthenticationHandlerTestCase.java
@@ -31,7 +31,6 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import org.forgerock.i18n.LocalizableMessage; import org.forgerock.opendj.ldap.ByteString; import org.opends.server.TestCaseUtils; import org.opends.server.api.SASLMechanismHandler; @@ -46,9 +45,7 @@ import com.forgerock.opendj.cli.ClientException; /** * A set of test cases for the LDAP authentication handler. */ /** A set of test cases for the LDAP authentication handler. */ public class LDAPAuthenticationHandlerTestCase extends ToolsTestCase { @@ -67,8 +64,6 @@ getFQDN(); } /** * Retrieves the names of the supported SASL mechanisms. * @@ -88,8 +83,6 @@ }; } /** * Tests the <CODE>getSupportedSASLMechanisms</CODE> method. * @@ -114,29 +107,16 @@ @Test(dataProvider = "saslMechanisms") public void testGetSASLProperties(String saslMechanismName) { LinkedHashMap<String, LocalizableMessage> properties = LDAPAuthenticationHandler.getSASLProperties(saslMechanismName); assertNotNull(properties); assertNotNull(LDAPAuthenticationHandler.getSASLProperties(saslMechanismName)); } /** * Tests the <CODE>getSASLProperties</CODE> method with an unsupported * mechanism name. */ /** Tests the <CODE>getSASLProperties</CODE> method with an unsupported mechanism name. */ @Test public void testGetSASLPropertiesInvlaid() public void testGetSASLPropertiesInvalid() { LinkedHashMap<String,LocalizableMessage> properties = LDAPAuthenticationHandler.getSASLProperties("unsupportedMechanism"); assertNull(properties); assertNull(LDAPAuthenticationHandler.getSASLProperties("unsupportedMechanism")); } /** * Tests the <CODE>doSimpleBind</CODE> method with a valid DN and password and * with no request controls. @@ -147,8 +127,8 @@ public void testDoSimpleBindWithValidDNAndPWNoControls() throws Exception { ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); try (Socket s = newSocket()) { LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost"); @@ -157,8 +137,6 @@ } } /** * Tests the <CODE>doSimpleBind</CODE> method with a null DN and password and * no request controls. @@ -169,8 +147,8 @@ public void testDoSimpleBindWithNullDNAndPWNoControls() throws Exception { ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); try (Socket s = newSocket()) { LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost"); @@ -178,8 +156,6 @@ } } /** * Tests the <CODE>doSimpleBind</CODE> method with an empty DN and password * and no request controls. @@ -190,8 +166,8 @@ public void testDoSimpleBindWithEmptyDNAndPWNoControls() throws Exception { ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); try (Socket s = newSocket()) { LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost"); @@ -199,20 +175,18 @@ } } /** * Tests the <CODE>doSimpleBind</CODE> method with an valid DN but no * password. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSimpleBindWithDNButNoPassword() throws Exception { ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); try (Socket s = newSocket()) { @@ -223,20 +197,18 @@ } } /** * Tests the <CODE>doSimpleBind</CODE> method with an valid DN but an invalid * password. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSimpleBindWithDNButInvalidPassword() throws Exception { ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); try (Socket s = newSocket()) { @@ -247,8 +219,6 @@ } } /** * Tests the <CODE>doSimpleBind</CODE> method with the password policy * request control. @@ -259,8 +229,8 @@ public void testDoSimpleBindWithPasswordPolicyControl() throws Exception { ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); requestControls.add(new PasswordPolicyRequestControl()); try (Socket s = newSocket()) { @@ -270,20 +240,18 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method with a null mechanism. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindNullMechanism() throws Exception { ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); try (Socket s = newSocket()) { @@ -292,20 +260,18 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method with an empty mechanism. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindEmptyMechanism() throws Exception { ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); try (Socket s = newSocket()) { @@ -314,20 +280,18 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method with an invalid mechanism. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindInvalidMechanism() throws Exception { ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); try (Socket s = newSocket()) { @@ -337,19 +301,17 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which ANONYMOUS * authentication is disabled in the server. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindAnonymousDisabled() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("trace", newArrayList("testDoSASLBindAnonymousDisabled")); try (Socket s = newSocket()) @@ -359,8 +321,6 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which ANONYMOUS * authentication is enabled in the server. @@ -374,7 +334,7 @@ AnonymousSASLMechanismHandler handler = new AnonymousSASLMechanismHandler(); handler.initializeSASLMechanismHandler(null); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("trace", newArrayList("testDoSASLBindAnonymous")); try (Socket s = newSocket()) @@ -399,7 +359,7 @@ AnonymousSASLMechanismHandler handler = new AnonymousSASLMechanismHandler(); handler.initializeSASLMechanismHandler(null); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); try (Socket s = newSocket()) { LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost"); @@ -408,8 +368,6 @@ handler.finalizeSASLMechanismHandler(); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which ANONYMOUS * authentication is enabled in the server and multiple trace values are @@ -417,14 +375,14 @@ * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindAnonymousMultivaluedTrace() throws Exception { AnonymousSASLMechanismHandler handler = new AnonymousSASLMechanismHandler(); handler.initializeSASLMechanismHandler(null); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("trace", newArrayList("testDoSASLBindAnonymousMultivaluedTrace", "aSecondTraceStringWhichIsInvalid")); @@ -439,8 +397,6 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which ANONYMOUS * authentication is enabled in the server and an invalid SASL property is @@ -448,14 +404,14 @@ * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindAnonymousInvalidProperty() throws Exception { AnonymousSASLMechanismHandler handler = new AnonymousSASLMechanismHandler(); handler.initializeSASLMechanismHandler(null); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("invalid", newArrayList("testDoSASLBindAnonymousInvalidProperty")); try (Socket s = newSocket()) @@ -469,8 +425,6 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which ANONYMOUS * authentication is enabled in the server and the request includes the @@ -485,10 +439,10 @@ AnonymousSASLMechanismHandler handler = new AnonymousSASLMechanismHandler(); handler.initializeSASLMechanismHandler(null); ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); requestControls.add(new PasswordPolicyRequestControl()); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("trace", newArrayList("testDoSASLBindAnonymous")); try (Socket s = newSocket()) { @@ -499,15 +453,13 @@ handler.finalizeSASLMechanismHandler(); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which CRAM-MD5 * authentication is disabled in the server. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindCRAMMD5Disabled() throws Exception { @@ -530,8 +482,7 @@ DirectoryServer.getSASLMechanismHandler("CRAM-MD5"); DirectoryServer.deregisterSASLMechanismHandler("CRAM-MD5"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); try @@ -544,8 +495,6 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which CRAM-MD5 * authentication is enabled in the server. @@ -571,61 +520,54 @@ "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," + "cn=Password Policies,cn=config"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); cramMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in * which an authID was provided that doesn't map to any user. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindCRAMMD5InvalidAuthID() throws Exception { TestCaseUtils.initializeTestBackend(true); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); cramMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in * which an empty authID was provided. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindCRAMMD5EmptyAuthID() throws Exception { TestCaseUtils.initializeTestBackend(true); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("")); cramMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in * which the provided password was incorrect. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindCRAMMD5InvalidPassword() throws Exception { @@ -644,8 +586,7 @@ "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," + "cn=Password Policies,cn=config"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); try (Socket s = newSocket()) @@ -655,15 +596,13 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in * which the specified user doesn't have a reversible password. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindCRAMMD5NoReversiblePassword() throws Exception { @@ -680,61 +619,55 @@ "cn: Test User", "userPassword: password"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); cramMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in * which the provided SASL properties were null. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindCRAMMD5NullProperties() throws Exception { LinkedHashMap<String,List<String>> saslProperties = null; Map<String, List<String>> saslProperties = null; cramMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in * which the provided SASL properties were empty. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindCRAMMD5EmptyProperties() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); cramMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method using CRAM-MD5 for the case in * which multiple authID values were provided * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindCRAMMD5MultipleAuthIDs() throws Exception { TestCaseUtils.initializeTestBackend(true); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test", "u:test.user")); cramMd5SaslBind(saslProperties); @@ -746,21 +679,19 @@ * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindCRAMMD5InvalidSASLProperty() throws Exception { TestCaseUtils.initializeTestBackend(true); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); saslProperties.put("invalid", newArrayList("foo")); cramMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which CRAM-MD5 * authentication is enabled in the server and the password policy request @@ -787,11 +718,10 @@ "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," + "cn=Password Policies,cn=config"); ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); requestControls.add(new PasswordPolicyRequestControl()); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); try (Socket s = newSocket()) { @@ -802,15 +732,13 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which DIGEST-MD5 * authentication is disabled in the server. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindDigestMD5Disabled() throws Exception { @@ -829,13 +757,11 @@ "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," + "cn=Password Policies,cn=config"); SASLMechanismHandler<?> digestMD5Handler = DirectoryServer.getSASLMechanismHandler("DIGEST-MD5"); DirectoryServer.deregisterSASLMechanismHandler("DIGEST-MD5"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); saslProperties.put("realm", newArrayList("o=test")); @@ -850,8 +776,6 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which DIGEST-MD5 * authentication is enabled in the server. @@ -877,8 +801,7 @@ "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," + "cn=Password Policies,cn=config"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); try (Socket s = newSocket()) @@ -888,8 +811,6 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which DIGEST-MD5 * authentication is enabled in the server and an authz ID was provided. @@ -915,8 +836,7 @@ "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," + "cn=Password Policies,cn=config"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); try (Socket s = newSocket()) @@ -926,119 +846,104 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties are <CODE>null</CODE>. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindDigestMD5NullProperties() throws Exception { LinkedHashMap<String,List<String>> saslProperties = null; Map<String, List<String>> saslProperties = null; digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties are empty. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindDigestMD5EmptyProperties() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties contain an invalid property. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindDigestMD5InvalidProperty() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("invalid", newArrayList("foo")); digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties contain multiple values for the authID property. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindDigestMD5MultipleAuthIDs() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); ArrayList<String> propList = newArrayList("dn:uid=test.user,o=test"); List<String> propList = newArrayList("dn:uid=test.user,o=test"); propList.add("u:test.user"); saslProperties.put("authid", propList); digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties contain an empty authID. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindDigestMD5MEmptyAuthID() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("")); digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties contain multiple values for the realm property. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindDigestMD5MultipleRealms() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); saslProperties.put("realm", newArrayList("o=test", "dc=example,dc=com")); digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties contain a valid quality of protection. @@ -1064,8 +969,7 @@ "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," + "cn=Password Policies,cn=config"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); saslProperties.put("qop", newArrayList("auth")); @@ -1083,11 +987,11 @@ * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindDigestMD5UnsupportedQoPAuthInt() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); saslProperties.put("realm", newArrayList("o=test")); saslProperties.put("qop", newArrayList("auth-int")); @@ -1095,8 +999,6 @@ digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties contain the unsupported confidentiality quality @@ -1104,11 +1006,11 @@ * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindDigestMD5UnsupportedQoPAuthConf() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); saslProperties.put("realm", newArrayList("o=test")); saslProperties.put("qop", newArrayList("auth-conf")); @@ -1116,19 +1018,17 @@ digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties contain an invalid quality of protection. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindDigestMD5InvalidQoP() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); saslProperties.put("realm", newArrayList("o=test")); saslProperties.put("qop", newArrayList("invalid")); @@ -1136,18 +1036,17 @@ digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties contain multiple quality of protection values. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindDigestMD5MultipleQoPs() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); saslProperties.put("realm", newArrayList("o=test")); saslProperties.put("qop", newArrayList("auth", "auth-int", "auth-conf")); @@ -1155,19 +1054,17 @@ digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties contain multiple digest URIs. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindDigestMD5MultipleDigestURIs() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); saslProperties.put("realm", newArrayList("o=test")); saslProperties.put("digest-uri", newArrayList("ldap/value1", "ldap/value2")); @@ -1175,18 +1072,17 @@ digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties contain multiple authorization IDs. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindDigestMD5MultipleAuthzIDs() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); saslProperties.put("realm", newArrayList("o=test")); saslProperties.put("authzid", newArrayList("dn:uid=test.user,o=test", "u:test.user")); @@ -1194,55 +1090,49 @@ digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties contain an invalid auth ID in the DN form. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindDigestMD5InvalidAuthDN() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:invalid")); saslProperties.put("realm", newArrayList("o=test")); digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the * DIGEST-MD5 SASL properties contain an auth ID that doesn't map to any user. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindDigestMD5NonExistentAuthID() throws Exception { TestCaseUtils.initializeTestBackend(true); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("u:nosuchuser")); saslProperties.put("realm", newArrayList("o=test")); digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which an invalid * password was provided. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindDigestMD5InvalidPassword() throws Exception { @@ -1261,8 +1151,7 @@ "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," + "cn=Password Policies,cn=config"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("u:nosuchuser")); saslProperties.put("realm", newArrayList("o=test")); @@ -1273,15 +1162,13 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the target * user does not have a reversible password. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindDigestMD5NoReversiblePassword() throws Exception { @@ -1298,16 +1185,13 @@ "cn: Test User", "userPassword: password"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("u:nosuchuser")); saslProperties.put("realm", newArrayList("o=test")); digestMd5SaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which DIGEST-MD5 * authentication is enabled in the server and the password policy request @@ -1334,11 +1218,10 @@ "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," + "cn=Password Policies,cn=config"); ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); requestControls.add(new PasswordPolicyRequestControl()); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); try (Socket s = newSocket()) @@ -1349,15 +1232,13 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which EXTERNAL * authentication is not enabled in the server. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindExternalDisabled() throws Exception { @@ -1373,24 +1254,20 @@ "sn: User", "cn: Test User"); SASLMechanismHandler<?> externalHandler = DirectoryServer.getSASLMechanismHandler("EXTERNAL"); DirectoryServer.deregisterSASLMechanismHandler("EXTERNAL"); String keyStorePath = DirectoryServer.getInstanceRoot() + File.separator + "config" + File.separator + "client.keystore"; String trustStorePath = DirectoryServer.getInstanceRoot() + File.separator + "config" + File.separator + "client.truststore"; SSLConnectionFactory factory = new SSLConnectionFactory(); factory.init(false, keyStorePath, "password", "client-cert", trustStorePath, "password"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); try (Socket s = factory.createSocket("127.0.0.1", TestCaseUtils.getServerLdapsPort())) { LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost"); @@ -1402,8 +1279,6 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which EXTERNAL * authentication is enabled in the server. @@ -1426,35 +1301,30 @@ "sn: User", "cn: Test User"); String keyStorePath = DirectoryServer.getInstanceRoot() + File.separator + "config" + File.separator + "client.keystore"; String trustStorePath = DirectoryServer.getInstanceRoot() + File.separator + "config" + File.separator + "client.truststore"; SSLConnectionFactory factory = new SSLConnectionFactory(); factory.init(false, keyStorePath, "password", "client-cert", trustStorePath, "password"); try (Socket s = factory.createSocket("127.0.0.1", TestCaseUtils.getServerLdapsPort())) { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost"); doSASLBind("EXTERNAL", null, authHandler, saslProperties); } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in the EXTERNAL SASL * properties were not empty. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindExternalInvalidProperties() throws Exception { @@ -1470,27 +1340,23 @@ "sn: User", "cn: Test User"); SASLMechanismHandler<?> externalHandler = DirectoryServer.getSASLMechanismHandler("EXTERNAL"); DirectoryServer.deregisterSASLMechanismHandler("EXTERNAL"); String keyStorePath = DirectoryServer.getInstanceRoot() + File.separator + "config" + File.separator + "client.keystore"; String trustStorePath = DirectoryServer.getInstanceRoot() + File.separator + "config" + File.separator + "client.truststore"; SSLConnectionFactory factory = new SSLConnectionFactory(); factory.init(false, keyStorePath, "password", "client-cert", trustStorePath, "password"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("invalid", newArrayList("foo")); try (Socket s = factory.createSocket("127.0.0.1", TestCaseUtils.getServerLdapsPort());) try (Socket s = factory.createSocket("127.0.0.1", TestCaseUtils.getServerLdapsPort())) { LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost"); doSASLBind("EXTERNAL", null, authHandler, saslProperties); @@ -1524,22 +1390,19 @@ "sn: User", "cn: Test User"); String keyStorePath = DirectoryServer.getInstanceRoot() + File.separator + "config" + File.separator + "client.keystore"; String trustStorePath = DirectoryServer.getInstanceRoot() + File.separator + "config" + File.separator + "client.truststore"; SSLConnectionFactory factory = new SSLConnectionFactory(); factory.init(false, keyStorePath, "password", "client-cert", trustStorePath, "password"); ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); requestControls.add(new PasswordPolicyRequestControl()); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); try (Socket s = factory.createSocket("127.0.0.1", TestCaseUtils.getServerLdapsPort())) { LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost"); @@ -1548,36 +1411,32 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the * provided properties list was null. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindGSSAPINullProperties() throws Exception { LinkedHashMap<String,List<String>> saslProperties = null; Map<String, List<String>> saslProperties = null; gssapiSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the * provided properties list was empty. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindGSSAPIEmptyProperties() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); gssapiSaslBind(saslProperties); } @@ -1641,7 +1500,7 @@ } } private void cramMd5SaslBind(LinkedHashMap<String, List<String>> saslProperties) throws Exception private void cramMd5SaslBind(Map<String, List<String>> saslProperties) throws Exception { try (Socket s = newSocket()) { @@ -1649,7 +1508,7 @@ } } private void digestMd5SaslBind(LinkedHashMap<String, List<String>> saslProperties) throws Exception private void digestMd5SaslBind(Map<String, List<String>> saslProperties) throws Exception { try (Socket s = newSocket()) { @@ -1657,7 +1516,7 @@ } } private void gssapiSaslBind(LinkedHashMap<String, List<String>> saslProperties) throws Exception private void gssapiSaslBind(Map<String, List<String>> saslProperties) throws Exception { try (Socket s = newSocket()) { @@ -1671,93 +1530,83 @@ * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindGSSAPIEmptyAuthID() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("")); gssapiSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the * provided properties has multiple authID values. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindGSSAPIMultipleAuthIDs() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("u:test.user", "dn:uid=test.user,o=test")); gssapiSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the * provided properties has multiple authzID values. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindGSSAPIMultipleAuthzIDs() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("u:test.user")); saslProperties.put("authzid", newArrayList("u:test.user", "dn:uid=test.user,o=test")); gssapiSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the * provided properties has multiple KDC values. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindGSSAPIMultipleKDCs() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("u:test.user")); saslProperties.put("kdc", newArrayList("kdc1", "kdc2")); gssapiSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the * provided properties has multiple quality of protection values. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindGSSAPIMultipleQoPs() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("u:test.user")); saslProperties.put("qop", newArrayList("auth", "auth-int", "auth-conf")); gssapiSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the * provided properties has an unsupported quality of protection value of @@ -1765,19 +1614,17 @@ * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindGSSAPIUnsupportedQoPAuthInt() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("u:test.user")); saslProperties.put("qop", newArrayList("auth-int")); gssapiSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the * provided properties has an unsupported quality of protection value of @@ -1785,100 +1632,91 @@ * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindGSSAPIUnsupportedQoPAuthConf() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("u:test.user")); saslProperties.put("qop", newArrayList("auth-conf")); gssapiSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the * provided properties has an invalid quality of protection value. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindGSSAPIInvalidQoP() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("u:test.user")); saslProperties.put("qop", newArrayList("invalid")); gssapiSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the * provided properties has multiple realm values. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindGSSAPIMultipleRealms() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("u:test.user")); saslProperties.put("realm", newArrayList("realm1", "realm2")); gssapiSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the * provided properties has an invalid property. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindGSSAPIInvalidProperty() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("u:test.user")); saslProperties.put("invalid", newArrayList("foo")); gssapiSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for GSSAPI authentication when the * provided properties isn't empty but doesn't contain an auth ID. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindGSSAPINoAuthID() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("qop", newArrayList("auth")); gssapiSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which PLAIN * authentication is disabled in the server. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindPlainDisabled() throws Exception { @@ -1895,13 +1733,11 @@ "cn: Test User", "userPassword: password"); SASLMechanismHandler<?> plainHandler = DirectoryServer.getSASLMechanismHandler("PLAIN"); DirectoryServer.deregisterSASLMechanismHandler("PLAIN"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); try (Socket s = newSocket()) @@ -1915,8 +1751,6 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which PLAIN * authentication is enabled in the server. @@ -1940,8 +1774,7 @@ "cn: Test User", "userPassword: password"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); try (Socket s = newSocket()) { @@ -1950,53 +1783,47 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the PLAIN * SASL properties are null. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindPlainNullProperties() throws Exception { LinkedHashMap<String,List<String>> saslProperties = null; Map<String, List<String>> saslProperties = null; plainSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the PLAIN * SASL properties are empty. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindPlainEmptyProperties() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); plainSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the PLAIN * SASL properties have multiple auth ID values. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindPlainMultipleAuthIDs() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test", "u:test.user")); plainSaslBind(saslProperties); @@ -2008,90 +1835,81 @@ * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindPlainZeroLengthAuthID() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("")); plainSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the PLAIN * SASL properties have multiple authzID values. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindPlainMultipleAuthzIDs() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); saslProperties.put("authzid", newArrayList("dn:uid=test.user,o=test", "u:test.user")); plainSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the PLAIN * SASL properties contains an invalid property. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindPlainInvalidProperty() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); saslProperties.put("invalid", newArrayList("foo")); plainSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which the PLAIN * SASL properties does not contain an auth ID. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { ClientException.class }) @Test(expectedExceptions = ClientException.class) public void testDoSASLBindPlainNoAuthID() throws Exception { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authzid", newArrayList("dn:uid=test.user,o=test")); plainSaslBind(saslProperties); } /** * Tests the <CODE>doSASLBind</CODE> method for PLAIN authentication in which * the target user does not exist in the server. * * @throws Exception If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindPlainNonExistentUser() throws Exception { TestCaseUtils.initializeTestBackend(true); try (Socket s = newSocket()) { LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=does.not.exist,o=test")); plain(newLDAPAuthenticationHandler(s, "localhost"), saslProperties); @@ -2105,7 +1923,7 @@ * @throws Exception * If an unexpected problem occurs. */ @Test(expectedExceptions = { LDAPException.class }) @Test(expectedExceptions = LDAPException.class) public void testDoSASLBindPlainWrongPassword() throws Exception { @@ -2122,8 +1940,7 @@ "cn: Test User", "userPassword: password"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=does.not.exist,o=test")); try (Socket s = newSocket()) { @@ -2132,8 +1949,6 @@ } } /** * Tests the <CODE>doSASLBind</CODE> method for the case in which PLAIN * authentication is enabled in the server and the password policy request @@ -2158,11 +1973,10 @@ "cn: Test User", "userPassword: password"); ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); requestControls.add(new PasswordPolicyRequestControl()); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); try (Socket s = newSocket()) { @@ -2172,8 +1986,6 @@ } } /** * Tests the <CODE>requestAuthorizationIdentity</CODE> method for an * unauthenticated client connection. @@ -2191,8 +2003,6 @@ } } /** * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client * connection after a simple anonymous bind. @@ -2203,8 +2013,8 @@ public void testRequestAuthorizationIdentitySimpleAnonymous() throws Exception { ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); try (Socket s = newSocket()) { @@ -2224,8 +2034,8 @@ public void testRequestAuthorizationIdentitySimpleRootUser() throws Exception { ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); try (Socket s = newSocket()) { LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost"); @@ -2235,8 +2045,6 @@ } } /** * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client * connection after a simple bind as a normal user. @@ -2260,9 +2068,8 @@ "cn: Test User", "userPassword: password"); ArrayList<Control> requestControls = new ArrayList<>(); ArrayList<Control> responseControls = new ArrayList<>(); List<Control> requestControls = new ArrayList<>(); List<Control> responseControls = new ArrayList<>(); try (Socket s = newSocket()) { LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost"); @@ -2272,8 +2079,6 @@ } } /** * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client * connection after a SASL ANONYMOUS bind. @@ -2287,7 +2092,7 @@ AnonymousSASLMechanismHandler handler = new AnonymousSASLMechanismHandler(); handler.initializeSASLMechanismHandler(null); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("trace", newArrayList("testDoSASLBindAnonymous")); try (Socket s = newSocket()) { @@ -2298,8 +2103,6 @@ handler.finalizeSASLMechanismHandler(); } /** * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client * connection after a CRAM-MD5 bind. @@ -2325,8 +2128,7 @@ "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," + "cn=Password Policies,cn=config"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); try (Socket s = newSocket()) { @@ -2336,8 +2138,6 @@ } } /** * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client * connection after a DIGEST-MD5 bind. @@ -2363,8 +2163,7 @@ "ds-pwp-password-policy-dn: cn=Clear UserPassword Policy," + "cn=Password Policies,cn=config"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); try (Socket s = newSocket()) @@ -2375,8 +2174,6 @@ } } /** * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client * connection after an EXTERNAL bind. @@ -2399,19 +2196,16 @@ "sn: User", "cn: Test User"); String keyStorePath = DirectoryServer.getInstanceRoot() + File.separator + "config" + File.separator + "client.keystore"; String trustStorePath = DirectoryServer.getInstanceRoot() + File.separator + "config" + File.separator + "client.truststore"; SSLConnectionFactory factory = new SSLConnectionFactory(); factory.init(false, keyStorePath, "password", "client-cert", trustStorePath, "password"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); try (Socket s = factory.createSocket("127.0.0.1", TestCaseUtils.getServerLdapsPort())) { LDAPAuthenticationHandler authHandler = newLDAPAuthenticationHandler(s, "localhost"); @@ -2420,8 +2214,6 @@ } } /** * Tests the <CODE>requestAuthorizationIdentity</CODE> method for a a client * connection after a PLAIN bind. @@ -2445,8 +2237,7 @@ "cn: Test User", "userPassword: password"); LinkedHashMap<String, List<String>> saslProperties = new LinkedHashMap<>(); Map<String, List<String>> saslProperties = new LinkedHashMap<>(); saslProperties.put("authid", newArrayList("dn:uid=test.user,o=test")); try (Socket s = newSocket()) {