/* * 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.Date; import com.slamd.asn1.ASN1Element; import com.slamd.asn1.ASN1Integer; import com.slamd.asn1.ASN1OctetString; import com.slamd.asn1.ASN1Sequence; /** * This class defines an LDAP bind request, which is used to authenticate to a * directory server. * * * @author Neil A. Wilson */ public class BindRequest extends ProtocolOp { /** * The authentication type that indicates that simple authentication is to be * performed. */ public static final byte AUTH_TYPE_SIMPLE = (byte) 0x80; /** * The authentication type that indicates that SASL authentication is to be * performed. */ public static final byte AUTH_TYPE_SASL = (byte) 0xA3; // The SASL credentials for this bind request. private ASN1OctetString saslCredentials; // The authentication type contained in this bind request. private byte authType; // The LDAP protocol version contained in this bind request. private int protocolVersion; // The DN of the user performing the bind. private String bindDN; // The password used for simple authentication. private String bindPassword; // The SASL mechanism used for this bind request. private String saslMechanism; /** * Creates a new bind request using simple authentication with the provided * information. * * @param protocolVersion The LDAP protocol version to use in the bind * request. * @param bindDN The DN of the user performing the bind. * @param bindPassword The password of the user performing the bind. */ public BindRequest(int protocolVersion, String bindDN, String bindPassword) { this.protocolVersion = protocolVersion; this.bindDN = bindDN; this.bindPassword = bindPassword; authType = AUTH_TYPE_SIMPLE; } /** * Creates a new bind request using SASL authentication with the provided * information. * * @param protocolVersion The LDAP protocol version to use in the bind * request. * @param bindDN The DN of the user performing the bind. * @param saslMechanism The SASL mechanism used to perform the bind. * @param saslCredentials The SASL credentials to use in the bind. */ public BindRequest(int protocolVersion, String bindDN, String saslMechanism, ASN1OctetString saslCredentials) { this.protocolVersion = protocolVersion; this.bindDN = bindDN; this.saslMechanism = saslMechanism; this.saslCredentials = saslCredentials; authType = AUTH_TYPE_SASL; } /** * Retrieves the LDAP protocol version used in this bind request. * * @return The LDAP protocol version used in this bind request. */ public int getProtocolVersion() { return protocolVersion; } /** * Retrieves the DN of the user performing the bind. * * @return The DN of the user performing the bind. */ public String getBindDN() { return bindDN; } /** * Retrieves the type of authentication contained in this bind request. * * @return <CODE>AUTH_TYPE_SIMPLE</CODE> if simple authentication is to be * performed, or <CODE>AUTH_TYPE_SASL</CODE> if SASL authentication * should be used. */ public byte getAuthType() { return authType; } /** * Retrieves the password used for simple authentication. * * @return The password used for simple authentication. */ public String getBindPassword() { return bindPassword; } /** * Retrieves the mechanism used for SASL authentication. * * @return The mechanism used for SASL authentication. */ public String getSASLMechanism() { return saslMechanism; } /** * Retrieves the credentials used for SASL authentication. * * @return The credentials used for SASL authentication. */ public ASN1OctetString getSASLCredentials() { return saslCredentials; } /** * Encodes this protocol op to an ASN.1 element. * * @return The ASN.1 element containing the encoded protocol op. */ public ASN1Element encode() { ASN1Element authenticationElement; if (authType == AUTH_TYPE_SIMPLE) { authenticationElement = new ASN1OctetString(AUTH_TYPE_SIMPLE, bindPassword); } else { ASN1Element[] saslElements; if (saslCredentials == null) { saslElements = new ASN1Element[] { new ASN1OctetString(saslMechanism) }; } else { saslElements = new ASN1Element[] { new ASN1OctetString(saslMechanism), saslCredentials }; } authenticationElement = new ASN1Sequence(AUTH_TYPE_SASL, saslElements); } ASN1Element[] bindElements = new ASN1Element[] { new ASN1Integer(protocolVersion), new ASN1OctetString(bindDN), authenticationElement }; return new ASN1Sequence(BIND_REQUEST_TYPE, bindElements); } /** * Decodes the provided ASN.1 element as a bind request protocol op. * * @param element The ASN.1 element to be decoded. * * @return The decoded bind request. * * @throws ProtocolException If a problem occurs while decoding the provided * ASN.1 element as a bind request. */ public static BindRequest decodeBindRequest(ASN1Element element) throws ProtocolException { ASN1Element[] bindElements; try { bindElements = element.decodeAsSequence().getElements(); } catch (Exception e) { throw new ProtocolException("Unable to decode bind request protocol op " + "as an ASN.1 sequence", e); } if (bindElements.length != 3) { throw new ProtocolException("There must be three elements in a bind " + "request sequence"); } int protocolVersion; try { protocolVersion = bindElements[0].decodeAsInteger().getIntValue(); } catch (Exception e) { throw new ProtocolException("Unable to decode protocol version", e); } String bindDN; try { bindDN = bindElements[1].decodeAsOctetString().getStringValue(); } catch (Exception e) { throw new ProtocolException("Unable to decode bind DN", e); } switch (bindElements[2].getType()) { case AUTH_TYPE_SIMPLE: try { String bindPassword = bindElements[2].decodeAsOctetString().getStringValue(); return new BindRequest(protocolVersion, bindDN, bindPassword); } catch (Exception e) { throw new ProtocolException("Unable to decode bind password", e); } case AUTH_TYPE_SASL: ASN1Element[] saslElements; try { saslElements = bindElements[2].decodeAsSequence().getElements(); } catch (Exception e) { throw new ProtocolException("Unable to decode SASL authentication " + "sequence", e); } if ((saslElements.length < 1) || (saslElements.length > 2)) { throw new ProtocolException("A SASL authentication sequence must " + "have one or two elements"); } String saslMechanism; try { saslMechanism = saslElements[0].decodeAsOctetString().getStringValue(); } catch (Exception e) { throw new ProtocolException("Unable to decode the SASL mechanism", e); } ASN1OctetString saslCredentials = null; if (saslElements.length == 2) { try { saslCredentials = saslElements[1].decodeAsOctetString(); } catch (Exception e) { throw new ProtocolException("Unable to decode the SASL credentials", e); } } // FIXME -- Add support for specific SASL mechanisms. return new BindRequest(protocolVersion, bindDN, saslMechanism, saslCredentials); default: throw new ProtocolException("Unknown authentication type " + bindElements[2].getType()); } } /** * Retrieves a user-friendly name for this protocol op. * * @return A user-friendly name for this protocol op. */ public String getProtocolOpType() { return "LDAP Bind Request"; } /** * 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("LDAP Version: "). append(protocolVersion).append(LDAPMessage.EOL); buffer.append(indentBuf).append("Bind DN: "). append(bindDN).append(LDAPMessage.EOL); buffer.append(indentBuf).append("Authentication Data:"). append(LDAPMessage.EOL); if (authType == AUTH_TYPE_SIMPLE) { buffer.append(indentBuf).append(" Authentication Type: Simple"). append(LDAPMessage.EOL); buffer.append(indentBuf).append(" Bind Password: "). append(bindPassword).append(LDAPMessage.EOL); } else if (authType == AUTH_TYPE_SASL) { buffer.append(indentBuf).append(" Authentication Type: SASL"). append(LDAPMessage.EOL); buffer.append(indentBuf).append(" SASL Mechanism: "). append(saslMechanism).append(LDAPMessage.EOL); if (saslCredentials != null) { byte[] credentialBytes = saslCredentials.getValue(); buffer.append(indentBuf).append(" SASL Credentials:"). append(LDAPMessage.EOL); buffer.append(LDAPMessage.byteArrayToString(credentialBytes, (indent+8))); } } 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) { scriptWriter.println("#### Bind request captured at " + new Date()); scriptWriter.println("# Bind DN: " + bindDN); if (authType == AUTH_TYPE_SIMPLE) { scriptWriter.println("# Authentication Type: Simple"); scriptWriter.println("# Authentication Password: " + bindPassword); scriptWriter.println("resultCode = conn.bind(\"" + bindDN + "\", \"" + bindPassword + "\");"); } else if (authType == AUTH_TYPE_SASL) { scriptWriter.println("# Authentication Type: SASL"); scriptWriter.println("# SASL Mechanism: " + saslMechanism); scriptWriter.println("# NOTE: The SLAMD scripting language does not " + "currently support SASL binds."); } scriptWriter.println(); scriptWriter.println(); } }