ARTEMIS-4028 - add alder32 checksum to the status of properties files read by the broker
This commit is contained in:
parent
03ef286cc8
commit
3b981b3920
|
@ -63,7 +63,7 @@ public class FluentPropertyBeanIntrospectorWithIgnores extends FluentPropertyBea
|
|||
pd.setWriteMethod(m);
|
||||
}
|
||||
} catch (IntrospectionException e) {
|
||||
logger.debug(e.getMessage(), e);
|
||||
logger.trace("error for property named {}", propertyName, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -409,6 +409,21 @@ public final class JsonUtil {
|
|||
return jsonObjectBuilder.build();
|
||||
}
|
||||
|
||||
// component path, may contain x/y/z as a pointer to a nested object
|
||||
public static JsonObjectBuilder objectBuilderWithValueAtPath(String componentPath, JsonValue componentStatus) {
|
||||
JsonObjectBuilder jsonObjectBuilder = JsonLoader.createObjectBuilder();
|
||||
String[] nestedComponents = componentPath.split("/", 0);
|
||||
// may need to nest this status in objects
|
||||
for (int i = nestedComponents.length - 1; i > 0; i--) {
|
||||
JsonObjectBuilder nestedBuilder = JsonLoader.createObjectBuilder();
|
||||
nestedBuilder.add(nestedComponents[i], componentStatus);
|
||||
componentStatus = nestedBuilder.build();
|
||||
}
|
||||
jsonObjectBuilder.add(nestedComponents[0], componentStatus);
|
||||
return jsonObjectBuilder;
|
||||
}
|
||||
|
||||
|
||||
private static class NullableJsonString implements JsonValue, JsonString {
|
||||
|
||||
private final String value;
|
||||
|
|
|
@ -212,4 +212,23 @@ public class JsonUtilTest {
|
|||
|
||||
Assert.assertEquals(sourceTwo, JsonUtil.mergeAndUpdate(sourceOne, sourceTwo));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuilderWithValueAtPath() {
|
||||
|
||||
JsonObjectBuilder jsonObjectBuilder = JsonLoader.createObjectBuilder();
|
||||
JsonUtil.addToObject("x", "y", jsonObjectBuilder);
|
||||
JsonObject target = jsonObjectBuilder.build();
|
||||
|
||||
JsonObjectBuilder nested = JsonUtil.objectBuilderWithValueAtPath("a/b/c", target);
|
||||
JsonObject inserted = nested.build();
|
||||
Assert.assertTrue(inserted.containsKey("a"));
|
||||
|
||||
Assert.assertEquals(target, inserted.getJsonObject("a").getJsonObject("b").getJsonObject("c"));
|
||||
|
||||
nested = JsonUtil.objectBuilderWithValueAtPath("c", target);
|
||||
inserted = nested.build();
|
||||
Assert.assertTrue(inserted.containsKey("c"));
|
||||
Assert.assertEquals(target, inserted.getJsonObject("c"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.lang.reflect.InvocationTargetException;
|
|||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedExceptionAction;
|
||||
import java.util.ArrayList;
|
||||
|
@ -123,6 +124,9 @@ import org.apache.commons.beanutils.expression.DefaultResolver;
|
|||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.zip.Adler32;
|
||||
import java.util.zip.Checksum;
|
||||
|
||||
import org.apache.commons.beanutils.expression.Resolver;
|
||||
|
||||
public class ConfigurationImpl implements Configuration, Serializable {
|
||||
|
@ -411,7 +415,8 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
* Parent folder for all data folders.
|
||||
*/
|
||||
private File artemisInstance;
|
||||
private transient volatile JsonObject status = JsonLoader.createObjectBuilder().build();
|
||||
private transient JsonObject status = JsonLoader.createObjectBuilder().build();
|
||||
private final transient Checksum checksum = new Adler32();
|
||||
|
||||
@Override
|
||||
public String getJournalRetentionDirectory() {
|
||||
|
@ -501,15 +506,16 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
try (FileInputStream fileInputStream = new FileInputStream(new File(dir, fileName)); BufferedInputStream reader = new BufferedInputStream(fileInputStream)) {
|
||||
brokerProperties.clear();
|
||||
brokerProperties.load(reader);
|
||||
parsePrefixedProperties(brokerProperties, null);
|
||||
parsePrefixedProperties(fileName, brokerProperties, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try (FileInputStream fileInputStream = new FileInputStream(fileUrl); BufferedInputStream reader = new BufferedInputStream(fileInputStream)) {
|
||||
File file = new File(fileUrl);
|
||||
try (FileInputStream fileInputStream = new FileInputStream(file); BufferedInputStream reader = new BufferedInputStream(fileInputStream)) {
|
||||
brokerProperties.load(reader);
|
||||
parsePrefixedProperties(brokerProperties, null);
|
||||
parsePrefixedProperties(file.getName(), brokerProperties, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -519,9 +525,14 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
}
|
||||
|
||||
public void parsePrefixedProperties(Properties properties, String prefix) throws Exception {
|
||||
Map<String, Object> beanProperties = new LinkedHashMap<>();
|
||||
parsePrefixedProperties("system", properties, prefix);
|
||||
}
|
||||
|
||||
public void parsePrefixedProperties(String name, Properties properties, String prefix) throws Exception {
|
||||
Map<String, Object> beanProperties = new LinkedHashMap<>();
|
||||
long alder32Hash = 0;
|
||||
synchronized (properties) {
|
||||
checksum.reset();
|
||||
String key = null;
|
||||
for (Map.Entry<Object, Object> entry : properties.entrySet()) {
|
||||
key = entry.getKey().toString();
|
||||
|
@ -531,53 +542,37 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
}
|
||||
key = entry.getKey().toString().substring(prefix.length());
|
||||
}
|
||||
String value = XMLUtil.replaceSystemPropsInString(entry.getValue().toString());
|
||||
String value = entry.getValue().toString();
|
||||
|
||||
checksum.update(key.getBytes(StandardCharsets.UTF_8));
|
||||
checksum.update('=');
|
||||
checksum.update(value.getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
value = XMLUtil.replaceSystemPropsInString(value);
|
||||
value = PasswordMaskingUtil.resolveMask(isMaskPassword(), value, getPasswordCodec());
|
||||
key = XMLUtil.replaceSystemPropsInString(key);
|
||||
logger.debug("Property config, {}={}", key, value);
|
||||
beanProperties.put(key, value);
|
||||
}
|
||||
alder32Hash = checksum.getValue();
|
||||
}
|
||||
updateReadPropertiesStatus(name, alder32Hash);
|
||||
|
||||
if (!beanProperties.isEmpty()) {
|
||||
populateWithProperties(beanProperties);
|
||||
populateWithProperties(name, beanProperties);
|
||||
}
|
||||
}
|
||||
|
||||
public void populateWithProperties(Map<String, Object> beanProperties) throws InvocationTargetException, IllegalAccessException {
|
||||
public void populateWithProperties(final String propsId, Map<String, Object> beanProperties) throws InvocationTargetException, IllegalAccessException {
|
||||
CollectionAutoFillPropertiesUtil autoFillCollections = new CollectionAutoFillPropertiesUtil();
|
||||
BeanUtilsBean beanUtils = new BeanUtilsBean(new ConvertUtilsBean(), autoFillCollections) {
|
||||
// override to treat missing properties as errors, not skip as the default impl does
|
||||
@Override
|
||||
public void setProperty(final Object bean, String name, final Object value) throws InvocationTargetException, IllegalAccessException {
|
||||
{
|
||||
if (logger.isTraceEnabled()) {
|
||||
final StringBuilder sb = new StringBuilder(" setProperty(");
|
||||
sb.append(bean);
|
||||
sb.append(", ");
|
||||
sb.append(name);
|
||||
sb.append(", ");
|
||||
if (value == null) {
|
||||
sb.append("<NULL>");
|
||||
} else if (value instanceof String) {
|
||||
sb.append((String) value);
|
||||
} else if (value instanceof String[]) {
|
||||
final String[] values = (String[]) value;
|
||||
sb.append('[');
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(',');
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("setProperty on {}, name: {}, value: {}", bean.getClass(), name, value);
|
||||
}
|
||||
sb.append(values[i]);
|
||||
}
|
||||
sb.append(']');
|
||||
} else {
|
||||
sb.append(value.toString());
|
||||
}
|
||||
sb.append(')');
|
||||
logger.trace(sb.toString());
|
||||
}
|
||||
|
||||
// Resolve any nested expression to get the actual target bean
|
||||
Object target = bean;
|
||||
final Resolver resolver = getPropertyUtils().getResolver();
|
||||
|
@ -592,10 +587,7 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
throw new InvocationTargetException(e, "No getter for property:" + name + ", on: " + bean);
|
||||
}
|
||||
}
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace(" Target bean = " + target);
|
||||
logger.trace(" Target name = " + name);
|
||||
}
|
||||
logger.trace("resolved target, bean: {}, name: {}", target.getClass(), name);
|
||||
|
||||
// Declare local variables we will require
|
||||
final String propName = resolver.getProperty(name); // Simple name of target property
|
||||
|
@ -746,7 +738,7 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
|
||||
BeanSupport.customise(beanUtils);
|
||||
|
||||
logger.debug("populate:" + this + ", " + beanProperties);
|
||||
logger.trace("populate: bean: {} with {}", this, beanProperties);
|
||||
|
||||
HashMap<String, String> errors = new HashMap<>();
|
||||
// Loop through the property name/value pairs to be set
|
||||
|
@ -757,7 +749,7 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
// Perform the assignment for this property
|
||||
beanUtils.setProperty(this, name, entry.getValue());
|
||||
} catch (InvocationTargetException invocationTargetException) {
|
||||
logger.trace("failed to populate property key: " + name, invocationTargetException);
|
||||
logger.trace("failed to populate property with key: {}", name, invocationTargetException);
|
||||
Throwable toLog = invocationTargetException;
|
||||
if (invocationTargetException.getCause() != null) {
|
||||
toLog = invocationTargetException.getCause();
|
||||
|
@ -768,23 +760,28 @@ public class ConfigurationImpl implements Configuration, Serializable {
|
|||
trackError(errors, entry, oops);
|
||||
}
|
||||
}
|
||||
updateStatus(errors);
|
||||
updateApplyStatus(propsId, errors);
|
||||
}
|
||||
|
||||
private void trackError(HashMap<String, String> errors, Map.Entry<String,?> entry, Throwable oops) {
|
||||
logger.debug("failed to populate property entry(" + entry.toString() + "), reason: " + oops.getLocalizedMessage(), oops);
|
||||
logger.debug("failed to populate property entry({}), reason: {}", entry, oops);
|
||||
errors.put(entry.toString(), oops.getLocalizedMessage());
|
||||
}
|
||||
|
||||
private void updateStatus(HashMap<String, String> errors) {
|
||||
|
||||
JsonArrayBuilder errorsObjectArray = JsonLoader.createArrayBuilder();
|
||||
private synchronized void updateApplyStatus(String propsId, HashMap<String, String> errors) {
|
||||
JsonArrayBuilder errorsObjectArrayBuilder = JsonLoader.createArrayBuilder();
|
||||
for (Map.Entry<String, String> entry : errors.entrySet()) {
|
||||
errorsObjectArray.add(JsonLoader.createObjectBuilder().add("value", entry.getKey()).add("reason", entry.getValue()));
|
||||
errorsObjectArrayBuilder.add(JsonLoader.createObjectBuilder().add("value", entry.getKey()).add("reason", entry.getValue()));
|
||||
}
|
||||
JsonObjectBuilder jsonObjectBuilder =
|
||||
JsonUtil.objectBuilderWithValueAtPath("properties/" + propsId + "/errors", errorsObjectArrayBuilder.build());
|
||||
status = JsonUtil.mergeAndUpdate(status, jsonObjectBuilder.build());
|
||||
}
|
||||
JsonObjectBuilder jsonObjectBuilder = JsonLoader.createObjectBuilder();
|
||||
jsonObjectBuilder.add("properties", JsonLoader.createObjectBuilder().add("errors", errorsObjectArray));
|
||||
|
||||
private synchronized void updateReadPropertiesStatus(String propsId, long alder32Hash) {
|
||||
JsonObjectBuilder propertiesReadStatusBuilder = JsonLoader.createObjectBuilder();
|
||||
propertiesReadStatusBuilder.add("alder32", String.valueOf(alder32Hash));
|
||||
JsonObjectBuilder jsonObjectBuilder = JsonUtil.objectBuilderWithValueAtPath("properties/" + propsId, propertiesReadStatusBuilder.build());
|
||||
status = JsonUtil.mergeAndUpdate(status, jsonObjectBuilder.build());
|
||||
}
|
||||
|
||||
|
|
|
@ -483,7 +483,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
|
|||
|
||||
this.serviceRegistry = serviceRegistry == null ? new ServiceRegistryImpl() : serviceRegistry;
|
||||
|
||||
this.serverStatus = new ServerStatus(this);
|
||||
this.serverStatus = ServerStatus.getInstanceFor(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -628,7 +628,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
|
|||
}
|
||||
|
||||
configuration.parseProperties(propertiesFileUrl);
|
||||
updateStatus("configuration", configuration.getStatus());
|
||||
updateStatus(ServerStatus.CONFIGURATION_COMPONENT, configuration.getStatus());
|
||||
|
||||
initializeExecutorServices();
|
||||
|
||||
|
@ -4402,7 +4402,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
|
|||
configurationReloadDeployed.set(false);
|
||||
if (isActive()) {
|
||||
configuration.parseProperties(propertiesFileUrl);
|
||||
updateStatus("configuration", configuration.getStatus());
|
||||
updateStatus(ServerStatus.CONFIGURATION_COMPONENT, configuration.getStatus());
|
||||
deployReloadableConfigFromConfiguration();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,21 +28,35 @@ import org.apache.activemq.artemis.utils.JsonLoader;
|
|||
|
||||
public class ServerStatus {
|
||||
|
||||
private final ActiveMQServerImpl server;
|
||||
public static final String SERVER_COMPONENT = "server";
|
||||
public static final String CONFIGURATION_COMPONENT = "configuration";
|
||||
public static final String JAAS_COMPONENT = SERVER_COMPONENT + "/jaas";
|
||||
|
||||
private static final ServerStatus instance = new ServerStatus();
|
||||
|
||||
public static synchronized ServerStatus getInstanceFor(ActiveMQServerImpl activeMQServer) {
|
||||
if (instance.server == null) {
|
||||
instance.server = activeMQServer;
|
||||
instance.immutableStateValues.put("version", instance.server.getVersion().getFullVersion());
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static synchronized ServerStatus getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
private ActiveMQServerImpl server;
|
||||
private final HashMap<String, String> immutableStateValues = new HashMap<>();
|
||||
private JsonObject globalStatus = JsonLoader.createObjectBuilder().build();
|
||||
|
||||
public ServerStatus(ActiveMQServerImpl activeMQServer) {
|
||||
this.server = activeMQServer;
|
||||
immutableStateValues.put("version", server.getVersion().getFullVersion());
|
||||
}
|
||||
|
||||
public synchronized String asJson() {
|
||||
updateServerStatus();
|
||||
return globalStatus.toString();
|
||||
}
|
||||
|
||||
private synchronized void updateServerStatus() {
|
||||
if (instance.server != null) {
|
||||
HashMap<String, String> snapshotOfServerStatusAttributes = new HashMap<>();
|
||||
snapshotOfServerStatusAttributes.putAll(immutableStateValues);
|
||||
snapshotOfServerStatusAttributes.put("identity", server.getIdentity());
|
||||
|
@ -51,18 +65,20 @@ public class ServerStatus {
|
|||
snapshotOfServerStatusAttributes.put("uptime", server.getUptime());
|
||||
snapshotOfServerStatusAttributes.put("state", server.getState().toString());
|
||||
|
||||
update("server", JsonUtil.toJsonObject(snapshotOfServerStatusAttributes));
|
||||
update(SERVER_COMPONENT, JsonUtil.toJsonObject(snapshotOfServerStatusAttributes));
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void update(String component, String statusJson) {
|
||||
JsonObjectBuilder jsonObjectBuilder = JsonLoader.createObjectBuilder();
|
||||
jsonObjectBuilder.add(component, JsonUtil.readJsonObject(statusJson));
|
||||
globalStatus = JsonUtil.mergeAndUpdate(globalStatus, jsonObjectBuilder.build());
|
||||
update(component, JsonUtil.readJsonObject(statusJson));
|
||||
}
|
||||
|
||||
public synchronized void update(String component, JsonObject componentStatus) {
|
||||
JsonObjectBuilder jsonObjectBuilder = JsonLoader.createObjectBuilder();
|
||||
jsonObjectBuilder.add(component, componentStatus);
|
||||
public synchronized void update(String component, HashMap<String, String> statusAttributes) {
|
||||
update(component, JsonUtil.toJsonObject(statusAttributes));
|
||||
}
|
||||
|
||||
public synchronized void update(String componentPath, JsonObject componentStatus) {
|
||||
JsonObjectBuilder jsonObjectBuilder = JsonUtil.objectBuilderWithValueAtPath(componentPath, componentStatus);
|
||||
globalStatus = JsonUtil.mergeAndUpdate(globalStatus, jsonObjectBuilder.build());
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.apache.activemq.artemis.spi.core.security.jaas;
|
|||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
@ -30,9 +31,14 @@ import java.util.regex.Pattern;
|
|||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
import org.apache.activemq.artemis.core.server.ActiveMQServerLogger;
|
||||
import org.apache.activemq.artemis.core.server.impl.ServerStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.zip.Adler32;
|
||||
import java.util.zip.Checksum;
|
||||
|
||||
import static org.apache.activemq.artemis.core.server.impl.ServerStatus.JAAS_COMPONENT;
|
||||
|
||||
public class ReloadableProperties {
|
||||
|
||||
|
@ -47,6 +53,8 @@ public class ReloadableProperties {
|
|||
private Map<String, Pattern> regexpProps;
|
||||
private long reloadTime = -1;
|
||||
private final PropertiesLoader.FileNameKey key;
|
||||
private final Checksum adler32 = new Adler32();
|
||||
private long checksum = 0;
|
||||
|
||||
public ReloadableProperties(PropertiesLoader.FileNameKey key) {
|
||||
this.key = key;
|
||||
|
@ -58,9 +66,25 @@ public class ReloadableProperties {
|
|||
|
||||
public synchronized ReloadableProperties obtained() {
|
||||
if (reloadTime < 0 || (key.isReload() && hasModificationAfter(reloadTime))) {
|
||||
props = new Properties();
|
||||
|
||||
adler32.reset();
|
||||
props = new Properties() {
|
||||
// want to checksum in read order
|
||||
@Override
|
||||
public synchronized Object put(Object key, Object value) {
|
||||
String sKey = key instanceof String ? (String)key : null;
|
||||
String sValue = value instanceof String ? (String)value : null;
|
||||
if (sKey != null && sValue != null) {
|
||||
adler32.update(sKey.getBytes(StandardCharsets.UTF_8));
|
||||
adler32.update('=');
|
||||
adler32.update(sValue.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
return super.put(key, value);
|
||||
}
|
||||
};
|
||||
try {
|
||||
load(key.file(), props);
|
||||
checksum = adler32.getValue();
|
||||
invertedProps = null;
|
||||
invertedValueProps = null;
|
||||
regexpProps = null;
|
||||
|
@ -74,10 +98,18 @@ public class ReloadableProperties {
|
|||
}
|
||||
}
|
||||
reloadTime = System.currentTimeMillis();
|
||||
updateStatus();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private void updateStatus() {
|
||||
HashMap<String, String> statusAttributes = new HashMap<>();
|
||||
statusAttributes.put("Alder32", String.valueOf(checksum));
|
||||
statusAttributes.put("reloadTime", String.valueOf(reloadTime));
|
||||
ServerStatus.getInstance().update(JAAS_COMPONENT + "/properties/" + key.file.getName(), statusAttributes);
|
||||
}
|
||||
|
||||
public synchronized Map<String, String> invertedPropertiesMap() {
|
||||
if (invertedProps == null) {
|
||||
invertedProps = new HashMap<>(props.size());
|
||||
|
|
|
@ -1337,6 +1337,7 @@ public class ConfigurationImplTest extends ActiveMQTestBase {
|
|||
|
||||
assertTrue(jsonStatus.contains(UPDATED_SHA));
|
||||
assertFalse(jsonStatus.contains(SHA));
|
||||
assertTrue(jsonStatus.contains("alder32"));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,19 +25,25 @@ import javax.security.auth.callback.UnsupportedCallbackException;
|
|||
import javax.security.auth.login.FailedLoginException;
|
||||
import javax.security.auth.login.LoginContext;
|
||||
import javax.security.auth.login.LoginException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URL;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.apache.activemq.artemis.core.server.impl.ServerStatus;
|
||||
import org.apache.activemq.artemis.spi.core.security.jaas.RolePrincipal;
|
||||
import org.apache.activemq.artemis.spi.core.security.jaas.UserPrincipal;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.zip.Adler32;
|
||||
import java.util.zip.Checksum;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -104,6 +110,9 @@ public class PropertiesLoginModuleTest extends Assert {
|
|||
assertEquals("Should have one user principal", 1, subject.getPrincipals(UserPrincipal.class).size());
|
||||
assertEquals("Should have two group principals", 2, subject.getPrincipals(RolePrincipal.class).size());
|
||||
|
||||
String hashOriginal = genHash(usersFile);
|
||||
assertTrue("Contains hash", ServerStatus.getInstance().asJson().contains(hashOriginal));
|
||||
|
||||
context.logout();
|
||||
|
||||
assertEquals("Should have zero principals", 0, subject.getPrincipals().size());
|
||||
|
@ -127,9 +136,28 @@ public class PropertiesLoginModuleTest extends Assert {
|
|||
|
||||
context.logout();
|
||||
|
||||
String hashUpdated = genHash(usersFile);
|
||||
assertTrue("Contains hashUpdated", ServerStatus.getInstance().asJson().contains(hashUpdated));
|
||||
assertNotEquals(hashOriginal, hashUpdated);
|
||||
|
||||
assertEquals("Should have zero principals", 0, subject.getPrincipals().size());
|
||||
}
|
||||
|
||||
private String genHash(File usersFile) {
|
||||
Checksum hash = new Adler32();
|
||||
|
||||
try (FileReader fileReader = new FileReader(usersFile); BufferedReader bufferedReader = new BufferedReader(fileReader)) {
|
||||
String line = null;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
if (!line.startsWith("#") && !line.isBlank()) {
|
||||
hash.update(line.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
}
|
||||
} catch (Exception expectedEof) {
|
||||
}
|
||||
return String.valueOf(hash.getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadUseridLogin() throws Exception {
|
||||
LoginContext context = new LoginContext("PropertiesLogin", new UserPassHandler("BAD", "secret"));
|
||||
|
|
Loading…
Reference in New Issue