Skip to content

Commit

Permalink
feat: apply password validation when defined and enabled #8146
Browse files Browse the repository at this point in the history
Signed-off-by: jgomer2001 <bonustrack310@gmail.com>
  • Loading branch information
jgomer2001 committed Jun 14, 2024
1 parent 552f7c4 commit 7d5f85b
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ public class AppConfiguration implements Configuration, Serializable {
private Boolean disableJdkLogger = true;
@DocProperty(description = "Boolean value specifying whether to enable local in-memory cache")
private Boolean useLocalCache = false;
@DocProperty(description = "Boolean value specifying whether to bypass the validation defined upon the password attribute")
private boolean skipDefinedPasswordValidation;

public String getBaseDN() {
return baseDN;
Expand Down Expand Up @@ -197,4 +199,12 @@ public void setUseLocalCache(Boolean useLocalCache) {
this.useLocalCache = useLocalCache;
}

public boolean isSkipDefinedPasswordValidation() {
return skipDefinedPasswordValidation;
}

public void setSkipDefinedPasswordValidation(boolean skipDefinedPasswordValidation) {
this.skipDefinedPasswordValidation = skipDefinedPasswordValidation;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import jakarta.annotation.PostConstruct;
Expand All @@ -30,7 +31,9 @@
import com.fasterxml.jackson.databind.ObjectMapper;

import io.jans.scim.model.conf.AppConfiguration;
import io.jans.model.attribute.AttributeValidation;
import io.jans.model.GluuStatus;
import io.jans.model.JansAttribute;
import io.jans.orm.PersistenceEntryManager;
import io.jans.orm.model.PagedResult;
import io.jans.orm.model.SortOrder;
Expand Down Expand Up @@ -619,6 +622,42 @@ public void removePPIDsBranch(String dn) {
log.error(e.getMessage(), e);
}
}

public boolean passwordValidationPassed(String password) {

try {
Filter filter = Filter.createEqualityFilter("jansAttrName", "userPassword");
List<JansAttribute> attrs = ldapEntryManager.findEntries("ou=attributes,o=jans",
JansAttribute.class, filter, new String[] { "jansValidation" }, 1);

AttributeValidation av = attrs.get(0).getAttributeValidation();

if (av == null) return true;

int len = Optional.ofNullable(av.getMinLength()).orElse(0);
if (len > 0 && password.length() < len) {
log.error("Password is required to have at least {} characters", len);
return false;
}

len = Optional.ofNullable(av.getMaxLength()).orElse(0);
if (len > 0 && password.length() > len) {
log.error("Password is required to have at most {} characters", len);
return false;
}

String regex = av.getRegexp();
if (regex != null && !Pattern.matches(regex, password)) {
log.error("Provided password does not match the regular expression {}", regex);
return false;
}

} catch (Exception e) {
log.error(e.getMessage(), e);
}
return true;

}

@PostConstruct
private void init() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,21 @@ private void checkUidExistence(String uid, String id) throws DuplicateEntryExcep
}

}

private void executeUserValidation(UserResource user, boolean laxRequiredness)
throws SCIMException {

executeValidation(user, laxRequiredness);
//See #8146
if (!appConfiguration.isSkipDefinedPasswordValidation()) {
String pwd = user.getPassword();

if (pwd != null && !scim2UserService.passwordValidationPassed(pwd))
throw new SCIMException("Supplied password not conformant to validation " +
"rules defined upon password attribute");
}

}

private Response doSearch(String filter, Integer startIndex, Integer count, String sortBy,
String sortOrder, String attrsList, String excludedAttrsList, String method) {
Expand Down Expand Up @@ -148,7 +163,7 @@ public Response createUser(
try {
log.debug("Executing web service method. createUser");

executeValidation(user);
executeUserValidation(user, false);
if (StringUtils.isEmpty(user.getUserName())) throw new SCIMException("Empty username not allowed");

checkUidExistence(user.getUserName());
Expand Down Expand Up @@ -244,7 +259,7 @@ public Response updateUser(
httpHeaders, uriInfo, HttpMethod.PUT, userResourceType);
if (response != null) return response;

executeValidation(user, true);
executeUserValidation(user, true);
if (StringUtils.isNotEmpty(user.getUserName())) {
checkUidExistence(user.getUserName(), id);
}
Expand Down Expand Up @@ -389,7 +404,7 @@ public Response patchUser(

//Throws exception if final representation does not pass overall validation
log.debug("patchUser. Revising final resource representation still passes validations");
executeValidation(user);
executeUserValidation(user, false);
ScimResourceUtil.adjustPrimarySubAttributes(user);

//Update timestamp
Expand Down

0 comments on commit 7d5f85b

Please sign in to comment.