diff options
Diffstat (limited to 'java/client')
7 files changed, 304 insertions, 131 deletions
diff --git a/java/client/distribution/pom.xml b/java/client/distribution/pom.xml index 3e9c0e493f..4ad14d40d2 100644 --- a/java/client/distribution/pom.xml +++ b/java/client/distribution/pom.xml @@ -48,20 +48,6 @@ <type>jar</type> <version>${pom.version}</version> </dependency> - <dependency> - <groupId>org.apache.qpid</groupId> - <artifactId>qpid-client</artifactId> - <type>jar</type> - <version>${pom.version}</version> - <classifier>java1.4</classifier> - </dependency> - <dependency> - <groupId>org.apache.qpid</groupId> - <artifactId>qpid-common</artifactId> - <type>jar</type> - <version>${pom.version}</version> - <classifier>java1.4</classifier> - </dependency> </dependencies> <build> @@ -119,7 +105,6 @@ <configuration> <descriptors> <descriptor>src/main/assembly/client-bin.xml</descriptor> - <descriptor>src/main/assembly/client-java1.4-bin.xml</descriptor> <descriptor>src/main/assembly/client-src.xml</descriptor> </descriptors> <finalName>qpid-${pom.version}</finalName> diff --git a/java/client/pom.xml b/java/client/pom.xml index af85c5e63a..3a425cae1a 100644 --- a/java/client/pom.xml +++ b/java/client/pom.xml @@ -15,7 +15,7 @@ KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - --> +--> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> @@ -100,12 +100,18 @@ <scope>test</scope> </dependency> - <!-- This needs to be included at compile time, for the retrotranslator verification to find it. --> - <dependency> - <groupId>net.sf.retrotranslator</groupId> - <artifactId>retrotranslator-runtime</artifactId> - <scope>provided</scope> - </dependency> + <!-- These need to be included at compile time only, for the retrotranslator verification to find them. --> + <dependency> + <groupId>net.sf.retrotranslator</groupId> + <artifactId>retrotranslator-runtime</artifactId> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>provided</scope> + </dependency> </dependencies> @@ -122,16 +128,16 @@ <configuration> <systemProperties> <property> - <name>amqj.noAutoCreateVMBroker</name> - <value>true</value> - </property> - <property> <name>amqj.logging.level</name> <value>${amqj.logging.level}</value> </property> <property> <name>log4j.configuration</name> - <value>file:///${basedir}/src/main/java/client.log4j</value> + <value>${log4j.configuration}</value> + </property> + <property> + <name>amqj.noAutoCreateVMBroker</name> + <value>true</value> </property> </systemProperties> </configuration> @@ -152,35 +158,38 @@ <!-- Backports the module to Java 1.4. This is done during the packaging phase as a transformation of the Jar. --> <plugin> - <groupId>org.codehaus.mojo</groupId> - <artifactId>retrotranslator-maven-plugin</artifactId> - <executions> - <execution> - <phase>package</phase> - <goals> - <goal>translate</goal> - </goals> - <configuration> - <destjar>${project.build.directory}/${project.build.finalName}-java1.4.jar</destjar> - <verify>${retrotranslator.verify}</verify> - <verifyClasspath> - <element>${retrotranslator.1.4-rt-path}</element> - <element>${retrotranslator.1.4-jce-path}</element> - <element>${retrotranslator.1.4-jsse-path}</element> - </verifyClasspath> - <includes> - <include> - <directory>${project.build.directory}</directory> - <pattern>${project.build.finalName}.jar</pattern> - </include> - </includes> - </configuration> - </execution> - - </executions> + <groupId>org.codehaus.mojo</groupId> + <artifactId>retrotranslator-maven-plugin</artifactId> + <executions> + <execution> + <id>retro-client</id> + <phase>package</phase> + <goals> + <goal>translate</goal> + </goals> + <configuration> + <!--<destdir>${project.build.directory}/retro-classes</destdir>--> + <destjar>${project.build.directory}/${project.build.finalName}-java14.jar</destjar> + <verify>${retrotranslator.verify}</verify> + <verifyClasspath> + <element>${retrotranslator.1.4-rt-path}</element> + <element>${retrotranslator.1.4-jce-path}</element> + <element>${retrotranslator.1.4-jsse-path}</element> + <element>${retrotranslator.1.4-sasl-path}</element> + </verifyClasspath> + <failonwarning>false</failonwarning> + <includes> + <include> + <directory>${project.build.directory}</directory> + <pattern>${project.build.finalName}.jar</pattern> + </include> + </includes> + </configuration> + </execution> + </executions> </plugin> - - <!-- This identifies the backported java 1.4 jar and attaches it as a jar (classified as java1.4) build artifact. --> + + <!-- This identifies the backported java 1.4 jars and attaches them as jar (classified as java14) build artifacts. --> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>build-helper-maven-plugin</artifactId> @@ -194,9 +203,9 @@ <configuration> <artifacts> <artifact> - <file>${project.build.directory}/${project.build.finalName}-java1.4.jar</file> + <file>${project.build.directory}/${project.build.finalName}-java14.jar</file> <type>jar</type> - <classifier>java1.4</classifier> + <classifier>java14</classifier> </artifact> </artifacts> </configuration> @@ -215,15 +224,18 @@ <include>**</include> </includes> </testResource> - <testResource> + + <!-- + <testResource> <targetPath>src/</targetPath> <filtering>false</filtering> <directory>src/test/java</directory> <includes> - <include>**/*.java</include> + <include>**/*.java</include> </includes> - </testResource> - + </testResource> + --> + <testResource> <targetPath></targetPath> <filtering>false</filtering> @@ -233,8 +245,7 @@ </includes> </testResource> </testResources> - + </build> </project> -
\ No newline at end of file diff --git a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java index 66ae92113c..2aa2c1872b 100644 --- a/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java +++ b/java/client/src/main/java/org/apache/qpid/client/handler/ConnectionStartMethodHandler.java @@ -29,6 +29,7 @@ import javax.security.sasl.SaslClient; import javax.security.sasl.SaslException; import org.apache.log4j.Logger; + import org.apache.qpid.AMQException; import org.apache.qpid.client.protocol.AMQProtocolSession; import org.apache.qpid.client.security.AMQCallbackHandler; @@ -48,7 +49,6 @@ import org.apache.qpid.protocol.AMQMethodEvent; public class ConnectionStartMethodHandler implements StateAwareMethodListener { - private static final Logger _log = Logger.getLogger(ConnectionStartMethodHandler.class); private static final ConnectionStartMethodHandler _instance = new ConnectionStartMethodHandler(); @@ -59,19 +59,23 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener } private ConnectionStartMethodHandler() - { - } + { } - public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt) throws AMQException + public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, AMQMethodEvent evt) + throws AMQException { + _log.debug("public void methodReceived(AMQStateManager stateManager, AMQProtocolSession protocolSession, " + + "AMQMethodEvent evt): called"); + ConnectionStartBody body = (ConnectionStartBody) evt.getMethod(); byte major = (byte) body.versionMajor; byte minor = (byte) body.versionMinor; boolean versionOk = false; - // for the purposes of interop, we can make the client accept the broker's version string. - // if it does, it then internally records the version as being the latest one that it understands. - // it needs to do this since frame lookup is done by version. + + // For the purposes of interop, we can make the client accept the broker's version string. + // If it does, it then internally records the version as being the latest one that it understands. + // It needs to do this since frame lookup is done by version. if (Boolean.getBoolean("qpid.accept.broker.version")) { versionOk = true; @@ -90,8 +94,9 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener try { - // the mechanism we are going to use + // Used to hold the SASL mechanism to authenticate with. String mechanism; + if (body.mechanisms == null) { throw new AMQException("mechanism not specified in ConnectionStart method frame"); @@ -99,6 +104,7 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener else { mechanism = chooseMechanism(body.mechanisms); + _log.debug("mechanism = " + mechanism); } if (mechanism == null) @@ -109,15 +115,17 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener byte[] saslResponse; try { - SaslClient sc = Sasl.createSaslClient(new String[]{mechanism}, - null, "AMQP", "localhost", - null,createCallbackHandler(mechanism, protocolSession)); + SaslClient sc = + Sasl.createSaslClient(new String[] { mechanism }, null, "AMQP", "localhost", null, + createCallbackHandler(mechanism, protocolSession)); if (sc == null) { - throw new AMQException("Client SASL configuration error: no SaslClient could be created for mechanism " + - mechanism + ". Please ensure all factories are registered. See DynamicSaslRegistrar for " + - " details of how to register non-standard SASL client providers."); + throw new AMQException( + "Client SASL configuration error: no SaslClient could be created for mechanism " + mechanism + + ". Please ensure all factories are registered. See DynamicSaslRegistrar for " + + " details of how to register non-standard SASL client providers."); } + protocolSession.setSaslClient(sc); saslResponse = (sc.hasInitialResponse() ? sc.evaluateChallenge(new byte[0]) : null); } @@ -131,6 +139,7 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener { throw new AMQException("Locales is not defined in Connection Start method"); } + final String locales = new String(body.locales, "utf8"); final StringTokenizer tokenizer = new StringTokenizer(locales, " "); String selectedLocale = null; @@ -146,21 +155,24 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener stateManager.changeState(AMQState.CONNECTION_NOT_TUNED); FieldTable clientProperties = FieldTableFactory.newFieldTable(); - clientProperties.setString(new AMQShortString(ClientProperties.instance.toString()), protocolSession.getClientID()); - clientProperties.setString(new AMQShortString(ClientProperties.product.toString()), QpidProperties.getProductName()); - clientProperties.setString(new AMQShortString(ClientProperties.version.toString()), QpidProperties.getReleaseVersion()); + clientProperties.setString(new AMQShortString(ClientProperties.instance.toString()), + protocolSession.getClientID()); + clientProperties.setString(new AMQShortString(ClientProperties.product.toString()), + QpidProperties.getProductName()); + clientProperties.setString(new AMQShortString(ClientProperties.version.toString()), + QpidProperties.getReleaseVersion()); clientProperties.setString(new AMQShortString(ClientProperties.platform.toString()), getFullSystemInfo()); // AMQP version change: Hardwire the version to 0-8 (major=8, minor=0) // TODO: Connect this to the session version obtained from ProtocolInitiation for this session. // Be aware of possible changes to parameter order as versions change. protocolSession.writeFrame(ConnectionStartOkBody.createAMQFrame(evt.getChannelId(), - protocolSession.getProtocolMajorVersion(), - protocolSession.getProtocolMinorVersion(), - clientProperties, // clientProperties - new AMQShortString(selectedLocale), // locale - new AMQShortString(mechanism), // mechanism - saslResponse)); // response + protocolSession.getProtocolMajorVersion(), + protocolSession.getProtocolMinorVersion(), + clientProperties, // clientProperties + new AMQShortString(selectedLocale), // locale + new AMQShortString(mechanism), // mechanism + saslResponse)); // response } catch (UnsupportedEncodingException e) @@ -170,11 +182,8 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener } else { - _log.error("Broker requested Protocol [" - + body.versionMajor - + "-" - + body.versionMinor - + "] which is not supported by this version of the client library"); + _log.error("Broker requested Protocol [" + body.versionMajor + "-" + body.versionMinor + + "] which is not supported by this version of the client library"); protocolSession.closeProtocolSession(); } @@ -185,7 +194,7 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener byte[][] supportedVersions = ProtocolVersionList.pv; boolean supported = false; int i = supportedVersions.length; - while(i-- != 0 && !supported) + while ((i-- != 0) && !supported) { supported = (supportedVersions[i][ProtocolVersionList.PROTOCOL_MAJOR] == versionMajor) && (supportedVersions[i][ProtocolVersionList.PROTOCOL_MINOR] == versionMinor); @@ -228,11 +237,12 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener return mech; } } + return null; } private AMQCallbackHandler createCallbackHandler(String mechanism, AMQProtocolSession protocolSession) - throws AMQException + throws AMQException { Class mechanismClass = CallbackHandlerRegistry.getInstance().getCallbackHandlerClass(mechanism); try @@ -240,6 +250,7 @@ public class ConnectionStartMethodHandler implements StateAwareMethodListener Object instance = mechanismClass.newInstance(); AMQCallbackHandler cbh = (AMQCallbackHandler) instance; cbh.initialise(protocolSession); + return cbh; } catch (Exception e) diff --git a/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.java b/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.java index bcf77e1586..5c0f1de5bb 100644 --- a/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.java +++ b/java/client/src/main/java/org/apache/qpid/client/security/CallbackHandlerRegistry.java @@ -7,9 +7,9 @@ * 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 @@ -33,45 +33,102 @@ import java.util.Properties; import org.apache.log4j.Logger; +import org.apache.qpid.util.FileUtils; + +/** + * CallbackHandlerRegistry is a registry for call back handlers for user authentication and interaction during user + * authentication. It is capable of reading its configuration from a properties file containing call back handler + * implementing class names for different SASL mechanism names. Instantiating this registry also has the effect of + * configuring and registering the SASL client factory implementations using {@link DynamicSaslRegistrar}. + * + * <p/>The callback configuration should be specified in a properties file, refered to by the System property + * "amp.callbackhandler.properties". The format of the properties file is: + * + * <p/><pre> + * CallbackHanlder.mechanism=fully.qualified.class.name + * </pre> + * + * <p/>Where mechanism is an IANA-registered mechanism name and the fully qualified class name refers to a + * class that implements org.apache.qpid.client.security.AMQCallbackHanlder and provides a call back handler for the + * specified mechanism. + * + * <p><table id="crc"><caption>CRC Card</caption> + * <tr><th> Responsibilities <th> Collaborations + * <tr><td> Parse callback properties. + * <tr><td> Provide mapping from SASL mechanisms to callback implementations. + * </table> + */ public class CallbackHandlerRegistry { + private static final Logger _logger = Logger.getLogger(CallbackHandlerRegistry.class); + + /** The name of the system property that holds the name of the callback handler properties file. */ private static final String FILE_PROPERTY = "amq.callbackhandler.properties"; - private static final Logger _logger = Logger.getLogger(CallbackHandlerRegistry.class); + /** The default name of the callback handler properties resource. */ + public static final String DEFAULT_RESOURCE_NAME = "org/apache/qpid/client/security/CallbackHandlerRegistry.properties"; + /** A static reference to the singleton instance of this registry. */ private static CallbackHandlerRegistry _instance = new CallbackHandlerRegistry(); - private Map _mechanismToHandlerClassMap = new HashMap(); + /** Holds a map from SASL mechanism names to call back handlers. */ + private Map<String, Class> _mechanismToHandlerClassMap = new HashMap<String, Class>(); + /** Holds a space delimited list of mechanisms that callback handlers exist for. */ private String _mechanisms; + /** + * Gets the singleton instance of this registry. + * + * @return The singleton instance of this registry. + */ public static CallbackHandlerRegistry getInstance() { - return _instance; + return _instance; } + /** + * Gets the callback handler class for a given SASL mechanism name. + * + * @param mechanism The SASL mechanism name. + * + * @return The callback handler class for the mechanism, or null if none is configured for that mechanism. + */ public Class getCallbackHandlerClass(String mechanism) { return (Class) _mechanismToHandlerClassMap.get(mechanism); } + /** + * Gets a space delimited list of supported SASL mechanisms. + * + * @return A space delimited list of supported SASL mechanisms. + */ public String getMechanisms() { return _mechanisms; } + /** + * Creates the call back handler registry from its configuration resource or file. This also has the side effect + * of configuring and registering the SASL client factory implementations using {@link DynamicSaslRegistrar}. + */ private CallbackHandlerRegistry() { - // first we register any Sasl client factories + // Register any configured SASL client factories. DynamicSaslRegistrar.registerSaslProviders(); - InputStream is = openPropertiesInputStream(); + String filename = System.getProperty(FILE_PROPERTY); + InputStream is = + FileUtils.openFileOrDefaultResource(filename, DEFAULT_RESOURCE_NAME, + CallbackHandlerRegistry.class.getClassLoader()); + try { Properties props = new Properties(); props.load(is); parseProperties(props); - _logger.info("Available SASL mechanisms: " + _mechanisms); + _logger.info("Callback handlers available for SASL mechanisms: " + _mechanisms); } catch (IOException e) { @@ -94,9 +151,8 @@ public class CallbackHandlerRegistry } } - private InputStream openPropertiesInputStream() + /*private InputStream openPropertiesInputStream(String filename) { - String filename = System.getProperty(FILE_PROPERTY); boolean useDefault = true; InputStream is = null; if (filename != null) @@ -111,15 +167,23 @@ public class CallbackHandlerRegistry _logger.error("Unable to read from file " + filename + ": " + e, e); } } - + if (useDefault) { - is = CallbackHandlerRegistry.class.getResourceAsStream("CallbackHandlerRegistry.properties"); + is = CallbackHandlerRegistry.class.getResourceAsStream(DEFAULT_RESOURCE_NAME); } - + return is; - } - + }*/ + + /** + * Scans the specified properties as a mapping from IANA registered SASL mechanism to call back handler + * implementations, that provide the necessary call back handling for obtaining user log in credentials + * during authentication for the specified mechanism, and builds a map from mechanism names to handler + * classes. + * + * @param props + */ private void parseProperties(Properties props) { Enumeration e = props.propertyNames(); @@ -130,8 +194,10 @@ public class CallbackHandlerRegistry if (period < 0) { _logger.warn("Unable to parse property " + propertyName + " when configuring SASL providers"); + continue; } + String mechanism = propertyName.substring(period + 1); String className = props.getProperty(propertyName); Class clazz = null; @@ -140,10 +206,12 @@ public class CallbackHandlerRegistry clazz = Class.forName(className); if (!AMQCallbackHandler.class.isAssignableFrom(clazz)) { - _logger.warn("SASL provider " + clazz + " does not implement " + AMQCallbackHandler.class + - ". Skipping"); + _logger.warn("SASL provider " + clazz + " does not implement " + AMQCallbackHandler.class + + ". Skipping"); + continue; } + _mechanismToHandlerClassMap.put(mechanism, clazz); if (_mechanisms == null) { @@ -158,6 +226,7 @@ public class CallbackHandlerRegistry catch (ClassNotFoundException ex) { _logger.warn("Unable to load class " + className + ". Skipping that SASL provider"); + continue; } } diff --git a/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java index 078c5e4989..f8ee22a5d9 100644 --- a/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java +++ b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.java @@ -7,9 +7,9 @@ * 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 @@ -36,20 +36,62 @@ import javax.security.sasl.SaslClientFactory; import org.apache.log4j.Logger; +import org.apache.qpid.util.FileUtils; + +/** + * DynamicSaslRegistrar provides a collection of helper methods for reading a configuration file that contains a mapping + * from SASL mechanism names to implementing client factory class names and registering a security provider with the + * Java runtime system, that uses the configured client factory implementations. + * + * <p/>The sasl configuration should be specified in a properties file, refered to by the System property + * "amp.dynamicsaslregistrar.properties". The format of the properties file is: + * + * <p/><pre> + * mechanism=fully.qualified.class.name + * </pre> + * + * <p/>Where mechanism is an IANA-registered mechanism name and the fully qualified class name refers to a + * class that implements javax.security.sasl.SaslClientFactory and provides the specified mechanism. + * + * <p><table id="crc"><caption>CRC Card</caption> + * <tr><th> Responsibilities <th> Collaborations + * <tr><td> Parse SASL mechanism properties. + * <tr><td> Create and register security provider for SASL mechanisms. + * </table> + */ public class DynamicSaslRegistrar { + private static final Logger _logger = Logger.getLogger(DynamicSaslRegistrar.class); + + /** The name of the system property that holds the name of the SASL configuration properties. */ private static final String FILE_PROPERTY = "amq.dynamicsaslregistrar.properties"; - private static final Logger _logger = Logger.getLogger(DynamicSaslRegistrar.class); + /** The default name of the SASL properties file resource. */ + public static final String DEFAULT_RESOURCE_NAME = "org/apache/qpid/client/security/DynamicSaslRegistrar.properties"; + /** + * Reads the properties file, and creates a dynamic security provider to register the SASL implementations + * with. + */ public static void registerSaslProviders() { - InputStream is = openPropertiesInputStream(); + _logger.debug("public static void registerSaslProviders(): called"); + + // Open the SASL properties file, using the default name is one is not specified. + String filename = System.getProperty(FILE_PROPERTY); + InputStream is = + FileUtils.openFileOrDefaultResource(filename, DEFAULT_RESOURCE_NAME, + DynamicSaslRegistrar.class.getClassLoader()); + try { Properties props = new Properties(); props.load(is); + + _logger.debug("props = " + props); + Map<String, Class<? extends SaslClientFactory>> factories = parseProperties(props); + if (factories.size() > 0) { Security.addProvider(new JCAProvider(factories)); @@ -77,16 +119,30 @@ public class DynamicSaslRegistrar } } - private static InputStream openPropertiesInputStream() + /** + * Either attempts to open the specified filename as an input stream, or uses the default SASL configuration + * resource. + * + * @param filename The name of the file to get the SASL properties from, null to use the default. + * + * @return An input stream to read the dynamic SASL configuration from, or null if one could not be opened. + */ + /*private static InputStream openPropertiesInputStream(String filename) { - String filename = System.getProperty(FILE_PROPERTY); - boolean useDefault = true; InputStream is = null; + + // Flag to indicate whether the default resource should be used. By default this is true, so that the default + // is used when opening the file fails. + boolean useDefault = true; + + // Try to open the file if one was specified. if (filename != null) { try { is = new BufferedInputStream(new FileInputStream(new File(filename))); + + // Clear the default flag because the file was succesfully opened. useDefault = false; } catch (FileNotFoundException e) @@ -95,19 +151,35 @@ public class DynamicSaslRegistrar } } + // Load the default resource if a file was not specified, or if opening the file failed. if (useDefault) { - is = CallbackHandlerRegistry.class.getResourceAsStream("DynamicSaslRegistrar.properties"); + is = CallbackHandlerRegistry.class.getResourceAsStream(DEFAULT_RESOURCE_NAME); } return is; - } + }*/ + /** + * Parses the specified properties as a mapping from IANA registered SASL mechanism names to implementing client + * factories. If the client factories cannot be instantiated or do not implement SaslClientFactory then the + * properties refering to them are ignored. + * + * @param props The properties to scan for Sasl client factory implementations. + * + * @return A map from SASL mechanism names to implementing client factory classes. + * + * @todo Why tree map here? Do really want mechanisms in alphabetical order? Seems more likely that the declared + * order of the mechanisms is intended to be preserved, so that they are registered in the declared order + * of preference. Consider LinkedHashMap instead. + */ private static Map<String, Class<? extends SaslClientFactory>> parseProperties(Properties props) { Enumeration e = props.propertyNames(); + TreeMap<String, Class<? extends SaslClientFactory>> factoriesToRegister = - new TreeMap<String, Class<? extends SaslClientFactory>>(); + new TreeMap<String, Class<? extends SaslClientFactory>>(); + while (e.hasMoreElements()) { String mechanism = (String) e.nextElement(); @@ -118,17 +190,18 @@ public class DynamicSaslRegistrar if (!(SaslClientFactory.class.isAssignableFrom(clazz))) { _logger.error("Class " + clazz + " does not implement " + SaslClientFactory.class + " - skipping"); + continue; } + factoriesToRegister.put(mechanism, (Class<? extends SaslClientFactory>) clazz); } catch (Exception ex) { - _logger.error("Error instantiating SaslClientFactory calss " + className + " - skipping"); + _logger.error("Error instantiating SaslClientFactory calss " + className + " - skipping"); } } + return factoriesToRegister; } - - } diff --git a/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties index ee66664455..c2a7d7928c 100644 --- a/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties +++ b/java/client/src/main/java/org/apache/qpid/client/security/DynamicSaslRegistrar.properties @@ -6,9 +6,9 @@ # 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 diff --git a/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java b/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java index ff3ead6d42..2fa8dcddde 100644 --- a/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java +++ b/java/client/src/main/java/org/apache/qpid/client/security/JCAProvider.java @@ -7,9 +7,9 @@ * 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 @@ -26,22 +26,46 @@ import java.util.Map; import javax.security.sasl.SaslClientFactory; +import org.apache.log4j.Logger; + +/** + * JCAProvider is a security provider for SASL client factories that is configured from a map of SASL mechanism names + * to client factories implementation class names. It is intended that the map of client factories can be read from a + * configuration file or other application configuration mechanism. + * + * <p><table id="crc"><caption>CRC Card</caption> + * <tr><th> Responsibilities <th> Collaborations + * <tr><td> Register SASL mechanism implementations. + * </table> + */ public class JCAProvider extends Provider { + private static final Logger log = Logger.getLogger(JCAProvider.class); + + /** + * Creates the security provider with a map from SASL mechanisms to implementing factories. + * + * @param providerMap The map from SASL mechanims to implementing factory classes. + */ public JCAProvider(Map<String, Class<? extends SaslClientFactory>> providerMap) { - super("AMQSASLProvider", 1.0, "A JCA provider that registers all " + - "AMQ SASL providers that want to be registered"); + super("AMQSASLProvider", 1.0, "A JCA provider that registers all " + + "AMQ SASL providers that want to be registered"); register(providerMap); Security.addProvider(this); } + /** + * Registers client factory classes for a map of mechanism names to client factory classes. + * + * @param providerMap The map from SASL mechanims to implementing factory classes. + */ private void register(Map<String, Class<? extends SaslClientFactory>> providerMap) { - for (Map.Entry<String, Class<? extends SaslClientFactory>> me : - providerMap.entrySet()) + for (Map.Entry<String, Class<? extends SaslClientFactory>> me : providerMap.entrySet()) { put("SaslClientFactory." + me.getKey(), me.getValue().getName()); + log.debug("Registered SASL Client factory for " + me.getKey() + " as " + me.getValue().getName()); } } } |
