This closes #3851
This commit is contained in:
commit
fd9eb2ec9f
|
@ -28,6 +28,7 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
@ -105,6 +106,7 @@ public class DefaultSensitiveStringCodec implements SensitiveDataCodec<String> {
|
||||||
System.out.println("Encoded password (without quotes): \"" + encode + "\"");
|
System.out.println("Encoded password (without quotes): \"" + encode + "\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public boolean verify(char[] inputValue, String storedValue) {
|
public boolean verify(char[] inputValue, String storedValue) {
|
||||||
return algorithm.verify(inputValue, storedValue);
|
return algorithm.verify(inputValue, storedValue);
|
||||||
}
|
}
|
||||||
|
@ -188,6 +190,16 @@ public class DefaultSensitiveStringCodec implements SensitiveDataCodec<String> {
|
||||||
BigInteger n = new BigInteger(encoding);
|
BigInteger n = new BigInteger(encoding);
|
||||||
return n.toString(16);
|
return n.toString(16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean verify(char[] inputValue, String storedValue) {
|
||||||
|
try {
|
||||||
|
return Objects.equals(storedValue, encode(String.valueOf(inputValue)));
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.debug("Exception on verifying: " + e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PBKDF2Algorithm extends CodecAlgorithm {
|
private class PBKDF2Algorithm extends CodecAlgorithm {
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* <p>
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* <p>
|
||||||
|
* 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.artemis.utils;
|
||||||
|
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public abstract class LazyHashProcessor implements HashProcessor {
|
||||||
|
|
||||||
|
private Supplier<HashProcessor> hashProcessorSupplier = Suppliers.memoize(() -> {
|
||||||
|
try {
|
||||||
|
return createHashProcessor();
|
||||||
|
} catch (RuntimeException e) {
|
||||||
|
throw e;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String hash(String plainText) throws Exception {
|
||||||
|
return hashProcessorSupplier.get().hash(plainText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean compare(char[] inputValue, String storedHash) {
|
||||||
|
return hashProcessorSupplier.get().compare(inputValue, storedHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract HashProcessor createHashProcessor() throws Exception;
|
||||||
|
}
|
|
@ -122,10 +122,17 @@ public final class PasswordMaskingUtil {
|
||||||
|
|
||||||
//stored password takes 2 forms, ENC() or plain text
|
//stored password takes 2 forms, ENC() or plain text
|
||||||
public static HashProcessor getHashProcessor(String storedPassword) {
|
public static HashProcessor getHashProcessor(String storedPassword) {
|
||||||
|
return getHashProcessor(storedPassword, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HashProcessor getHashProcessor(String storedPassword, HashProcessor secureHashProcessor) {
|
||||||
|
|
||||||
if (!isEncoded(storedPassword)) {
|
if (!isEncoded(storedPassword)) {
|
||||||
return LazyPlainTextProcessorHolder.INSTANCE;
|
return LazyPlainTextProcessorHolder.INSTANCE;
|
||||||
}
|
}
|
||||||
|
if (secureHashProcessor != null) {
|
||||||
|
return secureHashProcessor;
|
||||||
|
}
|
||||||
final Exception secureProcessorException = LazySecureProcessorHolder.EXCEPTION;
|
final Exception secureProcessorException = LazySecureProcessorHolder.EXCEPTION;
|
||||||
if (secureProcessorException != null) {
|
if (secureProcessorException != null) {
|
||||||
//reuse old descriptions/messages of the exception but refill the stack trace
|
//reuse old descriptions/messages of the exception but refill the stack trace
|
||||||
|
|
|
@ -18,9 +18,9 @@ package org.apache.activemq.artemis.utils;
|
||||||
|
|
||||||
public class SecureHashProcessor implements HashProcessor {
|
public class SecureHashProcessor implements HashProcessor {
|
||||||
|
|
||||||
private DefaultSensitiveStringCodec codec;
|
private SensitiveDataCodec<String> codec;
|
||||||
|
|
||||||
public SecureHashProcessor(DefaultSensitiveStringCodec codec) {
|
public SecureHashProcessor(SensitiveDataCodec<String> codec) {
|
||||||
this.codec = codec;
|
this.codec = codec;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,10 +27,14 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
public interface SensitiveDataCodec<T> {
|
public interface SensitiveDataCodec<T> {
|
||||||
|
|
||||||
T decode(Object mask) throws Exception;
|
T decode(Object encodedValue) throws Exception;
|
||||||
|
|
||||||
T encode(Object secret) throws Exception;
|
T encode(Object value) throws Exception;
|
||||||
|
|
||||||
default void init(Map<String, String> params) throws Exception {
|
default void init(Map<String, String> params) throws Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default boolean verify(char[] value, T encodedValue) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,20 +39,33 @@ public class DefaultSensitiveStringCodecTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOnewayAlgorithm() throws Exception {
|
public void testOnewayAlgorithm() throws Exception {
|
||||||
DefaultSensitiveStringCodec codec = new DefaultSensitiveStringCodec();
|
testAlgorithm(DefaultSensitiveStringCodec.ONE_WAY);
|
||||||
Map<String, String> params = new HashMap<>();
|
}
|
||||||
params.put(DefaultSensitiveStringCodec.ALGORITHM, DefaultSensitiveStringCodec.ONE_WAY);
|
|
||||||
codec.init(params);
|
@Test
|
||||||
|
public void testTwowayAlgorithm() throws Exception {
|
||||||
|
testAlgorithm(DefaultSensitiveStringCodec.TWO_WAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testAlgorithm(String algorithm) throws Exception {
|
||||||
|
DefaultSensitiveStringCodec codec = getDefaultSensitiveStringCodec(algorithm);
|
||||||
|
|
||||||
String plainText = "some_password";
|
String plainText = "some_password";
|
||||||
String maskedText = codec.encode(plainText);
|
String maskedText = codec.encode(plainText);
|
||||||
log.debug("encoded value: " + maskedText);
|
log.debug("encoded value: " + maskedText);
|
||||||
|
|
||||||
//one way can't decode
|
if (algorithm.equals(DefaultSensitiveStringCodec.ONE_WAY)) {
|
||||||
try {
|
//one way can't decode
|
||||||
codec.decode(maskedText);
|
try {
|
||||||
fail("one way algorithm can't decode");
|
codec.decode(maskedText);
|
||||||
} catch (IllegalArgumentException expected) {
|
fail("one way algorithm can't decode");
|
||||||
|
} catch (IllegalArgumentException expected) {
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String decoded = codec.decode(maskedText);
|
||||||
|
log.debug("encoded value: " + maskedText);
|
||||||
|
|
||||||
|
assertEquals("decoded result not match: " + decoded, decoded, plainText);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertTrue(codec.verify(plainText.toCharArray(), maskedText));
|
assertTrue(codec.verify(plainText.toCharArray(), maskedText));
|
||||||
|
@ -62,19 +75,34 @@ public class DefaultSensitiveStringCodecTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTwowayAlgorithm() throws Exception {
|
public void testCompareWithOnewayAlgorithm() throws Exception {
|
||||||
DefaultSensitiveStringCodec codec = new DefaultSensitiveStringCodec();
|
testCompareWithAlgorithm(DefaultSensitiveStringCodec.ONE_WAY);
|
||||||
Map<String, String> params = new HashMap<>();
|
}
|
||||||
params.put(DefaultSensitiveStringCodec.ALGORITHM, DefaultSensitiveStringCodec.TWO_WAY);
|
|
||||||
codec.init(params);
|
@Test
|
||||||
|
public void testCompareWithTwowayAlgorithm() throws Exception {
|
||||||
|
testCompareWithAlgorithm(DefaultSensitiveStringCodec.TWO_WAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testCompareWithAlgorithm(String algorithm) throws Exception {
|
||||||
|
DefaultSensitiveStringCodec codec = getDefaultSensitiveStringCodec(algorithm);
|
||||||
|
|
||||||
String plainText = "some_password";
|
String plainText = "some_password";
|
||||||
String maskedText = codec.encode(plainText);
|
String maskedText = codec.encode(plainText);
|
||||||
log.debug("encoded value: " + maskedText);
|
log.debug("encoded value: " + maskedText);
|
||||||
|
|
||||||
String decoded = codec.decode(maskedText);
|
assertTrue(codec.verify(plainText.toCharArray(), maskedText));
|
||||||
log.debug("encoded value: " + maskedText);
|
|
||||||
|
|
||||||
assertEquals("decoded result not match: " + decoded, decoded, plainText);
|
String otherPassword = "some_other_password";
|
||||||
|
assertFalse(codec.verify(otherPassword.toCharArray(), maskedText));
|
||||||
|
}
|
||||||
|
|
||||||
|
private DefaultSensitiveStringCodec getDefaultSensitiveStringCodec(String algorithm) throws Exception {
|
||||||
|
DefaultSensitiveStringCodec codec = new DefaultSensitiveStringCodec();
|
||||||
|
Map<String, String> params = new HashMap<>();
|
||||||
|
params.put(DefaultSensitiveStringCodec.ALGORITHM, algorithm);
|
||||||
|
codec.init(params);
|
||||||
|
|
||||||
|
return codec;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,9 @@ import java.util.Properties;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.apache.activemq.artemis.utils.HashProcessor;
|
import org.apache.activemq.artemis.utils.HashProcessor;
|
||||||
|
import org.apache.activemq.artemis.utils.LazyHashProcessor;
|
||||||
import org.apache.activemq.artemis.utils.PasswordMaskingUtil;
|
import org.apache.activemq.artemis.utils.PasswordMaskingUtil;
|
||||||
|
import org.apache.activemq.artemis.utils.SecureHashProcessor;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
public class PropertiesLoginModule extends PropertiesLoader implements AuditLoginModule {
|
public class PropertiesLoginModule extends PropertiesLoader implements AuditLoginModule {
|
||||||
|
@ -41,6 +43,7 @@ public class PropertiesLoginModule extends PropertiesLoader implements AuditLogi
|
||||||
|
|
||||||
public static final String USER_FILE_PROP_NAME = "org.apache.activemq.jaas.properties.user";
|
public static final String USER_FILE_PROP_NAME = "org.apache.activemq.jaas.properties.user";
|
||||||
public static final String ROLE_FILE_PROP_NAME = "org.apache.activemq.jaas.properties.role";
|
public static final String ROLE_FILE_PROP_NAME = "org.apache.activemq.jaas.properties.role";
|
||||||
|
public static final String PASSWORD_CODEC_PROP_NAME = "org.apache.activemq.jaas.properties.password.codec";
|
||||||
|
|
||||||
private Subject subject;
|
private Subject subject;
|
||||||
private CallbackHandler callbackHandler;
|
private CallbackHandler callbackHandler;
|
||||||
|
@ -64,10 +67,21 @@ public class PropertiesLoginModule extends PropertiesLoader implements AuditLogi
|
||||||
init(options);
|
init(options);
|
||||||
users = load(USER_FILE_PROP_NAME, "user", options).getProps();
|
users = load(USER_FILE_PROP_NAME, "user", options).getProps();
|
||||||
roles = load(ROLE_FILE_PROP_NAME, "role", options).invertedPropertiesValuesMap();
|
roles = load(ROLE_FILE_PROP_NAME, "role", options).invertedPropertiesValuesMap();
|
||||||
|
|
||||||
|
String passwordCodec = (String)options.get(PASSWORD_CODEC_PROP_NAME);
|
||||||
|
if (passwordCodec != null) {
|
||||||
|
hashProcessor = new LazyHashProcessor() {
|
||||||
|
@Override
|
||||||
|
protected HashProcessor createHashProcessor() throws Exception {
|
||||||
|
return new SecureHashProcessor(PasswordMaskingUtil.getCodec(passwordCodec));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean login() throws LoginException {
|
public boolean login() throws LoginException {
|
||||||
|
HashProcessor userHashProcessor;
|
||||||
Callback[] callbacks = new Callback[2];
|
Callback[] callbacks = new Callback[2];
|
||||||
|
|
||||||
callbacks[0] = new NameCallback("Username: ");
|
callbacks[0] = new NameCallback("Username: ");
|
||||||
|
@ -94,12 +108,12 @@ public class PropertiesLoginModule extends PropertiesLoader implements AuditLogi
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
hashProcessor = PasswordMaskingUtil.getHashProcessor(password);
|
userHashProcessor = PasswordMaskingUtil.getHashProcessor(password, hashProcessor);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new FailedLoginException("Failed to get hash processor");
|
throw new FailedLoginException("Failed to get hash processor");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hashProcessor.compare(tmpPassword, password)) {
|
if (!userHashProcessor.compare(tmpPassword, password)) {
|
||||||
throw new FailedLoginException("Password does not match for user: " + user);
|
throw new FailedLoginException("Password does not match for user: " + user);
|
||||||
}
|
}
|
||||||
loginSucceeded = true;
|
loginSucceeded = true;
|
||||||
|
|
|
@ -259,7 +259,26 @@ codec other than the default one. For example
|
||||||
With this configuration, both passwords in ra.xml and all of its MDBs will have
|
With this configuration, both passwords in ra.xml and all of its MDBs will have
|
||||||
to be in masked form.
|
to be in masked form.
|
||||||
|
|
||||||
### login.config
|
### PropertiesLoginModule
|
||||||
|
Artemis supports Properties login module to be configured in JAAS configuration file
|
||||||
|
(default name is `login.config`). By default, the passwords of the users are in plain text
|
||||||
|
or masked with the [the default codec](#the-default-codec).
|
||||||
|
|
||||||
|
To use a custom codec class, set the `org.apache.activemq.jaas.properties.password.codec` property to the class name
|
||||||
|
e.g. to use the `com.example.MySensitiveDataCodecImpl` codec class:
|
||||||
|
|
||||||
|
```
|
||||||
|
PropertiesLoginWithPasswordCodec {
|
||||||
|
org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule required
|
||||||
|
debug=true
|
||||||
|
org.apache.activemq.jaas.properties.user="users.properties"
|
||||||
|
org.apache.activemq.jaas.properties.role="roles.properties"
|
||||||
|
org.apache.activemq.jaas.properties.password.codec="com.example.MySensitiveDataCodecImpl";
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### LDAPLoginModule
|
||||||
|
|
||||||
Artemis supports LDAP login modules to be configured in JAAS configuration file
|
Artemis supports LDAP login modules to be configured in JAAS configuration file
|
||||||
(default name is `login.config`). When connecting to an LDAP server usually you
|
(default name is `login.config`). When connecting to an LDAP server usually you
|
||||||
|
@ -429,22 +448,8 @@ using the new defined codec.
|
||||||
|
|
||||||
To use a different codec than the built-in one, you either pick one from
|
To use a different codec than the built-in one, you either pick one from
|
||||||
existing libraries or you implement it yourself. All codecs must implement
|
existing libraries or you implement it yourself. All codecs must implement
|
||||||
the `org.apache.activemq.artemis.utils.SensitiveDataCodec<T>` interface:
|
the `org.apache.activemq.artemis.utils.SensitiveDataCodec<String>` interface.
|
||||||
|
So a new codec would be defined like
|
||||||
```java
|
|
||||||
public interface SensitiveDataCodec<T> {
|
|
||||||
|
|
||||||
T decode(Object mask) throws Exception;
|
|
||||||
|
|
||||||
T encode(Object secret) throws Exception;
|
|
||||||
|
|
||||||
default void init(Map<String, String> params) throws Exception {
|
|
||||||
};
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This is a generic type interface but normally for a password you just need
|
|
||||||
String type. So a new codec would be defined like
|
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public class MyCodec implements SensitiveDataCodec<String> {
|
public class MyCodec implements SensitiveDataCodec<String> {
|
||||||
|
@ -464,6 +469,12 @@ public class MyCodec implements SensitiveDataCodec<String> {
|
||||||
public void init(Map<String, String> params) {
|
public void init(Map<String, String> params) {
|
||||||
// Initialization done here. It is called right after the codec has been created.
|
// Initialization done here. It is called right after the codec has been created.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean verify(char[] value, String encodedValue) {
|
||||||
|
// Return true if the value matches the encodedValue.
|
||||||
|
return checkValueMatchesEncoding(value, encodedValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -567,6 +567,10 @@ integration with LDAP is preferable. It is implemented by
|
||||||
- `org.apache.activemq.jaas.properties.role` - the path to the file which
|
- `org.apache.activemq.jaas.properties.role` - the path to the file which
|
||||||
contains user and role properties
|
contains user and role properties
|
||||||
|
|
||||||
|
- `org.apache.activemq.jaas.properties.password.codec` - the fully qualified
|
||||||
|
class name of the password codec to use. See the [password masking](masking-passwords.md)
|
||||||
|
documentation for more details on how this works.
|
||||||
|
|
||||||
- `reload` - boolean flag; whether or not to reload the properties files when a
|
- `reload` - boolean flag; whether or not to reload the properties files when a
|
||||||
modification occurs; default is `false`
|
modification occurs; default is `false`
|
||||||
|
|
||||||
|
|
|
@ -71,6 +71,7 @@ import org.apache.activemq.artemis.spi.core.security.ActiveMQSecurityManager4;
|
||||||
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
import org.apache.activemq.artemis.tests.util.ActiveMQTestBase;
|
||||||
import org.apache.activemq.artemis.tests.util.CreateMessage;
|
import org.apache.activemq.artemis.tests.util.CreateMessage;
|
||||||
import org.apache.activemq.artemis.utils.CompositeAddress;
|
import org.apache.activemq.artemis.utils.CompositeAddress;
|
||||||
|
import org.apache.activemq.artemis.utils.SensitiveDataCodec;
|
||||||
import org.apache.activemq.artemis.utils.Wait;
|
import org.apache.activemq.artemis.utils.Wait;
|
||||||
import org.apache.activemq.command.ActiveMQQueue;
|
import org.apache.activemq.command.ActiveMQQueue;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
|
@ -129,6 +130,22 @@ public class SecurityTest extends ActiveMQTestBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJAASSecurityManagerAuthenticationWithPasswordCodec() throws Exception {
|
||||||
|
ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("PropertiesLoginWithPasswordCodec");
|
||||||
|
ActiveMQServer server = addServer(ActiveMQServers.newActiveMQServer(createDefaultInVMConfig().setSecurityEnabled(true), ManagementFactory.getPlatformMBeanServer(), securityManager, false));
|
||||||
|
server.start();
|
||||||
|
ClientSessionFactory cf = createSessionFactory(locator);
|
||||||
|
|
||||||
|
try {
|
||||||
|
ClientSession session = cf.createSession("test","password", false, true, true, false, 0);
|
||||||
|
session.close();
|
||||||
|
} catch (ActiveMQException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Assert.fail("should not throw exception");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testJAASSecurityManagerAuthenticationWithValidateUser() throws Exception {
|
public void testJAASSecurityManagerAuthenticationWithValidateUser() throws Exception {
|
||||||
ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("PropertiesLogin");
|
ActiveMQJAASSecurityManager securityManager = new ActiveMQJAASSecurityManager("PropertiesLogin");
|
||||||
|
@ -2564,4 +2581,21 @@ public class SecurityTest extends ActiveMQTestBase {
|
||||||
fail("Invalid Exception type:" + e.getType());
|
fail("Invalid Exception type:" + e.getType());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class DummySensitiveDataCodec implements SensitiveDataCodec<String> {
|
||||||
|
@Override
|
||||||
|
public String decode(Object encodedValue) throws Exception {
|
||||||
|
throw new IllegalStateException("Decoding not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String encode(Object value) throws Exception {
|
||||||
|
return new StringBuffer((String)value).reverse().toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean verify(char[] value, String encodedValue) {
|
||||||
|
return encodedValue.equals(new StringBuffer(String.valueOf(value)).reverse().toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,13 @@ PropertiesLogin {
|
||||||
org.apache.activemq.jaas.properties.role="roles.properties";
|
org.apache.activemq.jaas.properties.role="roles.properties";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PropertiesLoginWithPasswordCodec {
|
||||||
|
org.apache.activemq.artemis.spi.core.security.jaas.PropertiesLoginModule required
|
||||||
|
debug=true
|
||||||
|
org.apache.activemq.jaas.properties.user="users.properties"
|
||||||
|
org.apache.activemq.jaas.properties.role="roles.properties"
|
||||||
|
org.apache.activemq.jaas.properties.password.codec="org.apache.activemq.artemis.tests.integration.security.SecurityTest$DummySensitiveDataCodec";
|
||||||
|
};
|
||||||
|
|
||||||
LDAPLogin {
|
LDAPLogin {
|
||||||
org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule required
|
org.apache.activemq.artemis.spi.core.security.jaas.LDAPLoginModule required
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
programmers=first
|
programmers=first
|
||||||
accounting=second
|
accounting=second
|
||||||
|
test=test
|
||||||
employees=first,second
|
employees=first,second
|
||||||
a=a
|
a=a
|
||||||
b=b
|
b=b
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
first=secret
|
first=secret
|
||||||
second=password
|
second=password
|
||||||
|
test=ENC(drowssap)
|
||||||
a=a
|
a=a
|
||||||
b=b
|
b=b
|
||||||
x=x
|
x=x
|
||||||
|
|
Loading…
Reference in New Issue