Skip to content

Commit

Permalink
Relocate the logic for updating uniqueness validation properties to t…
Browse files Browse the repository at this point in the history
…he service layer
  • Loading branch information
AfraHussaindeen committed Dec 3, 2024
1 parent 56b53bd commit e271a0d
Show file tree
Hide file tree
Showing 6 changed files with 301 additions and 446 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

Expand All @@ -67,6 +68,7 @@
import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_NON_EXISTING_EXTERNAL_CLAIM_URI;
import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_NON_EXISTING_LOCAL_CLAIM;
import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_NON_EXISTING_LOCAL_CLAIM_URI;
import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimMetadataUtils.getServerLevelClaimUniquenessScope;

/**
* Default implementation of {@link org.wso2.carbon.identity.claim.metadata.mgt.ClaimMetadataManagementService}
Expand Down Expand Up @@ -212,6 +214,8 @@ public void addLocalClaim(LocalClaim localClaim, String tenantDomain) throws Cla
String.format(ERROR_CODE_EXISTING_LOCAL_CLAIM_URI.getMessage(), localClaim.getClaimURI()));
}

validateAndSyncUniquenessClaimProperties(localClaim.getClaimProperties(), null);

ClaimMetadataEventPublisherProxy.getInstance().publishPreAddLocalClaim(tenantId, localClaim);

this.unifiedClaimMetadataManager.addLocalClaim(localClaim, tenantId);
Expand All @@ -236,11 +240,15 @@ public void updateLocalClaim(LocalClaim localClaim, String tenantDomain) throws
// TODO : validate tenant domain?
int tenantId = IdentityTenantUtil.getTenantId(tenantDomain);

if (!isExistingLocalClaim(localClaim.getClaimURI(), tenantId)) {
Optional<LocalClaim> existingLocalClaim = getLocalClaim(localClaim.getClaimURI(), tenantId);
if (!existingLocalClaim.isPresent()) {
throw new ClaimMetadataClientException(ERROR_CODE_NON_EXISTING_LOCAL_CLAIM.getCode(),
String.format(ERROR_CODE_NON_EXISTING_LOCAL_CLAIM.getMessage(), localClaim.getClaimURI()));
}

validateAndSyncUniquenessClaimProperties(localClaim.getClaimProperties(),
existingLocalClaim.get().getClaimProperties());

ClaimMetadataEventPublisherProxy.getInstance().publishPreUpdateLocalClaim(tenantId, localClaim);

this.unifiedClaimMetadataManager.updateLocalClaim(localClaim, tenantId);
Expand Down Expand Up @@ -595,6 +603,11 @@ private boolean isExistingLocalClaim(String localClaimURI, int tenantId) throws
claim -> claim.getClaimURI().equalsIgnoreCase(localClaimURI));
}

private Optional<LocalClaim> getLocalClaim(String localClaimURI, int tenantId) throws ClaimMetadataException {

return this.unifiedClaimMetadataManager.getLocalClaim(localClaimURI, tenantId);
}

@Override
public List<Claim> getMappedExternalClaimsForLocalClaim(String localClaimURI, String tenantDomain) throws
ClaimMetadataException {
Expand All @@ -603,4 +616,80 @@ public List<Claim> getMappedExternalClaimsForLocalClaim(String localClaimURI, St
return this.unifiedClaimMetadataManager.getMappedExternalClaims(localClaimURI, tenantId);
}

/**
* Updates and synchronizes the claim uniqueness properties in the properties map.
* Manages the relationship between the legacy 'isUnique' property and the newer 'UniquenessScope' property,
* ensuring consistency between both properties based on their values.
*
* @param claimProperties Map of claim properties to be updated.
* @param existingClaimProperties Map of existing claim properties (null for new claims).
*/
private void validateAndSyncUniquenessClaimProperties(Map<String, String> claimProperties,
Map<String, String> existingClaimProperties) {

// Case 1: If the 'isUnique' property is not provided,
// no property synchronization is needed.
if (!claimProperties.containsKey(ClaimConstants.IS_UNIQUE_CLAIM_PROPERTY)) {
return;
}

String newUniquenessScopeValue = claimProperties.get(ClaimConstants.CLAIM_UNIQUENESS_SCOPE_PROPERTY);
String newIsUniqueValue = claimProperties.get(ClaimConstants.IS_UNIQUE_CLAIM_PROPERTY);

// Case 2: If only the 'isUnique' property is provided,
// set the 'UniquenessScope' property based on the 'isUnique' value.
if (!claimProperties.containsKey(ClaimConstants.CLAIM_UNIQUENESS_SCOPE_PROPERTY)) {
updateScopeFromIsUnique(claimProperties, newIsUniqueValue);
return;
}

// Case 3: If both 'isUnique' and 'UniquenessScope' properties are provided.
if (existingClaimProperties == null) {
// If there are no existing claim properties (i.e., this is a new claim),
// prioritize 'UniquenessScope' & update the 'isUnique' property accordingly.
updateIsUniqueFromScope(claimProperties, newUniquenessScopeValue);
return;
}

String existingScopeValue = existingClaimProperties.get(ClaimConstants.CLAIM_UNIQUENESS_SCOPE_PROPERTY);
String existingIsUniqueValue = existingClaimProperties.get(ClaimConstants.IS_UNIQUE_CLAIM_PROPERTY);

boolean isScopeChanged = !StringUtils.equals(newUniquenessScopeValue, existingScopeValue);
boolean isUniqueChanged = !StringUtils.equalsIgnoreCase(newIsUniqueValue, existingIsUniqueValue);

if (isScopeChanged) {
// If 'UniquenessScope' has changed (regardless of 'isUnique' changes), prioritize 'UniquenessScope'.
updateIsUniqueFromScope(claimProperties, newUniquenessScopeValue);
} else if (isUniqueChanged) {
// If only 'isUnique' has changed, update 'UniquenessScope' based on the new 'isUnique' value.
updateScopeFromIsUnique(claimProperties, newIsUniqueValue);
}
}

/**
* Updates the uniqueness scope property based on the isUnique value.
*
* @param properties Map of claim properties to update.
* @param isUniqueValue String value of isUnique property ("true" or "false").
*/
private void updateScopeFromIsUnique(Map<String, String> properties, String isUniqueValue) {

boolean isUnique = Boolean.parseBoolean(isUniqueValue);
properties.put(ClaimConstants.CLAIM_UNIQUENESS_SCOPE_PROPERTY,
isUnique ? getServerLevelClaimUniquenessScope().toString() :
ClaimConstants.ClaimUniquenessScope.NONE.toString());
}

/**
* Updates the isUnique property based on the uniqueness scope value.
*
* @param properties Map of claim properties to update.
* @param scopeValue String value of the uniqueness scope.
*/
private void updateIsUniqueFromScope(Map<String, String> properties, String scopeValue) {

boolean isUnique = !ClaimConstants.ClaimUniquenessScope.NONE.toString().equals(scopeValue);
properties.put(ClaimConstants.IS_UNIQUE_CLAIM_PROPERTY, String.valueOf(isUnique));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -261,36 +261,4 @@ public int getIdOfClaim(Connection connection, String claimDialectURI, String cl
}
return claimId;
}

/**
* Retrieves claim properties for a given claim ID from the database.
*
* @param connection Database connection to use for the query.
* @param claimId ID of the claim whose properties are to be retrieved.
* @param tenantId ID of the tenant.
* @return Map containing property name-value pairs for the claim.
* @throws ClaimMetadataException If an error occurs while retrieving the claim properties.
*/
public Map<String, String> getClaimPropertiesById(Connection connection, int claimId, int tenantId)
throws ClaimMetadataException {

Map<String, String> claimProperties = new HashMap<>();

try (PreparedStatement prepStmt = connection.prepareStatement(SQLConstants.GET_CLAIM_PROPERTIES_BY_ID)) {
prepStmt.setInt(1, claimId);
prepStmt.setInt(2, tenantId);

try (ResultSet rs = prepStmt.executeQuery()) {
while (rs.next()) {
String propertyName = rs.getString(SQLConstants.PROPERTY_NAME_COLUMN);
String propertyValue = rs.getString(SQLConstants.PROPERTY_VALUE_COLUMN);
claimProperties.put(propertyName, propertyValue);
}
}
} catch (SQLException e) {
throw new ClaimMetadataException("Error while retrieving claim properties for claim ID: " + claimId, e);
}

return claimProperties;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@
import java.util.List;
import java.util.Map;

import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimMetadataUtils.getServerLevelClaimUniquenessScope;

/**
* Data access object for org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim.
*/
Expand Down Expand Up @@ -67,6 +65,7 @@ public List<LocalClaim> getLocalClaims(int tenantId) throws ClaimMetadataExcepti

List<AttributeMapping> attributeMappingsOfClaim = claimAttributeMappingsOfDialect.get(claimId);
Map<String, String> propertiesOfClaim = claimPropertiesOfDialect.get(claimId);

localClaims.add(new LocalClaim(claim.getClaimURI(), attributeMappingsOfClaim, propertiesOfClaim));
}
} finally {
Expand Down Expand Up @@ -179,9 +178,6 @@ public void addLocalClaim(LocalClaim localClaim, int tenantId) throws ClaimMetad
}

addClaimAttributeMappings(connection, localClaimId, localClaim.getMappedAttributes(), tenantId);
if (shouldUpdateUniquenessValidationProperty(localClaim.getClaimProperties())) {
updateUniquenessValidationProperty(localClaim.getClaimProperties(), null, -1, -1);
}
addClaimProperties(connection, localClaimId, localClaim.getClaimProperties(), tenantId);

// End transaction
Expand Down Expand Up @@ -210,9 +206,6 @@ public void updateLocalClaim(LocalClaim localClaim, int tenantId) throws ClaimMe
deleteClaimAttributeMappings(connection, localClaimId, tenantId);
addClaimAttributeMappings(connection, localClaimId, localClaim.getMappedAttributes(), tenantId);

if (shouldUpdateUniquenessValidationProperty(localClaim.getClaimProperties())) {
updateUniquenessValidationProperty(localClaim.getClaimProperties(), connection, localClaimId, tenantId);
}
deleteClaimProperties(connection, localClaimId, tenantId);
addClaimProperties(connection, localClaimId, localClaim.getClaimProperties(), tenantId);

Expand Down Expand Up @@ -422,95 +415,4 @@ public List<Claim> fetchMappedExternalClaims(String localClaimURI, int tenantId)
throw new ClaimMetadataException("Error while obtaining mapped external claims for local claim.", e);
}
}

/**
* Checks if the uniqueness validation property/properties needs to be updated.
* This occurs when the properties map contains the legacy isUnique property
* that needs to be mapped to the new UniquenessScope property.
*
* @param properties Map of claim properties to check.
* @return true if properties contain isUnique property.
*/
private boolean shouldUpdateUniquenessValidationProperty(Map<String, String> properties) {

return properties != null &&
properties.containsKey(ClaimConstants.IS_UNIQUE_CLAIM_PROPERTY);
}

/**
* Updates the uniqueness validation property/properties in the properties map.
* Handles the synchronization between legacy isUnique property
* and the new UniquenessScope property if isUnique property is defined.
*
* @param properties Map of claim properties to update.
* @param connection Database connection to use for retrieving existing properties. Can be null for new claims.
* @param localClaimId ID of the local claim. Only required when connection is provided.
* @param tenantId ID of the tenant. Only required when connection is provided.
* @throws ClaimMetadataException If an error occurs while updating the properties.
*/
private void updateUniquenessValidationProperty(Map<String, String> properties, Connection connection,
int localClaimId, int tenantId) throws ClaimMetadataException {

String newScopeValue = properties.get(ClaimConstants.CLAIM_UNIQUENESS_SCOPE_PROPERTY);
String newIsUniqueValue = properties.get(ClaimConstants.IS_UNIQUE_CLAIM_PROPERTY);

boolean hasUniquenessScope = newScopeValue != null;

// Case 1 : Only isUnique exists.
if (!hasUniquenessScope) {
updateScopeFromIsUnique(properties, newIsUniqueValue);
return;
}

// Case 2 : Both isUnique & UniquenessScope exists.
if (connection == null) {
// If no database connection is available, use the UniquenessScope property value for uniqueness validation
// and update the isUnique property accordingly.
updateIsUniqueFromScope(properties, newScopeValue);
return;
}

// Retrieve existing property values from the DB to determine what has changed.
Map<String, String> existingProperties = getClaimPropertiesById(connection, localClaimId, tenantId);
String existingScopeValue = existingProperties.get(ClaimConstants.CLAIM_UNIQUENESS_SCOPE_PROPERTY);
String existingIsUniqueValue = existingProperties.get(ClaimConstants.IS_UNIQUE_CLAIM_PROPERTY);

boolean isScopeChanged = !newScopeValue.equals(existingScopeValue);
boolean isUniqueChanged = !newIsUniqueValue.equals(existingIsUniqueValue);

// If UniquenessScope changed (regardless of isUnique changes), prioritize scope.
if (isScopeChanged) {
updateIsUniqueFromScope(properties, newScopeValue);
}
// If only isUnique changed.
else if (isUniqueChanged) {
updateScopeFromIsUnique(properties, newIsUniqueValue);
}
}

/**
* Updates the uniqueness scope property based on the isUnique value.
*
* @param properties Map of claim properties to update.
* @param isUniqueValue String value of isUnique property ("true" or "false").
*/
private void updateScopeFromIsUnique(Map<String, String> properties, String isUniqueValue) {

boolean isUnique = Boolean.parseBoolean(isUniqueValue);
properties.put(ClaimConstants.CLAIM_UNIQUENESS_SCOPE_PROPERTY,
isUnique ? getServerLevelClaimUniquenessScope().toString() :
ClaimConstants.ClaimUniquenessScope.NONE.toString());
}

/**
* Updates the isUnique property based on the uniqueness scope value.
*
* @param properties Map of claim properties to update.
* @param scopeValue String value of the uniqueness scope.
*/
private void updateIsUniqueFromScope(Map<String, String> properties, String scopeValue) {

boolean isUnique = !ClaimConstants.ClaimUniquenessScope.NONE.toString().equals(scopeValue);
properties.put(ClaimConstants.IS_UNIQUE_CLAIM_PROPERTY, String.valueOf(isUnique));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ private SQLConstants() {
"PROPERTY_VALUE, TENANT_ID) VALUES (?, ?, ?, ?)";
public static final String DELETE_CLAIM_PROPERTY = "DELETE FROM IDN_CLAIM_PROPERTY WHERE LOCAL_CLAIM_ID=? AND " +
"TENANT_ID=?";
public static final String GET_CLAIM_PROPERTIES_BY_ID = "SELECT PROPERTY_NAME, PROPERTY_VALUE FROM IDN_CLAIM_PROPERTY WHERE LOCAL_CLAIM_ID=? AND TENANT_ID=?";

public static final String GET_CLAIMS = "SELECT CLAIMS.ID, PROPERTY.PROPERTY_NAME, PROPERTY.PROPERTY_VALUE, "
+ "CLAIMS.CLAIM_URI, RESOLVED.CLAIM_URI MAPPED_URI FROM IDN_CLAIM CLAIMS "
Expand Down
Loading

0 comments on commit e271a0d

Please sign in to comment.