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.Broker;
021    import org.apache.activemq.broker.BrokerFilter;
022    import org.apache.activemq.broker.ConnectionContext;
023    import org.apache.activemq.broker.Connector;
024    import org.apache.activemq.broker.EmptyBroker;
025    import org.apache.activemq.broker.TransportConnector;
026    import org.apache.activemq.command.ConnectionInfo;
027    import org.apache.activemq.transport.tcp.SslTransportServer;
028    
029    /**
030     * A JAAS Authentication Broker that uses different JAAS domain configurations
031     * depending if the connection is over an SSL enabled Connector or not.
032     *
033     * This allows you to, for instance, do DN based authentication for SSL connections
034     * and use a mixture of username/passwords and simple guest authentication for
035     * non-SSL connections.
036     * <p>
037     * An example <code>login.config</code> to do do this is:
038     * <pre>
039     * activemq-domain {
040     *   org.apache.activemq.jaas.PropertiesLoginModule sufficient
041     *       debug=true
042     *       org.apache.activemq.jaas.properties.user="users.properties"
043     *       org.apache.activemq.jaas.properties.group="groups.properties";
044     *   org.apache.activemq.jaas.GuestLoginModule sufficient
045     *       debug=true
046     *       org.apache.activemq.jaas.guest.user="guest"
047     *       org.apache.activemq.jaas.guest.group="guests";
048     * };
049     *
050     * activemq-ssl-domain {
051     *   org.apache.activemq.jaas.TextFileCertificateLoginModule required
052     *       debug=true
053     *       org.apache.activemq.jaas.textfiledn.user="dns.properties"
054     *       org.apache.activemq.jaas.textfiledn.group="groups.properties";
055     * };
056     * </pre>
057     */
058    public class JaasDualAuthenticationBroker extends BrokerFilter {
059        private final JaasCertificateAuthenticationBroker sslBroker;
060        private final JaasAuthenticationBroker nonSslBroker;
061    
062    
063        /*** Simple constructor. Leaves everything to superclass.
064         *
065         * @param next The Broker that does the actual work for this Filter.
066         * @param jaasConfiguration The JAAS domain configuration name for
067         *                non-SSL connections (refer to JAAS documentation).
068         * @param jaasSslConfiguration The JAAS domain configuration name for
069         *                SSL connections (refer to JAAS documentation).
070         */
071        public JaasDualAuthenticationBroker(Broker next, String jaasConfiguration, String jaasSslConfiguration) {
072            super(next);
073    
074            this.nonSslBroker = new JaasAuthenticationBroker(new EmptyBroker(), jaasConfiguration);
075            this.sslBroker = new JaasCertificateAuthenticationBroker(new EmptyBroker(), jaasSslConfiguration);
076        }
077    
078        /**
079         * Overridden to allow for authentication using different Jaas
080         * configurations depending on if the connection is SSL or not.
081         *
082         * @param context The context for the incoming Connection.
083         * @param info The ConnectionInfo Command representing the incoming
084         *                connection.
085         */
086        public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
087            if (context.getSecurityContext() == null) {
088                boolean isSSL;
089                Connector connector = context.getConnector();
090                if (connector instanceof TransportConnector) {
091                    TransportConnector transportConnector = (TransportConnector) connector;
092                    isSSL = transportConnector.getServer().isSslServer();
093                } else {
094                    isSSL = false;
095                }
096    
097                if (isSSL) {
098                    this.sslBroker.addConnection(context, info);
099                } else {
100                    this.nonSslBroker.addConnection(context, info);
101                }
102                super.addConnection(context, info);
103            }
104        }
105    
106        /**
107         * Overriding removeConnection to make sure the security context is cleaned.
108         */
109        public void removeConnection(ConnectionContext context, ConnectionInfo info, Throwable error) throws Exception {
110            boolean isSSL;
111            Connector connector = context.getConnector();
112            if (connector instanceof TransportConnector) {
113                TransportConnector transportConnector = (TransportConnector) connector;
114                isSSL = (transportConnector.getServer() instanceof SslTransportServer);
115            } else {
116                isSSL = false;
117            }
118            super.removeConnection(context, info, error);
119            if (isSSL) {
120                this.sslBroker.removeConnection(context, info, error);
121            } else {
122                this.nonSslBroker.removeConnection(context, info, error);
123            }
124        }
125    }