From e32debe1df7d0a837e30cd937fb7a18fc5cfa203 Mon Sep 17 00:00:00 2001 From: Robert Godfrey Date: Thu, 24 Apr 2008 17:49:03 +0000 Subject: QPID-832 : Fix eol-style git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk@651325 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/qpid/sasl/ClientFactoryImpl.java | 686 ++++++++++---------- .../java/org/apache/qpid/sasl/CramMD5Client.java | 694 ++++++++++----------- .../java/org/apache/qpid/sasl/PlainClient.java | 550 ++++++++-------- .../main/java/org/apache/qpid/sasl/Provider.java | 122 ++-- .../test/integration/client/ConnectionTest.java | 132 ++-- 5 files changed, 1092 insertions(+), 1092 deletions(-) (limited to 'qpid/java/client-java14') diff --git a/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/ClientFactoryImpl.java b/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/ClientFactoryImpl.java index 691020307a..ed8e4ad80f 100644 --- a/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/ClientFactoryImpl.java +++ b/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/ClientFactoryImpl.java @@ -1,343 +1,343 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.sasl; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import javax.security.auth.callback.*; -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslClient; -import javax.security.sasl.SaslClientFactory; -import javax.security.sasl.SaslException; - -import org.apache.log4j.Logger; - -import org.apache.qpid.util.PrettyPrintingUtils; - -/** - * Implements a factory for generating Sasl client implementations. - * - *

- *
CRC Card
Responsibilities Collaborations - *
Provide a list of supported encryption mechansims that meet a defined set of Sasl properties. - *
Provide the best matching supported Sasl mechanism to a preference ordered list of mechanisms and Sasl - * properties. - *
Perform username and password request call backs. CallBackHandler - *
- */ -public class ClientFactoryImpl implements SaslClientFactory -{ - //private static final Logger log = Logger.getLogger(ClientFactoryImpl.class); - - /** Holds the names of the supported encryption mechanisms. */ - private static final String[] SUPPORTED_MECHANISMS = { "CRAM-MD5", "PLAIN" }; - - /** Defines index of the CRAM-MD5 mechanism within the supported mechanisms. */ - private static final int CRAM_MD5 = 0; - - /** Defines index of the PLAIN mechanism within the supported mechanisms. */ - private static final int PLAIN = 1; - - /** Bit mapping of the no plain text policy. */ - private static final int NOPLAINTEXT = 0x0001; - - /** Bit mapping of the no susceptible active attacks policy. */ - private static final int NOACTIVE = 0x0002; - - /** Bit mapping of the no susceptible to dictionary attacks policy. */ - private static final int NODICTIONARY = 0x0004; - - /** Bit mapping of the must use forward secrecy between sessions policy. */ - private static final int FORWARD_SECRECY = 0x0008; - - /** Bit mapping of the no anonymous logins policy. */ - private static final int NOANONYMOUS = 0x0010; - - /** Bit mapping of the must pass credentials policy. */ - private static final int PASS_CREDENTIALS = 0x0020; - - /** Defines a mapping from supported mechanisms to supported policy flags. */ - private static final int[] SUPPPORTED_MECHANISMS_POLICIES = - { - NOPLAINTEXT | NOANONYMOUS, // CRAM-MD5 - NOANONYMOUS // PLAIN - }; - - /** - * Creates a SaslClient using the parameters supplied. - * - * @param mechanisms The non-null list of mechanism names to try. Each is the IANA-registered name of a SASL - * mechanism. (e.g. "GSSAPI", "CRAM-MD5"). - * @param authorizationId The possibly null protocol-dependent identification to be used for authorization. - * If null or empty, the server derives an authorization ID from the client's authentication - * credentials. When the SASL authentication completes successfully, the specified entity is - * granted access. - * @param protocol The non-null string name of the protocol for which the authentication is being performed - * (e.g., "ldap"). - * @param serverName The non-null fully qualified host name of the server to authenticate to. - * @param props The possibly null set of properties used to select the SASL mechanism and to configure the - * authentication exchange of the selected mechanism. See the Sasl class for a list - * of standard properties. Other, possibly mechanism-specific, properties can be included. - * Properties not relevant to the selected mechanism are ignored. - * @param cbh The possibly null callback handler to used by the SASL mechanisms to get further - * information from the application/library to complete the authentication. For example, a - * SASL mechanism might require the authentication ID, password and realm from the caller. - * The authentication ID is requested by using a NameCallback. - * The password is requested by using a PasswordCallback. - * The realm is requested by using a RealmChoiceCallback if there is a list - * of realms to choose from, and by using a RealmCallback if - * the realm must be entered. - * - * @return A possibly null SaslClient created using the parameters supplied. If null, this factory cannot - * produce a SaslClient using the parameters supplied. - * - * @throws javax.security.sasl.SaslException If cannot create a SaslClient because of an error. - */ - public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol, String serverName, - Map props, CallbackHandler cbh) throws SaslException - { - /*log.debug("public SaslClient createSaslClient(String[] mechanisms = " + PrettyPrintingUtils.printArray(mechanisms) - + ", String authorizationId = " + authorizationId + ", String protocol = " + protocol - + ", String serverName = " + serverName + ", Map props = " + props + ", CallbackHandler cbh): called");*/ - - // Get a list of all supported mechanisms that matched the required properties. - String[] matchingMechanisms = getMechanismNames(props); - //log.debug("matchingMechanisms = " + PrettyPrintingUtils.printArray(matchingMechanisms)); - - // Scan down the list of mechanisms until the first one that matches one of the matching supported mechanisms - // is found. - String chosenMechanism = null; - - for (int i = 0; i < mechanisms.length; i++) - { - String mechanism = mechanisms[i]; - - for (int j = 0; j < matchingMechanisms.length; j++) - { - String matchingMechanism = matchingMechanisms[j]; - - if (mechanism.equals(matchingMechanism)) - { - chosenMechanism = mechanism; - - break; - } - } - - // Stop scanning if a match has been found. - if (chosenMechanism != null) - { - break; - } - } - - // Check that a matching mechanism was found or return null otherwise. - if (chosenMechanism == null) - { - //log.debug("No matching mechanism could be found."); - - return null; - } - - // Instantiate an appropriate client type for the chosen mechanism. - if (chosenMechanism.equals(SUPPORTED_MECHANISMS[CRAM_MD5])) - { - Object[] uinfo = getUserInfo("CRAM-MD5", authorizationId, cbh); - - //log.debug("Using CRAM-MD5 mechanism."); - - return new CramMD5Client((String) uinfo[0], (byte[]) uinfo[1]); - } - else - { - Object[] uinfo = getUserInfo("PLAIN", authorizationId, cbh); - - //log.debug("Using PLAIN mechanism."); - - return new PlainClient(authorizationId, (String) uinfo[0], (byte[]) uinfo[1]); - } - } - - /** - * Returns an array of names of mechanisms that match the specified - * mechanism selection policies. - * - * @param props The possibly null set of properties used to specify the - * security policy of the SASL mechanisms. For example, if props - * contains the Sasl.POLICY_NOPLAINTEXT property with the value - * "true", then the factory must not return any SASL mechanisms - * that are susceptible to simple plain passive attacks. - * See the Sasl class for a complete list of policy properties. - * Non-policy related properties, if present in props, are ignored. - * - * @return A non-null array containing a IANA-registered SASL mechanism names. - */ - public String[] getMechanismNames(Map props) - { - //log.debug("public String[] getMechanismNames(Map props = " + props + "): called"); - - // Used to build up the valid mechanisms in. - List validMechanisms = new ArrayList(); - - // Transform the Sasl properties into a set of bit mapped flags indicating the required properties of the - // encryption mechanism employed. - int requiredFlags = bitMapSaslProperties(props); - //log.debug("requiredFlags = " + requiredFlags); - - // Scan down the list of supported mechanisms filtering in only those that satisfy all of the desired - // encryption properties. - for (int i = 0; i < SUPPORTED_MECHANISMS.length; i++) - { - int mechanismFlags = SUPPPORTED_MECHANISMS_POLICIES[i]; - //log.debug("mechanismFlags = " + mechanismFlags); - - // Check if the current mechanism contains all of the required flags. - if ((requiredFlags & ~mechanismFlags) == 0) - { - //log.debug("Mechanism " + SUPPORTED_MECHANISMS[i] + " meets the required properties."); - validMechanisms.add(SUPPORTED_MECHANISMS[i]); - } - } - - String[] result = (String[]) validMechanisms.toArray(new String[validMechanisms.size()]); - - //log.debug("result = " + PrettyPrintingUtils.printArray(result)); - - return result; - } - - /** - * Transforms a set of Sasl properties, defined using the property names in javax.security.sasl.Sasl, into - * a bit mapped set of property flags encoded using the bit mapping constants defined in this class. - * - * @param properties The Sasl properties to bit map. - * - * @return A set of bit mapped properties encoded in an integer. - */ - private int bitMapSaslProperties(Map properties) - { - //log.debug("private int bitMapSaslProperties(Map properties = " + properties + "): called"); - - int result = 0; - - // No flags set if no properties are set. - if (properties == null) - { - return result; - } - - if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_NOPLAINTEXT))) - { - result |= NOPLAINTEXT; - } - - if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_NOACTIVE))) - { - result |= NOACTIVE; - } - - if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_NODICTIONARY))) - { - result |= NODICTIONARY; - } - - if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_NOANONYMOUS))) - { - result |= NOANONYMOUS; - } - - if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_FORWARD_SECRECY))) - { - result |= FORWARD_SECRECY; - } - - if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_PASS_CREDENTIALS))) - { - result |= PASS_CREDENTIALS; - } - - return result; - } - - /** - * Uses the specified call back handler to query for the users log in name and password. - * - * @param prefix A prefix to prepend onto the username and password queries. - * @param authorizationId The default autorhization name. - * @param cbh The call back handler. - * - * @return The username and password from the callback. - * - * @throws SaslException If the callback fails for any reason. - */ - private Object[] getUserInfo(String prefix, String authorizationId, CallbackHandler cbh) throws SaslException - { - // Check that the callback handler is defined. - if (cbh == null) - { - throw new SaslException("Callback handler to get username/password required."); - } - - try - { - String userPrompt = prefix + " authentication id: "; - String passwdPrompt = prefix + " password: "; - - NameCallback ncb = - (authorizationId == null) ? new NameCallback(userPrompt) : new NameCallback(userPrompt, authorizationId); - PasswordCallback pcb = new PasswordCallback(passwdPrompt, false); - - // Ask the call back handler to get the users name and password. - cbh.handle(new Callback[] { ncb, pcb }); - - char[] pw = pcb.getPassword(); - - byte[] bytepw; - String authId; - - if (pw != null) - { - bytepw = new String(pw).getBytes("UTF8"); - pcb.clearPassword(); - } - else - { - bytepw = null; - } - - authId = ncb.getName(); - - return new Object[] { authId, bytepw }; - } - catch (IOException e) - { - throw new SaslException("Cannot get password.", e); - } - catch (UnsupportedCallbackException e) - { - throw new SaslException("Cannot get userid/password.", e); - } - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.sasl; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.security.auth.callback.*; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslClientFactory; +import javax.security.sasl.SaslException; + +import org.apache.log4j.Logger; + +import org.apache.qpid.util.PrettyPrintingUtils; + +/** + * Implements a factory for generating Sasl client implementations. + * + *

+ *
CRC Card
Responsibilities Collaborations + *
Provide a list of supported encryption mechansims that meet a defined set of Sasl properties. + *
Provide the best matching supported Sasl mechanism to a preference ordered list of mechanisms and Sasl + * properties. + *
Perform username and password request call backs. CallBackHandler + *
+ */ +public class ClientFactoryImpl implements SaslClientFactory +{ + //private static final Logger log = Logger.getLogger(ClientFactoryImpl.class); + + /** Holds the names of the supported encryption mechanisms. */ + private static final String[] SUPPORTED_MECHANISMS = { "CRAM-MD5", "PLAIN" }; + + /** Defines index of the CRAM-MD5 mechanism within the supported mechanisms. */ + private static final int CRAM_MD5 = 0; + + /** Defines index of the PLAIN mechanism within the supported mechanisms. */ + private static final int PLAIN = 1; + + /** Bit mapping of the no plain text policy. */ + private static final int NOPLAINTEXT = 0x0001; + + /** Bit mapping of the no susceptible active attacks policy. */ + private static final int NOACTIVE = 0x0002; + + /** Bit mapping of the no susceptible to dictionary attacks policy. */ + private static final int NODICTIONARY = 0x0004; + + /** Bit mapping of the must use forward secrecy between sessions policy. */ + private static final int FORWARD_SECRECY = 0x0008; + + /** Bit mapping of the no anonymous logins policy. */ + private static final int NOANONYMOUS = 0x0010; + + /** Bit mapping of the must pass credentials policy. */ + private static final int PASS_CREDENTIALS = 0x0020; + + /** Defines a mapping from supported mechanisms to supported policy flags. */ + private static final int[] SUPPPORTED_MECHANISMS_POLICIES = + { + NOPLAINTEXT | NOANONYMOUS, // CRAM-MD5 + NOANONYMOUS // PLAIN + }; + + /** + * Creates a SaslClient using the parameters supplied. + * + * @param mechanisms The non-null list of mechanism names to try. Each is the IANA-registered name of a SASL + * mechanism. (e.g. "GSSAPI", "CRAM-MD5"). + * @param authorizationId The possibly null protocol-dependent identification to be used for authorization. + * If null or empty, the server derives an authorization ID from the client's authentication + * credentials. When the SASL authentication completes successfully, the specified entity is + * granted access. + * @param protocol The non-null string name of the protocol for which the authentication is being performed + * (e.g., "ldap"). + * @param serverName The non-null fully qualified host name of the server to authenticate to. + * @param props The possibly null set of properties used to select the SASL mechanism and to configure the + * authentication exchange of the selected mechanism. See the Sasl class for a list + * of standard properties. Other, possibly mechanism-specific, properties can be included. + * Properties not relevant to the selected mechanism are ignored. + * @param cbh The possibly null callback handler to used by the SASL mechanisms to get further + * information from the application/library to complete the authentication. For example, a + * SASL mechanism might require the authentication ID, password and realm from the caller. + * The authentication ID is requested by using a NameCallback. + * The password is requested by using a PasswordCallback. + * The realm is requested by using a RealmChoiceCallback if there is a list + * of realms to choose from, and by using a RealmCallback if + * the realm must be entered. + * + * @return A possibly null SaslClient created using the parameters supplied. If null, this factory cannot + * produce a SaslClient using the parameters supplied. + * + * @throws javax.security.sasl.SaslException If cannot create a SaslClient because of an error. + */ + public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol, String serverName, + Map props, CallbackHandler cbh) throws SaslException + { + /*log.debug("public SaslClient createSaslClient(String[] mechanisms = " + PrettyPrintingUtils.printArray(mechanisms) + + ", String authorizationId = " + authorizationId + ", String protocol = " + protocol + + ", String serverName = " + serverName + ", Map props = " + props + ", CallbackHandler cbh): called");*/ + + // Get a list of all supported mechanisms that matched the required properties. + String[] matchingMechanisms = getMechanismNames(props); + //log.debug("matchingMechanisms = " + PrettyPrintingUtils.printArray(matchingMechanisms)); + + // Scan down the list of mechanisms until the first one that matches one of the matching supported mechanisms + // is found. + String chosenMechanism = null; + + for (int i = 0; i < mechanisms.length; i++) + { + String mechanism = mechanisms[i]; + + for (int j = 0; j < matchingMechanisms.length; j++) + { + String matchingMechanism = matchingMechanisms[j]; + + if (mechanism.equals(matchingMechanism)) + { + chosenMechanism = mechanism; + + break; + } + } + + // Stop scanning if a match has been found. + if (chosenMechanism != null) + { + break; + } + } + + // Check that a matching mechanism was found or return null otherwise. + if (chosenMechanism == null) + { + //log.debug("No matching mechanism could be found."); + + return null; + } + + // Instantiate an appropriate client type for the chosen mechanism. + if (chosenMechanism.equals(SUPPORTED_MECHANISMS[CRAM_MD5])) + { + Object[] uinfo = getUserInfo("CRAM-MD5", authorizationId, cbh); + + //log.debug("Using CRAM-MD5 mechanism."); + + return new CramMD5Client((String) uinfo[0], (byte[]) uinfo[1]); + } + else + { + Object[] uinfo = getUserInfo("PLAIN", authorizationId, cbh); + + //log.debug("Using PLAIN mechanism."); + + return new PlainClient(authorizationId, (String) uinfo[0], (byte[]) uinfo[1]); + } + } + + /** + * Returns an array of names of mechanisms that match the specified + * mechanism selection policies. + * + * @param props The possibly null set of properties used to specify the + * security policy of the SASL mechanisms. For example, if props + * contains the Sasl.POLICY_NOPLAINTEXT property with the value + * "true", then the factory must not return any SASL mechanisms + * that are susceptible to simple plain passive attacks. + * See the Sasl class for a complete list of policy properties. + * Non-policy related properties, if present in props, are ignored. + * + * @return A non-null array containing a IANA-registered SASL mechanism names. + */ + public String[] getMechanismNames(Map props) + { + //log.debug("public String[] getMechanismNames(Map props = " + props + "): called"); + + // Used to build up the valid mechanisms in. + List validMechanisms = new ArrayList(); + + // Transform the Sasl properties into a set of bit mapped flags indicating the required properties of the + // encryption mechanism employed. + int requiredFlags = bitMapSaslProperties(props); + //log.debug("requiredFlags = " + requiredFlags); + + // Scan down the list of supported mechanisms filtering in only those that satisfy all of the desired + // encryption properties. + for (int i = 0; i < SUPPORTED_MECHANISMS.length; i++) + { + int mechanismFlags = SUPPPORTED_MECHANISMS_POLICIES[i]; + //log.debug("mechanismFlags = " + mechanismFlags); + + // Check if the current mechanism contains all of the required flags. + if ((requiredFlags & ~mechanismFlags) == 0) + { + //log.debug("Mechanism " + SUPPORTED_MECHANISMS[i] + " meets the required properties."); + validMechanisms.add(SUPPORTED_MECHANISMS[i]); + } + } + + String[] result = (String[]) validMechanisms.toArray(new String[validMechanisms.size()]); + + //log.debug("result = " + PrettyPrintingUtils.printArray(result)); + + return result; + } + + /** + * Transforms a set of Sasl properties, defined using the property names in javax.security.sasl.Sasl, into + * a bit mapped set of property flags encoded using the bit mapping constants defined in this class. + * + * @param properties The Sasl properties to bit map. + * + * @return A set of bit mapped properties encoded in an integer. + */ + private int bitMapSaslProperties(Map properties) + { + //log.debug("private int bitMapSaslProperties(Map properties = " + properties + "): called"); + + int result = 0; + + // No flags set if no properties are set. + if (properties == null) + { + return result; + } + + if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_NOPLAINTEXT))) + { + result |= NOPLAINTEXT; + } + + if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_NOACTIVE))) + { + result |= NOACTIVE; + } + + if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_NODICTIONARY))) + { + result |= NODICTIONARY; + } + + if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_NOANONYMOUS))) + { + result |= NOANONYMOUS; + } + + if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_FORWARD_SECRECY))) + { + result |= FORWARD_SECRECY; + } + + if ("true".equalsIgnoreCase((String) properties.get(Sasl.POLICY_PASS_CREDENTIALS))) + { + result |= PASS_CREDENTIALS; + } + + return result; + } + + /** + * Uses the specified call back handler to query for the users log in name and password. + * + * @param prefix A prefix to prepend onto the username and password queries. + * @param authorizationId The default autorhization name. + * @param cbh The call back handler. + * + * @return The username and password from the callback. + * + * @throws SaslException If the callback fails for any reason. + */ + private Object[] getUserInfo(String prefix, String authorizationId, CallbackHandler cbh) throws SaslException + { + // Check that the callback handler is defined. + if (cbh == null) + { + throw new SaslException("Callback handler to get username/password required."); + } + + try + { + String userPrompt = prefix + " authentication id: "; + String passwdPrompt = prefix + " password: "; + + NameCallback ncb = + (authorizationId == null) ? new NameCallback(userPrompt) : new NameCallback(userPrompt, authorizationId); + PasswordCallback pcb = new PasswordCallback(passwdPrompt, false); + + // Ask the call back handler to get the users name and password. + cbh.handle(new Callback[] { ncb, pcb }); + + char[] pw = pcb.getPassword(); + + byte[] bytepw; + String authId; + + if (pw != null) + { + bytepw = new String(pw).getBytes("UTF8"); + pcb.clearPassword(); + } + else + { + bytepw = null; + } + + authId = ncb.getName(); + + return new Object[] { authId, bytepw }; + } + catch (IOException e) + { + throw new SaslException("Cannot get password.", e); + } + catch (UnsupportedCallbackException e) + { + throw new SaslException("Cannot get userid/password.", e); + } + } +} diff --git a/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/CramMD5Client.java b/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/CramMD5Client.java index 7d15f03329..4f890ffed5 100644 --- a/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/CramMD5Client.java +++ b/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/CramMD5Client.java @@ -1,347 +1,347 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.sasl; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslClient; -import javax.security.sasl.SaslException; - -/** - * Implements the CRAM-MD5 SASL mechanism. - * - *

- *
CRC Card
Responsibilities Collaborations - *
Concatenate the user id and password hashed by a challenge string as the challenge response. - *
Ensure password is wiped once a challenge has been processed. - *
- */ -public class CramMD5Client implements SaslClient -{ - /** Defines the HMAC block size. */ - private static final int MD5_BLOCKSIZE = 64; - - /** Flag used to indicate that the authentication has completed. */ - private boolean completed = false; - - private String authenticationId; - private byte[] password; - - /** - * Creates a PLAIN SASL client for an authorization id, authentication id and password. - * - * @param authenticationId The authentication id. - * @param password The password. - * - * @throws SaslException If the authentication id or password is null. - */ - CramMD5Client(String authenticationId, byte[] password) throws SaslException - { - // Check that a username and password are specified. - if ((authenticationId == null) || (password == null)) - { - throw new SaslException("CRAM: authentication id and password must be specified"); - } - - // Keep the log in credentials. - this.authenticationId = authenticationId; - this.password = password; - } - - /** - * Returns the IANA-registered mechanism name of this SASL client. (e.g. "CRAM-MD5", "GSSAPI"). - * - * @return A non-null string representing the IANA-registered mechanism name. - */ - public String getMechanismName() - { - return "CRAM-MD5"; - } - - /** - * Determines whether this mechanism has an optional initial response. If true, caller should call - * evaluateChallenge() with an empty array to get the initial response. - * - *

CRAM-MD5 has no intial response. - * - * @return true if this mechanism has an initial response. - */ - public boolean hasInitialResponse() - { - return false; - } - - /** - * Evaluates the challenge data and generates a response. If a challenge is received from the server during the - * authentication process, this method is called to prepare an appropriate next response to submit to the server. - * - *

The initial response for the SASL command, for the CRAM-MD5 mechanism is the concatenation of authentication - * ID and password HMAC-MD5 hashed by the server challenge. - * - * @param challenge The non-null challenge sent from the server. The challenge array may have zero length. - * - * @return The possibly null reponse to send to the server. It is null if the challenge accompanied a "SUCCESS" - * status and the challenge only contains data for the client to update its state and no response - * needs to be sent to the server. The response is a zero-length byte array if the client is to send a - * response with no data. - * - * @throws javax.security.sasl.SaslException If an error occurred while processing the challenge or generating a - * response. - */ - public byte[] evaluateChallenge(byte[] challenge) throws SaslException - { - // Check that the authentication has not already been performed. - if (completed) - { - throw new IllegalStateException("CRAM-MD5 authentication already completed."); - } - - // Check if the password is null, this will be the case if a previous attempt to authenticated failed. - if (password == null) - { - throw new IllegalStateException("CRAM-MD5 authentication previously aborted due to error."); - } - - // Generate a keyed-MD5 digest from the user's password keyed by the challenge bytes. - try - { - String digest = hmac_md5(password, challenge); - String result = authenticationId + " " + digest; - - completed = true; - - return result.getBytes("UTF8"); - } - catch (java.security.NoSuchAlgorithmException e) - { - throw new SaslException("MD5 algorithm not available on platform", e); - } - catch (java.io.UnsupportedEncodingException e) - { - throw new SaslException("UTF8 not available on platform", e); - } - finally - { - clearPassword(); - } - } - - /** - * Determines whether the authentication exchange has completed. This method may be called at any time, but - * typically, it will not be called until the caller has received indication from the server (in a protocol-specific - * manner) that the exchange has completed. - * - * @return true if the authentication exchange has completed; false otherwise. - */ - public boolean isComplete() - { - return completed; - } - - /** - * Unwraps a byte array received from the server. This method can be called only after the authentication exchange - * has completed (i.e., when isComplete() returns true) and only if the authentication exchange has - * negotiated integrity and/or privacy as the quality of protection; otherwise, an IllegalStateException is - * thrown. - * - *

incoming is the contents of the SASL buffer as defined in RFC 2222 without the leading four octet - * field that represents the length. offset and len specify the portion of incoming - * to use. - * - * @param incoming A non-null byte array containing the encoded bytes from the server. - * @param offset The starting position at incoming of the bytes to use. - * @param len The number of bytes from incoming to use. - * - * @return A non-null byte array containing the decoded bytes. - * - * @throws javax.security.sasl.SaslException If incoming cannot be successfully unwrapped. - * @throws IllegalStateException If the authentication exchange has not completed, or if the negotiated quality of - * protection has neither integrity nor privacy. - */ - public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException - { - throw new SaslException("CRAM-MD5 does not support quality of protection."); - } - - /** - * Wraps a byte array to be sent to the server. This method can be called only after the authentication exchange has - * completed (i.e., when isComplete() returns true) and only if the authentication exchange has negotiated - * integrity and/or privacy as the quality of protection; otherwise, an IllegalStateException is thrown. - * - *

The result of this method will make up the contents of the SASL buffer as defined in RFC 2222 without the - * leading four octet field that represents the length. offset and len specify the portion of - * outgoing to use. - * - * @param outgoing A non-null byte array containing the bytes to encode. - * @param offset The starting position at outgoing of the bytes to use. - * @param len The number of bytes from outgoing to use. - * - * @return A non-null byte array containing the encoded bytes. - * - * @throws javax.security.sasl.SaslException If outgoing cannot be successfully wrapped. - * @throws IllegalStateException If the authentication exchange has not completed, or if the negotiated quality of - * protection has neither integrity nor privacy. - */ - public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException - { - throw new SaslException("CRAM-MD5 does not support quality of protection."); - } - - /** - * Retrieves the negotiated property. This method can be called only after the authentication exchange has - * completed (i.e., when isComplete() returns true); otherwise, an IllegalStateException is thrown. - * - * @param propName The non-null property name. - * - * @return The value of the negotiated property. If null, the property was not negotiated or is not applicable to - * this mechanism. - * - * @throws IllegalStateException If this authentication exchange has not completed. - */ - public Object getNegotiatedProperty(String propName) - { - if (completed) - { - if (propName.equals(Sasl.QOP)) - { - return "auth"; - } - else - { - return null; - } - } - else - { - throw new IllegalStateException("CRAM-MD5 authentication not completed"); - } - } - - /** - * Disposes of any system resources or security-sensitive information the SaslClient might be using. Invoking this - * method invalidates the SaslClient instance. This method is idempotent. - * - * @throws javax.security.sasl.SaslException If a problem was encountered while disposing the resources. - */ - public void dispose() throws SaslException - { } - - /* - * Hashes its input arguments according to HMAC-MD5 (RFC 2104) and returns the resulting digest in its ASCII - * representation. - * - *

The HMAC-MD5 function is described as follows: - *

-     *     MD5(key XOR opad, MD5(key XOR ipad, text))
-     * 
- * - *

Where key is an n byte key, ipad is the byte 0x36 repeated 64 times, opad is the byte 0x5c repeated 64 times - * and text is the data to be protected. - * - * @param key The key to hash by. - * @param text The plain text to hash. - * - * @return The hashed text. - * - * @throws NoSuchAlgorithmException If the Java platform does not supply an MD5 implementation. - */ - private static final String hmac_md5(byte[] key, byte[] text) throws NoSuchAlgorithmException - { - MessageDigest md5 = MessageDigest.getInstance("MD5"); - - /* digest the key if longer than 64 bytes */ - if (key.length > 64) - { - key = md5.digest(key); - } - - byte[] ipad = new byte[MD5_BLOCKSIZE]; /* inner padding */ - byte[] opad = new byte[MD5_BLOCKSIZE]; /* outer padding */ - byte[] digest; - int i; - - /* store key in pads */ - for (i = 0; i < MD5_BLOCKSIZE; i++) - { - for (; i < key.length; i++) - { - ipad[i] = key[i]; - opad[i] = key[i]; - } - - ipad[i] = 0x00; - opad[i] = 0x00; - } - - /* XOR key with pads */ - for (i = 0; i < MD5_BLOCKSIZE; i++) - { - ipad[i] ^= 0x36; - opad[i] ^= 0x5c; - } - - /* inner MD5 */ - md5.update(ipad); - md5.update(text); - digest = md5.digest(); - - /* outer MD5 */ - md5.update(opad); - md5.update(digest); - digest = md5.digest(); - - // Get character representation of digest - StringBuffer digestString = new StringBuffer(); - - for (i = 0; i < digest.length; i++) - { - if ((digest[i] & 0x000000ff) < 0x10) - { - digestString.append("0" + Integer.toHexString(digest[i] & 0x000000ff)); - } - else - { - digestString.append(Integer.toHexString(digest[i] & 0x000000ff)); - } - } - - return (digestString.toString()); - } - - /** - * Overwrites the password with zeros. - */ - private void clearPassword() - { - if (password != null) - { - // Zero out password. - for (int i = 0; i < password.length; i++) - { - password[i] = (byte) 0; - } - - password = null; - } - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.sasl; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + * Implements the CRAM-MD5 SASL mechanism. + * + *

+ *
CRC Card
Responsibilities Collaborations + *
Concatenate the user id and password hashed by a challenge string as the challenge response. + *
Ensure password is wiped once a challenge has been processed. + *
+ */ +public class CramMD5Client implements SaslClient +{ + /** Defines the HMAC block size. */ + private static final int MD5_BLOCKSIZE = 64; + + /** Flag used to indicate that the authentication has completed. */ + private boolean completed = false; + + private String authenticationId; + private byte[] password; + + /** + * Creates a PLAIN SASL client for an authorization id, authentication id and password. + * + * @param authenticationId The authentication id. + * @param password The password. + * + * @throws SaslException If the authentication id or password is null. + */ + CramMD5Client(String authenticationId, byte[] password) throws SaslException + { + // Check that a username and password are specified. + if ((authenticationId == null) || (password == null)) + { + throw new SaslException("CRAM: authentication id and password must be specified"); + } + + // Keep the log in credentials. + this.authenticationId = authenticationId; + this.password = password; + } + + /** + * Returns the IANA-registered mechanism name of this SASL client. (e.g. "CRAM-MD5", "GSSAPI"). + * + * @return A non-null string representing the IANA-registered mechanism name. + */ + public String getMechanismName() + { + return "CRAM-MD5"; + } + + /** + * Determines whether this mechanism has an optional initial response. If true, caller should call + * evaluateChallenge() with an empty array to get the initial response. + * + *

CRAM-MD5 has no intial response. + * + * @return true if this mechanism has an initial response. + */ + public boolean hasInitialResponse() + { + return false; + } + + /** + * Evaluates the challenge data and generates a response. If a challenge is received from the server during the + * authentication process, this method is called to prepare an appropriate next response to submit to the server. + * + *

The initial response for the SASL command, for the CRAM-MD5 mechanism is the concatenation of authentication + * ID and password HMAC-MD5 hashed by the server challenge. + * + * @param challenge The non-null challenge sent from the server. The challenge array may have zero length. + * + * @return The possibly null reponse to send to the server. It is null if the challenge accompanied a "SUCCESS" + * status and the challenge only contains data for the client to update its state and no response + * needs to be sent to the server. The response is a zero-length byte array if the client is to send a + * response with no data. + * + * @throws javax.security.sasl.SaslException If an error occurred while processing the challenge or generating a + * response. + */ + public byte[] evaluateChallenge(byte[] challenge) throws SaslException + { + // Check that the authentication has not already been performed. + if (completed) + { + throw new IllegalStateException("CRAM-MD5 authentication already completed."); + } + + // Check if the password is null, this will be the case if a previous attempt to authenticated failed. + if (password == null) + { + throw new IllegalStateException("CRAM-MD5 authentication previously aborted due to error."); + } + + // Generate a keyed-MD5 digest from the user's password keyed by the challenge bytes. + try + { + String digest = hmac_md5(password, challenge); + String result = authenticationId + " " + digest; + + completed = true; + + return result.getBytes("UTF8"); + } + catch (java.security.NoSuchAlgorithmException e) + { + throw new SaslException("MD5 algorithm not available on platform", e); + } + catch (java.io.UnsupportedEncodingException e) + { + throw new SaslException("UTF8 not available on platform", e); + } + finally + { + clearPassword(); + } + } + + /** + * Determines whether the authentication exchange has completed. This method may be called at any time, but + * typically, it will not be called until the caller has received indication from the server (in a protocol-specific + * manner) that the exchange has completed. + * + * @return true if the authentication exchange has completed; false otherwise. + */ + public boolean isComplete() + { + return completed; + } + + /** + * Unwraps a byte array received from the server. This method can be called only after the authentication exchange + * has completed (i.e., when isComplete() returns true) and only if the authentication exchange has + * negotiated integrity and/or privacy as the quality of protection; otherwise, an IllegalStateException is + * thrown. + * + *

incoming is the contents of the SASL buffer as defined in RFC 2222 without the leading four octet + * field that represents the length. offset and len specify the portion of incoming + * to use. + * + * @param incoming A non-null byte array containing the encoded bytes from the server. + * @param offset The starting position at incoming of the bytes to use. + * @param len The number of bytes from incoming to use. + * + * @return A non-null byte array containing the decoded bytes. + * + * @throws javax.security.sasl.SaslException If incoming cannot be successfully unwrapped. + * @throws IllegalStateException If the authentication exchange has not completed, or if the negotiated quality of + * protection has neither integrity nor privacy. + */ + public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException + { + throw new SaslException("CRAM-MD5 does not support quality of protection."); + } + + /** + * Wraps a byte array to be sent to the server. This method can be called only after the authentication exchange has + * completed (i.e., when isComplete() returns true) and only if the authentication exchange has negotiated + * integrity and/or privacy as the quality of protection; otherwise, an IllegalStateException is thrown. + * + *

The result of this method will make up the contents of the SASL buffer as defined in RFC 2222 without the + * leading four octet field that represents the length. offset and len specify the portion of + * outgoing to use. + * + * @param outgoing A non-null byte array containing the bytes to encode. + * @param offset The starting position at outgoing of the bytes to use. + * @param len The number of bytes from outgoing to use. + * + * @return A non-null byte array containing the encoded bytes. + * + * @throws javax.security.sasl.SaslException If outgoing cannot be successfully wrapped. + * @throws IllegalStateException If the authentication exchange has not completed, or if the negotiated quality of + * protection has neither integrity nor privacy. + */ + public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException + { + throw new SaslException("CRAM-MD5 does not support quality of protection."); + } + + /** + * Retrieves the negotiated property. This method can be called only after the authentication exchange has + * completed (i.e., when isComplete() returns true); otherwise, an IllegalStateException is thrown. + * + * @param propName The non-null property name. + * + * @return The value of the negotiated property. If null, the property was not negotiated or is not applicable to + * this mechanism. + * + * @throws IllegalStateException If this authentication exchange has not completed. + */ + public Object getNegotiatedProperty(String propName) + { + if (completed) + { + if (propName.equals(Sasl.QOP)) + { + return "auth"; + } + else + { + return null; + } + } + else + { + throw new IllegalStateException("CRAM-MD5 authentication not completed"); + } + } + + /** + * Disposes of any system resources or security-sensitive information the SaslClient might be using. Invoking this + * method invalidates the SaslClient instance. This method is idempotent. + * + * @throws javax.security.sasl.SaslException If a problem was encountered while disposing the resources. + */ + public void dispose() throws SaslException + { } + + /* + * Hashes its input arguments according to HMAC-MD5 (RFC 2104) and returns the resulting digest in its ASCII + * representation. + * + *

The HMAC-MD5 function is described as follows: + *

+     *     MD5(key XOR opad, MD5(key XOR ipad, text))
+     * 
+ * + *

Where key is an n byte key, ipad is the byte 0x36 repeated 64 times, opad is the byte 0x5c repeated 64 times + * and text is the data to be protected. + * + * @param key The key to hash by. + * @param text The plain text to hash. + * + * @return The hashed text. + * + * @throws NoSuchAlgorithmException If the Java platform does not supply an MD5 implementation. + */ + private static final String hmac_md5(byte[] key, byte[] text) throws NoSuchAlgorithmException + { + MessageDigest md5 = MessageDigest.getInstance("MD5"); + + /* digest the key if longer than 64 bytes */ + if (key.length > 64) + { + key = md5.digest(key); + } + + byte[] ipad = new byte[MD5_BLOCKSIZE]; /* inner padding */ + byte[] opad = new byte[MD5_BLOCKSIZE]; /* outer padding */ + byte[] digest; + int i; + + /* store key in pads */ + for (i = 0; i < MD5_BLOCKSIZE; i++) + { + for (; i < key.length; i++) + { + ipad[i] = key[i]; + opad[i] = key[i]; + } + + ipad[i] = 0x00; + opad[i] = 0x00; + } + + /* XOR key with pads */ + for (i = 0; i < MD5_BLOCKSIZE; i++) + { + ipad[i] ^= 0x36; + opad[i] ^= 0x5c; + } + + /* inner MD5 */ + md5.update(ipad); + md5.update(text); + digest = md5.digest(); + + /* outer MD5 */ + md5.update(opad); + md5.update(digest); + digest = md5.digest(); + + // Get character representation of digest + StringBuffer digestString = new StringBuffer(); + + for (i = 0; i < digest.length; i++) + { + if ((digest[i] & 0x000000ff) < 0x10) + { + digestString.append("0" + Integer.toHexString(digest[i] & 0x000000ff)); + } + else + { + digestString.append(Integer.toHexString(digest[i] & 0x000000ff)); + } + } + + return (digestString.toString()); + } + + /** + * Overwrites the password with zeros. + */ + private void clearPassword() + { + if (password != null) + { + // Zero out password. + for (int i = 0; i < password.length; i++) + { + password[i] = (byte) 0; + } + + password = null; + } + } +} diff --git a/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/PlainClient.java b/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/PlainClient.java index 97e607c57e..f5a9f150bb 100644 --- a/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/PlainClient.java +++ b/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/PlainClient.java @@ -1,275 +1,275 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.sasl; - -import javax.security.sasl.Sasl; -import javax.security.sasl.SaslClient; -import javax.security.sasl.SaslException; - -/** - * Implements the PLAIN SASL mechanism. - * - *

- *
CRC Card
Responsibilities Collaborations - *
Concatenate the user id and password in plain text as the challenge respose. - *
Ensure password is wiped once a challenge has been processed. - *
- */ -public class PlainClient implements SaslClient -{ - /** Flag used to indicate that the authentication has completed. */ - private boolean completed = false; - - private String authorizationId; - private String authenticationId; - private byte[] password; - - private static byte SEPERATOR = 0; // US-ASCII - - /** - * Creates a PLAIN SASL client for an authorization id, authentication id and password. - * - * @param authorizationId The authorization id. May be null. - * @param authenticationId The authentication id. - * @param password The password. - * - * @throws SaslException If the authentication id or password is null. - */ - PlainClient(String authorizationId, String authenticationId, byte[] password) throws SaslException - { - // Check that a username and password are specified. - if ((authenticationId == null) || (password == null)) - { - throw new SaslException("PLAIN: authentication ID and password must be specified"); - } - - // Keep the log in credentials. - this.authorizationId = authorizationId; - this.authenticationId = authenticationId; - this.password = password; - } - - /** - * Returns the IANA-registered mechanism name of this SASL client. (e.g. "CRAM-MD5", "GSSAPI"). - * - * @return A non-null string representing the IANA-registered mechanism name. - */ - public String getMechanismName() - { - return "PLAIN"; - } - - /** - * Determines whether this mechanism has an optional initial response. If true, caller should call - * evaluateChallenge() with an empty array to get the initial response. - * - * @return true if this mechanism has an initial response. - */ - public boolean hasInitialResponse() - { - return true; - } - - /** - * Evaluates the challenge data and generates a response. If a challenge is received from the server during the - * authentication process, this method is called to prepare an appropriate next response to submit to the server. - * - *

The initial response for the SASL command, for the PLAIN mechanism is the concatenation of authorization ID, - * authentication ID and password, with each component separated by the US-ASCII byte. - * - * @param challenge The non-null challenge sent from the server. The challenge array may have zero length. - * - * @return The possibly null reponse to send to the server. It is null if the challenge accompanied a "SUCCESS" - * status and the challenge only contains data for the client to update its state and no response - * needs to be sent to the server. The response is a zero-length byte array if the client is to send a - * response with no data. - * - * @throws javax.security.sasl.SaslException If an error occurred while processing the challenge or generating a - * response. - */ - public byte[] evaluateChallenge(byte[] challenge) throws SaslException - { - // Check that the authentication has not already been performed. - if (completed) - { - throw new IllegalStateException("PLAIN authentication already completed"); - } - - try - { - // Get the authorization and authentication ids in bytes. - byte[] authorizationBytes = (authorizationId != null) ? authorizationId.getBytes("UTF8") : null; - byte[] authenticationBytes = authenticationId.getBytes("UTF8"); - - // Create an array big enough to hold the results. - byte[] result = - new byte[password.length + authenticationBytes.length + 2 - + ((authorizationBytes == null) ? 0 : authorizationBytes.length)]; - - // Copy the authorization id, authentication id and password into the results. - int pos = 0; - if (authorizationBytes != null) - { - System.arraycopy(authorizationBytes, 0, result, 0, authorizationBytes.length); - pos = authorizationBytes.length; - } - - result[pos++] = SEPERATOR; - System.arraycopy(authenticationBytes, 0, result, pos, authenticationBytes.length); - - pos += authenticationBytes.length; - result[pos++] = SEPERATOR; - - System.arraycopy(password, 0, result, pos, password.length); - - completed = true; - - return result; - } - catch (java.io.UnsupportedEncodingException e) - { - throw new SaslException("Cannot get UTF-8 encoding of ids", e); - } - finally - { - clearPassword(); - } - } - - /** - * Determines whether the authentication exchange has completed. This method may be called at any time, but - * typically, it will not be called until the caller has received indication from the server (in a protocol-specific - * manner) that the exchange has completed. - * - * @return true if the authentication exchange has completed; false otherwise. - */ - public boolean isComplete() - { - return completed; - } - - /** - * Unwraps a byte array received from the server. This method can be called only after the authentication exchange has - * completed (i.e., when isComplete() returns true) and only if the authentication exchange has negotiated - * integrity and/or privacy as the quality of protection; otherwise, an IllegalStateException is thrown. - * - *

incoming is the contents of the SASL buffer as defined in RFC 2222 without the leading four octet - * field that represents the length. offset and len specify the portion of incoming - * to use. - * - * @param incoming A non-null byte array containing the encoded bytes - * from the server. - * @param offset The starting position at incoming of the bytes to use. - * @param len The number of bytes from incoming to use. - * - * @return A non-null byte array containing the decoded bytes. - * - * @throws javax.security.sasl.SaslException If incoming cannot be successfully unwrapped. - * @throws IllegalStateException If the authentication exchange has not completed, or if the negotiated quality of - * protection has neither integrity nor privacy. - */ - public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException - { - throw new SaslException("PLAIN does not support quality of protection."); - } - - /** - * Wraps a byte array to be sent to the server. This method can be called only after the authentication exchange has - * completed (i.e., when isComplete() returns true) and only if the authentication exchange has negotiated - * integrity and/or privacy as the quality of protection; otherwise, an IllegalStateException is thrown. - * - *

The result of this method will make up the contents of the SASL buffer as defined in RFC 2222 without the - * leading four octet field that represents the length. offset and len specify the portion of - * outgoing to use. - * - * @param outgoing A non-null byte array containing the bytes to encode. - * @param offset The starting position at outgoing of the bytes to use. - * @param len The number of bytes from outgoing to use. - * - * @return A non-null byte array containing the encoded bytes. - * - * @throws javax.security.sasl.SaslException If outgoing cannot be successfully wrapped. - * @throws IllegalStateException If the authentication exchange has not completed, or if the negotiated quality of - * protection has neither integrity nor privacy. - */ - public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException - { - throw new SaslException("PLAIN does not support quality of protection."); - } - - /** - * Retrieves the negotiated property. This method can be called only after the authentication exchange has - * completed (i.e., when isComplete() returns true); otherwise, an IllegalStateException is thrown. - * - * @param propName The non-null property name. - * - * @return The value of the negotiated property. If null, the property was not negotiated or is not applicable to - * this mechanism. - * - * @throws IllegalStateException If this authentication exchange has not completed. - */ - public Object getNegotiatedProperty(String propName) - { - if (completed) - { - if (propName.equals(Sasl.QOP)) - { - return "auth"; - } - else - { - return null; - } - } - else - { - throw new IllegalStateException("PLAIN authentication not completed"); - } - } - - /** - * Disposes of any system resources or security-sensitive information the SaslClient might be using. Invoking this - * method invalidates the SaslClient instance. This method is idempotent. - * - * @throws javax.security.sasl.SaslException If a problem was encountered while disposing the resources. - */ - public void dispose() throws SaslException - { - clearPassword(); - } - - /** - * Overwrites the password with zeros. - */ - private void clearPassword() - { - if (password != null) - { - // Zero out password. - for (int i = 0; i < password.length; i++) - { - password[i] = (byte) 0; - } - - password = null; - } - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.sasl; + +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslException; + +/** + * Implements the PLAIN SASL mechanism. + * + *

+ *
CRC Card
Responsibilities Collaborations + *
Concatenate the user id and password in plain text as the challenge respose. + *
Ensure password is wiped once a challenge has been processed. + *
+ */ +public class PlainClient implements SaslClient +{ + /** Flag used to indicate that the authentication has completed. */ + private boolean completed = false; + + private String authorizationId; + private String authenticationId; + private byte[] password; + + private static byte SEPERATOR = 0; // US-ASCII + + /** + * Creates a PLAIN SASL client for an authorization id, authentication id and password. + * + * @param authorizationId The authorization id. May be null. + * @param authenticationId The authentication id. + * @param password The password. + * + * @throws SaslException If the authentication id or password is null. + */ + PlainClient(String authorizationId, String authenticationId, byte[] password) throws SaslException + { + // Check that a username and password are specified. + if ((authenticationId == null) || (password == null)) + { + throw new SaslException("PLAIN: authentication ID and password must be specified"); + } + + // Keep the log in credentials. + this.authorizationId = authorizationId; + this.authenticationId = authenticationId; + this.password = password; + } + + /** + * Returns the IANA-registered mechanism name of this SASL client. (e.g. "CRAM-MD5", "GSSAPI"). + * + * @return A non-null string representing the IANA-registered mechanism name. + */ + public String getMechanismName() + { + return "PLAIN"; + } + + /** + * Determines whether this mechanism has an optional initial response. If true, caller should call + * evaluateChallenge() with an empty array to get the initial response. + * + * @return true if this mechanism has an initial response. + */ + public boolean hasInitialResponse() + { + return true; + } + + /** + * Evaluates the challenge data and generates a response. If a challenge is received from the server during the + * authentication process, this method is called to prepare an appropriate next response to submit to the server. + * + *

The initial response for the SASL command, for the PLAIN mechanism is the concatenation of authorization ID, + * authentication ID and password, with each component separated by the US-ASCII byte. + * + * @param challenge The non-null challenge sent from the server. The challenge array may have zero length. + * + * @return The possibly null reponse to send to the server. It is null if the challenge accompanied a "SUCCESS" + * status and the challenge only contains data for the client to update its state and no response + * needs to be sent to the server. The response is a zero-length byte array if the client is to send a + * response with no data. + * + * @throws javax.security.sasl.SaslException If an error occurred while processing the challenge or generating a + * response. + */ + public byte[] evaluateChallenge(byte[] challenge) throws SaslException + { + // Check that the authentication has not already been performed. + if (completed) + { + throw new IllegalStateException("PLAIN authentication already completed"); + } + + try + { + // Get the authorization and authentication ids in bytes. + byte[] authorizationBytes = (authorizationId != null) ? authorizationId.getBytes("UTF8") : null; + byte[] authenticationBytes = authenticationId.getBytes("UTF8"); + + // Create an array big enough to hold the results. + byte[] result = + new byte[password.length + authenticationBytes.length + 2 + + ((authorizationBytes == null) ? 0 : authorizationBytes.length)]; + + // Copy the authorization id, authentication id and password into the results. + int pos = 0; + if (authorizationBytes != null) + { + System.arraycopy(authorizationBytes, 0, result, 0, authorizationBytes.length); + pos = authorizationBytes.length; + } + + result[pos++] = SEPERATOR; + System.arraycopy(authenticationBytes, 0, result, pos, authenticationBytes.length); + + pos += authenticationBytes.length; + result[pos++] = SEPERATOR; + + System.arraycopy(password, 0, result, pos, password.length); + + completed = true; + + return result; + } + catch (java.io.UnsupportedEncodingException e) + { + throw new SaslException("Cannot get UTF-8 encoding of ids", e); + } + finally + { + clearPassword(); + } + } + + /** + * Determines whether the authentication exchange has completed. This method may be called at any time, but + * typically, it will not be called until the caller has received indication from the server (in a protocol-specific + * manner) that the exchange has completed. + * + * @return true if the authentication exchange has completed; false otherwise. + */ + public boolean isComplete() + { + return completed; + } + + /** + * Unwraps a byte array received from the server. This method can be called only after the authentication exchange has + * completed (i.e., when isComplete() returns true) and only if the authentication exchange has negotiated + * integrity and/or privacy as the quality of protection; otherwise, an IllegalStateException is thrown. + * + *

incoming is the contents of the SASL buffer as defined in RFC 2222 without the leading four octet + * field that represents the length. offset and len specify the portion of incoming + * to use. + * + * @param incoming A non-null byte array containing the encoded bytes + * from the server. + * @param offset The starting position at incoming of the bytes to use. + * @param len The number of bytes from incoming to use. + * + * @return A non-null byte array containing the decoded bytes. + * + * @throws javax.security.sasl.SaslException If incoming cannot be successfully unwrapped. + * @throws IllegalStateException If the authentication exchange has not completed, or if the negotiated quality of + * protection has neither integrity nor privacy. + */ + public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException + { + throw new SaslException("PLAIN does not support quality of protection."); + } + + /** + * Wraps a byte array to be sent to the server. This method can be called only after the authentication exchange has + * completed (i.e., when isComplete() returns true) and only if the authentication exchange has negotiated + * integrity and/or privacy as the quality of protection; otherwise, an IllegalStateException is thrown. + * + *

The result of this method will make up the contents of the SASL buffer as defined in RFC 2222 without the + * leading four octet field that represents the length. offset and len specify the portion of + * outgoing to use. + * + * @param outgoing A non-null byte array containing the bytes to encode. + * @param offset The starting position at outgoing of the bytes to use. + * @param len The number of bytes from outgoing to use. + * + * @return A non-null byte array containing the encoded bytes. + * + * @throws javax.security.sasl.SaslException If outgoing cannot be successfully wrapped. + * @throws IllegalStateException If the authentication exchange has not completed, or if the negotiated quality of + * protection has neither integrity nor privacy. + */ + public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException + { + throw new SaslException("PLAIN does not support quality of protection."); + } + + /** + * Retrieves the negotiated property. This method can be called only after the authentication exchange has + * completed (i.e., when isComplete() returns true); otherwise, an IllegalStateException is thrown. + * + * @param propName The non-null property name. + * + * @return The value of the negotiated property. If null, the property was not negotiated or is not applicable to + * this mechanism. + * + * @throws IllegalStateException If this authentication exchange has not completed. + */ + public Object getNegotiatedProperty(String propName) + { + if (completed) + { + if (propName.equals(Sasl.QOP)) + { + return "auth"; + } + else + { + return null; + } + } + else + { + throw new IllegalStateException("PLAIN authentication not completed"); + } + } + + /** + * Disposes of any system resources or security-sensitive information the SaslClient might be using. Invoking this + * method invalidates the SaslClient instance. This method is idempotent. + * + * @throws javax.security.sasl.SaslException If a problem was encountered while disposing the resources. + */ + public void dispose() throws SaslException + { + clearPassword(); + } + + /** + * Overwrites the password with zeros. + */ + private void clearPassword() + { + if (password != null) + { + // Zero out password. + for (int i = 0; i < password.length; i++) + { + password[i] = (byte) 0; + } + + password = null; + } + } +} diff --git a/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/Provider.java b/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/Provider.java index f9a5c42c3d..ef075a0cad 100644 --- a/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/Provider.java +++ b/qpid/java/client-java14/src/main/java/org/apache/qpid/sasl/Provider.java @@ -1,61 +1,61 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.sasl; - -import java.security.AccessController; -import java.security.PrivilegedAction; - -import org.apache.log4j.Logger; - -/** - * A SASL provider for Java 1.4. Declares the capabilities of this implementation, which supports PLAIN and CRAM-MD5 - * client implementations only. - * - *

- *
CRC Card
Responsibilities Collaborations - *
Declare PLAIN SASL support. - *
Declare CRAM-MD5 SASL support. - *
- */ -public class Provider extends java.security.Provider -{ - //Logger log = Logger.getLogger(Provider.class); - - private static final String info = "Qpid SASL provider" + "(implements client mechanisms for: PLAIN, CRAM-MD5)"; - - public Provider() - { - super("QpidSASL", 1.4, info); - - //log.debug("public Provider(): called"); - - AccessController.doPrivileged(new PrivilegedAction() - { - public Object run() - { - put("SaslClientFactory.PLAIN", "org.apache.qpid.sasl.ClientFactoryImpl"); - put("SaslClientFactory.CRAM-MD5", "org.apache.qpid.sasl.ClientFactoryImpl"); - - return null; - } - }); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.sasl; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +import org.apache.log4j.Logger; + +/** + * A SASL provider for Java 1.4. Declares the capabilities of this implementation, which supports PLAIN and CRAM-MD5 + * client implementations only. + * + *

+ *
CRC Card
Responsibilities Collaborations + *
Declare PLAIN SASL support. + *
Declare CRAM-MD5 SASL support. + *
+ */ +public class Provider extends java.security.Provider +{ + //Logger log = Logger.getLogger(Provider.class); + + private static final String info = "Qpid SASL provider" + "(implements client mechanisms for: PLAIN, CRAM-MD5)"; + + public Provider() + { + super("QpidSASL", 1.4, info); + + //log.debug("public Provider(): called"); + + AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + put("SaslClientFactory.PLAIN", "org.apache.qpid.sasl.ClientFactoryImpl"); + put("SaslClientFactory.CRAM-MD5", "org.apache.qpid.sasl.ClientFactoryImpl"); + + return null; + } + }); + } +} diff --git a/qpid/java/client-java14/src/test/java/org/apache/qpid/test/integration/client/ConnectionTest.java b/qpid/java/client-java14/src/test/java/org/apache/qpid/test/integration/client/ConnectionTest.java index 468beda5b5..77cc79bc49 100644 --- a/qpid/java/client-java14/src/test/java/org/apache/qpid/test/integration/client/ConnectionTest.java +++ b/qpid/java/client-java14/src/test/java/org/apache/qpid/test/integration/client/ConnectionTest.java @@ -1,66 +1,66 @@ -/* - * - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * - */ -package org.apache.qpid.test.integration.client; - -import junit.framework.Assert; -import junit.framework.TestCase; - -import org.apache.log4j.Logger; -import org.apache.log4j.NDC; - -import org.apache.qpid.client.AMQConnection; - -/** - * Implements a trivial broker connection test, to a broker on the default port on localhost, to check that SASL - * authentication works. - * - *

- *
CRC Card
Responsibilities Collaborations - *
Check that a connection to a broker can be established. - *
- */ -public class ConnectionTest extends TestCase -{ - private String BROKER_URL = "tcp://localhost:5672"; - - public ConnectionTest(String name) - { - super(name); - } - - /** Check that a connection to a broker can be established. */ - public void testConnection() throws Exception - { - // Open a connection to the broker and close it again. - AMQConnection conn = new AMQConnection(BROKER_URL, "guest", "guest", "clientid", "test"); - conn.close(); - } - - protected void setUp() - { - NDC.push(getName()); - } - - protected void tearDown() - { - NDC.pop(); - } -} +/* + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + */ +package org.apache.qpid.test.integration.client; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.apache.log4j.Logger; +import org.apache.log4j.NDC; + +import org.apache.qpid.client.AMQConnection; + +/** + * Implements a trivial broker connection test, to a broker on the default port on localhost, to check that SASL + * authentication works. + * + *

+ *
CRC Card
Responsibilities Collaborations + *
Check that a connection to a broker can be established. + *
+ */ +public class ConnectionTest extends TestCase +{ + private String BROKER_URL = "tcp://localhost:5672"; + + public ConnectionTest(String name) + { + super(name); + } + + /** Check that a connection to a broker can be established. */ + public void testConnection() throws Exception + { + // Open a connection to the broker and close it again. + AMQConnection conn = new AMQConnection(BROKER_URL, "guest", "guest", "clientid", "test"); + conn.close(); + } + + protected void setUp() + { + NDC.push(getName()); + } + + protected void tearDown() + { + NDC.pop(); + } +} -- cgit v1.2.1