diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/ClaimMetadataManagementService.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/ClaimMetadataManagementService.java index 9340fc858e9b..774e75e8fc37 100644 --- a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/ClaimMetadataManagementService.java +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/ClaimMetadataManagementService.java @@ -16,23 +16,14 @@ package org.wso2.carbon.identity.claim.metadata.mgt; -import org.apache.commons.lang.StringUtils; -import org.wso2.carbon.identity.claim.metadata.mgt.dao.CacheBackedLocalClaimDAO; -import org.wso2.carbon.identity.claim.metadata.mgt.dao.LocalClaimDAO; -import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataClientException; import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; import org.wso2.carbon.identity.claim.metadata.mgt.model.Claim; import org.wso2.carbon.identity.claim.metadata.mgt.model.ClaimDialect; import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; import org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim; -import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import java.util.List; -import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_EMPTY_LOCAL_CLAIM_URI; -import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_EMPTY_MAPPED_ATTRIBUTES_IN_LOCAL_CLAIM; -import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_NON_EXISTING_LOCAL_CLAIM_URI; - /** * This interface used to expose claim metadata management functionalities as an OSGi Service. */ diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/ClaimMetadataManagementServiceImpl.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/ClaimMetadataManagementServiceImpl.java index 88e2bacebdf9..6ebb035f8b95 100644 --- a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/ClaimMetadataManagementServiceImpl.java +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/ClaimMetadataManagementServiceImpl.java @@ -22,15 +22,9 @@ import org.apache.commons.lang.math.NumberUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.wso2.carbon.identity.claim.metadata.mgt.dao.CacheBackedClaimDialectDAO; -import org.wso2.carbon.identity.claim.metadata.mgt.dao.CacheBackedExternalClaimDAO; -import org.wso2.carbon.identity.claim.metadata.mgt.dao.CacheBackedLocalClaimDAO; -import org.wso2.carbon.identity.claim.metadata.mgt.dao.ClaimDialectDAO; -import org.wso2.carbon.identity.claim.metadata.mgt.dao.ExternalClaimDAO; -import org.wso2.carbon.identity.claim.metadata.mgt.dao.LocalClaimDAO; import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataClientException; import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; -import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataServerException; +import org.wso2.carbon.identity.claim.metadata.mgt.internal.ReadWriteClaimMetadataManager; import org.wso2.carbon.identity.claim.metadata.mgt.internal.IdentityClaimManagementServiceComponent; import org.wso2.carbon.identity.claim.metadata.mgt.internal.IdentityClaimManagementServiceDataHolder; import org.wso2.carbon.identity.claim.metadata.mgt.listener.ClaimMetadataMgtListener; @@ -41,7 +35,6 @@ import org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.core.util.IdentityUtil; -import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.core.UserCoreConstants; import org.wso2.carbon.user.core.claim.inmemory.ClaimConfig; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; @@ -64,11 +57,15 @@ import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_EXISTING_EXTERNAL_CLAIM_URI; import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_EXISTING_LOCAL_CLAIM_MAPPING; import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_EXISTING_LOCAL_CLAIM_URI; +import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_INVALID_EXTERNAL_CLAIM_DIALECT_URI; import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_INVALID_EXTERNAL_CLAIM_URI; import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_INVALID_EXTERNAL_CLAIM_DIALECT; import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_INVALID_TENANT_DOMAIN; import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_LOCAL_CLAIM_HAS_MAPPED_EXTERNAL_CLAIM; import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_MAPPED_TO_EMPTY_LOCAL_CLAIM_URI; +import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_MAPPED_TO_INVALID_LOCAL_CLAIM_URI; +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; /** @@ -79,9 +76,7 @@ public class ClaimMetadataManagementServiceImpl implements ClaimMetadataManageme private static final Log log = LogFactory.getLog(ClaimMetadataManagementServiceImpl.class); - private ClaimDialectDAO claimDialectDAO = new CacheBackedClaimDialectDAO(); - private CacheBackedLocalClaimDAO localClaimDAO = new CacheBackedLocalClaimDAO(new LocalClaimDAO()); - private CacheBackedExternalClaimDAO externalClaimDAO = new CacheBackedExternalClaimDAO(new ExternalClaimDAO()); + private final ReadWriteClaimMetadataManager unifiedClaimMetadataManager = new UnifiedClaimMetadataManager(); private static final int MAX_CLAIM_PROPERTY_LENGTH = 255; private static final int MAX_CLAIM_PROPERTY_LENGTH_LIMIT = 1024; private static final int MIN_CLAIM_PROPERTY_LENGTH_LIMIT = 0; @@ -94,7 +89,7 @@ public List getClaimDialects(String tenantDomain) throws ClaimMeta // Add listener - List claimDialects = this.claimDialectDAO.getClaimDialects(tenantId); + List claimDialects = this.unifiedClaimMetadataManager.getClaimDialects(tenantId); // Add listener @@ -116,7 +111,7 @@ public void addClaimDialect(ClaimDialect claimDialect, String tenantDomain) thro String.format(ERROR_CODE_INVALID_TENANT_DOMAIN.getMessage(), tenantDomain)); } - List claimDialects = this.claimDialectDAO.getClaimDialects(tenantId); + List claimDialects = this.unifiedClaimMetadataManager.getClaimDialects(tenantId); Set claimDialectUris = claimDialects.stream().map(ClaimDialect::getClaimDialectURI). collect(Collectors.toSet()); @@ -127,7 +122,7 @@ public void addClaimDialect(ClaimDialect claimDialect, String tenantDomain) thro ClaimMetadataEventPublisherProxy.getInstance().publishPreAddClaimDialect(tenantId, claimDialect); - this.claimDialectDAO.addClaimDialect(claimDialect, tenantId); + this.unifiedClaimMetadataManager.addClaimDialect(claimDialect, tenantId); ClaimMetadataEventPublisherProxy.getInstance().publishPostAddClaimDialect(tenantId, claimDialect); @@ -147,10 +142,15 @@ public void renameClaimDialect(ClaimDialect oldClaimDialect, ClaimDialect newCla // TODO : validate tenant domain? int tenantId = IdentityTenantUtil.getTenantId(tenantDomain); + boolean isRenamedDialectAlreadyTaken = isExistingClaimDialect(newClaimDialect.getClaimDialectURI(), tenantId); + if (isRenamedDialectAlreadyTaken) { + throw new ClaimMetadataClientException(ERROR_CODE_EXISTING_CLAIM_DIALECT.getCode(), + String.format(ERROR_CODE_EXISTING_CLAIM_DIALECT.getMessage(), newClaimDialect.getClaimDialectURI())); + } + ClaimMetadataEventPublisherProxy.getInstance().publishPreUpdateClaimDialect(tenantId, oldClaimDialect, newClaimDialect); - this.claimDialectDAO.renameClaimDialect(oldClaimDialect, newClaimDialect, tenantId); - externalClaimDAO.removeExternalClaimCache(oldClaimDialect.getClaimDialectURI(), tenantId); + this.unifiedClaimMetadataManager.renameClaimDialect(oldClaimDialect, newClaimDialect, tenantId); ClaimMetadataEventPublisherProxy.getInstance().publishPostUpdateClaimDialect(tenantId, oldClaimDialect, newClaimDialect); @@ -171,10 +171,7 @@ public void removeClaimDialect(ClaimDialect claimDialect, String tenantDomain) t ClaimMetadataEventPublisherProxy.getInstance().publishPreDeleteClaimDialect(tenantId, claimDialect); - this.claimDialectDAO.removeClaimDialect(claimDialect, tenantId); - // When deleting a claim dialect the relevant external claim deletion is handled by the DB through - // ON DELETE CASCADE. Here we are removing the relevant cache entry. - externalClaimDAO.removeExternalClaimCache(claimDialect.getClaimDialectURI(), tenantId); + this.unifiedClaimMetadataManager.removeClaimDialect(claimDialect, tenantId); ClaimMetadataEventPublisherProxy.getInstance().publishPostDeleteClaimDialect(tenantId, claimDialect); } @@ -186,7 +183,7 @@ public List getLocalClaims(String tenantDomain) throws ClaimMetadata // Add listener - List localClaims = this.localClaimDAO.getLocalClaims(tenantId); + List localClaims = this.unifiedClaimMetadataManager.getLocalClaims(tenantId); // Add listener @@ -210,14 +207,14 @@ public void addLocalClaim(LocalClaim localClaim, String tenantDomain) throws Cla // TODO : validate tenant domain? int tenantId = IdentityTenantUtil.getTenantId(tenantDomain); - if (isExistingLocalClaimURI(localClaim.getClaimURI(), tenantId)) { + if (isExistingLocalClaim(localClaim.getClaimURI(), tenantId)) { throw new ClaimMetadataClientException(ERROR_CODE_EXISTING_LOCAL_CLAIM_URI.getCode(), String.format(ERROR_CODE_EXISTING_LOCAL_CLAIM_URI.getMessage(), localClaim.getClaimURI())); } ClaimMetadataEventPublisherProxy.getInstance().publishPreAddLocalClaim(tenantId, localClaim); - this.localClaimDAO.addLocalClaim(localClaim, tenantId); + this.unifiedClaimMetadataManager.addLocalClaim(localClaim, tenantId); ClaimMetadataEventPublisherProxy.getInstance().publishPostAddLocalClaim(tenantId, localClaim); } @@ -239,9 +236,14 @@ public void updateLocalClaim(LocalClaim localClaim, String tenantDomain) throws // TODO : validate tenant domain? int tenantId = IdentityTenantUtil.getTenantId(tenantDomain); + if (!isExistingLocalClaim(localClaim.getClaimURI(), tenantId)) { + throw new ClaimMetadataClientException(ERROR_CODE_NON_EXISTING_LOCAL_CLAIM.getCode(), + String.format(ERROR_CODE_NON_EXISTING_LOCAL_CLAIM.getMessage(), localClaim.getClaimURI())); + } + ClaimMetadataEventPublisherProxy.getInstance().publishPreUpdateLocalClaim(tenantId, localClaim); - this.localClaimDAO.updateLocalClaim(localClaim, tenantId); + this.unifiedClaimMetadataManager.updateLocalClaim(localClaim, tenantId); ClaimMetadataEventPublisherProxy.getInstance().publishPostUpdateLocalClaim(tenantId, localClaim); } @@ -257,7 +259,7 @@ public void updateLocalClaimMappings(List localClaimList, String ten claimMetadataEventPublisherProxy.publishPreUpdateLocalClaim(tenantId, localClaim); } - this.localClaimDAO.updateLocalClaimMappings(localClaimList, tenantId, userStoreDomain); + this.unifiedClaimMetadataManager.updateLocalClaimMappings(localClaimList, tenantId, userStoreDomain); for (LocalClaim localClaim : localClaimList) { claimMetadataEventPublisherProxy.publishPostUpdateLocalClaim(tenantId, localClaim); @@ -276,8 +278,7 @@ public void removeLocalClaim(String localClaimURI, String tenantDomain) throws C // TODO : validate tenant domain? int tenantId = IdentityTenantUtil.getTenantId(tenantDomain); - boolean isMappedLocalClaim = this.externalClaimDAO.isMappedLocalClaim(localClaimURI, tenantId); - + boolean isMappedLocalClaim = this.unifiedClaimMetadataManager.isMappedLocalClaim(localClaimURI, tenantId); if (isMappedLocalClaim) { throw new ClaimMetadataClientException(ERROR_CODE_LOCAL_CLAIM_HAS_MAPPED_EXTERNAL_CLAIM.getCode(), String.format(ERROR_CODE_LOCAL_CLAIM_HAS_MAPPED_EXTERNAL_CLAIM.getMessage(), localClaimURI)); @@ -292,7 +293,7 @@ public void removeLocalClaim(String localClaimURI, String tenantDomain) throws C } } - this.localClaimDAO.removeLocalClaim(localClaimURI, tenantId); + this.unifiedClaimMetadataManager.removeLocalClaim(localClaimURI, tenantId); ClaimMetadataEventPublisherProxy.getInstance().publishPostDeleteLocalClaim(tenantId, localClaimURI); for (ClaimMetadataMgtListener listener : listeners) { @@ -318,7 +319,8 @@ public List getExternalClaims(String externalClaimDialectURI, Str // Add listener - List externalClaims = this.externalClaimDAO.getExternalClaims(externalClaimDialectURI, tenantId); + List externalClaims = this.unifiedClaimMetadataManager.getExternalClaims( + externalClaimDialectURI, tenantId); // Add listener @@ -357,14 +359,26 @@ public void addExternalClaim(ExternalClaim externalClaim, String tenantDomain) t // TODO : validate tenant domain? int tenantId = IdentityTenantUtil.getTenantId(tenantDomain); - if (isExistingExternalClaimURI(externalClaim.getClaimDialectURI(), externalClaim.getClaimURI(), tenantId)) { + if (!isExistingClaimDialect(externalClaim.getClaimDialectURI(), tenantId)) { + throw new ClaimMetadataClientException(ERROR_CODE_INVALID_EXTERNAL_CLAIM_DIALECT_URI.getCode(), + String.format(ERROR_CODE_INVALID_EXTERNAL_CLAIM_DIALECT_URI.getMessage(), + externalClaim.getClaimDialectURI())); + } + + if (isExistingExternalClaim(externalClaim.getClaimDialectURI(), externalClaim.getClaimURI(), tenantId)) { throw new ClaimMetadataClientException(ERROR_CODE_EXISTING_EXTERNAL_CLAIM_URI.getCode(), String.format(ERROR_CODE_EXISTING_EXTERNAL_CLAIM_URI.getMessage(), externalClaim.getClaimURI(), externalClaim.getClaimDialectURI())); } + if (!isExistingLocalClaim(externalClaim.getMappedLocalClaim(), tenantId)) { + throw new ClaimMetadataClientException(ERROR_CODE_MAPPED_TO_INVALID_LOCAL_CLAIM_URI.getCode(), + String.format(ERROR_CODE_MAPPED_TO_INVALID_LOCAL_CLAIM_URI.getMessage(), + externalClaim.getMappedLocalClaim(), ClaimConstants.LOCAL_CLAIM_DIALECT_URI)); + } + boolean isLocalClaimAlreadyMapped = - this.externalClaimDAO.isLocalClaimMappedWithinDialect(externalClaim.getMappedLocalClaim(), + this.unifiedClaimMetadataManager.isLocalClaimMappedWithinDialect(externalClaim.getMappedLocalClaim(), externalClaim.getClaimDialectURI(), tenantId); if (isLocalClaimAlreadyMapped) { @@ -375,7 +389,7 @@ public void addExternalClaim(ExternalClaim externalClaim, String tenantDomain) t // Add listener - this.externalClaimDAO.addExternalClaim(externalClaim, tenantId); + this.unifiedClaimMetadataManager.addExternalClaim(externalClaim, tenantId); ClaimMetadataEventPublisherProxy.getInstance().publishPostAddExternalClaim(tenantId, externalClaim); } @@ -405,9 +419,37 @@ public void updateExternalClaim(ExternalClaim externalClaim, String tenantDomain // TODO : validate tenant domain? int tenantId = IdentityTenantUtil.getTenantId(tenantDomain); + if (!isExistingClaimDialect(externalClaim.getClaimDialectURI(), tenantId)) { + throw new ClaimMetadataClientException(ERROR_CODE_INVALID_EXTERNAL_CLAIM_DIALECT_URI.getCode(), + String.format(ERROR_CODE_INVALID_EXTERNAL_CLAIM_DIALECT_URI.getMessage(), + externalClaim.getClaimDialectURI())); + } + + if (!isExistingExternalClaim(externalClaim.getClaimDialectURI(), externalClaim.getClaimURI(), tenantId)) { + throw new ClaimMetadataClientException(ERROR_CODE_NON_EXISTING_EXTERNAL_CLAIM_URI.getCode(), + String.format(ERROR_CODE_NON_EXISTING_EXTERNAL_CLAIM_URI.getMessage(), externalClaim.getClaimURI(), + externalClaim.getClaimDialectURI())); + } + + if (!isExistingLocalClaim(externalClaim.getMappedLocalClaim(), tenantId)) { + throw new ClaimMetadataClientException(ERROR_CODE_NON_EXISTING_LOCAL_CLAIM.getCode(), + String.format(ERROR_CODE_NON_EXISTING_LOCAL_CLAIM.getMessage(), externalClaim.getMappedLocalClaim())); + } + + boolean isLocalClaimAlreadyMapped = this.unifiedClaimMetadataManager.getMappedExternalClaims( + externalClaim.getMappedLocalClaim(), tenantId).stream() + .filter(claim -> claim.getClaimDialectURI().equals(externalClaim.getClaimDialectURI())) + .anyMatch(claim -> !claim.getClaimURI().equals(externalClaim.getClaimURI())); + + if (isLocalClaimAlreadyMapped) { + throw new ClaimMetadataClientException((ERROR_CODE_EXISTING_LOCAL_CLAIM_MAPPING.getCode()), + String.format(ERROR_CODE_EXISTING_LOCAL_CLAIM_MAPPING.getMessage(), + externalClaim.getMappedLocalClaim(), externalClaim.getClaimDialectURI())); + } + ClaimMetadataEventPublisherProxy.getInstance().publishPreUpdateExternalClaim(tenantId, externalClaim); - this.externalClaimDAO.updateExternalClaim(externalClaim, tenantId); + this.unifiedClaimMetadataManager.updateExternalClaim(externalClaim, tenantId); ClaimMetadataEventPublisherProxy.getInstance().publishPostUpdateExternalClaim(tenantId, externalClaim); } @@ -437,7 +479,7 @@ public void removeExternalClaim(String externalClaimDialectURI, String externalC ClaimMetadataEventPublisherProxy.getInstance().publishPreDeleteExternalClaim(tenantId, externalClaimDialectURI, externalClaimURI); - this.externalClaimDAO.removeExternalClaim(externalClaimDialectURI, externalClaimURI, tenantId); + this.unifiedClaimMetadataManager.removeExternalClaim(externalClaimDialectURI, externalClaimURI, tenantId); ClaimMetadataEventPublisherProxy.getInstance().publishPostDeleteExternalClaim(tenantId, externalClaimDialectURI, externalClaimURI); @@ -450,16 +492,7 @@ public void removeClaimMappingAttributes(int tenantId, String userstoreDomain) t throw new ClaimMetadataClientException(ERROR_CODE_EMPTY_TENANT_DOMAIN.getCode(), ERROR_CODE_EMPTY_TENANT_DOMAIN.getMessage()); } - try { - this.localClaimDAO.removeClaimMappingAttributes(tenantId, userstoreDomain); - } catch (UserStoreException e) { - String errorMessage = String.format( - ClaimConstants.ErrorMessage.ERROR_CODE_SERVER_ERROR_DELETING_CLAIM_MAPPINGS.getMessage(), - tenantId, userstoreDomain); - throw new ClaimMetadataServerException( - ClaimConstants.ErrorMessage.ERROR_CODE_SERVER_ERROR_DELETING_CLAIM_MAPPINGS.getCode(), - errorMessage, e); - } + this.unifiedClaimMetadataManager.removeClaimMappingAttributes(tenantId, userstoreDomain); } /** @@ -471,8 +504,7 @@ public void removeClaimMappingAttributes(int tenantId, String userstoreDomain) t @Override public void removeAllClaims(int tenantId) throws ClaimMetadataException { - // The relevant external claim deletions are handled by the DB through ON DELETE CASCADE. - this.claimDialectDAO.removeAllClaimDialects(tenantId); + this.unifiedClaimMetadataManager.removeAllClaimDialects(tenantId); } @Override @@ -491,7 +523,7 @@ public String getMaskingRegexForLocalClaim(String localClaimURI, String tenantDo } @Override - public void validateClaimAttributeMapping(List localClaimList, String tenantDomain) + public void validateClaimAttributeMapping(List localClaimList, String tenantDomain) throws ClaimMetadataException { for (LocalClaim localClaim : localClaimList) { @@ -502,7 +534,7 @@ public void validateClaimAttributeMapping(List localClaimList, Stri String.format(ERROR_CODE_EMPTY_MAPPED_ATTRIBUTES_IN_LOCAL_CLAIM.getMessage(), localClaim .getClaimDialectURI(), localClaim.getClaimURI())); } - if (!isExistingLocalClaimURI(localClaim.getClaimURI(), IdentityTenantUtil.getTenantId(tenantDomain))) { + if (!isExistingLocalClaim(localClaim.getClaimURI(), IdentityTenantUtil.getTenantId(tenantDomain))) { throw new ClaimMetadataClientException(ERROR_CODE_NON_EXISTING_LOCAL_CLAIM_URI.getCode(), String.format(ERROR_CODE_NON_EXISTING_LOCAL_CLAIM_URI.getMessage(), localClaim.getClaimURI())); } @@ -544,17 +576,23 @@ private void checkMinMaxLimit(String property, String value) throws ClaimMetadat } } - private boolean isExistingExternalClaimURI(String externalClaimDialectURI, String externalClaimURI, int tenantId) + private boolean isExistingClaimDialect(String claimDialectURI, int tenantId) throws ClaimMetadataException { + + return this.unifiedClaimMetadataManager.getClaimDialects(tenantId).stream().anyMatch( + claimDialect -> claimDialect.getClaimDialectURI().equalsIgnoreCase(claimDialectURI)); + } + + private boolean isExistingExternalClaim(String externalClaimDialectURI, String externalClaimURI, int tenantId) throws ClaimMetadataException { - return this.externalClaimDAO.getExternalClaims(externalClaimDialectURI, tenantId).stream().filter( - claim -> claim.getClaimURI().equalsIgnoreCase(externalClaimURI)).findFirst().isPresent(); + return this.unifiedClaimMetadataManager.getExternalClaims(externalClaimDialectURI, tenantId).stream().anyMatch( + claim -> claim.getClaimURI().equalsIgnoreCase(externalClaimURI)); } - private boolean isExistingLocalClaimURI(String localClaimURI, int tenantId) throws ClaimMetadataException { + private boolean isExistingLocalClaim(String localClaimURI, int tenantId) throws ClaimMetadataException { - return this.localClaimDAO.getLocalClaims(tenantId).stream().filter( - claim -> claim.getClaimURI().equalsIgnoreCase(localClaimURI)).findFirst().isPresent(); + return this.unifiedClaimMetadataManager.getLocalClaims(tenantId).stream().anyMatch( + claim -> claim.getClaimURI().equalsIgnoreCase(localClaimURI)); } @Override @@ -562,7 +600,7 @@ public List getMappedExternalClaimsForLocalClaim(String localClaimURI, St ClaimMetadataException { int tenantId = IdentityTenantUtil.getTenantId(tenantDomain); - return this.localClaimDAO.fetchMappedExternalClaims(localClaimURI, tenantId); + return this.unifiedClaimMetadataManager.getMappedExternalClaims(localClaimURI, tenantId); } } diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/DBBasedClaimMetadataManager.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/DBBasedClaimMetadataManager.java new file mode 100644 index 000000000000..0a4acc134d30 --- /dev/null +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/DBBasedClaimMetadataManager.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.claim.metadata.mgt; + +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.claim.metadata.mgt.dao.CacheBackedClaimDialectDAO; +import org.wso2.carbon.identity.claim.metadata.mgt.dao.CacheBackedExternalClaimDAO; +import org.wso2.carbon.identity.claim.metadata.mgt.dao.CacheBackedLocalClaimDAO; +import org.wso2.carbon.identity.claim.metadata.mgt.dao.ClaimDialectDAO; +import org.wso2.carbon.identity.claim.metadata.mgt.dao.ExternalClaimDAO; +import org.wso2.carbon.identity.claim.metadata.mgt.dao.LocalClaimDAO; +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataServerException; +import org.wso2.carbon.identity.claim.metadata.mgt.internal.ReadOnlyClaimMetadataManager; +import org.wso2.carbon.identity.claim.metadata.mgt.internal.ReadWriteClaimMetadataManager; +import org.wso2.carbon.identity.claim.metadata.mgt.model.Claim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ClaimDialect; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants; +import org.wso2.carbon.user.api.UserStoreException; + +import java.util.List; +import java.util.Optional; + +/** + * Database based claim metadata manager. + */ +public class DBBasedClaimMetadataManager implements ReadWriteClaimMetadataManager { + + private final ClaimDialectDAO claimDialectDAO = new CacheBackedClaimDialectDAO(); + private final CacheBackedLocalClaimDAO localClaimDAO = new CacheBackedLocalClaimDAO(new LocalClaimDAO()); + private final CacheBackedExternalClaimDAO externalClaimDAO = new CacheBackedExternalClaimDAO(new ExternalClaimDAO()); + + @Override + public List getClaimDialects(int tenantId) throws ClaimMetadataException { + + return this.claimDialectDAO.getClaimDialects(tenantId); + } + + @Override + public Optional getClaimDialect(String claimDialectURI, int tenantId) throws ClaimMetadataException { + + if (StringUtils.isBlank(claimDialectURI)) { + throw new ClaimMetadataException("Invalid claim dialect URI: " + claimDialectURI); + } + + return this.claimDialectDAO.getClaimDialects(tenantId).stream() + .filter(claimDialect -> claimDialectURI.equals(claimDialect.getClaimDialectURI())) + .findFirst(); + } + + @Override + public void addClaimDialect(ClaimDialect claimDialect, int tenantId) throws ClaimMetadataException { + + this.claimDialectDAO.addClaimDialect(claimDialect, tenantId); + } + + @Override + public void removeClaimDialect(ClaimDialect claimDialect, int tenantId) throws ClaimMetadataException { + + this.claimDialectDAO.removeClaimDialect(claimDialect, tenantId); + // When deleting a claim dialect the relevant external claim deletion is handled by the DB through + // ON DELETE CASCADE. Here we are removing the relevant cache entry. + externalClaimDAO.removeExternalClaimCache(claimDialect.getClaimDialectURI(), tenantId); + } + + @Override + public List getLocalClaims(int tenantId) throws ClaimMetadataException { + + return this.localClaimDAO.getLocalClaims(tenantId); + } + + @Override + public Optional getLocalClaim(String localClaimURI , int tenantId) throws ClaimMetadataException { + + if (StringUtils.isBlank(localClaimURI)) { + throw new ClaimMetadataException("Invalid local claim URI: " + localClaimURI); + } + + List localClaims = this.localClaimDAO.getLocalClaims(tenantId); + return localClaims.stream() + .filter(localClaim -> localClaimURI.equals(localClaim.getClaimURI())) + .findFirst(); + } + + @Override + public List getExternalClaims(String externalClaimDialectURI, int tenantId) + throws ClaimMetadataException { + + return this.externalClaimDAO.getExternalClaims(externalClaimDialectURI, tenantId); + } + + @Override + public Optional getExternalClaim(String externalClaimDialectURI, String claimURI, int tenantId) + throws ClaimMetadataException { + + if (StringUtils.isBlank(externalClaimDialectURI) || StringUtils.isBlank(claimURI)) { + throw new ClaimMetadataException("Invalid external claim dialect URI or claim URI"); + } + + return this.externalClaimDAO.getExternalClaims(externalClaimDialectURI, tenantId).stream() + .filter(externalClaim -> claimURI.equals(externalClaim.getClaimURI())) + .findFirst(); + } + + @Override + public void addLocalClaim(LocalClaim localClaim, int tenantId) throws ClaimMetadataException { + + this.localClaimDAO.addLocalClaim(localClaim, tenantId); + } + + @Override + public void updateLocalClaim(LocalClaim localClaim, int tenantId) throws ClaimMetadataException { + + this.localClaimDAO.updateLocalClaim(localClaim, tenantId); + } + + @Override + public void updateLocalClaimMappings(List localClaims, int tenantId, String userStoreDomain) + throws ClaimMetadataException { + + this.localClaimDAO.updateLocalClaimMappings(localClaims, tenantId, userStoreDomain); + } + + @Override + public void removeLocalClaim(String localClaimURI, int tenantId) throws ClaimMetadataException { + + this.localClaimDAO.removeLocalClaim(localClaimURI, tenantId); + } + + @Override + public void removeClaimMappingAttributes(int tenantId, String userstoreDomain) throws ClaimMetadataException { + + try { + this.localClaimDAO.removeClaimMappingAttributes(tenantId, userstoreDomain); + } catch (UserStoreException e) { + String errorMessage = String.format( + ClaimConstants.ErrorMessage.ERROR_CODE_SERVER_ERROR_DELETING_CLAIM_MAPPINGS.getMessage(), + tenantId, userstoreDomain); + throw new ClaimMetadataServerException( + ClaimConstants.ErrorMessage.ERROR_CODE_SERVER_ERROR_DELETING_CLAIM_MAPPINGS.getCode(), + errorMessage, e); + } + } + + @Override + public void addExternalClaim(ExternalClaim externalClaim, int tenantId) throws ClaimMetadataException { + + this.externalClaimDAO.addExternalClaim(externalClaim, tenantId); + } + + @Override + public void updateExternalClaim(ExternalClaim externalClaim, int tenantId) throws ClaimMetadataException { + + this.externalClaimDAO.updateExternalClaim(externalClaim, tenantId); + } + + @Override + public void removeExternalClaim(String externalClaimDialectURI, String externalClaimURI, int tenantId) + throws ClaimMetadataException { + + this.externalClaimDAO.removeExternalClaim(externalClaimDialectURI, externalClaimURI, tenantId); + } + + @Override + public List getMappedExternalClaims(String localClaimURI, int tenantId) throws ClaimMetadataException { + + return this.localClaimDAO.fetchMappedExternalClaims(localClaimURI, tenantId); + } + + @Override + public void renameClaimDialect(ClaimDialect oldClaimDialect, ClaimDialect newClaimDialect, int tenantId) + throws ClaimMetadataException { + + this.claimDialectDAO.renameClaimDialect(oldClaimDialect, newClaimDialect, tenantId); + externalClaimDAO.removeExternalClaimCache(oldClaimDialect.getClaimDialectURI(), tenantId); + } + + @Override + public void removeAllClaimDialects(int tenantId) throws ClaimMetadataException { + + // The relevant external claim deletions are handled by the DB through ON DELETE CASCADE. + this.claimDialectDAO.removeAllClaimDialects(tenantId); + } + + @Override + public boolean isMappedLocalClaim(String localClaimURI, int tenantId) throws ClaimMetadataException { + + return this.externalClaimDAO.isMappedLocalClaim(localClaimURI, tenantId); + } + + @Override + public boolean isLocalClaimMappedWithinDialect(String mappedLocalClaim, String externalClaimDialectURI, + int tenantId) throws ClaimMetadataException { + + return this.externalClaimDAO.isLocalClaimMappedWithinDialect(mappedLocalClaim, externalClaimDialectURI, + tenantId); + } +} diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/DefaultClaimMetadataStore.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/DefaultClaimMetadataStore.java index d0f073b2fb9b..25e4bf1131c5 100644 --- a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/DefaultClaimMetadataStore.java +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/DefaultClaimMetadataStore.java @@ -57,9 +57,7 @@ public class DefaultClaimMetadataStore implements ClaimMetadataStore { private static final Log log = LogFactory.getLog(DefaultClaimMetadataStore.class); - private ClaimDialectDAO claimDialectDAO = new CacheBackedClaimDialectDAO(); - private CacheBackedLocalClaimDAO localClaimDAO = new CacheBackedLocalClaimDAO(new LocalClaimDAO()); - private CacheBackedExternalClaimDAO externalClaimDAO = new CacheBackedExternalClaimDAO(new ExternalClaimDAO()); + private final UnifiedClaimMetadataManager unifiedClaimMetadataManager = new UnifiedClaimMetadataManager(); private int tenantId; @@ -71,7 +69,7 @@ public static DefaultClaimMetadataStore getInstance(int tenantId) { public DefaultClaimMetadataStore(ClaimConfig claimConfig, int tenantId) { try { - if (claimDialectDAO.getClaimDialects(tenantId).size() == 0) { + if (unifiedClaimMetadataManager.getClaimDialects(tenantId).size() == 0) { IdentityClaimManagementServiceDataHolder.getInstance().getClaimConfigInitDAO() .initClaimConfig(claimConfig, tenantId); } @@ -96,7 +94,7 @@ public String[] getAllClaimUris() throws UserStoreException { try { - List localClaimList = this.localClaimDAO.getLocalClaims(tenantId); + List localClaimList = this.unifiedClaimMetadataManager.getLocalClaims(tenantId); localClaims = new String[localClaimList.size()]; @@ -136,7 +134,7 @@ public String getAttributeName(String domainName, String claimURI) throws UserSt try { // Add listener - List localClaimList = this.localClaimDAO.getLocalClaims(tenantId); + List localClaimList = this.unifiedClaimMetadataManager.getLocalClaims(tenantId); // Add listener @@ -148,14 +146,14 @@ public String getAttributeName(String domainName, String claimURI) throws UserSt // For backward compatibility - List claimDialects = claimDialectDAO.getClaimDialects(tenantId); + List claimDialects = unifiedClaimMetadataManager.getClaimDialects(tenantId); for (ClaimDialect claimDialect : claimDialects) { if (ClaimConstants.LOCAL_CLAIM_DIALECT_URI.equalsIgnoreCase(claimDialect.getClaimDialectURI())) { continue; } - List externalClaims = externalClaimDAO.getExternalClaims(claimDialect + List externalClaims = unifiedClaimMetadataManager.getExternalClaims(claimDialect .getClaimDialectURI(), tenantId); for (ExternalClaim externalClaim : externalClaims) { @@ -247,7 +245,7 @@ public String getAttributeName(String claimURI) throws UserStoreException { @Deprecated public Claim getClaim(String claimURI) throws UserStoreException { try { - List localClaims = localClaimDAO.getLocalClaims(this.tenantId); + List localClaims = unifiedClaimMetadataManager.getLocalClaims(this.tenantId); for (LocalClaim localClaim : localClaims) { if (localClaim.getClaimURI().equalsIgnoreCase(claimURI)) { @@ -258,14 +256,14 @@ public Claim getClaim(String claimURI) throws UserStoreException { } // For backward compatibility - List claimDialects = claimDialectDAO.getClaimDialects(tenantId); + List claimDialects = unifiedClaimMetadataManager.getClaimDialects(tenantId); for (ClaimDialect claimDialect : claimDialects) { if (ClaimConstants.LOCAL_CLAIM_DIALECT_URI.equalsIgnoreCase(claimDialect.getClaimDialectURI())) { continue; } - List externalClaims = externalClaimDAO.getExternalClaims(claimDialect + List externalClaims = unifiedClaimMetadataManager.getExternalClaims(claimDialect .getClaimDialectURI(), tenantId); for (ExternalClaim externalClaim : externalClaims) { @@ -294,7 +292,7 @@ public Claim getClaim(String claimURI) throws UserStoreException { @Deprecated public ClaimMapping getClaimMapping(String claimURI) throws UserStoreException { try { - List localClaims = localClaimDAO.getLocalClaims(this.tenantId); + List localClaims = unifiedClaimMetadataManager.getLocalClaims(this.tenantId); for (LocalClaim localClaim : localClaims) { if (localClaim.getClaimURI().equalsIgnoreCase(claimURI)) { @@ -305,14 +303,14 @@ public ClaimMapping getClaimMapping(String claimURI) throws UserStoreException { } // For backward compatibility - List claimDialects = claimDialectDAO.getClaimDialects(tenantId); + List claimDialects = unifiedClaimMetadataManager.getClaimDialects(tenantId); for (ClaimDialect claimDialect : claimDialects) { if (ClaimConstants.LOCAL_CLAIM_DIALECT_URI.equalsIgnoreCase(claimDialect.getClaimDialectURI())) { continue; } - List externalClaims = externalClaimDAO.getExternalClaims(claimDialect + List externalClaims = unifiedClaimMetadataManager.getExternalClaims(claimDialect .getClaimDialectURI(), tenantId); for (ExternalClaim externalClaim : externalClaims) { @@ -345,7 +343,7 @@ public ClaimMapping[] getAllClaimMappings(String dialectUri) throws UserStoreExc if (ClaimConstants.LOCAL_CLAIM_DIALECT_URI.equalsIgnoreCase(dialectUri)) { try { - List localClaims = localClaimDAO.getLocalClaims(this.tenantId); + List localClaims = unifiedClaimMetadataManager.getLocalClaims(this.tenantId); List claimMappings = new ArrayList<>(); @@ -365,8 +363,9 @@ public ClaimMapping[] getAllClaimMappings(String dialectUri) throws UserStoreExc } } else { try { - List externalClaims = externalClaimDAO.getExternalClaims(dialectUri, this.tenantId); - List localClaims = localClaimDAO.getLocalClaims(this.tenantId); + List externalClaims = unifiedClaimMetadataManager.getExternalClaims(dialectUri, + this.tenantId); + List localClaims = unifiedClaimMetadataManager.getLocalClaims(this.tenantId); List claimMappings = new ArrayList<>(); @@ -414,7 +413,7 @@ public void updateClaimMapping(ClaimMapping claimMapping) throws UserStoreExcept public ClaimMapping[] getAllSupportClaimMappingsByDefault() throws UserStoreException { try { - List localClaims = localClaimDAO.getLocalClaims(this.tenantId); + List localClaims = unifiedClaimMetadataManager.getLocalClaims(this.tenantId); List claimMappings = new ArrayList<>(); @@ -442,7 +441,7 @@ public ClaimMapping[] getAllSupportClaimMappingsByDefault() throws UserStoreExce public ClaimMapping[] getAllRequiredClaimMappings() throws UserStoreException { try { - List localClaims = localClaimDAO.getLocalClaims(this.tenantId); + List localClaims = unifiedClaimMetadataManager.getLocalClaims(this.tenantId); List claimMappings = new ArrayList<>(); diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/SystemDefaultClaimMetadataManager.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/SystemDefaultClaimMetadataManager.java new file mode 100644 index 000000000000..97d0333ef4ff --- /dev/null +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/SystemDefaultClaimMetadataManager.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.claim.metadata.mgt; + +import org.apache.commons.lang.StringUtils; +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; +import org.wso2.carbon.identity.claim.metadata.mgt.internal.ReadOnlyClaimMetadataManager; +import org.wso2.carbon.identity.claim.metadata.mgt.internal.IdentityClaimManagementServiceDataHolder; +import org.wso2.carbon.identity.claim.metadata.mgt.model.Claim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ClaimDialect; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimMetadataUtils; +import org.wso2.carbon.user.core.claim.inmemory.ClaimConfig; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.LOCAL_CLAIM_DIALECT_URI; + +/** + * System default claim metadata manager. + */ +public class SystemDefaultClaimMetadataManager implements ReadOnlyClaimMetadataManager { + + private static final List claimDialects; + private static final Map> claims; + + static { + + ClaimConfig claimConfig = IdentityClaimManagementServiceDataHolder.getInstance().getClaimConfig(); + claims = ClaimMetadataUtils.getClaimsMapFromClaimConfig(claimConfig); + claimDialects = claims.keySet().stream() + .map(ClaimDialect::new) + .collect(Collectors.toList()); + } + + @Override + public List getClaimDialects(int tenantId) throws ClaimMetadataException { + + return claimDialects; + } + + @Override + public Optional getClaimDialect(String claimDialectURI, int tenantId) throws ClaimMetadataException { + + if (StringUtils.isBlank(claimDialectURI)) { + throw new ClaimMetadataException("Invalid claim dialect URI: " + claimDialectURI); + } + + return claimDialects.stream() + .filter(claimDialect -> claimDialectURI.equals(claimDialect.getClaimDialectURI())) + .findFirst(); + } + + @Override + public List getLocalClaims(int tenantId) throws ClaimMetadataException { + + List localClaims = claims.get(LOCAL_CLAIM_DIALECT_URI); + + if (localClaims == null) { + return Collections.emptyList(); + } + + return localClaims.stream() + .map(LocalClaim.class::cast) + .collect(Collectors.toList()); + } + + @Override + public Optional getLocalClaim(String localClaimURI ,int tenantId) throws ClaimMetadataException { + + if (StringUtils.isBlank(localClaimURI)) { + throw new ClaimMetadataException("Invalid local claim URI: " + localClaimURI); + } + + return claims.getOrDefault(LOCAL_CLAIM_DIALECT_URI, Collections.emptyList()).stream() + .filter(claim -> localClaimURI.equals(claim.getClaimURI())) + .map(LocalClaim.class::cast) + .findFirst(); + } + + @Override + public List getExternalClaims(String externalClaimDialectURI, int tenantId) + throws ClaimMetadataException { + + if (StringUtils.isBlank(externalClaimDialectURI)) { + throw new ClaimMetadataException("Invalid external claim dialect URI: " + externalClaimDialectURI); + } + + if (externalClaimDialectURI.equals(LOCAL_CLAIM_DIALECT_URI)) { + throw new ClaimMetadataException("Invalid external claim dialect URI: " + externalClaimDialectURI); + } + + return claims.getOrDefault(externalClaimDialectURI, Collections.emptyList()).stream() + .map(ExternalClaim.class::cast) + .collect(Collectors.toList()); + } + + @Override + public Optional getExternalClaim(String externalClaimDialectURI, String claimURI, int tenantId) + throws ClaimMetadataException { + + if (StringUtils.isBlank(externalClaimDialectURI) || StringUtils.isBlank(claimURI)) { + throw new ClaimMetadataException("Invalid external claim dialect URI or claim URI"); + } + + if (externalClaimDialectURI.equals(LOCAL_CLAIM_DIALECT_URI)) { + throw new ClaimMetadataException("Invalid external claim dialect URI: " + externalClaimDialectURI); + } + + return claims.getOrDefault(externalClaimDialectURI, Collections.emptyList()).stream() + .filter(claim -> claimURI.equals(claim.getClaimURI())) + .map(ExternalClaim.class::cast) + .findFirst(); + } + + @Override + public List getMappedExternalClaims(String localClaimURI, int tenantId) throws ClaimMetadataException { + + if (StringUtils.isBlank(localClaimURI)) { + throw new ClaimMetadataException("Invalid local claim URI: " + localClaimURI); + } + + List mappedExternalClaims = new ArrayList<>(); + for (Map.Entry> entry : claims.entrySet()) { + if (LOCAL_CLAIM_DIALECT_URI.equals(entry.getKey())) { + continue; + } + List externalClaims = entry.getValue().stream() + .map(ExternalClaim.class::cast) + .filter(claim -> localClaimURI.equals(claim.getMappedLocalClaim())) + .map(Claim.class::cast) + .collect(Collectors.toList()); + mappedExternalClaims.addAll(externalClaims); + } + return mappedExternalClaims; + } + + @Override + public boolean isMappedLocalClaim(String localClaimURI, int tenantId) throws ClaimMetadataException { + + if (StringUtils.isBlank(localClaimURI)) { + throw new ClaimMetadataException("Invalid local claim URI: " + localClaimURI); + } + + for (Map.Entry> entry : claims.entrySet()) { + if (LOCAL_CLAIM_DIALECT_URI.equals(entry.getKey())) { + continue; + } + boolean isMapped = entry.getValue().stream() + .filter(claim -> claim instanceof ExternalClaim) + .map(ExternalClaim.class::cast) + .anyMatch(claim -> localClaimURI.equals(claim.getMappedLocalClaim())); + + if (isMapped) { + return true; + } + } + return false; + } + + @Override + public boolean isLocalClaimMappedWithinDialect(String mappedLocalClaim, String externalClaimDialectURI, int tenantId) throws ClaimMetadataException { + + if (StringUtils.isBlank(externalClaimDialectURI) || StringUtils.isBlank(mappedLocalClaim)) { + throw new ClaimMetadataException("Invalid external claim dialect URI or mapped local claim"); + } + if (!claims.containsKey(externalClaimDialectURI)) { + return false; + } + return claims.get(externalClaimDialectURI).stream() + .filter(claim -> claim instanceof ExternalClaim) + .map(ExternalClaim.class::cast) + .anyMatch(claim -> mappedLocalClaim.equals(claim.getMappedLocalClaim())); + } +} diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/UnifiedClaimMetadataManager.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/UnifiedClaimMetadataManager.java new file mode 100644 index 000000000000..424bff9d5b09 --- /dev/null +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/UnifiedClaimMetadataManager.java @@ -0,0 +1,576 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.claim.metadata.mgt; + +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataClientException; +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; +import org.wso2.carbon.identity.claim.metadata.mgt.internal.ReadOnlyClaimMetadataManager; +import org.wso2.carbon.identity.claim.metadata.mgt.internal.ReadWriteClaimMetadataManager; +import org.wso2.carbon.identity.claim.metadata.mgt.model.AttributeMapping; +import org.wso2.carbon.identity.claim.metadata.mgt.model.Claim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ClaimDialect; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; + +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.ClaimConstants.ErrorMessage.ERROR_CODE_NO_DELETE_SYSTEM_CLAIM; +import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_NO_DELETE_SYSTEM_DIALECT; +import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.ErrorMessage.ERROR_CODE_NO_RENAME_SYSTEM_DIALECT; + +/** + * Unified claim metadata manager. + * + * This class provides a unified view of claim metadata from the system default claim metadata manager and the + * database-based claim metadata manager. + */ +public class UnifiedClaimMetadataManager implements ReadWriteClaimMetadataManager { + + private final ReadOnlyClaimMetadataManager systemDefaultClaimMetadataManager = + new SystemDefaultClaimMetadataManager(); + private final ReadWriteClaimMetadataManager dbBasedClaimMetadataManager = new DBBasedClaimMetadataManager(); + + /** + * Get all claim dialects. + * + * @param tenantId Tenant ID. + * @return List of claim dialects. + * @throws ClaimMetadataException If an error occurs while retrieving claim dialects. + */ + public List getClaimDialects(int tenantId) throws ClaimMetadataException { + + List claimDialectsInDB = this.dbBasedClaimMetadataManager.getClaimDialects(tenantId); + List claimDialectsInSystem = this.systemDefaultClaimMetadataManager.getClaimDialects(tenantId); + Set claimDialectURIsInDB = claimDialectsInDB.stream() + .map(ClaimDialect::getClaimDialectURI) + .collect(Collectors.toSet()); + + List allClaimDialects = new ArrayList<>(claimDialectsInDB); + claimDialectsInSystem.stream() + .filter(claimDialect -> !claimDialectURIsInDB.contains(claimDialect.getClaimDialectURI())) + .forEach(allClaimDialects::add); + return allClaimDialects; + } + + /** + * Get a claim dialect by URI. + * + * @param claimDialectURI Claim dialect URI. + * @param tenantId Tenant ID. + * @return Claim dialect. + * @throws ClaimMetadataException If an error occurs while retrieving claim dialect. + */ + public Optional getClaimDialect(String claimDialectURI, int tenantId) throws ClaimMetadataException { + + Optional claimDialectInDB = this.dbBasedClaimMetadataManager.getClaimDialect(claimDialectURI, tenantId); + if (claimDialectInDB.isPresent()) { + return claimDialectInDB; + } + return this.systemDefaultClaimMetadataManager.getClaimDialect(claimDialectURI, tenantId); + } + + /** + * Add a claim dialect. + * + * @param claimDialect Claim dialect. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException If an error occurs while adding claim dialect. + */ + public void addClaimDialect(ClaimDialect claimDialect, int tenantId) throws ClaimMetadataException { + + this.dbBasedClaimMetadataManager.addClaimDialect(claimDialect, tenantId); + } + + /** + * Rename a claim dialect. + * + * @param oldClaimDialect Old claim dialect. + * @param newClaimDialect New claim dialect. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException If an error occurs while renaming claim dialect. + */ + public void renameClaimDialect(ClaimDialect oldClaimDialect, ClaimDialect newClaimDialect, int tenantId) + throws ClaimMetadataException { + + boolean isSystemDefaultClaimDialect = isSystemDefaultClaimDialect(oldClaimDialect.getClaimDialectURI(), + tenantId); + if (isSystemDefaultClaimDialect) { + throw new ClaimMetadataClientException(ERROR_CODE_NO_RENAME_SYSTEM_DIALECT.getCode(), + String.format(ERROR_CODE_NO_RENAME_SYSTEM_DIALECT.getMessage(), + oldClaimDialect.getClaimDialectURI())); + } + + this.dbBasedClaimMetadataManager.renameClaimDialect(oldClaimDialect, newClaimDialect, tenantId); + } + + /** + * Remove a claim dialect. + * + * @param claimDialect Claim dialect. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException If an error occurs while removing claim dialect. + */ + public void removeClaimDialect(ClaimDialect claimDialect, int tenantId) throws ClaimMetadataException { + + boolean isSystemDefaultClaimDialect = isSystemDefaultClaimDialect(claimDialect.getClaimDialectURI(), tenantId); + if (isSystemDefaultClaimDialect) { + throw new ClaimMetadataClientException(ERROR_CODE_NO_DELETE_SYSTEM_DIALECT.getCode(), + String.format(ERROR_CODE_NO_DELETE_SYSTEM_DIALECT.getMessage(), claimDialect.getClaimDialectURI())); + } + + this.dbBasedClaimMetadataManager.removeClaimDialect(claimDialect, tenantId); + } + + /** + * Get all local claims. + * + * @param tenantId Tenant ID. + * @return List of local claims. + * @throws ClaimMetadataException If an error occurs while retrieving local claims. + */ + public List getLocalClaims(int tenantId) throws ClaimMetadataException { + + List localClaimsInSystem = this.systemDefaultClaimMetadataManager.getLocalClaims(tenantId); + List localClaimsInDB = this.dbBasedClaimMetadataManager.getLocalClaims(tenantId); + + List allLocalClaims = new ArrayList<>(localClaimsInDB); + localClaimsInSystem.forEach(systemClaim -> { + Optional matchingClaimInDB = allLocalClaims.stream() + .filter(dbClaim -> dbClaim.getClaimURI().equals(systemClaim.getClaimURI())) + .findFirst(); + + if (matchingClaimInDB.isPresent()) { + matchingClaimInDB.get().setClaimProperty(ClaimConstants.IS_SYSTEM_CLAIM, Boolean.TRUE.toString()); + } else { + systemClaim.setClaimProperty(ClaimConstants.IS_SYSTEM_CLAIM, Boolean.TRUE.toString()); + allLocalClaims.add(systemClaim); + } + }); + + return allLocalClaims; + } + + /** + * Get a local claim by URI. + * + * @param localClaimURI Local claim URI. + * @param tenantId Tenant ID. + * @return Local claim. + * @throws ClaimMetadataException If an error occurs while retrieving local claim. + */ + public Optional getLocalClaim(String localClaimURI, int tenantId) throws ClaimMetadataException { + + Optional localClaimInDB = this.dbBasedClaimMetadataManager.getLocalClaim(localClaimURI, tenantId); + if (localClaimInDB.isPresent()) { + if (isSystemDefaultLocalClaim(localClaimURI, tenantId)) { + localClaimInDB.get().setClaimProperty(ClaimConstants.IS_SYSTEM_CLAIM, Boolean.TRUE.toString()); + } + return localClaimInDB; + } + Optional localClaimInSystem = this.systemDefaultClaimMetadataManager.getLocalClaim(localClaimURI, tenantId); + if (localClaimInSystem.isPresent()) { + localClaimInSystem.get().setClaimProperty(ClaimConstants.IS_SYSTEM_CLAIM, Boolean.TRUE.toString()); + return localClaimInSystem; + } + return Optional.empty(); + } + + /** + * Add a local claim. + * + * @param localClaim Local claim. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException If an error occurs while adding local claim. + */ + public void addLocalClaim(LocalClaim localClaim, int tenantId) throws ClaimMetadataException { + + localClaim.getClaimProperties().remove(ClaimConstants.IS_SYSTEM_CLAIM); + if (!isClaimDialectInDB(ClaimConstants.LOCAL_CLAIM_DIALECT_URI, tenantId)) { + addSystemDefaultDialectToDB(ClaimConstants.LOCAL_CLAIM_DIALECT_URI, tenantId); + } + this.dbBasedClaimMetadataManager.addLocalClaim(localClaim, tenantId); + } + + /** + * Update a local claim. + * + * @param localClaim Local claim. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException If an error occurs while updating local claim. + */ + public void updateLocalClaim(LocalClaim localClaim, int tenantId) throws ClaimMetadataException { + + localClaim.getClaimProperties().remove(ClaimConstants.IS_SYSTEM_CLAIM); + if (isLocalClaimInDB(localClaim.getClaimURI(), tenantId)) { + this.dbBasedClaimMetadataManager.updateLocalClaim(localClaim, tenantId); + } else { + this.addLocalClaim(localClaim, tenantId); + } + } + + /** + * Update local claim mappings. + * + * @param localClaimList List of local claims. + * @param tenantId Tenant ID. + * @param userStoreDomain User store domain. + * @throws ClaimMetadataException If an error occurs while updating local claim mappings. + */ + public void updateLocalClaimMappings(List localClaimList, int tenantId, String userStoreDomain) + throws ClaimMetadataException { + + if (localClaimList == null) { + return; + } + if (!localClaimList.isEmpty() && !isClaimDialectInDB(ClaimConstants.LOCAL_CLAIM_DIALECT_URI, tenantId)) { + addSystemDefaultDialectToDB(ClaimConstants.LOCAL_CLAIM_DIALECT_URI, tenantId); + } + + Map localClaimMap = this.getLocalClaims(tenantId).stream() + .collect(Collectors.toMap(LocalClaim::getClaimURI, localClaim -> localClaim)); + for (LocalClaim localClaim : localClaimList) { + if (localClaimMap.get(localClaim.getClaimURI()) == null) { + throw new ClaimMetadataClientException(ERROR_CODE_NON_EXISTING_LOCAL_CLAIM_URI.getCode(), + String.format(ERROR_CODE_NON_EXISTING_LOCAL_CLAIM_URI.getMessage(), localClaim.getClaimURI())); + } + List missingMappedAttributes = localClaimMap.get(localClaim.getClaimURI()) + .getMappedAttributes().stream() + .filter(mappedAttribute -> !mappedAttribute.getUserStoreDomain().equals(userStoreDomain)) + .collect(Collectors.toList()); + localClaim.getMappedAttributes().addAll(missingMappedAttributes); + localClaim.setClaimProperties(localClaimMap.get(localClaim.getClaimURI()).getClaimProperties()); + } + this.dbBasedClaimMetadataManager.updateLocalClaimMappings(localClaimList, tenantId, userStoreDomain); + } + + /** + * Remove a local claim. + * + * @param localClaimURI Local claim URI. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException If an error occurs while removing local claim. + */ + public void removeLocalClaim(String localClaimURI, int tenantId) throws ClaimMetadataException { + + boolean isSystemDefaultClaim = isSystemDefaultLocalClaim(localClaimURI, tenantId); + if (isSystemDefaultClaim) { + throw new ClaimMetadataClientException(ERROR_CODE_NO_DELETE_SYSTEM_CLAIM.getCode(), + String.format(ERROR_CODE_NO_DELETE_SYSTEM_CLAIM.getMessage(), localClaimURI)); + } + + this.dbBasedClaimMetadataManager.removeLocalClaim(localClaimURI, tenantId); + } + + /** + * Get all external claims. + * + * @param externalClaimDialectURI External claim dialect URI. + * @param tenantId Tenant ID. + * @return List of external claims. + * @throws ClaimMetadataException If an error occurs while retrieving external claims. + */ + public List getExternalClaims(String externalClaimDialectURI, int tenantId) + throws ClaimMetadataException { + + List externalClaimsInSystem = this.systemDefaultClaimMetadataManager.getExternalClaims( + externalClaimDialectURI, tenantId); + List externalClaimsInDB = this.dbBasedClaimMetadataManager.getExternalClaims( + externalClaimDialectURI, tenantId); + + Map externalClaimsInDBMap = externalClaimsInDB.stream() + .collect(Collectors.toMap(ExternalClaim::getClaimURI, claim -> claim)); + + List allExternalClaims = new ArrayList<>(); + for (ExternalClaim externalClaimInSystem : externalClaimsInSystem) { + ExternalClaim matchingClaimInDB = externalClaimsInDBMap.get(externalClaimInSystem.getClaimURI()); + if (matchingClaimInDB != null) { + matchingClaimInDB.setClaimProperty(ClaimConstants.IS_SYSTEM_CLAIM, Boolean.TRUE.toString()); + allExternalClaims.add(matchingClaimInDB); + externalClaimsInDBMap.remove(externalClaimInSystem.getClaimURI()); + } else { + externalClaimInSystem.setClaimProperty(ClaimConstants.IS_SYSTEM_CLAIM, Boolean.TRUE.toString()); + allExternalClaims.add(externalClaimInSystem); + } + } + allExternalClaims.addAll(externalClaimsInDBMap.values()); + return allExternalClaims; + } + + /** + * Get an external claim by URI. + * + * @param externalClaimDialectURI External claim dialect URI. + * @param claimURI Claim URI. + * @param tenantId Tenant ID. + * @return External claim. + * @throws ClaimMetadataException If an error occurs while retrieving external claim. + */ + public Optional getExternalClaim(String externalClaimDialectURI, String claimURI, int tenantId) + throws ClaimMetadataException { + + Optional externalClaim = this.dbBasedClaimMetadataManager.getExternalClaim( + externalClaimDialectURI, claimURI, tenantId); + if (externalClaim.isPresent()) { + if (isSystemDefaultExternalClaim(externalClaimDialectURI, claimURI, tenantId)) { + externalClaim.get().setClaimProperty(ClaimConstants.IS_SYSTEM_CLAIM, Boolean.TRUE.toString()); + } + return externalClaim; + } + Optional externalClaimInSystem = this.systemDefaultClaimMetadataManager.getExternalClaim( + externalClaimDialectURI, claimURI, tenantId); + if (externalClaimInSystem.isPresent()) { + externalClaimInSystem.get().setClaimProperty(ClaimConstants.IS_SYSTEM_CLAIM, Boolean.TRUE.toString()); + return externalClaimInSystem; + } + return Optional.empty(); + } + + /** + * Add an external claim. + * + * @param externalClaim External claim. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException If an error occurs while adding external claim. + */ + public void addExternalClaim(ExternalClaim externalClaim, int tenantId) + throws ClaimMetadataException { + + externalClaim.getClaimProperties().remove(ClaimConstants.IS_SYSTEM_CLAIM); + if (!isClaimDialectInDB(externalClaim.getClaimDialectURI(), tenantId)) { + addSystemDefaultDialectToDB(externalClaim.getClaimDialectURI(), tenantId); + } + if (!isLocalClaimInDB(externalClaim.getMappedLocalClaim(), tenantId)) { + addSystemDefaultLocalClaimToDB(externalClaim.getMappedLocalClaim(), tenantId); + } + this.dbBasedClaimMetadataManager.addExternalClaim(externalClaim, tenantId); + } + + /** + * Update an external claim. + * + * @param externalClaim External claim. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException If an error occurs while updating external claim. + */ + public void updateExternalClaim(ExternalClaim externalClaim, int tenantId) + throws ClaimMetadataException { + + externalClaim.getClaimProperties().remove(ClaimConstants.IS_SYSTEM_CLAIM); + if (!isLocalClaimInDB(externalClaim.getMappedLocalClaim(), tenantId)) { + addSystemDefaultLocalClaimToDB(externalClaim.getMappedLocalClaim(), tenantId); + } + if (isExternalClaimInDB(externalClaim.getClaimURI(), externalClaim.getClaimDialectURI(), tenantId)) { + this.dbBasedClaimMetadataManager.updateExternalClaim(externalClaim, tenantId); + } else { + this.addExternalClaim(externalClaim, tenantId); + } + } + + /** + * Remove an external claim. + * + * @param externalClaimDialectURI External claim dialect URI. + * @param externalClaimURI External claim URI. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException If an error occurs while removing external claim. + */ + public void removeExternalClaim(String externalClaimDialectURI, String externalClaimURI, int tenantId) + throws ClaimMetadataException { + + boolean isSystemDefaultClaim = isSystemDefaultExternalClaim(externalClaimDialectURI, externalClaimURI, tenantId); + if (isSystemDefaultClaim) { + throw new ClaimMetadataClientException(ERROR_CODE_NO_DELETE_SYSTEM_CLAIM.getCode(), + String.format(ERROR_CODE_NO_DELETE_SYSTEM_CLAIM.getMessage(), externalClaimURI)); + } + + this.dbBasedClaimMetadataManager.removeExternalClaim(externalClaimDialectURI, externalClaimURI, tenantId); + } + + /** + * Check whether any external claim maps to a given local claim. + * @param localClaimURI Local claim URI. + * @param tenantId Tenant ID. + * @return True if the local claim is mapped. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + public boolean isMappedLocalClaim(String localClaimURI, int tenantId) throws ClaimMetadataException { + + List claimDialects = this.getClaimDialects(tenantId); + + for (ClaimDialect claimDialect : claimDialects) { + if (ClaimConstants.LOCAL_CLAIM_DIALECT_URI.equals(claimDialect.getClaimDialectURI())) { + continue; + } + List externalClaims = getExternalClaims(claimDialect.getClaimDialectURI(), tenantId); + for (ExternalClaim externalClaim : externalClaims) { + if (externalClaim.getMappedLocalClaim().equals(localClaimURI)) { + return true; + } + } + } + return false; + } + + /** + * Remove mapped user store attributes of a user store domain. + * @param tenantId Tenant ID. + * @param userstoreDomain User Store Domain name. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + public void removeClaimMappingAttributes(int tenantId, String userstoreDomain) throws ClaimMetadataException { + + this.dbBasedClaimMetadataManager.removeClaimMappingAttributes(tenantId, userstoreDomain); + } + + /** + * Remove all claim dialects. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + public void removeAllClaimDialects(int tenantId) throws ClaimMetadataException { + + this.dbBasedClaimMetadataManager.removeAllClaimDialects(tenantId); + } + + /** + * Get all external claims mapped to a local claim. + * @param localClaimURI Local claim URI. + * @param tenantId Tenant ID. + * @return List of mapped external claims. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + public List getMappedExternalClaims(String localClaimURI, int tenantId) throws ClaimMetadataException { + + List mappedExternalClaims = new ArrayList<>(); + List claimDialects = getClaimDialects(tenantId); + for (ClaimDialect claimDialect : claimDialects) { + if (ClaimConstants.LOCAL_CLAIM_DIALECT_URI.equals(claimDialect.getClaimDialectURI())) { + continue; + } + List externalClaimsInDialect = getExternalClaims(claimDialect.getClaimDialectURI(), + tenantId); + for (ExternalClaim externalClaim : externalClaimsInDialect) { + if (externalClaim.getMappedLocalClaim().equals(localClaimURI)) { + mappedExternalClaims.add(externalClaim); + } + } + } + return mappedExternalClaims; + } + + /** + * Check whether a local claim is mapped within a dialect. + * @param mappedLocalClaim Mapped local claim. + * @param externalClaimDialectURI External claim dialect URI. + * @param tenantId Tenant ID. + * @return True if the local claim is mapped. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + public boolean isLocalClaimMappedWithinDialect(String mappedLocalClaim, String externalClaimDialectURI, + int tenantId) throws ClaimMetadataException { + + return getExternalClaims(externalClaimDialectURI, tenantId).stream() + .anyMatch(externalClaim -> externalClaim.getMappedLocalClaim().equals(mappedLocalClaim)); + } + + /** + * Check whether a claim dialect is a system default claim dialect. + * @param claimDialectURI Claim dialect URI. + * @param tenantId Tenant ID. + * @return True if the claim dialect is a system default claim dialect. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + private boolean isSystemDefaultClaimDialect(String claimDialectURI, int tenantId) throws ClaimMetadataException { + + return this.systemDefaultClaimMetadataManager.getClaimDialect(claimDialectURI, tenantId).isPresent(); + } + + /** + * Check whether a local claim is a system default local claim. + * @param localClaimURI Local claim URI. + * @param tenantId Tenant ID. + * @return True if the local claim is a system default local claim. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + private boolean isSystemDefaultLocalClaim(String localClaimURI, int tenantId) throws ClaimMetadataException { + + return this.systemDefaultClaimMetadataManager.getLocalClaims(tenantId).stream() + .anyMatch(localClaim -> localClaim.getClaimURI().equals(localClaimURI)); + } + + /** + * Check whether an external claim is a system default external claim. + * @param externalClaimDialectURI External claim dialect URI. + * @param externalClaimURI External claim URI. + * @param tenantId Tenant ID. + * @return True if the external claim is a system default external claim. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + private boolean isSystemDefaultExternalClaim(String externalClaimDialectURI, String externalClaimURI, int tenantId) + throws ClaimMetadataException { + + return this.systemDefaultClaimMetadataManager.getExternalClaims(externalClaimDialectURI,tenantId).stream() + .anyMatch(externalClaim -> externalClaim.getClaimURI().equals(externalClaimURI)); + } + + private boolean isClaimDialectInDB(String claimDialectURI, int tenantId) throws ClaimMetadataException { + + return this.dbBasedClaimMetadataManager.getClaimDialect(claimDialectURI, tenantId).isPresent(); + } + + private boolean isLocalClaimInDB(String localClaimURI, int tenantId) throws ClaimMetadataException { + + return this.dbBasedClaimMetadataManager.getLocalClaim(localClaimURI, tenantId).isPresent(); + } + + private boolean isExternalClaimInDB(String claimURI, String claimDialectURI, int tenantId) + throws ClaimMetadataException { + + return this.dbBasedClaimMetadataManager.getExternalClaim(claimDialectURI, claimURI, tenantId).isPresent(); + } + + private void addSystemDefaultDialectToDB(String claimDialectURI, int tenantId) throws ClaimMetadataException { + + Optional claimDialectInSystem = this.systemDefaultClaimMetadataManager + .getClaimDialect(claimDialectURI, tenantId); + if (claimDialectInSystem.isPresent()) { + this.dbBasedClaimMetadataManager.addClaimDialect(claimDialectInSystem.get(), tenantId); + } + } + + private void addSystemDefaultLocalClaimToDB(String claimURI, int tenantId) + throws ClaimMetadataException { + + boolean isClaimDialectInDB = isClaimDialectInDB(ClaimConstants.LOCAL_CLAIM_DIALECT_URI, tenantId); + if (!isClaimDialectInDB) { + addSystemDefaultDialectToDB(ClaimConstants.LOCAL_CLAIM_DIALECT_URI, tenantId); + } + Optional claimInSystem = this.systemDefaultClaimMetadataManager.getLocalClaim(claimURI, tenantId); + if (claimInSystem.isPresent()) { + this.dbBasedClaimMetadataManager.addLocalClaim(claimInSystem.get(), tenantId); + } + } +} diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/ClaimDAO.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/ClaimDAO.java index 485202f6612a..34f799c1d829 100644 --- a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/ClaimDAO.java +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/ClaimDAO.java @@ -232,4 +232,33 @@ protected void deleteClaimProperties(Connection connection, int claimId, int ten throw new ClaimMetadataException("Error while deleting claim properties", e); } } + + public int getIdOfClaim(Connection connection, String claimDialectURI, String claimURI, int tenantId) throws + ClaimMetadataException { + + PreparedStatement prepStmt = null; + ResultSet rs = null; + + int claimId = 0; + String query = SQLConstants.GET_CLAIM_ID; + try { + prepStmt = connection.prepareStatement(query); + prepStmt.setString(1, claimDialectURI); + prepStmt.setInt(2, tenantId); + prepStmt.setString(3, claimURI); + prepStmt.setInt(4, tenantId); + rs = prepStmt.executeQuery(); + + while (rs.next()) { + claimId = rs.getInt(SQLConstants.ID_COLUMN); + } + } catch (SQLException e) { + throw new ClaimMetadataException("Error while retrieving ID for claim " + claimURI + " in dialect " + + claimDialectURI, e); + } finally { + IdentityDatabaseUtil.closeResultSet(rs); + IdentityDatabaseUtil.closeStatement(prepStmt); + } + return claimId; + } } diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/ExternalClaimDAO.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/ExternalClaimDAO.java index a43b3da176d8..881022570710 100644 --- a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/ExternalClaimDAO.java +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/ExternalClaimDAO.java @@ -20,7 +20,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; -import org.wso2.carbon.identity.claim.metadata.mgt.model.Claim; import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; import org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants; import org.wso2.carbon.identity.claim.metadata.mgt.util.SQLConstants; @@ -62,7 +61,6 @@ public List getExternalClaims(String externalDialectURI, int tena public void addExternalClaim(ExternalClaim externalClaim, int tenantId) throws ClaimMetadataException { Connection connection = IdentityDatabaseUtil.getDBConnection(); - PreparedStatement prepStmt = null; String externalClaimURI = externalClaim.getClaimURI(); String externalClaimDialectURI = externalClaim.getClaimDialectURI(); diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/LocalClaimDAO.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/LocalClaimDAO.java index 0f3debc73001..9a1c139bc5f8 100644 --- a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/LocalClaimDAO.java +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/LocalClaimDAO.java @@ -194,7 +194,6 @@ public void addLocalClaim(LocalClaim localClaim, int tenantId) throws ClaimMetad public void updateLocalClaim(LocalClaim localClaim, int tenantId) throws ClaimMetadataException { Connection connection = IdentityDatabaseUtil.getDBConnection(); - PreparedStatement prepStmt = null; String localClaimURI = localClaim.getClaimURI(); @@ -243,17 +242,36 @@ public void updateLocalClaimMappings(List localClaimList, int tenant for (LocalClaim localClaim : localClaimList) { String localClaimURI = localClaim.getClaimURI(); - int localClaimId = getClaimId(connection, ClaimConstants.LOCAL_CLAIM_DIALECT_URI, - localClaimURI, tenantId); - List existingClaimAttributeMappings = - claimAttributeMappingsOfDialect.get(localClaimId); - existingClaimAttributeMappings.removeIf(attributeMapping -> attributeMapping.getUserStoreDomain(). - equals(userStoreDomain.toUpperCase())); - existingClaimAttributeMappings.add(new AttributeMapping(userStoreDomain, - localClaim.getMappedAttribute(userStoreDomain))); - - deleteClaimAttributeMappings(connection, localClaimId, tenantId); - addClaimAttributeMappings(connection, localClaimId, existingClaimAttributeMappings, tenantId); + int localClaimId = getIdOfClaim(connection, ClaimConstants.LOCAL_CLAIM_DIALECT_URI, localClaimURI, + tenantId); + boolean isLocalClaimExist = localClaimId != 0; + if (isLocalClaimExist) { + List existingClaimAttributeMappings = + claimAttributeMappingsOfDialect.get(localClaimId); + if (existingClaimAttributeMappings == null) { + existingClaimAttributeMappings = new ArrayList<>(); + } + existingClaimAttributeMappings.removeIf(attributeMapping -> attributeMapping.getUserStoreDomain() + .equals(userStoreDomain.toUpperCase())); + existingClaimAttributeMappings.add(new AttributeMapping(userStoreDomain, + localClaim.getMappedAttribute(userStoreDomain))); + + deleteClaimAttributeMappings(connection, localClaimId, tenantId); + addClaimAttributeMappings(connection, localClaimId, existingClaimAttributeMappings, tenantId); + } else { + localClaimId = addClaim(connection, ClaimConstants.LOCAL_CLAIM_DIALECT_URI, localClaimURI, tenantId); + + // Some JDBC Drivers returns this in the result, some don't + if (localClaimId == 0) { + if (log.isDebugEnabled()) { + log.debug("JDBC Driver did not return the claimId, executing Select operation"); + } + localClaimId = getClaimId(connection, ClaimConstants.LOCAL_CLAIM_DIALECT_URI, localClaimURI, tenantId); + } + + addClaimAttributeMappings(connection, localClaimId, localClaim.getMappedAttributes(), tenantId); + addClaimProperties(connection, localClaimId, localClaim.getClaimProperties(), tenantId); + } } // End transaction. diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/internal/ReadOnlyClaimMetadataManager.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/internal/ReadOnlyClaimMetadataManager.java new file mode 100644 index 000000000000..4c6c77e46f18 --- /dev/null +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/internal/ReadOnlyClaimMetadataManager.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.claim.metadata.mgt.internal; + +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; +import org.wso2.carbon.identity.claim.metadata.mgt.model.Claim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ClaimDialect; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim; + +import java.util.List; +import java.util.Optional; + +/** + * Claim metadata reader. + */ +public interface ReadOnlyClaimMetadataManager { + + /** + * Get all claim dialects. + * + * @param tenantId Tenant ID. + * @return List of claim dialects. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + List getClaimDialects(int tenantId) throws ClaimMetadataException; + + /** + * Get a claim dialect by URI. + * + * @param claimDialectURI Claim dialect URI. + * @param tenantId Tenant ID. + * @return Claim dialect. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + Optional getClaimDialect(String claimDialectURI, int tenantId) throws ClaimMetadataException; + + /** + * Get all local claims. + * + * @param tenantId Tenant ID. + * @return List of local claims. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + List getLocalClaims(int tenantId) throws ClaimMetadataException; + + /** + * Get a local claim by URI. + * + * @param localClaimURI Local claim URI. + * @param tenantId Tenant ID. + * @return Local claim. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + Optional getLocalClaim(String localClaimURI ,int tenantId) throws ClaimMetadataException; + + /** + * Get all external claims. + * + * @param externalClaimDialectURI External claim dialect URI. + * @param tenantId Tenant ID. + * @return List of external claims. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + List getExternalClaims(String externalClaimDialectURI, int tenantId) + throws ClaimMetadataException; + + /** + * Get an external claim by URI. + * @param externalClaimDialectURI External claim dialect URI. + * @param claimURI Claim URI. + * @param tenantId Tenant ID. + * @return External claim. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + Optional getExternalClaim(String externalClaimDialectURI, String claimURI, int tenantId) + throws ClaimMetadataException; + + /** + * Get all mapped external claims of a local claim. + * @param localClaimURI Local claim URI. + * @param tenantId Tenant ID. + * @return List of mapped external claims. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + List getMappedExternalClaims(String localClaimURI, int tenantId) throws ClaimMetadataException; + + /** + * Check whether any external claim maps to a given local claim. + * @param localClaimURI Local claim URI. + * @param tenantId Tenant ID. + * @return True if the local claim is mapped. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + boolean isMappedLocalClaim(String localClaimURI, int tenantId) throws ClaimMetadataException; + + /** + * Check whether a local claim is mapped within a given dialect. + * @param mappedLocalClaim Mapped local claim. + * @param externalClaimDialectURI External claim dialect URI. + * @param tenantId Tenant ID. + * @return True if the local claim is mapped within the dialect. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + boolean isLocalClaimMappedWithinDialect(String mappedLocalClaim, String externalClaimDialectURI, int tenantId) + throws ClaimMetadataException; +} diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/internal/ReadWriteClaimMetadataManager.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/internal/ReadWriteClaimMetadataManager.java new file mode 100644 index 000000000000..ed92977607a7 --- /dev/null +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/internal/ReadWriteClaimMetadataManager.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.claim.metadata.mgt.internal; + +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ClaimDialect; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim; + +import java.util.List; + +/** + * Claim metadata writer. + */ +public interface ReadWriteClaimMetadataManager extends ReadOnlyClaimMetadataManager { + + /** + * Add a claim dialect. + * + * @param claimDialect Claim dialect. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + void addClaimDialect(ClaimDialect claimDialect, int tenantId) throws ClaimMetadataException; + + /** + * Rename a claim dialect. + * + * @param oldClaimDialect Old claim dialect. + * @param newClaimDialect New claim dialect. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + void renameClaimDialect(ClaimDialect oldClaimDialect, ClaimDialect newClaimDialect, int tenantId) + throws ClaimMetadataException; + + /** + * Remove a claim dialect. + * @param claimDialect Claim dialect. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + void removeClaimDialect(ClaimDialect claimDialect, int tenantId) throws ClaimMetadataException; + + /** + * Add a local claim. + * + * @param localClaim Local claim. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + void addLocalClaim(LocalClaim localClaim, int tenantId) throws ClaimMetadataException; + + /** + * Update a local claim. + * + * @param localClaim Local claim. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + void updateLocalClaim(LocalClaim localClaim, int tenantId) throws ClaimMetadataException; + + /** + * Update mapped user store attributes of a user store domain in bulk. + * + * @param localClaimList List of local claims. + * @param tenantId Tenant ID. + * @param userStoreDomain User Store Domain name. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + void updateLocalClaimMappings(List localClaimList, int tenantId, String userStoreDomain) + throws ClaimMetadataException; + + /** + * Remove a local claim. + * @param localClaimURI Local claim URI. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + void removeLocalClaim(String localClaimURI, int tenantId) throws ClaimMetadataException; + + /** + * Remove mapped user store attributes of a user store domain. + * + * @param tenantId Tenant ID. + * @param userstoreDomain User Store Domain name. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + void removeClaimMappingAttributes(int tenantId, String userstoreDomain) throws ClaimMetadataException; + + /** + * Add an external claim. + * @param externalClaim External claim. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + void addExternalClaim(ExternalClaim externalClaim, int tenantId) throws ClaimMetadataException; + + /** + * Update an external claim. + * @param externalClaim External claim. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + void updateExternalClaim(ExternalClaim externalClaim, int tenantId) throws ClaimMetadataException; + + /** + * Remove an external claim. + * @param externalClaimDialectURI External claim dialect URI. + * @param externalClaimURI External claim URI. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + void removeExternalClaim(String externalClaimDialectURI, String externalClaimURI, int tenantId) + throws ClaimMetadataException; + + /** + * Remove all claim dialects. + * @param tenantId Tenant ID. + * @throws ClaimMetadataException if an error occurs during the operation. + */ + void removeAllClaimDialects(int tenantId) throws ClaimMetadataException; +} diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/model/LocalClaim.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/model/LocalClaim.java index 46c5afd7aa6c..d3b230c16bfe 100644 --- a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/model/LocalClaim.java +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/model/LocalClaim.java @@ -19,7 +19,6 @@ import org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/util/ClaimConstants.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/util/ClaimConstants.java index 86e54c269800..94b68fba4c31 100644 --- a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/util/ClaimConstants.java +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/util/ClaimConstants.java @@ -42,6 +42,7 @@ public class ClaimConstants { public static final String EXCLUDED_USER_STORES_PROPERTY = "ExcludedUserStores"; public static final String MIN_LENGTH = "minLength"; public static final String MAX_LENGTH = "maxLength"; + public static final String IS_SYSTEM_CLAIM = "isSystemClaim"; /** * Enum for error messages. @@ -88,6 +89,13 @@ public enum ErrorMessage { ERROR_CODE_EXISTING_LOCAL_CLAIM_MAPPING("CMT-60004", "Local claim URI : %s is already mapped in claim " + "dialect: %s"), ERROR_CODE_CLAIM_LENGTH_LIMIT("CMT-60005", "Claim property: %s should be between %s and %s"), + ERROR_CODE_NO_DELETE_SYSTEM_CLAIM("CMT-60006", "Cannot delete claim %s as it is a system claim"), + ERROR_CODE_NO_RENAME_SYSTEM_DIALECT("CMT-60007", "Cannot rename dialect %s as it is a system dialect"), + ERROR_CODE_NO_DELETE_SYSTEM_DIALECT("CMT-60008", "Cannot delete dialect %s as it is a system dialect"), + ERROR_CODE_INVALID_EXTERNAL_CLAIM_DIALECT_URI("CMT-60009", "Invalid external claim dialect URI: %s"), + ERROR_CODE_NON_EXISTING_EXTERNAL_CLAIM_URI("CMT-600010", "External claim URI: %s in dialect: %s does not exist."), + ERROR_CODE_NON_EXISTING_LOCAL_CLAIM("CMT-600011", "Local claim URI: %s does not exist."), + ERROR_CODE_EXISTING_EXTERNAL_CLAIM("CMT-600012", "External claim URI: %s in dialect: %s already exists."), // Server Errors ERROR_CODE_DELETE_IDN_CLAIM_MAPPED_ATTRIBUTE("65001", "Error occurred while deleting claim " + diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/util/ClaimMetadataUtils.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/util/ClaimMetadataUtils.java index b18e46519721..f75ad03383d4 100644 --- a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/util/ClaimMetadataUtils.java +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/main/java/org/wso2/carbon/identity/claim/metadata/mgt/util/ClaimMetadataUtils.java @@ -16,6 +16,8 @@ package org.wso2.carbon.identity.claim.metadata.mgt.util; +import org.apache.commons.collections.MapUtils; +import org.apache.commons.lang.StringUtils; import org.wso2.carbon.identity.claim.metadata.mgt.dto.AttributeMappingDTO; import org.wso2.carbon.identity.claim.metadata.mgt.dto.ClaimDialectDTO; import org.wso2.carbon.identity.claim.metadata.mgt.dto.ClaimPropertyDTO; @@ -26,11 +28,14 @@ import org.wso2.carbon.identity.claim.metadata.mgt.model.ClaimDialect; import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; import org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim; +import org.wso2.carbon.identity.core.util.IdentityUtil; import org.wso2.carbon.user.api.UserRealm; import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.core.UserCoreConstants; import org.wso2.carbon.user.core.claim.Claim; +import org.wso2.carbon.user.core.claim.ClaimKey; import org.wso2.carbon.user.core.claim.ClaimMapping; +import org.wso2.carbon.user.core.claim.inmemory.ClaimConfig; import org.wso2.carbon.user.core.service.RealmService; import java.util.ArrayList; @@ -38,6 +43,8 @@ import java.util.List; import java.util.Map; +import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.LOCAL_CLAIM_DIALECT_URI; + /** * Utility class containing various claim metadata implementation related functionality. */ @@ -318,4 +325,78 @@ public static ClaimMapping convertExternalClaimToClaimMapping(ExternalClaim exte claimMapping.getClaim().setClaimUri(externalClaim.getClaimURI()); return claimMapping; } + + /** + * This method is used to build system default claims from claim config. + * + * @param claimConfig Claim Mapping + * @return Claim Dialect + */ + public static Map> getClaimsMapFromClaimConfig + (ClaimConfig claimConfig) { + + Map> claims = new HashMap<>(); + if (claimConfig != null && MapUtils.isNotEmpty(claimConfig.getClaimMap())) { + for (Map.Entry entry : claimConfig.getClaimMap().entrySet()) { + ClaimKey claimKey = entry.getKey(); + ClaimMapping claimMapping = entry.getValue(); + String claimDialectURI = claimKey.getDialectUri(); + org.wso2.carbon.identity.claim.metadata.mgt.model.Claim claim; + + if (LOCAL_CLAIM_DIALECT_URI.equals(claimDialectURI)) { + claim = createLocalClaim(claimKey, claimMapping, + filterClaimProperties(claimConfig.getPropertyHolderMap().get(claimKey))); + } else { + claim = createExternalClaim(claimKey, claimConfig.getPropertyHolderMap().get(claimKey)); + } + claims.computeIfAbsent(claimDialectURI, k -> new ArrayList<>()).add(claim); + } + } + return claims; + } + + public static Map filterClaimProperties(Map claimProperties) { + + claimProperties.remove(ClaimConstants.DIALECT_PROPERTY); + claimProperties.remove(ClaimConstants.CLAIM_URI_PROPERTY); + claimProperties.remove(ClaimConstants.ATTRIBUTE_ID_PROPERTY); + claimProperties.remove(ClaimConstants.IS_SYSTEM_CLAIM); + + claimProperties.putIfAbsent(ClaimConstants.DISPLAY_NAME_PROPERTY, "0"); + claimProperties.computeIfPresent(ClaimConstants.SUPPORTED_BY_DEFAULT_PROPERTY, + (k, v) -> StringUtils.isBlank(v) ? "true" : v); + claimProperties.computeIfPresent(ClaimConstants.READ_ONLY_PROPERTY, + (k, v) -> StringUtils.isBlank(v) ? "true" : v); + claimProperties.computeIfPresent(ClaimConstants.REQUIRED_PROPERTY, + (k, v) -> StringUtils.isBlank(v) ? "true" : v); + return claimProperties; + } + + private static LocalClaim createLocalClaim(ClaimKey claimKey, ClaimMapping claimMapping, + Map claimProperties) { + + String primaryDomainName = IdentityUtil.getPrimaryDomainName(); + List mappedAttributes = new ArrayList<>(); + if (StringUtils.isNotBlank(claimMapping.getMappedAttribute())) { + mappedAttributes + .add(new AttributeMapping(primaryDomainName, claimMapping.getMappedAttribute())); + } + + if (claimMapping.getMappedAttributes() != null) { + for (Map.Entry claimMappingEntry : claimMapping.getMappedAttributes() + .entrySet()) { + mappedAttributes.add(new AttributeMapping(claimMappingEntry.getKey(), + claimMappingEntry.getValue())); + } + } + return new LocalClaim(claimKey.getClaimUri(), mappedAttributes, claimProperties); + } + + private static ExternalClaim createExternalClaim(ClaimKey claimKey, Map claimProperties) { + + String mappedLocalClaimURI = claimProperties.get(ClaimConstants.MAPPED_LOCAL_CLAIM_PROPERTY); + Map filteredClaimProperties = filterClaimProperties(claimProperties); + return new ExternalClaim(claimKey.getDialectUri(), claimKey.getClaimUri(), + mappedLocalClaimURI, filteredClaimProperties); + } } diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/ClaimMetadataManagementServiceImplTest.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/ClaimMetadataManagementServiceImplTest.java index 20cfb950a9eb..4d851de6b99a 100644 --- a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/ClaimMetadataManagementServiceImplTest.java +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/ClaimMetadataManagementServiceImplTest.java @@ -20,16 +20,23 @@ import org.mockito.MockedStatic; import org.mockito.Mockito; +import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; -import org.wso2.carbon.identity.claim.metadata.mgt.dao.CacheBackedExternalClaimDAO; +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataClientException; import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; +import org.wso2.carbon.identity.claim.metadata.mgt.internal.IdentityClaimManagementServiceDataHolder; +import org.wso2.carbon.identity.claim.metadata.mgt.model.AttributeMapping; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ClaimDialect; import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim; import org.wso2.carbon.identity.common.testng.WithCarbonHome; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; +import org.wso2.carbon.identity.core.util.IdentityUtil; import java.util.ArrayList; import java.util.Collections; +import java.util.List; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; @@ -39,14 +46,20 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.testng.Assert.assertThrows; import static org.wso2.carbon.base.MultitenantConstants.SUPER_TENANT_DOMAIN_NAME; import static org.wso2.carbon.base.MultitenantConstants.SUPER_TENANT_ID; +import static org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants.LOCAL_CLAIM_DIALECT_URI; import static org.wso2.carbon.identity.testutil.Whitebox.setInternalState; @WithCarbonHome +@Test public class ClaimMetadataManagementServiceImplTest { - private static final String EXTERNAL_CLAIM_DIALECT_URI = "https://wso2.org"; + private static final String LOCAL_CLAIM_DIALECT = "http://wso2.org/claims"; + private static final String LOCAL_CLAIM_1 = "http://wso2.org/claims/username"; + private static final String LOCAL_CLAIM_2 = "http://wso2.org/claims/email"; + private static final String EXTERNAL_CLAIM_DIALECT_URI = "https://abc.org"; private static final String EXTERNAL_CLAIM_URI = "test"; private static final String MAPPED_LOCAL_CLAIM_URI = "http://wso2.org/claims/test"; @@ -54,66 +67,300 @@ public class ClaimMetadataManagementServiceImplTest { MAPPED_LOCAL_CLAIM_URI); private ClaimMetadataManagementService service; + private UnifiedClaimMetadataManager unifiedClaimMetadataManager; + private MockedStatic dataHolderStaticMock; + private MockedStatic identityUtilStaticMock; + private MockedStatic identityTenantUtil; + private MockedStatic claimMetadataEventPublisherProxy; + private IdentityClaimManagementServiceDataHolder dataHolder; @BeforeMethod - public void setup() { + public void setup() throws Exception { + + dataHolderStaticMock = mockStatic(IdentityClaimManagementServiceDataHolder.class); + identityUtilStaticMock = mockStatic(IdentityUtil.class); + dataHolder = mock(IdentityClaimManagementServiceDataHolder.class); + dataHolderStaticMock.when(IdentityClaimManagementServiceDataHolder::getInstance).thenReturn(dataHolder); + + unifiedClaimMetadataManager = Mockito.mock(UnifiedClaimMetadataManager.class); service = new ClaimMetadataManagementServiceImpl(); + setInternalState(service, "unifiedClaimMetadataManager", unifiedClaimMetadataManager); + + identityTenantUtil = mockStatic(IdentityTenantUtil.class); + claimMetadataEventPublisherProxy = mockStatic(ClaimMetadataEventPublisherProxy.class); + identityTenantUtil.when(() -> IdentityTenantUtil.getTenantId(anyString())).thenReturn(SUPER_TENANT_ID); + claimMetadataEventPublisherProxy.when(ClaimMetadataEventPublisherProxy::getInstance) + .thenReturn(mock(ClaimMetadataEventPublisherProxy.class)); } @Test public void testAddExternalClaim() throws Exception { - try (MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic claimMetadataEventPublisherProxy = - mockStatic(ClaimMetadataEventPublisherProxy.class)) { - identityTenantUtil.when(() -> IdentityTenantUtil.getTenantId(anyString())).thenReturn(SUPER_TENANT_ID); - claimMetadataEventPublisherProxy.when(ClaimMetadataEventPublisherProxy::getInstance) - .thenReturn(mock(ClaimMetadataEventPublisherProxy.class)); - CacheBackedExternalClaimDAO externalClaimDAO = Mockito.mock(CacheBackedExternalClaimDAO.class); - when(externalClaimDAO.getExternalClaims(anyString(), anyInt())).thenReturn(new ArrayList<>()); - setInternalState(service, "externalClaimDAO", externalClaimDAO); + when(unifiedClaimMetadataManager.getExternalClaims(anyString(), anyInt())).thenReturn(new ArrayList<>()); + List claimDialects = new ArrayList<>(); + claimDialects.add(new ClaimDialect(EXTERNAL_CLAIM_DIALECT_URI)); + when(unifiedClaimMetadataManager.getClaimDialects(anyInt())).thenReturn(claimDialects); + when(unifiedClaimMetadataManager.getLocalClaims(anyInt())) + .thenReturn(Collections.singletonList(new LocalClaim(MAPPED_LOCAL_CLAIM_URI))); + + service.addExternalClaim(externalClaim, SUPER_TENANT_DOMAIN_NAME); + verify(unifiedClaimMetadataManager, times(1)).addExternalClaim(any(), anyInt()); + + when(unifiedClaimMetadataManager.getExternalClaims(anyString(), anyInt())) + .thenReturn(Collections.singletonList(externalClaim)); + assertThrows(ClaimMetadataException.class, () -> { + service.addExternalClaim(externalClaim, SUPER_TENANT_DOMAIN_NAME); + }); + when(unifiedClaimMetadataManager.isLocalClaimMappedWithinDialect(MAPPED_LOCAL_CLAIM_URI, EXTERNAL_CLAIM_DIALECT_URI, + SUPER_TENANT_ID)).thenReturn(Boolean.TRUE); + assertThrows(ClaimMetadataException.class, () -> { service.addExternalClaim(externalClaim, SUPER_TENANT_DOMAIN_NAME); - verify(externalClaimDAO, times(1)).addExternalClaim(any(), anyInt()); - } + }); + + assertThrows(ClaimMetadataClientException.class, () -> { + service.addExternalClaim(null, SUPER_TENANT_DOMAIN_NAME); + }); } @Test(expectedExceptions = ClaimMetadataException.class) public void testAddExistingExternalClaim() throws Exception { - try (MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic claimMetadataEventPublisherProxy = - mockStatic(ClaimMetadataEventPublisherProxy.class)) { - identityTenantUtil.when(() -> IdentityTenantUtil.getTenantId(anyString())).thenReturn(SUPER_TENANT_ID); - claimMetadataEventPublisherProxy.when(ClaimMetadataEventPublisherProxy::getInstance) - .thenReturn(mock(ClaimMetadataEventPublisherProxy.class)); - CacheBackedExternalClaimDAO externalClaimDAO = Mockito.mock(CacheBackedExternalClaimDAO.class); - when(externalClaimDAO.getExternalClaims(anyString(), anyInt())) - .thenReturn(Collections.singletonList(externalClaim)); - setInternalState(service, "externalClaimDAO", externalClaimDAO); + when(unifiedClaimMetadataManager.getExternalClaims(anyString(), anyInt())) + .thenReturn(Collections.singletonList(externalClaim)); - service.addExternalClaim(externalClaim, SUPER_TENANT_DOMAIN_NAME); - } + service.addExternalClaim(externalClaim, SUPER_TENANT_DOMAIN_NAME); } @Test(expectedExceptions = ClaimMetadataException.class) public void testAddExtClaimWithExistingLocalClaimMapping() throws Exception { - try (MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); - MockedStatic claimMetadataEventPublisherProxy = - mockStatic(ClaimMetadataEventPublisherProxy.class)) { - identityTenantUtil.when(() -> IdentityTenantUtil.getTenantId(anyString())).thenReturn(SUPER_TENANT_ID); - claimMetadataEventPublisherProxy.when(ClaimMetadataEventPublisherProxy::getInstance) - .thenReturn(mock(ClaimMetadataEventPublisherProxy.class)); - CacheBackedExternalClaimDAO externalClaimDAO = Mockito.mock(CacheBackedExternalClaimDAO.class); - when(externalClaimDAO.getExternalClaims(anyString(), anyInt())) - .thenReturn(Collections.singletonList(externalClaim)); - when(externalClaimDAO.isLocalClaimMappedWithinDialect(MAPPED_LOCAL_CLAIM_URI, EXTERNAL_CLAIM_DIALECT_URI, - SUPER_TENANT_ID)).thenReturn(Boolean.TRUE); - setInternalState(service, "externalClaimDAO", externalClaimDAO); + when(unifiedClaimMetadataManager.getExternalClaims(anyString(), anyInt())) + .thenReturn(Collections.singletonList(externalClaim)); + when(unifiedClaimMetadataManager.isLocalClaimMappedWithinDialect(MAPPED_LOCAL_CLAIM_URI, EXTERNAL_CLAIM_DIALECT_URI, + SUPER_TENANT_ID)).thenReturn(Boolean.TRUE); - service.addExternalClaim(externalClaim, SUPER_TENANT_DOMAIN_NAME); - } + service.addExternalClaim(externalClaim, SUPER_TENANT_DOMAIN_NAME); + } + + @Test + public void testGetClaimDialects() throws Exception { + + when(unifiedClaimMetadataManager.getExternalClaims(anyString(), anyInt())).thenReturn(new ArrayList<>()); + List claimDialects = new ArrayList<>(); + claimDialects.add(new ClaimDialect(EXTERNAL_CLAIM_DIALECT_URI)); + when(unifiedClaimMetadataManager.getClaimDialects(anyInt())).thenReturn(claimDialects); + + service.getClaimDialects(SUPER_TENANT_DOMAIN_NAME); + verify(unifiedClaimMetadataManager, times(1)).getClaimDialects(anyInt()); + } + + @Test + public void testAddClaimDialect() throws ClaimMetadataException { + + ClaimDialect claimDialectToBeAdded = new ClaimDialect(EXTERNAL_CLAIM_DIALECT_URI); + when(unifiedClaimMetadataManager.getClaimDialects(anyInt())).thenReturn(new ArrayList<>()); + service.addClaimDialect(claimDialectToBeAdded, SUPER_TENANT_DOMAIN_NAME); + verify(unifiedClaimMetadataManager, times(1)).addClaimDialect(any(), anyInt()); + + when(unifiedClaimMetadataManager.getClaimDialects(anyInt())) + .thenReturn(Collections.singletonList(claimDialectToBeAdded)); + assertThrows(ClaimMetadataException.class, () -> { + service.addClaimDialect(claimDialectToBeAdded, SUPER_TENANT_DOMAIN_NAME); + }); + + assertThrows(ClaimMetadataClientException.class, () -> { + service.addClaimDialect(null, SUPER_TENANT_DOMAIN_NAME); + }); + } + + @Test + public void testRenameClaimDialect() throws ClaimMetadataException { + + ClaimDialect newClaimDialect = new ClaimDialect(EXTERNAL_CLAIM_DIALECT_URI); + ClaimDialect oldClaimDialect = new ClaimDialect(LOCAL_CLAIM_DIALECT_URI); + service.renameClaimDialect(oldClaimDialect, newClaimDialect, SUPER_TENANT_DOMAIN_NAME); + verify(unifiedClaimMetadataManager, times(1)).renameClaimDialect(any(), any(), anyInt()); + } + + @Test + public void testRemoveClaimDialect() throws ClaimMetadataException { + + ClaimDialect claimDialectToBeDeleted = new ClaimDialect(EXTERNAL_CLAIM_DIALECT_URI); + service.removeClaimDialect(claimDialectToBeDeleted, SUPER_TENANT_DOMAIN_NAME); + verify(unifiedClaimMetadataManager, times(1)).removeClaimDialect(any(), anyInt()); + } + + @Test + public void testGetLocalClaims() throws ClaimMetadataException { + + service.getLocalClaims(SUPER_TENANT_DOMAIN_NAME); + verify(unifiedClaimMetadataManager, times(1)).getLocalClaims(anyInt()); + } + + @Test + public void testAddLocalClaim() throws ClaimMetadataException { + + LocalClaim localClaimToBeAdded = new LocalClaim(LOCAL_CLAIM_1); + localClaimToBeAdded.setMappedAttributes(new ArrayList<>()); + localClaimToBeAdded.getMappedAttributes() + .add(new AttributeMapping("PRIMARY", "username")); + when(unifiedClaimMetadataManager.getLocalClaims(anyInt())).thenReturn(new ArrayList<>()); + service.addLocalClaim(localClaimToBeAdded, SUPER_TENANT_DOMAIN_NAME); + verify(unifiedClaimMetadataManager, times(1)).addLocalClaim(any(), anyInt()); + + when(unifiedClaimMetadataManager.getLocalClaims(anyInt())) + .thenReturn(Collections.singletonList(localClaimToBeAdded)); + assertThrows(ClaimMetadataClientException.class, () -> { + service.addLocalClaim(localClaimToBeAdded, SUPER_TENANT_DOMAIN_NAME); + }); + } + + @Test + public void testUpdateLocalClaim() throws ClaimMetadataException { + + LocalClaim localClaimToBeUpdated = new LocalClaim(LOCAL_CLAIM_1); + localClaimToBeUpdated.setMappedAttributes(new ArrayList<>()); + localClaimToBeUpdated.getMappedAttributes() + .add(new AttributeMapping("PRIMARY", "user_name")); + + LocalClaim existingLocalClaim = new LocalClaim(LOCAL_CLAIM_1); + existingLocalClaim.setMappedAttributes(new ArrayList<>()); + existingLocalClaim.getMappedAttributes() + .add(new AttributeMapping("PRIMARY", "username")); + + when(unifiedClaimMetadataManager.getLocalClaims(SUPER_TENANT_ID)) + .thenReturn(Collections.singletonList(existingLocalClaim)); + service.updateLocalClaim(localClaimToBeUpdated, SUPER_TENANT_DOMAIN_NAME); + verify(unifiedClaimMetadataManager, times(1)).updateLocalClaim(any(), anyInt()); + + when(unifiedClaimMetadataManager.getLocalClaims(SUPER_TENANT_ID)).thenReturn(new ArrayList<>()); + assertThrows(ClaimMetadataClientException.class, () -> { + service.updateLocalClaim(localClaimToBeUpdated, SUPER_TENANT_DOMAIN_NAME); + }); + } + + @Test + public void testUpdateLocalClaimMappings() throws ClaimMetadataException { + + LocalClaim localClaimToBeUpdated = new LocalClaim(LOCAL_CLAIM_1); + localClaimToBeUpdated.setMappedAttributes(new ArrayList<>()); + localClaimToBeUpdated.getMappedAttributes() + .add(new AttributeMapping("PRIMARY", "user_name")); + List localClaimsList = new ArrayList<>(); + localClaimsList.add(localClaimToBeUpdated); + + service.updateLocalClaimMappings(localClaimsList, SUPER_TENANT_DOMAIN_NAME, "PRIMARY"); + verify(unifiedClaimMetadataManager, times(1)) + .updateLocalClaimMappings(any(), anyInt(), anyString()); + } + + @Test + public void testRemoveLocalClaim() throws ClaimMetadataException { + + String localClaimURIToBeRemoved = LOCAL_CLAIM_1; + service.removeLocalClaim(localClaimURIToBeRemoved, SUPER_TENANT_DOMAIN_NAME); + verify(unifiedClaimMetadataManager, times(1)).removeLocalClaim(anyString(), anyInt()); + + when(unifiedClaimMetadataManager.isMappedLocalClaim(LOCAL_CLAIM_1, SUPER_TENANT_ID)).thenReturn(true); + assertThrows(ClaimMetadataClientException.class, () -> { + service.removeLocalClaim(localClaimURIToBeRemoved, SUPER_TENANT_DOMAIN_NAME); + }); } + @Test + public void testGetExternalClaims() throws ClaimMetadataException { + + service.getExternalClaims(EXTERNAL_CLAIM_DIALECT_URI, SUPER_TENANT_DOMAIN_NAME); + verify(unifiedClaimMetadataManager, times(1)).getExternalClaims(anyString(), anyInt()); + + assertThrows(ClaimMetadataClientException.class, () -> { + service.getExternalClaims(null, SUPER_TENANT_DOMAIN_NAME); + }); + + assertThrows(ClaimMetadataClientException.class, () -> { + service.getExternalClaims(LOCAL_CLAIM_DIALECT, null); + }); + } + + @Test + public void testUpdateExternalClaim() throws ClaimMetadataException { + + ClaimDialect externalDialect = new ClaimDialect(EXTERNAL_CLAIM_DIALECT_URI); + ExternalClaim externalClaim = new ExternalClaim(EXTERNAL_CLAIM_DIALECT_URI, EXTERNAL_CLAIM_URI, LOCAL_CLAIM_1); + when(unifiedClaimMetadataManager.getClaimDialects(SUPER_TENANT_ID)) + .thenReturn(Collections.singletonList(externalDialect)); + when(unifiedClaimMetadataManager.getExternalClaims(EXTERNAL_CLAIM_DIALECT_URI, SUPER_TENANT_ID)) + .thenReturn(Collections.singletonList(externalClaim)); + when(unifiedClaimMetadataManager.getLocalClaims(SUPER_TENANT_ID)) + .thenReturn(Collections.singletonList(new LocalClaim(LOCAL_CLAIM_1))); + service.updateExternalClaim(externalClaim, SUPER_TENANT_DOMAIN_NAME); + verify(unifiedClaimMetadataManager, times(1)).updateExternalClaim(externalClaim, SUPER_TENANT_ID); + + when(unifiedClaimMetadataManager.getExternalClaims(EXTERNAL_CLAIM_DIALECT_URI, SUPER_TENANT_ID)) + .thenReturn(Collections.emptyList()); + assertThrows(ClaimMetadataClientException.class, () -> { + service.updateExternalClaim(externalClaim, SUPER_TENANT_DOMAIN_NAME); + }); + + when(unifiedClaimMetadataManager.getClaimDialects(SUPER_TENANT_ID)) + .thenReturn(Collections.emptyList()); + assertThrows(ClaimMetadataClientException.class, () -> { + service.updateExternalClaim(externalClaim, SUPER_TENANT_DOMAIN_NAME); + }); + } + + @Test + public void testRemoveExternalClaim() throws ClaimMetadataException { + + service.removeExternalClaim(EXTERNAL_CLAIM_DIALECT_URI, EXTERNAL_CLAIM_URI, SUPER_TENANT_DOMAIN_NAME); + verify(unifiedClaimMetadataManager, times(1)) + .removeExternalClaim(EXTERNAL_CLAIM_DIALECT_URI, EXTERNAL_CLAIM_URI, SUPER_TENANT_ID); + + assertThrows(ClaimMetadataClientException.class, () -> { + service.removeExternalClaim(null, EXTERNAL_CLAIM_URI, SUPER_TENANT_DOMAIN_NAME); + }); + assertThrows(ClaimMetadataClientException.class, () -> { + service.removeExternalClaim(EXTERNAL_CLAIM_DIALECT_URI, null, SUPER_TENANT_DOMAIN_NAME); + }); + assertThrows(ClaimMetadataClientException.class, () -> { + service.removeExternalClaim(LOCAL_CLAIM_DIALECT, LOCAL_CLAIM_1, SUPER_TENANT_DOMAIN_NAME); + }); + } + + @Test + public void testRemoveClaimMappingAttributes() throws ClaimMetadataException { + + String testUserStoreDomain = "TEST_DOMAIN"; + service.removeClaimMappingAttributes(SUPER_TENANT_ID, testUserStoreDomain); + verify(unifiedClaimMetadataManager, times(1)) + .removeClaimMappingAttributes(SUPER_TENANT_ID, testUserStoreDomain); + + assertThrows(ClaimMetadataClientException.class, () -> { + service.removeClaimMappingAttributes(SUPER_TENANT_ID, null); + }); + } + + @Test + public void testRemoveAllClaims() throws ClaimMetadataException { + + service.removeAllClaims(SUPER_TENANT_ID); + verify(unifiedClaimMetadataManager, times(1)).removeAllClaimDialects(SUPER_TENANT_ID); + } + + @Test + public void testGetMappedExternalClaimsForLocalClaim() throws ClaimMetadataException { + + service.getMappedExternalClaimsForLocalClaim(LOCAL_CLAIM_1, SUPER_TENANT_DOMAIN_NAME); + verify(unifiedClaimMetadataManager, times(1)).getMappedExternalClaims(LOCAL_CLAIM_1, SUPER_TENANT_ID); + } + + @AfterMethod + public void tearDown() { + + dataHolderStaticMock.close(); + identityUtilStaticMock.close(); + identityTenantUtil.close(); + claimMetadataEventPublisherProxy.close(); + } } diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/DBBasedClaimMetadataManagerTest.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/DBBasedClaimMetadataManagerTest.java new file mode 100644 index 000000000000..66d7229d485a --- /dev/null +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/DBBasedClaimMetadataManagerTest.java @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.claim.metadata.mgt; + +import org.mockito.Mockito; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.claim.metadata.mgt.dao.CacheBackedClaimDialectDAO; +import org.wso2.carbon.identity.claim.metadata.mgt.dao.CacheBackedExternalClaimDAO; +import org.wso2.carbon.identity.claim.metadata.mgt.dao.CacheBackedLocalClaimDAO; +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataServerException; +import org.wso2.carbon.identity.claim.metadata.mgt.model.Claim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ClaimDialect; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim; +import org.wso2.carbon.identity.common.testng.WithCarbonHome; +import org.wso2.carbon.user.api.UserStoreException; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.assertTrue; + +@WithCarbonHome +@Test +public class DBBasedClaimMetadataManagerTest { + + private DBBasedClaimMetadataManager claimMetadataManager; + private final CacheBackedClaimDialectDAO mockClaimDialectDAO = Mockito.mock(CacheBackedClaimDialectDAO.class); + private final CacheBackedLocalClaimDAO mockLocalClaimDAO = Mockito.mock(CacheBackedLocalClaimDAO.class); + private final CacheBackedExternalClaimDAO mockExternalClaimDAO = Mockito.mock(CacheBackedExternalClaimDAO.class); + private final String LOCAL_CLAIM_DIALECT = "http://wso2.org/claims"; + private final String EXT_CLAIM_DIALECT_1 = "http://abc.org"; + private final String EXT_CLAIM_DIALECT_2 = "http://def.org"; + private final String LOCAL_CLAIM_1 = "http://wso2.org/claims/username"; + private final String LOCAL_CLAIM_2 = "http://wso2.org/claims/email"; + private final String LOCAL_CLAIM_3 = "http://wso2.org/claims/country"; + private final String LOCAL_CLAIM_4 = "http://wso2.org/claims/identity/accountLocked"; + private final String LOCAL_CLAIM_5 = "http://wso2.org/claims/identity/emailVerified"; + private final String LOCAL_CLAIM_6 = "http://wso2.org/claims/identity/lastLoginTime"; + private final String EXT_CLAIM_DIALECT_1_CLAIM_1 = "http://abc.org/claim1"; + private final String EXT_CLAIM_DIALECT_1_CLAIM_2 = "http://abc.org/claim2"; + private final String EXT_CLAIM_DIALECT_1_CLAIM_3 = "http://abc.org/claim3"; + private final String EXT_CLAIM_DIALECT_2_CLAIM_1 = "http://def.org/claim1"; + private final String EXT_CLAIM_DIALECT_2_CLAIM_2 = "http://def.org/claim2"; + private final String NON_EXISTING_CLAIM_DIALECT_URI = "http://nonexisting.org"; + private final String TEST_USER_STORE_DOMAIN = "TEST_USER_STORE_DOMAIN"; + + @BeforeClass + public void setUp() throws Exception { + + claimMetadataManager = new DBBasedClaimMetadataManager(); + + setPrivateField(claimMetadataManager, "claimDialectDAO", mockClaimDialectDAO); + setPrivateField(claimMetadataManager, "localClaimDAO", mockLocalClaimDAO); + setPrivateField(claimMetadataManager, "externalClaimDAO", mockExternalClaimDAO); + } + + private void setPrivateField(Object target, String fieldName, Object value) throws Exception { + Field field = target.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(target, value); + } + + @Test + public void testGetClaimDialects() throws ClaimMetadataException { + + List claimDialects = new ArrayList<>(); + claimDialects.add(new ClaimDialect(LOCAL_CLAIM_DIALECT)); + claimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_1)); + claimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_2)); + when(mockClaimDialectDAO.getClaimDialects(anyInt())).thenReturn(claimDialects); + + List returnedClaimDialects = claimMetadataManager.getClaimDialects(1); + List claimDialectURIs = returnedClaimDialects.stream() + .map(ClaimDialect::getClaimDialectURI) + .collect(Collectors.toList()); + assertNotNull(returnedClaimDialects); + assertEquals(returnedClaimDialects.size(), 3); + assertTrue(claimDialectURIs.contains(LOCAL_CLAIM_DIALECT)); + assertTrue(claimDialectURIs.contains(EXT_CLAIM_DIALECT_1)); + assertTrue(claimDialectURIs.contains(EXT_CLAIM_DIALECT_2)); + } + + @Test + public void testGetClaimDialect() throws ClaimMetadataException { + + List claimDialects = new ArrayList<>(); + claimDialects.add(new ClaimDialect(LOCAL_CLAIM_DIALECT)); + claimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_1)); + claimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_2)); + when(mockClaimDialectDAO.getClaimDialects(anyInt())).thenReturn(claimDialects); + + Optional returnedClaimDialect = claimMetadataManager.getClaimDialect(EXT_CLAIM_DIALECT_2, 1); + assertTrue(returnedClaimDialect.isPresent()); + assertEquals(returnedClaimDialect.get().getClaimDialectURI(), EXT_CLAIM_DIALECT_2); + + returnedClaimDialect = claimMetadataManager.getClaimDialect(NON_EXISTING_CLAIM_DIALECT_URI, 1); + assertFalse(returnedClaimDialect.isPresent()); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getClaimDialect(null, 1); + }); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getClaimDialect("", 1); + }); + } + + @Test + public void testAddClaimDialect() throws ClaimMetadataException { + + ClaimDialect newClaimDialect = new ClaimDialect(EXT_CLAIM_DIALECT_1); + claimMetadataManager.addClaimDialect(newClaimDialect, 1); + verify(mockClaimDialectDAO, times(1)).addClaimDialect(newClaimDialect, 1); + } + + @Test + public void testRemoveClaimDialect() throws ClaimMetadataException { + + ClaimDialect claimDialect = new ClaimDialect(EXT_CLAIM_DIALECT_1); + claimMetadataManager.removeClaimDialect(claimDialect, 1); + verify(mockClaimDialectDAO, times(1)).removeClaimDialect(claimDialect, 1); + verify(mockExternalClaimDAO, times(1)).removeExternalClaimCache(EXT_CLAIM_DIALECT_1, 1); + } + + @Test + public void testGetLocalClaims() throws ClaimMetadataException { + + List localClaims = new ArrayList<>(); + localClaims.add(new LocalClaim(LOCAL_CLAIM_1)); + localClaims.add(new LocalClaim(LOCAL_CLAIM_2)); + when(mockLocalClaimDAO.getLocalClaims(anyInt())).thenReturn(localClaims); + + List returnedLocalClaims = claimMetadataManager.getLocalClaims(1); + List localClaimURIs = returnedLocalClaims.stream() + .map(LocalClaim::getClaimURI) + .collect(Collectors.toList()); + assertNotNull(returnedLocalClaims); + assertEquals(returnedLocalClaims.size(), 2); + assertTrue(localClaimURIs.contains(LOCAL_CLAIM_1)); + assertTrue(localClaimURIs.contains(LOCAL_CLAIM_2)); + } + + @Test + public void testGetLocalClaim() throws ClaimMetadataException { + + List claimDialects = new ArrayList<>(); + claimDialects.add(new ClaimDialect(LOCAL_CLAIM_DIALECT)); + when(mockClaimDialectDAO.getClaimDialects(anyInt())).thenReturn(claimDialects); + + List localClaims = new ArrayList<>(); + localClaims.add(new LocalClaim(LOCAL_CLAIM_1)); + localClaims.add(new LocalClaim(LOCAL_CLAIM_2)); + localClaims.add(new LocalClaim(LOCAL_CLAIM_3)); + when(mockLocalClaimDAO.getLocalClaims(anyInt())).thenReturn(localClaims); + + Optional returnedLocalClaim = claimMetadataManager.getLocalClaim(LOCAL_CLAIM_1, 1); + assertTrue(returnedLocalClaim.isPresent()); + assertEquals(returnedLocalClaim.get().getClaimURI(), LOCAL_CLAIM_1); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getLocalClaim(null, 1); + }); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getLocalClaim("", 1); + }); + + returnedLocalClaim = claimMetadataManager.getLocalClaim(LOCAL_CLAIM_4, 1); + assertFalse(returnedLocalClaim.isPresent()); + } + + @Test + public void testGetExternalClaims() throws ClaimMetadataException { + + List externalClaims = new ArrayList<>(); + externalClaims.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1)); + externalClaims.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_2, LOCAL_CLAIM_2)); + externalClaims.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_3, LOCAL_CLAIM_3)); + when(mockExternalClaimDAO.getExternalClaims(EXT_CLAIM_DIALECT_1, 1)).thenReturn(externalClaims); + + List returnedExternalClaims = claimMetadataManager.getExternalClaims(EXT_CLAIM_DIALECT_1, 1); + List externalClaimURIs = returnedExternalClaims.stream() + .map(ExternalClaim::getClaimURI) + .collect(Collectors.toList()); + assertNotNull(returnedExternalClaims); + assertEquals(returnedExternalClaims.size(), 3); + assertTrue(externalClaimURIs.contains(EXT_CLAIM_DIALECT_1_CLAIM_1)); + assertTrue(externalClaimURIs.contains(EXT_CLAIM_DIALECT_1_CLAIM_2)); + assertTrue(externalClaimURIs.contains(EXT_CLAIM_DIALECT_1_CLAIM_3)); + } + + @Test + public void testGetExternalClaim() throws ClaimMetadataException { + + List externalClaims = new ArrayList<>(); + externalClaims.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1)); + externalClaims.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_2, LOCAL_CLAIM_2)); + externalClaims.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_3, LOCAL_CLAIM_3)); + when(mockExternalClaimDAO.getExternalClaims(EXT_CLAIM_DIALECT_1, 1)).thenReturn(externalClaims); + + Optional returnedExternalClaim = claimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, + EXT_CLAIM_DIALECT_1_CLAIM_2, 1); + assertTrue(returnedExternalClaim.isPresent()); + assertEquals(returnedExternalClaim.get().getClaimURI(), EXT_CLAIM_DIALECT_1_CLAIM_2); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, null, 1); + }); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, "", 1); + }); + } + + @Test + public void testAddLocalClaim() throws ClaimMetadataException { + + LocalClaim newLocalClaim = new LocalClaim(LOCAL_CLAIM_4); + claimMetadataManager.addLocalClaim(newLocalClaim, 1); + verify(mockLocalClaimDAO, times(1)).addLocalClaim(newLocalClaim, 1); + } + + @Test + public void testUpdateLocalClaim() throws ClaimMetadataException { + + LocalClaim updatedLocalClaim = new LocalClaim(LOCAL_CLAIM_5); + claimMetadataManager.updateLocalClaim(updatedLocalClaim, 1); + verify(mockLocalClaimDAO, times(1)).updateLocalClaim(updatedLocalClaim, 1); + } + + @Test + public void testUpdateLocalClaimMappings() throws ClaimMetadataException { + + List updatedLocalClaims = new ArrayList<>(); + updatedLocalClaims.add(new LocalClaim(LOCAL_CLAIM_6)); + claimMetadataManager.updateLocalClaimMappings(updatedLocalClaims, 1, TEST_USER_STORE_DOMAIN); + verify(mockLocalClaimDAO, times(1)).updateLocalClaimMappings(updatedLocalClaims, 1, TEST_USER_STORE_DOMAIN); + } + + @Test + public void testRemoveLocalClaim() throws ClaimMetadataException { + + LocalClaim localClaim = new LocalClaim(LOCAL_CLAIM_4); + claimMetadataManager.removeLocalClaim(localClaim.getClaimURI(), 1); + verify(mockLocalClaimDAO, times(1)).removeLocalClaim(localClaim.getClaimURI(), 1); + } + + @Test + public void testRemoveClaimMappingAttributes() throws ClaimMetadataException, UserStoreException { + + claimMetadataManager.removeClaimMappingAttributes(1, TEST_USER_STORE_DOMAIN); + verify(mockLocalClaimDAO, times(1)).removeClaimMappingAttributes(1, TEST_USER_STORE_DOMAIN); + + doThrow(new UserStoreException("User store error")).when(mockLocalClaimDAO) + .removeClaimMappingAttributes(1, TEST_USER_STORE_DOMAIN); + assertThrows(ClaimMetadataServerException.class, () -> { + claimMetadataManager.removeClaimMappingAttributes(1, TEST_USER_STORE_DOMAIN); + }); + } + + @Test + public void testAddExternalClaim() throws ClaimMetadataException { + + ExternalClaim externalClaim = new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1); + claimMetadataManager.addExternalClaim(externalClaim, 1); + verify(mockExternalClaimDAO, times(1)).addExternalClaim(externalClaim, 1); + } + + @Test + public void testUpdateExternalClaim() throws ClaimMetadataException { + + ExternalClaim updatedExternalClaim = new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_2, LOCAL_CLAIM_4); + claimMetadataManager.updateExternalClaim(updatedExternalClaim, 1); + verify(mockExternalClaimDAO, times(1)).updateExternalClaim(updatedExternalClaim, 1); + } + + @Test + public void testRemoveExternalClaim() throws ClaimMetadataException { + + claimMetadataManager.removeExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1); + verify(mockExternalClaimDAO, times(1)) + .removeExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1); + } + + @Test + public void testGetMappedExternalClaims() throws ClaimMetadataException { + + List externalClaims = new ArrayList<>(); + externalClaims.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1)); + externalClaims.add(new ExternalClaim(EXT_CLAIM_DIALECT_2, EXT_CLAIM_DIALECT_2_CLAIM_2, LOCAL_CLAIM_1)); + when(mockLocalClaimDAO.fetchMappedExternalClaims(LOCAL_CLAIM_1, 1)).thenReturn(externalClaims); + + List returnedExternalClaims = claimMetadataManager.getMappedExternalClaims(LOCAL_CLAIM_1, 1); + List externalClaimURIs = returnedExternalClaims.stream() + .map(Claim::getClaimURI) + .collect(Collectors.toList()); + assertNotNull(returnedExternalClaims); + assertEquals(returnedExternalClaims.size(), 2); + assertTrue(externalClaimURIs.contains(EXT_CLAIM_DIALECT_1_CLAIM_1)); + assertTrue(externalClaimURIs.contains(EXT_CLAIM_DIALECT_2_CLAIM_2)); + } + + @Test + public void testRenameClaimDialect() throws ClaimMetadataException { + + ClaimDialect oldClaimDialect = new ClaimDialect(EXT_CLAIM_DIALECT_1); + ClaimDialect newClaimDialect = new ClaimDialect(EXT_CLAIM_DIALECT_2); + + clearInvocations(mockExternalClaimDAO, mockClaimDialectDAO); + claimMetadataManager.renameClaimDialect(oldClaimDialect, newClaimDialect, 1); + verify(mockClaimDialectDAO, times(1)).renameClaimDialect(oldClaimDialect, newClaimDialect, 1); + verify(mockExternalClaimDAO, times(1)).removeExternalClaimCache(EXT_CLAIM_DIALECT_1, 1); + } + + @Test + public void testRemoveAllClaimDialects() throws ClaimMetadataException { + + claimMetadataManager.removeAllClaimDialects(1); + verify(mockClaimDialectDAO, times(1)).removeAllClaimDialects(1); + } + + @Test + public void testIsMappedLocalClaim() throws ClaimMetadataException { + + when(mockExternalClaimDAO.isMappedLocalClaim(LOCAL_CLAIM_1, 1)).thenReturn(true); + assertTrue(claimMetadataManager.isMappedLocalClaim(LOCAL_CLAIM_1, 1)); + } + + @Test + public void testIsLocalClaimMappedWithinDialect() throws ClaimMetadataException { + + when(mockExternalClaimDAO.isLocalClaimMappedWithinDialect(LOCAL_CLAIM_1, EXT_CLAIM_DIALECT_1, 1)).thenReturn(true); + assertTrue(claimMetadataManager.isLocalClaimMappedWithinDialect(LOCAL_CLAIM_1, EXT_CLAIM_DIALECT_1, 1)); + } +} diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/SystemDefaultClaimMetadataManagerTest.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/SystemDefaultClaimMetadataManagerTest.java new file mode 100644 index 000000000000..36958be09e0a --- /dev/null +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/SystemDefaultClaimMetadataManagerTest.java @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.claim.metadata.mgt; + +import org.mockito.MockedStatic; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; +import org.wso2.carbon.identity.claim.metadata.mgt.internal.IdentityClaimManagementServiceDataHolder; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ClaimDialect; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants; +import org.wso2.carbon.identity.core.util.IdentityUtil; +import org.wso2.carbon.user.core.claim.Claim; +import org.wso2.carbon.user.core.claim.ClaimKey; +import org.wso2.carbon.user.core.claim.ClaimMapping; +import org.wso2.carbon.user.core.claim.inmemory.ClaimConfig; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.assertTrue; + +@Test +public class SystemDefaultClaimMetadataManagerTest { + + private SystemDefaultClaimMetadataManager claimMetadataManager; + private MockedStatic dataHolderStaticMock; + private MockedStatic identityUtilStaticMock; + private final String LOCAL_CLAIM_DIALECT = "http://wso2.org/claims"; + private final String LOCAL_CLAIM_1 = "http://wso2.org/claims/username"; + private final String LOCAL_CLAIM_2 = "http://wso2.org/claims/email"; + private final String LOCAL_CLAIM_3 = "http://wso2.org/claims/country"; + private final String LOCAL_CLAIM_4 = "http://wso2.org/claims/identity/accountLocked"; + private final String LOCAL_CLAIM_5 = "http://wso2.org/claims/identity/emailVerified"; + private final String LOCAL_CLAIM_6 = "http://wso2.org/claims/identity/lastLoginTime"; + private final String EXT_CLAIM_DIALECT_1 = "http://abc.org"; + private final String EXT_CLAIM_DIALECT_1_CLAIM_1 = "http://abc.org/claim1"; + private final String EXT_CLAIM_DIALECT_1_CLAIM_2 = "http://abc.org/claim2"; + private final String EXT_CLAIM_DIALECT_1_CLAIM_3 = "http://abc.org/claim3"; + private final String EXT_CLAIM_DIALECT_1_CLAIM_4 = "http://abc.org/claim4"; + private final String EXT_CLAIM_DIALECT_1_CLAIM_5 = "http://abc.org/claim5"; + private final String EXT_CLAIM_DIALECT_2 = "http://def.org"; + private final String EXT_CLAIM_DIALECT_2_CLAIM_1 = "http://def.org/claim1"; + private final String EXT_CLAIM_DIALECT_2_CLAIM_2 = "http://def.org/claim2"; + private final String EXT_CLAIM_DIALECT_2_CLAIM_3 = "http://def.org/claim3"; + private final String NON_EXISTING_CLAIM_DIALECT_URI = "http://nonexisting.org"; + private final String PRIMARY_DOMAIN = "PRIMARY"; + + @BeforeClass + public void setUp() { + + dataHolderStaticMock = mockStatic(IdentityClaimManagementServiceDataHolder.class); + identityUtilStaticMock = mockStatic(IdentityUtil.class); + + IdentityClaimManagementServiceDataHolder dataHolder = mock(IdentityClaimManagementServiceDataHolder.class); + + dataHolderStaticMock.when(IdentityClaimManagementServiceDataHolder::getInstance).thenReturn(dataHolder); + when(dataHolder.getClaimConfig()).thenReturn(getClaimConfigWithDummyData()); + identityUtilStaticMock.when(IdentityUtil::getPrimaryDomainName).thenReturn(PRIMARY_DOMAIN); + claimMetadataManager = new SystemDefaultClaimMetadataManager(); + } + + @Test + public void testGetClaimDialects() throws ClaimMetadataException { + List claimDialects = claimMetadataManager.getClaimDialects(1); + List dialectURIs = claimDialects.stream() + .map(ClaimDialect::getClaimDialectURI) + .collect(Collectors.toList()); + + assertNotNull(claimDialects); + assertEquals(claimDialects.size(), 3); + assertTrue(dialectURIs.contains(ClaimConstants.LOCAL_CLAIM_DIALECT_URI)); + assertTrue(dialectURIs.contains(EXT_CLAIM_DIALECT_1)); + assertTrue(dialectURIs.contains(EXT_CLAIM_DIALECT_2)); + } + + @Test + public void testGetClaimDialect() throws ClaimMetadataException { + String claimDialectURI = LOCAL_CLAIM_DIALECT; + Optional claimDialect = claimMetadataManager.getClaimDialect(claimDialectURI, 1); + assertTrue(claimDialect.isPresent()); + assertEquals(claimDialectURI, claimDialect.get().getClaimDialectURI()); + + Optional nonExistingClaimDialect = claimMetadataManager.getClaimDialect(NON_EXISTING_CLAIM_DIALECT_URI, 1); + assertFalse(nonExistingClaimDialect.isPresent()); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getClaimDialect(null, 1); + }); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getClaimDialect("", 1); + }); + } + + @Test + public void testGetLocalClaims() throws ClaimMetadataException { + + List claims = claimMetadataManager.getLocalClaims(1); + List claimURIs = claims.stream() + .map(LocalClaim::getClaimURI) + .collect(Collectors.toList()); + assertNotNull(claims); + assertEquals(claims.size(), 6); + assertTrue(claimURIs.contains(LOCAL_CLAIM_1)); + assertTrue(claimURIs.contains(LOCAL_CLAIM_2)); + assertTrue(claimURIs.contains(LOCAL_CLAIM_3)); + assertTrue(claimURIs.contains(LOCAL_CLAIM_4)); + assertTrue(claimURIs.contains(LOCAL_CLAIM_5)); + assertTrue(claimURIs.contains(LOCAL_CLAIM_6)); + } + + @Test void getLocalClaim() throws ClaimMetadataException { + + Optional claim = claimMetadataManager.getLocalClaim(LOCAL_CLAIM_1, 1); + assertTrue(claim.isPresent()); + assertEquals(LOCAL_CLAIM_1, claim.get().getClaimURI()); + + Optional nonExistingClaim = claimMetadataManager.getLocalClaim(NON_EXISTING_CLAIM_DIALECT_URI, 1); + assertFalse(nonExistingClaim.isPresent()); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getLocalClaim(null, 1); + }); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getLocalClaim("", 1); + }); + } + + @Test + public void getExternalClaims() throws ClaimMetadataException { + + List externalClaims = claimMetadataManager.getExternalClaims(EXT_CLAIM_DIALECT_1, 1); + List externalClaimURIs = externalClaims.stream() + .map(ExternalClaim::getClaimURI) + .collect(Collectors.toList()); + + assertNotNull(externalClaims); + assertEquals(externalClaims.size(), 5); + assertTrue(externalClaimURIs.contains(EXT_CLAIM_DIALECT_1_CLAIM_1)); + assertTrue(externalClaimURIs.contains(EXT_CLAIM_DIALECT_1_CLAIM_2)); + assertTrue(externalClaimURIs.contains(EXT_CLAIM_DIALECT_1_CLAIM_3)); + assertTrue(externalClaimURIs.contains(EXT_CLAIM_DIALECT_1_CLAIM_4)); + assertTrue(externalClaimURIs.contains(EXT_CLAIM_DIALECT_1_CLAIM_5)); + + List externalClaimsForNonExistingDialect = claimMetadataManager.getExternalClaims( + NON_EXISTING_CLAIM_DIALECT_URI, 1); + assertNotNull(externalClaimsForNonExistingDialect); + assertEquals(externalClaimsForNonExistingDialect.size(), 0); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getExternalClaims(null, 1); + }); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getExternalClaims("", 1); + }); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getExternalClaims(LOCAL_CLAIM_DIALECT, 1); + }); + } + + @Test + public void getExternalClaim() throws ClaimMetadataException { + + Optional externalClaim = claimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, + EXT_CLAIM_DIALECT_1_CLAIM_1, 1); + assertTrue(externalClaim.isPresent()); + assertEquals(EXT_CLAIM_DIALECT_1_CLAIM_1, externalClaim.get().getClaimURI()); + + String nonExistingExternalClaimURI = "http://nonexisting.org/nonExistingClaim"; + Optional nonExistingExternalClaim = claimMetadataManager.getExternalClaim(NON_EXISTING_CLAIM_DIALECT_URI, + nonExistingExternalClaimURI, 1); + assertFalse(nonExistingExternalClaim.isPresent()); + + nonExistingExternalClaim = claimMetadataManager.getExternalClaim( + EXT_CLAIM_DIALECT_1, nonExistingExternalClaimURI, 1); + assertFalse(nonExistingExternalClaim.isPresent()); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getExternalClaim(LOCAL_CLAIM_DIALECT, LOCAL_CLAIM_1, 1); + }); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, null, 1); + }); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getExternalClaim(null, EXT_CLAIM_DIALECT_1_CLAIM_1, 1); + }); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, "", 1); + }); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getExternalClaim("", EXT_CLAIM_DIALECT_1_CLAIM_1, 1); + }); + } + + @Test + public void testGetMappedExternalClaims() throws ClaimMetadataException { + + List externalClaims = claimMetadataManager + .getMappedExternalClaims(LOCAL_CLAIM_2, 1); + List externalClaimURIs = externalClaims.stream() + .map(ExternalClaim.class::cast) + .map(ExternalClaim::getClaimURI) + .collect(Collectors.toList()); + assertNotNull(externalClaims); + assertEquals(externalClaims.size(), 2); + assertTrue(externalClaimURIs.contains(EXT_CLAIM_DIALECT_1_CLAIM_1)); + assertTrue(externalClaimURIs.contains(EXT_CLAIM_DIALECT_2_CLAIM_1)); + + externalClaims = claimMetadataManager.getMappedExternalClaims( + "http://wso2.org/claims/nonExistingClaim", 1); + assertNotNull(externalClaims); + assertEquals(externalClaims.size(), 0); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getMappedExternalClaims(null, 1); + }); + + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.getMappedExternalClaims("", 1); + }); + } + + @Test + public void testIsMappedLocalClaim() throws ClaimMetadataException { + + assertTrue(claimMetadataManager.isMappedLocalClaim(LOCAL_CLAIM_1, 1)); + assertFalse(claimMetadataManager.isMappedLocalClaim(LOCAL_CLAIM_6, 1)); + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.isMappedLocalClaim(null, 1); + }); + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.isMappedLocalClaim("", 1); + }); + } + + @Test + public void testIsLocalClaimMappedWithinDialect() throws ClaimMetadataException { + + assertTrue(claimMetadataManager.isLocalClaimMappedWithinDialect(LOCAL_CLAIM_1, EXT_CLAIM_DIALECT_1, 1)); + assertFalse(claimMetadataManager.isLocalClaimMappedWithinDialect(LOCAL_CLAIM_6, EXT_CLAIM_DIALECT_1, 1)); + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.isLocalClaimMappedWithinDialect(LOCAL_CLAIM_6, "", 1); + }); + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.isLocalClaimMappedWithinDialect(LOCAL_CLAIM_6, null, 1); + }); + assertFalse(claimMetadataManager.isLocalClaimMappedWithinDialect(LOCAL_CLAIM_6, NON_EXISTING_CLAIM_DIALECT_URI, 1)); + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.isLocalClaimMappedWithinDialect(null, EXT_CLAIM_DIALECT_1, 1); + }); + assertThrows(ClaimMetadataException.class, () -> { + claimMetadataManager.isLocalClaimMappedWithinDialect("", EXT_CLAIM_DIALECT_1, 1); + }); + } + + @AfterClass + public void tearDown() { + + dataHolderStaticMock.close(); + identityUtilStaticMock.close(); + } + + private ClaimConfig getClaimConfigWithDummyData() { + + ClaimConfig claimConfig = new ClaimConfig(); + Map claims = new HashMap<>(); + Map> propertyHolder = new HashMap<>(); + List claimKeys = Arrays.asList( + new ClaimKey(LOCAL_CLAIM_1, LOCAL_CLAIM_DIALECT), + new ClaimKey(LOCAL_CLAIM_2, LOCAL_CLAIM_DIALECT), + new ClaimKey(LOCAL_CLAIM_3, LOCAL_CLAIM_DIALECT), + new ClaimKey(LOCAL_CLAIM_4, LOCAL_CLAIM_DIALECT), + new ClaimKey(LOCAL_CLAIM_5, LOCAL_CLAIM_DIALECT), + new ClaimKey(LOCAL_CLAIM_6, LOCAL_CLAIM_DIALECT), + new ClaimKey(EXT_CLAIM_DIALECT_1_CLAIM_1, EXT_CLAIM_DIALECT_1), + new ClaimKey(EXT_CLAIM_DIALECT_1_CLAIM_2, EXT_CLAIM_DIALECT_1), + new ClaimKey(EXT_CLAIM_DIALECT_1_CLAIM_3, EXT_CLAIM_DIALECT_1), + new ClaimKey(EXT_CLAIM_DIALECT_1_CLAIM_4, EXT_CLAIM_DIALECT_1), + new ClaimKey(EXT_CLAIM_DIALECT_1_CLAIM_5, EXT_CLAIM_DIALECT_1), + new ClaimKey(EXT_CLAIM_DIALECT_2_CLAIM_1, EXT_CLAIM_DIALECT_2), + new ClaimKey(EXT_CLAIM_DIALECT_2_CLAIM_2, EXT_CLAIM_DIALECT_2), + new ClaimKey(EXT_CLAIM_DIALECT_2_CLAIM_3, EXT_CLAIM_DIALECT_2) + ); + List claimMappings = Arrays.asList( + new ClaimMapping(new Claim(), "username"), + new ClaimMapping(new Claim(), "email"), + new ClaimMapping(new Claim(), "country"), + new ClaimMapping(new Claim(), "accountLocked"), + new ClaimMapping(new Claim(), "emailVerified"), + new ClaimMapping(new Claim(), "lastLoginTime"), + new ClaimMapping(new Claim(), null), + new ClaimMapping(new Claim(), null), + new ClaimMapping(new Claim(), null), + new ClaimMapping(new Claim(), null), + new ClaimMapping(new Claim(), null), + new ClaimMapping(new Claim(), null), + new ClaimMapping(new Claim(), null), + new ClaimMapping(new Claim(), null) + ); + + for (int i = 0; i < claimKeys.size(); i++) { + Map properties = new HashMap<>(); + properties.put("property" + (i * 2 + 1), "value" + (i * 2 + 1)); + properties.put("property" + (i * 2 + 2), "value" + (i * 2 + 2)); + properties.put(ClaimConstants.MAPPED_LOCAL_CLAIM_PROPERTY, claimKeys.get(i%5).getClaimUri()); + propertyHolder.put(claimKeys.get(i), properties); + } + for (int i = 0; i < claimKeys.size(); i++) { + claims.put(claimKeys.get(i), claimMappings.get(i)); + } + claimConfig.setClaimMap(claims); + claimConfig.setPropertyHolderMap(propertyHolder); + return claimConfig; + } +} diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/UnifiedClaimMetadataManagerTest.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/UnifiedClaimMetadataManagerTest.java new file mode 100644 index 000000000000..e0907bb75d24 --- /dev/null +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/UnifiedClaimMetadataManagerTest.java @@ -0,0 +1,735 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.carbon.identity.claim.metadata.mgt; + +import org.mockito.MockedStatic; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataClientException; +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; +import org.wso2.carbon.identity.claim.metadata.mgt.internal.IdentityClaimManagementServiceDataHolder; +import org.wso2.carbon.identity.claim.metadata.mgt.model.AttributeMapping; +import org.wso2.carbon.identity.claim.metadata.mgt.model.Claim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ClaimDialect; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.model.LocalClaim; +import org.wso2.carbon.identity.claim.metadata.mgt.util.ClaimConstants; +import org.wso2.carbon.identity.common.testng.WithCarbonHome; +import org.wso2.carbon.identity.core.util.IdentityUtil; +import org.wso2.carbon.user.core.claim.inmemory.ClaimConfig; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.assertTrue; + +@WithCarbonHome +@Test +public class UnifiedClaimMetadataManagerTest { + + private UnifiedClaimMetadataManager claimMetadataManager; + private SystemDefaultClaimMetadataManager systemDefaultClaimMetadataManager; + private DBBasedClaimMetadataManager dbBasedClaimMetadataManager; + private MockedStatic dataHolderStaticMock; + private MockedStatic identityUtilStaticMock; + private final String LOCAL_CLAIM_DIALECT = "http://wso2.org/claims"; + private final String EXT_CLAIM_DIALECT_1 = "http://abc.org"; + private final String EXT_CLAIM_DIALECT_2 = "http://def.org"; + private final String NON_EXISTING_CLAIM_DIALECT = "http://nonexisting.org"; + private final String LOCAL_CLAIM_1 = "http://wso2.org/claims/username"; + private final String LOCAL_CLAIM_2 = "http://wso2.org/claims/email"; + private final String LOCAL_CLAIM_3 = "http://wso2.org/claims/country"; + private final String LOCAL_CLAIM_4 = "http://wso2.org/claims/identity/accountLocked"; + private final String EXT_CLAIM_DIALECT_1_CLAIM_1 = "http://abc.org/claim1"; + private final String EXT_CLAIM_DIALECT_1_CLAIM_2 = "http://abc.org/claim2"; + private final String EXT_CLAIM_DIALECT_1_CLAIM_3 = "http://abc.org/claim3"; + private final String EXT_CLAIM_DIALECT_2_CLAIM_1 = "http://def.org/claim1"; + private final String EXT_CLAIM_DIALECT_2_CLAIM_2 = "http://def.org/claim2"; + + @BeforeMethod + public void setUp() throws Exception { + + dataHolderStaticMock = mockStatic(IdentityClaimManagementServiceDataHolder.class); + identityUtilStaticMock = mockStatic(IdentityUtil.class); + IdentityClaimManagementServiceDataHolder dataHolder = mock(IdentityClaimManagementServiceDataHolder.class); + dataHolderStaticMock.when(IdentityClaimManagementServiceDataHolder::getInstance).thenReturn(dataHolder); + ClaimConfig claimConfig = new ClaimConfig(); + when(dataHolder.getClaimConfig()).thenReturn(claimConfig); + systemDefaultClaimMetadataManager = mock(SystemDefaultClaimMetadataManager.class); + dbBasedClaimMetadataManager = mock(DBBasedClaimMetadataManager.class); + + claimMetadataManager = new UnifiedClaimMetadataManager(); + setPrivateField(claimMetadataManager, "systemDefaultClaimMetadataManager", systemDefaultClaimMetadataManager); + setPrivateField(claimMetadataManager, "dbBasedClaimMetadataManager", dbBasedClaimMetadataManager); + } + + private void setPrivateField(Object target, String fieldName, Object value) throws Exception { + + Field field = target.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(target, value); + } + + @Test + public void testGetClaimDialects() throws ClaimMetadataException { + + List systemDefaultClaimDialects = new ArrayList<>(); + systemDefaultClaimDialects.add(new ClaimDialect(LOCAL_CLAIM_DIALECT)); + systemDefaultClaimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_1)); + systemDefaultClaimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_2)); + List dbClaimDialects = new ArrayList<>(); + when(systemDefaultClaimMetadataManager.getClaimDialects(anyInt())).thenReturn(systemDefaultClaimDialects); + when(dbBasedClaimMetadataManager.getClaimDialects(anyInt())).thenReturn(dbClaimDialects); + List result = claimMetadataManager.getClaimDialects(0); + assertNotNull(result); + List claimDialectURIsInResult = result.stream() + .map(ClaimDialect::getClaimDialectURI) + .collect(Collectors.toList()); + assertEquals(claimDialectURIsInResult.size(), 3); + assertTrue(claimDialectURIsInResult.contains(LOCAL_CLAIM_DIALECT)); + assertTrue(claimDialectURIsInResult.contains(EXT_CLAIM_DIALECT_1)); + assertTrue(claimDialectURIsInResult.contains(EXT_CLAIM_DIALECT_2)); + + systemDefaultClaimDialects = new ArrayList<>(); + systemDefaultClaimDialects.add(new ClaimDialect(LOCAL_CLAIM_DIALECT)); + systemDefaultClaimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_1)); + dbClaimDialects = new ArrayList<>(); + dbClaimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_2)); + when(systemDefaultClaimMetadataManager.getClaimDialects(anyInt())).thenReturn(systemDefaultClaimDialects); + when(dbBasedClaimMetadataManager.getClaimDialects(anyInt())).thenReturn(dbClaimDialects); + result = claimMetadataManager.getClaimDialects(0); + assertNotNull(result); + claimDialectURIsInResult = result.stream() + .map(ClaimDialect::getClaimDialectURI) + .collect(Collectors.toList()); + assertEquals(claimDialectURIsInResult.size(), 3); + assertTrue(claimDialectURIsInResult.contains(LOCAL_CLAIM_DIALECT)); + assertTrue(claimDialectURIsInResult.contains(EXT_CLAIM_DIALECT_1)); + assertTrue(claimDialectURIsInResult.contains(EXT_CLAIM_DIALECT_2)); + + systemDefaultClaimDialects = new ArrayList<>(); + systemDefaultClaimDialects.add(new ClaimDialect(LOCAL_CLAIM_DIALECT)); + systemDefaultClaimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_1)); + dbClaimDialects = new ArrayList<>(); + dbClaimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_1)); + dbClaimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_2)); + when(systemDefaultClaimMetadataManager.getClaimDialects(anyInt())).thenReturn(systemDefaultClaimDialects); + when(dbBasedClaimMetadataManager.getClaimDialects(anyInt())).thenReturn(dbClaimDialects); + result = claimMetadataManager.getClaimDialects(0); + assertNotNull(result); + claimDialectURIsInResult = result.stream() + .map(ClaimDialect::getClaimDialectURI) + .collect(Collectors.toList()); + assertEquals(claimDialectURIsInResult.size(), 3); + assertTrue(claimDialectURIsInResult.contains(LOCAL_CLAIM_DIALECT)); + assertTrue(claimDialectURIsInResult.contains(EXT_CLAIM_DIALECT_1)); + assertTrue(claimDialectURIsInResult.contains(EXT_CLAIM_DIALECT_2)); + } + + @Test + public void testGetClaimDialect() throws ClaimMetadataException { + + ClaimDialect claimDialect = new ClaimDialect(LOCAL_CLAIM_DIALECT); + when(systemDefaultClaimMetadataManager.getClaimDialect(LOCAL_CLAIM_DIALECT, 0)) + .thenReturn(Optional.of(claimDialect)); + when(dbBasedClaimMetadataManager.getClaimDialect(LOCAL_CLAIM_DIALECT, 0)).thenReturn(Optional.empty()); + Optional result = claimMetadataManager.getClaimDialect(LOCAL_CLAIM_DIALECT, 0); + assertTrue(result.isPresent()); + assertEquals(result.get().getClaimDialectURI(), LOCAL_CLAIM_DIALECT); + + claimDialect = new ClaimDialect(EXT_CLAIM_DIALECT_1); + when(systemDefaultClaimMetadataManager.getClaimDialect(LOCAL_CLAIM_DIALECT, 0)).thenReturn(Optional.empty()); + when(dbBasedClaimMetadataManager.getClaimDialect(EXT_CLAIM_DIALECT_1, 0)) + .thenReturn(Optional.of(claimDialect)); + result = claimMetadataManager.getClaimDialect(EXT_CLAIM_DIALECT_1, 0); + assertTrue(result.isPresent()); + assertEquals(result.get().getClaimDialectURI(), EXT_CLAIM_DIALECT_1); + + claimDialect = new ClaimDialect(EXT_CLAIM_DIALECT_2); + when(systemDefaultClaimMetadataManager.getClaimDialect(LOCAL_CLAIM_DIALECT, 0)) + .thenReturn(Optional.of(claimDialect)); + when(dbBasedClaimMetadataManager.getClaimDialect(EXT_CLAIM_DIALECT_2, 0)) + .thenReturn(Optional.of(claimDialect)); + result = claimMetadataManager.getClaimDialect(EXT_CLAIM_DIALECT_2, 0); + assertTrue(result.isPresent()); + assertEquals(result.get().getClaimDialectURI(), EXT_CLAIM_DIALECT_2); + + when(systemDefaultClaimMetadataManager.getClaimDialect(LOCAL_CLAIM_DIALECT, 0)) + .thenReturn(Optional.empty()); + when(dbBasedClaimMetadataManager.getClaimDialect(NON_EXISTING_CLAIM_DIALECT, 0)) + .thenReturn(Optional.empty()); + result = claimMetadataManager.getClaimDialect(NON_EXISTING_CLAIM_DIALECT, 0); + assertFalse(result.isPresent()); + } + + @Test + public void testAddClaimDialect() throws ClaimMetadataException { + + ClaimDialect claimDialect = new ClaimDialect(EXT_CLAIM_DIALECT_1); + claimMetadataManager.addClaimDialect(claimDialect, 0); + verify(dbBasedClaimMetadataManager, times(1)).addClaimDialect(claimDialect, 0); + } + + @Test + public void testRenameClaimDialect() throws ClaimMetadataException { + + ClaimDialect oldClaimDialect = new ClaimDialect(EXT_CLAIM_DIALECT_1); + ClaimDialect newClaimDialect = new ClaimDialect(EXT_CLAIM_DIALECT_2); + claimMetadataManager.renameClaimDialect(oldClaimDialect, newClaimDialect, 0); + verify(dbBasedClaimMetadataManager, times(1)).renameClaimDialect(oldClaimDialect, newClaimDialect, 0); + } + + @Test + public void testRemoveClaimDialect() throws ClaimMetadataException { + + ClaimDialect claimDialect = new ClaimDialect(EXT_CLAIM_DIALECT_1); + claimMetadataManager.removeClaimDialect(claimDialect, 0); + verify(dbBasedClaimMetadataManager, times(1)).removeClaimDialect(claimDialect, 0); + } + + @Test + public void testGetLocalClaims() throws ClaimMetadataException { + + List localClaimsInSystem = new ArrayList<>(); + localClaimsInSystem.add(new LocalClaim(LOCAL_CLAIM_1)); + localClaimsInSystem.add(new LocalClaim(LOCAL_CLAIM_2)); + + List localClaimsInDB = new ArrayList<>(); + localClaimsInDB.add(new LocalClaim(LOCAL_CLAIM_3)); + localClaimsInDB.add(new LocalClaim(LOCAL_CLAIM_4)); + LocalClaim duplicatedLocalClaim = new LocalClaim(LOCAL_CLAIM_2); + duplicatedLocalClaim.setMappedAttributes(new ArrayList<>()); + duplicatedLocalClaim.getMappedAttributes().add(new AttributeMapping("PRIMARY", "username")); + localClaimsInDB.add(duplicatedLocalClaim); + + when(systemDefaultClaimMetadataManager.getLocalClaims(0)).thenReturn(localClaimsInSystem); + when(dbBasedClaimMetadataManager.getLocalClaims(0)).thenReturn(localClaimsInDB); + List result = claimMetadataManager.getLocalClaims(0); + assertNotNull(result); + assertEquals(result.size(), 4); + List localClaimURIsInResult = result.stream() + .map(LocalClaim::getClaimURI) + .collect(Collectors.toList()); + assertTrue(localClaimURIsInResult.contains(LOCAL_CLAIM_1)); + assertTrue(localClaimURIsInResult.contains(LOCAL_CLAIM_3)); + assertTrue(localClaimURIsInResult.contains(LOCAL_CLAIM_4)); + LocalClaim localClaim4 = result.stream() + .filter(localClaim -> localClaim.getClaimURI().equals(LOCAL_CLAIM_2)) + .findFirst() + .orElse(null); + assertNotNull(localClaim4); + assertEquals(localClaim4.getMappedAttributes().size(), 1); + assertEquals(localClaim4.getMappedAttributes().get(0).getUserStoreDomain(), "PRIMARY"); + assertEquals(localClaim4.getMappedAttributes().get(0).getAttributeName(), "username"); + } + + @Test + public void testGetLocalClaim() throws ClaimMetadataException { + + LocalClaim localClaim = new LocalClaim(LOCAL_CLAIM_1); + when(systemDefaultClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_1, 0)) + .thenReturn(Optional.of(localClaim)); + when(dbBasedClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_1, 0)).thenReturn(Optional.empty()); + Optional result = claimMetadataManager.getLocalClaim(LOCAL_CLAIM_1, 0); + assertTrue(result.isPresent()); + assertEquals(result.get().getClaimURI(), LOCAL_CLAIM_1); + + localClaim = new LocalClaim(LOCAL_CLAIM_2); + when(systemDefaultClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_2, 0)).thenReturn(null); + when(dbBasedClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_2, 0)) + .thenReturn(Optional.of(localClaim)); + result = claimMetadataManager.getLocalClaim(LOCAL_CLAIM_2, 0); + assertTrue(result.isPresent()); + assertEquals(result.get().getClaimURI(), LOCAL_CLAIM_2); + + LocalClaim localClaimInSystem = new LocalClaim(LOCAL_CLAIM_3); + when(systemDefaultClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_3, 0)) + .thenReturn(Optional.of(localClaimInSystem)); + LocalClaim localClaimInDB = new LocalClaim(LOCAL_CLAIM_3); + localClaimInDB.setMappedAttributes(new ArrayList<>()); + localClaimInDB.getMappedAttributes().add(new AttributeMapping("PRIMARY", "country")); + when(dbBasedClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_3, 0)) + .thenReturn(Optional.of(localClaimInDB)); + result = claimMetadataManager.getLocalClaim(LOCAL_CLAIM_3, 0); + assertTrue(result.isPresent()); + assertEquals(result.get().getClaimURI(), LOCAL_CLAIM_3); + assertEquals(result.get().getMappedAttributes().size(), 1); + assertEquals(result.get().getMappedAttributes().get(0).getUserStoreDomain(), "PRIMARY"); + assertEquals(result.get().getMappedAttributes().get(0).getAttributeName(), "country"); + + when(systemDefaultClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_4, 0)).thenReturn(Optional.empty()); + when(dbBasedClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_4, 0)).thenReturn(Optional.empty()); + result = claimMetadataManager.getLocalClaim(LOCAL_CLAIM_4, 0); + assertFalse(result.isPresent()); + } + + @Test + public void testAddLocalClaim() throws ClaimMetadataException { + + ClaimDialect claimDialect = new ClaimDialect(LOCAL_CLAIM_DIALECT); + when(dbBasedClaimMetadataManager.getClaimDialect(LOCAL_CLAIM_DIALECT, 0)) + .thenReturn(Optional.of(claimDialect)); + LocalClaim localClaim = new LocalClaim(LOCAL_CLAIM_1); + claimMetadataManager.addLocalClaim(localClaim, 0); + verify(dbBasedClaimMetadataManager, times(1)).addLocalClaim(localClaim, 0); + clearInvocations(dbBasedClaimMetadataManager); + + when(dbBasedClaimMetadataManager.getClaimDialect(LOCAL_CLAIM_DIALECT, 0)).thenReturn(Optional.empty()); + when(systemDefaultClaimMetadataManager.getClaimDialect(LOCAL_CLAIM_DIALECT, 0)) + .thenReturn(Optional.of(claimDialect)); + claimMetadataManager.addLocalClaim(localClaim, 0); + verify(dbBasedClaimMetadataManager, times(1)).addClaimDialect(claimDialect, 0); + verify(dbBasedClaimMetadataManager, times(1)).addLocalClaim(localClaim, 0); + } + + @Test + public void testUpdateLocalClaim() throws ClaimMetadataException { + + LocalClaim localClaimInSystem = new LocalClaim(LOCAL_CLAIM_1); + localClaimInSystem.setMappedAttributes(new ArrayList<>()); + localClaimInSystem.getMappedAttributes().add(new AttributeMapping("PRIMARY", "username")); + localClaimInSystem.setClaimProperties(new HashMap<>()); + localClaimInSystem.getClaimProperties().put("Property1", "Value1"); + + LocalClaim localClaimInDB = new LocalClaim(LOCAL_CLAIM_1); + localClaimInDB.setMappedAttributes(new ArrayList<>()); + localClaimInDB.getMappedAttributes().add(new AttributeMapping("PRIMARY", "username")); + localClaimInDB.getMappedAttributes().add(new AttributeMapping("SECONDARY", "user_name")); + localClaimInDB.setClaimProperties(new HashMap<>()); + localClaimInDB.getClaimProperties().put("Property1", "Value1"); + + LocalClaim updatedLocalClaim = new LocalClaim(LOCAL_CLAIM_1); + updatedLocalClaim.setMappedAttributes(new ArrayList<>()); + updatedLocalClaim.getMappedAttributes().add(new AttributeMapping("PRIMARY", "username")); + updatedLocalClaim.getMappedAttributes().add(new AttributeMapping("SECONDARY", "user_id")); + updatedLocalClaim.setClaimProperties(new HashMap<>()); + updatedLocalClaim.getClaimProperties().put("Property2", "Value2"); + + when(systemDefaultClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_1, 0)) + .thenReturn(Optional.of(localClaimInSystem)); + when(dbBasedClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_1, 0)).thenReturn(Optional.empty()); + claimMetadataManager.updateLocalClaim(updatedLocalClaim, 0); + verify(dbBasedClaimMetadataManager, times(1)).addLocalClaim(updatedLocalClaim, 0); + clearInvocations(dbBasedClaimMetadataManager); + + when(systemDefaultClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_1, 0)) + .thenReturn(Optional.of(localClaimInSystem)); + when(dbBasedClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_1, 0)) + .thenReturn(Optional.of(localClaimInDB)); + claimMetadataManager.updateLocalClaim(updatedLocalClaim, 0); + verify(dbBasedClaimMetadataManager, times(1)).updateLocalClaim(updatedLocalClaim, 0); + clearInvocations(dbBasedClaimMetadataManager); + + when(systemDefaultClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_1, 0)).thenReturn(null); + when(dbBasedClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_1, 0)) + .thenReturn(Optional.of(localClaimInDB)); + claimMetadataManager.updateLocalClaim(updatedLocalClaim, 0); + verify(dbBasedClaimMetadataManager, times(1)).updateLocalClaim(updatedLocalClaim, 0); + } + + @Test + public void testUpdateLocalClaimMappings() throws ClaimMetadataException { + + List updatedLocalClaims = new ArrayList<>(); + LocalClaim localClaim = new LocalClaim(LOCAL_CLAIM_1); + updatedLocalClaims.add(localClaim); + when(dbBasedClaimMetadataManager.getClaimDialect(ClaimConstants.LOCAL_CLAIM_DIALECT_URI, 1)) + .thenReturn(Optional.empty()); + when(systemDefaultClaimMetadataManager.getClaimDialect(ClaimConstants.LOCAL_CLAIM_DIALECT_URI, 1)) + .thenReturn(Optional.of(new ClaimDialect(ClaimConstants.LOCAL_CLAIM_DIALECT_URI))); + List finalUpdatedLocalClaims = updatedLocalClaims; + assertThrows(ClaimMetadataClientException.class, () -> { + claimMetadataManager.updateLocalClaimMappings(finalUpdatedLocalClaims, 1, "PRIMARY"); + }); + verify(dbBasedClaimMetadataManager, times(1)).addClaimDialect(any(), anyInt()); + clearInvocations(dbBasedClaimMetadataManager); + + LocalClaim localClaimInSystem1 = new LocalClaim(LOCAL_CLAIM_1); + localClaimInSystem1.setMappedAttributes(new ArrayList<>()); + localClaimInSystem1.getMappedAttributes().add(new AttributeMapping("PRIMARY", "username")); + localClaimInSystem1.setClaimProperties(new HashMap<>()); + localClaimInSystem1.getClaimProperties().put("Property1", "Value1"); + + LocalClaim localClaimInSystem2 = new LocalClaim(LOCAL_CLAIM_2); + localClaimInSystem2.setMappedAttributes(new ArrayList<>()); + localClaimInSystem2.getMappedAttributes().add(new AttributeMapping("PRIMARY", "email")); + localClaimInSystem2.getMappedAttributes().add(new AttributeMapping("SECONDARY", "email")); + localClaimInSystem2.setClaimProperties(new HashMap<>()); + localClaimInSystem2.getClaimProperties().put("Property2", "Value2"); + + List localClaimsInSystem = new ArrayList<>(); + localClaimsInSystem.add(localClaimInSystem1); + localClaimsInSystem.add(localClaimInSystem2); + when(systemDefaultClaimMetadataManager.getLocalClaims(1)).thenReturn(localClaimsInSystem); + + LocalClaim localClaimInDB1 = new LocalClaim(LOCAL_CLAIM_3); + localClaimInDB1.setMappedAttributes(new ArrayList<>()); + localClaimInDB1.getMappedAttributes().add(new AttributeMapping("SECONDARY", "country")); + localClaimInDB1.setClaimProperties(new HashMap<>()); + localClaimInDB1.getClaimProperties().put("Property3", "Value3"); + + LocalClaim localClaimInDB2 = new LocalClaim(LOCAL_CLAIM_4); + + List localClaimsInDB = new ArrayList<>(); + localClaimsInDB.add(localClaimInDB1); + localClaimsInDB.add(localClaimInDB2); + when(dbBasedClaimMetadataManager.getLocalClaims(1)).thenReturn(localClaimsInDB); + + when(systemDefaultClaimMetadataManager.getClaimDialect(ClaimConstants.LOCAL_CLAIM_DIALECT_URI, 1)) + .thenReturn(Optional.of(new ClaimDialect(ClaimConstants.LOCAL_CLAIM_DIALECT_URI))); + + LocalClaim updatedLocalClaim1 = new LocalClaim(LOCAL_CLAIM_1); + updatedLocalClaim1.setMappedAttributes(new ArrayList<>()); + updatedLocalClaim1.getMappedAttributes().add(new AttributeMapping("SECONDARY", "user_name")); + + LocalClaim updatedLocalClaim2 = new LocalClaim(LOCAL_CLAIM_2); + updatedLocalClaim2.setMappedAttributes(new ArrayList<>()); + updatedLocalClaim2.getMappedAttributes().add(new AttributeMapping("PRIMARY", "email")); + updatedLocalClaim2.getMappedAttributes().add(new AttributeMapping("SECONDARY", "email_address")); + + LocalClaim updatedLocalClaim3 = new LocalClaim(LOCAL_CLAIM_3); + updatedLocalClaim3.setMappedAttributes(new ArrayList<>()); + updatedLocalClaim3.getMappedAttributes().add(new AttributeMapping("SECONDARY", "user_country")); + + LocalClaim updatedLocalClaim4 = new LocalClaim(LOCAL_CLAIM_4); + updatedLocalClaim4.setMappedAttributes(new ArrayList<>()); + updatedLocalClaim4.getMappedAttributes().add(new AttributeMapping("SECONDARY", "isAccountLocked")); + + updatedLocalClaims = new ArrayList<>(); + updatedLocalClaims.add(updatedLocalClaim1); + updatedLocalClaims.add(updatedLocalClaim2); + updatedLocalClaims.add(updatedLocalClaim3); + updatedLocalClaims.add(updatedLocalClaim4); + + claimMetadataManager.updateLocalClaimMappings(updatedLocalClaims, 1, "SECONDARY"); + } + + @Test + public void testRemoveLocalClaim() throws ClaimMetadataException { + + claimMetadataManager.removeLocalClaim(LOCAL_CLAIM_1, 0); + verify(dbBasedClaimMetadataManager, times(1)).removeLocalClaim(LOCAL_CLAIM_1, 0); + } + + @Test + public void testGetExternalClaims() throws ClaimMetadataException { + + List externalClaimsInSystem = new ArrayList<>(); + externalClaimsInSystem.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1)); + externalClaimsInSystem.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_2, LOCAL_CLAIM_2)); + when(systemDefaultClaimMetadataManager.getExternalClaims(EXT_CLAIM_DIALECT_1, 1)) + .thenReturn(externalClaimsInSystem); + + List externalClaimsInDB = new ArrayList<>(); + externalClaimsInDB.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_2, LOCAL_CLAIM_4)); + externalClaimsInDB.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_3, LOCAL_CLAIM_3)); + when(dbBasedClaimMetadataManager.getExternalClaims(EXT_CLAIM_DIALECT_1, 1)) + .thenReturn(externalClaimsInDB); + + List result = claimMetadataManager.getExternalClaims(EXT_CLAIM_DIALECT_1, 1); + assertNotNull(result); + assertEquals(result.size(), 3); + List externalClaimURIsInResult = result.stream() + .map(ExternalClaim::getClaimURI) + .collect(Collectors.toList()); + assertTrue(externalClaimURIsInResult.contains(EXT_CLAIM_DIALECT_1_CLAIM_1)); + assertTrue(externalClaimURIsInResult.contains(EXT_CLAIM_DIALECT_1_CLAIM_2)); + assertTrue(externalClaimURIsInResult.contains(EXT_CLAIM_DIALECT_1_CLAIM_3)); + List mappedLocalClaimURIsInResult = result.stream() + .map(ExternalClaim::getMappedLocalClaim) + .collect(Collectors.toList()); + assertTrue(mappedLocalClaimURIsInResult.contains(LOCAL_CLAIM_1)); + assertTrue(mappedLocalClaimURIsInResult.contains(LOCAL_CLAIM_3)); + assertTrue(mappedLocalClaimURIsInResult.contains(LOCAL_CLAIM_4)); + } + + @Test + public void testGetExternalClaim() throws ClaimMetadataException { + + ExternalClaim externalClaimsInSystem = new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1); + when(systemDefaultClaimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1)) + .thenReturn(Optional.of(externalClaimsInSystem)); + when(dbBasedClaimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1)) + .thenReturn(Optional.empty()); + Optional result = claimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1); + assertTrue(result.isPresent()); + assertEquals(result.get().getClaimURI(), EXT_CLAIM_DIALECT_1_CLAIM_1); + assertEquals(result.get().getMappedLocalClaim(), LOCAL_CLAIM_1); + + ExternalClaim externalClaimsInDB = new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1); + when(systemDefaultClaimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1)) + .thenReturn(null); + when(dbBasedClaimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1)) + .thenReturn(Optional.of(externalClaimsInDB)); + result = claimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1); + assertTrue(result.isPresent()); + assertEquals(result.get().getClaimURI(), EXT_CLAIM_DIALECT_1_CLAIM_1); + assertEquals(result.get().getMappedLocalClaim(), LOCAL_CLAIM_1); + + externalClaimsInSystem = new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1); + externalClaimsInDB = new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_2); + when(systemDefaultClaimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1)) + .thenReturn(Optional.of(externalClaimsInSystem)); + when(dbBasedClaimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1)) + .thenReturn(Optional.of(externalClaimsInDB)); + result = claimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1); + assertTrue(result.isPresent()); + assertEquals(result.get().getClaimURI(), EXT_CLAIM_DIALECT_1_CLAIM_1); + assertEquals(result.get().getMappedLocalClaim(), LOCAL_CLAIM_2); + + when(systemDefaultClaimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1)) + .thenReturn(Optional.empty()); + when(dbBasedClaimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1)) + .thenReturn(Optional.empty()); + result = claimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1); + assertFalse(result.isPresent()); + } + + @Test + public void testAddExternalClaim() throws ClaimMetadataException { + + when(systemDefaultClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_1, 1)) + .thenReturn(Optional.of(new LocalClaim(LOCAL_CLAIM_1))); + when(systemDefaultClaimMetadataManager.getClaimDialect(EXT_CLAIM_DIALECT_1, 1)) + .thenReturn(Optional.of(new ClaimDialect(EXT_CLAIM_DIALECT_1))); + when(systemDefaultClaimMetadataManager.getClaimDialect(LOCAL_CLAIM_DIALECT, 1)) + .thenReturn(Optional.of(new ClaimDialect(LOCAL_CLAIM_DIALECT))); + + ExternalClaim externalClaim = new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1); + claimMetadataManager.addExternalClaim(externalClaim, 1); + verify(dbBasedClaimMetadataManager, times(2)).addClaimDialect(any(), anyInt()); + verify(dbBasedClaimMetadataManager, times(1)).addLocalClaim(any(), anyInt()); + verify(dbBasedClaimMetadataManager, times(1)).addExternalClaim(externalClaim, 1); + clearInvocations(dbBasedClaimMetadataManager); + + when(dbBasedClaimMetadataManager.getClaimDialect(EXT_CLAIM_DIALECT_1, 1)) + .thenReturn(Optional.of(new ClaimDialect(EXT_CLAIM_DIALECT_1))); + claimMetadataManager.addExternalClaim(externalClaim, 1); + verify(dbBasedClaimMetadataManager, times(1)).addClaimDialect(any(), anyInt()); + verify(dbBasedClaimMetadataManager, times(1)).addLocalClaim(any(), anyInt()); + verify(dbBasedClaimMetadataManager, times(1)).addExternalClaim(externalClaim, 1); + clearInvocations(dbBasedClaimMetadataManager); + + when(dbBasedClaimMetadataManager.getClaimDialect(LOCAL_CLAIM_DIALECT, 1)) + .thenReturn(Optional.of(new ClaimDialect(LOCAL_CLAIM_DIALECT))); + claimMetadataManager.addExternalClaim(externalClaim, 1); + verify(dbBasedClaimMetadataManager, never()).addClaimDialect(any(), anyInt()); + verify(dbBasedClaimMetadataManager, times(1)).addLocalClaim(any(), anyInt()); + verify(dbBasedClaimMetadataManager, times(1)).addExternalClaim(externalClaim, 1); + clearInvocations(dbBasedClaimMetadataManager); + + when(dbBasedClaimMetadataManager.getLocalClaim(LOCAL_CLAIM_1, 1)) + .thenReturn(Optional.of(new LocalClaim(LOCAL_CLAIM_1))); + claimMetadataManager.addExternalClaim(externalClaim, 1); + verify(dbBasedClaimMetadataManager, never()).addClaimDialect(any(), anyInt()); + verify(dbBasedClaimMetadataManager, never()).addLocalClaim(any(), anyInt()); + verify(dbBasedClaimMetadataManager, times(1)).addExternalClaim(externalClaim, 1); + clearInvocations(dbBasedClaimMetadataManager); + } + + @Test + public void testUpdateExternalClaim() throws ClaimMetadataException { + + ExternalClaim updatedExternalClaim = new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_2); + when(dbBasedClaimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1)) + .thenReturn(Optional.empty()); + claimMetadataManager.updateExternalClaim(updatedExternalClaim, 1); + verify(dbBasedClaimMetadataManager, times(1)).addExternalClaim(updatedExternalClaim, 1); + clearInvocations(dbBasedClaimMetadataManager); + + when(dbBasedClaimMetadataManager.getExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1)) + .thenReturn(Optional.of(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1))); + claimMetadataManager.updateExternalClaim(updatedExternalClaim, 1); + verify(dbBasedClaimMetadataManager, times(1)) + .updateExternalClaim(updatedExternalClaim, 1); + } + + @Test + public void testRemoveExternalClaim() throws ClaimMetadataException { + + claimMetadataManager.removeExternalClaim(EXT_CLAIM_DIALECT_1_CLAIM_1, EXT_CLAIM_DIALECT_1, 1); + verify(dbBasedClaimMetadataManager, times(1)) + .removeExternalClaim(EXT_CLAIM_DIALECT_1_CLAIM_1, EXT_CLAIM_DIALECT_1, 1); + } + + @Test + public void testIsMappedLocalClaim() throws ClaimMetadataException { + + List claimDialects = new ArrayList<>(); + claimDialects.add(new ClaimDialect(LOCAL_CLAIM_DIALECT)); + claimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_1)); + claimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_2)); + when(systemDefaultClaimMetadataManager.getClaimDialects(1)).thenReturn(claimDialects); + + List claimsOfExternalDialect1 = new ArrayList<>(); + claimsOfExternalDialect1.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1)); + claimsOfExternalDialect1.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_2, LOCAL_CLAIM_2)); + when(systemDefaultClaimMetadataManager.getExternalClaims(EXT_CLAIM_DIALECT_1, 1)) + .thenReturn(claimsOfExternalDialect1); + + List claimsOfExternalDialect2 = new ArrayList<>(); + claimsOfExternalDialect2.add(new ExternalClaim(EXT_CLAIM_DIALECT_2, EXT_CLAIM_DIALECT_2_CLAIM_1, LOCAL_CLAIM_2)); + claimsOfExternalDialect2.add(new ExternalClaim(EXT_CLAIM_DIALECT_2, EXT_CLAIM_DIALECT_2_CLAIM_2, LOCAL_CLAIM_3)); + when(systemDefaultClaimMetadataManager.getExternalClaims(EXT_CLAIM_DIALECT_2, 1)) + .thenReturn(claimsOfExternalDialect2); + + assertTrue(claimMetadataManager.isMappedLocalClaim(LOCAL_CLAIM_1, 1)); + assertTrue(claimMetadataManager.isMappedLocalClaim(LOCAL_CLAIM_2, 1)); + assertFalse(claimMetadataManager.isMappedLocalClaim(LOCAL_CLAIM_4, 1)); + } + + @Test + public void testRemoveClaimMappingAttributes() throws ClaimMetadataException { + + claimMetadataManager.removeClaimMappingAttributes(1, "PRIMARY"); + verify(dbBasedClaimMetadataManager, times(1)).removeClaimMappingAttributes(1, "PRIMARY"); + } + + @Test + public void testRemoveAllClaimDialects() throws ClaimMetadataException { + + claimMetadataManager.removeAllClaimDialects(1); + verify(dbBasedClaimMetadataManager, times(1)).removeAllClaimDialects(1); + } + + @Test + public void testGetMappedExternalClaims() throws ClaimMetadataException { + + List claimDialects = new ArrayList<>(); + claimDialects.add(new ClaimDialect(LOCAL_CLAIM_DIALECT)); + claimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_1)); + claimDialects.add(new ClaimDialect(EXT_CLAIM_DIALECT_2)); + when(systemDefaultClaimMetadataManager.getClaimDialects(1)).thenReturn(claimDialects); + + List claimsOfExternalDialect1 = new ArrayList<>(); + claimsOfExternalDialect1.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1)); + claimsOfExternalDialect1.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_2, LOCAL_CLAIM_2)); + when(systemDefaultClaimMetadataManager.getExternalClaims(EXT_CLAIM_DIALECT_1, 1)) + .thenReturn(claimsOfExternalDialect1); + + List claimsOfExternalDialect2 = new ArrayList<>(); + claimsOfExternalDialect2.add(new ExternalClaim(EXT_CLAIM_DIALECT_2, EXT_CLAIM_DIALECT_2_CLAIM_1, LOCAL_CLAIM_2)); + claimsOfExternalDialect2.add(new ExternalClaim(EXT_CLAIM_DIALECT_2, EXT_CLAIM_DIALECT_2_CLAIM_2, LOCAL_CLAIM_3)); + when(systemDefaultClaimMetadataManager.getExternalClaims(EXT_CLAIM_DIALECT_2, 1)) + .thenReturn(claimsOfExternalDialect2); + + List result = claimMetadataManager.getMappedExternalClaims(LOCAL_CLAIM_1, 1); + assertNotNull(result); + assertEquals(result.size(), 1); + assertEquals(result.get(0).getClaimURI(), EXT_CLAIM_DIALECT_1_CLAIM_1); + + result = claimMetadataManager.getMappedExternalClaims(LOCAL_CLAIM_2, 1); + assertNotNull(result); + assertEquals(result.size(), 2); + List claimURIsInResult = result.stream() + .map(Claim::getClaimURI) + .collect(Collectors.toList()); + assertTrue(claimURIsInResult.contains(EXT_CLAIM_DIALECT_1_CLAIM_2)); + assertTrue(claimURIsInResult.contains(EXT_CLAIM_DIALECT_2_CLAIM_1)); + + result = claimMetadataManager.getMappedExternalClaims(LOCAL_CLAIM_4, 1); + assertNotNull(result); + assertEquals(result.size(), 0); + } + + @Test + public void testIsLocalClaimMappedWithinDialect() throws ClaimMetadataException { + + List claimsOfExternalDialect = new ArrayList<>(); + claimsOfExternalDialect.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1)); + claimsOfExternalDialect.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_2, LOCAL_CLAIM_2)); + when(systemDefaultClaimMetadataManager.getExternalClaims(EXT_CLAIM_DIALECT_1, 1)) + .thenReturn(claimsOfExternalDialect); + + assertTrue(claimMetadataManager.isLocalClaimMappedWithinDialect(LOCAL_CLAIM_1, EXT_CLAIM_DIALECT_1, 1)); + assertFalse(claimMetadataManager.isLocalClaimMappedWithinDialect(LOCAL_CLAIM_3, EXT_CLAIM_DIALECT_1, 1)); + } + +// @Test +// public void testIsSystemDefaultClaimDialect() throws ClaimMetadataException { +// +// when(systemDefaultClaimMetadataManager.getClaimDialect(LOCAL_CLAIM_DIALECT, 1)) +// .thenReturn(Optional.of(new ClaimDialect(LOCAL_CLAIM_DIALECT))); +// when(systemDefaultClaimMetadataManager.getClaimDialect(EXT_CLAIM_DIALECT_1, 1)) +// .thenReturn(Optional.of(new ClaimDialect(EXT_CLAIM_DIALECT_1))); +// when(dbBasedClaimMetadataManager.getClaimDialect(EXT_CLAIM_DIALECT_1, 1)) +// .thenReturn(Optional.of(new ClaimDialect(EXT_CLAIM_DIALECT_1))); +// when(dbBasedClaimMetadataManager.getClaimDialect(EXT_CLAIM_DIALECT_2, 1)) +// .thenReturn(Optional.of(new ClaimDialect(EXT_CLAIM_DIALECT_2))); +// +// assertTrue(claimMetadataManager.isSystemDefaultClaimDialect(LOCAL_CLAIM_DIALECT, 1)); +// assertTrue(claimMetadataManager.isSystemDefaultClaimDialect(EXT_CLAIM_DIALECT_1, 1)); +// assertFalse(claimMetadataManager.isSystemDefaultClaimDialect(EXT_CLAIM_DIALECT_2, 1)); +// } + +// @Test +// public void testIsSystemDefaultLocalClaim() throws ClaimMetadataException { +// +// List localClaimsInSystem = new ArrayList<>(); +// localClaimsInSystem.add(new LocalClaim(LOCAL_CLAIM_1)); +// localClaimsInSystem.add(new LocalClaim(LOCAL_CLAIM_2)); +// when(systemDefaultClaimMetadataManager.getLocalClaims(1)).thenReturn(localClaimsInSystem); +// +// List localClaimsInDB = new ArrayList<>(); +// localClaimsInDB.add(new LocalClaim(LOCAL_CLAIM_3)); +// localClaimsInDB.add(new LocalClaim(LOCAL_CLAIM_4)); +// when(dbBasedClaimMetadataManager.getLocalClaims(1)).thenReturn(localClaimsInDB); +// +// assertTrue(claimMetadataManager.isSystemDefaultLocalClaim(LOCAL_CLAIM_1, 1)); +// assertFalse(claimMetadataManager.isSystemDefaultLocalClaim(LOCAL_CLAIM_3, 1)); +// } + +// @Test +// public void testIsSystemDefaultExternalClaim() throws ClaimMetadataException { +// +// List claimsOfExternalDialect = new ArrayList<>(); +// claimsOfExternalDialect.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, LOCAL_CLAIM_1)); +// claimsOfExternalDialect.add(new ExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_2, LOCAL_CLAIM_2)); +// when(systemDefaultClaimMetadataManager.getExternalClaims(EXT_CLAIM_DIALECT_1, 1)) +// .thenReturn(claimsOfExternalDialect); +// +// assertTrue(claimMetadataManager.isSystemDefaultExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_1, 1)); +// assertFalse(claimMetadataManager.isSystemDefaultExternalClaim(EXT_CLAIM_DIALECT_1, EXT_CLAIM_DIALECT_1_CLAIM_3, 1)); +// } + + @AfterMethod + public void tearDown() { + + dataHolderStaticMock.close(); + identityUtilStaticMock.close(); + } +} diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/LocalClaimDAOTest.java b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/LocalClaimDAOTest.java index 0e82797be45b..67ca15ba01a7 100644 --- a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/LocalClaimDAOTest.java +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/java/org/wso2/carbon/identity/claim/metadata/mgt/dao/LocalClaimDAOTest.java @@ -27,12 +27,16 @@ import org.wso2.carbon.identity.common.testng.WithH2Database; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertThrows; +import static org.testng.Assert.assertTrue; @Test @WithH2Database(jndiName = "jdbc/WSO2IdentityDB", @@ -193,4 +197,141 @@ public Object[][] testUpdateLocalClaimData() { }; } + + @Test(dataProvider = "updateLocalClaimMappings") + public void testUpdateLocalClaimMappings(List claimsToBeUpdated, List claimsInDB, + List resultClaims, String userStoreDomain) + throws ClaimMetadataException { + + ClaimDialectDAO claimDialectDAO = new ClaimDialectDAO(); + ClaimDialect claimDialect = new ClaimDialect(ClaimConstants.LOCAL_CLAIM_DIALECT_URI); + claimDialectDAO.addClaimDialect(claimDialect, TEST_LOCAL_TENANT_ID); + + LocalClaimDAO localClaimDAO = new LocalClaimDAO(); + for (LocalClaim localClaim : claimsInDB) { + localClaimDAO.addLocalClaim(localClaim, TEST_LOCAL_TENANT_ID); + } + + localClaimDAO.updateLocalClaimMappings(claimsToBeUpdated, TEST_LOCAL_TENANT_ID, userStoreDomain); + + List localClaimsFromDB = localClaimDAO.getLocalClaims(TEST_LOCAL_TENANT_ID); + assertEquals(localClaimsFromDB.size(), resultClaims.size(), "Failed to update local claim mappings"); + + for (LocalClaim localClaimInResultSet : resultClaims) { + LocalClaim localClaimFromDB = localClaimsFromDB.stream() + .filter(claim -> claim.getClaimURI().equals(localClaimInResultSet.getClaimURI())) + .findFirst() + .orElse(null); + assert localClaimFromDB != null; + assertTrue(areLocalClaimsEqual(localClaimInResultSet, localClaimFromDB)); + } + + claimDialectDAO.removeClaimDialect(claimDialect, TEST_LOCAL_TENANT_ID); + assertThrows(ClaimMetadataException.class, () -> localClaimDAO.updateLocalClaimMappings(claimsToBeUpdated, + TEST_LOCAL_TENANT_ID, userStoreDomain)); + } + + @DataProvider(name = "updateLocalClaimMappings") + public Object[][] testUpdateLocalClaimMappingsData() { + + String testUserStoreDomain = "TEST_DOMAIN"; + + // Local claims to be updated. + List localClaimsToBeUpdated = Arrays.asList( + createLocalClaim("http://wso2.org/claims/test1", "TestDescription1", + createAttributeMappings("PRIMARY", "givenname", "TEST_DOMAIN", "firstname")), + createLocalClaim("http://wso2.org/claims/test2", "TestDescription2", + createAttributeMappings("PRIMARY", "givenname", "TEST_DOMAIN", "firstname")), + createLocalClaim("http://wso2.org/claims/test3", "TestDescription3", + createAttributeMappings("TEST_DOMAIN", "firstname")), + createLocalClaim("http://wso2.org/claims/test4", null, + createAttributeMappings("TEST_DOMAIN", "firstname")) + ); + + // Local claims in DB. + List localClaimsInDB = Arrays.asList( + createLocalClaim("http://wso2.org/claims/test2", "TestDescription2", + createAttributeMappings("PRIMARY", "firstname", "TEST_DOMAIN", "givenname")), + createLocalClaim("http://wso2.org/claims/test3", "TestDescription3", + createAttributeMappings("PRIMARY", "givenname")), + createLocalClaim("http://wso2.org/claims/test4", "TestDescription4", + null) + ); + + // Expected result local claims. + List resultLocalClaims = Arrays.asList( + createLocalClaim("http://wso2.org/claims/test1", "TestDescription1", + createAttributeMappings("PRIMARY", "givenname", "TEST_DOMAIN", "firstname")), + createLocalClaim("http://wso2.org/claims/test2", "TestDescription2", + createAttributeMappings("PRIMARY", "firstname", "TEST_DOMAIN", "firstname")), + createLocalClaim("http://wso2.org/claims/test3", "TestDescription3", + createAttributeMappings("PRIMARY", "givenname", "TEST_DOMAIN", "firstname")), + createLocalClaim("http://wso2.org/claims/test4", "TestDescription4", + createAttributeMappings("TEST_DOMAIN", "firstname")) + ); + + return new Object[][] { + { localClaimsToBeUpdated, localClaimsInDB, resultLocalClaims, testUserStoreDomain } + }; + } + + private LocalClaim createLocalClaim(String uri, String description, List attributeMappings) { + LocalClaim localClaim = new LocalClaim(uri); + if (description != null) { + Map claimProperties = new HashMap<>(); + claimProperties.put("Description", description); + localClaim.setClaimProperties(claimProperties); + } + if (attributeMappings != null) { + localClaim.setMappedAttributes(attributeMappings); + } + return localClaim; + } + + private List createAttributeMappings(String... mappings) { + List attributeMappings = new ArrayList<>(); + for (int i = 0; i < mappings.length; i += 2) { + attributeMappings.add(new AttributeMapping(mappings[i], mappings[i + 1])); + } + return attributeMappings; + } + + private boolean areLocalClaimsEqual(LocalClaim localClaim1, LocalClaim localClaim2) { + + if (localClaim1 == localClaim2) { + return true; + } + return localClaim1 != null && localClaim2 != null + && Objects.equals(localClaim1.getClaimURI(), localClaim2.getClaimURI()) + && Objects.equals(localClaim1.getClaimProperties(), localClaim2.getClaimProperties()) + && areAttributeMappingsEqual(localClaim1.getMappedAttributes(), localClaim2.getMappedAttributes()); + } + + private boolean areAttributeMappingsEqual(List attributeMappings1, + List attributeMappings2) { + + if (attributeMappings1 == attributeMappings2) { + return true; + } + if (attributeMappings1 == null || attributeMappings2 == null) { + return false; + } + if (attributeMappings1.size() != attributeMappings2.size()) { + return false; + } + for (AttributeMapping attributeMapping1 : attributeMappings1) { + boolean found = false; + for (AttributeMapping attributeMapping2 : attributeMappings2) { + if (Objects.equals(attributeMapping1.getUserStoreDomain(), attributeMapping2.getUserStoreDomain()) + && Objects.equals(attributeMapping1.getAttributeName(), attributeMapping2.getAttributeName())) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + return true; + } } diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/resources/dbScripts/claim_properties.sql b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/resources/dbScripts/claim_properties.sql index bb5587adcf02..9dd2f4217b33 100644 --- a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/resources/dbScripts/claim_properties.sql +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/resources/dbScripts/claim_properties.sql @@ -8,7 +8,7 @@ CREATE TABLE IF NOT EXISTS IDN_CLAIM_DIALECT ( CREATE TABLE IF NOT EXISTS IDN_CLAIM ( ID INTEGER NOT NULL AUTO_INCREMENT, - DIALECT_ID INTEGER, + DIALECT_ID INTEGER NOT NULL, CLAIM_URI VARCHAR (255) NOT NULL, TENANT_ID INTEGER NOT NULL, PRIMARY KEY (ID), diff --git a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/resources/testng.xml b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/resources/testng.xml index 2b071aa02c77..a09f8e521b4b 100644 --- a/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/resources/testng.xml +++ b/components/claim-mgt/org.wso2.carbon.identity.claim.metadata.mgt/src/test/resources/testng.xml @@ -24,6 +24,9 @@ + + +