mirror of https://github.com/apache/activemq.git
https://issues.apache.org/jira/browse/AMQ-5876 - refactor properties loading such that it can be reused by cert and props login modules. Both loading on start and refreshing if reload=true and lastMod indicates change
This commit is contained in:
parent
6f457d2f5c
commit
59cd018979
|
@ -43,7 +43,7 @@ import org.slf4j.LoggerFactory;
|
|||
*
|
||||
* @author sepandm@gmail.com (Sepand)
|
||||
*/
|
||||
public abstract class CertificateLoginModule implements LoginModule {
|
||||
public abstract class CertificateLoginModule extends PropertiesLoader implements LoginModule {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(CertificateLoginModule.class);
|
||||
|
||||
|
@ -54,7 +54,6 @@ public abstract class CertificateLoginModule implements LoginModule {
|
|||
private String username;
|
||||
private Set<String> groups;
|
||||
private Set<Principal> principals = new HashSet<Principal>();
|
||||
private boolean debug;
|
||||
|
||||
/**
|
||||
* Overriding to allow for proper initialization. Standard JAAS.
|
||||
|
@ -63,12 +62,7 @@ public abstract class CertificateLoginModule implements LoginModule {
|
|||
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
|
||||
this.subject = subject;
|
||||
this.callbackHandler = callbackHandler;
|
||||
|
||||
debug = "true".equalsIgnoreCase((String)options.get("debug"));
|
||||
|
||||
if (debug) {
|
||||
LOG.debug("Initialized debug");
|
||||
}
|
||||
init(options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/**
|
||||
* 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.jaas;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
class PrincipalProperties {
|
||||
private final Properties principals;
|
||||
private final long reloadTime;
|
||||
|
||||
PrincipalProperties(final String type, final File source, final Logger log) {
|
||||
Properties props = new Properties();
|
||||
long reloadTime = 0;
|
||||
try {
|
||||
load(source, props);
|
||||
reloadTime = System.currentTimeMillis();
|
||||
} catch (IOException ioe) {
|
||||
log.warn("Unable to load " + type + " properties file " + source);
|
||||
}
|
||||
this.reloadTime = reloadTime;
|
||||
this.principals = props;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
Set<Map.Entry<String, String>> entries() {
|
||||
return (Set) principals.entrySet();
|
||||
}
|
||||
|
||||
String getProperty(String name) {
|
||||
return principals.getProperty(name);
|
||||
}
|
||||
|
||||
long getReloadTime() {
|
||||
return reloadTime;
|
||||
}
|
||||
|
||||
private void load(final File source, Properties props) throws FileNotFoundException, IOException {
|
||||
FileInputStream in = new FileInputStream(source);
|
||||
try {
|
||||
props.load(in);
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
Properties getPrincipals() {
|
||||
return principals;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/**
|
||||
* 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.jaas;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PropertiesLoader {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PropertiesLoader.class);
|
||||
static Map<FileNameKey, ReloadableProperties> staticCache = new HashMap<FileNameKey, ReloadableProperties>();
|
||||
protected boolean debug;
|
||||
|
||||
public void init(Map options) {
|
||||
debug = booleanOption("debug", options);
|
||||
if (debug) {
|
||||
LOG.debug("Initialized debug");
|
||||
}
|
||||
}
|
||||
|
||||
public ReloadableProperties load(String nameProperty, String fallbackName, Map options) {
|
||||
ReloadableProperties result;
|
||||
FileNameKey key = new FileNameKey(nameProperty, fallbackName, options);
|
||||
key.setDebug(debug);
|
||||
|
||||
synchronized (staticCache) {
|
||||
result = staticCache.get(key);
|
||||
if (result == null) {
|
||||
result = new ReloadableProperties(key);
|
||||
staticCache.put(key, result);
|
||||
}
|
||||
}
|
||||
|
||||
return result.obtained();
|
||||
}
|
||||
|
||||
private static boolean booleanOption(String name, Map options) {
|
||||
return Boolean.parseBoolean((String) options.get(name));
|
||||
}
|
||||
|
||||
public class FileNameKey {
|
||||
final File file;
|
||||
final String absPath;
|
||||
final boolean reload;
|
||||
private boolean decrypt;
|
||||
private boolean debug;
|
||||
|
||||
public FileNameKey(String nameProperty, String fallbackName, Map options) {
|
||||
this.file = new File(baseDir(options), stringOption(nameProperty, fallbackName, options));
|
||||
absPath = file.getAbsolutePath();
|
||||
reload = booleanOption("reload", options);
|
||||
decrypt = booleanOption("decrypt", options);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return other instanceof FileNameKey && this.absPath.equals(((FileNameKey) other).absPath);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return this.absPath.hashCode();
|
||||
}
|
||||
|
||||
public boolean isReload() {
|
||||
return reload;
|
||||
}
|
||||
|
||||
public File file() {
|
||||
return file;
|
||||
}
|
||||
|
||||
public boolean isDecrypt() {
|
||||
return decrypt;
|
||||
}
|
||||
|
||||
public void setDecrypt(boolean decrypt) {
|
||||
this.decrypt = decrypt;
|
||||
}
|
||||
|
||||
private String stringOption(String key, String nameDefault, Map options) {
|
||||
Object result = options.get(key);
|
||||
return result != null ? result.toString() : nameDefault;
|
||||
}
|
||||
|
||||
private File baseDir(Map options) {
|
||||
File baseDir = null;
|
||||
if (options.get("baseDir") != null) {
|
||||
baseDir = new File((String) options.get("baseDir"));
|
||||
} else {
|
||||
if (System.getProperty("java.security.auth.login.config") != null) {
|
||||
baseDir = new File(System.getProperty("java.security.auth.login.config")).getParentFile();
|
||||
}
|
||||
}
|
||||
if (debug) {
|
||||
LOG.debug("Using basedir=" + baseDir.getAbsolutePath());
|
||||
}
|
||||
return baseDir;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "PropsFile=" + absPath;
|
||||
}
|
||||
|
||||
public void setDebug(boolean debug) {
|
||||
this.debug = debug;
|
||||
}
|
||||
|
||||
public boolean isDebug() {
|
||||
return debug;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For test-usage only.
|
||||
*/
|
||||
public static void resetUsersAndGroupsCache() {
|
||||
staticCache.clear();
|
||||
}
|
||||
}
|
|
@ -16,11 +16,11 @@
|
|||
*/
|
||||
package org.apache.activemq.jaas;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
|
@ -36,80 +36,30 @@ import javax.security.auth.spi.LoginModule;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class PropertiesLoginModule implements LoginModule {
|
||||
public class PropertiesLoginModule extends PropertiesLoader implements LoginModule {
|
||||
|
||||
private static final String USER_FILE = "org.apache.activemq.jaas.properties.user";
|
||||
private static final String GROUP_FILE = "org.apache.activemq.jaas.properties.group";
|
||||
private static final String USER_FILE_PROP_NAME = "org.apache.activemq.jaas.properties.user";
|
||||
private static final String GROUP_FILE_PROP_NAME = "org.apache.activemq.jaas.properties.group";
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(PropertiesLoginModule.class);
|
||||
|
||||
private Subject subject;
|
||||
private CallbackHandler callbackHandler;
|
||||
|
||||
private boolean debug;
|
||||
private boolean reload = false;
|
||||
private static volatile PrincipalProperties users;
|
||||
private static volatile PrincipalProperties groups;
|
||||
private Properties users;
|
||||
private Properties groups;
|
||||
private String user;
|
||||
private final Set<Principal> principals = new HashSet<Principal>();
|
||||
private File baseDir;
|
||||
private boolean loginSucceeded;
|
||||
private boolean decrypt = true;
|
||||
|
||||
@Override
|
||||
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
|
||||
this.subject = subject;
|
||||
this.callbackHandler = callbackHandler;
|
||||
loginSucceeded = false;
|
||||
|
||||
debug = "true".equalsIgnoreCase((String) options.get("debug"));
|
||||
if (options.get("reload") != null) {
|
||||
reload = "true".equalsIgnoreCase((String) options.get("reload"));
|
||||
}
|
||||
|
||||
if (options.get("baseDir") != null) {
|
||||
baseDir = new File((String) options.get("baseDir"));
|
||||
}
|
||||
|
||||
setBaseDir();
|
||||
String usersFile = (String) options.get(USER_FILE) + "";
|
||||
File uf = baseDir != null ? new File(baseDir, usersFile) : new File(usersFile);
|
||||
|
||||
if (reload || users == null || uf.lastModified() > users.getReloadTime()) {
|
||||
if (debug) {
|
||||
LOG.debug("Reloading users from " + uf.getAbsolutePath());
|
||||
}
|
||||
users = new PrincipalProperties("user", uf, LOG);
|
||||
if( decrypt ) {
|
||||
try {
|
||||
EncryptionSupport.decrypt(users.getPrincipals());
|
||||
} catch(NoClassDefFoundError e) {
|
||||
// this Happens whe jasypt is not on the classpath..
|
||||
decrypt = false;
|
||||
LOG.info("jasypt is not on the classpath: password decryption disabled.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String groupsFile = (String) options.get(GROUP_FILE) + "";
|
||||
File gf = baseDir != null ? new File(baseDir, groupsFile) : new File(groupsFile);
|
||||
if (reload || groups == null || gf.lastModified() > groups.getReloadTime()) {
|
||||
if (debug) {
|
||||
LOG.debug("Reloading groups from " + gf.getAbsolutePath());
|
||||
}
|
||||
groups = new PrincipalProperties("group", gf, LOG);
|
||||
}
|
||||
}
|
||||
|
||||
private void setBaseDir() {
|
||||
if (baseDir == null) {
|
||||
if (System.getProperty("java.security.auth.login.config") != null) {
|
||||
baseDir = new File(System.getProperty("java.security.auth.login.config")).getParentFile();
|
||||
if (debug) {
|
||||
LOG.debug("Using basedir=" + baseDir.getAbsolutePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
init(options);
|
||||
users = load(USER_FILE_PROP_NAME, "user", options).getProps();
|
||||
groups = load(GROUP_FILE_PROP_NAME, "group", options).getProps();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -155,9 +105,9 @@ public class PropertiesLoginModule implements LoginModule {
|
|||
if (result) {
|
||||
principals.add(new UserPrincipal(user));
|
||||
|
||||
for (Map.Entry<String, String> entry : groups.entries()) {
|
||||
String name = entry.getKey();
|
||||
String[] userList = entry.getValue().split(",");
|
||||
for (Map.Entry<Object, Object> entry : groups.entrySet()) {
|
||||
String name = (String) entry.getKey();
|
||||
String[] userList = ((String)entry.getValue()).split(",");
|
||||
for (int i = 0; i < userList.length; i++) {
|
||||
if (user.equals(userList[i])) {
|
||||
principals.add(new GroupPrincipal(name));
|
||||
|
@ -204,11 +154,4 @@ public class PropertiesLoginModule implements LoginModule {
|
|||
loginSucceeded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* For test-usage only.
|
||||
*/
|
||||
static void resetUsersAndGroupsCache() {
|
||||
users = null;
|
||||
groups = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* 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.jaas;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class ReloadableProperties {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ReloadableProperties.class);
|
||||
|
||||
private Properties props = new Properties();
|
||||
private Map<String, String> invertedProps;
|
||||
private long reloadTime = -1;
|
||||
private final PropertiesLoader.FileNameKey key;
|
||||
|
||||
public ReloadableProperties(PropertiesLoader.FileNameKey key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public synchronized Properties getProps() {
|
||||
return props;
|
||||
}
|
||||
|
||||
public synchronized ReloadableProperties obtained() {
|
||||
if (reloadTime < 0 || (key.isReload() && hasModificationAfter(reloadTime))) {
|
||||
props = new Properties();
|
||||
try {
|
||||
load(key.file(), props);
|
||||
invertedProps = null;
|
||||
if (key.isDebug()) {
|
||||
LOG.debug("Load of: " + key);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
LOG.error("Failed to load: " + key + ", reason:" + e.getLocalizedMessage());
|
||||
if (key.isDebug()) {
|
||||
LOG.debug("Load of: " + key + ", failure exception" + e);
|
||||
}
|
||||
}
|
||||
reloadTime = System.currentTimeMillis();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public synchronized Map<String, String> invertedPropertiesMap() {
|
||||
if (invertedProps == null) {
|
||||
invertedProps = new HashMap<>(props.size());
|
||||
for (Map.Entry<Object, Object> val : props.entrySet()) {
|
||||
invertedProps.put((String) val.getValue(), (String) val.getKey());
|
||||
}
|
||||
}
|
||||
return invertedProps;
|
||||
}
|
||||
|
||||
private void load(final File source, Properties props) throws IOException {
|
||||
FileInputStream in = new FileInputStream(source);
|
||||
try {
|
||||
props.load(in);
|
||||
if (key.isDecrypt()) {
|
||||
try {
|
||||
EncryptionSupport.decrypt(this.props);
|
||||
} catch (NoClassDefFoundError e) {
|
||||
// this Happens whe jasypt is not on the classpath..
|
||||
key.setDecrypt(false);
|
||||
LOG.info("jasypt is not on the classpath: password decryption disabled.");
|
||||
}
|
||||
}
|
||||
|
||||
} finally {
|
||||
in.close();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasModificationAfter(long reloadTime) {
|
||||
return key.file.lastModified() > reloadTime;
|
||||
}
|
||||
|
||||
}
|
|
@ -17,8 +17,6 @@
|
|||
|
||||
package org.apache.activemq.jaas;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
|
@ -45,12 +43,11 @@ import javax.security.auth.login.LoginException;
|
|||
*/
|
||||
public class TextFileCertificateLoginModule extends CertificateLoginModule {
|
||||
|
||||
private static final String USER_FILE = "org.apache.activemq.jaas.textfiledn.user";
|
||||
private static final String GROUP_FILE = "org.apache.activemq.jaas.textfiledn.group";
|
||||
private static final String USER_FILE_PROP_NAME = "org.apache.activemq.jaas.textfiledn.user";
|
||||
private static final String GROUP_FILE_PROP_NAME = "org.apache.activemq.jaas.textfiledn.group";
|
||||
|
||||
private File baseDir;
|
||||
private String usersFilePathname;
|
||||
private String groupsFilePathname;
|
||||
private Properties groups;
|
||||
private Map<String, String> usersByDn;
|
||||
|
||||
/**
|
||||
* Performs initialization of file paths. A standard JAAS override.
|
||||
|
@ -58,14 +55,9 @@ public class TextFileCertificateLoginModule extends CertificateLoginModule {
|
|||
@Override
|
||||
public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) {
|
||||
super.initialize(subject, callbackHandler, sharedState, options);
|
||||
if (System.getProperty("java.security.auth.login.config") != null) {
|
||||
baseDir = new File(System.getProperty("java.security.auth.login.config")).getParentFile();
|
||||
} else {
|
||||
baseDir = new File(".");
|
||||
}
|
||||
|
||||
usersFilePathname = (String)options.get(USER_FILE) + "";
|
||||
groupsFilePathname = (String)options.get(GROUP_FILE) + "";
|
||||
usersByDn = load(USER_FILE_PROP_NAME, "", options).invertedPropertiesMap();
|
||||
groups = load(GROUP_FILE_PROP_NAME, "", options).getProps();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,28 +76,7 @@ public class TextFileCertificateLoginModule extends CertificateLoginModule {
|
|||
throw new LoginException("Client certificates not found. Cannot authenticate.");
|
||||
}
|
||||
|
||||
File usersFile = new File(baseDir, usersFilePathname);
|
||||
|
||||
Properties users = new Properties();
|
||||
|
||||
try(java.io.FileInputStream in = new java.io.FileInputStream(usersFile)) {
|
||||
users.load(in);
|
||||
} catch (IOException ioe) {
|
||||
throw new LoginException("Unable to load user properties file " + usersFile);
|
||||
}
|
||||
|
||||
String dn = getDistinguishedName(certs);
|
||||
|
||||
Enumeration<Object> keys = users.keys();
|
||||
for (Enumeration<Object> vals = users.elements(); vals.hasMoreElements();) {
|
||||
if (((String)vals.nextElement()).equals(dn)) {
|
||||
return (String)keys.nextElement();
|
||||
} else {
|
||||
keys.nextElement();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return usersByDn.get(getDistinguishedName(certs));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,16 +89,6 @@ public class TextFileCertificateLoginModule extends CertificateLoginModule {
|
|||
*/
|
||||
@Override
|
||||
protected Set<String> getUserGroups(String username) throws LoginException {
|
||||
File groupsFile = new File(baseDir, groupsFilePathname);
|
||||
|
||||
Properties groups = new Properties();
|
||||
try {
|
||||
java.io.FileInputStream in = new java.io.FileInputStream(groupsFile);
|
||||
groups.load(in);
|
||||
in.close();
|
||||
} catch (IOException ioe) {
|
||||
throw new LoginException("Unable to load group properties file " + groupsFile);
|
||||
}
|
||||
Set<String> userGroups = new HashSet<String>();
|
||||
for (Enumeration<Object> enumeration = groups.keys(); enumeration.hasMoreElements();) {
|
||||
String groupName = (String)enumeration.nextElement();
|
||||
|
|
|
@ -121,7 +121,7 @@ public class PropertiesLoginModuleRaceConditionTest {
|
|||
public void after() throws InterruptedException {
|
||||
pool.shutdown();
|
||||
assertTrue(pool.awaitTermination(500, TimeUnit.SECONDS));
|
||||
PropertiesLoginModule.resetUsersAndGroupsCache();
|
||||
PropertiesLoader.resetUsersAndGroupsCache();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* 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.net.URL;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.HashMap;
|
||||
import javax.management.remote.JMXPrincipal;
|
||||
import javax.security.auth.Subject;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import org.apache.activemq.jaas.CertificateLoginModule;
|
||||
import org.apache.activemq.jaas.JaasCertificateCallbackHandler;
|
||||
import org.apache.activemq.jaas.PropertiesLoader;
|
||||
import org.apache.activemq.jaas.TextFileCertificateLoginModule;
|
||||
import org.apache.activemq.transport.tcp.StubX509Certificate;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class TextFileCertificateLoginModuleTest {
|
||||
|
||||
private static final String CERT_USERS_FILE_SMALL = "cert-users-SMALL.properties";
|
||||
private static final String CERT_USERS_FILE_LARGE = "cert-users-LARGE.properties";
|
||||
private static final String CERT_GROUPS_FILE = "cert-groups.properties";
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(TextFileCertificateLoginModuleTest.class);
|
||||
private static final int NUMBER_SUBJECTS = 10;
|
||||
|
||||
static {
|
||||
String path = System.getProperty("java.security.auth.login.config");
|
||||
if (path == null) {
|
||||
URL resource = TextFileCertificateLoginModuleTest.class.getClassLoader().getResource("login.config");
|
||||
if (resource != null) {
|
||||
path = resource.getFile();
|
||||
System.setProperty("java.security.auth.login.config", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CertificateLoginModule loginModule;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
loginModule = new TextFileCertificateLoginModule();
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
PropertiesLoader.resetUsersAndGroupsCache();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginWithSMALLUsersFile() throws Exception {
|
||||
loginTest(CERT_USERS_FILE_SMALL, CERT_GROUPS_FILE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoginWithLARGEUsersFile() throws Exception {
|
||||
loginTest(CERT_USERS_FILE_LARGE, CERT_GROUPS_FILE);
|
||||
}
|
||||
|
||||
private void loginTest(String usersFiles, String groupsFile) throws LoginException {
|
||||
|
||||
HashMap options = new HashMap<String, String>();
|
||||
options.put("org.apache.activemq.jaas.textfiledn.user", usersFiles);
|
||||
options.put("org.apache.activemq.jaas.textfiledn.group", groupsFile);
|
||||
options.put("reload", "true");
|
||||
|
||||
JaasCertificateCallbackHandler[] callbackHandlers = new JaasCertificateCallbackHandler[NUMBER_SUBJECTS];
|
||||
Subject[] subjects = new Subject[NUMBER_SUBJECTS];
|
||||
|
||||
for (int i = 0; i < callbackHandlers.length; i++) {
|
||||
callbackHandlers[i] = getJaasCertificateCallbackHandler("DN=TEST_USER_" + (i + 1));
|
||||
}
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
for (int outer=0; outer<500;outer++) {
|
||||
for (int i = 0; i < NUMBER_SUBJECTS; i++) {
|
||||
Subject subject = doAuthenticate(options, callbackHandlers[i]);
|
||||
subjects[i] = subject;
|
||||
}
|
||||
}
|
||||
|
||||
long endTime = System.currentTimeMillis();
|
||||
long timeTaken = endTime - startTime;
|
||||
|
||||
|
||||
for (int i = 0; i < NUMBER_SUBJECTS; i++) {
|
||||
LOG.info("subject is: " + subjects[i].getPrincipals().toString());
|
||||
}
|
||||
|
||||
LOG.info(usersFiles + ": Time taken is " + timeTaken);
|
||||
|
||||
}
|
||||
|
||||
private JaasCertificateCallbackHandler getJaasCertificateCallbackHandler(String user) {
|
||||
JMXPrincipal principal = new JMXPrincipal(user);
|
||||
X509Certificate cert = new StubX509Certificate(principal);
|
||||
return new JaasCertificateCallbackHandler(new X509Certificate[]{cert});
|
||||
}
|
||||
|
||||
private Subject doAuthenticate(HashMap options, JaasCertificateCallbackHandler callbackHandler) throws LoginException {
|
||||
Subject mySubject = new Subject();
|
||||
loginModule.initialize(mySubject, callbackHandler, null, options);
|
||||
loginModule.login();
|
||||
loginModule.commit();
|
||||
return mySubject;
|
||||
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,100 @@
|
|||
1CN=TEST0000001, OU=TEST, O=TEST TEST TEST1 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
2CN=TEST0000001, OU=TEST, O=TEST TEST TEST2 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
3CN=TEST0000001, OU=TEST, O=TEST TEST TEST3 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
4CN=TEST0000001, OU=TEST, O=TEST TEST TEST4 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
5CN=TEST0000001, OU=TEST, O=TEST TEST TEST5 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
6CN=TEST0000001, OU=TEST, O=TEST TEST TEST6 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
7CN=TEST0000001, OU=TEST, O=TEST TEST TEST7 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
8CN=TEST0000001, OU=TEST, O=TEST TEST TEST8 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
9CN=TEST0000001, OU=TEST, O=TEST TEST TEST9 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
10CN=TEST0000001, OU=TEST, O=TEST TEST TEST10 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
11CN=TEST0000001, OU=TEST, O=TEST TEST TEST11 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
12CN=TEST0000001, OU=TEST, O=TEST TEST TEST12 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
13CN=TEST0000001, OU=TEST, O=TEST TEST TEST13 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
14CN=TEST0000001, OU=TEST, O=TEST TEST TEST14 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
15CN=TEST0000001, OU=TEST, O=TEST TEST TEST15 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
16CN=TEST0000001, OU=TEST, O=TEST TEST TEST16 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
17CN=TEST0000001, OU=TEST, O=TEST TEST TEST17 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
18CN=TEST0000001, OU=TEST, O=TEST TEST TEST18 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
19CN=TEST0000001, OU=TEST, O=TEST TEST TEST19 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
20CN=TEST0000001, OU=TEST, O=TEST TEST TEST20 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
21CN=TEST0000001, OU=TEST, O=TEST TEST TEST21 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
22CN=TEST0000001, OU=TEST, O=TEST TEST TEST22 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
23CN=TEST0000001, OU=TEST, O=TEST TEST TEST23 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
24CN=TEST0000001, OU=TEST, O=TEST TEST TEST24 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
25CN=TEST0000001, OU=TEST, O=TEST TEST TEST25 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
26CN=TEST0000001, OU=TEST, O=TEST TEST TEST26 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
27CN=TEST0000001, OU=TEST, O=TEST TEST TEST27 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
28CN=TEST0000001, OU=TEST, O=TEST TEST TEST28 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
29CN=TEST0000001, OU=TEST, O=TEST TEST TEST29 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
30CN=TEST0000001, OU=TEST, O=TEST TEST TEST30 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
31CN=TEST0000001, OU=TEST, O=TEST TEST TEST31 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
32CN=TEST0000001, OU=TEST, O=TEST TEST TEST32 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
33CN=TEST0000001, OU=TEST, O=TEST TEST TEST33 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
34CN=TEST0000001, OU=TEST, O=TEST TEST TEST34 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
35CN=TEST0000001, OU=TEST, O=TEST TEST TEST35 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
36CN=TEST0000001, OU=TEST, O=TEST TEST TEST36 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
37CN=TEST0000001, OU=TEST, O=TEST TEST TEST37 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
38CN=TEST0000001, OU=TEST, O=TEST TEST TEST38 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
39CN=TEST0000001, OU=TEST, O=TEST TEST TEST39 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
40CN=TEST0000001, OU=TEST, O=TEST TEST TEST40 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
41CN=TEST0000001, OU=TEST, O=TEST TEST TEST41 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
42CN=TEST0000001, OU=TEST, O=TEST TEST TEST42 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
43CN=TEST0000001, OU=TEST, O=TEST TEST TEST43 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
44CN=TEST0000001, OU=TEST, O=TEST TEST TEST44 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
45CN=TEST0000001, OU=TEST, O=TEST TEST TEST45 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
46CN=TEST0000001, OU=TEST, O=TEST TEST TEST46 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
47CN=TEST0000001, OU=TEST, O=TEST TEST TEST47 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
48CN=TEST0000001, OU=TEST, O=TEST TEST TEST48 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
49CN=TEST0000001, OU=TEST, O=TEST TEST TEST49 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
50CN=TEST0000001, OU=TEST, O=TEST TEST TEST50 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
51CN=TEST0000001, OU=TEST, O=TEST TEST TEST51 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
52CN=TEST0000001, OU=TEST, O=TEST TEST TEST52 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
53CN=TEST0000001, OU=TEST, O=TEST TEST TEST53 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
54CN=TEST0000001, OU=TEST, O=TEST TEST TEST54 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
55CN=TEST0000001, OU=TEST, O=TEST TEST TEST55 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
56CN=TEST0000001, OU=TEST, O=TEST TEST TEST56 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
57CN=TEST0000001, OU=TEST, O=TEST TEST TEST57 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
58CN=TEST0000001, OU=TEST, O=TEST TEST TEST58 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
59CN=TEST0000001, OU=TEST, O=TEST TEST TEST59 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
60CN=TEST0000001, OU=TEST, O=TEST TEST TEST60 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
61CN=TEST0000001, OU=TEST, O=TEST TEST TEST61 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
62CN=TEST0000001, OU=TEST, O=TEST TEST TEST62 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
63CN=TEST0000001, OU=TEST, O=TEST TEST TEST63 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
64CN=TEST0000001, OU=TEST, O=TEST TEST TEST64 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
65CN=TEST0000001, OU=TEST, O=TEST TEST TEST65 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
66CN=TEST0000001, OU=TEST, O=TEST TEST TEST66 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
67CN=TEST0000001, OU=TEST, O=TEST TEST TEST67 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
68CN=TEST0000001, OU=TEST, O=TEST TEST TEST68 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
69CN=TEST0000001, OU=TEST, O=TEST TEST TEST69 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
70CN=TEST0000001, OU=TEST, O=TEST TEST TEST70 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
71CN=TEST0000001, OU=TEST, O=TEST TEST TEST71 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
72CN=TEST0000001, OU=TEST, O=TEST TEST TEST72 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
73CN=TEST0000001, OU=TEST, O=TEST TEST TEST73 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
74CN=TEST0000001, OU=TEST, O=TEST TEST TEST74 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
75CN=TEST0000001, OU=TEST, O=TEST TEST TEST75 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
76CN=TEST0000001, OU=TEST, O=TEST TEST TEST76 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
77CN=TEST0000001, OU=TEST, O=TEST TEST TEST77 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
78CN=TEST0000001, OU=TEST, O=TEST TEST TEST78 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
79CN=TEST0000001, OU=TEST, O=TEST TEST TEST79 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
80CN=TEST0000001, OU=TEST, O=TEST TEST TEST80 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
81CN=TEST0000001, OU=TEST, O=TEST TEST TEST81 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
82CN=TEST0000001, OU=TEST, O=TEST TEST TEST82 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
83CN=TEST0000001, OU=TEST, O=TEST TEST TEST83 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
84CN=TEST0000001, OU=TEST, O=TEST TEST TEST84 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
85CN=TEST0000001, OU=TEST, O=TEST TEST TEST85 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
86CN=TEST0000001, OU=TEST, O=TEST TEST TEST86 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
87CN=TEST0000001, OU=TEST, O=TEST TEST TEST87 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
88CN=TEST0000001, OU=TEST, O=TEST TEST TEST88 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
89CN=TEST0000001, OU=TEST, O=TEST TEST TEST89 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
90CN=TEST0000001, OU=TEST, O=TEST TEST TEST90 TEST TEST TEST TEST TEST TEST, L=TEST, ST=TEST, C=GB
|
||||
10001CN=DN=TEST_USER_1
|
||||
10002CN=DN=TEST_USER_2
|
||||
10003CN=DN=TEST_USER_3
|
||||
10004CN=DN=TEST_USER_4
|
||||
10005CN=DN=TEST_USER_5
|
||||
10006CN=DN=TEST_USER_6
|
||||
10007CN=DN=TEST_USER_7
|
||||
10008CN=DN=TEST_USER_8
|
||||
10009CN=DN=TEST_USER_9
|
||||
10010CN=DN=TEST_USER_10
|
Loading…
Reference in New Issue