Shiro
ActiveMQ Classic 5.10 及更高版本通过使用 Apache Shiro 提供了完全可定制的安全体验。
ActiveMQ Classic Shiro 插件可以保护 ActiveMQ Classic 代理,从身份验证传输连接到授权主题和队列的行为,以及介于两者之间的所有内容。
快速入门
启用 ShiroPlugin 的最快/最简单的方法是在 broker
plugins
部分将其定义为 Spring bean,并将 Shiro ini 配置 嵌入其中。
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:amq="https://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
https://activemq.apache.org/schema/core https://activemq.apache.org/schema/core/activemq-core.xsd">
<broker xmlns="https://activemq.apache.org/schema/core" ... other attributes here ...>
<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, advisory, users, administrators
#
# 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 Classic System User
# needed for in-VM/local connections when authentication is enabled:
system = manager, system
# Other users here. You should almost always add the \`advisory\` role for each
# user to make your life easy! See the [roles] comments below for more info.
# jsmith = jsmithsPassword, advisory
# djones = djonesPassword, advisory, ...
# etc.
[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:
#
# https://activemq.apache.org/Features/security.md
#
# 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 in the [users] section above, e.g.
#
# jsmith = jsmithsPassword, advisory, ...
advisory = topic:ActiveMQ.Advisory*
</value></property>
</bean>
</plugins>
</broker>
</beans>
此配置假设您有一组简单/小的静态用户访问您的 ActiveMQ Classic 代理。我们将在后面介绍启用更高级的用户存储库。
加密密码
上面的示例使用明文密码,这对于设置和测试来说很简单,但并不真正安全。大多数生产部署可能希望使用加密密码。例如
<bean id="shiroPlugin" class="org.apache.activemq.shiro.ShiroPlugin" xmlns="http://www.springframework.org/schema/beans">
<!-- enabled by default. To disable, uncomment:
<property name="iniConfig"><value>
[main]
# Shiro object graph configuration here
passwordMatcher = org.apache.shiro.authc.credential.PasswordMatcher
iniRealm.credentialsMatcher = $passwordMatcher
[users]
scott = $shiro1$SHA-256$500000$eWpVX2tGX7WCP2J+jMCNqw==$it/NRclMOHrfOvhAEFZ0mxIZRdbcfqIBdwdwdDXW2dM=, advisory
system = $shiro1$SHA-256$500000$eUyGwMGr9GYzB/gg/MoNgw==$WGc0yWFWv8+hLqjzVLgW7Hat2FQTywDXBl5izpqaLSY=, system
[roles]
system = *
advisory = topic:ActiveMQ.Advisory*
</value></property>
</bean>
如您所见,有两件事与更简单/默认配置不同
- 在
[main]
部分,在隐式iniRealm
上配置了PasswordMatcher
。这表示所有.ini
配置的用户都应具有适当的哈希/安全密码。 [users]
行现在在password
位置具有哈希值,而不是明文值。
要获取哈希密码文本值,您需要从 Maven Central 下载 Shiro 的命令行哈希器。下载完成后,您可以使用它来创建安全的密码哈希,您可以安全地将其复制粘贴到 [users]
部分
$ java -jar shiro-tools-hasher-X.X.X-cli.jar -p
然后它会要求您输入密码,然后确认它
Password to hash:
Password to hash (confirm):
当此命令执行时,它将打印出安全盐化迭代和哈希的密码。例如
$shiro1$SHA-256$500000$eWpVX2tGX7WCP2J+jMCNqw==$it/NRclMOHrfOvhAEFZ0mxIZRdbcfqIBdwdwdDXW2dM=
获取此值,将其放在用户定义行中的密码位置(后跟任何所需的 roles,例如 advisory
role)。例如
[users]
scott = $shiro1$SHA-256$500000$eWpVX2tGX7WCP2J+jMCNqw==$it/NRclMOHrfOvhAEFZ0mxIZRdbcfqIBdwdwdDXW2dM=, advisory
system = $shiro1$SHA-256$500000$eUyGwMGr9GYzB/gg/MoNgw==$WGc0yWFWv8+hLqjzVLgW7Hat2FQTywDXBl5izpqaLSY=, system
配置
ActiveMQ Classic Shiro 插件可以通过多种方式进行配置。例如,使用 Java
BrokerService brokerService = new BrokerService();
ShiroPlugin shiroPlugin = new ShiroPlugin();
//configure shiroPlugin via getters/setters here
broker.setPlugins(new BrokerPlugin[]{shiroPlugin});
//continue configuring the brokerService as necessary ...
或者,如果使用传统的 ActiveMQ Classic xml,则作为 broker
plugins
部分中的 Spring bean。例如
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:amq="https://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
https://activemq.apache.org/schema/core https://activemq.apache.org/schema/core/activemq-core.xsd">
<broker xmlns="https://activemq.apache.org/schema/core" ... other attributes here ...>
<plugins>
<bean id="shiroPlugin" class="org.apache.activemq.shiro.ShiroPlugin" xmlns="http://www.springframework.org/schema/beans">
<!-- Config properties via getters/setters as necessary: -->
</bean>
</plugins>
</broker>
</beans>
本页上的其余配置示例将显示为 bean XML,但请注意,相同的配置可以通过 Java 作为标准的 JavaBeans 兼容的 getter 和 setter 方法来完成。
启用/禁用
您可以完全启用或禁用 ShiroPlugin,而无需将其从配置中删除。这在测试时很方便,或者当您想要根据启动时的配置参数启用或禁用它时。
<bean id="shiroPlugin" class="org.apache.activemq.shiro.ShiroPlugin" xmlns="http://www.springframework.org/schema/beans">
<!-- enabled by default. To disable, uncomment:
<property name="enabled" value="false"/> -->
</bean>
一个不错的技巧是使用 Spring 的 PropertySourcesPlaceholderConfigurer 和占位符标记(在您的其中一个占位符属性文件中设置 shiro.enabled = true
)
<beans ...>
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
...
</bean>
<broker ...>
<plugins ...>
<bean id="shiroPlugin" class="org.apache.activemq.shiro.ShiroPlugin" xmlns="http://www.springframework.org/schema/beans">
<property name="enabled" value="${shiro.enabled}"/>
</bean>
</plugins>
</broker>
</beans>
这允许您通过简单地在 .properties
文件中设置一个属性来启用或禁用 Shiro 插件,而无需更改您的 XML 配置。
Shiro 环境
shiroPlugin
需要一个 Shiro 环境 才能正常工作。您必须通过以下方式配置插件:
- 一个
Environment
实例(或一个 ShiroSecurityManager
实例),您可以在其他地方实例化和配置它 - 例如,在 Java 代码中或 Spring XML 配置中的其他地方,或者 - 指定一些 Shiro .ini 配置,无论是作为直接字符串、Ini 实例,还是作为 资源路径,其中您的
shiro.ini
文件位于。该插件将加载 ini 配置并自动创建一个Environment
。
自定义环境
Shiro Environment
对象包含 Shiro 运行所需的一切,这封装了 Shiro SecurityManager
。如果您想自己构建和配置 Environment 实例,请执行以下操作:
<beans ...>
<broker ...>
<plugins>
<bean id="shiroPlugin" class="org.apache.activemq.shiro.ShiroPlugin" xmlns="http://www.springframework.org/schema/beans">
<property name="environment" ref="shiroEnvironment"/>
</bean>
</plugins>
</broker>
<bean id="shiroEnvironment" class="..">
... config here ...
</bean>
<bean class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>
自定义 SecurityManager
您也可以构建一个 SecurityManager
,而不是配置一个 Environment
实例。
<beans ...>
<broker ...>
<plugins>
<bean id="shiroPlugin" class="org.apache.activemq.shiro.ShiroPlugin" xmlns="http://www.springframework.org/schema/beans">
<property name="securityManager" ref="shiroSecurityManager"/>
</bean>
</plugins>
</broker>
<bean id="shiroSecurityManager" class="org.apache.shiro.mgt.DefaultSecurityManager">
<property name="realms">
<list>
<bean id="myRealm" class="...">
...
</bean>
... maybe more Realm beans ...
</list>
</property>
</bean>
<bean class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
</beans>
如果指定 SecurityManager
而不是 Environment
属性,则会自动创建一个 Environment
,它将包装配置的 SecurityManager
。
shiro.ini 文件
如果您不想在代码或 xml 中构建 SecurityManager
或 Environment
,您可以轻松地指定一个 shiro.ini 文件,并且将根据该文件自动创建一个 Environment/SecurityManager。
<beans ...>
<broker ...>
<plugins>
<bean id="shiroPlugin" class="org.apache.activemq.shiro.ShiroPlugin" xmlns="http://www.springframework.org/schema/beans">
<property name="iniResourcePath" value="classpath:myshiro.ini"/>
</bean>
</plugins>
</broker>
</beans>
这允许您在需要时将 Shiro 配置与 ActiveMQ Classic 代理配置分开。
shiro.ini 嵌入
如果您想使用 ini 配置,并且希望将所有配置都放在一个地方,您可以将 ini 配置嵌入其中
<beans ...>
<broker ...>
<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]
system = manager, system
[roles]
system = *
advisory = topic:ActiveMQ.Advisory*
</value>
</property>
</bean>
</plugins>
</broker>
</beans>
设计
Shiro 插件是一个 BrokerPlugin,它在代理过滤器链中插入 3 个 BrokerFilter:SubjectFilter
、AuthenticationFilter
和 AuthorizationFilter
SubjectFilter
SubjectFilter
存在于代理过滤器链中所有其他 Shiro 相关代理过滤器之前。它构造一个 Shiro Subject 实例,反映代理客户端,并确保 Subject
实例可用于所有可能需要使用 Subject
执行安全操作的下游代理过滤器。
AuthenticationFilter
AuthenticationFilter
存在于代理过滤器链中 SubjectFilter
之后。它确保代理客户端 Subject
在允许链继续之前经过身份验证(如果需要)。如果需要身份验证且 Subject
未经身份验证,则不会执行代理过滤器链,从而确保只有经过验证的身份才能执行进一步的行为。
AuthorizationFilter
AuthorizationFilter
存在于代理过滤器链中 AuthenticationFilter
之后。它确保与过滤器链关联的 Subject
经过授权(允许)执行正在尝试的操作,然后才允许操作执行。
例如,它将确保 Subject
被允许向特定主题发送消息,然后才允许发送操作执行。如果授权已启用且 Subject
未被授权执行所需操作,则不会执行代理过滤器链。
SubjectFilter
ShiroPlugin 会在代理过滤器链中所有其他 Shiro 相关代理过滤器之前安装和执行 SubjectFilter
。该 SubjectFilter
会构造一个 Shiro Subject 实例,反映代理客户端,并确保 Subject
实例可用于所有可能需要使用 Subject
执行安全操作的下游代理过滤器。
SubjectFilter
主要是一个“幕后”组件,但它确实为高级用例提供了一些定制功能,例如:
- 通过
ConnectionSubjectFactory
自定义代理客户端Subject
实例的创建方式,以及 - 自定义 ActiveMQ Classic ConnectionContext 的 SecurityContext 的构建方式。
除非您非常熟悉 ActiveMQ Classic 的安全模型,否则您可以安全地跳过下面的**身份验证**部分。
ConnectionSubjectFactory
ConnectionSubjectFactory
创建一个 Subject
实例,它表示代理客户端的身份。该 SubjectFilter
的默认实例是 DefaultConnectionSubjectFactory
大多数 ConnectionSubjectFactory
实现将简单地使用 Shiro 的 Subject.Builder
来创建一个匿名 Subject 实例,并让下游的 AuthenticationFilter
根据与连接关联的任何凭据对 Subject 进行身份验证。身份验证后,Subject 将具有一个身份,这是大多数连接客户端的预期流程。
但是,如果连接中有一些其他数据可以被检查以创建 Subject 实例,而不仅仅是 DefaultConnectionSubjectFactory
,您可以实现 ConnectionSubjectFactory
接口,并将其插入到 SubjectFilter
中
<bean id="shiroPlugin" class="org.apache.activemq.shiro.ShiroPlugin" xmlns="http://www.springframework.org/schema/beans">
<property name="subjectFilter.connectionSubjectFactory">
<bean class="com.my.ConnectionSubjectFactory" .../>
</property>
</bean>
SecurityContextFactory
与代理客户端连接关联的 ActiveMQ Classic ConnectionContext
使用一个 SecurityContext
对象。当 SubjectFilter
执行时,它需要创建一个 Shiro 特定的 SecurityContext
并将其与 ConnectionContext
关联,以便可以在后续所有安全操作中访问 Subject。
SubjectFilter
将 SecurityContext
的创建委托给 SecurityContextFactory
实例。该 DefaultSecurityContextFactory
实现根据连接关联的 Subject
返回 SubjectSecurityContext
实例。更改它应该非常罕见,但如果您必须配置一个自定义的 SecurityContextFactory
,您可以执行以下操作:
<bean id="shiroPlugin" class="org.apache.activemq.shiro.ShiroPlugin" xmlns="http://www.springframework.org/schema/beans">
<property name="subjectFilter.securityContextFactory">
<bean class="com.my.SecurityContextFactory" .../>
</property>
</bean>
但是请注意,插件的许多功能和下游过滤器都期望创建的 SecurityContext
实例是 SubjectSecurityContext
实例。
身份验证
ShiroPlugin 在代理过滤器链中将 AuthenticationFilter
安装在 SubjectFilter
之后。 AuthenticationFilter
确保代理客户端 Subject
在允许链继续之前,如有必要,进行身份验证。如果需要身份验证并且 Subject
未经身份验证,代理过滤器链将不会执行,确保只有经过验证的身份才能执行进一步的操作。
正在进行中 - 仍在撰写