use of com.evolveum.midpoint.xml.ns._public.common.common_3.StringLimitType in project midpoint by Evolveum.
the class ValuePolicyProcessor method validateValue.
public <O extends ObjectType> boolean validateValue(String newValue, ValuePolicyType pp, PrismObject<O> object, StringBuilder message, String shortDesc, Task task, OperationResult parentResult) throws SchemaException, ObjectNotFoundException, ExpressionEvaluationException {
Validate.notNull(pp, "Value policy must not be null.");
OperationResult result = parentResult.createSubresult(OPERATION_STRING_POLICY_VALIDATION);
result.addParam("policyName", pp.getName());
normalize(pp);
if (newValue == null && (pp.getMinOccurs() == null || XsdTypeMapper.multiplicityToInteger(pp.getMinOccurs()) == 0)) {
// No password is allowed
result.recordSuccess();
return true;
}
if (newValue == null) {
newValue = "";
}
LimitationsType lims = pp.getStringPolicy().getLimitations();
testMinimalLength(newValue, lims, result, message);
testMaximalLength(newValue, lims, result, message);
testMinimalUniqueCharacters(newValue, lims, result, message);
if (lims.getLimit() == null || lims.getLimit().isEmpty()) {
if (message.toString() == null || message.toString().isEmpty()) {
result.computeStatus();
} else {
result.computeStatus(message.toString());
}
return result.isAcceptable();
}
// check limitation
HashSet<String> validChars = null;
HashSet<String> allValidChars = new HashSet<>();
List<String> passwd = StringPolicyUtils.stringTokenizer(newValue);
for (StringLimitType stringLimitationType : lims.getLimit()) {
OperationResult limitResult = new OperationResult("Tested limitation: " + stringLimitationType.getDescription());
validChars = getValidCharacters(stringLimitationType.getCharacterClass(), pp);
int count = countValidCharacters(validChars, passwd);
allValidChars.addAll(validChars);
testMinimalOccurence(stringLimitationType, count, limitResult, message);
testMaximalOccurence(stringLimitationType, count, limitResult, message);
testMustBeFirst(stringLimitationType, count, limitResult, message, newValue, validChars);
limitResult.computeStatus();
result.addSubresult(limitResult);
}
testInvalidCharacters(passwd, allValidChars, result, message);
testCheckExpression(newValue, lims, object, shortDesc, task, result, message);
if (message.toString() == null || message.toString().isEmpty()) {
result.computeStatus();
} else {
result.computeStatus(message.toString());
}
return result.isAcceptable();
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.StringLimitType in project midpoint by Evolveum.
the class ValuePolicyProcessor method cardinalityCounter.
/**
* Count cardinality
*/
private Map<Integer, List<String>> cardinalityCounter(Map<StringLimitType, List<String>> lims, List<String> password, Boolean skipMatchedLims, boolean uniquenessReached, OperationResult op) {
HashMap<String, Integer> counter = new HashMap<String, Integer>();
for (StringLimitType l : lims.keySet()) {
int counterKey = 1;
List<String> chars = lims.get(l);
int i = 0;
if (null != password) {
i = charIntersectionCounter(lims.get(l), password);
}
// If max is exceed then error unable to continue
if (l.getMaxOccurs() != null && i > l.getMaxOccurs()) {
OperationResult o = new OperationResult("Limitation check :" + l.getDescription());
o.recordFatalError("Exceeded maximal value for this limitation. " + i + ">" + l.getMaxOccurs());
op.addSubresult(o);
return null;
// if max is all ready reached or skip enabled for minimal skip
// counting
} else if (l.getMaxOccurs() != null && i == l.getMaxOccurs()) {
continue;
// other cases minimum is not reached
} else if ((l.getMinOccurs() == null || i >= l.getMinOccurs()) && !skipMatchedLims) {
continue;
}
for (String s : chars) {
if (null == password || !password.contains(s) || uniquenessReached) {
// if (null == counter.get(s)) {
counter.put(s, counterKey);
// } else {
// counter.put(s, counter.get(s) + 1);
// }
}
}
counterKey++;
}
// If need to remove disabled chars (already reached limitations)
if (null != password) {
for (StringLimitType l : lims.keySet()) {
int i = charIntersectionCounter(lims.get(l), password);
if (l.getMaxOccurs() != null && i > l.getMaxOccurs()) {
OperationResult o = new OperationResult("Limitation check :" + l.getDescription());
o.recordFatalError("Exceeded maximal value for this limitation. " + i + ">" + l.getMaxOccurs());
op.addSubresult(o);
return null;
} else if (l.getMaxOccurs() != null && i == l.getMaxOccurs()) {
// limitation matched remove all used chars
LOGGER.trace("Skip " + l.getDescription());
for (String charToRemove : lims.get(l)) {
counter.remove(charToRemove);
}
}
}
}
// Transpone to better format
Map<Integer, List<String>> ret = new HashMap<Integer, List<String>>();
for (String s : counter.keySet()) {
// if not there initialize
if (null == ret.get(counter.get(s))) {
ret.put(counter.get(s), new ArrayList<String>());
}
ret.get(counter.get(s)).add(s);
}
return ret;
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.StringLimitType in project midpoint by Evolveum.
the class ValuePolicyProcessor method generateAttempt.
private String generateAttempt(StringPolicyType policy, int defaultLength, boolean generateMinimalSize, OperationResult result) {
// if (policy.getLimitations() != null &&
// policy.getLimitations().getMinLength() != null){
// generateMinimalSize = true;
// }
// setup default values where missing
// PasswordPolicyUtils.normalize(pp);
// Optimize usage of limits ass hashmap of limitas and key is set of
// valid chars for each limitation
Map<StringLimitType, List<String>> lims = new HashMap<StringLimitType, List<String>>();
int minLen = defaultLength;
int maxLen = defaultLength;
int unique = defaultLength / 2;
if (policy != null) {
for (StringLimitType l : policy.getLimitations().getLimit()) {
if (null != l.getCharacterClass().getValue()) {
lims.put(l, StringPolicyUtils.stringTokenizer(l.getCharacterClass().getValue()));
} else {
lims.put(l, StringPolicyUtils.stringTokenizer(StringPolicyUtils.collectCharacterClass(policy.getCharacterClass(), l.getCharacterClass().getRef())));
}
}
// Get global limitations
minLen = policy.getLimitations().getMinLength() == null ? 0 : policy.getLimitations().getMinLength().intValue();
if (minLen != 0 && minLen > defaultLength) {
defaultLength = minLen;
}
maxLen = (policy.getLimitations().getMaxLength() == null ? 0 : policy.getLimitations().getMaxLength().intValue());
unique = policy.getLimitations().getMinUniqueChars() == null ? minLen : policy.getLimitations().getMinUniqueChars().intValue();
}
// test correctness of definition
if (unique > minLen) {
minLen = unique;
OperationResult reportBug = new OperationResult("Global limitation check");
reportBug.recordWarning("There is more required uniq characters then definied minimum. Raise minimum to number of required uniq chars.");
}
if (minLen == 0 && maxLen == 0) {
minLen = defaultLength;
maxLen = defaultLength;
generateMinimalSize = true;
}
if (maxLen == 0) {
if (minLen > defaultLength) {
maxLen = minLen;
} else {
maxLen = defaultLength;
}
}
// Initialize generator
StringBuilder password = new StringBuilder();
/*
* ********************************** Try to find best characters to be
* first in password
*/
Map<StringLimitType, List<String>> mustBeFirst = new HashMap<StringLimitType, List<String>>();
for (StringLimitType l : lims.keySet()) {
if (l.isMustBeFirst() != null && l.isMustBeFirst()) {
mustBeFirst.put(l, lims.get(l));
}
}
// If any limitation was found to be first
if (!mustBeFirst.isEmpty()) {
Map<Integer, List<String>> posibleFirstChars = cardinalityCounter(mustBeFirst, null, false, false, result);
int intersectionCardinality = mustBeFirst.keySet().size();
List<String> intersectionCharacters = posibleFirstChars.get(intersectionCardinality);
// If no intersection was found then raise error
if (null == intersectionCharacters || intersectionCharacters.size() == 0) {
result.recordFatalError("No intersection for required first character sets in value policy:" + policy.getDescription());
// Log error
if (LOGGER.isErrorEnabled()) {
LOGGER.error("Unable to generate value for " + getPath() + ": No intersection for required first character sets in value policy: [" + policy.getDescription() + "] following character limitation and sets are used:");
for (StringLimitType l : mustBeFirst.keySet()) {
StrBuilder tmp = new StrBuilder();
tmp.appendSeparator(", ");
tmp.appendAll(mustBeFirst.get(l));
LOGGER.error("L:" + l.getDescription() + " -> [" + tmp + "]");
}
}
// EXIT
return null;
} else {
if (LOGGER.isDebugEnabled()) {
StrBuilder tmp = new StrBuilder();
tmp.appendSeparator(", ");
tmp.appendAll(intersectionCharacters);
LOGGER.trace("Generate first character intersection items [" + tmp + "] into " + getPath() + ".");
}
// Generate random char into password from intersection
password.append(intersectionCharacters.get(RAND.nextInt(intersectionCharacters.size())));
}
}
/*
* ************************************** Generate rest to fulfill
* minimal criteria
*/
boolean uniquenessReached = false;
// Count cardinality of elements
Map<Integer, List<String>> chars;
for (int i = 0; i < minLen; i++) {
// Check if still unique chars are needed
if (password.length() >= unique) {
uniquenessReached = true;
}
// Find all usable characters
chars = cardinalityCounter(lims, StringPolicyUtils.stringTokenizer(password.toString()), false, uniquenessReached, result);
// If something goes badly then go out
if (null == chars) {
return null;
}
if (chars.isEmpty()) {
LOGGER.trace("Minimal criterias was met. No more characters");
break;
}
// Find lowest possible cardinality and then generate char
for (int card = 1; card < lims.keySet().size(); card++) {
if (chars.containsKey(card)) {
List<String> validChars = chars.get(card);
password.append(validChars.get(RAND.nextInt(validChars.size())));
break;
}
}
}
// test if maximum is not exceeded
if (password.length() > maxLen) {
result.recordFatalError("Unable to meet minimal criteria and not exceed maximxal size of " + getPath() + ".");
return null;
}
for (int i = 0; i < minLen; i++) {
// test if max is reached
if (password.length() == maxLen) {
// no more characters maximal size is reached
break;
}
if (password.length() >= minLen && generateMinimalSize) {
// no more characters are needed
break;
}
// Check if still unique chars are needed
if (password.length() >= unique) {
uniquenessReached = true;
}
// find all usable characters
chars = cardinalityCounter(lims, StringPolicyUtils.stringTokenizer(password.toString()), true, uniquenessReached, result);
// If something goes badly then go out
if (null == chars) {
// we hope this never happend.
result.recordFatalError("No valid characters to generate, but no all limitation are reached");
return null;
}
// our work
if (chars.isEmpty()) {
if (i == 0) {
password.append(RandomStringUtils.randomAlphanumeric(minLen));
}
break;
// if (!StringUtils.isBlank(password.toString()) &&
// password.length() >= minLen) {
// break;
// }
// check uf this is a firs cycle and if we need to user some
// default (alphanum) character class.
}
// Find lowest possible cardinality and then generate char
for (int card = 1; card <= lims.keySet().size(); card++) {
if (chars.containsKey(card)) {
List<String> validChars = chars.get(card);
password.append(validChars.get(RAND.nextInt(validChars.size())));
break;
}
}
}
if (password.length() < minLen) {
result.recordFatalError("Unable to generate value for " + getPath() + " and meet minimal size of " + getPath() + ". Actual lenght: " + password.length() + ", required: " + minLen);
LOGGER.trace("Unable to generate value for " + getPath() + " and meet minimal size of " + getPath() + ". Actual lenght: {}, required: {}", password.length(), minLen);
return null;
}
result.recordSuccess();
// Shuffle output to solve pattern like output
StrBuilder sb = new StrBuilder(password.substring(0, 1));
List<String> shuffleBuffer = StringPolicyUtils.stringTokenizer(password.substring(1));
Collections.shuffle(shuffleBuffer);
sb.appendAll(shuffleBuffer);
return sb.toString();
}
use of com.evolveum.midpoint.xml.ns._public.common.common_3.StringLimitType in project midpoint by Evolveum.
the class TestPasswordPolicy method testPasswordGeneratorComplexNegative.
@Test
public void testPasswordGeneratorComplexNegative() throws Exception {
final String TEST_NAME = "testPasswordGeneratorComplexNegative";
TestUtil.displayTestTile(TEST_NAME);
Task task = createTask(TEST_NAME);
OperationResult result = task.getResult();
File file = new File(TEST_DIR, "password-policy-complex.xml");
ValuePolicyType pp = (ValuePolicyType) PrismTestUtil.parseObject(file).asObjectable();
// Make switch some cosistency
pp.getStringPolicy().getLimitations().setMinLength(2);
pp.getStringPolicy().getLimitations().setMinUniqueChars(5);
// WHEN
TestUtil.displayWhen(TEST_NAME);
String psswd = valuePolicyProcessor.generate(SchemaConstants.PATH_PASSWORD_VALUE, pp.getStringPolicy(), 10, null, TEST_NAME, task, result);
// THEN
TestUtil.displayThen(TEST_NAME);
display("Generated password", psswd);
result.computeStatus();
AssertJUnit.assertTrue(result.isAcceptable());
assertNotNull(psswd);
// Switch to all must be first :-) to test if there is error
for (StringLimitType l : pp.getStringPolicy().getLimitations().getLimit()) {
l.setMustBeFirst(true);
}
LOGGER.info("Negative testing: passwordGeneratorComplexTest");
try {
valuePolicyProcessor.generate(SchemaConstants.PATH_PASSWORD_VALUE, pp.getStringPolicy(), 10, null, TEST_NAME, task, result);
assertNotReached();
} catch (ExpressionEvaluationException e) {
result.computeStatus();
TestUtil.assertFailure(result);
}
}
Aggregations