001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.activemq.security;
019    
020    import org.apache.activemq.broker.*;
021    import org.apache.activemq.broker.jmx.ManagedTransportConnector;
022    import org.apache.activemq.command.ConnectionInfo;
023    
024    import org.apache.activemq.transport.tcp.SslTransportServer;
025    
026    /**
027     * A JAAS Authentication Broker that uses different JAAS domain configurations
028     * depending if the connection is over an SSL enabled Connector or not.
029     *
030     * This allows you to, for instance, do DN based authentication for SSL connections
031     * and use a mixture of username/passwords and simple guest authentication for
032     * non-SSL connections.
033     * <p>
034     * An example <code>login.config</code> to do do this is:
035     * <pre>
036     * activemq-domain {
037     *   org.apache.activemq.jaas.PropertiesLoginModule sufficient
038     *       debug=true
039     *       org.apache.activemq.jaas.properties.user="users.properties"
040     *       org.apache.activemq.jaas.properties.group="groups.properties";
041     *   org.apache.activemq.jaas.GuestLoginModule sufficient
042     *       debug=true
043     *       org.apache.activemq.jaas.guest.user="guest"
044     *       org.apache.activemq.jaas.guest.group="guests";
045     * };
046     *
047     * activemq-ssl-domain {
048     *   org.apache.activemq.jaas.TextFileCertificateLoginModule required
049     *       debug=true
050     *       org.apache.activemq.jaas.textfiledn.user="dns.properties"
051     *       org.apache.activemq.jaas.textfiledn.group="groups.properties";
052     * };
053     * </pre>
054     */
055    public class JaasDualAuthenticationBroker extends BrokerFilter {
056        private final JaasCertificateAuthenticationBroker sslBroker;
057        private final JaasAuthenticationBroker nonSslBroker;
058    
059    
060        /*** Simple constructor. Leaves everything to superclass.
061         *
062         * @param next The Broker that does the actual work for this Filter.
063         * @param jaasConfiguration The JAAS domain configuration name for
064         *                non-SSL connections (refer to JAAS documentation).
065         * @param jaasSslConfiguration The JAAS domain configuration name for
066         *                SSL connections (refer to JAAS documentation).
067         */
068        public JaasDualAuthenticationBroker(Broker next, String jaasConfiguration, String jaasSslConfiguration) {
069            super(next);
070    
071            this.nonSslBroker = new JaasAuthenticationBroker(new EmptyBroker(), jaasConfiguration);
072            this.sslBroker = new JaasCertificateAuthenticationBroker(new EmptyBroker(), jaasSslConfiguration);
073        }
074    
075        /**
076         * Overridden to allow for authentication using different Jaas
077         * configurations depending on if the connection is SSL or not.
078         *
079         * @param context The context for the incoming Connection.
080         * @param info The ConnectionInfo Command representing the incoming
081         *                connection.
082         */
083        public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
084            if (context.getSecurityContext() == null) {
085                boolean isSSL;
086                Connector connector = context.getConnector();
087                if (connector instanceof TransportConnector) {
088                    TransportConnector transportConnector = (TransportConnector) connector;
089                    isSSL = (transportConnector.getServer() instanceof SslTransportServer);
090                } else {
091                    isSSL = false;
092                }
093    
094                if (isSSL) {
095                    this.sslBroker.addConnection(context, info);
096                } else {
097                    this.nonSslBroker.addConnection(context, info);
098                }
099                super.addConnection(context, info);
100            }
101        }
102    
103        /**
104         * Overriding removeConnection to make sure the security context is cleaned.
105         */
106        public void removeConnection(ConnectionContext context, ConnectionInfo info, Throwable error) throws Exception {
107            boolean isSSL;
108            Connector connector = context.getConnector();
109            if (connector instanceof TransportConnector) {
110                TransportConnector transportConnector = (TransportConnector) connector;
111                isSSL = (transportConnector.getServer() instanceof SslTransportServer);
112            } else {
113                isSSL = false;
114            }
115            super.removeConnection(context, info, error);
116            if (isSSL) {
117                this.sslBroker.removeConnection(context, info, error);
118            } else {
119                this.nonSslBroker.removeConnection(context, info, error);
120            }
121        }
122    }