ActiveMQ授权源码分析simpleAuthentication(一)
由昨天弄了下activemq 的自定义认证觉得不过瘾,想看看他的simpleAuthentication 和 JAAS 是怎么弄的 于是研究了一下源码,了解的信息整理一下发出来,如有不对的地方还望包涵及指正。
打开activemq-broker 目录结构
授权模块需要关注broker 和 security 就可以了,先来了解一下activemq 授权的基本要素有2点
1.验证 Authentication
2. 授权Authorization
第一个验证你的登录账号是否正确,第二个验证通过后对该账号进行授权。
ActiveMQ安全机制
ActiveMQ原有安全机制均基于插件实现,实现思路如图所示
通过实现BrokerPlugin 完成授权的注册, Broker接口是ActiveMQ的核心接口 , BrokerPlugin通过installPlugin方法传入Broker对象为其创建插件。
看看simpleAuthentication是怎么做的首先根据上面的原理 在security 包中可以找到名字为SimpleAuthenticationPlugin的类这个就是simpleAuthentication注册类我们在activemq.xml中配置simpleAuth的配置项:
<simpleAuthenticationPlugin> <users>
<authenticationUser username="admin" password="admin" groups="admins,publishers,consumers"/>
<authenticationUser username="publisher" password="publisher" groups="publishers,consumers"/>
<authenticationUser username="consumer" password="consumer" groups="consumers"/>
<authenticationUser username="guest" password="guest" groups="guests"/>
</users>
</simpleAuthenticationPlugin>
声明的simpleAuth 会通过构造器传入user信息 SimpleAuthenticationPlugin的默认组和默认用户为 anonymous
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;
public Broker installPlugin(Broker parent) { SimpleAuthenticationBroker broker = new SimpleAuthenticationBroker(parent, userPasswords, userGroups);
broker.setAnonymousAccessAllowed(anonymousAccessAllowed);
broker.setAnonymousUser(anonymousUser);
broker.setAnonymousGroup(anonymousGroup);
return broker;
}
传入 SimpleAuthenticationBroker 中
/** * Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.activemq.security;
import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.activemq.broker.Broker;
import org.apache.activemq.broker.ConnectionContext;
import org.apache.activemq.command.ConnectionInfo;
import org.apache.activemq.jaas.GroupPrincipal;
/**
* Handles authenticating a users against a simple user name/password map.
*/
public class SimpleAuthenticationBroker extends AbstractAuthenticationBroker {
private boolean anonymousAccessAllowed = false;
private String anonymousUser;
private String anonymousGroup;
private Map<String,String> userPasswords;
private Map<String,Set<Principal>> userGroups;
public SimpleAuthenticationBroker(Broker next, Map<String,String> userPasswords, Map<String,Set<Principal>> userGroups) {
super(next);
this.userPasswords = userPasswords;
this.userGroups = userGroups;
}
public void setAnonymousAccessAllowed(boolean anonymousAccessAllowed) {
this.anonymousAccessAllowed = anonymousAccessAllowed;
}
public void setAnonymousUser(String anonymousUser) {
this.anonymousUser = anonymousUser;
}
public void setAnonymousGroup(String anonymousGroup) {
this.anonymousGroup = anonymousGroup;
}
public void setUserPasswords(Map<String,String> value) {
userPasswords = value;
}
public void setUserGroups(Map<String, Set<Principal>> value) {
userGroups = value;
}
@Override
public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
SecurityContext securityContext = context.getSecurityContext();
if (securityContext == null) {
securityContext = authenticate(info.getUserName(), info.getPassword(), null);
context.setSecurityContext(securityContext);
securityContexts.add(securityContext);
}
try {
super.addConnection(context, info);
} catch (Exception e) {
securityContexts.remove(securityContext);
context.setSecurityContext(null);
throw e;
}
}
@Override
public SecurityContext authenticate(String username, String password, X509Certificate[] certificates) throws SecurityException {
SecurityContext securityContext = null;
// Check the username and password.
if (anonymousAccessAllowed && username == null && password == null) {
username = anonymousUser;
securityContext = new SecurityContext(username) {
@Override
public Set<Principal> getPrincipals() {
Set<Principal> groups = new HashSet<Principal>();
groups.add(new GroupPrincipal(anonymousGroup));
return groups;
}
};
} else {
String pw = userPasswords.get(username);
if (pw == null || !pw.equals(password)) {
throw new SecurityException("User name [" + username + "] or password is invalid.");
}
final Set<Principal> groups = userGroups.get(username);
securityContext = new SecurityContext(username) {
@Override
public Set<Principal> getPrincipals() {
return groups;
}
};
}
return securityContext;
}
}
通过brokerFilter 的addConnection 到达SimpleAuthenticationBroker方法中看看里面是做些什么的
@Override
public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
SecurityContext securityContext = context.getSecurityContext();
if (securityContext == null) {
securityContext = authenticate(info.getUserName(), info.getPassword(), null);
context.setSecurityContext(securityContext);
securityContexts.add(securityContext);
}
try {
super.addConnection(context, info);
} catch (Exception e) {
securityContexts.remove(securityContext);
context.setSecurityContext(null);
throw e;
}
}
@Override
public SecurityContext authenticate(String username, String password, X509Certificate[] certificates) throws SecurityException {
SecurityContext securityContext = null;
// Check the username and password.
if (anonymousAccessAllowed && username == null && password == null) {
username = anonymousUser;
securityContext = new SecurityContext(username) {
@Override
public Set<Principal> getPrincipals() {
Set<Principal> groups = new HashSet<Principal>();
groups.add(new GroupPrincipal(anonymousGroup));
return groups;
}
};
} else {
String pw = userPasswords.get(username);
if (pw == null || !pw.equals(password)) {
throw new SecurityException("User name [" + username + "] or password is invalid.");
}
final Set<Principal> groups = userGroups.get(username);
securityContext = new SecurityContext(username) {
@Override
public Set<Principal> getPrincipals() {
return groups;
}
};
}
return securityContext;
}
进入addConnection 方法 通过authenticate 来验证客户端用户是否是属于合法用户,第一个if 是如果支持陌生人登录那么就给这个陌生人设置默认的用户组也就是anonymous 陌生用户 ,反之不支持那么就要验证用户的真实性,第一个根据用户名在userPasswords map 寻找用户并判断用户名如果 该用户不存在或者密码错误就会返回 User name [" + username + "] or password is invalid. 的异常。
测试一下:
验证通过,根据用户名从userGroups中获取分组给该用户进行授权
最后再由 super.addConnection(context, info); 交付下一个broker 认证,如果认证通过就会建立连接成功
以上是 ActiveMQ授权源码分析simpleAuthentication(一) 的全部内容, 来源链接: utcz.com/z/515574.html