安全

功能 > 安全

ActiveMQ Classic 4.x 及更高版本通过各种不同的提供者提供可插拔的安全功能。

最常见的提供者是

  • JAAS 用于身份验证
  • 使用简单的 XML 配置文件进行默认授权机制。

身份验证

默认的 JAAS 插件依赖于标准的 JAAS 机制进行身份验证。请参阅 文档 以获取更多详细信息。

通常,您使用类似 此文件 的配置文件来配置 JAAS,并将 java.security.auth.login.config 系统属性设置为指向它。如果没有指定系统属性,则默认情况下,ActiveMQ Classic JAAS 插件将在类路径中查找 login.config 并使用它。

身份验证示例

这是一个示例 login.config,它指向以下文件

注意:在 5.11.1 版本之前,这些属性文件默认情况下在每次身份验证请求时都会重新加载。因此,对用户、密码和组的更新会立即加载。从 5.12 开始,只有在您的 LoginModule 配置中设置了 reload=true 时,它们才会重新加载,例如:

activemq { org.apache.activemq.jaas.PropertiesLoginModule required org.apache.activemq.jaas.properties.user="users.properties" org.apache.activemq.jaas.properties.group="groups.properties" reload=true; };

如果未设置 reload=true,则这些属性文件只会在代理启动时加载一次!有关详细信息,请参阅 AMQ-5876。

简单身份验证插件

如果您有适度的身份验证需求(或者只想快速设置您的测试环境),您可以使用 SimpleAuthenticationPlugin。使用此插件,您可以在代理的 XML 配置中直接定义用户和组。例如,请查看以下代码片段

<simpleAuthenticationPlugin>
  <users>
    <authenticationUser username="system" password="manager" groups="users,admins"/>
    <authenticationUser username="user" password="password" groups="users"/>
    <authenticationUser username="guest" password="password" groups="guests"/>
  </users>
</simpleAuthenticationPlugin>

以这种方式定义的用户和组稍后可以与相应的授权插件一起使用。

匿名访问

从 5.4.0 版本开始,您可以配置简单身份验证插件以允许匿名访问代理。

<simpleAuthenticationPlugin anonymousAccessAllowed="true"> <users> <authenticationUser username="system" password="manager" groups="users,admins"/> <authenticationUser username="user" password="password" groups="users"/> <authenticationUser username="guest" password="password" groups="guests"/> </users> </simpleAuthenticationPlugin>

要允许匿名访问代理,请使用 anonymousAccessAllowed 属性并将其设置为 true,如上所示。现在,当客户端在未提供用户名和密码的情况下连接时,将为其安全上下文分配默认用户名 (anonymous) 和组 (anonymous)。您可以使用此用户名和密码来授权客户端访问相应的代理资源(请参阅下一节)。您还可以使用 anonymousUseranonymousGroup 属性更改将分配给匿名用户的用户名和组。

授权

在 ActiveMQ Classic 中,我们使用许多操作,您可以将这些操作与用户角色以及单个队列或主题相关联,或者您可以使用通配符将这些操作附加到主题和队列的层次结构。

操作 描述
读取 您可以浏览和消费来自目的地的消息
写入 您可以向目的地发送消息
管理 如果目的地尚不存在,您可以延迟创建它。这允许您对哪些新的目的地可以在队列/主题层次结构的哪个部分动态创建进行细粒度的控制

可以使用 ActiveMQ Classic 通配符 语法来指定队列/主题。

授权示例

以下 示例 显示了这两个插件的操作。尽管请注意,编写您自己的插件非常容易。注意,通常应该向 ActiveMQ.Advisory 目的地授予完全访问权限,因为默认情况下,ActiveMQConnection 使用目的地公告来尽早了解临时目的地的创建和删除。此外,动态网络连接器使用公告来确定消费者需求。
如果需要,可以通过 ActiveMQConnectionFactory 的watchTopicAdvisories 布尔属性禁用以这种方式使用公告,对于网络连接器,可以通过网络连接器的staticBridge(5.6) 布尔属性禁用。

代理到代理身份验证和授权

如果您已为特定消息代理启用了身份验证,则希望连接到该代理的其他代理必须通过其元素提供适当的身份验证凭据。例如,假设我们有一个具有以下配置的代理网络

  • 代理网络包含两个代理(BrokerA 和 BrokerB)
  • BrokerA 的身份验证已通过示例 <simpleAuthenticationPlugin> 元素启用。
  • BrokerB 的身份验证未启用。
  • BrokerA 仅侦听连接。换句话说,BrokerA 具有 <transportConnector> 元素,但没有 <networkConnector> 元素。

为了使 BrokerB 连接到 BrokerA,BrokerB 的 XML 配置文件中的相应元素必须按如下方式设置。

<networkConnectors> 
  <networkConnector name="brokerAbridge" userName="user" password="password" uri="static://(tcp://brokerA:61616)"/> 
</networkConnectors>

请注意,BrokerB 的 <networkConnector> 元素必须提供适当的凭据才能连接到 BrokerA。如果 BrokerA 已启用授权,则分配给 <networkConnector> 元素的 userName 也必须具有适当的授权凭据。如果 BrokerA 已启用授权,并且 BrokerB 的相应 <networkConnector> 元素的 userName 未被授予适当的授权凭据,则消息将无法从 BrokerB 转发到 BrokerA。

此外,如果 BrokerA 被授予 <networkConnector> 元素,以便它可以启动到 BrokerB 的连接,则该 <networkConnector> 必须被授予在 <simpleAuthenticationPlugin> 元素中定义的 userName/password 组合;即使 BrokerB 未启用身份验证服务,这也是必需的。

控制对临时目的地的访问

要控制对临时目的地的访问,您需要将 <tempDestinationAuthorizationEntry> 元素添加到 authorizationMap 中。通过此元素,您可以控制对所有临时目的地的访问。如果此元素不存在,则将向所有用户授予临时目的地的读取、写入和管理权限。在下面的示例中,只有那些被分配到 'admin' 组的客户端才能获得对临时目的地的读取、写入和管理权限。

<broker> 
  .. 
    <plugins> 
      .. 
      <authorizationPlugin> 
        <map> 
          <authorizationMap> 
            <authorizationEntries> 
              <authorizationEntry queue="TEST.Q" read="users" write="users" admin="users" /> 
              <authorizationEntry topic="ActiveMQ.Advisory.>" read="*" write="*" admin="*"/> 
            </authorizationEntries> 
            <tempDestinationAuthorizationEntry> 
              <tempDestinationAuthorizationEntry read="admin" write="admin" admin="admin"/> 
            </tempDestinationAuthorizationEntry> 
          </authorizationMap> 
        </map> 
      </authorizationPlugin> 
      .. 
    </plugins> 
  .. 
</broker>

使用 JAAS 插件进行 LDAP 身份验证

新模块

从 5.6 开始,提供了一个新的/更好的 ldap 授权模块。有关更多信息,请参阅 缓存的 LDAP 授权模块

  1. 在 activemq.xml 中配置 JAAS LDAPLoginModule 和 LDAPAuthorizationMap

     <plugins> 
       <!-- use JAAS to authenticate using the login.config file on the classpath to configure JAAS --> 
       <jaasAuthenticationPlugin configuration="LdapConfiguration" /> 
       <!-- lets configure a destination based role/group authorization mechanism --> 
       <authorizationPlugin> 
         <map> 
           <bean xmlns="http://www.springframework.org/schema/beans" id="lDAPAuthorizationMap" class="org.apache.activemq.security.LDAPAuthorizationMap"> 
             <property name="initialContextFactory" value="com.sun.jndi.ldap.LdapCtxFactory"/> 
             <property name="connectionURL" value="ldap://ldap.acme.com:389"/> 
             <property name="authentication" value="simple"/> 
             <property name="connectionUsername" value="cn=mqbroker,ou=Services,dc=acme,dc=com"/> 
             <property name="connectionPassword" value="password"/> 
             <property name="connectionProtocol" value="s"/> 
             <property name="topicSearchMatching" value="cn={0},ou=Topic,ou=Destination,ou=ActiveMQ,ou=systems,dc=acme,dc=com"/> 
             <property name="topicSearchSubtreeBool" value="true"/> 
             <property name="queueSearchMatching" value="cn={0},ou=Queue,ou=Destination,ou=ActiveMQ,ou=systems,dc=acme,dc=com"/> 
             <property name="queueSearchSubtreeBool" value="true"/> 
             <property name="adminBase" value="(cn=admin)"/> 
             <property name="adminAttribute" value="member"/> 
             <property name="adminAttributePrefix" value="cn="/> 
             <property name="readBase" value="(cn=read)"/> 
             <property name="readAttribute" value="member"/> 
             <property name="readAttributePrefix" value="cn="/> 
             <property name="writeBase" value="(cn=write)"/> 
             <property name="writeAttribute" value="member"/> 
             <property name="writeAttributePrefix" value="cn="/> 
           </bean> 
         </map> 
       </authorizationPlugin> 
     </plugins>
    
  2. 配置 JAAS login.config(我还没有对配置进行重复数据删除)
     LdapConfiguration { 
        org.apache.activemq.jaas.LDAPLoginModule required 
        initialContextFactory=com.sun.jndi.ldap.LdapCtxFactory 
        connectionURL="ldap://ldap.acme.com:389" 
        connectionUsername="cn=mqbroker,ou=Services,dc=acme,dc=com" 
        connectionPassword=password connectionProtocol=s 
        authentication=simple 
        userBase="ou=User,ou=ActiveMQ,ou=systems,dc=acme,dc=com" 
        userRoleName=dummyUserRoleName 
        userSearchMatching="(uid={0})" 
        userSearchSubtree=false 
        roleBase="ou=Group,ou=ActiveMQ,ou=systems,dc=acme,dc=com" 
        roleName=cn 
        roleSearchMatching="(member:=uid={1})" 
        roleSearchSubtree=true 
        ; 
     };
    
  3. 将以下 LDIF 文件导入 LDAP 服务器
     version: 1 
     # 
     # Sample LDIF for ActiveMQ LDAP authentication and authorisation 
     # Passwords are defaulted to "password" - it is your responsibility to change them! 
     # 
     # Sets up: 
     # 1. Bind user 
     # 2. A sample queue with admin,read,write permission assignments 
     # 3. ActiveMQ Classic advisory topics 
     # 4. Two groups - admin and webapp 
     # 5. Two users - admin and webapp 
     # 6. Role assignments - admin->admin, webapp->webapp 
     # 
     # (c) Robin Bramley 2008 # Provided as is without any warranty of any kind 
     # 
     dn: dc=acme,dc=com 
     dc: acme 
     objectClass: domain 
     objectClass: top 
        
     dn: ou=Services,dc=acme,dc=com 
     ou: Services 
     objectClass: organizationalUnit 
     objectClass: top 
        
     dn: cn=mqbroker,ou=Services,dc=acme,dc=com 
     cn: mqbroker 
     objectClass: organizationalRole 
     objectClass: top 
     objectClass: simpleSecurityObject 
     userPassword: {SSHA}j0NpveEO0YD5rgI5kY8OxSRiN5KQ/kE4 
     description: Bind user for MQ broker 
        
     dn: ou=systems,dc=acme,dc=com 
     ou: systems 
     objectClass: organizationalUnit 
     objectClass: top 
        
     dn: ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     objectClass: organizationalUnit 
     objectClass: top 
     ou: ActiveMQ 
        
     dn: ou=Destination,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     objectClass: organizationalUnit 
     objectClass: top 
     ou: Destination 
        
     dn: ou=Queue,ou=Destination,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     objectClass: organizationalUnit 
     objectClass: top 
     ou: Queue 
        
     dn: cn=com.acme.myfirstrealqueue,ou=Queue,ou=Destination,ou=ActiveMQ,ou=syst ems,dc=acme,dc=com 
     cn: com.acme.myfirstrealqueue 
     description: A queue 
     objectClass: applicationProcess 
     objectClass: top 
        
     dn: cn=admin,cn=com.acme.myfirstrealqueue,ou=Queue,ou=Destination,ou=ActiveM Q,ou=systems,dc=acme,dc=com 
     cn: admin 
     description: Admin privilege group, members are roles 
     member: cn=admin 
     member: cn=webapp 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: cn=read,cn=com.acme.myfirstrealqueue,ou=Queue,ou=Destination,ou=ActiveMQ ,ou=systems,dc=acme,dc=com 
     cn: read member: cn=webapp 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: cn=write,cn=com.acme.myfirstrealqueue,ou=Queue,ou=Destination,ou=ActiveM Q,ou=systems,dc=acme,dc=com 
     cn: write 
     objectClass: groupOfNames 
     objectClass: top member: cn=webapp 
        
     dn: ou=Topic,ou=Destination,ou=ActiveMQ,ou=systems,dc=acme,dc=co m 
     objectClass: organizationalUnit 
     objectClass: top 
     ou: Topic 
        
     dn: cn=ActiveMQ.Advisory.Consumer,ou=Topic,ou=Destination,ou=ActiveMQ,ou=sys tems,dc=acme,dc=com 
     cn: ActiveMQ.Advisory.Consumer 
     objectClass: applicationProcess 
     objectClass: top description: Advisory topic about consumers 
        
     dn: cn=read,cn=ActiveMQ.Advisory.Consumer,ou=Topic,ou=Destination,ou=ActiveM Q,ou=systems,dc=acme,dc=com 
     cn: read member: cn=webapp 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: cn=ActiveMQ.Advisory.TempQueue,ou=Topic,ou=Destination,ou=ActiveMQ,ou=sy stems,dc=acme,dc=com 
     cn: ActiveMQ.Advisory.TempQueue 
     description: Advisory topic about temporary queues 
     objectClass: applicationProcess 
     objectClass: top 
        
     dn: cn=read,cn=ActiveMQ.Advisory.TempQueue,ou=Topic,ou=Destination,ou=Active MQ,ou=systems,dc=acme,dc=com 
     cn: read member: cn=webapp 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: cn=ActiveMQ.Advisory.TempTopic,ou=Topic,ou=Destination,ou=ActiveMQ,ou=sy stems,dc=acme,dc=com 
     cn: ActiveMQ.Advisory.TempTopic 
     objectClass: applicationProcess 
     objectClass: top 
     description: Advisory topic about temporary topics 
        
     dn: cn=read,cn=ActiveMQ.Advisory.TempTopic,ou=Topic,ou=Destination,ou=Active MQ,ou=systems,dc=acme,dc=com 
     cn: read 
     member: cn=webapp 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: ou=Group,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     objectClass: organizationalUnit 
     objectClass: top 
     ou: Group 
        
     dn: cn=admin,ou=Group,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     cn: admin 
     member: uid=admin 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: cn=webapp,ou=Group,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     cn: webapp 
     member: uid=webapp 
     objectClass: groupOfNames 
     objectClass: top 
        
     dn: ou=User,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     objectClass: organizationalUnit 
     objectClass: top 
     ou: User 
        
     dn: uid=admin,ou=User,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     uid: admin 
     userPassword: {SSHA}j0NpveEO0YD5rgI5kY8OxSRiN5KQ/kE4 
     objectClass: account 
     objectClass: simpleSecurityObject 
     objectClass: top 
        
     dn: uid=webapp,ou=User,ou=ActiveMQ,ou=systems,dc=acme,dc=com 
     uid: webapp 
     userPassword: {SSHA}j0NpveEO0YD5rgI5kY8OxSRiN5KQ/kE4 
     objectClass: account 
     objectClass: simpleSecurityObject 
     objectClass: top
    
  4. 启动 ActiveMQ Classic

  5. 测试它

安全性和 ActiveMQ Classic 组件

除了消息代理之外,您还可以选择执行几个额外的“组件”,例如 Camel 和/或 Web 控制台。这些组件与代理建立连接;因此,如果您已保护您的代理(即已启用身份验证),则必须配置这些组件,以便它们在连接到代理时提供所需的安全性凭据(用户名、密码)。

骆驼

您可能在代理的 XML 配置文件中定义了以下 Camel 上下文。

<!-- ** Lets deploy some Enterprise Integration Patterns inside the ActiveMQ Classic Message Broker ** For more details see ** ** https://activemq.apache.ac.cnFeatures/enterprise-integration-patterns.md -->
<camelContext id="camel" xmlns="https://activemq.apache.org/camel/schema/spring">
  <package>org.foo.bar</package>
  <route> 
    <from uri="activemq:example.A"/>
    <to uri="activemq:example.B"/>
  </route>
</camelContext>

以上配置未设置为在安全环境中工作。

如果应用程序在 OSGi 容器中运行,请在 CamelContext 定义之前添加以下行

<osgi:reference id="activemq" interface="org.apache.camel.Component" />

这允许容器中部署的任何预先配置的 ActiveMQComponent 实例优先于默认的 ActiveMQComponent。

也就是说,使用以上配置,Camel 将与 ActiveMQ Classic 建立连接,但不会提供用户名和密码。因此,当启用 ActiveMQ Classic 安全性时,以上配置会导致安全性异常。异常将被多次抛出,因为 Camel 将继续重试连接。如果您未使用 Camel,请注释掉以上 XML 代码。如果您正在使用 Camel,请将以下 bean 定义添加到代理的 XML 配置中

<!-- configure the camel activemq component to use the current broker -->
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent" >
  <property name="connectionFactory"> 
    <bean class="org.apache.activemq.ActiveMQConnectionFactory">
      <property name="brokerURL" value="vm://127.0.0.1?create=false&amp;waitForStart=10000" />
      <property name="userName" value="system"/> 
      <property name="password" value="manager"/>
    </bean>
  </property>
</bean>

使用以上 bean 定义,Camel 将在连接到代理时传递指定的安全性凭据。

如果代理在 OSGi 容器中运行,请在 ActiveMQComponent bean 定义之后添加以下行

<service ref="activemq" interface="org.apache.camel.Component"/>

网络控制台

如果您想在安全代理中使用 Web 控制台,您必须更改 webapps/admin/WEB-INF/webconsole-embeded.xml 中的 connectionFactory bean,使其类似于以下内容

<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
  <property name="brokerURL" value="vm://127.0.0.1"/>
  <property name="userName" value="system"/>
  <property name="password" value="manager"/>
</bean>

默认凭据

从 5.3 版本开始,所有以上配置详细信息都包含在默认的 ActiveMQ Classic 配置中。此外,还有一个中央位置,您可以在其中设置这些组件将用于连接到代理的凭据。只需在 conf/credentials.properties 文件中设置所需的用户名和密码,该文件默认情况下看起来像这样

activemq.username=system activemq.password=manager

加密密码

从 5.4.1 版本开始,您还可以对代理使用 加密密码

消息级别授权

还可以使用您选择的基于内容的授权策略来授权每条单独的消息。与之前描述的其他安全选项相比,消息级别授权需要比一些配置更多的东西。您必须从创建一个新的 Maven 项目开始,并将 activemq-all Maven 依赖项(与您的 activemq 安装相同版本)添加到新项目的 pom.xml 中。
在下一步中,您必须创建一个新的 Java 类,并让它实现 org.apache.activemq.security.MessageAuthorizationPolicy 接口。之后,只需添加一个具有以下签名的方法

public boolean isAllowedToConsume(ConnectionContext context, Message message){...}

到新的 Java 类中。为了使用您自己的消息级别授权策略,Java 类必须打包为 jar 并添加到 ActiveMQ Classic 的 /lib 文件夹中,以使其可用。在最后一步中,必须通过使用 *messageAuthorizationPolicy* 属性或将其添加到 XML 中,将其直接配置到代理上,如下所示

<broker>
  ..
  <messageAuthorizationPolicy>
    <bean class="com.acme.MyMessageAuthorizationPolicy" xmlns=""/>
  </messageAuthorizationPolicy>
  ..
</broker>

实现您自己的自定义安全插件

所有各种安全性实现都是作为 拦截器 实现的,因此添加您自己的自定义实现非常容易。如果使用 JAAS,您可能更容易从 简单实现 之一入手,尽管您可以从 JAAS 实现 中派生。

Apache, ActiveMQ, Apache ActiveMQ,Apache 羽毛标志和 Apache ActiveMQ 项目标志是 Apache 软件基金会的商标。版权所有 © 2024,Apache 软件基金会。根据 Apache 许可证 2.0 授权。