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    }