/* * 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.message; import java.util.ArrayList; import com.slamd.asn1.ASN1Boolean; import com.slamd.asn1.ASN1Element; import com.slamd.asn1.ASN1Enumerated; import com.slamd.asn1.ASN1Exception; import com.slamd.asn1.ASN1Integer; import com.slamd.asn1.ASN1OctetString; import com.slamd.asn1.ASN1Sequence; import com.slamd.common.Constants; import com.slamd.common.SLAMDException; /** * This class defines a client hello message that the client uses to identify * itself to the server and optionally perform authentication so that the * server can verify the identity of the client. * * * @author Neil A. Wilson */ public class ClientHelloMessage extends Message { // Indicates whether the client is requesting the server to authenticate // itself. private final boolean requestServerAuth; // Indicates whether this client will operate in restricted mode, in which // case it should only be asked to run jobs that explicitly name it as a // requested client. private final boolean restrictedMode; // Indicates whether this client supports time synchronization. private final boolean supportsTimeSync; // The type of authentication that the client is going to perform. private final int authType; // The credentials corresponding to the authentication type and ID. private final String authCredentials; // The ID that the client is using to authenticate. private final String authID; // The client identifier, which is a human-readable name that administrators // can use to identify the client when viewing server status messages private final String clientID; // The version that the client is using, which may be used to determine // functionality available to that client or determine whether the client // should be allowed to authenticate private final String clientVersion; /** * Creates a new client hello message that will only provide client version * and identification information but does not perform any authentication. * * @param messageID The message ID for this message. * @param clientVersion The version of the client software being used. * @param clientID The human-readable text that can be used to * identify this client. * @param supportsTimeSync Indicates whether the client supports time * synchronization with the server. */ public ClientHelloMessage(int messageID, String clientVersion, String clientID, boolean supportsTimeSync) { this(messageID, clientVersion, clientID, Constants.AUTH_TYPE_NONE, "", "", false, false, supportsTimeSync); } /** * Creates a new client hello message with the specified information. Server * authentication will not be requested. * * @param messageID The message ID for this message. * @param clientVersion The version of the client software being used. * @param clientID The human-readable text that can be used to * identify this client. * @param authType The type of authentication that the client is * using. * @param authID The ID that the client is using to authenticate. * @param authCredentials The credentials that the client is using to * authenticate. * @param supportsTimeSync Indicates whether the client supports time * synchronization with the server. */ public ClientHelloMessage(int messageID, String clientVersion, String clientID, int authType, String authID, String authCredentials, boolean supportsTimeSync) { this(messageID, clientVersion, clientID, authType, authID, authCredentials, false, false, supportsTimeSync); } /** * Creates a new client hello message with the specified information. * * @param messageID The message ID for this message. * @param clientVersion The version of the client software being used. * @param clientID The human-readable text that can be used to * identify this client. * @param authType The type of authentication that the client is * using. * @param authID The ID that the client is using to authenticate. * @param authCredentials The credentials that the client is using to * authenticate. * @param requestServerAuth Indicates whether the client requests that the * server authenticate itself. * @param restrictedMode Indicates whether the client will operate in * restricted mode, in which case it should only * be used to run jobs for which it is explicitly * requested. * @param supportsTimeSync Indicates whether the client supports time * synchronization with the server. */ public ClientHelloMessage(int messageID, String clientVersion, String clientID, int authType, String authID, String authCredentials, boolean requestServerAuth, boolean restrictedMode, boolean supportsTimeSync) { super(messageID, Constants.MESSAGE_TYPE_CLIENT_HELLO); this.clientVersion = clientVersion; this.clientID = clientID; this.authType = authType; this.authID = authID; this.authCredentials = authCredentials; this.requestServerAuth = requestServerAuth; this.restrictedMode = restrictedMode; this.supportsTimeSync = supportsTimeSync; } /** * Retrieves the version of the client software being used. * * @return The version of the client software being used. */ public String getClientVersion() { return clientVersion; } /** * Retrieves the human-readable ID for the client. * * @return The human-readable ID for the client. */ public String getClientID() { return clientID; } /** * Retrieves the type of authentication that the client is using. * * @return The type of authentication that the client is using. */ public int getAuthType() { return authType; } /** * Retrieves the ID that the client is using to authenticate itself. * * @return The ID that the client is using to authenticate itself. */ public String getAuthID() { return authID; } /** * Retrieves the credentials that the client is using to authenticate itself. * * @return The credentials that the client is using to authenticate itself. */ public String getAuthCredentials() { return authCredentials; } /** * Indicates whether the client is requesting server authentication. * * @return <CODE>true</CODE> if the client is requesting server * authentication, or <CODE>false</CODE> if not. */ public boolean requestServerAuth() { return requestServerAuth; } /** * Indicates whether the client is operating in restricted mode, in which case * the server should only give it jobs for which the client was explicitly * requested. * * @return <CODE>true</CODE> if the client is operating in restricted mode, * or <CODE>false</CODE> if not. */ public boolean restrictedMode() { return restrictedMode; } /** * Indicates whether this client supports time synchronization with the * server. * * @return <CODE>true</CODE> if the client supports time synchronization, or * <CODE>false</CODE> if not. */ public boolean supportsTimeSync() { return supportsTimeSync; } /** * Retrieves a string representation of this message. * * @return A string representation of this message. */ @Override() public String toString() { String eol = System.getProperty("line.separator"); return "Client Hello Message" + eol + " Message ID: " + messageID + eol + " Client ID: " + clientID + eol + " Client Version: " + clientVersion + eol + " Authentication Type: " + authType + eol + " Authentication ID: " + authID + eol + " Authentication Credentials: <hidden>" + eol + " Request Server Authentication: " + (requestServerAuth ? "true" : "false") + eol + " Restricted Mode: " + (restrictedMode ? "true" : "false") + eol + " Supports Time Synchronization: " + (supportsTimeSync ? "true" : "false") + eol; } /** * Decodes the provided ASN.1 element as a client hello message. * * @param messageID The message ID to use for this message. * @param element The ASN.1 element containing the ClientHello sequence. * * @return The client hello message decoded from the ASN.1 element. * * @throws SLAMDException If the provided ASN.1 element cannot be decoded * as a client hello message. */ public static ClientHelloMessage decodeClientHello(int messageID, ASN1Element element) throws SLAMDException { ASN1Sequence helloSequence = null; try { helloSequence = element.decodeAsSequence(); } catch (ASN1Exception ae) { throw new SLAMDException("The provided ASN.1 element cannot be decoded " + "as a sequence", ae); } ASN1Element[] elements = helloSequence.getElements(); if ((elements.length < 2) || (elements.length > 6)) { throw new SLAMDException("There must be between 2 and 6 elements in a " + "client hello message"); } String clientVersion = null; try { clientVersion = elements[0].decodeAsOctetString().getStringValue(); } catch (ASN1Exception ae) { throw new SLAMDException("Could not decode first element as an octet " + "string", ae); } String clientID = null; try { clientID = elements[1].decodeAsOctetString().getStringValue(); } catch (ASN1Exception ae) { throw new SLAMDException("Could not decode second element as an octet " + "string", ae); } int authType = Constants.AUTH_TYPE_NONE; String authID = null; String authCredentials = null; if (elements.length >= 3) { try { ASN1Element[] authElements = elements[2].decodeAsSequence().getElements(); if (authElements.length != 3) { throw new SLAMDException("There must be three elements in an " + "authentication sequence"); } authType = authElements[0].decodeAsInteger().getIntValue(); authID = authElements[1].decodeAsOctetString().getStringValue(); authCredentials = authElements[2].decodeAsOctetString().getStringValue(); } catch (ASN1Exception ae) { throw new SLAMDException("Could not decode the authentication " + "information", ae); } } boolean requestServerAuth = false; if (elements.length >= 4) { try { requestServerAuth = elements[3].decodeAsBoolean().getBooleanValue(); } catch (ASN1Exception ae) { throw new SLAMDException("Could not decode the requestServerAuth " + "information", ae); } } boolean restrictedMode = false; if (elements.length >= 5) { try { restrictedMode = elements[4].decodeAsBoolean().getBooleanValue(); } catch (ASN1Exception ae) { throw new SLAMDException("Could not decode the restricted mode " + "information", ae); } } boolean supportsTimeSync = false; if (elements.length == 6) { try { supportsTimeSync = elements[5].decodeAsBoolean().getBooleanValue(); } catch (ASN1Exception ae) { throw new SLAMDException("Could not decode the time synchronization " + "information", ae); } } return new ClientHelloMessage(messageID, clientVersion, clientID, authType, authID, authCredentials, requestServerAuth, restrictedMode, supportsTimeSync); } /** * Encodes this message into an ASN.1 element. A client hello message has the * following ASN.1 syntax: * <BR><BR> * <CODE>ClientHello ::= [APPLICATION 0] SEQUENCE {</CODE> * <CODE> clientVersion OCTET STRING,</CODE> * <CODE> clientID OCTET STRING,</CODE> * <CODE> authentication Authentication OPTIONAL,</CODE> * <CODE> requestServerAuth BOOLEAN OPTIONAL DEFAULT FALSE,</CODE> * <CODE> restrictedMode BOOLEAN OPTIONAL DEFAULT FALSE }</CODE> * <CODE> supportsTimeSync BOOLEAN OPTIONAL DEFAULT FALSE }</CODE> * <BR> * * @return An ASN.1 encoded representation of this message. */ @Override() public ASN1Element encode() { ASN1Integer messageIDElement = new ASN1Integer(messageID); ArrayList<ASN1Element> elementList = new ArrayList<ASN1Element>(); elementList.add(new ASN1OctetString(clientVersion)); elementList.add(new ASN1OctetString(clientID)); if ((authType != Constants.AUTH_TYPE_NONE) || requestServerAuth || restrictedMode || supportsTimeSync) { if (authType == Constants.AUTH_TYPE_SIMPLE) { ASN1Element[] authElements = new ASN1Element[] { new ASN1Enumerated(Constants.AUTH_TYPE_SIMPLE), new ASN1OctetString(authID), new ASN1OctetString(authCredentials) }; elementList.add(new ASN1Sequence(authElements)); } else { ASN1Element[] authElements = new ASN1Element[] { new ASN1Enumerated(Constants.AUTH_TYPE_NONE), new ASN1OctetString(), new ASN1OctetString() }; elementList.add(new ASN1Sequence(authElements)); } if (requestServerAuth || restrictedMode || supportsTimeSync) { elementList.add(new ASN1Boolean(requestServerAuth)); } if (restrictedMode || supportsTimeSync) { elementList.add(new ASN1Boolean(restrictedMode)); } if (supportsTimeSync) { elementList.add(new ASN1Boolean(supportsTimeSync)); } } ASN1Element[] clientHelloElements = new ASN1Element[elementList.size()]; elementList.toArray(clientHelloElements); ASN1Sequence clientHelloSequence = new ASN1Sequence(ASN1_TYPE_CLIENT_HELLO, clientHelloElements); ASN1Element[] messageElements = new ASN1Element[] { messageIDElement, clientHelloSequence }; return new ASN1Sequence(messageElements); } }