You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by de...@apache.org on 2010/05/17 18:04:23 UTC

svn commit: r945227 - in /activemq/trunk/activemq-core/src: main/java/org/apache/activemq/security/ test/java/org/apache/activemq/security/

Author: dejanb
Date: Mon May 17 16:04:23 2010
New Revision: 945227

URL: http://svn.apache.org/viewvc?rev=945227&view=rev
Log:
https://issues.apache.org/activemq/browse/AMQ-2456 - JaasDualAuthentcationPlugin/Broker

Added:
    activemq/trunk/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationBroker.java
    activemq/trunk/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationPlugin.java
    activemq/trunk/activemq-core/src/test/java/org/apache/activemq/security/JaasDualAuthenticationBrokerTest.java
    activemq/trunk/activemq-core/src/test/java/org/apache/activemq/security/StubDualJaasConfiguration.java

Added: activemq/trunk/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationBroker.java
URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationBroker.java?rev=945227&view=auto
==============================================================================
--- activemq/trunk/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationBroker.java (added)
+++ activemq/trunk/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationBroker.java Mon May 17 16:04:23 2010
@@ -0,0 +1,122 @@
+/**
+ * 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.activemq.security;
+
+import org.apache.activemq.broker.*;
+import org.apache.activemq.broker.jmx.ManagedTransportConnector;
+import org.apache.activemq.command.ConnectionInfo;
+
+import org.apache.activemq.transport.tcp.SslTransportServer;
+
+/**
+ * A JAAS Authentication Broker that uses different JAAS domain configurations
+ * depending if the connection is over an SSL enabled Connector or not.
+ *
+ * This allows you to, for instance, do DN based authentication for SSL connections
+ * and use a mixture of username/passwords and simple guest authentication for
+ * non-SSL connections.
+ * <p>
+ * An example <code>login.config</code> to do do this is:
+ * <pre>
+ * activemq-domain {
+ *   org.apache.activemq.jaas.PropertiesLoginModule sufficient
+ *       debug=true
+ *       org.apache.activemq.jaas.properties.user="users.properties"
+ *       org.apache.activemq.jaas.properties.group="groups.properties";
+ *   org.apache.activemq.jaas.GuestLoginModule sufficient
+ *       debug=true
+ *       org.apache.activemq.jaas.guest.user="guest"
+ *       org.apache.activemq.jaas.guest.group="guests";
+ * };
+ *
+ * activemq-ssl-domain {
+ *   org.apache.activemq.jaas.TextFileCertificateLoginModule required
+ *       debug=true
+ *       org.apache.activemq.jaas.textfiledn.user="dns.properties"
+ *       org.apache.activemq.jaas.textfiledn.group="groups.properties";
+ * };
+ * </pre>
+ */
+public class JaasDualAuthenticationBroker extends BrokerFilter {
+    private final JaasCertificateAuthenticationBroker sslBroker;
+    private final JaasAuthenticationBroker nonSslBroker;
+
+
+    /*** Simple constructor. Leaves everything to superclass.
+     *
+     * @param next The Broker that does the actual work for this Filter.
+     * @param jaasConfiguration The JAAS domain configuration name for
+     *                non-SSL connections (refer to JAAS documentation).
+     * @param jaasSslConfiguration The JAAS domain configuration name for
+     *                SSL connections (refer to JAAS documentation).
+     */
+    public JaasDualAuthenticationBroker(Broker next, String jaasConfiguration, String jaasSslConfiguration) {
+        super(next);
+
+        this.nonSslBroker = new JaasAuthenticationBroker(new EmptyBroker(), jaasConfiguration);
+        this.sslBroker = new JaasCertificateAuthenticationBroker(new EmptyBroker(), jaasSslConfiguration);
+    }
+
+    /**
+     * Overridden to allow for authentication using different Jaas
+     * configurations depending on if the connection is SSL or not.
+     *
+     * @param context The context for the incoming Connection.
+     * @param info The ConnectionInfo Command representing the incoming
+     *                connection.
+     */
+    public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
+        if (context.getSecurityContext() == null) {
+            boolean isSSL;
+            Connector connector = context.getConnector();
+            if (connector instanceof TransportConnector) {
+                TransportConnector transportConnector = (TransportConnector) connector;
+                isSSL = (transportConnector.getServer() instanceof SslTransportServer);
+            } else {
+                isSSL = false;
+            }
+
+            if (isSSL) {
+                this.sslBroker.addConnection(context, info);
+            } else {
+                this.nonSslBroker.addConnection(context, info);
+            }
+            super.addConnection(context, info);
+        }
+    }
+
+    /**
+     * Overriding removeConnection to make sure the security context is cleaned.
+     */
+    public void removeConnection(ConnectionContext context, ConnectionInfo info, Throwable error) throws Exception {
+        boolean isSSL;
+        Connector connector = context.getConnector();
+        if (connector instanceof ManagedTransportConnector) {
+            ManagedTransportConnector managedTransportConnector = (ManagedTransportConnector) connector;
+                isSSL = (managedTransportConnector.getServer() instanceof SslTransportServer);
+            } else {
+                isSSL = false;
+            }
+        if (isSSL) {
+            this.sslBroker.removeConnection(context, info, error);
+        } else {
+            this.nonSslBroker.removeConnection(context, info, error);
+        }
+        super.removeConnection(context, info, error);
+    }
+}

Added: activemq/trunk/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationPlugin.java
URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationPlugin.java?rev=945227&view=auto
==============================================================================
--- activemq/trunk/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationPlugin.java (added)
+++ activemq/trunk/activemq-core/src/main/java/org/apache/activemq/security/JaasDualAuthenticationPlugin.java Mon May 17 16:04:23 2010
@@ -0,0 +1,51 @@
+/**
+ * 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.activemq.security;
+
+import org.apache.activemq.broker.Broker;
+
+/**
+ * A JAAS based SSL certificate authentication plugin.
+ *
+ * @org.apache.xbean.XBean description="Provides a JAAS based authentication plugin
+ * which uses properties for non-SSL and certificates for SSL"
+ * 
+ * @version $Revision: $
+ */
+public class JaasDualAuthenticationPlugin extends JaasAuthenticationPlugin {
+    private String sslConfiguration = "activemq-ssl-domain";
+
+    public Broker installPlugin(Broker broker) {
+        initialiseJaas();
+        return new JaasDualAuthenticationBroker(broker, configuration, sslConfiguration);
+    }
+
+    // Properties
+    // -------------------------------------------------------------------------
+
+    /**
+     * Set the JAAS SSL configuration domain
+     */
+    public void setSslConfiguration(String sslConfiguration) {
+        this.sslConfiguration = sslConfiguration;
+    }
+
+    public String getSslConfiguration() {
+        return sslConfiguration;
+    }
+}

Added: activemq/trunk/activemq-core/src/test/java/org/apache/activemq/security/JaasDualAuthenticationBrokerTest.java
URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-core/src/test/java/org/apache/activemq/security/JaasDualAuthenticationBrokerTest.java?rev=945227&view=auto
==============================================================================
--- activemq/trunk/activemq-core/src/test/java/org/apache/activemq/security/JaasDualAuthenticationBrokerTest.java (added)
+++ activemq/trunk/activemq-core/src/test/java/org/apache/activemq/security/JaasDualAuthenticationBrokerTest.java Mon May 17 16:04:23 2010
@@ -0,0 +1,209 @@
+/**
+ * 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.activemq.security;
+
+import junit.framework.TestCase;
+import org.apache.activemq.broker.ConnectionContext;
+import org.apache.activemq.broker.Connector;
+import org.apache.activemq.broker.StubBroker;
+import org.apache.activemq.broker.TransportConnector;
+import org.apache.activemq.command.ConnectionInfo;
+import org.apache.activemq.jaas.GroupPrincipal;
+import org.apache.activemq.jaas.UserPrincipal;
+import org.apache.activemq.transport.tcp.*;
+
+import javax.net.ssl.SSLServerSocket;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import java.net.URI;
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ *
+ */
+public class JaasDualAuthenticationBrokerTest extends TestCase {
+
+    private static final String INSECURE_GROUP = "insecureGroup";
+    private static final String INSECURE_USERNAME = "insecureUserName";
+    private static final String DN_GROUP = "dnGroup";
+    private static final String DN_USERNAME = "dnUserName";
+
+    StubBroker receiveBroker;
+    JaasDualAuthenticationBroker authBroker;
+
+    ConnectionContext connectionContext;
+    ConnectionInfo connectionInfo;
+
+    SslTransportServer sslTransportServer;
+    TcpTransportServer nonSslTransportServer;
+
+    /** create a dual login config, for both SSL and non-SSL connections
+     * using the StubLoginModule
+     *
+     */
+    void createLoginConfig() {
+        HashMap<String, String> sslConfigOptions = new HashMap<String, String>();
+        HashMap<String, String> configOptions = new HashMap<String, String>();
+
+        sslConfigOptions.put(StubLoginModule.ALLOW_LOGIN_PROPERTY, "true");
+        sslConfigOptions.put(StubLoginModule.USERS_PROPERTY, DN_USERNAME);
+        sslConfigOptions.put(StubLoginModule.GROUPS_PROPERTY, DN_GROUP);
+        AppConfigurationEntry sslConfigEntry = new AppConfigurationEntry("org.apache.activemq.security.StubLoginModule",
+                AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, sslConfigOptions);
+
+        configOptions.put(StubLoginModule.ALLOW_LOGIN_PROPERTY, "true");
+        configOptions.put(StubLoginModule.USERS_PROPERTY, INSECURE_USERNAME);
+        configOptions.put(StubLoginModule.GROUPS_PROPERTY, INSECURE_GROUP);
+        AppConfigurationEntry configEntry = new AppConfigurationEntry("org.apache.activemq.security.StubLoginModule",
+                AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, configOptions);
+
+        StubDualJaasConfiguration jaasConfig = new StubDualJaasConfiguration(configEntry, sslConfigEntry);
+
+        Configuration.setConfiguration(jaasConfig);
+    }
+
+    protected void setUp() throws Exception {
+        receiveBroker = new StubBroker();
+
+        authBroker = new JaasDualAuthenticationBroker(receiveBroker, "activemq-domain", "activemq-ssl-domain");
+
+        connectionContext = new ConnectionContext();
+
+        SSLServerSocket sslServerSocket = new StubSSLServerSocket();
+        StubSSLSocketFactory socketFactory = new StubSSLSocketFactory(sslServerSocket);
+
+        try {
+            sslTransportServer = new SslTransportServer(null, new URI("ssl://localhost:61616?needClientAuth=true"),
+                    socketFactory);
+        } catch (Exception e) {
+            fail("Unable to create SslTransportServer.");
+        }
+        sslTransportServer.setNeedClientAuth(true);
+        sslTransportServer.bind();
+
+        try {
+            nonSslTransportServer = new TcpTransportServer(null, new URI("tcp://localhost:61613"), socketFactory); 
+        } catch (Exception e) {
+            fail("Unable to create TcpTransportServer.");
+        }
+
+
+        connectionInfo = new ConnectionInfo();
+
+        createLoginConfig();
+    }
+
+    protected void tearDown() throws Exception {
+            super.tearDown();
+    }
+
+
+    public void testSecureConnector() {
+        Connector connector = new TransportConnector(sslTransportServer);
+        connectionContext.setConnector(connector);
+        connectionInfo.setTransportContext(new StubX509Certificate[] {});
+
+        try {
+            authBroker.addConnection(connectionContext, connectionInfo);
+        } catch (Exception e) {
+            fail("Call to addConnection failed: " + e.getMessage());
+        }
+
+        assertEquals("Number of addConnection calls to underlying Broker must match number of calls made to " +
+                "AuthenticationBroker.", 1, receiveBroker.addConnectionData.size());
+
+        ConnectionContext receivedContext = receiveBroker.addConnectionData.getFirst().connectionContext;
+
+        assertEquals("The SecurityContext's userName must be set to that of the UserPrincipal.",
+                DN_USERNAME, receivedContext.getSecurityContext().getUserName());
+
+        Set receivedPrincipals = receivedContext.getSecurityContext().getPrincipals();
+
+
+        assertEquals("2 Principals received", 2, receivedPrincipals.size());
+        
+        for (Iterator iter = receivedPrincipals.iterator(); iter.hasNext();) {
+            Principal currentPrincipal = (Principal)iter.next();
+
+            if (currentPrincipal instanceof UserPrincipal) {
+                assertEquals("UserPrincipal is '" + DN_USERNAME + "'", DN_USERNAME, currentPrincipal.getName());
+            } else if (currentPrincipal instanceof GroupPrincipal) {
+                assertEquals("GroupPrincipal is '" + DN_GROUP + "'", DN_GROUP, currentPrincipal.getName());
+            } else {
+                fail("Unexpected Principal subclass found.");
+            }
+        }
+
+        try {
+            authBroker.removeConnection(connectionContext, connectionInfo, null);
+        } catch (Exception e) {
+            fail("Call to removeConnection failed: " + e.getMessage());
+        }
+        assertEquals("Number of removeConnection calls to underlying Broker must match number of calls made to " +
+                "AuthenticationBroker.", 1, receiveBroker.removeConnectionData.size());
+    }
+
+    public void testInsecureConnector() {
+        Connector connector = new TransportConnector(nonSslTransportServer);
+        connectionContext.setConnector(connector);
+        connectionInfo.setUserName(INSECURE_USERNAME);
+        
+        try {
+            authBroker.addConnection(connectionContext, connectionInfo);
+        } catch (Exception e) {
+            fail("Call to addConnection failed: " + e.getMessage());
+        }
+
+        assertEquals("Number of addConnection calls to underlying Broker must match number of calls made to " +
+                "AuthenticationBroker.", 1, receiveBroker.addConnectionData.size());
+
+        ConnectionContext receivedContext = receiveBroker.addConnectionData.getFirst().connectionContext;
+
+        assertEquals("The SecurityContext's userName must be set to that of the UserPrincipal.",
+                INSECURE_USERNAME, receivedContext.getSecurityContext().getUserName());
+
+        Set receivedPrincipals = receivedContext.getSecurityContext().getPrincipals();
+
+        assertEquals("2 Principals received", 2, receivedPrincipals.size());
+        for (Iterator iter = receivedPrincipals.iterator(); iter.hasNext();) {
+            Principal currentPrincipal = (Principal)iter.next();
+
+            if (currentPrincipal instanceof UserPrincipal) {
+                assertEquals("UserPrincipal is '" + INSECURE_USERNAME + "'",
+                        INSECURE_USERNAME, currentPrincipal.getName());
+            } else if (currentPrincipal instanceof GroupPrincipal) {
+                assertEquals("GroupPrincipal is '" + INSECURE_GROUP + "'",
+                        INSECURE_GROUP, currentPrincipal.getName());
+            } else {
+                fail("Unexpected Principal subclass found.");
+            }
+        }
+
+        try {
+            authBroker.removeConnection(connectionContext, connectionInfo, null);
+        } catch (Exception e) {
+            fail("Call to removeConnection failed: " + e.getMessage());
+        }
+        assertEquals("Number of removeConnection calls to underlying Broker must match number of calls made to " +
+                "AuthenticationBroker.", 1, receiveBroker.removeConnectionData.size());
+    }
+}

Added: activemq/trunk/activemq-core/src/test/java/org/apache/activemq/security/StubDualJaasConfiguration.java
URL: http://svn.apache.org/viewvc/activemq/trunk/activemq-core/src/test/java/org/apache/activemq/security/StubDualJaasConfiguration.java?rev=945227&view=auto
==============================================================================
--- activemq/trunk/activemq-core/src/test/java/org/apache/activemq/security/StubDualJaasConfiguration.java (added)
+++ activemq/trunk/activemq-core/src/test/java/org/apache/activemq/security/StubDualJaasConfiguration.java Mon May 17 16:04:23 2010
@@ -0,0 +1,43 @@
+/**
+ * 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.activemq.security;
+
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+
+public class StubDualJaasConfiguration extends Configuration {
+    private AppConfigurationEntry nonSslConfigEntry;
+    private AppConfigurationEntry sslConfigEntry;
+
+    public StubDualJaasConfiguration(AppConfigurationEntry nonSslConfigEntry, AppConfigurationEntry sslConfigEntry) {
+        this.nonSslConfigEntry = nonSslConfigEntry;
+        this.sslConfigEntry = sslConfigEntry;
+    }
+
+    public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
+        if ("activemq-domain".equals(name)) {
+            return new AppConfigurationEntry[] {nonSslConfigEntry};
+        } else {
+            return new AppConfigurationEntry[] {sslConfigEntry};            
+        }
+    }
+
+    public void refresh() {
+    }
+
+}