package com.hwlcn.ldap.ldap.sdk;
import com.hwlcn.ldap.asn1.ASN1OctetString;
import com.hwlcn.core.annotation.NotMutable;
import com.hwlcn.core.annotation.ThreadSafety;
import com.hwlcn.ldap.util.ThreadSafetyLevel;
import static com.hwlcn.ldap.util.StaticUtils.*;
import static com.hwlcn.ldap.util.Validator.*;
/**
* This class provides a SASL PLAIN bind request implementation as described in
* <A HREF="http://www.ietf.org/rfc/rfc4616.txt">RFC 4616</A>. The SASL PLAIN
* mechanism allows the client to authenticate with an authentication ID and
* password, and optionally allows the client to provide an authorization ID for
* use in performing subsequent operations.
* <BR><BR>
* Elements included in a PLAIN bind request include:
* <UL>
* <LI>Authentication ID -- A string which identifies the user that is
* attempting to authenticate. It should be an "authzId" value as
* described in section 5.2.1.8 of
* <A HREF="http://www.ietf.org/rfc/rfc4513.txt">RFC 4513</A>. That is,
* it should be either "dn:" followed by the distinguished name of the
* target user, or "u:" followed by the username. If the "u:" form is
* used, then the mechanism used to resolve the provided username to an
* entry may vary from server to server.</LI>
* <LI>Authorization ID -- An optional string which specifies an alternate
* authorization identity that should be used for subsequent operations
* requested on the connection. Like the authentication ID, the
* authorization ID should use the "authzId" syntax.</LI>
* <LI>Password -- The clear-text password for the target user.</LI>
* </UL>
* <H2>Example</H2>
* The following example demonstrates the process for performing a PLAIN bind
* against a directory server with a username of "john.doe" and a password of
* "password":
* <PRE>
* PLAINBindRequest bindRequest =
* new PLAINBindRequest("u:john.doe", "password");
* try
* {
* BindResult bindResult = connection.bind(bindRequest);
* // If we get here, then the bind was successful.
* }
* catch (LDAPException le)
* {
* // The bind failed for some reason.
* }
* </PRE>
*/
@NotMutable()
@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE)
public final class PLAINBindRequest
extends SASLBindRequest
{
public static final String PLAIN_MECHANISM_NAME = "PLAIN";
private static final long serialVersionUID = -5186140710317748684L;
private final ASN1OctetString password;
private final String authenticationID;
private final String authorizationID;
public PLAINBindRequest(final String authenticationID, final String password)
{
this(authenticationID, null, new ASN1OctetString(password), NO_CONTROLS);
ensureNotNull(password);
}
public PLAINBindRequest(final String authenticationID, final byte[] password)
{
this(authenticationID, null, new ASN1OctetString(password), NO_CONTROLS);
ensureNotNull(password);
}
public PLAINBindRequest(final String authenticationID,
final ASN1OctetString password)
{
this(authenticationID, null, password, NO_CONTROLS);
}
public PLAINBindRequest(final String authenticationID,
final String authorizationID, final String password)
{
this(authenticationID, authorizationID, new ASN1OctetString(password),
NO_CONTROLS);
ensureNotNull(password);
}
public PLAINBindRequest(final String authenticationID,
final String authorizationID, final byte[] password)
{
this(authenticationID, authorizationID, new ASN1OctetString(password),
NO_CONTROLS);
ensureNotNull(password);
}
public PLAINBindRequest(final String authenticationID,
final String authorizationID,
final ASN1OctetString password)
{
this(authenticationID, authorizationID, password, NO_CONTROLS);
}
public PLAINBindRequest(final String authenticationID, final String password,
final Control... controls)
{
this(authenticationID, null, new ASN1OctetString(password), controls);
ensureNotNull(password);
}
public PLAINBindRequest(final String authenticationID, final byte[] password,
final Control... controls)
{
this(authenticationID, null, new ASN1OctetString(password), controls);
ensureNotNull(password);
}
public PLAINBindRequest(final String authenticationID,
final ASN1OctetString password,
final Control... controls)
{
this(authenticationID, null, password, controls);
}
public PLAINBindRequest(final String authenticationID,
final String authorizationID, final String password,
final Control... controls)
{
this(authenticationID, authorizationID, new ASN1OctetString(password),
controls);
ensureNotNull(password);
}
public PLAINBindRequest(final String authenticationID,
final String authorizationID, final byte[] password,
final Control... controls)
{
this(authenticationID, authorizationID, new ASN1OctetString(password),
controls);
ensureNotNull(password);
}
public PLAINBindRequest(final String authenticationID,
final String authorizationID,
final ASN1OctetString password,
final Control... controls)
{
super(controls);
ensureNotNull(authenticationID, password);
this.authenticationID = authenticationID;
this.authorizationID = authorizationID;
this.password = password;
}
@Override()
public String getSASLMechanismName()
{
return PLAIN_MECHANISM_NAME;
}
public String getAuthenticationID()
{
return authenticationID;
}
public String getAuthorizationID()
{
return authorizationID;
}
public String getPasswordString()
{
return password.stringValue();
}
public byte[] getPasswordBytes()
{
return password.getValue();
}
@Override()
protected BindResult process(final LDAPConnection connection, final int depth)
throws LDAPException
{
final byte[] authZIDBytes = getBytes(authorizationID);
final byte[] authNIDBytes = getBytes(authenticationID);
final byte[] passwordBytes = password.getValue();
final byte[] credBytes = new byte[2 + authZIDBytes.length +
authNIDBytes.length + passwordBytes.length];
System.arraycopy(authZIDBytes, 0, credBytes, 0, authZIDBytes.length);
int pos = authZIDBytes.length + 1;
System.arraycopy(authNIDBytes, 0, credBytes, pos, authNIDBytes.length);
pos += authNIDBytes.length + 1;
System.arraycopy(passwordBytes, 0, credBytes, pos, passwordBytes.length);
return sendBindRequest(connection, "", new ASN1OctetString(credBytes),
getControls(), getResponseTimeoutMillis(connection));
}
@Override()
public PLAINBindRequest getRebindRequest(final String host, final int port)
{
return new PLAINBindRequest(authenticationID, authorizationID, password,
getControls());
}
@Override()
public PLAINBindRequest duplicate()
{
return duplicate(getControls());
}
@Override()
public PLAINBindRequest duplicate(final Control[] controls)
{
final PLAINBindRequest bindRequest = new PLAINBindRequest(authenticationID,
authorizationID, password, controls);
bindRequest.setResponseTimeoutMillis(getResponseTimeoutMillis(null));
return bindRequest;
}
@Override()
public void toString(final StringBuilder buffer)
{
buffer.append("PLAINBindRequest(authenticationID='");
buffer.append(authenticationID);
buffer.append('\'');
if (authorizationID != null)
{
buffer.append(", authorizationID='");
buffer.append(authorizationID);
buffer.append('\'');
}
final Control[] controls = getControls();
if (controls.length > 0)
{
buffer.append(", controls={");
for (int i=0; i < controls.length; i++)
{
if (i > 0)
{
buffer.append(", ");
}
buffer.append(controls[i]);
}
buffer.append('}');
}
buffer.append(')');
}
}