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 }