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 package org.apache.activemq.security; 018 019 import java.util.Set; 020 021 import org.apache.activemq.broker.Broker; 022 import org.apache.activemq.broker.BrokerFilter; 023 import org.apache.activemq.broker.ConnectionContext; 024 import org.apache.activemq.broker.ProducerBrokerExchange; 025 import org.apache.activemq.broker.region.Destination; 026 import org.apache.activemq.broker.region.Subscription; 027 import org.apache.activemq.command.ActiveMQDestination; 028 import org.apache.activemq.command.ActiveMQQueue; 029 import org.apache.activemq.command.ActiveMQTopic; 030 import org.apache.activemq.command.ConsumerInfo; 031 import org.apache.activemq.command.DestinationInfo; 032 import org.apache.activemq.command.Message; 033 import org.apache.activemq.command.ProducerInfo; 034 035 /** 036 * Verifies if a authenticated user can do an operation against the broker using 037 * an authorization map. 038 * 039 * @version $Revision: 891790 $ 040 */ 041 public class AuthorizationBroker extends BrokerFilter implements SecurityAdminMBean { 042 043 private final AuthorizationMap authorizationMap; 044 045 public AuthorizationBroker(Broker next, AuthorizationMap authorizationMap) { 046 super(next); 047 this.authorizationMap = authorizationMap; 048 } 049 050 public void addDestinationInfo(ConnectionContext context, DestinationInfo info) throws Exception { 051 addDestination(context, info.getDestination()); 052 super.addDestinationInfo(context, info); 053 } 054 055 public Destination addDestination(ConnectionContext context, ActiveMQDestination destination) throws Exception { 056 final SecurityContext securityContext = (SecurityContext)context.getSecurityContext(); 057 if (securityContext == null) { 058 throw new SecurityException("User is not authenticated."); 059 } 060 061 Destination existing = this.getDestinationMap().get(destination); 062 if (existing != null) { 063 return super.addDestination(context, destination); 064 } 065 066 if (!securityContext.isBrokerContext()) { 067 Set<?> allowedACLs = null; 068 if (!destination.isTemporary()) { 069 allowedACLs = authorizationMap.getAdminACLs(destination); 070 } else { 071 allowedACLs = authorizationMap.getTempDestinationAdminACLs(); 072 } 073 074 if (allowedACLs != null && !securityContext.isInOneOf(allowedACLs)) { 075 throw new SecurityException("User " + securityContext.getUserName() + " is not authorized to create: " + destination); 076 } 077 078 } 079 080 return super.addDestination(context, destination); 081 } 082 083 public void removeDestination(ConnectionContext context, ActiveMQDestination destination, long timeout) throws Exception { 084 085 final SecurityContext securityContext = (SecurityContext)context.getSecurityContext(); 086 if (securityContext == null) { 087 throw new SecurityException("User is not authenticated."); 088 } 089 Set<?> allowedACLs = null; 090 if (!destination.isTemporary()) { 091 allowedACLs = authorizationMap.getAdminACLs(destination); 092 } else { 093 allowedACLs = authorizationMap.getTempDestinationAdminACLs(); 094 } 095 096 if (!securityContext.isBrokerContext() && allowedACLs != null && !securityContext.isInOneOf(allowedACLs)) { 097 throw new SecurityException("User " + securityContext.getUserName() + " is not authorized to remove: " + destination); 098 } 099 super.removeDestination(context, destination, timeout); 100 } 101 102 public Subscription addConsumer(ConnectionContext context, ConsumerInfo info) throws Exception { 103 104 final SecurityContext subject = (SecurityContext)context.getSecurityContext(); 105 if (subject == null) { 106 throw new SecurityException("User is not authenticated."); 107 } 108 Set<?> allowedACLs = null; 109 if (!info.getDestination().isTemporary()) { 110 allowedACLs = authorizationMap.getReadACLs(info.getDestination()); 111 } else { 112 allowedACLs = authorizationMap.getTempDestinationReadACLs(); 113 } 114 115 if (!subject.isBrokerContext() && allowedACLs != null && !subject.isInOneOf(allowedACLs)) { 116 throw new SecurityException("User " + subject.getUserName() + " is not authorized to read from: " + info.getDestination()); 117 } 118 subject.getAuthorizedReadDests().put(info.getDestination(), info.getDestination()); 119 120 /* 121 * Need to think about this a little more. We could do per message 122 * security checking to implement finer grained security checking. For 123 * example a user can only see messages with price>1000 . Perhaps this 124 * should just be another additional broker filter that installs this 125 * type of feature. If we did want to do that, then we would install a 126 * predicate. We should be careful since there may be an existing 127 * predicate already assigned and the consumer info may be sent to a 128 * remote broker, so it also needs to support being marshaled. 129 * info.setAdditionalPredicate(new BooleanExpression() { public boolean 130 * matches(MessageEvaluationContext message) throws JMSException { if( 131 * !subject.getAuthorizedReadDests().contains(message.getDestination()) ) { 132 * Set allowedACLs = 133 * authorizationMap.getReadACLs(message.getDestination()); 134 * if(allowedACLs!=null && !subject.isInOneOf(allowedACLs)) return 135 * false; subject.getAuthorizedReadDests().put(message.getDestination(), 136 * message.getDestination()); } return true; } public Object 137 * evaluate(MessageEvaluationContext message) throws JMSException { 138 * return matches(message) ? Boolean.TRUE : Boolean.FALSE; } }); 139 */ 140 141 return super.addConsumer(context, info); 142 } 143 144 public void addProducer(ConnectionContext context, ProducerInfo info) throws Exception { 145 146 SecurityContext subject = (SecurityContext)context.getSecurityContext(); 147 if (subject == null) { 148 throw new SecurityException("User is not authenticated."); 149 } 150 if (!subject.isBrokerContext() && info.getDestination() != null) { 151 152 Set<?> allowedACLs = null; 153 if (!info.getDestination().isTemporary()) { 154 allowedACLs = authorizationMap.getWriteACLs(info.getDestination()); 155 } else { 156 allowedACLs = authorizationMap.getTempDestinationWriteACLs(); 157 } 158 if (allowedACLs != null && !subject.isInOneOf(allowedACLs)) { 159 throw new SecurityException("User " + subject.getUserName() + " is not authorized to write to: " + info.getDestination()); 160 } 161 subject.getAuthorizedWriteDests().put(info.getDestination(), info.getDestination()); 162 } 163 164 super.addProducer(context, info); 165 } 166 167 public void send(ProducerBrokerExchange producerExchange, Message messageSend) throws Exception { 168 SecurityContext subject = (SecurityContext)producerExchange.getConnectionContext().getSecurityContext(); 169 if (subject == null) { 170 throw new SecurityException("User is not authenticated."); 171 } 172 if (!subject.isBrokerContext() && !subject.getAuthorizedWriteDests().contains(messageSend.getDestination())) { 173 174 Set<?> allowedACLs = null; 175 if (!messageSend.getDestination().isTemporary()) { 176 allowedACLs = authorizationMap.getWriteACLs(messageSend.getDestination()); 177 } else { 178 allowedACLs = authorizationMap.getTempDestinationWriteACLs(); 179 } 180 181 if (allowedACLs != null && !subject.isInOneOf(allowedACLs)) { 182 throw new SecurityException("User " + subject.getUserName() + " is not authorized to write to: " + messageSend.getDestination()); 183 } 184 subject.getAuthorizedWriteDests().put(messageSend.getDestination(), messageSend.getDestination()); 185 } 186 187 super.send(producerExchange, messageSend); 188 } 189 190 // SecurityAdminMBean interface 191 // ------------------------------------------------------------------------- 192 193 public void addQueueRole(String queue, String operation, String role) { 194 addDestinationRole(new ActiveMQQueue(queue), operation, role); 195 } 196 197 public void addTopicRole(String topic, String operation, String role) { 198 addDestinationRole(new ActiveMQTopic(topic), operation, role); 199 } 200 201 public void removeQueueRole(String queue, String operation, String role) { 202 removeDestinationRole(new ActiveMQQueue(queue), operation, role); 203 } 204 205 public void removeTopicRole(String topic, String operation, String role) { 206 removeDestinationRole(new ActiveMQTopic(topic), operation, role); 207 } 208 209 public void addDestinationRole(javax.jms.Destination destination, String operation, String role) { 210 } 211 212 public void removeDestinationRole(javax.jms.Destination destination, String operation, String role) { 213 } 214 215 public void addRole(String role) { 216 } 217 218 public void addUserRole(String user, String role) { 219 } 220 221 public void removeRole(String role) { 222 } 223 224 public void removeUserRole(String user, String role) { 225 } 226 227 }