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