Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9059,7 +9059,7 @@ private Map<String, String> doGetUserClaimValues(String userName, String[] claim
Map<String, String> userPropertyValues = this.getUserPropertyValues(userName, properties,
profileName);

processAttributesAfterRetrieval(userName, userPropertyValues, profileName);
processAttributesAfterRetrievalWithException(userName, userPropertyValues, profileName);

List<String> getAgain = new ArrayList<>();
Map<String, String> finalValues = new HashMap<>();
Expand Down Expand Up @@ -9189,12 +9189,30 @@ private Map<String, String> doGetUserClaimValues(String userName, String[] claim
* @param userName Username of the user.
* @param userAttributes Un-processed map (user store attribute name -> attribute value) of user store.
* @param profileName Profile name of the user.
*
* @deprecated Please use {@link #processAttributesAfterRetrievalWithException(String, Map, String)}
* instead which throws UserStoreException.
* This method is kept for backward compatibility and will be removed in future releases.
*/
@Deprecated
protected void processAttributesAfterRetrieval(String userName, Map<String, String> userAttributes,
String profileName) {
// Not implemented for AbstractUserStoreManager, may have implementations at subclasses.
}

/**
* Handles the processing of any special user store attribute values after retrieval.
*
* @param userName Username of the user.
* @param userAttributes Un-processed map (user store attribute name -> attribute value) of user store.
* @param profileName Profile name of the user.
*/
protected void processAttributesAfterRetrievalWithException(String userName, Map<String, String> userAttributes,
String profileName) throws UserStoreException {

processAttributesAfterRetrieval(userName, userAttributes, profileName);
Comment on lines +9209 to +9213

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 1

Suggested change
*/
protected void processAttributesAfterRetrievalWithException(String userName, Map<String, String> userAttributes,
String profileName) throws UserStoreException {
processAttributesAfterRetrieval(userName, userAttributes, profileName);
protected void processAttributesAfterRetrievalWithException(String userName, Map<String, String> userAttributes,
String profileName) throws UserStoreException {
if (log.isDebugEnabled()) {
log.debug("Processing attributes after retrieval for user: " + userName + ", profile: " + profileName);
}
processAttributesAfterRetrieval(userName, userAttributes, profileName);

}

/**
* Handles the processing of any special user store attribute values before update.
*
Expand All @@ -9213,12 +9231,30 @@ protected void processAttributesBeforeUpdate(String userName, Map<String, ? exte
* @param userID User ID of the user.
* @param userAttributes Un-processed map (user store attribute name -> attribute value) of user store.
* @param profileName Profile name of the user.
*
* @deprecated Please use {@link #processAttributesAfterRetrievalWithIDWithException(String, Map, String)}
* instead which throws UserStoreException.
* This method is kept for backward compatibility and will be removed in future releases.
*/
@Deprecated
protected void processAttributesAfterRetrievalWithID(String userID, Map<String, String> userAttributes,
String profileName) {
// Not implemented for AbstractUserStoreManager, may have implementations at subclasses.
}

/**
* Handles the processing of any special user store attribute values after retrieval.
*
* @param userID User ID of the user.
* @param userAttributes Un-processed map (user store attribute name -> attribute value) of user store.
* @param profileName Profile name of the user.
*/
protected void processAttributesAfterRetrievalWithIDWithException(String userID, Map<String, String> userAttributes,
String profileName) throws UserStoreException {

processAttributesAfterRetrievalWithID(userID, userAttributes, profileName);
Comment on lines +9251 to +9255

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 2

Suggested change
*/
protected void processAttributesAfterRetrievalWithIDWithException(String userID, Map<String, String> userAttributes,
String profileName) throws UserStoreException {
processAttributesAfterRetrievalWithID(userID, userAttributes, profileName);
protected void processAttributesAfterRetrievalWithIDWithException(String userID, Map<String, String> userAttributes,
String profileName) throws UserStoreException {
if (log.isDebugEnabled()) {
log.debug("Processing attributes after retrieval for userID: " + userID + ", profile: " + profileName);
}
processAttributesAfterRetrievalWithID(userID, userAttributes, profileName);

}

/**
* Handles the processing of any special user store attribute values before update.
*
Expand Down Expand Up @@ -10975,7 +11011,7 @@ protected Map<String, Map<String, String>> getUsersPropertyValues(List<String> u
Map<String, Map<String, String>> usersPropertyValuesMap = new HashMap<>();
for (String userName : users) {
Map<String, String> propertyValuesMap = getUserPropertyValues(userName, propertyNames, profileName);
processAttributesAfterRetrieval(userName, propertyValuesMap, profileName);
processAttributesAfterRetrievalWithException(userName, propertyValuesMap, profileName);
if (propertyValuesMap != null && !propertyValuesMap.isEmpty()) {
usersPropertyValuesMap.put(userName, propertyValuesMap);
}
Expand Down Expand Up @@ -13491,7 +13527,7 @@ protected Map<String, String> doGetUserClaimValuesWithID(String userID, String[]

String[] properties = propertySet.toArray(new String[0]);
Map<String, String> userPropertyValues = this.getUserPropertyValuesWithID(userID, properties, profileName);
processAttributesAfterRetrievalWithID(userID, userPropertyValues, profileName);
processAttributesAfterRetrievalWithIDWithException(userID, userPropertyValues, profileName);

List<String> getAgain = new ArrayList<>();
Map<String, String> finalValues = new HashMap<>();
Expand Down Expand Up @@ -17932,7 +17968,7 @@ protected Map<String, Map<String, String>> getUsersPropertyValuesWithID(List<Str
Map<String, Map<String, String>> usersPropertyValuesMap = new HashMap<>();
for (String userID : userIDs) {
Map<String, String> propertyValuesMap = getUserPropertyValuesWithID(userID, propertyNames, profileName);
processAttributesAfterRetrievalWithID(userID, propertyValuesMap, profileName);
processAttributesAfterRetrievalWithIDWithException(userID, propertyValuesMap, profileName);
if (propertyValuesMap != null && !propertyValuesMap.isEmpty()) {
usersPropertyValuesMap.put(userID, propertyValuesMap);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4857,6 +4857,23 @@ protected boolean isGUIDValue(String value) {
protected void processAttributesAfterRetrieval(String userName, Map<String, String> userStorePropertyValues,
String profileName) {

try {
processAttributesAfterRetrieval(userStorePropertyValues);
} catch (UserStoreException e) {
Comment on lines 4857 to +4862

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 3

Suggested change
protected void processAttributesAfterRetrieval(String userName, Map<String, String> userStorePropertyValues,
String profileName) {
try {
processAttributesAfterRetrieval(userStorePropertyValues);
} catch (UserStoreException e) {
protected void processAttributesAfterRetrieval(String userName, Map<String, String> userStorePropertyValues,
String profileName) {
if (logger.isDebugEnabled()) {
logger.debug("Processing attributes after retrieval for user: " + userName);
}
try {
processAttributesAfterRetrieval(userStorePropertyValues);

logger.error("Error while processing attributes after retrieval with ID for userID: " + userName, e);
}
}

@Override
protected void processAttributesAfterRetrievalWithException(String userName, Map<String,
String> userStorePropertyValues, String profileName) throws UserStoreException {

processAttributesAfterRetrieval(userStorePropertyValues);
}

private void processAttributesAfterRetrieval(Map<String, String> userStorePropertyValues)
throws UserStoreException {

Comment on lines +4874 to +4876

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 4

Suggested change
private void processAttributesAfterRetrieval(Map<String, String> userStorePropertyValues)
throws UserStoreException {
throws UserStoreException {
if (logger.isDebugEnabled()) {
logger.debug("Processing attributes with timestamp conversions");
}
String timestampAttributesProperty = Optional.ofNullable(realmConfig

String timestampAttributesProperty = Optional.ofNullable(realmConfig
.getUserStoreProperty(UserStoreConfigConstants.timestampAttributes)).orElse(StringUtils.EMPTY);

Expand All @@ -4871,11 +4888,13 @@ protected void processAttributesAfterRetrieval(String userName, Map<String, Stri
logger.debug("Retrieved user store properties before type conversions: " + userStorePropertyValues);
}

Map<String, String> convertedTimestampAttributeValues = Arrays.stream(timestampAttributes)
.map(StringUtils::trim)
.filter(attribute -> userStorePropertyValues.get(attribute) != null)
.collect(Collectors.toMap(Function.identity(),
attribute -> convertDateFormatFromLDAP(userStorePropertyValues.get(attribute))));
Map<String, String> convertedTimestampAttributeValues = new HashMap<>();
for (String attribute : timestampAttributes) {
if (userStorePropertyValues.get(attribute) != null) {
convertedTimestampAttributeValues.put(attribute,
LDAPUtil.convertToStandardTimeFormat(realmConfig, userStorePropertyValues.get(attribute)));
}
}

if (logger.isDebugEnabled()) {
logger.debug("Converted timestamp attribute values: " + convertedTimestampAttributeValues);
Expand All @@ -4897,7 +4916,7 @@ protected void processAttributesAfterRetrieval(String userName, Map<String, Stri
*/
protected String convertDateFormatFromLDAP(String date) {

DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(GENARALIZE_DATE_TIME_FORMAT);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(date);
OffsetDateTime offsetDateTime = OffsetDateTime.parse(date, dateTimeFormatter);
Instant instant = offsetDateTime.toInstant();
return instant.toString();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,19 +177,6 @@ public class UniqueIDReadOnlyLDAPUserStoreManager extends ReadOnlyLDAPUserStoreM
// Regex pattern to match bracketed segments without nested brackets.
private static final Pattern TIMESTAMP_FORMAT_PATTERN = Pattern.compile("\\[[^\\[\\]]+\\]");

// Regex patterns for LDAP timestamp formats.
private static final Pattern NO_FRACTION_TIMESTAMP_PATTERN = Pattern.compile("^\\d{14}([-+]\\d{4}|Z)$");
private static final Pattern THREE_DIGIT_FRACTION_TIMESTAMP_PATTERN =
Pattern.compile("^\\d{14}[,\\.]\\d{3}([-+]\\d{4}|Z)$");
private static final Pattern TWO_DIGIT_FRACTION_TIMESTAMP_PATTERN =
Pattern.compile("^\\d{14}[,\\.]\\d{2}([-+]\\d{4}|Z)$");
private static final Pattern ONE_DIGIT_FRACTION_TIMESTAMP_PATTERN =
Pattern.compile("^\\d{12}[,\\.]\\d{1}([-+]\\d{4}|Z)$");
private static final Pattern ONE_DIGIT_FRACTION_WITH_SECONDS_TIMESTAMP_PATTERN =
Pattern.compile("^\\d{14}[,\\.]\\d{1}([-+]\\d{4}|Z)$");
private static final Pattern ONE_DIGIT_FRACTION_WITH_MINUTES_TIMESTAMP_PATTERN =
Pattern.compile("^\\d{12}[,\\.]\\d{1}([-+]\\d{4}|Z)$");

static {
setAdvancedProperties();
}
Expand Down Expand Up @@ -3225,8 +3212,24 @@ public boolean isUniqueUserIdEnabled() {
return true;
}

protected void processAttributesAfterRetrievalWithID(String userID, Map<String, String> userStorePropertyValues,
String profileName) {
protected void processAttributesAfterRetrievalWithID(String userID, Map<String,
String> userStorePropertyValues, String profileName) {

try {
processAttributesAfterRetrievalWithID(userStorePropertyValues);
} catch (UserStoreException e) {
Comment on lines +3215 to +3220

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 5

Suggested change
protected void processAttributesAfterRetrievalWithID(String userID, Map<String,
String> userStorePropertyValues, String profileName) {
try {
processAttributesAfterRetrievalWithID(userStorePropertyValues);
} catch (UserStoreException e) {
protected void processAttributesAfterRetrievalWithID(String userID, Map<String,
String> userStorePropertyValues, String profileName) {
log.debug("Processing attributes after retrieval for userID: " + userID);
try {
processAttributesAfterRetrievalWithID(userStorePropertyValues);
} catch (UserStoreException e) {

logger.error("Error while processing attributes after retrieval with ID for userID: " + userID, e);
}
}

protected void processAttributesAfterRetrievalWithIDWithException(String userID, Map<String,
String> userStorePropertyValues, String profileName) throws UserStoreException {

processAttributesAfterRetrievalWithID(userStorePropertyValues);
}

private void processAttributesAfterRetrievalWithID(Map<String,
String> userStorePropertyValues) throws UserStoreException {

Comment on lines +3230 to 3233

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Log Improvement Suggestion No: 6

Suggested change
private void processAttributesAfterRetrievalWithID(Map<String,
String> userStorePropertyValues) throws UserStoreException {
private void processAttributesAfterRetrievalWithID(Map<String,
String> userStorePropertyValues) throws UserStoreException {
log.debug("Processing timestamp attributes for user store properties");
String timestampAttributesProperty = Optional.ofNullable(realmConfig

String timestampAttributesProperty = Optional.ofNullable(realmConfig
.getUserStoreProperty(UserStoreConfigConstants.timestampAttributes)).orElse(StringUtils.EMPTY);
Expand All @@ -3242,10 +3245,13 @@ protected void processAttributesAfterRetrievalWithID(String userID, Map<String,
logger.debug("Retrieved user store properties before type conversions: " + userStorePropertyValues);
}

Map<String, String> convertedTimestampAttributeValues = Arrays.stream(timestampAttributes)
.filter(attribute -> userStorePropertyValues.get(attribute) != null)
.collect(Collectors.toMap(Function.identity(),
attribute -> convertDateFormatFromLDAP(userStorePropertyValues.get(attribute))));
Map<String, String> convertedTimestampAttributeValues = new HashMap<>();
for (String attribute : timestampAttributes) {
if (userStorePropertyValues.get(attribute) != null) {
convertedTimestampAttributeValues.put(attribute,
LDAPUtil.convertToStandardTimeFormat(realmConfig, userStorePropertyValues.get(attribute)));
}
}

if (logger.isDebugEnabled()) {
logger.debug("Converted timestamp attribute values: " + convertedTimestampAttributeValues);
Expand Down Expand Up @@ -4086,9 +4092,9 @@ private Group buildGroupFromAttributes(String[] responseAttributes, Attributes a
}
group.setGroupName(groupName);
} else if (realmConfig.getUserStoreProperty(GROUP_CREATED_DATE_ATTRIBUTE).equals(attributeId)) {
group.setCreatedDate(this.convertToStandardTimeFormat(value));
group.setCreatedDate(LDAPUtil.convertToStandardTimeFormat(realmConfig, value));
} else if (realmConfig.getUserStoreProperty(GROUP_LAST_MODIFIED_DATE_ATTRIBUTE).equals(attributeId)) {
group.setLastModifiedDate(this.convertToStandardTimeFormat(value));
group.setLastModifiedDate(LDAPUtil.convertToStandardTimeFormat(realmConfig, value));
} else {
log.error("Unsupported group attribute: when building the group response object" + attributeId);
}
Expand All @@ -4106,45 +4112,6 @@ private Group buildGroupFromAttributes(String[] responseAttributes, Attributes a
return group;
}

/**
* Covert the LDAP timestamp format (Zulutime) to the generic timestamp supported by the identity server.
* Refer to the "Generalized Time" section in the spec: https://www.ietf.org/rfc/rfc4517.txt.
*
* @param dateTimestamp Ldap timestamp.
* @return Given timestamp in the standard format.
* @throws UserStoreException If an error occurred while converting timestamp or if unsupported timestamp
* configured in the userstore.
*/
private String convertToStandardTimeFormat(String dateTimestamp) throws UserStoreException {

if (StringUtils.isBlank(dateTimestamp)) {
return dateTimestamp;
}
String userstoreTimestampFormat = realmConfig.getUserStoreProperty(dateAndTimePattern);
if (StringUtils.isNotBlank(userstoreTimestampFormat) &&
!StringUtils.equals(userstoreTimestampFormat, DEFAULT_LDAP_TIME_FORMATS_PATTERN)) {
try {
return OffsetDateTime.parse(dateTimestamp, DateTimeFormatter.ofPattern(userstoreTimestampFormat))
.toInstant()
.toString();
} catch (DateTimeParseException e) {
throw new UserStoreException("Invalid timestamp format for pattern: " + userstoreTimestampFormat, e);
}
}

String derivedTimeStampPattern = deriveTimestampFormat(dateTimestamp);
if (StringUtils.isNotBlank(derivedTimeStampPattern)) {
try {
return OffsetDateTime.parse(dateTimestamp, DateTimeFormatter.ofPattern(derivedTimeStampPattern))
.toInstant()
.toString();
} catch (DateTimeParseException e) {
throw new UserStoreException("Invalid timestamp format for pattern: " + derivedTimeStampPattern, e);
}
}
throw new UserStoreException("Unsupported LDAP timestamp format: " + dateTimestamp);
}

/**
* Build the group filter by transforming the filtering value to the appropriate format.
*
Expand Down Expand Up @@ -4474,47 +4441,9 @@ private String inferLDAPTimestampFormat(NamingEnumeration<SearchResult> answer,
Attribute attr = sr.getAttributes().get(timestampAttributeName);
if (attr != null) {
String sampleTimestamp = (String) attr.get();
return deriveTimestampFormat(sampleTimestamp);
return LDAPUtil.deriveTimestampFormat(sampleTimestamp);
}
}
return null;
}

/**
* Derives the timestamp format based on the provided timestamp string.
* The patterns checked here correspond to formats defined in DEFAULT_LDAP_TIME_FORMATS_PATTERN
* ("[uuuuMMddHHmmss[,SSS][.SSS]X][uuuuMMddHHmmss[,SS][.SS]X][uuuuMMddHHmm[,S][.S]X]").
*
* @param timestamp The timestamp string to analyze.
* @return The derived timestamp format, or null if no matching format is found.
*/
private static String deriveTimestampFormat(String timestamp) {

if (StringUtils.isBlank(timestamp)) {
return null;
}

// Case 1: 14 digits with no fractional seconds.
if (NO_FRACTION_TIMESTAMP_PATTERN.matcher(timestamp).matches()) {
return "uuuuMMddHHmmssX";
}
// Case 2: 14 digits with 3-digit fraction.
else if (THREE_DIGIT_FRACTION_TIMESTAMP_PATTERN.matcher(timestamp).matches()) {
return timestamp.contains(",") ? "uuuuMMddHHmmss,SSSX" : "uuuuMMddHHmmss.SSSX";
}
// Case 3: 14 digits with 2-digit fraction.
else if (TWO_DIGIT_FRACTION_TIMESTAMP_PATTERN.matcher(timestamp).matches()) {
return timestamp.contains(",") ? "uuuuMMddHHmmss,SSX" : "uuuuMMddHHmmss.SSX";
}
// Case 4: 14 digits with 1-digit fraction (seconds precision).
else if (ONE_DIGIT_FRACTION_WITH_SECONDS_TIMESTAMP_PATTERN.matcher(timestamp).matches()) {
return timestamp.contains(",") ? "uuuuMMddHHmmss,SX" : "uuuuMMddHHmmss.SX";
}
// Case 5: 12 digits with 1-digit fraction (minutes precision).
else if (ONE_DIGIT_FRACTION_WITH_MINUTES_TIMESTAMP_PATTERN.matcher(timestamp).matches()) {
return timestamp.contains(",") ? "uuuuMMddHHmm,SX" : "uuuuMMddHHmm.SX";
}

return null;
}
}
Loading
Loading