| /** |
| * 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.command.ActiveMQDestination; |
| import org.apache.shiro.authz.Permission; |
| import org.apache.shiro.authz.permission.WildcardPermission; |
| |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.LinkedHashSet; |
| import java.util.Set; |
| |
| /** |
| * A {@code DestinationActionPermissionResolver} inspects {@link DestinationAction}s and returns one or more |
| * {@link WildcardPermission}s that must be granted to a {@code Subject} in order for that {@code Subject} to |
| * perform the action being taken on an {@link ActiveMQDestination}. |
| * <p/> |
| * See the {@link #createPermissionString createPermissionString documentation} to see what the |
| * resulting {@link WildcardPermission} instances would look like. |
| * |
| * @see #createPermissionString(org.apache.activemq.command.ActiveMQDestination, String) ) |
| * @see #setPermissionStringPrefix(String) |
| * @since 5.10.0 |
| */ |
| public class DestinationActionPermissionResolver implements ActionPermissionResolver { |
| |
| private String permissionStringPrefix; |
| private boolean permissionStringCaseSensitive = true; |
| |
| /** |
| * Returns the String prefix that should be automatically prepended to a permission String before the |
| * String is converted to a {@link WildcardPermission} instance. This is convenient if you want to provide a |
| * 'scope' or 'namespace' for ActiveMQ Destinations to clearly distinguish ActiveMQ-specific permissions from any |
| * others you might assign to user accounts. The default value is {@code null}, indicating no prefix will be |
| * set by default. |
| * <p/> |
| * For example, the default settings might result in permissions Strings that look like this: |
| * <pre> |
| * topic:TEST:create |
| * temp-queue:MyQueue:remove |
| * topic:ActiveMQ.Advisory.*:read |
| * </pre> |
| * <p/> |
| * However, if your application has any application-specific permissions that start with the tokens {@code topic}, |
| * {@code temp-topic}, {@code queue}, or {@code temp-queue}, you wouldn't be able to distinguish between |
| * application-specific permissions and those specific to ActiveMQ. In this case you might set the |
| * {@code permissionStringPrefix}. For example, if you set: |
| * {@code resolver.setPermissionStringPrefix("jms");}, the above permission strings would look like this: |
| * <pre> |
| * jms:topic:TEST:create |
| * jms:temp-queue:MyQueue:remove |
| * jms:topic:ActiveMQ.Advisory.*:read |
| * </pre> |
| * <p/> |
| * Similarly, if the {@code permissionStringPrefix} was equal to {@code activeMQ}: |
| * <pre> |
| * activeMQ:topic:TEST:create |
| * activeMQ:temp-queue:MyQueue:remove |
| * activeMQ:topic:ActiveMQ.Advisory.*:read |
| * </pre> |
| * |
| * @return any String prefix that should be automatically prepended to a permission String before the |
| * String is converted to a {@link WildcardPermission} instance. Useful for namespacing permissions. |
| */ |
| public String getPermissionStringPrefix() { |
| return permissionStringPrefix; |
| } |
| |
| /** |
| * Sets the String prefix that should be automatically prepended to a permission String before the |
| * String is converted to a {@link WildcardPermission} instance. This is convenient if you want to provide a |
| * 'scope' or 'namespace' for ActiveMQ Destinations to clearly distinguish ActiveMQ-specific permissions from any |
| * others you might assign to user accounts. The default value is {@code null}, indicating no prefix will be |
| * set by default. |
| * <p/> |
| * For example, the default settings might result in permissions Strings that look like this: |
| * <pre> |
| * topic:TEST:create |
| * temp-queue:MyQueue:remove |
| * topic:ActiveMQ.Advisory.*:read |
| * </pre> |
| * <p/> |
| * However, if your application has any application-specific permissions that start with the tokens {@code topic}, |
| * {@code temp-topic}, {@code queue}, or {@code temp-queue}, you wouldn't be able to distinguish between |
| * application-specific permissions and those specific to ActiveMQ. In this case you might set the |
| * {@code permissionStringPrefix}. For example, if you set: |
| * {@code resolver.setPermissionStringPrefix("jms");}, the above permission strings would look like this: |
| * <pre> |
| * jms:topic:TEST:create |
| * jms:temp-queue:MyQueue:remove |
| * jms:topic:ActiveMQ.Advisory.*:read |
| * </pre> |
| * <p/> |
| * Similarly, if the {@code permissionStringPrefix} was equal to {@code activeMQ}: |
| * <pre> |
| * activeMQ:topic:TEST:create |
| * activeMQ:temp-queue:MyQueue:remove |
| * activeMQ:topic:ActiveMQ.Advisory.*:read |
| * </pre> |
| * |
| * @param permissionStringPrefix any String prefix that should be automatically prepended to a permission String |
| * before the String is converted to a {@link WildcardPermission} instance. Useful |
| * for namespacing permissions. |
| */ |
| public void setPermissionStringPrefix(String permissionStringPrefix) { |
| this.permissionStringPrefix = permissionStringPrefix; |
| } |
| |
| /** |
| * Returns {@code true} if returned {@link WildcardPermission} instances should be considered case-sensitive, |
| * {@code false} otherwise. The default value is {@code true}, which is <em>not</em> the normal |
| * {@link WildcardPermission} default setting. This default was chosen to reflect ActiveMQ's |
| * <a href="http://activemq.apache.org/are-destinations-case-sensitive.html">case-sensitive destination names</a>. |
| * |
| * @return {@code true} if returned {@link WildcardPermission} instances should be considered case-sensitive, |
| * {@code false} otherwise. |
| */ |
| public boolean isPermissionStringCaseSensitive() { |
| return permissionStringCaseSensitive; |
| } |
| |
| /** |
| * Sets whether returned {@link WildcardPermission} instances should be considered case-sensitive. |
| * The default value is {@code true}, which is <em>not</em> the normal |
| * {@link WildcardPermission} default setting. This default was chosen to accurately reflect ActiveMQ's |
| * <a href="http://activemq.apache.org/are-destinations-case-sensitive.html">case-sensitive destination names</a>. |
| * |
| * @param permissionStringCaseSensitive whether returned {@link WildcardPermission} instances should be considered |
| * case-sensitive. |
| */ |
| public void setPermissionStringCaseSensitive(boolean permissionStringCaseSensitive) { |
| this.permissionStringCaseSensitive = permissionStringCaseSensitive; |
| } |
| |
| @Override |
| public Collection<Permission> getPermissions(Action action) { |
| if (!(action instanceof DestinationAction)) { |
| throw new IllegalArgumentException("Action argument must be a " + DestinationAction.class.getName() + " instance."); |
| } |
| DestinationAction da = (DestinationAction) action; |
| return getPermissions(da); |
| } |
| |
| protected Collection<Permission> getPermissions(DestinationAction da) { |
| ActiveMQDestination dest = da.getDestination(); |
| String verb = da.getVerb(); |
| return createPermissions(dest, verb); |
| } |
| |
| protected Collection<Permission> createPermissions(ActiveMQDestination dest, String verb) { |
| |
| Set<Permission> set; |
| |
| if (dest.isComposite()) { |
| ActiveMQDestination[] composites = dest.getCompositeDestinations(); |
| set = new LinkedHashSet<Permission>(composites.length); |
| for(ActiveMQDestination d : composites) { |
| Collection<Permission> perms = createPermissions(d, verb); |
| set.addAll(perms); |
| } |
| } else { |
| set = new HashSet<Permission>(1); |
| String permString = createPermissionString(dest, verb); |
| Permission perm = createPermission(permString); |
| set.add(perm); |
| } |
| |
| return set; |
| } |
| |
| /** |
| * Inspects the specified {@code destination} and {@code verb} and returns a {@link WildcardPermission}-compatible |
| * String the represents the action. |
| * <h3>Format</h3> |
| * This implementation returns WildcardPermission strings with the following format: |
| * <pre> |
| * optionalPermissionStringPrefix + destinationType + ':' + destinationPhysicalName + ':' + actionVerb |
| * </pre> |
| * where: |
| * <ol> |
| * <li>{@code optionalPermissionStringPrefix} is the {@link #getPermissionStringPrefix() permissionStringPrefix} |
| * followed by a colon delimiter (':'). This is only present if the {@code permissionStringPrefix} has been |
| * specified and is non-null</li> |
| * <li>{@code destinationType} is one of the following four string tokens: |
| * <ul> |
| * <li>{@code topic}</li> |
| * <li>{@code temp-topic}</li> |
| * <li>{@code queue}</li> |
| * <li>{@code temp-queue}</li> |
| * </ul> |
| * based on whether the {@link DestinationAction#getDestination() destination} is |
| * a topic, temporary topic, queue, or temporary queue (respectively). |
| * </li> |
| * <li> |
| * {@code destinationPhysicalName} is |
| * {@link org.apache.activemq.command.ActiveMQDestination#getPhysicalName() destination.getPhysicalName()} |
| * </li> |
| * <li> |
| * {@code actionVerb} is {@link DestinationAction#getVerb() action.getVerb()} |
| * </li> |
| * </ol> |
| * <h3>Examples</h3> |
| * With the default settings (no {@link #getPermissionStringPrefix() permissionStringPrefix}), this might produce |
| * strings that look like the following: |
| * <pre> |
| * topic:TEST:create |
| * temp-queue:MyTempQueue:remove |
| * queue:ActiveMQ.Advisory.*:read |
| * </pre> |
| * If {@link #getPermissionStringPrefix() permissionStringPrefix} was set to {@code jms}, the above examples would |
| * look like this: |
| * <pre> |
| * jms:topic:TEST:create |
| * jms:temp-queue:MyTempQueue:remove |
| * jms:queue:ActiveMQ.Advisory.*:read |
| * </pre> |
| * |
| * @param dest the destination to inspect and convert to a {@link WildcardPermission} string. |
| * @param verb the behavior taken on the destination |
| * @return a {@link WildcardPermission} string that represents the specified {@code action}. |
| * @see #getPermissionStringPrefix() getPermissionStringPrefix() for more on why you might want to set this value |
| */ |
| protected String createPermissionString(ActiveMQDestination dest, String verb) { |
| if (dest.isComposite()) { |
| throw new IllegalArgumentException("Use createPermissionStrings for composite destinations."); |
| } |
| |
| StringBuilder sb = new StringBuilder(); |
| |
| if (permissionStringPrefix != null) { |
| sb.append(permissionStringPrefix); |
| if (!permissionStringPrefix.endsWith(":")) { |
| sb.append(":"); |
| } |
| } |
| |
| if (dest.isTemporary()) { |
| sb.append("temp-"); |
| } |
| if (dest.isTopic()) { |
| sb.append("topic:"); |
| } else { |
| sb.append("queue:"); |
| } |
| |
| sb.append(dest.getPhysicalName()); |
| sb.append(':'); |
| sb.append(verb); |
| |
| return sb.toString(); |
| |
| } |
| |
| protected Permission createPermission(String permissionString) { |
| return new ActiveMQWildcardPermission(permissionString, isPermissionStringCaseSensitive()); |
| } |
| } |