ActiveMQ支持可插拔的安全机制,用以在不同的provider之间切换。
1.JAAS认证插件
JAAS(Java Authentication and Authorization Service)也就是Java 的验证Authentication)、授权
(Authorization)服务。简单来说,验证Authentication就是要验证一个用户的有效性,即用户名、密码是否正确。
授权Authorization就是授予用户某种角色,可以访问哪些资源。 JAASAuthentication Plugin依赖标准的JAAS
机制来实现认证。通常情况下,你需要通过设置java.security.auth.login.config系统属性来配置login
modules的配置文件。如果没有指定这个系统属性,那么JAAS Authentication Plugin会缺省使用
login.config作为文件名。
以下是一个login.config文件的例子:
activemq { org.apache.activemq.jaas.PropertiesLoginModule required org.apache.activemq.jaas.properties.user = "users.properties" org.apache.activemq.jaas.properties.group = "groups.properties" ; };
users.properties
admin=admin user=sky guest=sky
group.properties
admins=admin users=user guests=guest
这个login.config文件中设置了两个属性:
org.apache.activemq.jaas.properties.user org.apache.activemq.jaas.properties.group
分别用来指向user.properties和group.properties文件。需要注意的是,PropertiesLoginModule使用本地文件的查找方式,而且查找时采用的base directory是login.config文件所在的目录。因此这个login.config说明user.properties和group.properties文件存放在跟login.config文件相同的目录里。(activemq 5.9 默认提供了以上的配置文件)以下是activemq.xml 配置的一个例子:
< plugins > <!-- Lets configure a destination based authorization mechanism 采用JAAS的管理机制来配置各种角色的权限 --> < jaasAuthenticationPlugin configuration = "activemq" /> < authorizationPlugin > < map > < authorizationMap > < authorizationEntries > < authorizationEntry queue = ">" read = "admins" write = "admins" admin = "admins" /> < authorizationEntry queue = "USERS.>" read = "users" write = "admins" admin = "admins" /> < authorizationEntry queue = "GUEST.>" read = "guests" write = "guests,users" admin = "guests,users" /> < authorizationEntry queue = "TEST.*" read = "guests" write = "guests" /> < authorizationEntry topic = ">" read = "admins" write = "admins" admin = "admins" /> < authorizationEntry topic = "USERS.>" read = "users" write = "users" admin = "users" /> < authorizationEntry topic = "GUEST.>" read = "guests" write = "guests,users" admin = "guests,users" /> < authorizationEntry topic = "ActiveMQ.Advisory.>" read = "guests,users" write = "guests,users" admin = "guests,users" /> </ authorizationEntries > < tempDestinationAuthorizationEntry > < tempDestinationAuthorizationEntry read = "tempDestinationAdmins" write = "tempDestinationAdmins" admin = "tempDestinationAdmins" /> </ tempDestinationAuthorizationEntry > </ authorizationMap > </ map > </ authorizationPlugin > </ plugins >
基于以上的配置,在JAAS的LoginContext中会使用login.config中activemq中配置的PropertiesLoginModule来进行登陆。
针对不同的queue或者topic设置了可以进行操作的组。里面主要涉及三种操作:read, write, admin
read:可以从queue或者topic里面接收消息 write:可以向queue或者topic发送消息 admin:可以创建queue或者topic(可能还有别的功能)
这些文件配制好时候,ActiveMQ就具有了基本的安全机制,当Client(生产者和消费者)连接ActiveMQ需要使用账号,还可以限制具体的Client对于某个/某些Topic/Queue的操作权限.
例如:
<authorizationEntry queue=">" read="admins" write="admins" admin="admins" />。 ">"是通配符的意思,也就是admins组的角色,拥有read、write、admin的权限。 <authorizationEntry queue="USERS.>" read="users" write="admins" admin="admins" /> 。queue名称以"USERS."开头的,users组只拥有读权限,即只能收消息,不能发消息。
2.简单认证插件
SimpleAuthentication Plugin适用于简单的认证需求,或者用于建立测试环境。它允许在XML配置文件中指定用户、用户组和密码等信息。(该文件位于:
%ACTIVEMQ_HOME%\conf\
activemq.xml, D:\sun_java\activemq\apache-activemq-5.9.0\conf
)
在 <shutdownHooks>加上以下的话
< plugins > ... < 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 > </ plugins >
用户名密码信息保存在conf/jetty-realm.properties文件中
按顺序分别是:用户名、密码、角色名
另:ActiveMQ使用的是jetty服务器, 可以通过设置conf/jetty.xml文件,在进入控制台时不输入密码
将图示的属性value="true"改为"false",重新启动MQ登录时就不需要输入用户名和密码了
下面是基于JASS认证插件的配置,首先启动activemq服务:
jsm.xml
<? xml version = "1.0" encoding = "UTF-8" ?> < beans xmlns = "http://www.springframework.org/schema/beans" 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-4.0.xsd" > < description > JMS高级应用配置(NON_PERSISTENT,DURIABLE,SELECTOR) </ description > < bean id = "advancedConnectionFactory" class = "org.apache.activemq.ActiveMQConnectionFactory" > < property name = "brokerURL" value = "${jms.broker_url}" /> < property name = "userName" value = "${jms.userName}" /> < property name = "password" value = "${jms.password}" /> </ bean > < bean id = "advancedTopicConnectionFactory" class = "org.apache.activemq.ActiveMQConnectionFactory" > < property name = "brokerURL" value = "${jms.broker_url}" /> < property name = "clientID" value = "${jms.client_id}" /> < property name = "userName" value = "${jms.userName}" /> < property name = "password" value = "${jms.password}" /> </ bean > < bean id = "advancedCachingConnectionFactory" class = "org.springframework.jms.connection.CachingConnectionFactory" > < property name = "targetConnectionFactory" ref = "advancedConnectionFactory" /> < property name = "sessionCacheSize" value = "10" /> </ bean > < bean id = "advancedNotifyQueue" class = "org.apache.activemq.command.ActiveMQQueue" > < constructor-arg value = "USERS.advanced.queue" /> </ bean > < bean id = "advancedNotifyTopic" class = "org.apache.activemq.command.ActiveMQTopic" > < constructor-arg value = "USERS.advanced.topic" /> </ bean > < bean id = "advancedJmsTemplate" class = "org.springframework.jms.core.JmsTemplate" > < property name = "connectionFactory" ref = "advancedCachingConnectionFactory" /> < property name = "explicitQosEnabled" value = "true" /> < property name = "deliveryPersistent" value = "false" /> < property name = "priority" value = "9" /> </ bean > < bean id = "advancedNotifyMessageProducer" class = "com.goldpalm.sgyl.api.jms.AdvancedNotifyMessageProducer" > < property name = "jmsTemplate" ref = "advancedJmsTemplate" /> < property name = "notifyQueue" ref = "advancedNotifyQueue" /> < property name = "notifyTopic" ref = "advancedNotifyTopic" /> </ bean > < bean id = "advancedQueueContainer" class = "org.springframework.jms.listener.DefaultMessageListenerContainer" > < property name = "connectionFactory" ref = "advancedConnectionFactory" /> < property name = "destination" ref = "advancedNotifyQueue" /> < property name = "messageListener" ref = "advancedNotifyMessageListener" /> < property name = "concurrentConsumers" value = "5" /> < property name = "maxConcurrentConsumers" value = "10" /> < property name = "sessionAcknowledgeModeName" value = "CLIENT_ACKNOWLEDGE" /> </ bean > < bean id = "advancedTopicContainer" class = "org.springframework.jms.listener.DefaultMessageListenerContainer" > < property name = "connectionFactory" ref = "advancedTopicConnectionFactory" /> < property name = "destination" ref = "advancedNotifyTopic" /> < property name = "messageListener" ref = "advancedNotifyMessageListener" /> < property name = "messageSelector" value = "objectType='user'" /> < property name = "subscriptionDurable" value = "true" /> </ bean > < bean id = "advancedNotifyMessageListener" class = "com.goldpalm.sgyl.api.jms.AdvancedNotifyMessageListener" /> </ beans >
jsm.properties
#activemq settings #vm broker #jms.broker_url=vm://showcase?broker.persistent=false&broker.useJmx=false&broker.schedulerSupport=false #localhost broker jms.broker_url=tcp://localhost:61616 #network of brokers #jms.broker_url=failover://(tcp://mqremote1:61616,tcp://mqremote2:61616)?randomize=false&initialReconnectDelay=100&timeout=5000 jms.client_id=durableTopicListenerDemo #jmx settings jmx.rmi_port=2099 #demo settings server.node_name=default server.addr=localhost jms.userName=user jms.password=sky
当我们不使用用户名密码连接时,console控制台会打印:WARN [DefaultMessageListenerContainer.java:888] - Could not refresh JMS Connection for destination 'queue://q.notify' - retrying in 5000 ms. Cause: User name [null] or password is invalid.
当使用用户名为user,密码为sky的账户连接时,如果我们向topic中发送消息,就会提示报错:org.springframework.jms.JmsSecurityException: User user is not authorized to write to: queue://USERS.advanced.queue; nested exception is javax.jms.JMSSecurityException: User user is not authorized to write to: queue://USERS.advanced.queue