diff options
| author | Bhupendra Bhusman Bhardwaj <bhupendrab@apache.org> | 2007-04-11 14:16:02 +0000 |
|---|---|---|
| committer | Bhupendra Bhusman Bhardwaj <bhupendrab@apache.org> | 2007-04-11 14:16:02 +0000 |
| commit | 41a95c994d425ea0dcb1ae5a099da1e530eadc87 (patch) | |
| tree | f2d54f1ad81df7e5b79269129c2e66588f2a8418 /java | |
| parent | b287b96e81dfff14c63285afb8c461187b18f87f (diff) | |
| download | qpid-python-41a95c994d425ea0dcb1ae5a099da1e530eadc87.tar.gz | |
QPID-444 : added CRAM-MD5-HASHED mechanism for sasl
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/branches/M2@527499 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java')
14 files changed, 323 insertions, 60 deletions
diff --git a/java/broker/etc/config.xml b/java/broker/etc/config.xml index d496e255c5..399ae9202c 100644 --- a/java/broker/etc/config.xml +++ b/java/broker/etc/config.xml @@ -42,6 +42,7 @@ <management> <enabled>true</enabled> <jmxport>8999</jmxport> + <security-enabled>true</security-enabled> </management> <advanced> <filterchain enableExecutorPool="true"/> diff --git a/java/broker/etc/jmxremote.access b/java/broker/etc/jmxremote.access index 0f17f420cf..d1172fc197 100644 --- a/java/broker/etc/jmxremote.access +++ b/java/broker/etc/jmxremote.access @@ -1,4 +1,3 @@ -#guest=admin +admin=admin guest=readonly -#user=readwrite -#admin=admin +user=readwrite diff --git a/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java b/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java index e86acd6566..66c564c0ab 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java +++ b/java/broker/src/main/java/org/apache/qpid/server/management/JMXManagedObjectRegistry.java @@ -50,7 +50,10 @@ import org.apache.qpid.AMQException; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.security.auth.database.PrincipalDatabase; +import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase; +import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase; import org.apache.qpid.server.security.auth.sasl.UsernamePrincipal; +import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser; /** * This class starts up an MBeanserver. If out of the box agent is being used then there are no security features @@ -96,20 +99,34 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _jmxURL = new JMXServiceURL("jmxmp", null, port); Map env = new HashMap(); - env.put("jmx.remote.profiles", "SASL/PLAIN"); - // env.put("jmx.remote.profiles", "SASL/CRAM-MD5"); - Map<String, PrincipalDatabase> map = appRegistry.getDatabaseManager().getDatabases(); - Map.Entry<String, PrincipalDatabase> entry = map.entrySet().iterator().next(); - - // Callback handler used by the PLAIN SASL server mechanism to perform user authentication - /* - PlainInitialiser plainInitialiser = new PlainInitialiser(); - plainInitialiser.initialise(entry.getValue()); - env.put("jmx.remote.sasl.callback.handler", plainInitialiser.getCallbackHandler()); - */ + PrincipalDatabase db = null; + + for (Map.Entry<String, PrincipalDatabase> entry : map.entrySet()) + { + if (entry.getValue() instanceof Base64MD5PasswordFilePrincipalDatabase) + { + db = entry.getValue(); + break; + } + else if (entry.getValue() instanceof PlainPasswordFilePrincipalDatabase) + { + db = entry.getValue(); + } + } - env.put("jmx.remote.sasl.callback.handler", new UserCallbackHandler(entry.getValue())); + if (db instanceof Base64MD5PasswordFilePrincipalDatabase) + { + env.put("jmx.remote.profiles", "SASL/CRAM-MD5"); + CRAMMD5HashedInitialiser initialiser = new CRAMMD5HashedInitialiser(); + initialiser.initialise(db); + env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler()); + } + else if (db instanceof PlainPasswordFilePrincipalDatabase) + { + env.put("jmx.remote.profiles", "SASL/PLAIN"); + env.put("jmx.remote.sasl.callback.handler", new UserCallbackHandler(db)); + } // Enable the SSL security and server authentication /* @@ -146,7 +163,6 @@ public class JMXManagedObjectRegistry implements ManagedObjectRegistry _log.error("Error in initialising Managed Object Registry." + ex.getMessage()); ex.printStackTrace(); } - } /** diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java index e76cd55024..66f928a70e 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBean.java @@ -129,9 +129,9 @@ public class AMQProtocolSessionMBean extends AMQManagedObject implements Managed return (_session.getContextKey() == null) ? null : _session.getContextKey().toString(); } - public Principal getAuthorizedId() + public String getAuthorizedId() { - return _session.getAuthorizedID(); + return (_session.getAuthorizedID() != null ) ? _session.getAuthorizedID().getName() : null; } public String getVersion() diff --git a/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java b/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java index 5e7575203d..e6e713ac6d 100644 --- a/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java +++ b/java/broker/src/main/java/org/apache/qpid/server/protocol/ManagedConnection.java @@ -46,7 +46,7 @@ public interface ManagedConnection String getClientId(); @MBeanAttribute(name = "AuthorizedId", description = "User Name") - Principal getAuthorizedId(); + String getAuthorizedId(); @MBeanAttribute(name = "Version", description = "Client Version") String getVersion(); @@ -68,16 +68,17 @@ public interface ManagedConnection /** * Tells the total number of bytes written till now. * @return number of bytes written. - */ + * @MBeanAttribute(name="WrittenBytes", description="The total number of bytes written till now") Long getWrittenBytes(); - + */ /** * Tells the total number of bytes read till now. * @return number of bytes read. - */ + * @MBeanAttribute(name="ReadBytes", description="The total number of bytes read till now") Long getReadBytes(); + */ /** * Threshold high value for no of channels. This is useful in setting notifications or diff --git a/java/management/eclipse-plugin/bin/qpidmc.sh b/java/management/eclipse-plugin/bin/qpidmc.sh index 4ab4b7f025..aae61b14c7 100755 --- a/java/management/eclipse-plugin/bin/qpidmc.sh +++ b/java/management/eclipse-plugin/bin/qpidmc.sh @@ -61,4 +61,4 @@ elif [ $os = "Linux" ]; then os="linux" fi -"$JAVA_HOME/bin/java" -Xms40m -Xmx256m -Declipse.consoleLog=false -Dsecurity=true -jar $QPIDMC_HOME/eclipse/startup.jar org.eclipse.core.launcher.Main -launcher $QPIDMC_HOME/eclipse/eclipse -name "Qpid Management Console" -showsplash 600 -configuration "file:$QPIDMC_HOME/configuration" -os $os -ws $ws -arch $arch +"$JAVA_HOME/bin/java" -Xms40m -Xmx256m -Declipse.consoleLog=false -Dsecurity=PLAIN -jar $QPIDMC_HOME/eclipse/startup.jar org.eclipse.core.launcher.Main -launcher $QPIDMC_HOME/eclipse/eclipse -name "Qpid Management Console" -showsplash 600 -configuration "file:$QPIDMC_HOME/configuration" -os $os -ws $ws -arch $arch diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java index c15bdc4fa0..714f84ea49 100644 --- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java +++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/ApplicationRegistry.java @@ -41,8 +41,9 @@ public abstract class ApplicationRegistry { private static ImageRegistry imageRegistry = new ImageRegistry(); private static FontRegistry fontRegistry = new FontRegistry(); - public static final boolean enableSecurity = Boolean.getBoolean("security"); - + public static final boolean debug = Boolean.getBoolean("debug"); + public static final String securityMechanism = System.getProperty("security", null); + static { imageRegistry.put(Constants.CONSOLE_IMAGE, @@ -131,4 +132,9 @@ public abstract class ApplicationRegistry _closedServerList.clear(); return list; } + + public static String getSecurityMechanism() + { + return securityMechanism; + } } diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java index 91dec841cf..dd3c388ed4 100644 --- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java +++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/Constants.java @@ -123,4 +123,9 @@ public class Constants public final static String INFO_HOST_PORT = "Please enter the port number"; public final static String INFO_USERNAME = "Please enter the " + USERNAME; public final static String INFO_PASSWORD = "Please enter the " + PASSWORD; + + public final static String MECH_CRAMMD5 = "CRAM-MD5"; + public final static String MECH_PLAIN = "PLAIN"; + public final static String SASL_CRAMMD5 = "SASL/CRAM-MD5"; + public final static String SASL_PLAIN = "SASL/PLAIN"; } diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java index 82447d645e..2be0ddbebf 100644 --- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java +++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/ClientListener.java @@ -45,10 +45,7 @@ public class ClientListener implements NotificationListener { ObjectName objName = null; String type = notification.getType(); - if (MBeanUtility.isDebug()) - { - System.out.println(type + ":" + objName); - } + MBeanUtility.printOutput(type + ":" + objName); if (MBeanServerNotification.REGISTRATION_NOTIFICATION.equals(type)) { diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java index 435f7f2ff1..4040f544d1 100644 --- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java +++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/JMXServerRegistry.java @@ -20,6 +20,8 @@ */ package org.apache.qpid.management.ui.jmx; +import static org.apache.qpid.management.ui.Constants.*; + import java.lang.reflect.Constructor; import java.security.Security; import java.util.ArrayList; @@ -37,9 +39,9 @@ import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; +import javax.security.sasl.SaslClientFactory; import org.apache.qpid.management.ui.ApplicationRegistry; -import org.apache.qpid.management.ui.Constants; import org.apache.qpid.management.ui.ManagedBean; import org.apache.qpid.management.ui.ManagedServer; import org.apache.qpid.management.ui.ServerRegistry; @@ -47,8 +49,10 @@ import org.apache.qpid.management.ui.model.ManagedAttributeModel; import org.apache.qpid.management.ui.model.NotificationInfoModel; import org.apache.qpid.management.ui.model.NotificationObject; import org.apache.qpid.management.ui.model.OperationDataModel; +import org.apache.qpid.management.ui.sasl.JCAProvider; import org.apache.qpid.management.ui.sasl.SaslProvider; import org.apache.qpid.management.ui.sasl.UserPasswordCallbackHandler; +import org.apache.qpid.management.ui.sasl.UsernameHashedPasswordCallbackHandler; public class JMXServerRegistry extends ServerRegistry @@ -89,37 +93,58 @@ public class JMXServerRegistry extends ServerRegistry super(server); JMXServiceURL jmxUrl = new JMXServiceURL(server.getUrl()); Map<String, Object> env = null; + String securityMechanism = ApplicationRegistry.getSecurityMechanism(); - if (ApplicationRegistry.enableSecurity) + if (securityMechanism != null) { try { // Check if the JMXMP connector is available Class klass = Class.forName("javax.management.remote.jmxmp.JMXMPConnector"); - // Now create the instance of JMXMPConnector - Security.addProvider(new SaslProvider()); jmxUrl = new JMXServiceURL("jmxmp", server.getHost(), server.getPort()); - env = new HashMap<String, Object>(); - env.put("jmx.remote.profiles", "SASL/PLAIN"); - //env.put("jmx.remote.profiles", "SASL/CRAM-MD5"); - env.put("jmx.remote.sasl.callback.handler", - new UserPasswordCallbackHandler(server.getUser(), server.getPassword())); + if (MECH_CRAMMD5.equals(securityMechanism)) + { + // For SASL/CRAM-MD5 + Map<String, Class<? extends SaslClientFactory>> map = new HashMap<String, Class<? extends SaslClientFactory>>(); + Class<?> clazz = Class.forName("org.apache.qpid.management.ui.sasl.CRAMMD5HashedSaslClientFactory"); + map.put("CRAM-MD5-HASHED", (Class<? extends SaslClientFactory>) clazz); + + Security.addProvider(new JCAProvider(map)); + env.put("jmx.remote.profiles", SASL_CRAMMD5); + env.put("jmx.remote.sasl.callback.handler", + new UsernameHashedPasswordCallbackHandler(server.getUser(), server.getPassword())); + } + else if (MECH_PLAIN.equals(securityMechanism)) + { + // For SASL/PLAIN + Security.addProvider(new SaslProvider()); + env.put("jmx.remote.profiles", SASL_PLAIN); + env.put("jmx.remote.sasl.callback.handler", + new UserPasswordCallbackHandler(server.getUser(), server.getPassword())); + } + else + { + MBeanUtility.printOutput("Security mechanism " + securityMechanism + " is not supported."); + } + + // Now create the instance of JMXMPConnector Class[] paramTypes = {JMXServiceURL.class, Map.class}; Constructor cons = klass.getConstructor(paramTypes); Object[] args = {jmxUrl, env}; Object theObject = cons.newInstance(args); + _jmxc = (JMXConnector)theObject; _jmxc.connect(); - System.out.println("Starting JMXConnector with SASL. Server=" + server.getName()); + MBeanUtility.printOutput("Starting JMXConnector with SASL. Server=" + server.getName()); } catch (Exception ex) { // When JMXMPConnector is not available - System.out.println("Starting JMXConnector. Server=" + server.getName()); + MBeanUtility.printOutput("Starting JMXConnector. Server=" + server.getName()); jmxUrl = new JMXServiceURL(server.getUrl()); _jmxc = JMXConnectorFactory.connect(jmxUrl, null); } @@ -197,10 +222,7 @@ public class JMXServerRegistry extends ServerRegistry public void removeManagedObject(ManagedBean mbean) { - if (MBeanUtility.isDebug()) - { - System.out.println("Removing MBean:" + mbean.getUniqueName()); - } + MBeanUtility.printOutput("Removing MBean:" + mbean.getUniqueName()); if (mbean.isQueue()) { @@ -296,7 +318,7 @@ public class JMXServerRegistry extends ServerRegistry map.put(name, list); } // Now add the notification type to the list - if (Constants.ALL.equals(type)) + if (ALL.equals(type)) { List<NotificationInfoModel> infoList = _notificationInfoMap.get(mbean.getUniqueName()); for (NotificationInfoModel model : infoList) @@ -355,7 +377,7 @@ public class JMXServerRegistry extends ServerRegistry HashMap<String, List<String>> map = _subscribedNotificationMap.get(mbean.getUniqueName()); if (map.containsKey(name)) { - if (Constants.ALL.equals(type)) + if (ALL.equals(type)) { map.remove(name); } diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java index 6c34ec9898..41db11c10e 100644 --- a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java +++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/jmx/MBeanUtility.java @@ -60,13 +60,6 @@ import org.apache.qpid.management.ui.views.ViewUtility; */ public class MBeanUtility { - private static boolean _debug; - static - { - String debug = System.getProperty("debug"); - _debug = "true".equalsIgnoreCase(debug) ? true : false; - } - public static final BigInteger MAX_LONG = BigInteger.valueOf(Long.MAX_VALUE); public static final BigInteger MAX_INT = BigInteger.valueOf(Integer.MAX_VALUE); /** @@ -461,18 +454,17 @@ public class MBeanUtility return Arrays.asList(domains); } - /** - * return true if System property is set to true -Ddebug=true - * @return - */ - public static boolean isDebug() + public static void printOutput(String statement) { - return _debug; + if (ApplicationRegistry.debug) + { + System.out.println(statement); + } } private static void printStackTrace(Throwable ex) { - if (isDebug()) + if (ApplicationRegistry.debug) { ex.printStackTrace(); } diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/CRAMMD5HashedSaslClientFactory.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/CRAMMD5HashedSaslClientFactory.java new file mode 100644 index 0000000000..32a0c12344 --- /dev/null +++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/CRAMMD5HashedSaslClientFactory.java @@ -0,0 +1,60 @@ +/* + * + * 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.management.ui.sasl; + +import java.util.Map; + +import javax.security.auth.callback.CallbackHandler; +import javax.security.sasl.Sasl; +import javax.security.sasl.SaslClient; +import javax.security.sasl.SaslClientFactory; +import javax.security.sasl.SaslException; + +public class CRAMMD5HashedSaslClientFactory implements SaslClientFactory +{ + /** The name of this mechanism */ + public static final String MECHANISM = "CRAM-MD5-HASHED"; + + public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol, + String serverName, Map<String, ?> props, CallbackHandler cbh) + throws SaslException + { + for (int i = 0; i < mechanisms.length; i++) + { + if (mechanisms[i].equals(MECHANISM)) + { + if (cbh == null) + { + throw new SaslException("CallbackHandler must not be null"); + } + + String[] mechs = {"CRAM-MD5"}; + return Sasl.createSaslClient(mechs, authorizationId, protocol, serverName, props, cbh); + } + } + return null; + } + + public String[] getMechanismNames(Map props) + { + return new String[]{MECHANISM}; + } +} diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/JCAProvider.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/JCAProvider.java new file mode 100644 index 0000000000..d8189f3ac3 --- /dev/null +++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/JCAProvider.java @@ -0,0 +1,56 @@ +/* + * + * 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.management.ui.sasl; + +import java.security.Provider; +import java.util.Map; + +import javax.security.sasl.SaslClientFactory; + +public class JCAProvider extends Provider +{ + private static final long serialVersionUID = 1L; + + /** + * 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"); + register(providerMap); + } + + /** + * 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()) + { + put("SaslClientFactory." + me.getKey(), me.getValue().getName()); + } + } +} diff --git a/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UsernameHashedPasswordCallbackHandler.java b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UsernameHashedPasswordCallbackHandler.java new file mode 100644 index 0000000000..12090e866a --- /dev/null +++ b/java/management/eclipse-plugin/src/main/java/org/apache/qpid/management/ui/sasl/UsernameHashedPasswordCallbackHandler.java @@ -0,0 +1,108 @@ +/* + * + * 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.management.ui.sasl; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +public class UsernameHashedPasswordCallbackHandler implements CallbackHandler +{ + private String user; + private char[] pwchars; + + public UsernameHashedPasswordCallbackHandler(String user, String password) throws Exception + { + this.user = user; + this.pwchars = getHash(password); + } + + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException + { + for (int i = 0; i < callbacks.length; i++) + { + if (callbacks[i] instanceof NameCallback) + { + NameCallback ncb = (NameCallback) callbacks[i]; + ncb.setName(user); + } + else if (callbacks[i] instanceof PasswordCallback) + { + PasswordCallback pcb = (PasswordCallback) callbacks[i]; + pcb.setPassword(pwchars); + } + else + { + throw new UnsupportedCallbackException(callbacks[i]); + } + } + } + + private char[] getHash(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException + { + + byte[] data = text.getBytes("utf-8"); + + MessageDigest md = MessageDigest.getInstance("MD5"); + + for (byte b : data) + { + md.update(b); + } + + byte[] digest = md.digest(); + + char[] hash = new char[digest.length + 1]; + + int index = 0; + for (byte b : digest) + { + index++; + hash[index] = (char) b; + } + + return hash; + } + + private void clearPassword() + { + if (pwchars != null) + { + for (int i = 0 ; i < pwchars.length ; i++) + { + pwchars[i] = 0; + } + pwchars = null; + } + } + + protected void finalize() + { + clearPassword(); + } +} |
