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