All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.activemq.shiro.authz.AuthorizationFilter Maven / Gradle / Ivy

There is a newer version: 6.1.2
Show newest version
/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.activemq.shiro.authz;

import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.broker.ProducerBrokerExchange;
import org.apache.activemq.broker.region.Destination;
import org.apache.activemq.broker.region.Subscription;
import org.apache.activemq.command.ActiveMQDestination;
import org.apache.activemq.command.ConsumerInfo;
import org.apache.activemq.command.DestinationInfo;
import org.apache.activemq.command.Message;
import org.apache.activemq.command.ProducerInfo;
import org.apache.activemq.security.SecurityContext;
import org.apache.activemq.shiro.env.EnvironmentFilter;
import org.apache.activemq.shiro.subject.ConnectionSubjectResolver;
import org.apache.shiro.authz.Permission;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;

import java.util.Collection;

/**
 * The {@code AuthorizationFilter} asserts that actions are allowed to execute first before they are actually
 * executed.  Such actions include creating, removing, reading from and writing to destinations.
 * 

* This implementation is strictly permission-based, allowing for the finest-grained security policies possible. * Whenever a {@link Subject} associated with a connection attempts to perform an {@link org.apache.activemq.shiro.authz.Action} (such as creating a * destination, or reading from a queue, etc), one or more {@link Permission}s representing that {@code action} are * checked. *

* If the {@code Subject}{@link Subject#isPermitted(org.apache.shiro.authz.Permission) isPermitted} to perform the * {@code action}, the action is allowed to execute and the broker filter chain executes uninterrupted. *

* However, if the {@code Subject} is not permitted to perform the action, an {@link UnauthorizedException} will be * thrown, preventing the filter chain from executing that action. *

ActionPermissionResolver

* The attempted {@code Action} is guarded by one or more {@link Permission}s as indicated by a configurable * {@link #setActionPermissionResolver(org.apache.activemq.shiro.authz.ActionPermissionResolver) actionPermissionResolver}. The * {@code actionPermissionResolver} indicates which permissions must be granted to the connection {@code Subject} in * order for the action to execute. *

* The default {@code actionPermissionResolver} instance is a * {@link org.apache.activemq.shiro.authz.DestinationActionPermissionResolver DestinationActionPermissionResolver}, which indicates which permissions * are required to perform any action on a particular destination. Those familiar with Shiro's * {@link org.apache.shiro.authz.permission.WildcardPermission WildcardPermission} syntax will find the * {@code DestinationActionPermissionResolver}'s * {@link org.apache.activemq.shiro.authz.DestinationActionPermissionResolver#createPermissionString createPermissionString} method * documentation valuable for understanding how destination actions are represented as permissions. * * @see org.apache.activemq.shiro.authz.ActionPermissionResolver * @see org.apache.activemq.shiro.authz.DestinationActionPermissionResolver * @since 5.10.0 */ public class AuthorizationFilter extends EnvironmentFilter { private ActionPermissionResolver actionPermissionResolver; public AuthorizationFilter() { this.actionPermissionResolver = new DestinationActionPermissionResolver(); } /** * Returns the {@code ActionPermissionResolver} used to indicate which permissions are required to be granted to * a {@link Subject} to perform a particular destination {@link org.apache.activemq.shiro.authz.Action}, (such as creating a * destination, or reading from a queue, etc). The default instance is a * {@link DestinationActionPermissionResolver}. * * @return the {@code ActionPermissionResolver} used to indicate which permissions are required to be granted to * a {@link Subject} to perform a particular destination {@link org.apache.activemq.shiro.authz.Action}, (such as creating a * destination, or reading from a queue, etc). */ public ActionPermissionResolver getActionPermissionResolver() { return actionPermissionResolver; } /** * Sets the {@code ActionPermissionResolver} used to indicate which permissions are required to be granted to * a {@link Subject} to perform a particular destination {@link org.apache.activemq.shiro.authz.Action}, (such as creating a * destination, or reading from a queue, etc). Unless overridden by this method, the default instance is a * {@link DestinationActionPermissionResolver}. * * @param actionPermissionResolver the {@code ActionPermissionResolver} used to indicate which permissions are * required to be granted to a {@link Subject} to perform a particular destination * {@link org.apache.activemq.shiro.authz.Action}, (such as creating a destination, or reading from a queue, etc). */ public void setActionPermissionResolver(ActionPermissionResolver actionPermissionResolver) { this.actionPermissionResolver = actionPermissionResolver; } /** * Returns the {@code Subject} associated with the specified connection using a * {@link org.apache.activemq.shiro.subject.ConnectionSubjectResolver}. * * @param ctx the connection context * @return the {@code Subject} associated with the specified connection. */ protected Subject getSubject(ConnectionContext ctx) { return new ConnectionSubjectResolver(ctx).getSubject(); } protected String toString(Subject subject) { PrincipalCollection pc = subject.getPrincipals(); if (pc != null && !pc.isEmpty()) { return "[" + pc.toString() + "] "; } return ""; } protected void assertAuthorized(DestinationAction action) { assertAuthorized(action, action.getVerb()); } //ActiveMQ internals will create a ConnectionContext with a SecurityContext that is not //Shiro specific. We need to allow actions for internal system operations: protected boolean isSystemBroker(DestinationAction action) { ConnectionContext context = action.getConnectionContext(); SecurityContext securityContext = context.getSecurityContext(); return securityContext != null && securityContext.isBrokerContext(); } protected void assertAuthorized(DestinationAction action, String verbText) { if (!isEnabled() || isSystemBroker(action)) { return; } final Subject subject = getSubject(action.getConnectionContext()); Collection perms = this.actionPermissionResolver.getPermissions(action); if (!subject.isPermittedAll(perms)) { String msg = createUnauthorizedMessage(subject, action, verbText); throw new UnauthorizedException(msg); } } protected String createUnauthorizedMessage(Subject subject, DestinationAction action, String verbDisplayText) { return "Subject " + toString(subject) + "is not authorized to " + verbDisplayText + " destination: " + action.getDestination(); } @Override public void addDestinationInfo(ConnectionContext context, DestinationInfo info) throws Exception { DestinationAction action = new DestinationAction(context, info.getDestination(), "create"); assertAuthorized(action); super.addDestinationInfo(context, info); } @Override public Destination addDestination(ConnectionContext context, ActiveMQDestination destination, boolean create) throws Exception { DestinationAction action = new DestinationAction(context, destination, "create"); assertAuthorized(action); return super.addDestination(context, destination, create); } @Override public void removeDestination(ConnectionContext context, ActiveMQDestination destination, long timeout) throws Exception { DestinationAction action = new DestinationAction(context, destination, "remove"); assertAuthorized(action); super.removeDestination(context, destination, timeout); } @Override public void removeDestinationInfo(ConnectionContext context, DestinationInfo info) throws Exception { DestinationAction action = new DestinationAction(context, info.getDestination(), "remove"); assertAuthorized(action); super.removeDestinationInfo(context, info); } @Override public Subscription addConsumer(ConnectionContext context, ConsumerInfo info) throws Exception { //Unlike when adding a producer, consumers must specify the destination at creation time, so we can rely on //a destination being available to perform the authz check: DestinationAction action = new DestinationAction(context, info.getDestination(), "read"); assertAuthorized(action, "read from"); return super.addConsumer(context, info); } @Override public void addProducer(ConnectionContext context, ProducerInfo info) throws Exception { // JMS allows producers to be created without first specifying a destination. In these cases, every send // operation must specify a destination. Because of this, we only authorize 'addProducer' if a destination is // specified. If not specified, the authz check in the 'send' method below will ensure authorization. if (info.getDestination() != null) { DestinationAction action = new DestinationAction(context, info.getDestination(), "write"); assertAuthorized(action, "write to"); } super.addProducer(context, info); } @Override public void send(ProducerBrokerExchange exchange, Message message) throws Exception { DestinationAction action = new DestinationAction(exchange.getConnectionContext(), message.getDestination(), "write"); assertAuthorized(action, "write to"); super.send(exchange, message); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy