博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ActiveMQ的安全机制使用及其源代码分析 [转]
阅读量:5815 次
发布时间:2019-06-18

本文共 11065 字,大约阅读时间需要 36 分钟。

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的二进制分发包目录如下所示:

ActiveMQ的安全机制使用及其源代码分析 - 小新 - 小新制造

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

2. Simple authentication plugin-in的使用

在activemq.xml中如下配置:

3. JAAS authentication plugin-in的使用

在activemq.xml中如下配置:

创建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中如下配置:

ActiveMQ安全机制的源代码分析

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

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
userPasswords; private Map
> 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
userPasswords; private final Map
> userGroups; private final CopyOnWriteArrayList
securityContexts = new CopyOnWriteArrayList
(); //...... //由于验证需要在创建连接时进行,因此重写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
getPrincipals() { Set
groups = new HashSet
(); 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
groups = userGroups.get(info.getUserName()); s = new SecurityContext(info.getUserName()) { public Set
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
securityContexts = new CopyOnWriteArrayList
(); //...... //由于验证需要在创建连接时进行,因此重写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的 addConsumer 方法,在该方法中,从访问控制列表中查看是否具有读授权,并调用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的验证和授权。

转载地址:http://gmmbx.baihongyu.com/

你可能感兴趣的文章
CodeIgniter 3.0 新手捣鼓源码(一) base_url()
查看>>
Chrome 广告屏蔽功能不影响浏览器性能
查看>>
vSphere 6将于2月2日全球同步发表
查看>>
Android状态栏实现沉浸式模式
查看>>
让你的APP实现即时聊天功能
查看>>
iOS 绝对路径和相对路径
查看>>
使用Openfiler搭建ISCSI网络存储
查看>>
IntPtr 转 string
查看>>
学生名单
查看>>
(转) 多模态机器翻译
查看>>
【官方文档】Nginx负载均衡学习笔记(三) TCP和UDP负载平衡官方参考文档
查看>>
矩阵常用归一化
查看>>
Oracle常用函数总结
查看>>
【聚能聊有奖话题】Boring隧道掘进机完成首段挖掘,离未来交通还有多远?
查看>>
USNews大学排名遭美国计算机研究学会怒怼,指排名荒谬要求撤回
查看>>
七大关键数据 移动安全迎来历史转折点
查看>>
盘点物联网网关现有联网技术及应用场景
查看>>
mui 总结2--新建第一个app项目
查看>>
nginx的lua api
查看>>
考研太苦逼没坚持下来!看苑老师视频有点上头
查看>>