mirror of https://github.com/apache/activemq.git
Fix for https://issues.apache.org/jira/browse/AMQ-3621 - Integrate Apache Shiro with ActiveMQ as "security solution" - many thanks to Les Hazlewood (lhazlewood) for the patch!
Commit dev changes to branch. Signed-off-by: Christian Posta <christian.posta@gmail.com> Added shiro support to 5.9.x Signed-off-by: Christian Posta <christian.posta@gmail.com> Added Shiro deps to dist zip/tarball and 'all' .jar Signed-off-by: Christian Posta <christian.posta@gmail.com> updated version number to reflect correctly packaging Shiro features Signed-off-by: Christian Posta <christian.posta@gmail.com> Handled case when adding a producer might not have a specified destination. Signed-off-by: Christian Posta <christian.posta@gmail.com> Merged latest Connection API changes from trunk. Signed-off-by: Christian Posta <christian.posta@gmail.com> removed accidental addition of Stormpath's m2 repo Signed-off-by: Christian Posta <christian.posta@gmail.com> reverted accidental deletion of <distributionManagement> Signed-off-by: Christian Posta <christian.posta@gmail.com>
This commit is contained in:
parent
e7e317dc7e
commit
f9451e56e2
|
@ -106,6 +106,7 @@
|
|||
<include>${project.groupId}:activemq-jaas</include>
|
||||
<include>${project.groupId}:activemq-broker</include>
|
||||
<include>${project.groupId}:activemq-console</include>
|
||||
<include>${project.groupId}:activemq-shiro</include>
|
||||
<include>${project.groupId}:activemq-spring</include>
|
||||
<include>${project.groupId}:activemq-pool</include>
|
||||
<include>${project.groupId}:activemq-jms-pool</include>
|
||||
|
@ -229,6 +230,13 @@
|
|||
<classifier>sources</classifier>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>activemq-shiro</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<classifier>sources</classifier>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>activemq-spring</artifactId>
|
||||
|
|
|
@ -0,0 +1,178 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-parent</artifactId>
|
||||
<version>5.10-SNAPSHOT</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>activemq-shiro</artifactId>
|
||||
<packaging>bundle</packaging>
|
||||
<name>ActiveMQ :: Shiro</name>
|
||||
<description>ActiveMQ secured by Apache Shiro</description>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<!-- =============================== -->
|
||||
<!-- Required Dependencies -->
|
||||
<!-- =============================== -->
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>activemq-broker</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-spring</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- =============================== -->
|
||||
<!-- Optional Dependencies -->
|
||||
<!-- =============================== -->
|
||||
<!-- <dependency>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
<artifactId>xstream</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.codehaus.jettison</groupId>
|
||||
<artifactId>jettison</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency> -->
|
||||
|
||||
<!-- =============================== -->
|
||||
<!-- Testing Dependencies -->
|
||||
<!-- =============================== -->
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>activemq-kahadb-store</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>activemq-broker</artifactId>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>activemq-unit-tests</artifactId>
|
||||
<type>test-jar</type>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!-- <dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>activemq-jaas</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency> -->
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-SymbolicName>org.apache.activemq.shiro</Bundle-SymbolicName>
|
||||
<Export-Package>org.apache.activemq.shiro*;version=${project.version};-noimport:=true;-split-package:=merge-first</Export-Package>
|
||||
<Import-Package>
|
||||
org.apache.activemq*;version=${project.version};resolution:=optional,
|
||||
org.apache.shiro*;version="[1.2,2]",
|
||||
*
|
||||
</Import-Package>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<!-- <build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>${project.basedir}/src/main/resources</directory>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>${project.basedir}/src/main/filtered-resources</directory>
|
||||
<filtering>true</filtering>
|
||||
<includes>
|
||||
<include>**/*</include>
|
||||
</includes>
|
||||
</resource>
|
||||
</resources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<forkMode>always</forkMode>
|
||||
<argLine>${surefire.argLine}</argLine>
|
||||
<runOrder>alphabetical</runOrder>
|
||||
<failIfNoTests>false</failIfNoTests>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>org.apache.activemq.default.directory.prefix</name>
|
||||
<value>target/</value>
|
||||
</property>
|
||||
<!- - Uncomment the following if you want to configure custom logging (using src/test/resources/log4j.properties)
|
||||
while running mvn:test
|
||||
Note: if you want to see log messages on the console window remove
|
||||
"redirectTestOutputToFile" from the parent pom
|
||||
- ->
|
||||
<!- -
|
||||
<property>
|
||||
<name>log4j.configuration</name>
|
||||
<value>file:target/test-classes/log4j.properties</value>
|
||||
</property>
|
||||
- ->
|
||||
</systemProperties>
|
||||
<includes>
|
||||
<include>**/*Test.*</include>
|
||||
</includes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build> -->
|
||||
</project>
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import org.apache.activemq.broker.ConnectionContext;
|
||||
import org.apache.activemq.command.ConnectionInfo;
|
||||
import org.apache.shiro.env.Environment;
|
||||
|
||||
/**
|
||||
* A reference (handle) to a client's {@link ConnectionContext} and {@link ConnectionInfo} as well as the Shiro
|
||||
* {@link Environment}.
|
||||
* <p/>
|
||||
* This implementation primarily exists as a <a href="http://sourcemaking.com/refactoring/introduce-parameter-object">
|
||||
* Parameter Object Design Pattern</a> implementation to eliminate long parameter lists, but provides additional
|
||||
* benefits, such as immutability and non-null guarantees, and possibility for future data without forcing method
|
||||
* signature changes.
|
||||
*
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class ConnectionReference {
|
||||
|
||||
private final ConnectionContext connectionContext;
|
||||
private final ConnectionInfo connectionInfo;
|
||||
private final Environment environment;
|
||||
|
||||
public ConnectionReference(ConnectionContext connCtx, ConnectionInfo connInfo, Environment environment) {
|
||||
if (connCtx == null) {
|
||||
throw new IllegalArgumentException("ConnectionContext argument cannot be null.");
|
||||
}
|
||||
if (connInfo == null) {
|
||||
throw new IllegalArgumentException("ConnectionInfo argument cannot be null.");
|
||||
}
|
||||
if (environment == null) {
|
||||
throw new IllegalArgumentException("Environment argument cannot be null.");
|
||||
}
|
||||
this.connectionContext = connCtx;
|
||||
this.connectionInfo = connInfo;
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
public ConnectionContext getConnectionContext() {
|
||||
return connectionContext;
|
||||
}
|
||||
|
||||
public ConnectionInfo getConnectionInfo() {
|
||||
return connectionInfo;
|
||||
}
|
||||
|
||||
public Environment getEnvironment() {
|
||||
return environment;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import org.apache.activemq.security.SecurityContext;
|
||||
import org.apache.activemq.shiro.subject.SubjectConnectionReference;
|
||||
import org.apache.activemq.shiro.subject.SubjectSecurityContext;
|
||||
import org.apache.shiro.env.Environment;
|
||||
|
||||
/**
|
||||
* Default {@code SecurityContextFactory} implementation that creates
|
||||
* {@link org.apache.activemq.shiro.subject.SubjectSecurityContext} instances, allowing the connection's {@code Subject} and the Shiro
|
||||
* {@link Environment} to be available to downstream security broker filters.
|
||||
*
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class DefaultSecurityContextFactory implements SecurityContextFactory {
|
||||
|
||||
/**
|
||||
* Returns a new {@link org.apache.activemq.shiro.subject.SubjectSecurityContext} instance, allowing the connection's {@code Subject} and the Shiro
|
||||
* {@link Environment} to be available to downstream security broker filters.
|
||||
*
|
||||
* @param conn the subject's connection
|
||||
* @return a new {@link org.apache.activemq.shiro.subject.SubjectSecurityContext} instance, allowing the connection's {@code Subject} and the Shiro
|
||||
* {@link Environment} to be available to downstream security broker filters.
|
||||
*/
|
||||
@Override
|
||||
public SecurityContext createSecurityContext(SubjectConnectionReference conn) {
|
||||
return new SubjectSecurityContext(conn);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import org.apache.activemq.security.SecurityContext;
|
||||
import org.apache.activemq.shiro.subject.SubjectConnectionReference;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
/**
|
||||
* A {@code SecurityContextFactory} returns a {@link SecurityContext} instance that retains a client
|
||||
* connection's {@link Subject} instance.
|
||||
* <p/>
|
||||
* It should be noted that at the time a {@code SecurityContextFactory} is invoked, a {@link Subject} is already
|
||||
* associated with the client connection. A {@code SecurityContextFactory} is merely responsible for creating
|
||||
* a Shiro-specific {@link org.apache.activemq.security.SecurityContext SecurityContext} instance.
|
||||
* <p/>
|
||||
* The returned {@code SecurityContext} instance will then be made available to any downstream Broker Filters via
|
||||
* {@code connectionContext.}{@link org.apache.activemq.broker.ConnectionContext#getSecurityContext() getSecurityContext()}
|
||||
* to ensure it may be used for Shiro-based security checks.
|
||||
*
|
||||
* @see org.apache.activemq.shiro.subject.SubjectSecurityContext
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public interface SecurityContextFactory {
|
||||
|
||||
/**
|
||||
* Creates a new {@link SecurityContext} retaining the client connection's {@link Subject} instance.
|
||||
* <p/>
|
||||
* It should be noted that at the time a {@code SecurityContextFactory} is invoked, a {@code Subject} is already
|
||||
* associated with the client connection. A {@code SecurityContextFactory} is merely responsible for creating
|
||||
* a Shiro-specific {@link org.apache.activemq.security.SecurityContext SecurityContext} instance.
|
||||
* <p/>
|
||||
* The returned {@code SecurityContext} instance will then be made available to any downstream Broker Filters via
|
||||
* {@code connectionContext.}{@link org.apache.activemq.broker.ConnectionContext#getSecurityContext() getSecurityContext()}
|
||||
* to ensure it may be used for Shiro-based security checks.
|
||||
*
|
||||
* @param ref the client's connection and subject
|
||||
* @return a new {@link SecurityContext} retaining the client connection's {@link Subject} instance.
|
||||
* @see org.apache.activemq.shiro.subject.SubjectSecurityContext
|
||||
*/
|
||||
SecurityContext createSecurityContext(SubjectConnectionReference ref);
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import org.apache.activemq.broker.MutableBrokerFilter;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public abstract class SecurityFilter extends MutableBrokerFilter {
|
||||
|
||||
private volatile boolean enabled;
|
||||
|
||||
public SecurityFilter() {
|
||||
super(null);
|
||||
this.enabled = true;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import org.apache.activemq.ConfigurationException;
|
||||
import org.apache.activemq.broker.Broker;
|
||||
import org.apache.activemq.broker.BrokerPluginSupport;
|
||||
import org.apache.activemq.shiro.authc.AuthenticationFilter;
|
||||
import org.apache.activemq.shiro.authc.AuthenticationPolicy;
|
||||
import org.apache.activemq.shiro.authc.DefaultAuthenticationPolicy;
|
||||
import org.apache.activemq.shiro.authz.AuthorizationFilter;
|
||||
import org.apache.activemq.shiro.env.IniEnvironment;
|
||||
import org.apache.activemq.shiro.subject.ConnectionSubjectFactory;
|
||||
import org.apache.activemq.shiro.subject.DefaultConnectionSubjectFactory;
|
||||
import org.apache.activemq.shiro.subject.SubjectFilter;
|
||||
import org.apache.shiro.config.Ini;
|
||||
import org.apache.shiro.env.Environment;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class ShiroPlugin extends BrokerPluginSupport {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ShiroPlugin.class);
|
||||
|
||||
private volatile boolean enabled = true;
|
||||
|
||||
private Broker broker; //the downstream broker after any/all Shiro-specific broker filters
|
||||
|
||||
private SecurityManager securityManager;
|
||||
private Environment environment;
|
||||
private IniEnvironment iniEnvironment; //only used if the above environment instance is not explicitly configured
|
||||
|
||||
private SubjectFilter subjectFilter;
|
||||
|
||||
private AuthenticationFilter authenticationFilter;
|
||||
|
||||
private AuthorizationFilter authorizationFilter;
|
||||
|
||||
public ShiroPlugin() {
|
||||
|
||||
//Default if this.environment is not configured. See the ensureEnvironment() method below.
|
||||
iniEnvironment = new IniEnvironment();
|
||||
|
||||
authorizationFilter = new AuthorizationFilter();
|
||||
|
||||
// we want to share one AuthenticationPolicy instance across both the AuthenticationFilter and the
|
||||
// ConnectionSubjectFactory:
|
||||
AuthenticationPolicy authcPolicy = new DefaultAuthenticationPolicy();
|
||||
|
||||
authenticationFilter = new AuthenticationFilter();
|
||||
authenticationFilter.setAuthenticationPolicy(authcPolicy);
|
||||
authenticationFilter.setNext(authorizationFilter);
|
||||
|
||||
subjectFilter = new SubjectFilter();
|
||||
DefaultConnectionSubjectFactory subjectFactory = new DefaultConnectionSubjectFactory();
|
||||
subjectFactory.setAuthenticationPolicy(authcPolicy);
|
||||
subjectFilter.setConnectionSubjectFactory(subjectFactory);
|
||||
subjectFilter.setNext(authenticationFilter);
|
||||
}
|
||||
|
||||
public SubjectFilter getSubjectFilter() {
|
||||
return subjectFilter;
|
||||
}
|
||||
|
||||
public void setSubjectFilter(SubjectFilter subjectFilter) {
|
||||
this.subjectFilter = subjectFilter;
|
||||
this.subjectFilter.setNext(this.authenticationFilter);
|
||||
}
|
||||
|
||||
public AuthenticationFilter getAuthenticationFilter() {
|
||||
return authenticationFilter;
|
||||
}
|
||||
|
||||
public void setAuthenticationFilter(AuthenticationFilter authenticationFilter) {
|
||||
this.authenticationFilter = authenticationFilter;
|
||||
this.authenticationFilter.setNext(this.authorizationFilter);
|
||||
this.subjectFilter.setNext(authenticationFilter);
|
||||
}
|
||||
|
||||
public AuthorizationFilter getAuthorizationFilter() {
|
||||
return authorizationFilter;
|
||||
}
|
||||
|
||||
public void setAuthorizationFilter(AuthorizationFilter authorizationFilter) {
|
||||
this.authorizationFilter = authorizationFilter;
|
||||
this.authorizationFilter.setNext(this.broker);
|
||||
this.authenticationFilter.setNext(authorizationFilter);
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
if (isInstalled()) {
|
||||
//we're running, so apply the changes now:
|
||||
applyEnabled(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
if (isInstalled()) {
|
||||
return getNext() == this.subjectFilter;
|
||||
}
|
||||
return enabled;
|
||||
}
|
||||
|
||||
private void applyEnabled(boolean enabled) {
|
||||
if (enabled) {
|
||||
//ensure the SubjectFilter and downstream filters are used:
|
||||
super.setNext(this.subjectFilter);
|
||||
} else {
|
||||
//Shiro is not enabled, restore the original downstream broker:
|
||||
super.setNext(this.broker);
|
||||
}
|
||||
}
|
||||
|
||||
public Environment getEnvironment() {
|
||||
return environment;
|
||||
}
|
||||
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
public SecurityManager getSecurityManager() {
|
||||
return securityManager;
|
||||
}
|
||||
|
||||
public void setSecurityManager(SecurityManager securityManager) {
|
||||
this.securityManager = securityManager;
|
||||
}
|
||||
|
||||
public void setIni(Ini ini) {
|
||||
this.iniEnvironment.setIni(ini);
|
||||
}
|
||||
|
||||
public void setIniConfig(String iniConfig) {
|
||||
this.iniEnvironment.setIniConfig(iniConfig);
|
||||
}
|
||||
|
||||
public void setIniResourcePath(String resourcePath) {
|
||||
this.iniEnvironment.setIniResourcePath(resourcePath);
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// Authentication Configuration
|
||||
// ===============================================================
|
||||
public void setAuthenticationEnabled(boolean authenticationEnabled) {
|
||||
this.authenticationFilter.setEnabled(authenticationEnabled);
|
||||
}
|
||||
|
||||
public boolean isAuthenticationEnabled() {
|
||||
return this.authenticationFilter.isEnabled();
|
||||
}
|
||||
|
||||
public AuthenticationPolicy getAuthenticationPolicy() {
|
||||
return authenticationFilter.getAuthenticationPolicy();
|
||||
}
|
||||
|
||||
public void setAuthenticationPolicy(AuthenticationPolicy authenticationPolicy) {
|
||||
authenticationFilter.setAuthenticationPolicy(authenticationPolicy);
|
||||
//also set it on the ConnectionSubjectFactory:
|
||||
ConnectionSubjectFactory factory = subjectFilter.getConnectionSubjectFactory();
|
||||
if (factory instanceof DefaultConnectionSubjectFactory) {
|
||||
((DefaultConnectionSubjectFactory) factory).setAuthenticationPolicy(authenticationPolicy);
|
||||
}
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// Authorization Configuration
|
||||
// ===============================================================
|
||||
public void setAuthorizationEnabled(boolean authorizationEnabled) {
|
||||
this.authorizationFilter.setEnabled(authorizationEnabled);
|
||||
}
|
||||
|
||||
public boolean isAuthorizationEnabled() {
|
||||
return this.authorizationFilter.isEnabled();
|
||||
}
|
||||
|
||||
private Environment ensureEnvironment() throws ConfigurationException {
|
||||
if (this.environment != null) {
|
||||
return this.environment;
|
||||
}
|
||||
|
||||
//this.environment is null - set it:
|
||||
if (this.securityManager != null) {
|
||||
this.environment = new Environment() {
|
||||
@Override
|
||||
public SecurityManager getSecurityManager() {
|
||||
return ShiroPlugin.this.securityManager;
|
||||
}
|
||||
};
|
||||
return this.environment;
|
||||
}
|
||||
|
||||
this.iniEnvironment.init(); //will automatically catch any config errors and throw.
|
||||
|
||||
this.environment = iniEnvironment;
|
||||
|
||||
return this.iniEnvironment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Broker installPlugin(Broker broker) throws Exception {
|
||||
|
||||
Environment environment = ensureEnvironment();
|
||||
|
||||
this.authorizationFilter.setEnvironment(environment);
|
||||
this.authenticationFilter.setEnvironment(environment);
|
||||
this.subjectFilter.setEnvironment(environment);
|
||||
|
||||
this.broker = broker;
|
||||
this.authorizationFilter.setNext(broker);
|
||||
this.authenticationFilter.setNext(this.authorizationFilter);
|
||||
this.subjectFilter.setNext(this.authenticationFilter);
|
||||
|
||||
Broker next = this.subjectFilter;
|
||||
if (!this.enabled) {
|
||||
//not enabled at startup - default to the original broker:
|
||||
next = broker;
|
||||
}
|
||||
|
||||
setNext(next);
|
||||
return this;
|
||||
}
|
||||
|
||||
private boolean isInstalled() {
|
||||
return getNext() != null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/**
|
||||
* 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.authc;
|
||||
|
||||
import org.apache.activemq.broker.ConnectionContext;
|
||||
import org.apache.activemq.command.ConnectionInfo;
|
||||
import org.apache.activemq.security.SecurityContext;
|
||||
import org.apache.activemq.shiro.ConnectionReference;
|
||||
import org.apache.activemq.shiro.env.EnvironmentFilter;
|
||||
import org.apache.activemq.shiro.subject.ConnectionSubjectResolver;
|
||||
import org.apache.activemq.shiro.subject.SubjectConnectionReference;
|
||||
import org.apache.activemq.shiro.subject.SubjectSecurityContext;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* The {@code AuthenticationFilter} enforces if authentication is required before allowing the broker filter chain
|
||||
* to continue.
|
||||
* <p/>
|
||||
* This implementation performs a connection-level authentication assertion: If the {@link Subject} associated with the
|
||||
* connection<b>*</b> is not authenticated, and the
|
||||
* {@link AuthenticationPolicy AuthenticationPolicy} requires the {@code Subject} to be authenticated, it will attempt
|
||||
* to {@link Subject#login(org.apache.shiro.authc.AuthenticationToken) login} the Subject automatically. The
|
||||
* {@link AuthenticationToken} used to login is created by the
|
||||
* {@link #getAuthenticationTokenFactory() authenticationTokenFactory}, typically by acquiring any credentials
|
||||
* associated with the connection.
|
||||
* <p/>
|
||||
* Once the connection's {@code Subject} is authenticated as necessary, the broker filter chain will continue
|
||||
* as expected.
|
||||
* <p/>
|
||||
* <b>*</b>: The upstream {@link org.apache.activemq.shiro.subject.SubjectFilter} is expected to execute before this one, ensuring a Subject instance
|
||||
* is already associated with the connection.
|
||||
*
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class AuthenticationFilter extends EnvironmentFilter {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(AuthenticationFilter.class);
|
||||
|
||||
private AuthenticationPolicy authenticationPolicy;
|
||||
private AuthenticationTokenFactory authenticationTokenFactory;
|
||||
|
||||
public AuthenticationFilter() {
|
||||
this.authenticationPolicy = new DefaultAuthenticationPolicy();
|
||||
this.authenticationTokenFactory = new DefaultAuthenticationTokenFactory();
|
||||
}
|
||||
|
||||
public AuthenticationPolicy getAuthenticationPolicy() {
|
||||
return authenticationPolicy;
|
||||
}
|
||||
|
||||
public void setAuthenticationPolicy(AuthenticationPolicy authenticationPolicy) {
|
||||
this.authenticationPolicy = authenticationPolicy;
|
||||
}
|
||||
|
||||
public AuthenticationTokenFactory getAuthenticationTokenFactory() {
|
||||
return authenticationTokenFactory;
|
||||
}
|
||||
|
||||
public void setAuthenticationTokenFactory(AuthenticationTokenFactory authenticationTokenFactory) {
|
||||
this.authenticationTokenFactory = authenticationTokenFactory;
|
||||
}
|
||||
|
||||
protected Subject getSubject(ConnectionReference conn) {
|
||||
return new ConnectionSubjectResolver(conn).getSubject();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
|
||||
|
||||
if (isEnabled()) { //disabled means don't enforce authentication (i.e. allow anonymous access):
|
||||
|
||||
Subject subject = getSubject(new ConnectionReference(context, info, getEnvironment()));
|
||||
|
||||
if (!subject.isAuthenticated()) {
|
||||
|
||||
SubjectConnectionReference connection = new SubjectConnectionReference(context, info, getEnvironment(), subject);
|
||||
|
||||
if (this.authenticationPolicy.isAuthenticationRequired(connection)) {
|
||||
AuthenticationToken token = this.authenticationTokenFactory.getAuthenticationToken(connection);
|
||||
if (token == null) {
|
||||
String msg = "Unable to obtain authentication credentials for newly established connection. " +
|
||||
"Authentication is required.";
|
||||
throw new AuthenticationException(msg);
|
||||
}
|
||||
//token is not null - login the current subject:
|
||||
subject.login(token);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
super.addConnection(context, info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeConnection(ConnectionContext context, ConnectionInfo info, Throwable error) throws Exception {
|
||||
try {
|
||||
super.removeConnection(context, info, error);
|
||||
} finally {
|
||||
SecurityContext secCtx = context.getSecurityContext();
|
||||
|
||||
if (secCtx instanceof SubjectSecurityContext) {
|
||||
|
||||
SubjectSecurityContext subjectSecurityContext = (SubjectSecurityContext) secCtx;
|
||||
Subject subject = subjectSecurityContext.getSubject();
|
||||
|
||||
if (subject != null) {
|
||||
try {
|
||||
subject.logout();
|
||||
} catch (Throwable t) {
|
||||
String msg = "Unable to cleanly logout connection Subject during connection removal. This is " +
|
||||
"unexpected but not critical: it can be safely ignored because the " +
|
||||
"connection will no longer be used.";
|
||||
LOG.info(msg, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* 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.authc;
|
||||
|
||||
import org.apache.activemq.shiro.ConnectionReference;
|
||||
import org.apache.activemq.shiro.subject.SubjectConnectionReference;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
/**
|
||||
* An {@code AuthenticationPolicy} customizes the behavior of the {@link AuthenticationFilter}, such as whether or not
|
||||
* authentication is required or how to represent trusted/known {@code Subject} identities.
|
||||
* <p/>
|
||||
* Most will find customizing properties on the {@link DefaultAuthenticationPolicy} easier than implementing this
|
||||
* interface directly.
|
||||
*
|
||||
* @see DefaultAuthenticationPolicy
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public interface AuthenticationPolicy {
|
||||
|
||||
/**
|
||||
* Allows customization of the {@code Subject} being built for the specified client
|
||||
* connection. This allows for any pre-existing connection-specific identity or state to be applied to the
|
||||
* {@link Subject.Builder} before the {@code Subject} instance is actually created.
|
||||
* <p/>
|
||||
* <b>NOTE:</b> This method is called by the {@link org.apache.activemq.shiro.subject.SubjectFilter SubjectFilter} <em>before</em> the filter chain
|
||||
* is executed (and before an authentication attempt occurs). Implementations <b><em>MUST NOT</em></b>
|
||||
* attempt to actually {@link org.apache.shiro.subject.Subject.Builder#buildSubject() build} the subject or perform
|
||||
* an authentication attempt in this method.
|
||||
*
|
||||
* @param subjectBuilder the builder for the Subject that will be created representing the associated client connection
|
||||
* @param ref a reference to the client's connection metadata
|
||||
* @see org.apache.activemq.shiro.subject.SubjectFilter
|
||||
*/
|
||||
void customizeSubject(Subject.Builder subjectBuilder, ConnectionReference ref);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the connection's {@code Subject} instance should be authenticated, {@code false} otherwise.
|
||||
*
|
||||
* @param ref the subject's connection
|
||||
* @return {@code true} if the connection's {@code Subject} instance should be authenticated, {@code false} otherwise.
|
||||
*/
|
||||
boolean isAuthenticationRequired(SubjectConnectionReference ref);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* 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.authc;
|
||||
|
||||
import org.apache.activemq.shiro.subject.SubjectConnectionReference;
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
|
||||
/**
|
||||
* A {@code AuthenticationTokenFactory} inspects a newly-added ActiveMQ connection and returns a Shiro
|
||||
* {@link AuthenticationToken} instance representing credentials associated with the connection. These credentials can
|
||||
* be used to {@link org.apache.shiro.subject.Subject#login(org.apache.shiro.authc.AuthenticationToken) authenticate}
|
||||
* the connection, allowing for later identity and authorization (access control) checks.
|
||||
*
|
||||
* @see AuthenticationFilter#addConnection(org.apache.activemq.broker.ConnectionContext, org.apache.activemq.command.ConnectionInfo)
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public interface AuthenticationTokenFactory {
|
||||
|
||||
/**
|
||||
* Returns a Shiro {@code AuthenticationToken} instance that should be used to authenticate the connection's
|
||||
* {@link org.apache.shiro.subject.Subject}, or {@code null} if no authentication information can be obtained.
|
||||
* <p/>
|
||||
* If no {@code AuthenticationToken} can be obtained, the connection's Subject will be considered anonymous and any
|
||||
* downstream security checks that enforce authentication or authorization will fail (as would be expected).
|
||||
*
|
||||
* @param ref the subject's connection
|
||||
* @return a Shiro {@code AuthenticationToken} instance that should be used to authenticate the connection's
|
||||
* {@link org.apache.shiro.subject.Subject}, or {@code null} if no authentication information can be obtained.
|
||||
* @throws Exception if there is a problem acquiring/creating an expected {@code AuthenticationToken}.
|
||||
*/
|
||||
AuthenticationToken getAuthenticationToken(SubjectConnectionReference ref) throws Exception;
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
/**
|
||||
* 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.authc;
|
||||
|
||||
import org.apache.activemq.shiro.ConnectionReference;
|
||||
import org.apache.activemq.shiro.subject.SubjectConnectionReference;
|
||||
import org.apache.shiro.subject.PrincipalCollection;
|
||||
import org.apache.shiro.subject.SimplePrincipalCollection;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class DefaultAuthenticationPolicy implements AuthenticationPolicy {
|
||||
|
||||
private boolean vmConnectionAuthenticationRequired = false;
|
||||
private String systemAccountUsername = "system";
|
||||
private String systemAccountRealmName = "iniRealm";
|
||||
|
||||
private boolean anonymousAccessAllowed = false;
|
||||
private String anonymousAccountUsername = "anonymous";
|
||||
private String anonymousAccountRealmName = "iniRealm";
|
||||
|
||||
public boolean isVmConnectionAuthenticationRequired() {
|
||||
return vmConnectionAuthenticationRequired;
|
||||
}
|
||||
|
||||
public void setVmConnectionAuthenticationRequired(boolean vmConnectionAuthenticationRequired) {
|
||||
this.vmConnectionAuthenticationRequired = vmConnectionAuthenticationRequired;
|
||||
}
|
||||
|
||||
public String getSystemAccountUsername() {
|
||||
return systemAccountUsername;
|
||||
}
|
||||
|
||||
public void setSystemAccountUsername(String systemAccountUsername) {
|
||||
this.systemAccountUsername = systemAccountUsername;
|
||||
}
|
||||
|
||||
public String getSystemAccountRealmName() {
|
||||
return systemAccountRealmName;
|
||||
}
|
||||
|
||||
public void setSystemAccountRealmName(String systemAccountRealmName) {
|
||||
this.systemAccountRealmName = systemAccountRealmName;
|
||||
}
|
||||
|
||||
public boolean isAnonymousAccessAllowed() {
|
||||
return anonymousAccessAllowed;
|
||||
}
|
||||
|
||||
public void setAnonymousAccessAllowed(boolean anonymousAccessAllowed) {
|
||||
this.anonymousAccessAllowed = anonymousAccessAllowed;
|
||||
}
|
||||
|
||||
public String getAnonymousAccountUsername() {
|
||||
return anonymousAccountUsername;
|
||||
}
|
||||
|
||||
public void setAnonymousAccountUsername(String anonymousAccountUsername) {
|
||||
this.anonymousAccountUsername = anonymousAccountUsername;
|
||||
}
|
||||
|
||||
public String getAnonymousAccountRealmName() {
|
||||
return anonymousAccountRealmName;
|
||||
}
|
||||
|
||||
public void setAnonymousAccountRealmName(String anonymousAccountRealmName) {
|
||||
this.anonymousAccountRealmName = anonymousAccountRealmName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the client connection has supplied credentials to authenticate itself, {@code false}
|
||||
* otherwise.
|
||||
*
|
||||
* @param conn the client's connection context
|
||||
* @return {@code true} if the client connection has supplied credentials to authenticate itself, {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
protected boolean credentialsAvailable(ConnectionReference conn) {
|
||||
return conn.getConnectionInfo().getUserName() != null || conn.getConnectionInfo().getPassword() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthenticationRequired(SubjectConnectionReference conn) {
|
||||
Subject subject = conn.getSubject();
|
||||
|
||||
if (subject.isAuthenticated()) {
|
||||
//already authenticated:
|
||||
return false;
|
||||
}
|
||||
//subject is not authenticated. Authentication is required by default for all accounts other than
|
||||
//the anonymous user (if enabled) or the vm account (if enabled)
|
||||
if (isAnonymousAccessAllowed()) {
|
||||
if (isAnonymousAccount(subject)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isVmConnectionAuthenticationRequired()) {
|
||||
if (isSystemAccount(subject)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isAnonymousAccount(Subject subject) {
|
||||
PrincipalCollection pc = subject.getPrincipals();
|
||||
return pc != null && matches(pc, anonymousAccountUsername, anonymousAccountRealmName);
|
||||
}
|
||||
|
||||
protected boolean isSystemAccount(Subject subject) {
|
||||
PrincipalCollection pc = subject.getPrincipals();
|
||||
return pc != null && matches(pc, systemAccountUsername, systemAccountRealmName);
|
||||
}
|
||||
|
||||
protected boolean matches(PrincipalCollection principals, String username, String realmName) {
|
||||
Collection realmPrincipals = principals.fromRealm(realmName);
|
||||
if (realmPrincipals != null && !realmPrincipals.isEmpty()) {
|
||||
if (realmPrincipals.iterator().next().equals(username)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isSystemConnection(ConnectionReference conn) {
|
||||
String remoteAddress = conn.getConnectionContext().getConnection().getRemoteAddress();
|
||||
return remoteAddress.startsWith("vm:");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizeSubject(Subject.Builder subjectBuilder, ConnectionReference conn) {
|
||||
// We only need to specify a custom identity or authentication state if a normal authentication will not occur.
|
||||
// If the client supplied connection credentials, the AuthenticationFilter will perform a normal authentication,
|
||||
// so we should exit immediately:
|
||||
if (credentialsAvailable(conn)) {
|
||||
return;
|
||||
}
|
||||
|
||||
//The connection cannot be authenticated, potentially implying a system or anonymous connection. Check if so:
|
||||
if (isAssumeIdentity(conn)) {
|
||||
PrincipalCollection assumedIdentity = createAssumedIdentity(conn);
|
||||
subjectBuilder.principals(assumedIdentity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if an unauthenticated connection should still assume a specific identity, {@code false}
|
||||
* otherwise. This method will <em>only</em> be called if there are no connection
|
||||
* {@link #credentialsAvailable(ConnectionReference) credentialsAvailable}.
|
||||
* If a client supplies connection credentials, they will always be used to authenticate the client with that
|
||||
* identity.
|
||||
* <p/>
|
||||
* If {@code true} is returned, the assumed identity will be returned by
|
||||
* {@link #createAssumedIdentity(ConnectionReference) createAssumedIdentity}.
|
||||
* <h3>Warning</h3>
|
||||
* This method exists primarily to support the system and anonymous accounts - it is probably unsafe to return
|
||||
* {@code true} in most other scenarios.
|
||||
*
|
||||
* @param conn a reference to the client's connection
|
||||
* @return {@code true} if an unauthenticated connection should still assume a specific identity, {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
protected boolean isAssumeIdentity(ConnectionReference conn) {
|
||||
return isAnonymousAccessAllowed() ||
|
||||
(isSystemConnection(conn) && !isVmConnectionAuthenticationRequired());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Shiro {@code PrincipalCollection} representing the identity to assume (without true authentication) for
|
||||
* the specified Connection.
|
||||
* <p/>
|
||||
* This method is <em>only</em> called if {@link #isAssumeIdentity(ConnectionReference)} is {@code true}.
|
||||
*
|
||||
* @param conn a reference to the client's connection
|
||||
* @return a Shiro {@code PrincipalCollection} representing the identity to assume (without true authentication) for
|
||||
* the specified Connection.
|
||||
*/
|
||||
protected PrincipalCollection createAssumedIdentity(ConnectionReference conn) {
|
||||
|
||||
//anonymous by default:
|
||||
String username = anonymousAccountUsername;
|
||||
String realmName = anonymousAccountRealmName;
|
||||
|
||||
//vm connections are special and should assume the system account:
|
||||
if (isSystemConnection(conn)) {
|
||||
username = systemAccountUsername;
|
||||
realmName = systemAccountRealmName;
|
||||
}
|
||||
|
||||
return new SimplePrincipalCollection(username, realmName);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* 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.authc;
|
||||
|
||||
import org.apache.activemq.command.ConnectionInfo;
|
||||
import org.apache.activemq.shiro.subject.SubjectConnectionReference;
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link AuthenticationTokenFactory} interface that returns
|
||||
* {@link org.apache.shiro.authc.UsernamePasswordToken UsernamePasswordToken} instances based on inspecting the
|
||||
* {@link ConnectionInfo}.
|
||||
*
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class DefaultAuthenticationTokenFactory implements AuthenticationTokenFactory {
|
||||
|
||||
public DefaultAuthenticationTokenFactory() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new {@link UsernamePasswordToken} instance populated based on the ConnectionInfo's
|
||||
* {@link org.apache.activemq.command.ConnectionInfo#getUserName() userName} and
|
||||
* {@link org.apache.activemq.command.ConnectionInfo#getPassword() password} properties.
|
||||
*
|
||||
* @param conn the subject's connection
|
||||
* @return a new {@link UsernamePasswordToken} instance populated based on the ConnectionInfo's
|
||||
* ConnectionInfo's {@link org.apache.activemq.command.ConnectionInfo#getUserName() userName} and
|
||||
* {@link org.apache.activemq.command.ConnectionInfo#getPassword() password} properties.
|
||||
*/
|
||||
@Override
|
||||
public AuthenticationToken getAuthenticationToken(SubjectConnectionReference conn) {
|
||||
|
||||
String username = conn.getConnectionInfo().getUserName();
|
||||
String password = conn.getConnectionInfo().getPassword();
|
||||
|
||||
if (username == null && password == null) {
|
||||
//no identity or credentials provided by the client for the connection - return null to reflect this
|
||||
return null;
|
||||
}
|
||||
|
||||
return new UsernamePasswordToken(username, password);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* An {@code Action} represents an attempt to perform some behavior, typically on a particular resource.
|
||||
*
|
||||
* @see DestinationAction
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public interface Action {
|
||||
|
||||
/**
|
||||
* Returns a human readable string that indicates what this action is, for example "open doors" or
|
||||
* "delete file /usr/local/foo"
|
||||
*
|
||||
* @return a human readable string that indicates what this action is
|
||||
*/
|
||||
String toString();
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* 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.shiro.authz.Permission;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* An {@code ActionPermissionResolver} will inspect an {@link Action} and return
|
||||
* {@link Permission}s that must be granted to a {@link org.apache.shiro.subject.Subject Subject} in order for the
|
||||
* {@code Subject} to execute the action.
|
||||
* <p/>
|
||||
* If a {@code Subject} is not granted all of the returned permissions, the {@code Action} will not be executed.
|
||||
*
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public interface ActionPermissionResolver {
|
||||
|
||||
/**
|
||||
* Returns all {@link Permission}s that must be granted to a
|
||||
* {@link org.apache.shiro.subject.Subject Subject} in order for the {@code Subject} to execute the action, or
|
||||
* an empty collection if no permissions are required.
|
||||
* <p/>
|
||||
* Most implementations will probably return a single Permission, but multiple permissions are possible, especially
|
||||
* if the Action represents behavior attempted on a
|
||||
* <a href="http://activemq.apache.org/composite-destinations.html">Composite Destination</a>.
|
||||
*
|
||||
* @param action the action attempted
|
||||
* @return all {@link Permission}s that must be granted to a
|
||||
* {@link org.apache.shiro.subject.Subject Subject} in order for the {@code Subject} to execute the action,
|
||||
* or an empty collection if no permissions are required.
|
||||
*/
|
||||
Collection<Permission> getPermissions(Action action);
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* 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.shiro.authz.Permission;
|
||||
import org.apache.shiro.authz.permission.WildcardPermission;
|
||||
import org.apache.shiro.authz.permission.WildcardPermissionResolver;
|
||||
|
||||
/**
|
||||
* {@link WildcardPermissionResolver} that can create case-sensitive (or case-insensitive)
|
||||
* {@link WildcardPermission} instances as expected for ActiveMQ.
|
||||
*
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class ActiveMQPermissionResolver extends WildcardPermissionResolver {
|
||||
|
||||
private boolean caseSensitive;
|
||||
|
||||
public ActiveMQPermissionResolver() {
|
||||
caseSensitive = true;
|
||||
}
|
||||
|
||||
public boolean isCaseSensitive() {
|
||||
return caseSensitive;
|
||||
}
|
||||
|
||||
public void setCaseSensitive(boolean caseSensitive) {
|
||||
this.caseSensitive = caseSensitive;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link WildcardPermission} instance, with case-sensitivity determined by the
|
||||
* {@link #isCaseSensitive() caseSensitive} setting.
|
||||
*
|
||||
* @param permissionString the wildcard permission-formatted string.
|
||||
* @return a new {@link WildcardPermission} instance, with case-sensitivity determined by the
|
||||
* {@link #isCaseSensitive() caseSensitive} setting.
|
||||
*/
|
||||
@Override
|
||||
public Permission resolvePermission(String permissionString) {
|
||||
return new ActiveMQWildcardPermission(permissionString, isCaseSensitive());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
/**
|
||||
* 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.shiro.authz.Permission;
|
||||
import org.apache.shiro.authz.permission.WildcardPermission;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class ActiveMQWildcardPermission extends WildcardPermission {
|
||||
|
||||
private final boolean caseSensitive;
|
||||
|
||||
public ActiveMQWildcardPermission(String wildcardString) {
|
||||
this(wildcardString, true);
|
||||
}
|
||||
|
||||
public ActiveMQWildcardPermission(String wildcardString, boolean caseSensitive) {
|
||||
super(wildcardString, caseSensitive);
|
||||
this.caseSensitive = caseSensitive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean implies(Permission p) {
|
||||
// By default only supports comparisons with other WildcardPermissions
|
||||
if (!(p instanceof WildcardPermission)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WildcardPermission wp = (WildcardPermission) p;
|
||||
|
||||
List<Set<String>> otherParts = getParts(wp);
|
||||
|
||||
int i = 0;
|
||||
for (Set<String> otherPart : otherParts) {
|
||||
// If this permission has less parts than the other permission, everything after the number of parts contained
|
||||
// in this permission is automatically implied, so return true
|
||||
if (getParts().size() - 1 < i) {
|
||||
return true;
|
||||
} else {
|
||||
Set<String> thisPart = getParts().get(i);
|
||||
|
||||
for (String token : thisPart) {
|
||||
if (token.equals(WILDCARD_TOKEN)) {
|
||||
continue;
|
||||
}
|
||||
for (String otherToken : otherPart) {
|
||||
if (!caseSensitive) {
|
||||
otherToken = otherToken.toLowerCase();
|
||||
}
|
||||
if (!matches(token, otherToken)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// If this permission has more parts than the other parts, only imply it if all of the other parts are wildcards
|
||||
for (; i < getParts().size(); i++) {
|
||||
Set<String> part = getParts().get(i);
|
||||
if (!part.contains(WILDCARD_TOKEN)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether or not a string matches against a pattern.
|
||||
* The pattern may contain two special characters:<br>
|
||||
* '*' means zero or more characters<br>
|
||||
* '?' means one and only one character
|
||||
*
|
||||
* @param pattern pattern to match against.
|
||||
* Must not be <code>null</code>.
|
||||
* @param value string which must be matched against the pattern.
|
||||
* Must not be <code>null</code>.
|
||||
* @return <code>true</code> if the string matches against the
|
||||
* pattern, or <code>false</code> otherwise.
|
||||
*/
|
||||
protected boolean matches(String pattern, String value) {
|
||||
|
||||
char[] patArr = pattern.toCharArray();
|
||||
char[] valArr = value.toCharArray();
|
||||
int patIndex = 0;
|
||||
int patEndIndex = patArr.length - 1;
|
||||
int valIndex = 0;
|
||||
int valEndIndex = valArr.length - 1;
|
||||
char ch;
|
||||
|
||||
boolean patternContainsStar = false;
|
||||
for (char patternChar : patArr) {
|
||||
if (patternChar == '*') {
|
||||
patternContainsStar = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!patternContainsStar) {
|
||||
// No '*'s, so we make a shortcut
|
||||
if (patEndIndex != valEndIndex) {
|
||||
return false; // Pattern and string do not have the same size
|
||||
}
|
||||
for (int i = 0; i <= patEndIndex; i++) {
|
||||
ch = patArr[i];
|
||||
if (ch != '?') {
|
||||
if (ch != valArr[i]) {
|
||||
return false;// Character mismatch
|
||||
}
|
||||
}
|
||||
}
|
||||
return true; // String matches against pattern
|
||||
}
|
||||
|
||||
|
||||
// Process characters before first star
|
||||
while ((ch = patArr[patIndex]) != '*' && valIndex <= valEndIndex) {
|
||||
if (ch != '?') {
|
||||
if (ch != valArr[valIndex]) {
|
||||
return false;// Character mismatch
|
||||
}
|
||||
}
|
||||
patIndex++;
|
||||
valIndex++;
|
||||
}
|
||||
if (valIndex > valEndIndex) {
|
||||
// All characters in the value are used. Check if only '*'s remain
|
||||
// in the pattern. If so, we succeeded. Otherwise failure.
|
||||
for (int i = patIndex; i <= patEndIndex; i++) {
|
||||
if (patArr[i] != '*') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Process characters after last star
|
||||
while ((ch = patArr[patEndIndex]) != '*' && valIndex <= valEndIndex) {
|
||||
if (ch != '?') {
|
||||
if (ch != valArr[valEndIndex]) {
|
||||
return false;// Character mismatch
|
||||
}
|
||||
}
|
||||
patEndIndex--;
|
||||
valEndIndex--;
|
||||
}
|
||||
if (valIndex > valEndIndex) {
|
||||
// All characters in the value are used. Check if only '*'s remain
|
||||
// in the pattern. If so, we succeeded. Otherwise failure.
|
||||
for (int i = patIndex; i <= patEndIndex; i++) {
|
||||
if (patArr[i] != '*') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// process pattern between stars. patIndex and patEndIndex always point to a '*'.
|
||||
while (patIndex != patEndIndex && valIndex <= valEndIndex) {
|
||||
int innerPatternIndex = -1;
|
||||
for (int i = patIndex + 1; i <= patEndIndex; i++) {
|
||||
if (patArr[i] == '*') {
|
||||
innerPatternIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (innerPatternIndex == patIndex + 1) {
|
||||
// Two stars next to each other, skip the first one.
|
||||
patIndex++;
|
||||
continue;
|
||||
}
|
||||
// Find the pattern between patIndex & innerPatternIndex in the value between
|
||||
// valIndex and valEndIndex
|
||||
int innerPatternLength = (innerPatternIndex - patIndex - 1);
|
||||
int innerValueLength = (valEndIndex - valIndex + 1);
|
||||
int foundIndex = -1;
|
||||
innerValueLoop:
|
||||
for (int i = 0; i <= innerValueLength - innerPatternLength; i++) {
|
||||
for (int j = 0; j < innerPatternLength; j++) {
|
||||
ch = patArr[patIndex + j + 1];
|
||||
if (ch != '?') {
|
||||
if (ch != valArr[valIndex + i + j]) {
|
||||
continue innerValueLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foundIndex = valIndex + i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (foundIndex == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
patIndex = innerPatternIndex;
|
||||
valIndex = foundIndex + innerPatternLength;
|
||||
}
|
||||
|
||||
// All characters in the string are used. Check if only '*'s are left
|
||||
// in the pattern. If so, we succeeded. Otherwise failure.
|
||||
for (int i = patIndex; i <= patEndIndex; i++) {
|
||||
if (patArr[i] != '*') {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected List<Set<String>> getParts(WildcardPermission wp) {
|
||||
if (wp instanceof ActiveMQWildcardPermission) {
|
||||
return ((ActiveMQWildcardPermission) wp).getParts();
|
||||
} else {
|
||||
return getPartsByReflection(wp);
|
||||
}
|
||||
}
|
||||
|
||||
protected List<Set<String>> getPartsByReflection(WildcardPermission wp) {
|
||||
try {
|
||||
return doGetPartsByReflection(wp);
|
||||
} catch (Exception e) {
|
||||
String msg = "Unable to obtain WildcardPermission instance's 'parts' value.";
|
||||
throw new IllegalStateException(msg, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected List<Set<String>> doGetPartsByReflection(WildcardPermission wp) throws Exception {
|
||||
Method getParts = WildcardPermission.class.getDeclaredMethod("getParts");
|
||||
getParts.setAccessible(true);
|
||||
return (List<Set<String>>) getParts.invoke(wp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
for (Set<String> part : getParts()) {
|
||||
if (buffer.length() > 0) {
|
||||
buffer.append(":");
|
||||
}
|
||||
boolean first = true;
|
||||
for (String token : part) {
|
||||
if (!first) {
|
||||
buffer.append(",");
|
||||
}
|
||||
buffer.append(token);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,226 @@
|
|||
/**
|
||||
* 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.
|
||||
* <p/>
|
||||
* 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.
|
||||
* <p/>
|
||||
* 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.
|
||||
* <p/>
|
||||
* 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.
|
||||
* <h2>ActionPermissionResolver</h2>
|
||||
* 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.
|
||||
* <p/>
|
||||
* 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<Permission> 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/**
|
||||
* 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.command.ActiveMQDestination;
|
||||
|
||||
/**
|
||||
* A {@code DestinationAction} represents behavior being taken on a particular {@link ActiveMQDestination}, such as
|
||||
* creation, removal, and reading messages from it or writing messages to it. The exact behavior being taken on the
|
||||
* specific {@link #getDestination() destination} is represented as a {@link #getVerb() verb} property, which is one of
|
||||
* the following string tokens:
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Verb</th>
|
||||
* <th>Description</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code create}</td>
|
||||
* <td>Create a specific destination.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code remove}</td>
|
||||
* <td>Remove a specific destination.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code read}</td>
|
||||
* <td>Read (consume) messages from a specific destination.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>{@code write}</td>
|
||||
* <td>Write messages to a specific destination.</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class DestinationAction implements Action {
|
||||
|
||||
private final ConnectionContext connectionContext;
|
||||
private final ActiveMQDestination destination;
|
||||
private final String verb;
|
||||
|
||||
public DestinationAction(ConnectionContext connectionContext, ActiveMQDestination destination, String verb) {
|
||||
if (connectionContext == null) {
|
||||
throw new IllegalArgumentException("ConnectionContext argument cannot be null.");
|
||||
}
|
||||
if (destination == null) {
|
||||
throw new IllegalArgumentException("ActiveMQDestination argument cannot be null.");
|
||||
}
|
||||
if (verb == null) {
|
||||
throw new IllegalArgumentException("verb argument cannot be null.");
|
||||
}
|
||||
|
||||
this.connectionContext = connectionContext;
|
||||
this.destination = destination;
|
||||
this.verb = verb;
|
||||
}
|
||||
|
||||
public ConnectionContext getConnectionContext() {
|
||||
return connectionContext;
|
||||
}
|
||||
|
||||
public ActiveMQDestination getDestination() {
|
||||
return destination;
|
||||
}
|
||||
|
||||
public String getVerb() {
|
||||
return verb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.verb + " destination: " + destination;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,272 @@
|
|||
/**
|
||||
* 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());
|
||||
}
|
||||
}
|
45
activemq-shiro/src/main/java/org/apache/activemq/shiro/env/EnvironmentFilter.java
vendored
Normal file
45
activemq-shiro/src/main/java/org/apache/activemq/shiro/env/EnvironmentFilter.java
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
/**
|
||||
* 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.env;
|
||||
|
||||
import org.apache.activemq.shiro.SecurityFilter;
|
||||
import org.apache.shiro.env.Environment;
|
||||
|
||||
/**
|
||||
* An abstract {@code BrokerFilter} that makes the Shiro {@link Environment} available to subclasses.
|
||||
*
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public abstract class EnvironmentFilter extends SecurityFilter {
|
||||
|
||||
private Environment environment;
|
||||
|
||||
public EnvironmentFilter() {
|
||||
}
|
||||
|
||||
public Environment getEnvironment() {
|
||||
if (this.environment == null) {
|
||||
String msg = "Environment has not yet been set. This should be done before this broker filter is used.";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
return environment;
|
||||
}
|
||||
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
}
|
136
activemq-shiro/src/main/java/org/apache/activemq/shiro/env/IniEnvironment.java
vendored
Normal file
136
activemq-shiro/src/main/java/org/apache/activemq/shiro/env/IniEnvironment.java
vendored
Normal file
|
@ -0,0 +1,136 @@
|
|||
/**
|
||||
* 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.env;
|
||||
|
||||
import org.apache.activemq.shiro.authz.ActiveMQPermissionResolver;
|
||||
import org.apache.activemq.shiro.mgt.DefaultActiveMqSecurityManager;
|
||||
import org.apache.shiro.ShiroException;
|
||||
import org.apache.shiro.config.ConfigurationException;
|
||||
import org.apache.shiro.config.Ini;
|
||||
import org.apache.shiro.config.IniSecurityManagerFactory;
|
||||
import org.apache.shiro.env.DefaultEnvironment;
|
||||
import org.apache.shiro.io.ResourceUtils;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
import org.apache.shiro.realm.Realm;
|
||||
import org.apache.shiro.realm.text.IniRealm;
|
||||
import org.apache.shiro.util.Initializable;
|
||||
import org.apache.shiro.util.LifecycleUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class IniEnvironment extends DefaultEnvironment implements Initializable {
|
||||
|
||||
private Ini ini;
|
||||
private String iniConfig;
|
||||
private String iniResourePath;
|
||||
|
||||
public IniEnvironment() {
|
||||
}
|
||||
|
||||
public IniEnvironment(Ini ini) {
|
||||
this.ini = ini;
|
||||
init();
|
||||
}
|
||||
|
||||
public IniEnvironment(String iniConfig) {
|
||||
Ini ini = new Ini();
|
||||
ini.load(iniConfig);
|
||||
this.ini = ini;
|
||||
init();
|
||||
}
|
||||
|
||||
public void setIni(Ini ini) {
|
||||
this.ini = ini;
|
||||
}
|
||||
|
||||
public void setIniConfig(String config) {
|
||||
this.iniConfig = config;
|
||||
}
|
||||
|
||||
public void setIniResourcePath(String iniResourcePath) {
|
||||
this.iniResourePath = iniResourcePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws ShiroException {
|
||||
//this.environment and this.securityManager are null. Try Ini config:
|
||||
Ini ini = this.ini;
|
||||
if (ini != null) {
|
||||
apply(ini);
|
||||
}
|
||||
|
||||
if (this.objects.isEmpty() && this.iniConfig != null) {
|
||||
ini = new Ini();
|
||||
ini.load(this.iniConfig);
|
||||
apply(ini);
|
||||
}
|
||||
|
||||
if (this.objects.isEmpty() && this.iniResourePath != null) {
|
||||
ini = new Ini();
|
||||
ini.loadFromPath(this.iniResourePath);
|
||||
apply(ini);
|
||||
}
|
||||
|
||||
if (this.objects.isEmpty()) {
|
||||
if (ResourceUtils.resourceExists("classpath:shiro.ini")) {
|
||||
ini = new Ini();
|
||||
ini.loadFromPath("classpath:shiro.ini");
|
||||
apply(ini);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.objects.isEmpty()) {
|
||||
String msg = "Configuration error. All heuristics for acquiring Shiro INI config " +
|
||||
"have been exhausted. Ensure you configure one of the following properties: " +
|
||||
"1) ini 2) iniConfig 3) iniResourcePath and the Ini sections are not empty.";
|
||||
throw new ConfigurationException(msg);
|
||||
}
|
||||
|
||||
LifecycleUtils.init(this.objects.values());
|
||||
}
|
||||
|
||||
protected void apply(Ini ini) {
|
||||
if (ini != null && !ini.isEmpty()) {
|
||||
Map<String, ?> objects = createObjects(ini);
|
||||
this.ini = ini;
|
||||
this.objects.clear();
|
||||
this.objects.putAll(objects);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, ?> createObjects(Ini ini) {
|
||||
IniSecurityManagerFactory factory = new IniSecurityManagerFactory(ini) {
|
||||
|
||||
@Override
|
||||
protected SecurityManager createDefaultInstance() {
|
||||
return new DefaultActiveMqSecurityManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Realm createRealm(Ini ini) {
|
||||
IniRealm realm = (IniRealm)super.createRealm(ini);
|
||||
realm.setPermissionResolver(new ActiveMQPermissionResolver());
|
||||
return realm;
|
||||
}
|
||||
};
|
||||
factory.getInstance(); //trigger beans creation
|
||||
return factory.getBeans();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* 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.mgt;
|
||||
|
||||
import org.apache.activemq.shiro.session.mgt.DisabledSessionManager;
|
||||
import org.apache.shiro.mgt.DefaultSecurityManager;
|
||||
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
|
||||
import org.apache.shiro.mgt.DefaultSubjectDAO;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class DefaultActiveMqSecurityManager extends DefaultSecurityManager {
|
||||
|
||||
public DefaultActiveMqSecurityManager() {
|
||||
super();
|
||||
|
||||
//disable sessions entirely:
|
||||
setSessionManager(new DisabledSessionManager());
|
||||
|
||||
//also prevent the SecurityManager impl from using the Session as a storage medium (i.e. after authc):
|
||||
DefaultSubjectDAO subjectDao = (DefaultSubjectDAO)getSubjectDAO();
|
||||
DefaultSessionStorageEvaluator sessionStorageEvaluator =
|
||||
(DefaultSessionStorageEvaluator)subjectDao.getSessionStorageEvaluator();
|
||||
sessionStorageEvaluator.setSessionStorageEnabled(false);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/**
|
||||
* 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.session.mgt;
|
||||
|
||||
import org.apache.shiro.session.Session;
|
||||
import org.apache.shiro.session.SessionException;
|
||||
import org.apache.shiro.session.mgt.SessionContext;
|
||||
import org.apache.shiro.session.mgt.SessionKey;
|
||||
import org.apache.shiro.session.mgt.SessionManager;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class DisabledSessionManager implements SessionManager {
|
||||
|
||||
@Override
|
||||
public Session start(SessionContext context) {
|
||||
throw new UnsupportedOperationException("Sessions are disabled.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Session getSession(SessionKey key) throws SessionException {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* 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.subject;
|
||||
|
||||
import org.apache.activemq.shiro.ConnectionReference;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
/**
|
||||
* A {@code ConnectionSubjectFactory} creates a {@code Subject} instance that represents the connection client's identity.
|
||||
* <p/>
|
||||
* Most implementations will simply use the {@link Subject.Builder Subject.Builder} to create an anonymous
|
||||
* {@code Subject} instance and let a downstream {@link org.apache.activemq.shiro.authc.AuthenticationFilter} authenticate the {@code Subject} based on
|
||||
* any credentials associated with the connection. After authentication, the {@code Subject} will have an identity, and
|
||||
* this is the expected flow for most connection clients.
|
||||
* <p/>
|
||||
* However, if there is some other data associated with the connection that can be inspected to create a
|
||||
* {@code Subject} instance beyond what the {@link DefaultConnectionSubjectFactory} provides, this interface allows that
|
||||
* logic to be plugged in as necessary.
|
||||
*
|
||||
* @see DefaultConnectionSubjectFactory
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public interface ConnectionSubjectFactory {
|
||||
|
||||
/**
|
||||
* Creates a {@code Subject} instance representing the connection client. It is common for {@code Subject} instances
|
||||
* returned from this method to be anonymous until a downstream {@link org.apache.activemq.shiro.authc.AuthenticationFilter} authenticates the
|
||||
* subject to associate an identity.
|
||||
*
|
||||
* @param ref a reference to the client's connection metadata
|
||||
* @return a {@code Subject} instance representing the connection client.
|
||||
*/
|
||||
Subject createSubject(ConnectionReference ref);
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* 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.subject;
|
||||
|
||||
import org.apache.activemq.broker.ConnectionContext;
|
||||
import org.apache.activemq.security.SecurityContext;
|
||||
import org.apache.activemq.shiro.ConnectionReference;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
/**
|
||||
* A {@code SubjectResolver} that acquires the current Subject from a {@link org.apache.activemq.shiro.ConnectionReference}.
|
||||
*
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class ConnectionSubjectResolver implements SubjectResolver {
|
||||
|
||||
private final SubjectSecurityContext securityContext;
|
||||
|
||||
public ConnectionSubjectResolver(ConnectionContext connCtx) {
|
||||
if (connCtx == null) {
|
||||
throw new IllegalArgumentException("ConnectionContext argument cannot be null.");
|
||||
}
|
||||
SecurityContext secCtx = connCtx.getSecurityContext();
|
||||
if (secCtx == null) {
|
||||
String msg = "There is no SecurityContext available on the ConnectionContext. It " +
|
||||
"is expected that a previous broker in the chain will create the SecurityContext prior to this " +
|
||||
"resolver being invoked. Ensure you have configured the SubjectPlugin and that it is " +
|
||||
"configured before all other Shiro-dependent broker filters.";
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
if (!(secCtx instanceof SubjectSecurityContext)) {
|
||||
String msg = "The specified SecurityContext is expected to be a " + SubjectSecurityContext.class.getName() +
|
||||
" instance. The current instance's class: " + secCtx.getClass().getName();
|
||||
throw new IllegalArgumentException(msg);
|
||||
}
|
||||
this.securityContext = (SubjectSecurityContext) secCtx;
|
||||
}
|
||||
|
||||
public ConnectionSubjectResolver(ConnectionReference conn) {
|
||||
this(conn.getConnectionContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject getSubject() {
|
||||
Subject subject = securityContext.getSubject();
|
||||
if (subject != null) {
|
||||
return subject;
|
||||
}
|
||||
String msg = "There is no Subject available in the SecurityContext. Ensure " +
|
||||
"that the SubjectPlugin is configured before all other Shiro-dependent broker filters.";
|
||||
throw new IllegalStateException(msg);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* 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.subject;
|
||||
|
||||
import org.apache.activemq.shiro.ConnectionReference;
|
||||
import org.apache.activemq.shiro.authc.AuthenticationPolicy;
|
||||
import org.apache.activemq.shiro.authc.DefaultAuthenticationPolicy;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class DefaultConnectionSubjectFactory implements ConnectionSubjectFactory {
|
||||
|
||||
private AuthenticationPolicy authenticationPolicy;
|
||||
|
||||
public DefaultConnectionSubjectFactory() {
|
||||
this.authenticationPolicy = new DefaultAuthenticationPolicy();
|
||||
}
|
||||
|
||||
public AuthenticationPolicy getAuthenticationPolicy() {
|
||||
return authenticationPolicy;
|
||||
}
|
||||
|
||||
public void setAuthenticationPolicy(AuthenticationPolicy authenticationPolicy) {
|
||||
this.authenticationPolicy = authenticationPolicy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Subject createSubject(ConnectionReference conn) {
|
||||
|
||||
Subject.Builder builder = new Subject.Builder(conn.getEnvironment().getSecurityManager());
|
||||
|
||||
authenticationPolicy.customizeSubject(builder, conn);
|
||||
|
||||
return builder.buildSubject();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* 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.subject;
|
||||
|
||||
import org.apache.activemq.broker.ConnectionContext;
|
||||
import org.apache.activemq.command.ConnectionInfo;
|
||||
import org.apache.activemq.shiro.ConnectionReference;
|
||||
import org.apache.shiro.env.Environment;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
/**
|
||||
* {@link org.apache.activemq.shiro.ConnectionReference} that further provides access to the connection's Subject instance.
|
||||
*
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class SubjectConnectionReference extends ConnectionReference {
|
||||
|
||||
private final Subject subject;
|
||||
|
||||
public SubjectConnectionReference(ConnectionContext connCtx, ConnectionInfo connInfo,
|
||||
Environment environment, Subject subject) {
|
||||
super(connCtx, connInfo, environment);
|
||||
if (subject == null) {
|
||||
throw new IllegalArgumentException("Subject argument cannot be null.");
|
||||
}
|
||||
this.subject = subject;
|
||||
}
|
||||
|
||||
public Subject getSubject() {
|
||||
return subject;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/**
|
||||
* 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.subject;
|
||||
|
||||
import org.apache.activemq.broker.ConnectionContext;
|
||||
import org.apache.activemq.command.ConnectionInfo;
|
||||
import org.apache.activemq.security.SecurityContext;
|
||||
import org.apache.activemq.shiro.ConnectionReference;
|
||||
import org.apache.activemq.shiro.DefaultSecurityContextFactory;
|
||||
import org.apache.activemq.shiro.SecurityContextFactory;
|
||||
import org.apache.activemq.shiro.env.EnvironmentFilter;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
/**
|
||||
* The {@code SubjectFilter} ensures a Shiro {@link Subject} representing the client's identity is associated with
|
||||
* every connection to the ActiveMQ Broker. The {@code Subject} is made available to downstream broker filters so
|
||||
* they may perform security checks as necessary.
|
||||
* <p/>
|
||||
* This implementation does not perform any security checks/assertions itself. It is expected that other broker filters
|
||||
* will be configured after this one and those will perform any security behavior or checks as necessary.
|
||||
*
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class SubjectFilter extends EnvironmentFilter {
|
||||
|
||||
private ConnectionSubjectFactory connectionSubjectFactory;
|
||||
private SecurityContextFactory securityContextFactory;
|
||||
|
||||
public SubjectFilter() {
|
||||
this.connectionSubjectFactory = new DefaultConnectionSubjectFactory();
|
||||
this.securityContextFactory = new DefaultSecurityContextFactory();
|
||||
}
|
||||
|
||||
public ConnectionSubjectFactory getConnectionSubjectFactory() {
|
||||
return connectionSubjectFactory;
|
||||
}
|
||||
|
||||
public void setConnectionSubjectFactory(ConnectionSubjectFactory connectionSubjectFactory) {
|
||||
if (connectionSubjectFactory == null) {
|
||||
throw new IllegalArgumentException("ConnectionSubjectFactory argument cannot be null.");
|
||||
}
|
||||
this.connectionSubjectFactory = connectionSubjectFactory;
|
||||
}
|
||||
|
||||
public SecurityContextFactory getSecurityContextFactory() {
|
||||
return this.securityContextFactory;
|
||||
}
|
||||
|
||||
public void setSecurityContextFactory(SecurityContextFactory securityContextFactory) {
|
||||
if (securityContextFactory == null) {
|
||||
throw new IllegalArgumentException("SecurityContextFactory argument cannot be null.");
|
||||
}
|
||||
this.securityContextFactory = securityContextFactory;
|
||||
}
|
||||
|
||||
protected Subject createSubject(ConnectionReference conn) {
|
||||
return this.connectionSubjectFactory.createSubject(conn);
|
||||
}
|
||||
|
||||
protected SecurityContext createSecurityContext(SubjectConnectionReference conn) {
|
||||
return this.securityContextFactory.createSecurityContext(conn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link Subject} instance reflecting the specified Connection. The {@code Subject} is then stored in
|
||||
* a {@link SecurityContext} instance which is set as the Connection's
|
||||
* {@link ConnectionContext#setSecurityContext(org.apache.activemq.security.SecurityContext) securityContext}.
|
||||
*
|
||||
* @param context state associated with the client's connection
|
||||
* @param info info about the client's connection
|
||||
* @throws Exception if there is a problem creating a Subject or {@code SecurityContext} instance.
|
||||
*/
|
||||
@Override
|
||||
public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
|
||||
|
||||
if (isEnabled()) {
|
||||
|
||||
SecurityContext secCtx = context.getSecurityContext();
|
||||
|
||||
if (secCtx == null) {
|
||||
ConnectionReference conn = new ConnectionReference(context, info, getEnvironment());
|
||||
Subject subject = createSubject(conn);
|
||||
SubjectConnectionReference subjectConn = new SubjectConnectionReference(context, info, getEnvironment(), subject);
|
||||
secCtx = createSecurityContext(subjectConn);
|
||||
context.setSecurityContext(secCtx);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
super.addConnection(context, info);
|
||||
} catch (Exception e) {
|
||||
context.setSecurityContext(null);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeConnection(ConnectionContext context, ConnectionInfo info, Throwable error) throws Exception {
|
||||
try {
|
||||
super.removeConnection(context, info, error);
|
||||
} finally {
|
||||
context.setSecurityContext(null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/**
|
||||
* 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.subject;
|
||||
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public interface SubjectResolver {
|
||||
|
||||
/**
|
||||
* Resolves and returns a {@link Subject} instance. If one cannot be found, a runtime {@code Exception} is thrown.
|
||||
*
|
||||
* @return a resolved {@code Subject} instance.
|
||||
*/
|
||||
Subject getSubject() throws RuntimeException;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/**
|
||||
* 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.subject;
|
||||
|
||||
import org.apache.activemq.command.ActiveMQDestination;
|
||||
import org.apache.activemq.security.SecurityContext;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* ActiveMQ {@code SecurityContext} implementation that retains a Shiro {@code Subject} instance for use during
|
||||
* security checks and other security-related operations.
|
||||
*
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class SubjectSecurityContext extends SecurityContext {
|
||||
|
||||
private final Subject subject;
|
||||
|
||||
public SubjectSecurityContext(SubjectConnectionReference conn) {
|
||||
//The username might not be available at the time this object is instantiated (the Subject might be
|
||||
//anonymous). Instead we override the getUserName() method below and that will always delegate to the
|
||||
//Subject to return the most accurate/freshest username available.
|
||||
super(null);
|
||||
this.subject = conn.getSubject();
|
||||
}
|
||||
|
||||
public Subject getSubject() {
|
||||
return subject;
|
||||
}
|
||||
|
||||
private static String getUsername(Subject subject) {
|
||||
if (subject != null) {
|
||||
Object principal = subject.getPrincipal();
|
||||
if (principal != null) {
|
||||
return String.valueOf(principal);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserName() {
|
||||
return getUsername(this.subject);
|
||||
}
|
||||
|
||||
private static UnsupportedOperationException notAllowed(String methodName) {
|
||||
String msg = "Do not invoke the '" + methodName + "' method or use a broker filter that invokes it. Use one " +
|
||||
"of the Shiro-based security filters instead.";
|
||||
return new UnsupportedOperationException(msg);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInOneOf(Set<?> allowedPrincipals) {
|
||||
throw notAllowed("isInOneOf");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConcurrentHashMap<ActiveMQDestination, ActiveMQDestination> getAuthorizedReadDests() {
|
||||
throw notAllowed("getAuthorizedReadDests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConcurrentHashMap<ActiveMQDestination, ActiveMQDestination> getAuthorizedWriteDests() {
|
||||
throw notAllowed("getAuthorizedWriteDests");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Principal> getPrincipals() {
|
||||
throw notAllowed("getPrincipals");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import org.apache.activemq.broker.ConnectionContext;
|
||||
import org.apache.activemq.command.ConnectionInfo;
|
||||
import org.apache.shiro.env.DefaultEnvironment;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class ConnectionReferenceTest {
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testNoConnectionContext() {
|
||||
new ConnectionReference(null, new ConnectionInfo(), new DefaultEnvironment());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testNoConnectionInfo() {
|
||||
new ConnectionReference(new ConnectionContext(), null, new DefaultEnvironment());
|
||||
}
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testNoEnvironment() {
|
||||
new ConnectionReference(new ConnectionContext(), new ConnectionInfo(), null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class SecurityFilterTest {
|
||||
|
||||
@Test
|
||||
public void testEnabled() {
|
||||
|
||||
SecurityFilter filter = new SecurityFilter() {};
|
||||
assertTrue(filter.isEnabled()); //enabled by default
|
||||
|
||||
filter.setEnabled(false);
|
||||
assertFalse(filter.isEnabled());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,403 @@
|
|||
/**
|
||||
* 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;
|
||||
|
||||
import org.apache.activemq.broker.BrokerPlugin;
|
||||
import org.apache.activemq.broker.BrokerService;
|
||||
import org.apache.activemq.broker.MutableBrokerFilter;
|
||||
import org.apache.activemq.shiro.authc.AuthenticationFilter;
|
||||
import org.apache.activemq.shiro.authc.DefaultAuthenticationPolicy;
|
||||
import org.apache.activemq.shiro.authz.AuthorizationFilter;
|
||||
import org.apache.activemq.shiro.env.IniEnvironment;
|
||||
import org.apache.activemq.shiro.subject.DefaultConnectionSubjectFactory;
|
||||
import org.apache.activemq.shiro.subject.SubjectFilter;
|
||||
import org.apache.activemq.test.JmsResourceProvider;
|
||||
import org.apache.activemq.test.TestSupport;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.config.Ini;
|
||||
import org.apache.shiro.env.DefaultEnvironment;
|
||||
import org.apache.shiro.env.Environment;
|
||||
import org.apache.shiro.mgt.DefaultSecurityManager;
|
||||
import org.apache.shiro.realm.text.IniRealm;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.ConnectionFactory;
|
||||
import javax.jms.Destination;
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.MessageConsumer;
|
||||
import javax.jms.MessageProducer;
|
||||
import javax.jms.Session;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class ShiroPluginTest extends TestSupport {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ShiroPluginTest.class);
|
||||
|
||||
protected BrokerService broker;
|
||||
protected SecureJmsResourceProvider resourceProvider;
|
||||
protected ConnectionFactory connectionFactory;
|
||||
protected Connection connection;
|
||||
protected Session session;
|
||||
protected Destination destination;
|
||||
protected MessageConsumer consumer;
|
||||
protected MessageProducer producer;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
resourceProvider = new SecureJmsResourceProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
LOG.info("Shutting down broker...");
|
||||
|
||||
if (session != null) {
|
||||
session.close();
|
||||
}
|
||||
session = null;
|
||||
|
||||
if (connection != null) {
|
||||
connection.close();
|
||||
}
|
||||
connection = null;
|
||||
|
||||
if (broker != null) {
|
||||
broker.stop();
|
||||
broker.waitUntilStopped();
|
||||
}
|
||||
broker = null;
|
||||
|
||||
LOG.info("Broker shut down.");
|
||||
}
|
||||
|
||||
protected void reconnect() throws Exception {
|
||||
reconnect(null, null);
|
||||
}
|
||||
|
||||
protected void reconnect(String username, String password) throws Exception {
|
||||
if (connection != null) {
|
||||
// Close the prev connection.
|
||||
connection.close();
|
||||
}
|
||||
session = null;
|
||||
if (username == null && password == null) {
|
||||
connection = resourceProvider.createConnection(connectionFactory);
|
||||
} else {
|
||||
connection = resourceProvider.createConnection(connectionFactory, username, password);
|
||||
}
|
||||
reconnectSession();
|
||||
connection.start();
|
||||
}
|
||||
|
||||
protected void reconnectSession() throws JMSException {
|
||||
if (session != null) {
|
||||
session.close();
|
||||
}
|
||||
session = resourceProvider.createSession(connection);
|
||||
destination = resourceProvider.createDestination(session, getSubject());
|
||||
producer = resourceProvider.createProducer(session, destination);
|
||||
consumer = resourceProvider.createConsumer(session, destination);
|
||||
}
|
||||
|
||||
protected ConnectionFactory newConnectionFactory() throws Exception {
|
||||
return resourceProvider.createConnectionFactory();
|
||||
}
|
||||
|
||||
protected void start() throws Exception {
|
||||
startBroker();
|
||||
topic = resourceProvider.isTopic();
|
||||
connectionFactory = newConnectionFactory();
|
||||
}
|
||||
|
||||
protected void startBroker() throws Exception {
|
||||
broker.start();
|
||||
broker.waitUntilStarted();
|
||||
}
|
||||
|
||||
protected BrokerService createBroker(BrokerPlugin... plugins) throws Exception {
|
||||
return createBroker(plugins, resourceProvider.getServerUri());
|
||||
}
|
||||
|
||||
protected BrokerService createBroker(BrokerPlugin[] plugins, String... connectorUris) throws Exception {
|
||||
BrokerService brokerService = new BrokerService();
|
||||
if (plugins != null && plugins.length > 0) {
|
||||
brokerService.setPlugins(plugins);
|
||||
}
|
||||
if (connectorUris != null) {
|
||||
for (String uri : connectorUris) {
|
||||
brokerService.addConnector(uri);
|
||||
}
|
||||
}
|
||||
return brokerService;
|
||||
}
|
||||
|
||||
protected ShiroPlugin createPlugin(String iniPath) {
|
||||
Ini ini = Ini.fromResourcePath(iniPath);
|
||||
Environment env = new IniEnvironment(ini);
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
plugin.setEnvironment(env);
|
||||
return plugin;
|
||||
}
|
||||
|
||||
public void testNoEnvironmentOrSecurityManager() throws Exception {
|
||||
//should build IniEnvironment from shiro.ini in the classpath at the least:
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
plugin.installPlugin(new MutableBrokerFilter(null));
|
||||
|
||||
Ini ini = Ini.fromResourcePath("classpath:shiro.ini");
|
||||
IniRealm realm = (IniRealm) ((DefaultSecurityManager) plugin.getEnvironment().getSecurityManager()).getRealms().iterator().next();
|
||||
assertEquals(ini, realm.getIni());
|
||||
}
|
||||
|
||||
public void testSetIni() throws Exception {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
Ini ini = Ini.fromResourcePath("classpath:minimal.shiro.ini");
|
||||
plugin.setIni(ini);
|
||||
plugin.installPlugin(new MutableBrokerFilter(null));
|
||||
|
||||
IniRealm realm = (IniRealm) ((DefaultSecurityManager) plugin.getEnvironment().getSecurityManager()).getRealms().iterator().next();
|
||||
assertSame(ini, realm.getIni());
|
||||
}
|
||||
|
||||
public void testSetIniString() throws Exception {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
plugin.setIniConfig(
|
||||
"[users]\n" +
|
||||
"system = manager, system\n" +
|
||||
"[roles]\n" +
|
||||
"system = *");
|
||||
plugin.installPlugin(new MutableBrokerFilter(null));
|
||||
|
||||
IniRealm realm = (IniRealm) ((DefaultSecurityManager) plugin.getEnvironment().getSecurityManager()).getRealms().iterator().next();
|
||||
Ini ini = realm.getIni();
|
||||
assertEquals(1, ini.getSection("users").size());
|
||||
assertEquals("manager, system", ini.getSection("users").get("system"));
|
||||
assertEquals(1, ini.getSection("roles").size());
|
||||
assertEquals("*", ini.getSection("roles").get("system"));
|
||||
}
|
||||
|
||||
public void testSetIniResourcePath() throws Exception {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
|
||||
String path = "classpath:minimal.shiro.ini";
|
||||
|
||||
plugin.setIniResourcePath(path);
|
||||
plugin.installPlugin(new MutableBrokerFilter(null));
|
||||
|
||||
Ini ini = Ini.fromResourcePath(path);
|
||||
|
||||
IniRealm realm = (IniRealm) ((DefaultSecurityManager) plugin.getEnvironment().getSecurityManager()).getRealms().iterator().next();
|
||||
assertEquals(ini, realm.getIni());
|
||||
}
|
||||
|
||||
public void testSetSubjectFilter() {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
SubjectFilter filter = new SubjectFilter();
|
||||
plugin.setSubjectFilter(filter);
|
||||
assertSame(filter, plugin.getSubjectFilter());
|
||||
//assert that the AuthenticationFilter is always the next filter in the chain after the SubjectFilter:
|
||||
assertSame(plugin.getAuthenticationFilter(), filter.getNext());
|
||||
}
|
||||
|
||||
public void testSetAuthenticationFilter() {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
AuthenticationFilter filter = new AuthenticationFilter();
|
||||
plugin.setAuthenticationFilter(filter);
|
||||
assertSame(filter, plugin.getAuthenticationFilter());
|
||||
//assert that the AuthenticationFilter is always the next filter in the chain after the SubjectFilter:
|
||||
assertSame(plugin.getSubjectFilter().getNext(), filter);
|
||||
}
|
||||
|
||||
public void testSetAuthorizationFilter() {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
AuthorizationFilter filter = new AuthorizationFilter();
|
||||
plugin.setAuthorizationFilter(filter);
|
||||
assertSame(filter, plugin.getAuthorizationFilter());
|
||||
//assert that the AuthenticationFilter is always the next filter in the chain after the AuthenticationFilter:
|
||||
assertSame(plugin.getAuthenticationFilter().getNext(), filter);
|
||||
}
|
||||
|
||||
public void testSetEnvironment() {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
Environment env = new DefaultEnvironment();
|
||||
plugin.setEnvironment(env);
|
||||
assertSame(env, plugin.getEnvironment());
|
||||
}
|
||||
|
||||
public void testSetSecurityManager() {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
org.apache.shiro.mgt.SecurityManager securityManager = new DefaultSecurityManager();
|
||||
plugin.setSecurityManager(securityManager);
|
||||
assertSame(securityManager, plugin.getSecurityManager());
|
||||
}
|
||||
|
||||
public void testSecurityManagerWhenInstalled() throws Exception {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
org.apache.shiro.mgt.SecurityManager securityManager = new DefaultSecurityManager();
|
||||
plugin.setSecurityManager(securityManager);
|
||||
|
||||
assertNull(plugin.getEnvironment()); //we will auto-create one when only a sm is provided
|
||||
|
||||
plugin.installPlugin(new MutableBrokerFilter(null));
|
||||
|
||||
assertSame(securityManager, plugin.getSecurityManager());
|
||||
assertNotNull(plugin.getEnvironment());
|
||||
assertSame(securityManager, plugin.getEnvironment().getSecurityManager());
|
||||
}
|
||||
|
||||
public void testEnabledWhenNotInstalled() {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
assertTrue(plugin.isEnabled()); //enabled by default
|
||||
|
||||
plugin.setEnabled(false);
|
||||
assertFalse(plugin.isEnabled());
|
||||
|
||||
plugin.setEnabled(true);
|
||||
assertTrue(plugin.isEnabled());
|
||||
}
|
||||
|
||||
public void testEnabledWhenInstalled() throws Exception {
|
||||
ShiroPlugin plugin = createPlugin("classpath:minimal.shiro.ini");
|
||||
this.broker = createBroker(plugin);
|
||||
start();
|
||||
assertTrue(plugin.isEnabled());
|
||||
|
||||
plugin.setEnabled(false);
|
||||
assertFalse(plugin.isEnabled());
|
||||
|
||||
plugin.setEnabled(true);
|
||||
assertTrue(plugin.isEnabled());
|
||||
}
|
||||
|
||||
public void testAuthenticationEnabledWhenNotInstalled() {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
assertTrue(plugin.isAuthenticationEnabled());
|
||||
|
||||
plugin.setAuthenticationEnabled(false);
|
||||
assertFalse(plugin.isAuthenticationEnabled());
|
||||
|
||||
plugin.setAuthenticationEnabled(true);
|
||||
assertTrue(plugin.isAuthenticationEnabled());
|
||||
}
|
||||
|
||||
public void testAuthenticationEnabledWhenInstalled() throws Exception {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
plugin.setEnvironment(new DefaultEnvironment());
|
||||
plugin.installPlugin(new MutableBrokerFilter(null));
|
||||
|
||||
assertTrue(plugin.isAuthenticationEnabled());
|
||||
|
||||
plugin.setAuthenticationEnabled(false);
|
||||
assertFalse(plugin.isAuthenticationEnabled());
|
||||
|
||||
plugin.setAuthenticationEnabled(true);
|
||||
assertTrue(plugin.isAuthenticationEnabled());
|
||||
}
|
||||
|
||||
public void testSetAuthenticationPolicy() {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
DefaultAuthenticationPolicy policy = new DefaultAuthenticationPolicy();
|
||||
plugin.setAuthenticationPolicy(policy);
|
||||
assertSame(policy, plugin.getAuthenticationPolicy());
|
||||
assertSame(policy, plugin.getAuthenticationFilter().getAuthenticationPolicy());
|
||||
assertSame(policy, ((DefaultConnectionSubjectFactory) plugin.getSubjectFilter().getConnectionSubjectFactory()).getAuthenticationPolicy());
|
||||
}
|
||||
|
||||
public void testAuthorizationEnabledWhenNotInstalled() {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
assertTrue(plugin.isAuthorizationEnabled());
|
||||
|
||||
plugin.setAuthorizationEnabled(false);
|
||||
assertFalse(plugin.isAuthorizationEnabled());
|
||||
|
||||
plugin.setAuthorizationEnabled(true);
|
||||
assertTrue(plugin.isAuthorizationEnabled());
|
||||
}
|
||||
|
||||
public void testAuthorizationEnabledWhenInstalled() throws Exception {
|
||||
ShiroPlugin plugin = new ShiroPlugin();
|
||||
plugin.setEnvironment(new DefaultEnvironment());
|
||||
plugin.installPlugin(new MutableBrokerFilter(null));
|
||||
|
||||
assertTrue(plugin.isAuthorizationEnabled());
|
||||
|
||||
plugin.setAuthorizationEnabled(false);
|
||||
assertFalse(plugin.isAuthorizationEnabled());
|
||||
|
||||
plugin.setAuthorizationEnabled(true);
|
||||
assertTrue(plugin.isAuthorizationEnabled());
|
||||
}
|
||||
|
||||
|
||||
public void testSimple() throws Exception {
|
||||
ShiroPlugin plugin = createPlugin("classpath:minimal.shiro.ini");
|
||||
this.broker = createBroker(plugin);
|
||||
start();
|
||||
reconnect();
|
||||
}
|
||||
|
||||
public void testDisabled() throws Exception {
|
||||
ShiroPlugin plugin = createPlugin("classpath:nosystem.shiro.ini");
|
||||
plugin.setEnabled(false);
|
||||
this.broker = createBroker(plugin);
|
||||
start();
|
||||
}
|
||||
|
||||
public void testRuntimeDisableEnableChanges() throws Exception {
|
||||
ShiroPlugin plugin = createPlugin("classpath:nosystem.shiro.ini");
|
||||
((DefaultAuthenticationPolicy) plugin.getAuthenticationPolicy()).setVmConnectionAuthenticationRequired(true);
|
||||
plugin.setEnabled(false);
|
||||
this.broker = createBroker(plugin);
|
||||
start();
|
||||
|
||||
//connection has no credentials. When disabled, this should succeed:
|
||||
reconnect();
|
||||
|
||||
//now enable the plugin and assert that credentials are required:
|
||||
plugin.setEnabled(true);
|
||||
|
||||
try {
|
||||
reconnect();
|
||||
fail("Connections without passwords in this configuration should fail.");
|
||||
} catch (JMSException expected) {
|
||||
assertTrue(expected.getCause() instanceof AuthenticationException);
|
||||
}
|
||||
|
||||
//this should work now that we're authenticating:
|
||||
reconnect("foo", "bar");
|
||||
}
|
||||
|
||||
static class SecureJmsResourceProvider extends JmsResourceProvider {
|
||||
|
||||
/**
|
||||
* Creates a connection, authenticating with the specified username and password.
|
||||
*
|
||||
* @see org.apache.activemq.test.JmsResourceProvider#createConnection(javax.jms.ConnectionFactory)
|
||||
*/
|
||||
public Connection createConnection(ConnectionFactory cf, String username, String password) throws JMSException {
|
||||
Connection connection = cf.createConnection(username, password);
|
||||
if (getClientID() != null) {
|
||||
connection.setClientID(getClientID());
|
||||
}
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* 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.authc;
|
||||
|
||||
import org.apache.activemq.broker.Broker;
|
||||
import org.apache.activemq.broker.BrokerPluginSupport;
|
||||
import org.apache.activemq.broker.ConnectionContext;
|
||||
import org.apache.activemq.command.ConnectionInfo;
|
||||
import org.apache.activemq.shiro.subject.SubjectAdapter;
|
||||
import org.apache.activemq.shiro.subject.SubjectConnectionReference;
|
||||
import org.apache.activemq.shiro.subject.SubjectSecurityContext;
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
import org.apache.shiro.env.DefaultEnvironment;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class AuthenticationFilterTest {
|
||||
|
||||
AuthenticationFilter filter = new AuthenticationFilter();
|
||||
|
||||
@Test
|
||||
public void testSetAuthenticationTokenFactory() {
|
||||
AuthenticationTokenFactory factory = new AuthenticationTokenFactory() {
|
||||
@Override
|
||||
public AuthenticationToken getAuthenticationToken(SubjectConnectionReference ref) throws Exception {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
filter.setAuthenticationTokenFactory(factory);
|
||||
assertSame(factory, filter.getAuthenticationTokenFactory());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveAuthenticationWithLogoutThrowable() throws Exception {
|
||||
|
||||
final boolean[] invoked = new boolean[1];
|
||||
|
||||
Broker broker = new BrokerPluginSupport() {
|
||||
@Override
|
||||
public void removeConnection(ConnectionContext context, ConnectionInfo info, Throwable error) throws Exception {
|
||||
invoked[0] = true;
|
||||
}
|
||||
};
|
||||
|
||||
DefaultEnvironment env = new DefaultEnvironment();
|
||||
|
||||
filter.setNext(broker);
|
||||
filter.setEnvironment(env);
|
||||
|
||||
Subject subject = new SubjectAdapter() {
|
||||
@Override
|
||||
public void logout() {
|
||||
throw new RuntimeException("Simulated failure.");
|
||||
}
|
||||
};
|
||||
|
||||
ConnectionContext ctx = new ConnectionContext();
|
||||
ConnectionInfo info = new ConnectionInfo();
|
||||
SubjectConnectionReference conn = new SubjectConnectionReference(ctx, info, env, subject);
|
||||
SubjectSecurityContext ssc = new SubjectSecurityContext(conn);
|
||||
ctx.setSecurityContext(ssc);
|
||||
|
||||
filter.removeConnection(ctx, info, null);
|
||||
|
||||
assertTrue(invoked[0]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,339 @@
|
|||
/**
|
||||
* 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.authc;
|
||||
|
||||
import org.apache.activemq.broker.Connection;
|
||||
import org.apache.activemq.broker.ConnectionContext;
|
||||
import org.apache.activemq.broker.Connector;
|
||||
import org.apache.activemq.broker.region.ConnectionStatistics;
|
||||
import org.apache.activemq.command.Command;
|
||||
import org.apache.activemq.command.ConnectionControl;
|
||||
import org.apache.activemq.command.ConnectionInfo;
|
||||
import org.apache.activemq.command.Response;
|
||||
import org.apache.activemq.shiro.subject.SubjectAdapter;
|
||||
import org.apache.activemq.shiro.subject.SubjectConnectionReference;
|
||||
import org.apache.shiro.env.DefaultEnvironment;
|
||||
import org.apache.shiro.subject.PrincipalCollection;
|
||||
import org.apache.shiro.subject.SimplePrincipalCollection;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class DefaultAuthenticationPolicyTest {
|
||||
|
||||
private DefaultAuthenticationPolicy policy;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.policy = new DefaultAuthenticationPolicy();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVmConnectionAuthenticationRequired() {
|
||||
boolean required = true;
|
||||
policy.setVmConnectionAuthenticationRequired(required);
|
||||
assertEquals(required, policy.isVmConnectionAuthenticationRequired());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSystemAccountUsername() {
|
||||
String name = "foo";
|
||||
policy.setSystemAccountUsername(name);
|
||||
assertEquals(name, policy.getSystemAccountUsername());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSystemAccountRealmName() {
|
||||
String name = "fooRealm";
|
||||
policy.setSystemAccountRealmName(name);
|
||||
assertEquals(name, policy.getSystemAccountRealmName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnonymousAllowed() {
|
||||
boolean allowed = true;
|
||||
policy.setAnonymousAccessAllowed(allowed);
|
||||
assertEquals(allowed, policy.isAnonymousAccessAllowed());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnonymousAccountUsername() {
|
||||
String name = "blah";
|
||||
policy.setAnonymousAccountUsername(name);
|
||||
assertEquals(name, policy.getAnonymousAccountUsername());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnonymousAccountRealmName() {
|
||||
String name = "blahRealm";
|
||||
policy.setAnonymousAccountRealmName(name);
|
||||
assertEquals(name, policy.getAnonymousAccountRealmName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAnonymousAccount() {
|
||||
Subject subject = new SubjectAdapter() {
|
||||
@Override
|
||||
public PrincipalCollection getPrincipals() {
|
||||
return new SimplePrincipalCollection("anonymous", "iniRealm");
|
||||
}
|
||||
};
|
||||
assertTrue(policy.isAnonymousAccount(subject));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAnonymousAccountWithNullPrincipals() {
|
||||
assertFalse(policy.isAnonymousAccount(new SubjectAdapter()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsSystemAccountWithNullPrincipals() {
|
||||
assertFalse(policy.isSystemAccount(new SubjectAdapter()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAuthenticationRequiredWhenAlreadyRequired() {
|
||||
Subject subject = new SubjectAdapter() {
|
||||
@Override
|
||||
public boolean isAuthenticated() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
SubjectConnectionReference sc = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
|
||||
new DefaultEnvironment(), subject);
|
||||
|
||||
assertFalse(policy.isAuthenticationRequired(sc));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAuthenticationRequiredWhenAnonymousAllowedAnonymousSubject() {
|
||||
|
||||
policy.setAnonymousAccessAllowed(true);
|
||||
|
||||
Subject subject = new SubjectAdapter() {
|
||||
@Override
|
||||
public PrincipalCollection getPrincipals() {
|
||||
return new SimplePrincipalCollection("anonymous", "iniRealm");
|
||||
}
|
||||
};
|
||||
SubjectConnectionReference sc = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
|
||||
new DefaultEnvironment(), subject);
|
||||
|
||||
assertFalse(policy.isAuthenticationRequired(sc));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAuthenticationRequiredWhenAnonymousAllowedAndNotAnonymousSubject() {
|
||||
|
||||
policy.setAnonymousAccessAllowed(true);
|
||||
|
||||
Subject subject = new SubjectAdapter() {
|
||||
@Override
|
||||
public PrincipalCollection getPrincipals() {
|
||||
return new SimplePrincipalCollection("system", "iniRealm");
|
||||
}
|
||||
};
|
||||
SubjectConnectionReference sc = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
|
||||
new DefaultEnvironment(), subject);
|
||||
|
||||
assertFalse(policy.isAuthenticationRequired(sc));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAuthenticationRequiredWhenSystemConnectionAndSystemSubject() {
|
||||
|
||||
Subject subject = new SubjectAdapter() {
|
||||
@Override
|
||||
public PrincipalCollection getPrincipals() {
|
||||
return new SimplePrincipalCollection("system", "iniRealm");
|
||||
}
|
||||
};
|
||||
SubjectConnectionReference sc = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
|
||||
new DefaultEnvironment(), subject);
|
||||
|
||||
assertFalse(policy.isAuthenticationRequired(sc));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAuthenticationRequiredWhenSystemConnectionRequiresAuthentication() {
|
||||
|
||||
policy.setVmConnectionAuthenticationRequired(true);
|
||||
|
||||
Subject subject = new SubjectAdapter() {
|
||||
@Override
|
||||
public PrincipalCollection getPrincipals() {
|
||||
return new SimplePrincipalCollection("system", "iniRealm");
|
||||
}
|
||||
};
|
||||
SubjectConnectionReference sc = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
|
||||
new DefaultEnvironment(), subject);
|
||||
|
||||
assertTrue(policy.isAuthenticationRequired(sc));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAuthenticationRequiredWhenSystemConnectionDoesNotRequireAuthenticationAndNotSystemAccount() {
|
||||
|
||||
Subject subject = new SubjectAdapter() {
|
||||
@Override
|
||||
public PrincipalCollection getPrincipals() {
|
||||
return new SimplePrincipalCollection("foo", "iniRealm");
|
||||
}
|
||||
};
|
||||
SubjectConnectionReference sc = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
|
||||
new DefaultEnvironment(), subject);
|
||||
|
||||
assertTrue(policy.isAuthenticationRequired(sc));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAssumeIdentity() {
|
||||
policy.setAnonymousAccessAllowed(true);
|
||||
assertTrue(policy.isAssumeIdentity(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAssumeIdentityWithSystemConnection() {
|
||||
|
||||
ConnectionContext ctx = new ConnectionContext();
|
||||
Connection connection = new Connection() {
|
||||
@Override
|
||||
public Connector getConnector() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchSync(Command message) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchAsync(Command command) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response service(Command command) {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceException(Throwable error) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSlow() {
|
||||
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlocked() {
|
||||
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDispatchQueueSize() {
|
||||
return 0; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConnectionStatistics getStatistics() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isManageable() {
|
||||
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRemoteAddress() {
|
||||
return "vm://localhost";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serviceExceptionAsync(IOException e) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getConnectionId() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNetworkConnection() {
|
||||
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFaultTolerantConnection() {
|
||||
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateClient(ConnectionControl control) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() throws Exception {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stop() throws Exception {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getActiveTransactionCount() {
|
||||
return 0; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getOldestActiveTransactionDuration() {
|
||||
return null; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
};
|
||||
|
||||
ctx.setConnection(connection);
|
||||
|
||||
SubjectConnectionReference sc = new SubjectConnectionReference(ctx, new ConnectionInfo(),
|
||||
new DefaultEnvironment(), new SubjectAdapter());
|
||||
|
||||
assertTrue(policy.isAssumeIdentity(sc));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* 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.shiro.authz.Permission;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class ActiveMQPermissionResolverTest {
|
||||
|
||||
@Test
|
||||
public void testDefault() {
|
||||
ActiveMQPermissionResolver resolver = new ActiveMQPermissionResolver();
|
||||
assertTrue(resolver.isCaseSensitive());
|
||||
Permission p = resolver.resolvePermission("Foo:Bar");
|
||||
assertNotNull(p);
|
||||
assertTrue(p instanceof ActiveMQWildcardPermission);
|
||||
assertTrue(p.implies(new ActiveMQWildcardPermission("Foo:Bar")));
|
||||
assertFalse(p.implies(new ActiveMQWildcardPermission("foo:bar")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCaseInsensitive() {
|
||||
ActiveMQPermissionResolver resolver = new ActiveMQPermissionResolver();
|
||||
resolver.setCaseSensitive(false);
|
||||
assertFalse(resolver.isCaseSensitive());
|
||||
Permission p = resolver.resolvePermission("Foo:Bar");
|
||||
assertNotNull(p);
|
||||
assertTrue(p instanceof ActiveMQWildcardPermission);
|
||||
assertTrue(p.implies(new ActiveMQWildcardPermission("foo:bar")));
|
||||
assertTrue(p.implies(new ActiveMQWildcardPermission("Foo:Bar", true)));
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/**
|
||||
* 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.shiro.authz.Permission;
|
||||
import org.apache.shiro.authz.permission.WildcardPermission;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class ActiveMQWildcardPermissionTest {
|
||||
|
||||
@Test
|
||||
public void testNotWildcardPermission() {
|
||||
ActiveMQWildcardPermission perm = new ActiveMQWildcardPermission("topic:TEST:*");
|
||||
Permission dummy = new Permission() {
|
||||
@Override
|
||||
public boolean implies(Permission p) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
assertFalse(perm.implies(dummy));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntrapartWildcard() {
|
||||
ActiveMQWildcardPermission superset = new ActiveMQWildcardPermission("topic:ActiveMQ.Advisory.*:read");
|
||||
ActiveMQWildcardPermission subset = new ActiveMQWildcardPermission("topic:ActiveMQ.Advisory.Topic:read");
|
||||
|
||||
assertTrue(superset.implies(subset));
|
||||
assertFalse(subset.implies(superset));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatches() {
|
||||
assertMatch("x", "x");
|
||||
assertNoMatch("x", "y");
|
||||
|
||||
assertMatch("xx", "xx");
|
||||
assertNoMatch("xy", "xz");
|
||||
|
||||
assertMatch("?", "x");
|
||||
assertMatch("x?", "xy");
|
||||
assertMatch("?y", "xy");
|
||||
assertMatch("x?z", "xyz");
|
||||
|
||||
assertMatch("*", "x");
|
||||
assertMatch("x*", "x");
|
||||
assertMatch("x*", "xy");
|
||||
assertMatch("xy*", "xy");
|
||||
assertMatch("xy*", "xyz");
|
||||
|
||||
assertMatch("*x", "x");
|
||||
assertNoMatch("*x", "y");
|
||||
|
||||
assertMatch("*x", "wx");
|
||||
assertNoMatch("*x", "wz");
|
||||
assertMatch("*x", "vwx");
|
||||
|
||||
assertMatch("x*z", "xz");
|
||||
assertMatch("x*z", "xyz");
|
||||
assertMatch("x*z", "xyyz");
|
||||
|
||||
assertNoMatch("ab*t?z", "abz");
|
||||
assertNoMatch("ab*d*yz", "abcdz");
|
||||
|
||||
assertMatch("ab**cd**ef*yz", "abcdefyz");
|
||||
assertMatch("a*c?*z", "abcxyz");
|
||||
assertMatch("a*cd*z", "abcdxyz");
|
||||
|
||||
assertMatch("*", "x:x");
|
||||
assertMatch("*", "x:x:x");
|
||||
assertMatch("x", "x:y");
|
||||
assertMatch("x", "x:y:z");
|
||||
|
||||
assertMatch("foo?armat*", "foobarmatches");
|
||||
assertMatch("f*", "f");
|
||||
assertNoMatch("foo", "f");
|
||||
assertMatch("fo*b", "foob");
|
||||
assertNoMatch("fo*b*r", "fooba");
|
||||
assertNoMatch("foo*", "f");
|
||||
|
||||
assertMatch("t*k?ou", "thankyou");
|
||||
assertMatch("he*l*world", "helloworld");
|
||||
assertNoMatch("foo", "foob");
|
||||
|
||||
assertMatch("*:ActiveMQ.Advisory", "foo:ActiveMQ.Advisory");
|
||||
assertNoMatch("*:ActiveMQ.Advisory", "foo:ActiveMQ.Advisory.");
|
||||
assertMatch("*:ActiveMQ.Advisory*", "foo:ActiveMQ.Advisory");
|
||||
assertMatch("*:ActiveMQ.Advisory*", "foo:ActiveMQ.Advisory.");
|
||||
assertMatch("*:ActiveMQ.Advisory.*", "foo:ActiveMQ.Advisory.Connection");
|
||||
assertMatch("*:ActiveMQ.Advisory*:read", "foo:ActiveMQ.Advisory.Connection:read");
|
||||
assertNoMatch("*:ActiveMQ.Advisory*:read", "foo:ActiveMQ.Advisory.Connection:write");
|
||||
assertMatch("*:ActiveMQ.Advisory*:*", "foo:ActiveMQ.Advisory.Connection:read");
|
||||
assertMatch("*:ActiveMQ.Advisory*:*", "foo:ActiveMQ.Advisory.");
|
||||
assertMatch("topic", "topic:TEST:*");
|
||||
assertNoMatch("*:ActiveMQ*", "topic:TEST:*");
|
||||
assertMatch("topic:ActiveMQ.Advisory*", "topic:ActiveMQ.Advisory.Connection:create");
|
||||
assertMatch("foo?ar", "foobar");
|
||||
}
|
||||
|
||||
protected static void assertMatch(String pattern, String value) {
|
||||
assertTrue(matches(pattern, value));
|
||||
}
|
||||
|
||||
protected static void assertNoMatch(String pattern, String value) {
|
||||
assertFalse(matches(pattern, value));
|
||||
}
|
||||
|
||||
protected static boolean matches(String pattern, String value) {
|
||||
ActiveMQWildcardPermission patternPerm = new ActiveMQWildcardPermission(pattern);
|
||||
WildcardPermission valuePerm = new WildcardPermission(value, true);
|
||||
return patternPerm.implies(valuePerm);
|
||||
}
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testGetPartsByReflectionThrowingException() {
|
||||
|
||||
ActiveMQWildcardPermission perm = new ActiveMQWildcardPermission("foo:bar") {
|
||||
@Override
|
||||
protected List<Set<String>> doGetPartsByReflection(WildcardPermission wp) throws Exception {
|
||||
throw new RuntimeException("Testing failure");
|
||||
}
|
||||
};
|
||||
|
||||
WildcardPermission otherPerm = new WildcardPermission("foo:bar:baz");
|
||||
|
||||
perm.implies(otherPerm);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testImpliesWithExtraParts() {
|
||||
ActiveMQWildcardPermission perm1 = new ActiveMQWildcardPermission("foo:bar:baz");
|
||||
ActiveMQWildcardPermission perm2 = new ActiveMQWildcardPermission("foo:bar");
|
||||
assertFalse(perm1.implies(perm2));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,364 @@
|
|||
/**
|
||||
* 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.StubBroker;
|
||||
import org.apache.activemq.command.ActiveMQDestination;
|
||||
import org.apache.activemq.command.ActiveMQTextMessage;
|
||||
import org.apache.activemq.command.ActiveMQTopic;
|
||||
import org.apache.activemq.command.ConnectionInfo;
|
||||
import org.apache.activemq.command.ConsumerInfo;
|
||||
import org.apache.activemq.command.DestinationInfo;
|
||||
import org.apache.activemq.command.ProducerInfo;
|
||||
import org.apache.activemq.shiro.subject.SubjectAdapter;
|
||||
import org.apache.activemq.shiro.subject.SubjectConnectionReference;
|
||||
import org.apache.activemq.shiro.subject.SubjectSecurityContext;
|
||||
import org.apache.shiro.authz.Permission;
|
||||
import org.apache.shiro.authz.UnauthorizedException;
|
||||
import org.apache.shiro.env.Environment;
|
||||
import org.apache.shiro.subject.PrincipalCollection;
|
||||
import org.apache.shiro.subject.SimplePrincipalCollection;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class AuthorizationFilterTest {
|
||||
|
||||
private AuthorizationFilter filter;
|
||||
private StubBroker nextBroker;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
filter = new AuthorizationFilter();
|
||||
nextBroker = new StubBroker();
|
||||
filter.setNext(nextBroker);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaults() {
|
||||
ActionPermissionResolver resolver = filter.getActionPermissionResolver();
|
||||
assertNotNull(resolver);
|
||||
assertTrue(resolver instanceof DestinationActionPermissionResolver);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetActionPermissionResolver() {
|
||||
ActionPermissionResolver resolver = new DestinationActionPermissionResolver();
|
||||
filter.setActionPermissionResolver(resolver);
|
||||
assertSame(resolver, filter.getActionPermissionResolver());
|
||||
}
|
||||
|
||||
private ConnectionContext createContext(Subject subject) {
|
||||
ConnectionContext ctx = new ConnectionContext();
|
||||
ConnectionInfo info = new ConnectionInfo();
|
||||
Environment environment = new Environment() {
|
||||
@Override
|
||||
public org.apache.shiro.mgt.SecurityManager getSecurityManager() {
|
||||
return null; //not needed in this test.
|
||||
}
|
||||
};
|
||||
SubjectConnectionReference ref = new SubjectConnectionReference(ctx, info, environment, subject);
|
||||
SubjectSecurityContext secCtx = new SubjectSecurityContext(ref);
|
||||
ctx.setSecurityContext(secCtx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubjectToString() {
|
||||
Subject subject = new PermsSubject() {
|
||||
@Override
|
||||
public PrincipalCollection getPrincipals() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
String string = filter.toString(subject);
|
||||
assertEquals("", string);
|
||||
}
|
||||
|
||||
@Test(expected=UnauthorizedException.class)
|
||||
public void testAddDestinationInfoNotAuthorized() throws Exception {
|
||||
String name = "myTopic";
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
DestinationInfo info = new DestinationInfo(null, DestinationInfo.ADD_OPERATION_TYPE, dest);
|
||||
|
||||
Subject subject = new PermsSubject();
|
||||
ConnectionContext context = createContext(subject);
|
||||
|
||||
filter.addDestinationInfo(context, info);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDestinationInfoAuthorized() throws Exception {
|
||||
|
||||
String name = "myTopic";
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
DestinationInfo info = new DestinationInfo(null, DestinationInfo.ADD_OPERATION_TYPE, dest);
|
||||
|
||||
Subject subject = new PermsSubject() {
|
||||
@Override
|
||||
public boolean isPermitted(Permission toCheck) {
|
||||
Permission assigned = createPerm("topic:myTopic:create");
|
||||
assertEquals(assigned.toString(), toCheck.toString());
|
||||
return assigned.implies(toCheck);
|
||||
}
|
||||
};
|
||||
|
||||
ConnectionContext context = createContext(subject);
|
||||
|
||||
filter.addDestinationInfo(context, info);
|
||||
}
|
||||
|
||||
@Test(expected=UnauthorizedException.class)
|
||||
public void testAddDestinationNotAuthorized() throws Exception {
|
||||
String name = "myTopic";
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
|
||||
Subject subject = new PermsSubject();
|
||||
ConnectionContext context = createContext(subject);
|
||||
|
||||
filter.addDestination(context, dest, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddDestinationAuthorized() throws Exception {
|
||||
String name = "myTopic";
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
|
||||
Subject subject = new PermsSubject() {
|
||||
@Override
|
||||
public boolean isPermitted(Permission toCheck) {
|
||||
Permission assigned = createPerm("topic:myTopic:create");
|
||||
assertEquals(assigned.toString(), toCheck.toString());
|
||||
return assigned.implies(toCheck);
|
||||
}
|
||||
};
|
||||
|
||||
ConnectionContext context = createContext(subject);
|
||||
|
||||
filter.addDestination(context, dest, true);
|
||||
}
|
||||
|
||||
@Test(expected=UnauthorizedException.class)
|
||||
public void testRemoveDestinationInfoNotAuthorized() throws Exception {
|
||||
String name = "myTopic";
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
DestinationInfo info = new DestinationInfo(null, DestinationInfo.REMOVE_OPERATION_TYPE, dest);
|
||||
|
||||
Subject subject = new PermsSubject();
|
||||
ConnectionContext context = createContext(subject);
|
||||
|
||||
filter.removeDestinationInfo(context, info);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveDestinationInfoAuthorized() throws Exception {
|
||||
|
||||
String name = "myTopic";
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
DestinationInfo info = new DestinationInfo(null, DestinationInfo.REMOVE_OPERATION_TYPE, dest);
|
||||
|
||||
Subject subject = new PermsSubject() {
|
||||
@Override
|
||||
public boolean isPermitted(Permission toCheck) {
|
||||
Permission assigned = createPerm("topic:myTopic:remove");
|
||||
assertEquals(assigned.toString(), toCheck.toString());
|
||||
return assigned.implies(toCheck);
|
||||
}
|
||||
};
|
||||
|
||||
ConnectionContext context = createContext(subject);
|
||||
|
||||
filter.removeDestinationInfo(context, info);
|
||||
}
|
||||
|
||||
@Test(expected=UnauthorizedException.class)
|
||||
public void testRemoveDestinationNotAuthorized() throws Exception {
|
||||
String name = "myTopic";
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
|
||||
Subject subject = new PermsSubject();
|
||||
ConnectionContext context = createContext(subject);
|
||||
|
||||
filter.removeDestination(context, dest, 1000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRemoveDestinationAuthorized() throws Exception {
|
||||
String name = "myTopic";
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
|
||||
Subject subject = new PermsSubject() {
|
||||
@Override
|
||||
public boolean isPermitted(Permission toCheck) {
|
||||
Permission assigned = createPerm("topic:myTopic:remove");
|
||||
assertEquals(assigned.toString(), toCheck.toString());
|
||||
return assigned.implies(toCheck);
|
||||
}
|
||||
};
|
||||
|
||||
ConnectionContext context = createContext(subject);
|
||||
|
||||
filter.removeDestination(context, dest, 1000);
|
||||
}
|
||||
|
||||
@Test(expected=UnauthorizedException.class)
|
||||
public void testAddConsumerNotAuthorized() throws Exception {
|
||||
String name = "myTopic";
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
|
||||
Subject subject = new PermsSubject();
|
||||
ConnectionContext context = createContext(subject);
|
||||
ConsumerInfo info = new ConsumerInfo(null);
|
||||
info.setDestination(dest);
|
||||
|
||||
filter.addConsumer(context, info);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddConsumerAuthorized() throws Exception {
|
||||
String name = "myTopic";
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
|
||||
Subject subject = new PermsSubject() {
|
||||
@Override
|
||||
public boolean isPermitted(Permission toCheck) {
|
||||
Permission assigned = createPerm("topic:myTopic:read");
|
||||
assertEquals(assigned.toString(), toCheck.toString());
|
||||
return assigned.implies(toCheck);
|
||||
}
|
||||
};
|
||||
|
||||
ConnectionContext context = createContext(subject);
|
||||
ConsumerInfo info = new ConsumerInfo(null);
|
||||
info.setDestination(dest);
|
||||
|
||||
filter.addConsumer(context, info);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddProducerWithoutDestination() throws Exception {
|
||||
Subject subject = new PermsSubject();
|
||||
ConnectionContext context = createContext(subject);
|
||||
ProducerInfo info = new ProducerInfo(null);
|
||||
filter.addProducer(context, info);
|
||||
}
|
||||
|
||||
@Test(expected=UnauthorizedException.class)
|
||||
public void testAddProducerNotAuthorized() throws Exception {
|
||||
String name = "myTopic";
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
|
||||
Subject subject = new PermsSubject();
|
||||
ConnectionContext context = createContext(subject);
|
||||
ProducerInfo info = new ProducerInfo(null);
|
||||
info.setDestination(dest);
|
||||
|
||||
filter.addProducer(context, info);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddProducerAuthorized() throws Exception {
|
||||
String name = "myTopic";
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
|
||||
Subject subject = new PermsSubject() {
|
||||
@Override
|
||||
public boolean isPermitted(Permission toCheck) {
|
||||
Permission assigned = createPerm("topic:myTopic:write");
|
||||
assertEquals(assigned.toString(), toCheck.toString());
|
||||
return assigned.implies(toCheck);
|
||||
}
|
||||
};
|
||||
|
||||
ConnectionContext context = createContext(subject);
|
||||
ProducerInfo info = new ProducerInfo(null);
|
||||
info.setDestination(dest);
|
||||
|
||||
filter.addProducer(context, info);
|
||||
}
|
||||
|
||||
@Test(expected=UnauthorizedException.class)
|
||||
public void testBrokerExchangeSendNotAuthorized() throws Exception {
|
||||
String name = "myTopic";
|
||||
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
ActiveMQTextMessage message = new ActiveMQTextMessage();
|
||||
message.setDestination(dest);
|
||||
message.setText("Hello, world!");
|
||||
|
||||
Subject subject = new PermsSubject();
|
||||
ConnectionContext context = createContext(subject);
|
||||
ProducerBrokerExchange exchange = new ProducerBrokerExchange();
|
||||
exchange.setConnectionContext(context);
|
||||
|
||||
filter.send(exchange, message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBrokerExchangeSendAuthorized() throws Exception {
|
||||
String name = "myTopic";
|
||||
ActiveMQDestination dest = new ActiveMQTopic(name);
|
||||
ActiveMQTextMessage message = new ActiveMQTextMessage();
|
||||
message.setDestination(dest);
|
||||
message.setText("Hello, world!");
|
||||
|
||||
Subject subject = new PermsSubject() {
|
||||
@Override
|
||||
public boolean isPermitted(Permission toCheck) {
|
||||
Permission assigned = createPerm("topic:myTopic:write");
|
||||
assertEquals(assigned.toString(), toCheck.toString());
|
||||
return assigned.implies(toCheck);
|
||||
}
|
||||
};
|
||||
|
||||
ConnectionContext context = createContext(subject);
|
||||
ProducerBrokerExchange exchange = new ProducerBrokerExchange();
|
||||
exchange.setConnectionContext(context);
|
||||
|
||||
filter.send(exchange, message);
|
||||
}
|
||||
|
||||
|
||||
protected Permission createPerm(String perm) {
|
||||
return new DestinationActionPermissionResolver().createPermission(perm);
|
||||
}
|
||||
|
||||
|
||||
private static class PermsSubject extends SubjectAdapter {
|
||||
|
||||
@Override
|
||||
public PrincipalCollection getPrincipals() {
|
||||
return new SimplePrincipalCollection("foo", "someRealm");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermittedAll(Collection<Permission> permissions) {
|
||||
assertNotNull(permissions);
|
||||
assertEquals(1, permissions.size());
|
||||
return isPermitted(permissions.iterator().next());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
/**
|
||||
* 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.command.ActiveMQDestination;
|
||||
import org.apache.activemq.command.ActiveMQQueue;
|
||||
import org.apache.activemq.command.ActiveMQTempQueue;
|
||||
import org.apache.activemq.command.ActiveMQTempTopic;
|
||||
import org.apache.activemq.command.ActiveMQTopic;
|
||||
import org.apache.activemq.filter.AnyDestination;
|
||||
import org.apache.shiro.authz.Permission;
|
||||
import org.apache.shiro.authz.permission.WildcardPermission;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class DestinationActionPermissionResolverTest {
|
||||
|
||||
private DestinationActionPermissionResolver resolver;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.resolver = new DestinationActionPermissionResolver();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaults() {
|
||||
assertNull(resolver.getPermissionStringPrefix());
|
||||
//default is true to reflect ActiveMQ's case-sensitive destination names:
|
||||
assertTrue(resolver.isPermissionStringCaseSensitive());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPermissionStringPrefixProp() {
|
||||
String prefix = "foo";
|
||||
resolver.setPermissionStringPrefix(prefix);
|
||||
assertEquals(prefix, resolver.getPermissionStringPrefix());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCaseSensitiveProp() {
|
||||
resolver.setPermissionStringCaseSensitive(true);
|
||||
assertTrue(resolver.isPermissionStringCaseSensitive());
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testGetPermissionsWithNonDestinationActionInstance() {
|
||||
resolver.getPermissions(new Action() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "foo";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testGetPermissionsWithNullArgument() {
|
||||
resolver.getPermissions((Action)null);
|
||||
}
|
||||
|
||||
void assertPermString(String perm, Collection<Permission> perms) {
|
||||
assertEquals(1, perms.size());
|
||||
assertEquals(perm, perms.iterator().next().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPermissionsWithTopic() {
|
||||
ActiveMQTopic topic = new ActiveMQTopic("myTopic");
|
||||
DestinationAction action = new DestinationAction(new ConnectionContext(), topic, "create");
|
||||
Collection<Permission> perms = resolver.getPermissions(action);
|
||||
assertPermString("topic:myTopic:create", perms);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPermissionsWithTemporaryTopic() {
|
||||
ActiveMQTempTopic topic = new ActiveMQTempTopic("myTempTopic");
|
||||
DestinationAction action = new DestinationAction(new ConnectionContext(), topic, "remove");
|
||||
Collection<Permission> perms = resolver.getPermissions(action);
|
||||
assertPermString("temp-topic:myTempTopic:remove", perms);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPermissionsWithQueue() {
|
||||
ActiveMQQueue queue = new ActiveMQQueue("myQueue");
|
||||
DestinationAction action = new DestinationAction(new ConnectionContext(), queue, "write");
|
||||
Collection<Permission> perms = resolver.getPermissions(action);
|
||||
assertPermString("queue:myQueue:write", perms);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPermissionsWithTemporaryQueue() {
|
||||
ActiveMQTempQueue queue = new ActiveMQTempQueue("myTempQueue");
|
||||
DestinationAction action = new DestinationAction(new ConnectionContext(), queue, "read");
|
||||
Collection<Permission> perms = resolver.getPermissions(action);
|
||||
assertPermString("temp-queue:myTempQueue:read", perms);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPermissionWithPrefix() {
|
||||
resolver.setPermissionStringPrefix("activeMQ");
|
||||
ActiveMQTopic topic = new ActiveMQTopic("myTopic");
|
||||
DestinationAction action = new DestinationAction(new ConnectionContext(), topic, "create");
|
||||
Collection<Permission> perms = resolver.getPermissions(action);
|
||||
assertPermString("activeMQ:topic:myTopic:create", perms);
|
||||
}
|
||||
|
||||
//Ensures if they explicitly set a prefix with a colon suffix that we don't add another one
|
||||
@Test
|
||||
public void testPermissionWithPrefixAndExplicitColon() {
|
||||
resolver.setPermissionStringPrefix("activeMQ:");
|
||||
ActiveMQTopic topic = new ActiveMQTopic("myTopic");
|
||||
DestinationAction action = new DestinationAction(new ConnectionContext(), topic, "create");
|
||||
Collection<Permission> perms = resolver.getPermissions(action);
|
||||
assertPermString("activeMQ:topic:myTopic:create", perms);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAlternateWildcardPermissionToStringWithMultipleActions() {
|
||||
Permission perm = resolver.createPermission("foo:bar:action1,action2");
|
||||
assertTrue(perm instanceof WildcardPermission);
|
||||
assertEquals("foo:bar:action1,action2", perm.toString());
|
||||
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testCreatePermissionStringWithCompositeDestination() {
|
||||
ActiveMQTopic topicA = new ActiveMQTopic("A");
|
||||
ActiveMQTopic topicB = new ActiveMQTopic("B");
|
||||
ActiveMQDestination composite = new AnyDestination(new ActiveMQDestination[]{topicA, topicB});
|
||||
resolver.createPermissionString(composite, "read");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* 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.command.ActiveMQQueue;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class DestinationActionTest {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testNullConnectionContext() {
|
||||
new DestinationAction(null, new ActiveMQQueue("foo"), "create");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testNullDestination() {
|
||||
new DestinationAction(new ConnectionContext(), null, "create");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testNullVerb() {
|
||||
new DestinationAction(new ConnectionContext(), new ActiveMQQueue("foo"), null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefault() {
|
||||
ConnectionContext ctx = new ConnectionContext();
|
||||
ActiveMQQueue queue = new ActiveMQQueue("foo");
|
||||
String verb = "create";
|
||||
|
||||
DestinationAction action = new DestinationAction(ctx, queue, verb);
|
||||
assertSame(ctx, action.getConnectionContext());
|
||||
assertSame(queue, action.getDestination());
|
||||
assertEquals(verb, action.getVerb());
|
||||
assertEquals("create destination: queue://foo", action.toString());
|
||||
}
|
||||
|
||||
}
|
30
activemq-shiro/src/test/java/org/apache/activemq/shiro/env/EnvironmentFilterTest.java
vendored
Normal file
30
activemq-shiro/src/test/java/org/apache/activemq/shiro/env/EnvironmentFilterTest.java
vendored
Normal file
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* 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.env;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class EnvironmentFilterTest {
|
||||
|
||||
@Test(expected=IllegalStateException.class)
|
||||
public void testNullEnvironment() {
|
||||
new EnvironmentFilter(){}.getEnvironment();
|
||||
}
|
||||
}
|
121
activemq-shiro/src/test/java/org/apache/activemq/shiro/env/IniEnvironmentTest.java
vendored
Normal file
121
activemq-shiro/src/test/java/org/apache/activemq/shiro/env/IniEnvironmentTest.java
vendored
Normal file
|
@ -0,0 +1,121 @@
|
|||
/**
|
||||
* 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.env;
|
||||
|
||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||
import org.apache.shiro.config.ConfigurationException;
|
||||
import org.apache.shiro.config.Ini;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class IniEnvironmentTest {
|
||||
|
||||
IniEnvironment env;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
env = new IniEnvironment();
|
||||
}
|
||||
|
||||
protected void authenticate() {
|
||||
authenticate("foo", "bar");
|
||||
}
|
||||
|
||||
protected void authenticate(String username, String password) {
|
||||
Subject subject = new Subject.Builder(env.getSecurityManager()).buildSubject();
|
||||
subject.login(new UsernamePasswordToken(username, password));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIniInstanceConstructorArg() {
|
||||
Ini ini = new Ini();
|
||||
ini.addSection("users").put("foo", "bar");
|
||||
env = new IniEnvironment(ini);
|
||||
authenticate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStringConstructorArg() {
|
||||
String config =
|
||||
"[users]\n" +
|
||||
"foo = bar";
|
||||
|
||||
env = new IniEnvironment(config);
|
||||
authenticate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetIni() {
|
||||
Ini ini = new Ini();
|
||||
ini.addSection("users").put("foo", "bar");
|
||||
|
||||
env = new IniEnvironment();
|
||||
env.setIni(ini);
|
||||
env.init();
|
||||
|
||||
authenticate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetIniString() {
|
||||
String config =
|
||||
"[users]\n" +
|
||||
"foo = bar";
|
||||
|
||||
env = new IniEnvironment();
|
||||
env.setIniConfig(config);
|
||||
env.init();
|
||||
|
||||
authenticate();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetIniResourcePath() {
|
||||
env = new IniEnvironment();
|
||||
env.setIniResourcePath("classpath:minimal.shiro.ini");
|
||||
env.init();
|
||||
|
||||
authenticate("system", "manager");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultClasspathIni() {
|
||||
env = new IniEnvironment();
|
||||
env.init();
|
||||
|
||||
authenticate("system", "manager");
|
||||
}
|
||||
|
||||
@Test(expected = ConfigurationException.class)
|
||||
public void testNoDefaultClasspathIni() {
|
||||
env = new IniEnvironment() {
|
||||
@Override
|
||||
protected void apply(Ini ini) {
|
||||
super.apply(ini);
|
||||
//clear out the objects to simulate as if the ini file wasn't found:
|
||||
this.objects.clear();
|
||||
}
|
||||
};
|
||||
env.init();
|
||||
authenticate("system", "manager");
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* 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.session.mgt;
|
||||
|
||||
import org.apache.shiro.session.mgt.DefaultSessionKey;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class DisabledSessionManagerTest {
|
||||
|
||||
private DisabledSessionManager mgr;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.mgr = new DisabledSessionManager();
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testStart() {
|
||||
mgr.start(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetSession() {
|
||||
assertNull(mgr.getSession(null));
|
||||
assertNull(mgr.getSession(new DefaultSessionKey("foo")));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/**
|
||||
* 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.subject;
|
||||
|
||||
import org.apache.activemq.broker.ConnectionContext;
|
||||
import org.apache.activemq.command.ConnectionInfo;
|
||||
import org.apache.activemq.security.SecurityContext;
|
||||
import org.apache.shiro.env.DefaultEnvironment;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.security.Principal;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class ConnectionSubjectResolverTest {
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testNullConstructorArg() {
|
||||
new ConnectionSubjectResolver((ConnectionContext)null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testNullSecurityContext() {
|
||||
SubjectConnectionReference reference =
|
||||
new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
|
||||
new DefaultEnvironment(), new SubjectAdapter());
|
||||
|
||||
new ConnectionSubjectResolver(reference);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void testNonSubjectSecurityContext() {
|
||||
SubjectConnectionReference reference =
|
||||
new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
|
||||
new DefaultEnvironment(), new SubjectAdapter());
|
||||
reference.getConnectionContext().setSecurityContext(new SecurityContext("") {
|
||||
@Override
|
||||
public Set<Principal> getPrincipals() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
new ConnectionSubjectResolver(reference);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testNullSubject() {
|
||||
|
||||
SubjectConnectionReference reference =
|
||||
new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
|
||||
new DefaultEnvironment(), new SubjectAdapter());
|
||||
reference.getConnectionContext().setSecurityContext(new SubjectSecurityContext(reference) {
|
||||
@Override
|
||||
public Subject getSubject() {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
ConnectionSubjectResolver resolver = new ConnectionSubjectResolver(reference);
|
||||
resolver.getSubject();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* 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.subject;
|
||||
|
||||
import org.apache.activemq.shiro.ConnectionReference;
|
||||
import org.apache.activemq.shiro.authc.AuthenticationPolicy;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class DefaultConnectionSubjectFactoryTest {
|
||||
|
||||
private DefaultConnectionSubjectFactory factory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.factory = new DefaultConnectionSubjectFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetAuthenticationPolicy() {
|
||||
AuthenticationPolicy policy = new AuthenticationPolicy() {
|
||||
@Override
|
||||
public void customizeSubject(Subject.Builder subjectBuilder, ConnectionReference ref) {
|
||||
//To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthenticationRequired(SubjectConnectionReference ref) {
|
||||
return false; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
};
|
||||
factory.setAuthenticationPolicy(policy);
|
||||
assertSame(policy, factory.getAuthenticationPolicy());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
/**
|
||||
* 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.subject;
|
||||
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.apache.shiro.authz.Permission;
|
||||
import org.apache.shiro.session.Session;
|
||||
import org.apache.shiro.subject.ExecutionException;
|
||||
import org.apache.shiro.subject.PrincipalCollection;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class SubjectAdapter implements Subject {
|
||||
|
||||
@Override
|
||||
public Object getPrincipal() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrincipalCollection getPrincipals() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermitted(String permission) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermitted(Permission permission) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean[] isPermitted(String... permissions) {
|
||||
return new boolean[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean[] isPermitted(List<Permission> permissions) {
|
||||
return new boolean[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermittedAll(String... permissions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPermittedAll(Collection<Permission> permissions) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkPermission(String permission) throws AuthorizationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkPermission(Permission permission) throws AuthorizationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkPermissions(String... permissions) throws AuthorizationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkPermissions(Collection<Permission> permissions) throws AuthorizationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRole(String roleIdentifier) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean[] hasRoles(List<String> roleIdentifiers) {
|
||||
return new boolean[0]; //To change body of implemented methods use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAllRoles(Collection<String> roleIdentifiers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkRole(String roleIdentifier) throws AuthorizationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkRoles(Collection<String> roleIdentifiers) throws AuthorizationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkRoles(String... roleIdentifiers) throws AuthorizationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void login(AuthenticationToken token) throws AuthenticationException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAuthenticated() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRemembered() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Session getSession() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Session getSession(boolean create) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void logout() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> V execute(Callable<V> callable) throws ExecutionException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(Runnable runnable) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V> Callable<V> associateWith(Callable<V> callable) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable associateWith(Runnable runnable) {
|
||||
return runnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runAs(PrincipalCollection principals) throws NullPointerException, IllegalStateException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRunAs() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrincipalCollection getPreviousPrincipals() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrincipalCollection releaseRunAs() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* 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.subject;
|
||||
|
||||
import org.apache.activemq.broker.ConnectionContext;
|
||||
import org.apache.activemq.command.ConnectionInfo;
|
||||
import org.apache.shiro.env.DefaultEnvironment;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class SubjectConnectionReferenceTest {
|
||||
|
||||
@Test(expected=IllegalArgumentException.class)
|
||||
public void testNullSubject() {
|
||||
new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(), new DefaultEnvironment(), null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* 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.subject;
|
||||
|
||||
import org.apache.activemq.security.SecurityContext;
|
||||
import org.apache.activemq.shiro.SecurityContextFactory;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class SubjectFilterTest {
|
||||
|
||||
private SubjectFilter filter;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
filter = new SubjectFilter();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void setNullSubjectConnectionFactory() {
|
||||
filter.setConnectionSubjectFactory(null);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void setNullSecurityContextFactory() {
|
||||
filter.setSecurityContextFactory(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSecurityContextFactory() {
|
||||
SecurityContextFactory factory = new SecurityContextFactory() {
|
||||
@Override
|
||||
public SecurityContext createSecurityContext(SubjectConnectionReference ref) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
filter.setSecurityContextFactory(factory);
|
||||
assertSame(factory, filter.getSecurityContextFactory());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* 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.subject;
|
||||
|
||||
import org.apache.activemq.broker.ConnectionContext;
|
||||
import org.apache.activemq.command.ConnectionInfo;
|
||||
import org.apache.shiro.env.DefaultEnvironment;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @since 5.10.0
|
||||
*/
|
||||
public class SubjectSecurityContextTest {
|
||||
|
||||
SubjectSecurityContext ctx;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
SubjectConnectionReference conn = new SubjectConnectionReference(new ConnectionContext(), new ConnectionInfo(),
|
||||
new DefaultEnvironment(), new SubjectAdapter());
|
||||
ctx = new SubjectSecurityContext(conn);
|
||||
}
|
||||
|
||||
@Test(expected=UnsupportedOperationException.class)
|
||||
public void testInOneOf() {
|
||||
ctx.isInOneOf(null);
|
||||
}
|
||||
|
||||
@Test(expected=UnsupportedOperationException.class)
|
||||
public void testGetAuthorizedReadDests() {
|
||||
ctx.getAuthorizedReadDests();
|
||||
}
|
||||
|
||||
@Test(expected=UnsupportedOperationException.class)
|
||||
public void testGetAuthorizedWriteDests() {
|
||||
ctx.getAuthorizedWriteDests();
|
||||
}
|
||||
|
||||
@Test(expected=UnsupportedOperationException.class)
|
||||
public void testGetPrincipals() {
|
||||
ctx.getPrincipals();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
# This empty file will cause an error at Shiro startup (as expected). Used for testing purposes only.
|
|
@ -0,0 +1,63 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
[main]
|
||||
|
||||
# Shiro object graph configuration here if desired/necessary
|
||||
|
||||
[users]
|
||||
|
||||
# users section format:
|
||||
#
|
||||
# username = password [, assignedRole1, assignedRole2, ..., assignedRoleN]
|
||||
#
|
||||
# for example:
|
||||
#
|
||||
# scott = tiger, users, administrators, advisory
|
||||
#
|
||||
# Roles and permissions assigned to roles are defined in the [roles] section
|
||||
# below. By transitive association, any user assigned a role is granted the
|
||||
# role's permissions.
|
||||
|
||||
# ActiveMQ System User
|
||||
# needed for in-VM/local connections when authentication is enabled:
|
||||
system = manager, system
|
||||
|
||||
[roles]
|
||||
|
||||
# roles section format:
|
||||
#
|
||||
# roleName = wildcardPermission1, wildcardPermission2, ..., wildcardPermissionN
|
||||
|
||||
# The 'system' role is assigned all permissions (*). Be careful when assigning
|
||||
# this to actual users other than then system user!
|
||||
system = *
|
||||
|
||||
# Full access rights should generally be given to the ActiveMQ.Advisory.*
|
||||
# destinations because by default an ActiveMQConnection uses advisory topics to
|
||||
# get early knowledge of temp destination creation and deletion. For more info:
|
||||
#
|
||||
# http://activemq.apache.org/security.html
|
||||
#
|
||||
# So we create an 'advisory' role here with a wildcard/catch-all permissions
|
||||
# for all advisory topics. To make your life easy, ensure you assign this to
|
||||
# any/all users, e.g.
|
||||
#
|
||||
# jsmith = password, advisory, ...
|
||||
|
||||
advisory = topic:ActiveMQ.Advisory*
|
|
@ -0,0 +1,38 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
[main]
|
||||
|
||||
# THIS IS USED FOR TESTING PURPOSES ONLY. DO NOT BASE YOUR CONFIGURATION OFF OF THIS FILE.
|
||||
|
||||
# Shiro object graph configuration here if desired/necessary
|
||||
|
||||
[users]
|
||||
# username is purposefully different than the system username:
|
||||
foo = bar, foo, advisory
|
||||
|
||||
[roles]
|
||||
# Full access rights should generally be given to the ActiveMQ.Advisory.* destinations because by default an
|
||||
# ActiveMQConnection uses advisory topics to get early knowledge of temp destination creation and deletion.
|
||||
# See http://activemq.apache.org/security.html for more.
|
||||
#
|
||||
# So we create an 'advisory' role here with a wildcard/catch-all permissions for all advisory topics:
|
||||
advisory = topic:ActiveMQ.Advisory*
|
||||
|
||||
# test specific roles/perms:
|
||||
foo = queue:QUEUE.org.apache.activemq.shiro.ShiroPluginTest.testRuntimeDisableEnableChanges:*
|
|
@ -0,0 +1,95 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<!-- this file can only be parsed using the xbean-spring library -->
|
||||
<!-- START SNIPPET: example -->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:amq="http://activemq.apache.org/schema/core"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
|
||||
|
||||
<broker xmlns="http://activemq.apache.org/schema/core"
|
||||
useJmx="false" persistent="false" populateJMSXUserID="true">
|
||||
|
||||
<destinations>
|
||||
<queue physicalName="TEST.Q"/>
|
||||
</destinations>
|
||||
|
||||
<transportConnectors>
|
||||
<transportConnector name="default" uri="tcp://0.0.0.0:61616"/>
|
||||
</transportConnectors>
|
||||
|
||||
<plugins>
|
||||
<bean id="shiroPlugin"
|
||||
class="org.apache.activemq.shiro.ShiroPlugin"
|
||||
xmlns="http://www.springframework.org/schema/beans">
|
||||
<property name="iniConfig">
|
||||
<value>
|
||||
[main]
|
||||
|
||||
# Shiro object graph configuration here if desired/necessary
|
||||
|
||||
[users]
|
||||
|
||||
# users section format:
|
||||
#
|
||||
# username = password [, assignedRole1, assignedRole2, ..., assignedRoleN]
|
||||
#
|
||||
# for example:
|
||||
#
|
||||
# scott = tiger, users, administrators, advisory
|
||||
#
|
||||
# Roles and permissions assigned to roles are defined in the [roles] section
|
||||
# below. By transitive association, any user assigned a role is granted the
|
||||
# role's permissions.
|
||||
|
||||
# ActiveMQ System User
|
||||
# needed for in-VM/local connections when authentication is enabled:
|
||||
system = manager, system
|
||||
|
||||
[roles]
|
||||
|
||||
# roles section format:
|
||||
#
|
||||
# roleName = wildcardPermission1, wildcardPermission2, ..., wildcardPermissionN
|
||||
|
||||
# The 'system' role is assigned all permissions (*). Be careful when assigning
|
||||
# this to actual users other than then system user:
|
||||
system = *
|
||||
|
||||
# Full access rights should generally be given to the ActiveMQ.Advisory.*
|
||||
# destinations because by default an ActiveMQConnection uses advisory topics to
|
||||
# get early knowledge of temp destination creation and deletion. For more info:
|
||||
#
|
||||
# http://activemq.apache.org/security.html
|
||||
#
|
||||
# So we create an 'advisory' role here with a wildcard/catch-all permissions
|
||||
# for all advisory topics. To make your life easy, ensure you assign this to
|
||||
# any/all users, e.g.
|
||||
#
|
||||
# jsmith = password, advisory, ...
|
||||
|
||||
advisory = topic:ActiveMQ.Advisory*
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
</plugins>
|
||||
</broker>
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,53 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<!-- this file can only be parsed using the xbean-spring library -->
|
||||
<!-- START SNIPPET: example -->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:amq="http://activemq.apache.org/schema/core"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
|
||||
|
||||
<broker xmlns="http://activemq.apache.org/schema/core"
|
||||
useJmx="false" persistent="false" populateJMSXUserID="true">
|
||||
|
||||
<destinations>
|
||||
<queue physicalName="TEST.Q"/>
|
||||
</destinations>
|
||||
|
||||
<transportConnectors>
|
||||
<transportConnector name="default" uri="tcp://0.0.0.0:61616"/>
|
||||
</transportConnectors>
|
||||
|
||||
<plugins>
|
||||
<bean id="shiroPlugin" class="org.apache.activemq.shiro.ShiroPlugin"
|
||||
xmlns="http://www.springframework.org/schema/beans">
|
||||
|
||||
<!-- Reference Shiro's ini config from an external path, e.g. classpath: -->
|
||||
<property name="iniResourcePath" value="classpath:org/apache/activemq/shiro/external-ini-config.xml"/>
|
||||
|
||||
<!-- or it could be in another location, such as a URL or file:
|
||||
<property name="iniResourcePath" value="url:http://config.somehost.com/mybroker/shiro.ini"/>
|
||||
<property name="iniResourcePath" value="file:/usr/local/somewhere/shiro.ini"/> -->
|
||||
</bean>
|
||||
</plugins>
|
||||
</broker>
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,78 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
|
||||
<!-- this file can only be parsed using the xbean-spring library -->
|
||||
<!-- START SNIPPET: example -->
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:amq="http://activemq.apache.org/schema/core"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://activemq.apache.org/schema/core http://activemq.apache.org/schema/core/activemq-core.xsd">
|
||||
|
||||
<broker xmlns="http://activemq.apache.org/schema/core"
|
||||
useJmx="false" persistent="false" populateJMSXUserID="true">
|
||||
|
||||
<destinations>
|
||||
<queue physicalName="TEST.Q"/>
|
||||
</destinations>
|
||||
|
||||
<transportConnectors>
|
||||
<transportConnector name="default" uri="tcp://0.0.0.0:61616"/>
|
||||
</transportConnectors>
|
||||
|
||||
<plugins>
|
||||
|
||||
<bean id="shiroPlugin" class="org.apache.activemq.shiro.ShiroPlugin"
|
||||
xmlns="http://www.springframework.org/schema/beans">
|
||||
<!-- This configuration doesn't rely on an INI file for config, and expects that Shiro is configured
|
||||
entirely within Spring. See the Shiro securityManager bean below. -->
|
||||
<property name="securityManager" ref="securityManager"/>
|
||||
</bean>
|
||||
|
||||
</plugins>
|
||||
</broker>
|
||||
|
||||
<bean id="securityManager" class="org.apache.shiro.mgt.DefaultSecurityManager">
|
||||
<!-- Do not use this cache manager in a clustered broker setup. If your broker is clustered, you should
|
||||
configure a cluster-aware CacheManager, e.g. Hazelcast, Terracotta+Ehcache, etc. -->
|
||||
<property name="cacheManager">
|
||||
<bean class="org.apache.shiro.cache.MemoryConstrainedCacheManager"/>
|
||||
</property>
|
||||
<property name="realms">
|
||||
<list>
|
||||
<!-- Replace this with the real realm you're going to use that accesses your security data store: -->
|
||||
<bean id="myRealm" class="org.apache.shiro.realm.text.TextConfigurationRealm">
|
||||
<property name="userDefinitions">
|
||||
<value>
|
||||
system = manager,system
|
||||
</value>
|
||||
</property>
|
||||
<property name="roleDefinitions">
|
||||
<value>
|
||||
system = *
|
||||
</value>
|
||||
</property>
|
||||
</bean>
|
||||
<!-- Add other realms if necessary -->
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
<bean class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
|
||||
|
||||
</beans>
|
|
@ -0,0 +1,64 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
[main]
|
||||
|
||||
# Shiro object graph configuration here if desired/necessary
|
||||
|
||||
[users]
|
||||
|
||||
# users section format:
|
||||
#
|
||||
# username = password [, assignedRole1, assignedRole2, ..., assignedRoleN]
|
||||
#
|
||||
# for example:
|
||||
#
|
||||
# scott = tiger, users, administrators, advisory
|
||||
#
|
||||
# Roles and permissions assigned to roles are defined in the [roles] section
|
||||
# below. By transitive association, any user assigned a role is granted the
|
||||
# role's permissions.
|
||||
|
||||
# ActiveMQ System User
|
||||
# needed for in-VM/local connections when authentication is enabled:
|
||||
system = manager, system
|
||||
|
||||
[roles]
|
||||
|
||||
# roles section format:
|
||||
#
|
||||
# roleName = wildcardPermission1, wildcardPermission2, ..., wildcardPermissionN
|
||||
|
||||
# The 'system' role is assigned all permissions (*). Be careful when assigning
|
||||
# this to actual users other than then system user:
|
||||
system = *
|
||||
|
||||
# Full access rights should generally be given to the ActiveMQ.Advisory.*
|
||||
# destinations because by default an ActiveMQConnection uses advisory topics to
|
||||
# get early knowledge of temp destination creation and deletion. For more info:
|
||||
#
|
||||
# http://activemq.apache.org/security.html
|
||||
#
|
||||
# So we create an 'advisory' role here with a wildcard/catch-all permissions
|
||||
# for all advisory topics. To make your life easy, ensure you assign this to
|
||||
# any/all users, e.g.
|
||||
#
|
||||
# jsmith = password, advisory, ...
|
||||
|
||||
advisory = topic:ActiveMQ.Advisory*
|
|
@ -175,6 +175,10 @@
|
|||
<artifactId>jaxb2-basics-runtime</artifactId>
|
||||
<version>${jaxb-basics-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>activemq-shiro</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>activemq-spring</artifactId>
|
||||
|
@ -285,6 +289,14 @@
|
|||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jta_1.0.1B_spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-spring</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.xbean</groupId>
|
||||
<artifactId>xbean-spring</artifactId>
|
||||
|
|
|
@ -172,6 +172,7 @@
|
|||
<include>${pom.groupId}:activemq-jms-pool</include>
|
||||
<include>${pom.groupId}:activemq-pool</include>
|
||||
<include>${pom.groupId}:activemq-partition</include>
|
||||
<include>${pom.groupId}:activemq-shiro</include>
|
||||
<include>${pom.groupId}:activeio-core</include>
|
||||
<include>commons-beanutils:commons-beanutils</include>
|
||||
<include>commons-collections:commons-collections</include>
|
||||
|
@ -223,7 +224,11 @@
|
|||
<include>org.linkedin:org.linkedin.zookeeper-impl</include>
|
||||
<include>org.linkedin:org.linkedin.util-core</include>
|
||||
<include>org.apache.zookeeper:zookeeper</include>
|
||||
|
||||
|
||||
<!-- Apache Shiro dependencies: -->
|
||||
<include>org.apache.shiro:shiro-core</include>
|
||||
<include>org.apache.shiro:shiro-spring</include>
|
||||
|
||||
</includes>
|
||||
</dependencySet>
|
||||
<dependencySet>
|
||||
|
|
36
pom.xml
36
pom.xml
|
@ -107,7 +107,9 @@
|
|||
<scala-plugin-version>3.1.0</scala-plugin-version>
|
||||
<scala-version>2.9.1</scala-version>
|
||||
<scala-bundle-version>2.9.1_3</scala-bundle-version>
|
||||
<shiro-version>1.2.2</shiro-version>
|
||||
<scalatest-version>1.8</scalatest-version>
|
||||
<shiro-version>1.2.2</shiro-version>
|
||||
<slf4j-version>1.7.5</slf4j-version>
|
||||
<snappy-version>1.1.0.1</snappy-version>
|
||||
<spring-version>3.2.5.RELEASE</spring-version>
|
||||
|
@ -244,6 +246,7 @@
|
|||
<module>activemq-ra</module>
|
||||
<module>activemq-rar</module>
|
||||
<module>activemq-run</module>
|
||||
<module>activemq-shiro</module>
|
||||
<module>activemq-spring</module>
|
||||
<module>activemq-runtime-config</module>
|
||||
<module>activemq-tooling</module>
|
||||
|
@ -384,6 +387,11 @@
|
|||
<artifactId>activemq-pool</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-shiro</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-spring</artifactId>
|
||||
|
@ -667,6 +675,34 @@
|
|||
<artifactId>openjpa-persistence-jdbc</artifactId>
|
||||
<version>${openjpa-version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Optional Shiro Support -->
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
<version>${shiro-version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-spring</artifactId>
|
||||
<version>${shiro-version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Optional Shiro Support -->
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
<version>${shiro-version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-spring</artifactId>
|
||||
<version>${shiro-version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Optional Spring Support -->
|
||||
<dependency>
|
||||
|
|
Loading…
Reference in New Issue