/*
* Sun Public License
*
* The contents of this file are subject to the Sun Public License Version
* 1.0 (the "License"). You may not use this file except in compliance with
* the License. A copy of the License is available at http://www.sun.com/
*
* The Original Code is the SLAMD Distributed Load Generation Engine.
* The Initial Developer of the Original Code is Neil A. Wilson.
* Portions created by Neil A. Wilson are Copyright (C) 2004-2010.
* Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc.
* All Rights Reserved.
*
* Contributor(s): Neil A. Wilson
*/
package com.slamd.tools.ldapdecoder.protocol;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Date;
import com.slamd.asn1.ASN1Element;
import com.slamd.asn1.ASN1Enumerated;
import com.slamd.asn1.ASN1OctetString;
import com.slamd.asn1.ASN1Sequence;
/**
* This class defines an LDAP bind response, which provides the result of
* processing a bind request.
*
*
* @author Neil A. Wilson
*/
public class BindResponse
extends ProtocolOp
{
/**
* The ASN.1 type used to hold the referral component of the response.
*/
public static final byte SERVER_SASL_CREDENTIALS_TYPE = (byte) 0x87;
// The set of SASL credentials provided by the server for use in the bind
// process.
private ASN1OctetString serverSASLCredentials;
// The result code for the operation.
private int resultCode;
// The error message associated with this result.
private String errorMessage;
// The matched DN for this result.
private String matchedDN;
// The set of referrals for this result.
private String[] referrals;
/**
* Creates a new bind response with the provided information.
*
* @param resultCode The result code for this response.
* @param matchedDN The matched DN for this response.
* @param errorMessage The error message for this response.
*/
public BindResponse(int resultCode, String matchedDN, String errorMessage)
{
this.resultCode = resultCode;
this.matchedDN = matchedDN;
this.errorMessage = errorMessage;
referrals = null;
serverSASLCredentials = null;
}
/**
* Creates a new bind response with the provided information.
*
* @param resultCode The result code for this response.
* @param matchedDN The matched DN for this response.
* @param errorMessage The error message for this response.
* @param referrals The set of referrals for this response.
*/
public BindResponse(int resultCode, String matchedDN, String errorMessage,
String[] referrals)
{
this.resultCode = resultCode;
this.matchedDN = matchedDN;
this.errorMessage = errorMessage;
this.referrals = referrals;
serverSASLCredentials = null;
}
/**
* Creates a new bind response with the provided information.
*
* @param resultCode The result code for this response.
* @param matchedDN The matched DN for this response.
* @param errorMessage The error message for this response.
* @param referrals The set of referrals for this response.
* @param serverSASLCredentials The set of credentials returned by the
* server for use in the SASL authentication
* process.
*/
public BindResponse(int resultCode, String matchedDN, String errorMessage,
String[] referrals, ASN1OctetString serverSASLCredentials)
{
this.resultCode = resultCode;
this.matchedDN = matchedDN;
this.errorMessage = errorMessage;
this.referrals = referrals;
this.serverSASLCredentials = serverSASLCredentials;
}
/**
* Retrieves the result code for the operation.
*
* @return The result code for the operation.
*/
public int getResultCode()
{
return resultCode;
}
/**
* Retrieves the error message for this result.
*
* @return The error message for this result.
*/
public String getErrorMessage()
{
return errorMessage;
}
/**
* Retrieves the matched DN for this result.
*
* @return The matched DN for this result.
*/
public String getMatchedDN()
{
return matchedDN;
}
/**
* Retrieves the set of referrals for this result.
*
* @return The set of referrals for this result, or <CODE>null</CODE> if
* there were no referrals contained in the result.
*/
public String[] getReferrals()
{
return referrals;
}
/**
* Retrieves the set of credentials returned by the server for use in the SASL
* authentication process.
*
* @return The set of credentials returned by the server for use in the SASL
* authentication process.
*/
public ASN1OctetString getServerSASLCredentials()
{
return serverSASLCredentials;
}
/**
* Encodes this protocol op to an ASN.1 element.
*
* @return The ASN.1 element containing the encoded protocol op.
*/
public ASN1Element encode()
{
ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(5);
elementList.add(new ASN1Enumerated(resultCode));
if (matchedDN == null)
{
elementList.add(new ASN1OctetString());
}
else
{
elementList.add(new ASN1OctetString(matchedDN));
}
if (errorMessage == null)
{
elementList.add(new ASN1OctetString());
}
else
{
elementList.add(new ASN1OctetString(errorMessage));
}
if ((referrals != null) && (referrals.length > 0))
{
ASN1Element[] referralElements = new ASN1Element[referrals.length];
for (int i=0; i < referrals.length; i++)
{
referralElements[i] = new ASN1OctetString(referrals[i]);
}
elementList.add(new ASN1Sequence(REFERRAL_TYPE, referralElements));
}
if (serverSASLCredentials != null)
{
serverSASLCredentials.setType(SERVER_SASL_CREDENTIALS_TYPE);
elementList.add(serverSASLCredentials);
}
ASN1Element[] bindResponseElements = new ASN1Element[elementList.size()];
elementList.toArray(bindResponseElements);
return new ASN1Sequence(BIND_RESPONSE_TYPE, bindResponseElements);
}
/**
* Decodes the provided ASN.1 element as a bind response protocol op.
*
* @param element The ASN.1 element to be decoded.
*
* @return The decoded bind response.
*
* @throws ProtocolException If a problem occurs while decoding the provided
* ASN.1 element as a bind response.
*/
public static BindResponse decodeBindResponse(ASN1Element element)
throws ProtocolException
{
ASN1Element[] bindResponseElements;
try
{
bindResponseElements = element.decodeAsSequence().getElements();
}
catch (Exception e)
{
throw new ProtocolException("Unable to decode bind response sequence", e);
}
if ((bindResponseElements.length < 3) || (bindResponseElements.length > 5))
{
throw new ProtocolException("There must be between 3 and 5 elements in " +
"a bind response sequence");
}
int resultCode;
try
{
resultCode = bindResponseElements[0].decodeAsInteger().getIntValue();
}
catch (Exception e)
{
throw new ProtocolException("Unable to decode bind result code", e);
}
String matchedDN;
try
{
matchedDN =
bindResponseElements[1].decodeAsOctetString().getStringValue();
}
catch (Exception e)
{
throw new ProtocolException("Unable to decode bind result matched DN", e);
}
String errorMessage;
try
{
errorMessage =
bindResponseElements[2].decodeAsOctetString().getStringValue();
}
catch (Exception e)
{
throw new ProtocolException("Unable to decode bind result error message",
e);
}
String[] referrals = null;
ASN1OctetString serverSASLCredentials = null;
if (bindResponseElements.length >= 4)
{
byte type = bindResponseElements[3].getType();
if (type == REFERRAL_TYPE)
{
try
{
ASN1Element[] referralElements =
bindResponseElements[3].decodeAsSequence().getElements();
referrals = new String[referralElements.length];
for (int i=0; i < referrals.length; i++)
{
referrals[i] =
referralElements[i].decodeAsOctetString().getStringValue();
}
}
catch (Exception e)
{
throw new ProtocolException("Unable to decode referral elements", e);
}
}
else if (type == SERVER_SASL_CREDENTIALS_TYPE)
{
try
{
serverSASLCredentials = bindResponseElements[3].decodeAsOctetString();
}
catch (Exception e)
{
throw new ProtocolException("Unable to decode server SASL " +
"credentials", e);
}
}
else
{
throw new ProtocolException("Unsupported bind response element type " +
type);
}
}
if (bindResponseElements.length == 5)
{
try
{
serverSASLCredentials = bindResponseElements[4].decodeAsOctetString();
}
catch (Exception e)
{
throw new ProtocolException("Unable to decode server SASL credentials",
e);
}
}
return new BindResponse(resultCode, matchedDN, errorMessage, referrals,
serverSASLCredentials);
}
/**
* Retrieves a user-friendly name for this protocol op.
*
* @return A user-friendly name for this protocol op.
*/
public String getProtocolOpType()
{
return "LDAP Bind Response";
}
/**
* Retrieves a string representation of this protocol op with the specified
* indent.
*
* @param indent The number of spaces to indent the output.
*
* @return A string representation of this protocol op with the specified
* indent.
*/
public String toString(int indent)
{
StringBuilder indentBuf = new StringBuilder(indent);
for (int i=0; i < indent; i++)
{
indentBuf.append(' ');
}
StringBuilder buffer = new StringBuilder();
buffer.append(indentBuf).append("Result Code: ").
append(resultCode).append(" (").
append(LDAPResultCode.resultCodeToString(resultCode)).
append(')').append(LDAPMessage.EOL);
if ((matchedDN != null) && (matchedDN.length() > 0))
{
buffer.append(indentBuf).append("Matched DN: ").
append(matchedDN).append(LDAPMessage.EOL);
}
if ((errorMessage != null) && (errorMessage.length() > 0))
{
buffer.append(indentBuf).append("Error Message: ").
append(errorMessage).append(LDAPMessage.EOL);
}
if ((referrals != null) && (referrals.length > 0))
{
buffer.append(indentBuf).append("Referrals:").append(LDAPMessage.EOL);
for (int i=0; i < referrals.length; i++)
{
buffer.append(indentBuf).append(" ").append(referrals[i]).
append(LDAPMessage.EOL);
}
}
if (serverSASLCredentials != null)
{
byte[] credentialsBytes = serverSASLCredentials.getValue();
buffer.append(indentBuf).append("Server SASL Credentials:").
append(LDAPMessage.EOL);
buffer.append(LDAPMessage.byteArrayToString(credentialsBytes,
(indent+4)));
}
return buffer.toString();
}
/**
* Constructs a string representation of this LDAP message in a form that can
* be written to a SLAMD script. It may be empty if this message isn't one
* that would be generated as part of a client request.
*
* @param scriptWriter The print stream to which the script contents should
* be written.
*/
public void toSLAMDScript(PrintStream scriptWriter)
{
// This is not something that would be generated by a client and therefore
// no operation needs to be performed. However, we can write a comment
// to the script indicating that an add response was received.
scriptWriter.println("#### Bind response captured at " + new Date());
scriptWriter.println("# Result code: " + resultCode);
if ((matchedDN != null) && (matchedDN.length() > 0))
{
scriptWriter.println("# Matched DN: " + matchedDN);
}
if ((errorMessage != null) && (errorMessage.length() > 0))
{
scriptWriter.println("# Error message: " + errorMessage);
}
if ((referrals != null) && (referrals.length > 0))
{
scriptWriter.println("# Referral(s):");
for (int i=0; i < referrals.length; i++)
{
scriptWriter.println("# " + referrals[i]);
}
}
scriptWriter.println();
scriptWriter.println();
}
}