[New] Implemented PasswordStrengthHandler, Simple and Basic:

<PasswordStrengthHandler class="li.strolch.privilege.handler.BasicPasswordStrengthHandler">
    <Parameters>
        <Parameter name="minLength" value="8"/>
        <Parameter name="maxLength" value="1024"/>
        <Parameter name="needsNumbers" value="true"/>
        <Parameter name="needsLowerCase" value="true"/>
        <Parameter name="needsUpperCase" value="true"/>
        <Parameter name="needsSpecialChars" value="true"/>
    </Parameters>
</PasswordStrengthHandler>
This commit is contained in:
Robert von Burg 2021-02-22 23:11:15 +01:00
parent daad639f9c
commit 64596cdfb5
16 changed files with 403 additions and 74 deletions

View File

@ -10,7 +10,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import li.strolch.privilege.base.AccessDeniedException; import li.strolch.privilege.base.AccessDeniedException;
import li.strolch.privilege.base.InvalidCredentialsException;
import li.strolch.privilege.model.UserState; import li.strolch.privilege.model.UserState;
import li.strolch.privilege.model.internal.User; import li.strolch.privilege.model.internal.User;
import li.strolch.privilege.model.internal.UserHistory; import li.strolch.privilege.model.internal.UserHistory;
@ -28,11 +27,12 @@ public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
@Override @Override
public synchronized void initialize(Map<String, String> parameterMap, EncryptionHandler encryptionHandler, public synchronized void initialize(Map<String, String> parameterMap, EncryptionHandler encryptionHandler,
PersistenceHandler persistenceHandler, UserChallengeHandler userChallengeHandler, PasswordStrengthHandler passwordStrengthHandler, PersistenceHandler persistenceHandler,
SingleSignOnHandler ssoHandler, Map<String, Class<PrivilegePolicy>> policyMap) { UserChallengeHandler userChallengeHandler, SingleSignOnHandler ssoHandler,
Map<String, Class<PrivilegePolicy>> policyMap) {
super.initialize(parameterMap, encryptionHandler, persistenceHandler, userChallengeHandler, ssoHandler, super.initialize(parameterMap, encryptionHandler, passwordStrengthHandler, persistenceHandler,
policyMap); userChallengeHandler, ssoHandler, policyMap);
this.providerUrl = parameterMap.get("providerUrl"); this.providerUrl = parameterMap.get("providerUrl");
this.searchBase = parameterMap.get("searchBase"); this.searchBase = parameterMap.get("searchBase");
@ -42,7 +42,7 @@ public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
@Override @Override
protected synchronized User checkCredentialsAndUserState(String username, char[] password) protected synchronized User checkCredentialsAndUserState(String username, char[] password)
throws InvalidCredentialsException, AccessDeniedException { throws AccessDeniedException {
// first see if this is a local user // first see if this is a local user
User internalUser = this.persistenceHandler.getUser(username); User internalUser = this.persistenceHandler.getUser(username);
@ -148,7 +148,7 @@ public abstract class BaseLdapPrivilegeHandler extends DefaultPrivilegeHandler {
protected String validateLdapUsername(String username, Attributes attrs) throws NamingException { protected String validateLdapUsername(String username, Attributes attrs) throws NamingException {
Attribute sAMAccountName = attrs.get("sAMAccountName"); Attribute sAMAccountName = attrs.get("sAMAccountName");
if (sAMAccountName == null || !username.toLowerCase().equals(sAMAccountName.get().toString().toLowerCase())) if (sAMAccountName == null || !username.equalsIgnoreCase(sAMAccountName.get().toString()))
throw new AccessDeniedException( throw new AccessDeniedException(
"Could not login with user: " + username + this.domain + " on Ldap: Wrong LDAP Data"); "Could not login with user: " + username + this.domain + " on Ldap: Wrong LDAP Data");

View File

@ -0,0 +1,101 @@
package li.strolch.privilege.handler;
import static java.lang.Boolean.parseBoolean;
import static java.lang.Integer.parseInt;
import static li.strolch.privilege.i18n.PrivilegeMessages.getString;
import java.text.MessageFormat;
import java.util.Locale;
import java.util.Map;
public class BasicPasswordStrengthHandler implements PasswordStrengthHandler {
protected int minLength;
protected int maxLength;
protected boolean needsNumbers;
protected boolean needsLowerCase;
protected boolean needsUpperCase;
protected boolean needsSpecialChars;
@Override
public void initialize(Map<String, String> parameterMap) {
this.minLength = parseInt(parameterMap.getOrDefault("minLength", "8"));
this.maxLength = parseInt(parameterMap.getOrDefault("maxLength", String.valueOf(1024)));
this.needsNumbers = parseBoolean(parameterMap.getOrDefault("needsNumbers", "true"));
this.needsLowerCase = parseBoolean(parameterMap.getOrDefault("needsLowerCase", "true"));
this.needsUpperCase = parseBoolean(parameterMap.getOrDefault("needsUpperCase", "true"));
this.needsSpecialChars = parseBoolean(parameterMap.getOrDefault("needsSpecialChars", "false"));
if (this.minLength < 8)
throw new IllegalStateException("minLength can not be less than 8");
if (this.maxLength > 1024)
throw new IllegalStateException("maxLength can not be greater than 1024");
}
@Override
public String getDescription(Locale locale) {
String description;
if (this.maxLength < 100)
description = MessageFormat
.format(getString(locale, "Privilege.passwordLengthBetween"), this.minLength, this.maxLength);
else
description = MessageFormat.format(getString(locale, "Privilege.passwordLengthAtLeast"), this.minLength);
if (this.needsNumbers)
description += ", " + getString(locale, "Privilege.passwordMustContainNumbers");
if (this.needsLowerCase && this.needsUpperCase)
description += ", " + getString(locale, "Privilege.passwordMustContainLowerAndUpperCase");
else if (this.needsLowerCase)
description += ", " + getString(locale, "Privilege.passwordMustContainLowerCase");
else
description += ", " + getString(locale, "Privilege.passwordMustContainUpperCase");
if (this.needsSpecialChars)
description += ", " + getString(locale, "Privilege.passwordMustContainSpecialCharacters");
return description;
}
@Override
public boolean validateStrength(char[] password) {
if (password.length < this.minLength || password.length > this.maxLength)
return false;
boolean numbersOk = !this.needsNumbers;
boolean lowerCaseOk = !this.needsLowerCase;
boolean upperCaseOk = !this.needsUpperCase;
boolean specialCharsOk = !this.needsSpecialChars;
for (char c : password) {
if (numbersOk && lowerCaseOk && upperCaseOk && specialCharsOk)
return true;
if (!numbersOk && Character.isDigit(c)) {
numbersOk = true;
continue;
}
if (!lowerCaseOk && Character.isLowerCase(c)) {
lowerCaseOk = true;
continue;
}
if (!upperCaseOk && Character.isUpperCase(c)) {
upperCaseOk = true;
continue;
}
if (!specialCharsOk && isSpecial(c))
specialCharsOk = true;
}
return numbersOk && lowerCaseOk && upperCaseOk && specialCharsOk;
}
public static boolean isSpecial(char c) {
return !(Character.isDigit(c) || Character.isLowerCase(c) || Character.isUpperCase(c));
}
}

View File

@ -84,6 +84,11 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
*/ */
protected EncryptionHandler encryptionHandler; protected EncryptionHandler encryptionHandler;
/**
* The password strength handler is used for validating the strength of a password when being set
*/
protected PasswordStrengthHandler passwordStrengthHandler;
/** /**
* The Single Sign On Handler * The Single Sign On Handler
*/ */
@ -399,7 +404,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
if (password != null) { if (password != null) {
// validate password meets basic requirements // validate password meets basic requirements
validatePassword(password); validatePassword(certificate.getLocale(), password);
// get new salt for user // get new salt for user
salt = this.encryptionHandler.nextSalt(); salt = this.encryptionHandler.nextSalt();
@ -464,7 +469,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
if (password != null) { if (password != null) {
// validate password meets basic requirements // validate password meets basic requirements
validatePassword(password); validatePassword(certificate.getLocale(), password);
// get new salt for user // get new salt for user
salt = this.encryptionHandler.nextSalt(); salt = this.encryptionHandler.nextSalt();
@ -779,7 +784,7 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
if (password != null) { if (password != null) {
// validate password meets basic requirements // validate password meets basic requirements
validatePassword(password); validatePassword(certificate.getLocale(), password);
// get new salt for user // get new salt for user
salt = this.encryptionHandler.nextSalt(); salt = this.encryptionHandler.nextSalt();
@ -1484,7 +1489,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
throws InvalidCredentialsException, AccessDeniedException { throws InvalidCredentialsException, AccessDeniedException {
// and validate the password // and validate the password
validatePassword(password); if (password == null || password.length < 3)
throw new InvalidCredentialsException("Password is invalid!");
// get user object // get user object
User user = this.persistenceHandler.getUser(username); User user = this.persistenceHandler.getUser(username);
@ -1755,21 +1761,10 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
return privilegeContext; return privilegeContext;
} }
/**
* This simple implementation validates that the password is not null, and that the password string is not empty
*
* @see li.strolch.privilege.handler.PrivilegeHandler#validatePassword(char[])
*/
@Override @Override
public void validatePassword(char[] password) throws PrivilegeException { public void validatePassword(Locale locale, char[] password) throws PrivilegeException {
if (!this.passwordStrengthHandler.validateStrength(password))
if (password == null || password.length == 0) { throw new PrivilegeException(this.passwordStrengthHandler.getDescription(locale));
throw new PrivilegeModelException("A password may not be empty!"); //$NON-NLS-1$
}
if (password.length < 3) {
throw new PrivilegeModelException("The given password is shorter than 3 characters"); //$NON-NLS-1$
}
} }
@Override @Override
@ -1811,6 +1806,8 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
* a map containing configuration properties * a map containing configuration properties
* @param encryptionHandler * @param encryptionHandler
* the {@link EncryptionHandler} instance for this {@link PrivilegeHandler} * the {@link EncryptionHandler} instance for this {@link PrivilegeHandler}
* @param passwordStrengthHandler
* the {@link PasswordStrengthHandler} instance for this {@link PrivilegeHandler}
* @param persistenceHandler * @param persistenceHandler
* the {@link PersistenceHandler} instance for this {@link PrivilegeHandler} * the {@link PersistenceHandler} instance for this {@link PrivilegeHandler}
* @param userChallengeHandler * @param userChallengeHandler
@ -1824,14 +1821,16 @@ public class DefaultPrivilegeHandler implements PrivilegeHandler {
* if the this method is called multiple times or an initialization exception occurs * if the this method is called multiple times or an initialization exception occurs
*/ */
public synchronized void initialize(Map<String, String> parameterMap, EncryptionHandler encryptionHandler, public synchronized void initialize(Map<String, String> parameterMap, EncryptionHandler encryptionHandler,
PersistenceHandler persistenceHandler, UserChallengeHandler userChallengeHandler, PasswordStrengthHandler passwordStrengthHandler, PersistenceHandler persistenceHandler,
SingleSignOnHandler ssoHandler, Map<String, Class<PrivilegePolicy>> policyMap) { UserChallengeHandler userChallengeHandler, SingleSignOnHandler ssoHandler,
Map<String, Class<PrivilegePolicy>> policyMap) {
if (this.initialized) if (this.initialized)
throw new PrivilegeModelException("Already initialized!"); //$NON-NLS-1$ throw new PrivilegeModelException("Already initialized!"); //$NON-NLS-1$
this.policyMap = policyMap; this.policyMap = policyMap;
this.encryptionHandler = encryptionHandler; this.encryptionHandler = encryptionHandler;
this.passwordStrengthHandler = passwordStrengthHandler;
this.persistenceHandler = persistenceHandler; this.persistenceHandler = persistenceHandler;
this.userChallengeHandler = userChallengeHandler; this.userChallengeHandler = userChallengeHandler;
this.ssoHandler = ssoHandler; this.ssoHandler = ssoHandler;

View File

@ -30,11 +30,12 @@ public class JsonConfigLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
@Override @Override
public synchronized void initialize(Map<String, String> parameterMap, EncryptionHandler encryptionHandler, public synchronized void initialize(Map<String, String> parameterMap, EncryptionHandler encryptionHandler,
PersistenceHandler persistenceHandler, UserChallengeHandler userChallengeHandler, PasswordStrengthHandler passwordStrengthHandler, PersistenceHandler persistenceHandler,
SingleSignOnHandler ssoHandler, Map<String, Class<PrivilegePolicy>> policyMap) { UserChallengeHandler userChallengeHandler, SingleSignOnHandler ssoHandler,
Map<String, Class<PrivilegePolicy>> policyMap) {
super.initialize(parameterMap, encryptionHandler, persistenceHandler, userChallengeHandler, ssoHandler, super.initialize(parameterMap, encryptionHandler, passwordStrengthHandler, persistenceHandler,
policyMap); userChallengeHandler, ssoHandler, policyMap);
this.realm = parameterMap.get(REALM); this.realm = parameterMap.get(REALM);
DBC.PRE.assertNotEmpty("realm must be set!", realm); DBC.PRE.assertNotEmpty("realm must be set!", realm);

View File

@ -0,0 +1,38 @@
package li.strolch.privilege.handler;
import java.util.Locale;
import java.util.Map;
/**
* The password strength handler allows to plug-in different algorithms for validating the strength of a password
*/
public interface PasswordStrengthHandler {
/**
* Initialize the concrete {@link PasswordStrengthHandler}. The passed parameter map contains any configuration the
* concrete {@link PasswordStrengthHandler} might need
*
* @param parameterMap
* a map containing configuration properties
*/
void initialize(Map<String, String> parameterMap);
/**
* Returns a description what a password must contain in order to be regarded as strong for this concrete
* implementation
*
* @return a description of a strong password
* @param locale
*/
String getDescription(Locale locale);
/**
* Performs the validation of the given password
*
* @param password
* the password to validate
*
* @return true if the password meets the criteria for a strong password
*/
boolean validateStrength(char[] password);
}

View File

@ -775,16 +775,9 @@ public interface PrivilegeHandler {
PrivilegeContext validate(Certificate certificate, String source) throws PrivilegeException; PrivilegeContext validate(Certificate certificate, String source) throws PrivilegeException;
/** /**
* Validate that the given password meets certain requirements. What these requirements are is a decision made by * @see li.strolch.privilege.handler.PasswordStrengthHandler#validateStrength(char[])
* the concrete implementation
*
* @param password
* the password to be validated to meet certain requirements
*
* @throws PrivilegeException
* if the password does not implement the requirement of the concrete implementation
*/ */
void validatePassword(char[] password) throws PrivilegeException; void validatePassword(Locale locale, char[] password) throws PrivilegeException;
/** /**
* <p> * <p>

View File

@ -26,11 +26,12 @@ public class SimpleLdapPrivilegeHandler extends BaseLdapPrivilegeHandler {
@Override @Override
public synchronized void initialize(Map<String, String> parameterMap, EncryptionHandler encryptionHandler, public synchronized void initialize(Map<String, String> parameterMap, EncryptionHandler encryptionHandler,
PersistenceHandler persistenceHandler, UserChallengeHandler userChallengeHandler, PasswordStrengthHandler passwordStrengthHandler, PersistenceHandler persistenceHandler,
SingleSignOnHandler ssoHandler, Map<String, Class<PrivilegePolicy>> policyMap) { UserChallengeHandler userChallengeHandler, SingleSignOnHandler ssoHandler,
Map<String, Class<PrivilegePolicy>> policyMap) {
super.initialize(parameterMap, encryptionHandler, persistenceHandler, userChallengeHandler, ssoHandler, super.initialize(parameterMap, encryptionHandler, passwordStrengthHandler, persistenceHandler,
policyMap); userChallengeHandler, ssoHandler, policyMap);
this.organisation = parameterMap.getOrDefault(ORGANISATION, ""); this.organisation = parameterMap.getOrDefault(ORGANISATION, "");
this.location = parameterMap.getOrDefault(LOCATION, ""); this.location = parameterMap.getOrDefault(LOCATION, "");

View File

@ -0,0 +1,22 @@
package li.strolch.privilege.handler;
import java.util.Locale;
import java.util.Map;
public class SimplePasswordStrengthHandler implements PasswordStrengthHandler {
@Override
public void initialize(Map<String, String> parameterMap) {
// do nothing
}
@Override
public String getDescription(Locale locale) {
return "Password must be at least 3 characters long";
}
@Override
public boolean validateStrength(char[] password) {
return password != null && password.length >= 3;
}
}

View File

@ -15,6 +15,8 @@
*/ */
package li.strolch.privilege.helper; package li.strolch.privilege.helper;
import static li.strolch.utils.helper.StringHelper.isEmpty;
import java.io.File; import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.nio.file.Files; import java.nio.file.Files;
@ -28,6 +30,8 @@ import li.strolch.privilege.policy.PrivilegePolicy;
import li.strolch.privilege.xml.PrivilegeConfigSaxReader; import li.strolch.privilege.xml.PrivilegeConfigSaxReader;
import li.strolch.utils.helper.ClassHelper; import li.strolch.utils.helper.ClassHelper;
import li.strolch.utils.helper.XmlHelper; import li.strolch.utils.helper.XmlHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** /**
* This class implements the initializing of the {@link PrivilegeHandler} by loading an XML file containing the * This class implements the initializing of the {@link PrivilegeHandler} by loading an XML file containing the
@ -37,6 +41,8 @@ import li.strolch.utils.helper.XmlHelper;
*/ */
public class PrivilegeInitializationHelper { public class PrivilegeInitializationHelper {
private static final Logger logger = LoggerFactory.getLogger(PrivilegeInitializationHelper.class);
/** /**
* Initializes the {@link DefaultPrivilegeHandler} from the configuration file * Initializes the {@link DefaultPrivilegeHandler} from the configuration file
* *
@ -108,6 +114,23 @@ public class PrivilegeInitializationHelper {
throw new PrivilegeException(msg, e); throw new PrivilegeException(msg, e);
} }
// initialize password strength handler
String passwordStrengthHandlerClassName = containerModel.getPasswordStrengthHandlerClassName();
if (isEmpty(passwordStrengthHandlerClassName)) {
logger.info("No PasswordStrengthHandler defined, using " + SimplePasswordStrengthHandler.class.getName());
passwordStrengthHandlerClassName = SimplePasswordStrengthHandler.class.getName();
}
PasswordStrengthHandler passwordStrengthHandler = ClassHelper
.instantiateClass(passwordStrengthHandlerClassName);
parameterMap = containerModel.getPasswordStrengthHandlerParameterMap();
try {
passwordStrengthHandler.initialize(parameterMap);
} catch (Exception e) {
String msg = "PasswordStrengthHandler {0} could not be initialized"; //$NON-NLS-1$
msg = MessageFormat.format(msg, passwordStrengthHandlerClassName);
throw new PrivilegeException(msg, e);
}
// initialize persistence handler // initialize persistence handler
String persistenceHandlerClassName = containerModel.getPersistenceHandlerClassName(); String persistenceHandlerClassName = containerModel.getPersistenceHandlerClassName();
PersistenceHandler persistenceHandler = ClassHelper.instantiateClass(persistenceHandlerClassName); PersistenceHandler persistenceHandler = ClassHelper.instantiateClass(persistenceHandlerClassName);
@ -164,9 +187,8 @@ public class PrivilegeInitializationHelper {
Map<String, Class<PrivilegePolicy>> policyMap = containerModel.getPolicies(); Map<String, Class<PrivilegePolicy>> policyMap = containerModel.getPolicies();
try { try {
privilegeHandler privilegeHandler.initialize(parameterMap, encryptionHandler, passwordStrengthHandler, persistenceHandler,
.initialize(parameterMap, encryptionHandler, persistenceHandler, challengeHandler, ssoHandler, challengeHandler, ssoHandler, policyMap);
policyMap);
} catch (Exception e) { } catch (Exception e) {
String msg = "PrivilegeHandler {0} could not be initialized"; //$NON-NLS-1$ String msg = "PrivilegeHandler {0} could not be initialized"; //$NON-NLS-1$
msg = MessageFormat.format(msg, privilegeHandler.getClass().getName()); msg = MessageFormat.format(msg, privilegeHandler.getClass().getName());

View File

@ -69,7 +69,12 @@ public class XmlConstants {
public static final String XML_HANDLER_ENCRYPTION = "EncryptionHandler"; public static final String XML_HANDLER_ENCRYPTION = "EncryptionHandler";
/** /**
* XML_HANDLER_ENCRYPTION = "EncryptionHandler" : * XML_HANDLER_ENCRYPTION = "PasswordStrengthHandler" :
*/
public static final String XML_HANDLER_PASSWORD_STRENGTH = "PasswordStrengthHandler";
/**
* XML_HANDLER_ENCRYPTION = "SsoHandler" :
*/ */
public static final String XML_HANDLER_SSO = "SsoHandler"; public static final String XML_HANDLER_SSO = "SsoHandler";

View File

@ -15,6 +15,7 @@
*/ */
package li.strolch.privilege.i18n; package li.strolch.privilege.i18n;
import java.util.Locale;
import java.util.MissingResourceException; import java.util.MissingResourceException;
import java.util.ResourceBundle; import java.util.ResourceBundle;
@ -29,6 +30,14 @@ public class PrivilegeMessages {
private PrivilegeMessages() { private PrivilegeMessages() {
} }
public static String getString(Locale locale, String key) {
try {
return ResourceBundle.getBundle(BUNDLE_NAME, locale).getString(key);
} catch (MissingResourceException e) {
return '!' + key + '!';
}
}
public static String getString(String key) { public static String getString(String key) {
try { try {
return RESOURCE_BUNDLE.getString(key); return RESOURCE_BUNDLE.getString(key);

View File

@ -37,12 +37,14 @@ import li.strolch.privilege.policy.PrivilegePolicy;
public class PrivilegeContainerModel { public class PrivilegeContainerModel {
private String encryptionHandlerClassName; private String encryptionHandlerClassName;
private String passwordStrengthHandlerClassName;
private String persistenceHandlerClassName; private String persistenceHandlerClassName;
private String userChallengeHandlerClassName; private String userChallengeHandlerClassName;
private String ssoHandlerClassName; private String ssoHandlerClassName;
private String privilegeHandlerClassName; private String privilegeHandlerClassName;
private Map<String, String> encryptionHandlerParameterMap; private Map<String, String> encryptionHandlerParameterMap;
private Map<String, String> passwordStrengthHandlerParameterMap;
private Map<String, String> persistenceHandlerParameterMap; private Map<String, String> persistenceHandlerParameterMap;
private Map<String, String> challengeHandlerParameterMap; private Map<String, String> challengeHandlerParameterMap;
private Map<String, String> ssoHandlerParameterMap; private Map<String, String> ssoHandlerParameterMap;
@ -50,11 +52,12 @@ public class PrivilegeContainerModel {
private Map<String, String> parameterMap; private Map<String, String> parameterMap;
private Map<String, Class<PrivilegePolicy>> policies; private final Map<String, Class<PrivilegePolicy>> policies;
public PrivilegeContainerModel() { public PrivilegeContainerModel() {
this.policies = new HashMap<>(); this.policies = new HashMap<>();
this.encryptionHandlerParameterMap = new HashMap<>(); this.encryptionHandlerParameterMap = new HashMap<>();
this.passwordStrengthHandlerParameterMap = new HashMap<>();
this.persistenceHandlerParameterMap = new HashMap<>(); this.persistenceHandlerParameterMap = new HashMap<>();
this.challengeHandlerParameterMap = new HashMap<>(); this.challengeHandlerParameterMap = new HashMap<>();
this.ssoHandlerParameterMap = new HashMap<>(); this.ssoHandlerParameterMap = new HashMap<>();
@ -77,6 +80,22 @@ public class PrivilegeContainerModel {
this.encryptionHandlerClassName = encryptionHandlerClassName; this.encryptionHandlerClassName = encryptionHandlerClassName;
} }
public String getPasswordStrengthHandlerClassName() {
return this.passwordStrengthHandlerClassName;
}
public void setPasswordStrengthHandlerClassName(String passwordStrengthHandlerClassName) {
this.passwordStrengthHandlerClassName = passwordStrengthHandlerClassName;
}
public Map<String, String> getPasswordStrengthHandlerParameterMap() {
return this.passwordStrengthHandlerParameterMap;
}
public void setPasswordStrengthHandlerParameterMap(Map<String, String> passwordStrengthHandlerParameterMap) {
this.passwordStrengthHandlerParameterMap = passwordStrengthHandlerParameterMap;
}
public Map<String, String> getEncryptionHandlerParameterMap() { public Map<String, String> getEncryptionHandlerParameterMap() {
return this.encryptionHandlerParameterMap; return this.encryptionHandlerParameterMap;
} }
@ -192,6 +211,10 @@ public class PrivilegeContainerModel {
builder.append(this.encryptionHandlerClassName); builder.append(this.encryptionHandlerClassName);
builder.append(", encryptionHandlerParameterMap="); builder.append(", encryptionHandlerParameterMap=");
builder.append(this.encryptionHandlerParameterMap.size()); builder.append(this.encryptionHandlerParameterMap.size());
builder.append(", passwordStrengthHandlerClassName=");
builder.append(this.passwordStrengthHandlerClassName);
builder.append(", passwordStrengthHandlerParameterMap=");
builder.append(this.passwordStrengthHandlerParameterMap);
builder.append(", persistenceHandlerClassName="); builder.append(", persistenceHandlerClassName=");
builder.append(this.persistenceHandlerClassName); builder.append(this.persistenceHandlerClassName);
builder.append(", persistenceHandlerParameterMap="); builder.append(", persistenceHandlerParameterMap=");

View File

@ -31,9 +31,8 @@ import org.xml.sax.helpers.DefaultHandler;
*/ */
public class PrivilegeConfigSaxReader extends DefaultHandler { public class PrivilegeConfigSaxReader extends DefaultHandler {
private Deque<ElementParser> buildersStack = new ArrayDeque<>(); private final Deque<ElementParser> buildersStack = new ArrayDeque<>();
private final PrivilegeContainerModel containerModel;
private PrivilegeContainerModel containerModel;
public PrivilegeConfigSaxReader(PrivilegeContainerModel containerModel) { public PrivilegeConfigSaxReader(PrivilegeContainerModel containerModel) {
this.containerModel = containerModel; this.containerModel = containerModel;
@ -46,12 +45,16 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
@Override @Override
public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
if (qName.equals(XmlConstants.XML_CONTAINER)) { switch (qName) {
case XmlConstants.XML_CONTAINER:
this.buildersStack.push(new ContainerParser()); this.buildersStack.push(new ContainerParser());
} else if (qName.equals(XmlConstants.XML_PARAMETERS)) { break;
case XmlConstants.XML_PARAMETERS:
this.buildersStack.push(new ParametersParser()); this.buildersStack.push(new ParametersParser());
} else if (qName.equals(XmlConstants.XML_POLICIES)) { break;
case XmlConstants.XML_POLICIES:
this.buildersStack.push(new PoliciesParser()); this.buildersStack.push(new PoliciesParser());
break;
} }
if (!this.buildersStack.isEmpty()) if (!this.buildersStack.isEmpty())
@ -71,12 +74,12 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
this.buildersStack.peek().endElement(uri, localName, qName); this.buildersStack.peek().endElement(uri, localName, qName);
ElementParser elementParser = null; ElementParser elementParser = null;
if (qName.equals(XmlConstants.XML_CONTAINER)) { switch (qName) {
elementParser = this.buildersStack.pop(); case XmlConstants.XML_CONTAINER:
} else if (qName.equals(XmlConstants.XML_PARAMETERS)) { case XmlConstants.XML_PARAMETERS:
elementParser = this.buildersStack.pop(); case XmlConstants.XML_POLICIES:
} else if (qName.equals(XmlConstants.XML_POLICIES)) {
elementParser = this.buildersStack.pop(); elementParser = this.buildersStack.pop();
break;
} }
if (!this.buildersStack.isEmpty() && elementParser != null) if (!this.buildersStack.isEmpty() && elementParser != null)
@ -90,28 +93,47 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
@Override @Override
public void startElement(String uri, String localName, String qName, Attributes attributes) public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException { throws SAXException {
if (qName.equals(XmlConstants.XML_CONTAINER)) {
switch (qName) {
case XmlConstants.XML_CONTAINER:
this.currentElement = qName; this.currentElement = qName;
} else if (qName.equals(XmlConstants.XML_HANDLER_ENCRYPTION)) { break;
case XmlConstants.XML_HANDLER_ENCRYPTION: {
this.currentElement = qName; this.currentElement = qName;
String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS); String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS);
getContainerModel().setEncryptionHandlerClassName(className); getContainerModel().setEncryptionHandlerClassName(className);
} else if (qName.equals(XmlConstants.XML_HANDLER_PERSISTENCE)) { break;
}
case XmlConstants.XML_HANDLER_PASSWORD_STRENGTH: {
this.currentElement = qName;
String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS);
getContainerModel().setPasswordStrengthHandlerClassName(className);
break;
}
case XmlConstants.XML_HANDLER_PERSISTENCE: {
this.currentElement = qName; this.currentElement = qName;
String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS); String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS);
getContainerModel().setPersistenceHandlerClassName(className); getContainerModel().setPersistenceHandlerClassName(className);
} else if (qName.equals(XmlConstants.XML_HANDLER_USER_CHALLENGE)) { break;
}
case XmlConstants.XML_HANDLER_USER_CHALLENGE: {
this.currentElement = qName; this.currentElement = qName;
String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS); String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS);
getContainerModel().setUserChallengeHandlerClassName(className); getContainerModel().setUserChallengeHandlerClassName(className);
} else if (qName.equals(XmlConstants.XML_HANDLER_SSO)) { break;
}
case XmlConstants.XML_HANDLER_SSO: {
this.currentElement = qName; this.currentElement = qName;
String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS); String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS);
getContainerModel().setSsoHandlerClassName(className); getContainerModel().setSsoHandlerClassName(className);
} else if (qName.equals(XmlConstants.XML_HANDLER_PRIVILEGE)) { break;
}
case XmlConstants.XML_HANDLER_PRIVILEGE: {
this.currentElement = qName; this.currentElement = qName;
String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS); String className = attributes.getValue(XmlConstants.XML_ATTR_CLASS);
getContainerModel().setPrivilegeHandlerClassName(className); getContainerModel().setPrivilegeHandlerClassName(className);
break;
}
} }
} }
@ -122,27 +144,37 @@ public class PrivilegeConfigSaxReader extends DefaultHandler {
ParametersParser parametersChild = (ParametersParser) child; ParametersParser parametersChild = (ParametersParser) child;
if (this.currentElement.equals(XmlConstants.XML_CONTAINER)) { switch (this.currentElement) {
case XmlConstants.XML_CONTAINER:
getContainerModel().setParameterMap(parametersChild.getParameterMap()); getContainerModel().setParameterMap(parametersChild.getParameterMap());
} else if (this.currentElement.equals(XmlConstants.XML_HANDLER_ENCRYPTION)) { break;
case XmlConstants.XML_HANDLER_ENCRYPTION:
getContainerModel().setEncryptionHandlerParameterMap(parametersChild.getParameterMap()); getContainerModel().setEncryptionHandlerParameterMap(parametersChild.getParameterMap());
} else if (this.currentElement.equals(XmlConstants.XML_HANDLER_PERSISTENCE)) { break;
case XmlConstants.XML_HANDLER_PASSWORD_STRENGTH:
getContainerModel().setPasswordStrengthHandlerParameterMap(parametersChild.getParameterMap());
break;
case XmlConstants.XML_HANDLER_PERSISTENCE:
getContainerModel().setPersistenceHandlerParameterMap(parametersChild.getParameterMap()); getContainerModel().setPersistenceHandlerParameterMap(parametersChild.getParameterMap());
} else if (this.currentElement.equals(XmlConstants.XML_HANDLER_USER_CHALLENGE)) { break;
case XmlConstants.XML_HANDLER_USER_CHALLENGE:
getContainerModel().setUserChallengeHandlerParameterMap(parametersChild.getParameterMap()); getContainerModel().setUserChallengeHandlerParameterMap(parametersChild.getParameterMap());
} else if (this.currentElement.equals(XmlConstants.XML_HANDLER_SSO)) { break;
case XmlConstants.XML_HANDLER_SSO:
getContainerModel().setSsoHandlerParameterMap(parametersChild.getParameterMap()); getContainerModel().setSsoHandlerParameterMap(parametersChild.getParameterMap());
} else if (this.currentElement.equals(XmlConstants.XML_HANDLER_PRIVILEGE)) { break;
case XmlConstants.XML_HANDLER_PRIVILEGE:
getContainerModel().setPrivilegeHandlerParameterMap(parametersChild.getParameterMap()); getContainerModel().setPrivilegeHandlerParameterMap(parametersChild.getParameterMap());
break;
} }
} }
} }
class ParametersParser extends ElementParserAdapter { static class ParametersParser extends ElementParserAdapter {
// <Parameter name="autoPersistOnPasswordChange" value="true" /> // <Parameter name="autoPersistOnPasswordChange" value="true" />
private Map<String, String> parameterMap = new HashMap<>(); private final Map<String, String> parameterMap = new HashMap<>();
@Override @Override
public void startElement(String uri, String localName, String qName, Attributes attributes) public void startElement(String uri, String localName, String qName, Attributes attributes)

View File

@ -15,3 +15,10 @@ Privilege.noprivilege.role=User {0} does not have the role {1}
Privilege.noprivilege.user=User {0} does not have the privilege {1} Privilege.noprivilege.user=User {0} does not have the privilege {1}
Privilege.roleAccessPrivilege.unknownPrivilege=Unhandled privilege {0} for policy {1} Privilege.roleAccessPrivilege.unknownPrivilege=Unhandled privilege {0} for policy {1}
Privilege.userAccessPrivilege.unknownPrivilege=Unhandled privilege {0} for policy {1} Privilege.userAccessPrivilege.unknownPrivilege=Unhandled privilege {0} for policy {1}
Privilege.passwordLengthBetween=Password must be between {0} and {1} characters long
Privilege.passwordLengthAtLeast=Password must be at least {0} characters long
Privilege.passwordMustContainNumbers=must contain numbers
Privilege.passwordMustContainLowerAndUpperCase=must container lower and upper case
Privilege.passwordMustContainLowerCase=must contain lower case
Privilege.passwordMustContainUpperCase=must contain upper case
Privilege.passwordMustContainSpecialCharacters=must contain special characters

View File

@ -0,0 +1,24 @@
Privilege.accessdenied.noprivilege=Benutzer {0} fehlt Privileg {1} benötigt von {2} mit Wert {3}
Privilege.accessdenied.noprivilege.value=Benutzer {0} fehlt Privileg {1} mit Wert {2} benötigt von {3}
Privilege.illegalArgument.nonstring=\ {0} has returned a non-string privilege value\!
Privilege.illegalArgument.nonstrolchrootelement=\ {0} has returned a privilege value which is not a StrolchRootElement\!
Privilege.illegalArgument.nonrole=\ {0} did not return a Role privilege value\!
Privilege.illegalArgument.noncertificate=\ {0} did not return a Certificate privilege value\!
Privilege.illegalArgument.nonuser=\ {0} did not return a User privilege value\!
Privilege.illegalArgument.privilegeNameMismatch=The passed privilege has the name {0} but the restrictable is referencing privilege {1}
Privilege.illegalArgument.nontuple=\ {0} did not return a Tuple privilege value\!
Privilege.privilegeNameEmpty=The PrivilegeName for the Restrictable is null or empty: {0}
Privilege.privilegeNull=Privilege may not be null\!
Privilege.restrictableNull=Restrictable may not be null\!
Privilege.noprivilege=Privileg {0} existiert nicht
Privilege.noprivilege.role=Benutzer {0} fehlt Rolle {1}
Privilege.noprivilege.user=Benutzer {0} fehlt Privileg {1}
Privilege.roleAccessPrivilege.unknownPrivilege=Unbekanntes Privileg {0} für Regel {1}
Privilege.userAccessPrivilege.unknownPrivilege=Unbekanntes Privileg {0} für Regel {1}
Privilege.passwordLengthBetween=Passwort muss zwischen {0} und {1} Zeichen lang sein
Privilege.passwordLengthAtLeast=Passwort muss mindesten {0} Zeichen lang sein
Privilege.passwordMustContainNumbers=muss Zahlen beinhalten
Privilege.passwordMustContainLowerAndUpperCase=muss grosse und kleine Buchstaben beinhalten
Privilege.passwordMustContainLowerCase=muss kleine Buchstaben beinhalten
Privilege.passwordMustContainUpperCase=muss grosse Buchstaben beinhalten
Privilege.passwordMustContainSpecialCharacters=muss Spezialzeichen beinhalten

View File

@ -0,0 +1,52 @@
package li.strolch.privilege.test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.util.HashMap;
import java.util.Map;
import li.strolch.privilege.handler.BasicPasswordStrengthHandler;
import li.strolch.privilege.handler.PasswordStrengthHandler;
import org.junit.Test;
public class BasicPasswordStrengthHandlerTest {
@Test
public void testPwStrengthBasic() {
PasswordStrengthHandler handler = new BasicPasswordStrengthHandler();
Map<String, String> parameters = new HashMap<>();
parameters.put("minLength", "8");
parameters.put("maxLength", "1024");
parameters.put("needsNumbers", "true");
parameters.put("needsLowerCase", "true");
parameters.put("needsUpperCase", "true");
parameters.put("needsSpecialChars", "true");
handler.initialize(parameters);
assertTrue(handler.validateStrength("Testing0!".toCharArray()));
assertTrue(handler.validateStrength("Täëing0!".toCharArray()));
assertTrue(handler.validateStrength("Testing0@".toCharArray()));
assertTrue(handler.validateStrength("Testing0¼".toCharArray()));
assertTrue(handler.validateStrength("Testing0|".toCharArray()));
assertTrue(handler.validateStrength("+n4lJ,7&".toCharArray()));
assertTrue(handler.validateStrength("]}`aH1&z".toCharArray()));
assertFalse(handler.validateStrength("Tg0!".toCharArray()));
}
@Test
public void testPwStrengthOnlyNumbers() {
PasswordStrengthHandler handler = new BasicPasswordStrengthHandler();
Map<String, String> parameters = new HashMap<>();
parameters.put("minLength", "8");
parameters.put("maxLength", "8");
parameters.put("needsNumbers", "true");
parameters.put("needsLowerCase", "false");
parameters.put("needsUpperCase", "false");
parameters.put("needsSpecialChars", "false");
handler.initialize(parameters);
assertTrue(handler.validateStrength("34534534".toCharArray()));
assertFalse(handler.validateStrength("Testing0!".toCharArray()));
}
}