You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicemix.apache.org by gn...@apache.org on 2006/08/31 10:24:45 UTC

svn commit: r438836 - /incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/

Author: gnodet
Date: Thu Aug 31 01:24:44 2006
New Revision: 438836

URL: http://svn.apache.org/viewvc?rev=438836&view=rev
Log:
Remove dependency on mx4j-tools
Add factory beans for jmx server, jmx connector, rmi registry and jmx password authentication

Added:
    incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/ConnectorServerFactoryBean.java
    incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/PasswordAuthenticator.java
    incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/PasswordAuthenticatorFactoryBean.java
    incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/RmiRegistryFactoryBean.java
Modified:
    incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/MBeanServerContext.java

Added: incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/ConnectorServerFactoryBean.java
URL: http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/ConnectorServerFactoryBean.java?rev=438836&view=auto
==============================================================================
--- incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/ConnectorServerFactoryBean.java (added)
+++ incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/ConnectorServerFactoryBean.java Thu Aug 31 01:24:44 2006
@@ -0,0 +1,132 @@
+/*
+ * 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.servicemix.jbi.management;
+
+import java.util.Map;
+import java.util.Properties;
+
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+
+public class ConnectorServerFactoryBean implements FactoryBean, InitializingBean, DisposableBean{
+
+    private Log log = LogFactory.getLog(ConnectorServerFactoryBean.class);
+    private String serviceUrl = org.springframework.jmx.support.ConnectorServerFactoryBean.DEFAULT_SERVICE_URL;
+    private org.springframework.jmx.support.ConnectorServerFactoryBean csfb = new org.springframework.jmx.support.ConnectorServerFactoryBean(); 
+
+    /**
+     * @param daemon
+     * @see org.springframework.jmx.support.ConnectorServerFactoryBean#setDaemon(boolean)
+     */
+    public void setDaemon(boolean daemon) {
+        csfb.setDaemon(daemon);
+    }
+
+    /**
+     * @param environment
+     * @see org.springframework.jmx.support.ConnectorServerFactoryBean#setEnvironment(java.util.Properties)
+     */
+    public void setEnvironment(Properties environment) {
+        csfb.setEnvironment(environment);
+    }
+
+    /**
+     * @param environment
+     * @see org.springframework.jmx.support.ConnectorServerFactoryBean#setEnvironmentMap(java.util.Map)
+     */
+    public void setEnvironmentMap(Map environment) {
+        csfb.setEnvironmentMap(environment);
+    }
+
+    /**
+     * @param objectName
+     * @throws MalformedObjectNameException
+     * @see org.springframework.jmx.support.ConnectorServerFactoryBean#setObjectName(java.lang.String)
+     */
+    public void setObjectName(String objectName) throws MalformedObjectNameException {
+        csfb.setObjectName(objectName);
+    }
+
+    /**
+     * @param registrationBehavior
+     * @see org.springframework.jmx.support.MBeanRegistrationSupport#setRegistrationBehavior(int)
+     */
+    public void setRegistrationBehavior(int registrationBehavior) {
+        csfb.setRegistrationBehavior(registrationBehavior);
+    }
+
+    /**
+     * @param registrationBehavior
+     * @see org.springframework.jmx.support.MBeanRegistrationSupport#setRegistrationBehaviorName(java.lang.String)
+     */
+    public void setRegistrationBehaviorName(String registrationBehavior) {
+        csfb.setRegistrationBehaviorName(registrationBehavior);
+    }
+
+    /**
+     * @param server
+     * @see org.springframework.jmx.support.MBeanRegistrationSupport#setServer(javax.management.MBeanServer)
+     */
+    public void setServer(MBeanServer server) {
+        csfb.setServer(server);
+    }
+
+    /**
+     * @param serviceUrl
+     * @see org.springframework.jmx.support.ConnectorServerFactoryBean#setServiceUrl(java.lang.String)
+     */
+    public void setServiceUrl(String serviceUrl) {
+        this.serviceUrl = serviceUrl;
+    }
+
+    /**
+     * @param threaded
+     * @see org.springframework.jmx.support.ConnectorServerFactoryBean#setThreaded(boolean)
+     */
+    public void setThreaded(boolean threaded) {
+        csfb.setThreaded(threaded);
+    }
+
+    public Object getObject() throws Exception {
+        return csfb.getObject();
+    }
+
+    public Class getObjectType() {
+        return csfb.getObjectType();
+    }
+
+    public boolean isSingleton() {
+        return csfb.isSingleton();
+    }
+
+    public void afterPropertiesSet() throws Exception {
+        csfb.setServiceUrl(serviceUrl);
+        csfb.afterPropertiesSet();
+        log.info("JMX connector available at: " + serviceUrl);
+    }
+
+    public void destroy() throws Exception {
+        csfb.destroy();
+    }
+
+}

Modified: incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/MBeanServerContext.java
URL: http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/MBeanServerContext.java?rev=438836&r1=438835&r2=438836&view=diff
==============================================================================
--- incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/MBeanServerContext.java (original)
+++ incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/MBeanServerContext.java Thu Aug 31 01:24:44 2006
@@ -32,7 +32,6 @@
 import javax.management.remote.JMXConnectorServerFactory;
 import javax.management.remote.JMXServiceURL;
 
-import org.apache.activemq.broker.jmx.ManagementContext;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
@@ -297,7 +296,7 @@
                 result=createMBeanServer();
             }
         }catch(NoClassDefFoundError e){
-            log.error("Couldnot load MBeanServer",e);
+            log.error("Could not load MBeanServer",e);
         }catch(Throwable e){
             // probably don't have access to system properties
             log.error("Failed to initialize MBeanServer",e);
@@ -391,7 +390,7 @@
         String serviceURL="service:jmx:rmi:///jndi/rmi://localhost:"+connectorPort+connectorPath;
         JMXServiceURL url=new JMXServiceURL(serviceURL);
         connectorServer=JMXConnectorServerFactory.newJMXConnectorServer(url,null,mbeanServer);
-        // log.info("JMX consoles can connect to serviceURL: " + serviceURL);
+        log.info("JMX connector available at: " + serviceURL);
     }
 
     public String getConnectorPath(){

Added: incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/PasswordAuthenticator.java
URL: http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/PasswordAuthenticator.java?rev=438836&view=auto
==============================================================================
--- incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/PasswordAuthenticator.java (added)
+++ incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/PasswordAuthenticator.java Thu Aug 31 01:24:44 2006
@@ -0,0 +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.servicemix.jbi.management;
+
+/*
+ * Copyright (C) The MX4J Contributors.
+ * All rights reserved.
+ *
+ * This software is distributed under the terms of the MX4J License version 1.0.
+ * See the terms of the MX4J License in the documentation provided with this software.
+ */
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import javax.management.remote.JMXAuthenticator;
+import javax.management.remote.JMXPrincipal;
+import javax.security.auth.Subject;
+
+import mx4j.util.Base64Codec;
+
+/**
+ * Implementation of the JMXAuthenticator interface to be used on server side
+ * to secure access to {@link javax.management.remote.JMXConnectorServer JMXConnectorServer}s. <br/>
+ * Usage:
+ * <pre>
+ * JMXAuthenticator authenticator = new PasswordAuthenticator(new File("users.properties"));
+ * Map environment = new HashMap();
+ * environment.put(JMXConnectorServer.AUTHENTICATOR, authenticator);
+ * JMXServiceURL address = new JMXServiceURL("rmi", "localhost", 0);
+ * MBeanServer server = ...;
+ * JMXConnectorServer cntorServer = JMXConnectorServerFactory.newJMXConnectorServer(address, environment, server);
+ * </pre>
+ * The format of the users.properties file is that of a standard properties file: <br/>
+ * &lt;user&gt;=&lt;password&gt;<br/>
+ * where &lt;password&gt; can be stored in 2 ways:
+ * <ul>
+ * <li>Clear text: the password is written in clear text</li>
+ * <li>Obfuscated text: the password is obfuscated</li>
+ * </ul>
+ * The obfuscated form can be obtained running this class as a main class:
+ * <pre>
+ * java -cp mx4j-remote.jar mx4j.tools.remote.PasswordAuthenticator
+ * </pre>
+ * and following the instructions printed on the console. The output will be a string that should be
+ * copy/pasted as the password into the properties file.<br/>
+ * The obfuscated password is obtained by digesting the clear text password using a
+ * {@link java.security.MessageDigest} algorithm, and then by Base64-encoding the resulting bytes.<br/>
+ * <br/>
+ * On client side, you are allowed to connect to a server side secured with the PasswordAuthenticator
+ * only if you provide the correct credentials:
+ * <pre>
+ * String[] credentials = new String[2];
+ * // The user will travel as clear text
+ * credentials[0] = "user";
+ * // You may send the password in clear text, but it's better to obfuscate it
+ * credentials[1] = PasswordAuthenticator.obfuscatePassword("password");
+ * Map environment = new HashMap();
+ * environment.put(JMXConnector.CREDENTIALS, credentials);
+ * JMXServiceURL address = ...;
+ * JMXConnector cntor = JMXConnectorFactory.connect(address, environment);
+ * </pre>
+ * Note that {@link #obfuscatePassword(java.lang.String,java.lang.String) obfuscating} the passwords only works if the server side has been
+ * setup with the PasswordAuthenticator.
+ * However, the PasswordAuthenticator can be used with other JSR 160 implementations, such as Sun's reference
+ * implementation.
+ *
+ * @version $Revision: 1.3 $
+ */
+public class PasswordAuthenticator implements JMXAuthenticator
+{
+   private static final String LEFT_DELIMITER = "OBF(";
+   private static final String RIGHT_DELIMITER = "):";
+
+   /**
+    * Runs this class as main class to obfuscate passwords.
+    * When no arguments are provided, it prints out the usage.
+    *
+    * @see #obfuscatePassword(java.lang.String,java.lang.String)
+    */
+   public static void main(String[] args) throws Exception
+   {
+      if (args.length == 1)
+      {
+         if (!"-help".equals(args[0]))
+         {
+            printPassword("MD5", args[0]);
+            return;
+         }
+      }
+      else if (args.length == 3)
+      {
+         if ("-alg".equals(args[0]))
+         {
+            printPassword(args[1], args[2]);
+            return;
+         }
+      }
+      printUsage();
+   }
+
+   private static void printPassword(String algorithm, String input)
+   {
+      String password = obfuscatePassword(input, algorithm);
+      System.out.println(password);
+   }
+
+   private static void printUsage()
+   {
+      System.out.println();
+      System.out.println("Usage: java -cp <lib>/mx4j-tools.jar mx4j.tools.remote.PasswordAuthenticator <options> <password>");
+      System.out.println("Where <options> is one of the following:");
+      System.out.println("   -help                     Prints this message");
+      System.out.println("   -alg <digest algorithm>   Specifies the digest algorithm (default is MD5)");
+      System.out.println();
+   }
+
+   /**
+    * Obfuscates the given password using MD5 as digest algorithm
+    *
+    * @see #obfuscatePassword(java.lang.String,java.lang.String)
+    */
+   public static String obfuscatePassword(String password)
+   {
+      return obfuscatePassword(password, "MD5");
+   }
+
+   /**
+    * Obfuscates the given password using the given digest algorithm.<br/>
+    * Obfuscation consists of 2 steps: first the clear text password is {@link java.security.MessageDigest#digest digested}
+    * using the specified algorithm, then the resulting bytes are Base64-encoded.<br/>
+    * For example, the obfuscated version of the password "password" is "OBF(MD5):X03MO1qnZdYdgyfeuILPmQ=="
+    * or "OBF(SHA-1):W6ph5Mm5Pz8GgiULbPgzG37mj9g=". <br/>
+    * OBF stands for "obfuscated", in parenthesis the algorithm used to digest the password.
+    */
+   public static String obfuscatePassword(String password, String algorithm)
+   {
+      try
+      {
+         MessageDigest digest = MessageDigest.getInstance(algorithm);
+         byte[] digestedBytes = digest.digest(password.getBytes());
+         byte[] obfuscatedBytes = Base64Codec.encodeBase64(digestedBytes);
+         return LEFT_DELIMITER + algorithm + RIGHT_DELIMITER + new String(obfuscatedBytes);
+      }
+      catch (NoSuchAlgorithmException x)
+      {
+         throw new SecurityException("Could not find digest algorithm " + algorithm);
+      }
+   }
+
+   private Map passwords;
+
+   /**
+    * Creates a new PasswordAuthenticator that reads user/password pairs from the specified properties file.
+    * The file format is described in the javadoc of this class.
+    *
+    * @see #obfuscatePassword
+    */
+   public PasswordAuthenticator(File passwordFile) throws IOException
+   {
+      this(new FileInputStream(passwordFile));
+   }
+
+   /**
+    * Creates a new PasswordAuthenticator that reads user/password pairs from the specified InputStream.
+    * The file format is described in the javadoc of this class.
+    *
+    * @see #obfuscatePassword
+    */
+   public PasswordAuthenticator(InputStream is) throws IOException
+   {
+      passwords = readPasswords(is);
+   }
+
+   private Map readPasswords(InputStream is) throws IOException
+   {
+      Properties properties = new Properties();
+      try
+      {
+         properties.load(is);
+      }
+      finally
+      {
+         is.close();
+      }
+      return new HashMap(properties);
+   }
+
+   public Subject authenticate(Object credentials) throws SecurityException
+   {
+      if (!(credentials instanceof String[])) throw new SecurityException("Bad credentials");
+      String[] creds = (String[])credentials;
+      if (creds.length != 2) throw new SecurityException("Bad credentials");
+
+      String user = creds[0];
+      String password = creds[1];
+
+      if (password == null) throw new SecurityException("Bad password");
+
+      if (!passwords.containsKey(user)) throw new SecurityException("Unknown user " + user);
+
+      String storedPassword = (String)passwords.get(user);
+      if (!isPasswordCorrect(password, storedPassword)) throw new SecurityException("Bad password");
+
+      Set principals = new HashSet();
+      principals.add(new JMXPrincipal(user));
+      return new Subject(true, principals, Collections.EMPTY_SET, Collections.EMPTY_SET);
+   }
+
+   private boolean isPasswordCorrect(String password, String storedPassword)
+   {
+      if (password.startsWith(LEFT_DELIMITER))
+      {
+         if (storedPassword.startsWith(LEFT_DELIMITER))
+         {
+            return password.equals(storedPassword);
+         }
+         else
+         {
+            String algorithm = getAlgorithm(password);
+            String obfuscated = obfuscatePassword(storedPassword, algorithm);
+            return password.equals(obfuscated);
+         }
+      }
+      else
+      {
+         if (storedPassword.startsWith(LEFT_DELIMITER))
+         {
+            // Password was sent in clear, bad practice
+            String algorithm = getAlgorithm(storedPassword);
+            String obfuscated = obfuscatePassword(password, algorithm);
+            return obfuscated.equals(storedPassword);
+         }
+         else
+         {
+            return password.equals(storedPassword);
+         }
+      }
+   }
+
+   private String getAlgorithm(String obfuscatedPassword)
+   {
+      try
+      {
+         return obfuscatedPassword.substring(LEFT_DELIMITER.length(), obfuscatedPassword.indexOf(RIGHT_DELIMITER));
+      }
+      catch (IndexOutOfBoundsException x)
+      {
+         throw new SecurityException("Bad password");
+      }
+   }
+}

Added: incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/PasswordAuthenticatorFactoryBean.java
URL: http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/PasswordAuthenticatorFactoryBean.java?rev=438836&view=auto
==============================================================================
--- incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/PasswordAuthenticatorFactoryBean.java (added)
+++ incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/PasswordAuthenticatorFactoryBean.java Thu Aug 31 01:24:44 2006
@@ -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.servicemix.jbi.management;
+
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.core.io.Resource;
+
+public class PasswordAuthenticatorFactoryBean implements FactoryBean {
+
+    private Resource passwords;
+    private PasswordAuthenticator authenticator;
+    
+    /**
+     * @return the passwords
+     */
+    public Resource getPasswords() {
+        return passwords;
+    }
+
+    /**
+     * @param passwords the passwords to set
+     */
+    public void setPasswords(Resource passwords) {
+        this.passwords = passwords;
+    }
+
+    public Object getObject() throws Exception {
+        if (authenticator == null) {
+            authenticator = new PasswordAuthenticator(passwords.getInputStream());
+        }
+        return authenticator;
+    }
+
+    public Class getObjectType() {
+        return PasswordAuthenticator.class;
+    }
+
+    public boolean isSingleton() {
+        return true;
+    }
+
+}

Added: incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/RmiRegistryFactoryBean.java
URL: http://svn.apache.org/viewvc/incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/RmiRegistryFactoryBean.java?rev=438836&view=auto
==============================================================================
--- incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/RmiRegistryFactoryBean.java (added)
+++ incubator/servicemix/trunk/servicemix-core/src/main/java/org/apache/servicemix/jbi/management/RmiRegistryFactoryBean.java Thu Aug 31 01:24:44 2006
@@ -0,0 +1,68 @@
+/*
+ * 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.servicemix.jbi.management;
+
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.rmi.server.UnicastRemoteObject;
+
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.InitializingBean;
+
+public class RmiRegistryFactoryBean implements FactoryBean, InitializingBean, DisposableBean{
+
+    private int port = Registry.REGISTRY_PORT;
+    private Registry registry;
+    
+    /**
+     * @return the port
+     */
+    public int getPort() {
+        return port;
+    }
+
+    /**
+     * @param port the port to set
+     */
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public Object getObject() throws Exception {
+        return registry;
+    }
+
+    public Class getObjectType() {
+        return Registry.class;
+    }
+
+    public boolean isSingleton() {
+        return true;
+    }
+
+    public void afterPropertiesSet() throws Exception {
+        registry = LocateRegistry.createRegistry(getPort());
+    }
+
+    public void destroy() throws Exception {
+        if (registry != null) {
+            UnicastRemoteObject.unexportObject(registry, true);
+        }
+    }
+
+}