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    }