ActiveMQ的安全机制使用及其源代码分析 [转]

ActiveMQ是目前较为流行的一款开源消息服务器。最近在项目开发中,需要为ActiveMQ开发基于IP的验证和授权机制,因此,对ActiveMQ的安全机制进行了了解,以下将介绍ActiveMQ的安全机制使用及其源代码分析。

本文开发环境介绍:

操作系统:Windows XP

Java:jdk 1.6.0_12

maven:maven 3.0.4

ActiveMQ:ActiveMQ 5.6.0

ActiveMQ安全机制的介绍

安 全机制一般包含验证(Authentication)和授权(Authorization)两部分。在ActiveMQ中,验证指通过访问者的用户名和密 码实现用户身份的验证,授权指为消息目标(队列或主题)的读、写、管理指定具有相应权限的用户组,并为用户分配权限。ActiveMQ的安全机制基于插件 实现。

ActiveMQ提供两种验证插件,分别是:

1)Simple authentication plugin-in;

2)JAAS(Java Authentication and Authorization Service)authentication plugin-in。ActiveMQ提供一种授权插件:Authorization plugin-in。

ActiveMQ安全机制的使用

1. ActiveMQ的使用

可 从ActiveMQ官网“http://activemq.apache.org/”下载ActiveMQ的源代码包或二进制分发包。由于 ActiveMQ使用Java开发,因此需要预先安装jdk,另外,由于ActiveMQ的开发使用了maven,因此,若下载的是源代码包,需要预先安 装maven。解压源代码包,并在源代码包目录下执行“mvn install -Dmaven.test.skip=true ”完成编译、打包和安装,成功后,会在assembly\target下生成二进制分发包。若下载的是二进制分发包,解压即可。

ActiveMQ的二进制分发包目录如下所示:

进入bin文件,执行脚本,即可运行ActiveMQ。

2. Simple authentication plugin-in的使用

在activemq.xml中如下配置:

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

3. JAAS authentication plugin-in的使用

在activemq.xml中如下配置:

<plugins>     <jaasAuthenticationPlugin configuration="activemq-domain" /> </plugins>   

创建login.config文件:

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

创建users.properties和groups.properties文件,包含用户和用户组信息。

users.properties:

system=password user=password guest=password

groups.properties:

admins=system users=system,user guests=guest 

4. Authorization plugin-in的使用

在activemq.xml中如下配置:

<plugins>   <authorizationPlugin>     <map>       <authorizationMap>         <authorizationEntries>           <authorizationEntry queue=">" read="admins" write="admins" admin="admins" />           <authorizationEntry queue="USERS.>" read="users" write="users" admin="users" />           <authorizationEntry queue="GUEST.>" read="guests" write="guests,users" admin="guests,users" /> 

          <authorizationEntry queue="TEST.Q" 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>       </authorizationMap>     </map>   </authorizationPlugin> </plugins>  

ActiveMQ安全机制的源代码分析

ActiveMQ在其maven工程的activemq-core模块中实现安全机制。ActiveMQ原有安全机制均基于插件实现,实现思路如图所示。

其中,Broker接口是ActiveMQ的核心接口,ActiveMQ消息服务器对象即该接口的实现。接口BrokerPlugin通过installPlugin方法传入Broker对象,为其创建插件。BrokerFilter类也实现自Broker接口,其与Broker的关系,类似于Struts中Interceptor与Action的关系,多个BrokerFilter对象以及消息服务器Broker对象通过指向下一个对象的引用next构成链状结构,当创建连接、消息生产者、消息消费者时,先后执行BrokerFilter中的相应方法,直至执行消息服务器中的方法,而安全机制类即继承自BrokerFilter。

ActiveMQ原有安全机制的相关类均继承或实现自上述类或接口,安全机制的类包为activemq-core中的org.apache.activemq.security。

1. Simple authentication plugin-in的源代码分析

Simple authentication plugin-in主要包含两个基本类:SimpleAuthenticationPlugin(实现自BrokerPlugin)和SimpleAuthenticationBroker(继承自BrokerFilter)。

SimpleAuthenticationPlugin部分代码:

public class SimpleAuthenticationPlugin implements BrokerPlugin {     private Map<String, String> userPasswords;     private Map<String, Set<Principal>> userGroups;     private static final String DEFAULT_ANONYMOUS_USER = "anonymous";     private static final String DEFAULT_ANONYMOUS_GROUP = "anonymous";     private String anonymousUser = DEFAULT_ANONYMOUS_USER;     private String anonymousGroup = DEFAULT_ANONYMOUS_GROUP;     private boolean anonymousAccessAllowed = false;     //......     //安装插件时,根据activemq.xml中的配置,新建 SimpleAuthenticationBroker对象, 并返回该对象      public Broker installPlugin(Broker parent) {         SimpleAuthenticationBroker broker = new SimpleAuthenticationBroker(parent, userPasswords, userGroups);         broker.setAnonymousAccessAllowed(anonymousAccessAllowed);         broker.setAnonymousUser(anonymousUser);         broker.setAnonymousGroup(anonymousGroup);         return broker;     }     //...... } 

SimpleAuthenticationBroker部分代码:

public class SimpleAuthenticationBroker extends BrokerFilter { 

    private boolean anonymousAccessAllowed = false;     private String anonymousUser;     private String anonymousGroup;     private final Map<String,String> userPasswords;     private final Map<String,Set<Principal>> userGroups;     private final CopyOnWriteArrayList<SecurityContext> securityContexts = new CopyOnWriteArrayList<SecurityContext>(); 

    //......     //由于验证需要在创建连接时进行,因此重写BrokerFilter的addConnection方法     public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception { 

        SecurityContext s = context.getSecurityContext();         if (s == null) { 

        //若允许匿名访问,则不进行验证         // Check the username and password.             if (anonymousAccessAllowed && info.getUserName() == null && info.getPassword() == null) {                 info.setUserName(anonymousUser);                 s = new SecurityContext(info.getUserName()) {                     public Set<Principal> getPrincipals() {                         Set<Principal> groups = new HashSet<Principal>();                         groups.add(new GroupPrincipal(anonymousGroup));                         return groups;                     }                 };        //若不允许匿名访问,则验证连接的用户名和密码是否与配置文件中的一致,若不一致,则抛出安全异常                   } else {                 String pw = userPasswords.get(info.getUserName());                 if (pw == null || !pw.equals(info.getPassword())) {                     throw new SecurityException(                             "User name [" + info.getUserName() + "] or password is invalid.");                 } 

                final Set<Principal> groups = userGroups.get(info.getUserName());                 s = new SecurityContext(info.getUserName()) {                     public Set<Principal> getPrincipals() {                         return groups;                     }                 };             } 

            context.setSecurityContext(s);             securityContexts.add(s);         } 

    //调用父对象的addConnection方法,即调用next引用的Broker对象的addConnection方法     try {             super.addConnection(context, info);         } catch (Exception e) {             securityContexts.remove(s);             context.setSecurityContext(null);             throw e;         }     }     //...... } 

2. JAAS authentication plugin-in的源代码分析

JAAS authentication plugin-in主要包含两个基本类:JaasAuthenticationPlugin(实现自BrokerPlugin)JaasAuthenticationBroker(继承自BrokerFilter)。

JaasAuthenticationPlugin部分代码:

public class JaasAuthenticationPlugin implements BrokerPlugin {     protected String configuration = "activemq-domain";     //......     public Broker installPlugin(Broker broker) {        //读取配置文件, 初始化JAAS           initialiseJaas();        //创建JaasAuthenticationBroker对象并返回               return new JaasAuthenticationBroker(broker, configuration);     }     //...... } 

JaasAuthenticationBroker部分代码:

public class JaasAuthenticationBroker extends BrokerFilter { 

    private final String jassConfiguration;     private final CopyOnWriteArrayList<SecurityContext> securityContexts = new CopyOnWriteArrayList<SecurityContext>(); 

    //......     //由于验证需要在创建连接时进行,因此重写BrokerFilter的addConnection方法        public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception { 

        if (context.getSecurityContext() == null) {             // Set the TCCL since it seems JAAS needs it to find the login             // module classes.             ClassLoader original = Thread.currentThread().getContextClassLoader();             Thread.currentThread().setContextClassLoader(JaasAuthenticationBroker.class.getClassLoader());             try {                 // Do the login.                 try {                     JassCredentialCallbackHandler callback = new JassCredentialCallbackHandler(info                         .getUserName(), info.getPassword());                     LoginContext lc = new LoginContext(jassConfiguration, callback);                     lc.login();                     Subject subject = lc.getSubject(); 

                    //基于JAAS判断用户名和密码是否正确                     SecurityContext s = new JaasSecurityContext(info.getUserName(), subject);                     context.setSecurityContext(s);                     securityContexts.add(s);                 } catch (Exception e) {                     throw (SecurityException)new SecurityException("User name [" + info.getUserName() + "] or password is invalid.")                         .initCause(e);                 }             } finally {                 Thread.currentThread().setContextClassLoader(original);             }         }         //调用父对象的addConnection方法,即调用next引用的Broker对象的addConnection方法         super.addConnection(context, info);     }     //...... } 

3. Authorization plugin-in的源代码分析

Authorization plugin-in主要包含两个基本类:AuthorizationPlugin(实现自BrokerPlugin)AuthorizationBroker(继承自BrokerFilter)。

AuthorizationPlugin部分代码:

ublic class AuthorizationPlugin implements BrokerPlugin { 

    //AuthorizationMap对象存储activemq.xml中消息目标、读、写、管理用户组信息     private AuthorizationMap map; 

    //......     //创建 AuthorizationBroker 对象并返回         public Broker installPlugin(Broker broker) {         if (map == null) {             throw new IllegalArgumentException("You must configure a ‘map‘ property");         }         return new AuthorizationBroker(broker, map);     }     //...... } 

AuthorizationBroker部分代码:

public class AuthorizationBroker extends BrokerFilter implements SecurityAdminMBean { 

    private final AuthorizationMap authorizationMap; 

    //......         //由于需要授权是否可管理消息目标,因此重写BrokerFilter的 addDestinationInfo 方法       @Override     public void addDestinationInfo(ConnectionContext context, DestinationInfo info) throws Exception {         addDestination(context, info.getDestination(),true);         super.addDestinationInfo(context, info);     } 

    //由于需要授权是否可管理消息目标,因此重写BrokerFilter的  addDestination  方法          @Override     public Destination addDestination(ConnectionContext context,
 ActiveMQDestination destination,boolean create) throws Exception {         final SecurityContext securityContext = context.getSecurityContext();         if (securityContext == null) {             throw new SecurityException("User is not authenticated.");         } 

        Destination existing = this.getDestinationMap().get(destination);         if (existing != null) {             return super.addDestination(context, destination,create);         } 

    //从访问控制列表中查看是否具有授权            if (!securityContext.isBrokerContext()) {             Set<?> allowedACLs = null;             if (!destination.isTemporary()) {                 allowedACLs = authorizationMap.getAdminACLs(destination);             } else {                 allowedACLs = authorizationMap.getTempDestinationAdminACLs();             } 

            if (allowedACLs != null && !securityContext.isInOneOf(allowedACLs)) {                 throw new SecurityException("User " + securityContext.getUserName() + " is not authorized to create: " + destination);             } 

        } 

        //调用next引用的addDestination方法                return super.addDestination(context, destination,create);     } 

    //由于需要授权是否可读消息,因此重写BrokerFilter的  addConsume
r  方法,在该方法中,从访问控制列表中查看是否具有读授权,并调用next引用的addConsumer方法             @Override     public Subscription addConsumer(ConnectionContext context, ConsumerInfo info) throws Exception {          //......          return super.addConsumer(context, info);     } 

    //由于需要授权是否可写消息,因此重写BrokerFilter的  addProducer   方法,在该方法中,
从访问控制列表中查看是否具有写授权,并调用next引用的 addProducer 方法          @Override     public void addProducer(ConnectionContext context, ProducerInfo info) throws Exception {          //......          super.addProducer(context, info);     }     //......  } 

ActiveMQ提供了便利的插件开发方式,并基于插件实现了包含验证和授权的安全机制。参考ActiveMQ的源代码,可以进行插件开发,实现个性化的安全机制,如基于IP的验证和授权。

时间: 2024-10-11 00:25:07

ActiveMQ的安全机制使用及其源代码分析 [转]的相关文章

FreeBSD 5.0中强制访问控制机制的使用与源代码分析【转】

本文主要讲述FreeBSD 5.0操作系统中新增的重要安全机制,即强制访问控制机制(MAC)的使用与源代码分析,主要包括强制访问控制框架及多级安全(MLS)策略两部分内容.这一部分讲述要将MAC框架与MLS策略用起来,应该做的一些工作,以及如何有效使用它们的问题. ? 强制访问控制(英文缩写MAC)是实现操作系统安全的一个重要的方法,现在几乎所有的安全操作系统都采用强制访问控制作为其核心安全机制之一.强制访问控制是对操作系统的各种客体(如文件.socket.系统FIFO.SCD.IPC等)进行细

cocos2d-x 源代码分析 : EventDispatcher、EventListener、Event 源代码分析 (新触摸机制,新的NotificationCenter机制)

源代码版本号来自3.x,转载请注明 cocos2d-x 源代码分析总文件夹 http://blog.csdn.net/u011225840/article/details/31743129 1.继承结构 1.1 结构 不详吐槽太多,也不贴图了.贴图要审核好久好久好久好久. 从小到大,先来看下Event的结构. 1.Event--------EventTouch,EventCustom,EventMouse,EventKeyboard,EventFocus,EventAcceleration 当中

Android应用Activity、Dialog、PopWindow、Toast窗体加入机制及源代码分析

[工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处.尊重劳动成果] 1 背景 之所以写这一篇博客的原因是由于之前有写过一篇<Android应用setContentView与LayoutInflater载入解析机制源代码分析>.然后有人在文章以下评论和微博私信中问我关于Android应用Activity.Dialog.PopWindow载入显示机制是咋回事,所以我就写一篇文章来分析分析吧(本文以Android5.1.1 (API 22)源代码为基础分析),以

Android 中View的绘制机制源代码分析 三

到眼下为止,measure过程已经解说完了,今天開始我们就来学习layout过程.只是在学习layout过程之前.大家有没有发现我换了编辑器,哈哈.最终下定决心从Html编辑器切换为markdown编辑器.这里之所以使用"下定决心"这个词.是由于毕竟Html编辑器使用好几年了.非常多习惯都已经养成了,要改变多年的习惯确实不易.相信这也是还有非常多人坚持使用Html编辑器的原因. 这也反应了一个现象.当人对某一事物非常熟悉时,一旦出现了新的事物想代替老的事物时,人们都有一种抵触的情绪,做

Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6642463 在前面几篇文章中,我们详细介绍了Android系统进程间通信机制Binder的原理,并且深入分析了系统提供的Binder运行库和驱动程序的 源代码.细心的读者会发现,这几篇文章分析的Binder接口都是基于C/C++语言来实现的,但是我们在编写应用程序都是基于Java语言的,那么,我 们如何使用Java语言来使用系统的Binder机

Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析

文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6633311 在上一篇文章中,我 们分析了Android系统进程间通信机制Binder中的Server在启动过程使用Service Manager的addService接口把自己添加到Service Manager守护过程中接受管理.在这一篇文章中,我们将深入到Binder驱动程序源代码去分析Client是如何通过Service Manager的

java-通过 HashMap、HashSet 的源代码分析其 Hash 存储机制

通过 HashMap.HashSet 的源代码分析其 Hash 存储机制 集合和引用 就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并不是真正的把 Java 对象放入数组中,只是把对象的引用放入数组中,每个数组元素都是一个引用变量. 实际上,HashSet 和 HashMap 之间有很多相似之处,对于 HashSet 而言,系统采用 Hash 算法决定集合元素的存储位置,这样可以保证能快速存.取集合元素:对于 HashMap 而言,系统 key-value 当成一个整体进行处理,

ActiveMQ讯息传送机制以及ACK机制

http://blog.csdn.net/lulongzhou_llz/article/details/42270113 ActiveMQ消息传送机制以及ACK机制详解 AcitveMQ是作为一种消息存储和分发组件,涉及到client与broker端数据交互的方方面面,它不仅要担保消息的存储安全性,还要提供额外的手段来确保消息的分发是可靠的. 一. ActiveMQ消息传送机制 Producer客户端使用来发送消息的, Consumer客户端用来消费消息:它们的协同中心就是ActiveMQ br

【Spark Core】任务运行机制和Task源代码浅析1

引言 上一小节<TaskScheduler源代码与任务提交原理浅析2>介绍了Driver側将Stage进行划分.依据Executor闲置情况分发任务,终于通过DriverActor向executorActor发送任务消息. 我们要了解Executor的运行机制首先要了解Executor在Driver側的注冊过程.这篇文章先了解一下Application和Executor的注冊过程. 1. Task类及其相关 1.1 Task类 Spark将由Executor运行的Task分为ShuffleMa