From 14c70f8eb7b018cbaba6e9fc8e457e8a46898f7d Mon Sep 17 00:00:00 2001 From: Maduranga Siriwardena Date: Wed, 6 Sep 2023 14:59:34 +0530 Subject: [PATCH 1/2] Add improved user profile export functionality --- .../pom.xml | 1 + .../internal/UserProfileExportDataHolder.java | 111 ++++++++ .../UserProfileExportServiceComponent.java | 169 ++++++++++++ .../impl/AbstractUserInformationProvider.java | 33 ++- .../impl/BasicUserInformationProvider.java | 56 +--- .../impl/ConsentInformationProvider.java | 74 +----- .../impl/SecurityInformationProvider.java | 39 +-- .../impl/UserInformationServiceImpl.java | 38 +-- .../user/export/core/model/LinkedAccount.java | 84 ++++++ .../service/impl/LinkedAccountsProvider.java | 99 +++++++ .../impl/UserProfileInformationProvider.java | 143 ++++++++++ .../user/export/core/utils/Utils.java | 51 +++- .../BasicUserInformationProviderTest.java | 18 +- .../impl/ConsentInformationProviderTest.java | 33 ++- .../impl/MockUserInformationProvider.java | 5 +- .../impl/UserInformationServiceImplTest.java | 7 +- .../impl/LinkedAccountsProviderTest.java | 207 +++++++++++++++ .../UserProfileInformationProviderTest.java | 245 ++++++++++++++++++ .../src/test/resources/testng.xml | 2 + 19 files changed, 1204 insertions(+), 211 deletions(-) create mode 100644 components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/UserProfileExportDataHolder.java create mode 100644 components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/UserProfileExportServiceComponent.java create mode 100644 components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/model/LinkedAccount.java create mode 100644 components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/service/impl/LinkedAccountsProvider.java create mode 100644 components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/service/impl/UserProfileInformationProvider.java create mode 100644 components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/service/impl/LinkedAccountsProviderTest.java create mode 100644 components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/service/impl/UserProfileInformationProviderTest.java diff --git a/components/org.wso2.carbon.identity.user.export.core/pom.xml b/components/org.wso2.carbon.identity.user.export.core/pom.xml index 4b056e410e..b3a6656b99 100644 --- a/components/org.wso2.carbon.identity.user.export.core/pom.xml +++ b/components/org.wso2.carbon.identity.user.export.core/pom.xml @@ -140,6 +140,7 @@ org.wso2.carbon.user.core.*; version="${carbon.kernel.package.import.version.range}", org.wso2.carbon.context; version="${carbon.kernel.package.import.version.range}", org.wso2.carbon.consent.mgt.core.*; version="${carbon.consent.mgt.version.range}", + org.wso2.carbon.identity.user.profile.mgt.*; version="${carbon.identity.framework.imp.pkg.version.range}", !org.wso2.carbon.identity.user.export.core.internal, diff --git a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/UserProfileExportDataHolder.java b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/UserProfileExportDataHolder.java new file mode 100644 index 0000000000..ae6141338e --- /dev/null +++ b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/UserProfileExportDataHolder.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2023, 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.user.export.core.internal; + +import org.wso2.carbon.consent.mgt.core.ConsentManager; +import org.wso2.carbon.identity.user.export.core.service.UserInformationProvider; +import org.wso2.carbon.identity.user.profile.mgt.association.federation.FederatedAssociationManager; +import org.wso2.carbon.user.core.service.RealmService; + +import java.util.ArrayList; +import java.util.List; + +/** + * Data holder for User Profile Export service. + */ +public class UserProfileExportDataHolder { + + private static RealmService realmService; + private static FederatedAssociationManager federatedAssociationManager; + private static ConsentManager consentManager; + + public static List getUserInformationProviders() { + + return userInformationProviders; + } + + public static void setUserInformationProviders( + List userInformationProviders) { + + UserProfileExportDataHolder.userInformationProviders = userInformationProviders; + } + + private static List userInformationProviders = new ArrayList<>(); + + + /** + * Get RealmService instance. + * + * @return RealmService instance. + */ + public static RealmService getRealmService() { + + return realmService; + } + + /** + * Set RealmService instance. + * + * @param realmService RealmService instance. + */ + public static void setRealmService(RealmService realmService) { + + UserProfileExportDataHolder.realmService = realmService; + } + + /** + * Set FederatedAssociationManager instance. + * + * @param federatedAssociationManager FederatedAssociationManager instance. + */ + public static void setFederatedAssociationManager(FederatedAssociationManager federatedAssociationManager) { + + UserProfileExportDataHolder.federatedAssociationManager = federatedAssociationManager; + } + + /** + * Get FederatedAssociationManager instance. + * + * @return FederatedAssociationManager instance. + */ + public static FederatedAssociationManager getFederatedAssociationManager() { + + return federatedAssociationManager; + } + + /** + * Get consent manager instance. + * + * @return Consent Manager + */ + public static ConsentManager getConsentManager() { + + return consentManager; + } + + /** + * Set consent manager instance. + * + * @param consentManager consent manager + */ + public static void setConsentManager(ConsentManager consentManager) { + + UserProfileExportDataHolder.consentManager = consentManager; + } +} diff --git a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/UserProfileExportServiceComponent.java b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/UserProfileExportServiceComponent.java new file mode 100644 index 0000000000..6bc4f6fd85 --- /dev/null +++ b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/UserProfileExportServiceComponent.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2023, 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.user.export.core.internal; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.osgi.service.component.ComponentContext; +import org.osgi.service.component.annotations.Activate; +import org.osgi.service.component.annotations.Component; +import org.osgi.service.component.annotations.Deactivate; +import org.osgi.service.component.annotations.Reference; +import org.osgi.service.component.annotations.ReferenceCardinality; +import org.osgi.service.component.annotations.ReferencePolicy; +import org.wso2.carbon.consent.mgt.core.ConsentManager; +import org.wso2.carbon.identity.user.export.core.internal.service.impl.BasicUserInformationProvider; +import org.wso2.carbon.identity.user.export.core.internal.service.impl.ConsentInformationProvider; +import org.wso2.carbon.identity.user.export.core.internal.service.impl.SecurityInformationProvider; +import org.wso2.carbon.identity.user.export.core.internal.service.impl.UserInformationServiceImpl; +import org.wso2.carbon.identity.user.export.core.service.UserInformationProvider; +import org.wso2.carbon.identity.user.export.core.service.UserInformationService; +import org.wso2.carbon.identity.user.export.core.service.impl.LinkedAccountsProvider; +import org.wso2.carbon.identity.user.export.core.service.impl.UserProfileInformationProvider; +import org.wso2.carbon.identity.user.profile.mgt.association.federation.FederatedAssociationManager; +import org.wso2.carbon.user.core.service.RealmService; + +/** + * User profile export service component. + */ +@Component( + name = "user.profile.export.service", + immediate = true +) +public class UserProfileExportServiceComponent { + + private static final Log LOG = LogFactory.getLog(UserProfileExportServiceComponent.class); + + @Activate + protected void activate(ComponentContext ctxt) { + + try { + UserInformationServiceImpl userInformationService = new UserInformationServiceImpl(); + ctxt.getBundleContext().registerService(UserInformationService.class.getName(), userInformationService, + null); + + UserProfileInformationProvider userProfileInfoProvider = new UserProfileInformationProvider(); + ctxt.getBundleContext().registerService(UserInformationProvider.class.getName(), userProfileInfoProvider, + null); + + LinkedAccountsProvider federatedAccountsProvider = new LinkedAccountsProvider(); + ctxt.getBundleContext().registerService(UserInformationProvider.class.getName(), federatedAccountsProvider, + null); + + BasicUserInformationProvider basicUserInformationProvider = new BasicUserInformationProvider(); + ctxt.getBundleContext().registerService(UserInformationProvider.class.getName(), basicUserInformationProvider, + null); + + ConsentInformationProvider consentInformationProvider = new ConsentInformationProvider(); + ctxt.getBundleContext().registerService(UserInformationProvider.class.getName(), consentInformationProvider, + null); + + SecurityInformationProvider securityInformationProvider = new SecurityInformationProvider(); + ctxt.getBundleContext().registerService(UserInformationProvider.class.getName(), securityInformationProvider, + null); + } catch (Exception e) { + LOG.error(e.getMessage(), e); + } + } + + @Deactivate + protected void deactivate(ComponentContext ctxt) { + + LOG.debug("User profile export service bundle is deactivated."); + } + + @Reference( + name = "user.realm.service", + service = RealmService.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetRealmService" + ) + protected void setRealmService(RealmService rlmService) { + + if (rlmService != null) { + LOG.debug("Realm service initialized."); + } + UserProfileExportDataHolder.setRealmService(rlmService); + } + + protected void unsetRealmService(RealmService realmService) { + + UserProfileExportDataHolder.setRealmService(null); + } + + + @Reference( + name = "federation.association.manager.component", + service = FederatedAssociationManager.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetFederatedAssociationManagerService" + ) + protected void setFederatedAssociationManagerService(FederatedAssociationManager + federatedAssociationManagerService) { + + UserProfileExportDataHolder.setFederatedAssociationManager(federatedAssociationManagerService); + } + + protected void unsetFederatedAssociationManagerService(FederatedAssociationManager + federatedAssociationManagerService) { + + UserProfileExportDataHolder.setFederatedAssociationManager(null); + } + + + @Reference( + name = "consent.manager", + service = ConsentManager.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetConsentManager") + public void setConsentManager(ConsentManager consentManager) { + + if (LOG.isDebugEnabled()) { + LOG.debug("Setting the ConsentManager Service"); + } + UserProfileExportDataHolder.setConsentManager(consentManager); + } + + public void unsetConsentManager(ConsentManager consentManager) { + + if (LOG.isDebugEnabled()) { + LOG.debug("Unsetting the ConsentManager Service"); + } + UserProfileExportDataHolder.setConsentManager(null); + } + + @Reference( + name = "user.export.attribute.provider", + service = UserInformationProvider.class, + cardinality = ReferenceCardinality.MULTIPLE, + policy = ReferencePolicy.DYNAMIC, + unbind = "unsetUserAttributeProvider" + ) + public void setUserAttributeProvider(UserInformationProvider userInformationProvider) { + UserProfileExportDataHolder.getUserInformationProviders().add(userInformationProvider); + } + + public void unsetUserAttributeProvider(UserInformationProvider userInformationProvider) { + UserProfileExportDataHolder.getUserInformationProviders().remove(userInformationProvider); + } + +} diff --git a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/AbstractUserInformationProvider.java b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/AbstractUserInformationProvider.java index 9af9866d5e..50b257b948 100644 --- a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/AbstractUserInformationProvider.java +++ b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/AbstractUserInformationProvider.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, + * 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 @@ -19,9 +19,38 @@ package org.wso2.carbon.identity.user.export.core.internal.service.impl; import org.wso2.carbon.identity.core.handler.AbstractIdentityHandler; +import org.wso2.carbon.identity.user.export.core.UserExportException; +import org.wso2.carbon.identity.user.export.core.internal.UserProfileExportDataHolder; import org.wso2.carbon.identity.user.export.core.service.UserInformationProvider; +import org.wso2.carbon.user.api.UserRealm; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.core.UserStoreManager; +import org.wso2.carbon.user.core.common.AbstractUserStoreManager; +import org.wso2.carbon.user.core.service.RealmService; public abstract class AbstractUserInformationProvider extends AbstractIdentityHandler implements UserInformationProvider { + + protected static final String WSO2_CLAIM_URI = "http://wso2.org/claims/"; + protected static final String WSO2_IDENTITY_CLAIM_URI = "http://wso2.org/claims/identity/"; + protected static final String WSO2_RUN_TIME_CLAIM_URI = "http://wso2.org/claims/runtime/"; + + protected UserStoreManager getUserStoreManager(int tenantId, String userStoreDomain) throws UserExportException { + + AbstractUserStoreManager userStoreManager; + try { + RealmService realmService = UserProfileExportDataHolder.getRealmService(); + UserRealm userRealm = realmService.getTenantUserRealm(tenantId); + userStoreManager = (AbstractUserStoreManager) userRealm.getUserStoreManager(); + } catch (UserStoreException e) { + throw new UserExportException("Error while getting userstore", e); + } + return userStoreManager.getSecondaryUserStoreManager(userStoreDomain); + } + + protected String getTenantDomain(int tenantId) throws UserStoreException { + + return UserProfileExportDataHolder.getRealmService().getTenantManager().getDomain(tenantId); + } } diff --git a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/BasicUserInformationProvider.java b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/BasicUserInformationProvider.java index f0aa3ae716..6f59487521 100644 --- a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/BasicUserInformationProvider.java +++ b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/BasicUserInformationProvider.java @@ -21,19 +21,13 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; import org.wso2.carbon.identity.core.util.IdentityUtil; import org.wso2.carbon.identity.user.export.core.UserExportException; import org.wso2.carbon.identity.user.export.core.dto.UserInformationDTO; -import org.wso2.carbon.identity.user.export.core.service.UserInformationProvider; +import org.wso2.carbon.identity.user.export.core.internal.UserProfileExportDataHolder; import org.wso2.carbon.user.api.Claim; import org.wso2.carbon.user.api.UserStoreException; -import org.wso2.carbon.user.api.UserStoreManager; import org.wso2.carbon.user.core.UserRealm; -import org.wso2.carbon.user.core.service.RealmService; import java.util.ArrayList; import java.util.Arrays; @@ -44,18 +38,12 @@ /** * Provide basic information of user. */ -@Component( - name = "org.wso2.carbon.user.export.basic", - immediate = true, - service = UserInformationProvider.class -) public class BasicUserInformationProvider extends AbstractUserInformationProvider { private static final Log log = LogFactory.getLog(BasicUserInformationProvider.class); protected static final String CHALLENGE_QUESTION_URIS_CLAIM = "http://wso2.org/claims/challengeQuestionUris"; protected static final String QUESTION_CHALLENGE_SEPARATOR = "Recovery.Question.Password.Separator"; protected static final String DEFAULT_CHALLENGE_QUESTION_SEPARATOR = "!"; - protected RealmService realmService; @Override public UserInformationDTO getRetainedUserInformation(String username, String userStoreDomain, int tenantId) @@ -109,28 +97,12 @@ protected List getChallengeQuestionUris(String challengeQuestionUrisClai } } - protected UserStoreManager getUserStoreManager(int tenantId, String userStoreDomain) throws UserExportException { - - UserStoreManager userStoreManager; - try { - String tenantDomain = realmService.getTenantManager().getDomain(tenantId); - userStoreManager = getUserRealm(tenantDomain).getUserStoreManager().getSecondaryUserStoreManager - (userStoreDomain); - } catch (UserStoreException e) { - throw new UserExportException("Error while retrieving the user store manager.", e); - } - if (log.isDebugEnabled()) { - log.debug("Retrieved user store manager for tenant id: " + tenantId); - } - return userStoreManager; - } - protected UserRealm getUserRealm(String tenantDomain) throws UserExportException { UserRealm realm; try { - int tenantId = realmService.getTenantManager().getTenantId(tenantDomain); - realm = (UserRealm) realmService.getTenantUserRealm(tenantId); + int tenantId = UserProfileExportDataHolder.getRealmService().getTenantManager().getTenantId(tenantDomain); + realm = (UserRealm) UserProfileExportDataHolder.getRealmService().getTenantUserRealm(tenantId); } catch (UserStoreException e) { throw new UserExportException( "Error occurred while retrieving the Realm for " + tenantDomain + " to handle claims", e); @@ -147,26 +119,4 @@ protected String challengeQuestionSeparator() { } return challengeQuestionSeparator; } - - @Reference( - name = "user.realmservice.default", - service = org.wso2.carbon.user.core.service.RealmService.class, - cardinality = ReferenceCardinality.MANDATORY, - policy = ReferencePolicy.DYNAMIC, - unbind = "unsetRealmService") - public void setRealmService(RealmService realmService) { - - if (log.isDebugEnabled()) { - log.debug("Setting the Realm Service"); - } - this.realmService = realmService; - } - - public void unsetRealmService(RealmService realmService) { - - if (log.isDebugEnabled()) { - log.debug("Unsetting the Realm Service"); - } - this.realmService = null; - } } diff --git a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/ConsentInformationProvider.java b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/ConsentInformationProvider.java index 47bca09c85..9fb8bea886 100644 --- a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/ConsentInformationProvider.java +++ b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/ConsentInformationProvider.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2018, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, + * 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 @@ -20,11 +20,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; -import org.wso2.carbon.consent.mgt.core.ConsentManager; import org.wso2.carbon.consent.mgt.core.constant.ConsentConstants; import org.wso2.carbon.consent.mgt.core.exception.ConsentManagementException; import org.wso2.carbon.consent.mgt.core.model.Receipt; @@ -32,10 +27,9 @@ import org.wso2.carbon.identity.user.export.core.UserExportException; import org.wso2.carbon.identity.user.export.core.dto.ConsentReceiptDTO; import org.wso2.carbon.identity.user.export.core.dto.UserInformationDTO; -import org.wso2.carbon.identity.user.export.core.service.UserInformationProvider; +import org.wso2.carbon.identity.user.export.core.internal.UserProfileExportDataHolder; import org.wso2.carbon.identity.user.export.core.utils.Utils; import org.wso2.carbon.user.api.UserStoreException; -import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.user.core.util.UserCoreUtil; import java.util.ArrayList; @@ -44,16 +38,9 @@ /** * Provide consent related information of user */ -@Component( - name = "org.wso2.carbon.user.export.consent", - immediate = true, - service = UserInformationProvider.class -) public class ConsentInformationProvider extends AbstractUserInformationProvider { - private static final Log log = LogFactory.getLog(ConsentInformationProvider.class); - private ConsentManager consentManager; - private RealmService realmService; + private static final Log LOG = LogFactory.getLog(ConsentInformationProvider.class); @Override public UserInformationDTO getRetainedUserInformation(String username, String userStoreDomain, int tenantId) @@ -63,17 +50,17 @@ public UserInformationDTO getRetainedUserInformation(String username, String use List receipts = new ArrayList<>(); int limit = 100; int offset = 0; - String tenantDomain = realmService.getTenantManager().getDomain(tenantId); + String tenantDomain = UserProfileExportDataHolder.getRealmService().getTenantManager().getDomain(tenantId); List receiptListResponses; do { - receiptListResponses = consentManager.searchReceipts(limit, offset, UserCoreUtil - .addDomainToName(username, userStoreDomain), tenantDomain, - null, ConsentConstants.ACTIVE_STATE); + receiptListResponses = UserProfileExportDataHolder.getConsentManager() + .searchReceipts(limit, offset, UserCoreUtil.addDomainToName(username, userStoreDomain), + tenantDomain, null, ConsentConstants.ACTIVE_STATE); for (ReceiptListResponse receiptListResponse : receiptListResponses) { String receiptId = receiptListResponse.getConsentReceiptId(); - Receipt receipt = consentManager.getReceipt(receiptId); + Receipt receipt = UserProfileExportDataHolder.getConsentManager().getReceipt(receiptId); receipts.add(Utils.getConsentReceiptDTO(receipt)); } offset += limit; @@ -96,47 +83,4 @@ public String getType() { return "consents"; } - @Reference( - name = "user.realmservice.default", - service = org.wso2.carbon.user.core.service.RealmService.class, - cardinality = ReferenceCardinality.MANDATORY, - policy = ReferencePolicy.DYNAMIC, - unbind = "unsetRealmService") - public void setRealmService(RealmService realmService) { - - if (log.isDebugEnabled()) { - log.info("Setting the Realm Service"); - } - this.realmService = realmService; - } - - public void unsetRealmService(RealmService realmService) { - - if (log.isDebugEnabled()) { - log.info("Unsetting the Realm Service"); - } - this.realmService = null; - } - - @Reference( - name = "consent.manager", - service = ConsentManager.class, - cardinality = ReferenceCardinality.MANDATORY, - policy = ReferencePolicy.DYNAMIC, - unbind = "unsetConsentManager") - public void setConsentManager(ConsentManager consentManager) { - - if (log.isDebugEnabled()) { - log.debug("Setting the ConsentManager Service"); - } - this.consentManager = consentManager; - } - - public void unsetConsentManager(ConsentManager consentManager) { - - if (log.isDebugEnabled()) { - log.debug("Unsetting the ConsentManager Service"); - } - this.consentManager = null; - } } diff --git a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/SecurityInformationProvider.java b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/SecurityInformationProvider.java index 4539bde636..3ad8b1a59d 100644 --- a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/SecurityInformationProvider.java +++ b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/SecurityInformationProvider.java @@ -20,18 +20,12 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; import org.wso2.carbon.identity.user.export.core.UserExportException; import org.wso2.carbon.identity.user.export.core.dto.SecurityInformationDTO; import org.wso2.carbon.identity.user.export.core.dto.UserInformationDTO; -import org.wso2.carbon.identity.user.export.core.service.UserInformationProvider; import org.wso2.carbon.user.api.Claim; import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.api.UserStoreManager; -import org.wso2.carbon.user.core.service.RealmService; import java.util.List; import java.util.Map; @@ -39,14 +33,9 @@ /** * Provide basic information of user. */ -@Component( - name = "org.wso2.carbon.user.export.security", - immediate = true, - service = UserInformationProvider.class -) public class SecurityInformationProvider extends BasicUserInformationProvider { - private static final Log log = LogFactory.getLog(SecurityInformationProvider.class); + private static final Log LOG = LogFactory.getLog(SecurityInformationProvider.class); @Override public UserInformationDTO getRetainedUserInformation(String username, String userStoreDomain, int tenantId) @@ -89,8 +78,8 @@ public UserInformationDTO getRetainedUserInformation(String username, String use return new UserInformationDTO(securityInformationDTO); } else { - if (log.isDebugEnabled()) { - log.debug("Challenge question claim is not available in the tenant: " + tenantId); + if (LOG.isDebugEnabled()) { + LOG.debug("Challenge question claim is not available in the tenant: " + tenantId); } } return new UserInformationDTO(); @@ -101,26 +90,4 @@ public String getType() { return "security"; } - @Reference( - name = "user.realmservice.default", - service = org.wso2.carbon.user.core.service.RealmService.class, - cardinality = ReferenceCardinality.MANDATORY, - policy = ReferencePolicy.DYNAMIC, - unbind = "unsetRealmService") - public void setRealmService(RealmService realmService) { - - if (log.isDebugEnabled()) { - log.debug("Setting the Realm Service"); - } - this.realmService = realmService; - } - - public void unsetRealmService(RealmService realmService) { - - if (log.isDebugEnabled()) { - log.debug("Unsetting the Realm Service"); - } - this.realmService = null; - } - } diff --git a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/UserInformationServiceImpl.java b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/UserInformationServiceImpl.java index 03733c7ff3..db75f6e99c 100644 --- a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/UserInformationServiceImpl.java +++ b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/UserInformationServiceImpl.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2018, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, + * 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 @@ -18,40 +18,31 @@ package org.wso2.carbon.identity.user.export.core.internal.service.impl; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferenceCardinality; -import org.osgi.service.component.annotations.ReferencePolicy; import org.wso2.carbon.identity.user.export.core.UserExportException; import org.wso2.carbon.identity.user.export.core.dto.UserInformationDTO; +import org.wso2.carbon.identity.user.export.core.internal.UserProfileExportDataHolder; import org.wso2.carbon.identity.user.export.core.service.UserInformationProvider; import org.wso2.carbon.identity.user.export.core.service.UserInformationService; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; import java.util.Map; /** * {@inheritDoc} */ -@Component( - name = "org.wso2.carbon.user.export.service", - immediate = true -) public class UserInformationServiceImpl implements UserInformationService { - private List userInformationProviders = new ArrayList<>(); @Override public Map getRetainedUserInformation(String username, String userStoreDomain, int tenantId) throws UserExportException { Map userInformation = new HashMap<>(); - for (UserInformationProvider userInformationProvider : userInformationProviders) { + for (UserInformationProvider userInformationProvider : + UserProfileExportDataHolder.getUserInformationProviders()) { if (userInformationProvider.isEnabled()) { - UserInformationDTO retainedUserInformation = userInformationProvider.getRetainedUserInformation - (username, userStoreDomain, tenantId); + UserInformationDTO retainedUserInformation = + userInformationProvider.getRetainedUserInformation(username, userStoreDomain, tenantId); if (retainedUserInformation != null && retainedUserInformation.isInformationAvailable()) { String type = userInformationProvider.getType(); userInformation.put(type, retainedUserInformation.getData()); @@ -60,19 +51,4 @@ public Map getRetainedUserInformation(String username, String us } return userInformation; } - - @Reference( - name = "user.export.attribute.provider", - service = UserInformationProvider.class, - cardinality = ReferenceCardinality.MULTIPLE, - policy = ReferencePolicy.DYNAMIC, - unbind = "unsetUserAttributeProvider" - ) - public void setUserAttributeProvider(UserInformationProvider userInformationProvider) { - userInformationProviders.add(userInformationProvider); - } - - public void unsetUserAttributeProvider(UserInformationProvider userInformationProvider) { - userInformationProviders.remove(userInformationProvider); - } } diff --git a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/model/LinkedAccount.java b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/model/LinkedAccount.java new file mode 100644 index 0000000000..38d3d86b1f --- /dev/null +++ b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/model/LinkedAccount.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2023, 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.user.export.core.model; + +/** + * Data model for linked accounts. + */ +public class LinkedAccount { + + private final String connection; + private final String connectionId; + private final String linkedAccountId; + private final boolean isExternalConnection; + + /** + * @param connectionName Name of the IDP. + * @param connectionId Unique Id of the IDP + * @param linkedAccountId User's linked account ID. + * @param isExternalConnection is social connection or not. + */ + public LinkedAccount(String connectionName, String connectionId, String linkedAccountId, + boolean isExternalConnection) { + + this.connection = connectionName; + this.connectionId = connectionId; + this.linkedAccountId = linkedAccountId; + this.isExternalConnection = isExternalConnection; + } + + /** + * Return the IdP name. + * + * @return connection Name; + */ + public String getConnection() { + + return this.connection; + } + + /** + * Return the unique ID of the IdP connection. + * + * @return connection ID. + */ + public String getConnectionId() { + + return this.connectionId; + } + + /** + * Return true if this is an external IdP connection. + * + * @return true if this is an external IdP connection. + */ + public boolean getIsExternalConnection() { + + return this.isExternalConnection; + } + + /** + * Return the userId of the linked account. + * + * @return linkedAccountId + */ + public String getLinkedAccountId() { + + return this.linkedAccountId; + } +} diff --git a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/service/impl/LinkedAccountsProvider.java b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/service/impl/LinkedAccountsProvider.java new file mode 100644 index 0000000000..df578cdaac --- /dev/null +++ b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/service/impl/LinkedAccountsProvider.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2023, 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.user.export.core.service.impl; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.common.model.User; +import org.wso2.carbon.identity.user.export.core.UserExportException; +import org.wso2.carbon.identity.user.export.core.dto.UserInformationDTO; +import org.wso2.carbon.identity.user.export.core.internal.UserProfileExportDataHolder; +import org.wso2.carbon.identity.user.export.core.internal.service.impl.AbstractUserInformationProvider; +import org.wso2.carbon.identity.user.export.core.model.LinkedAccount; +import org.wso2.carbon.identity.user.profile.mgt.association.federation.FederatedAssociationManager; +import org.wso2.carbon.identity.user.profile.mgt.association.federation.exception.FederatedAssociationManagerException; +import org.wso2.carbon.identity.user.profile.mgt.association.federation.model.AssociatedIdentityProvider; +import org.wso2.carbon.identity.user.profile.mgt.association.federation.model.FederatedAssociation; +import org.wso2.carbon.user.api.UserStoreException; + +import java.util.ArrayList; +import java.util.List; + +/** + * This is used to provide the details about the linked accounts of user in the user profile export API. + */ +public class LinkedAccountsProvider extends AbstractUserInformationProvider { + + private static final Log LOG = LogFactory.getLog(LinkedAccountsProvider.class); + + public LinkedAccountsProvider() { + + } + + @Override + public UserInformationDTO getRetainedUserInformation(String username, String userStoreDomain, int tenantId) + throws UserExportException { + + FederatedAssociationManager federatedAssociationManager = UserProfileExportDataHolder + .getFederatedAssociationManager(); + + try { + List linkedAccounts = new ArrayList<>(); + FederatedAssociation[] federatedAssociations = federatedAssociationManager.getFederatedAssociationsOfUser + (getUser(username, userStoreDomain, tenantId)); + + if (ArrayUtils.isEmpty(federatedAssociations)) { + return new UserInformationDTO(); + } + + for (FederatedAssociation federatedAssociation : federatedAssociations) { + if (federatedAssociation == null) { + break; + } + AssociatedIdentityProvider idp = federatedAssociation.getIdp(); + if (idp != null) { + LinkedAccount linkedAccount = new LinkedAccount(idp.getName(), idp.getId(), + federatedAssociation.getFederatedUserId(), true); + linkedAccounts.add(linkedAccount); + } else { + LOG.debug("Linked Connection is null"); + } + } + return new UserInformationDTO(linkedAccounts); + } catch (FederatedAssociationManagerException | UserStoreException e) { + throw new UserExportException("Error while getting federated associations", e); + } + } + + @Override + public String getType() { + + return "linked_accounts"; + } + + private User getUser(String username, String userStoreDomain, int tenantId) throws UserStoreException { + + User user = new AuthenticatedUser(); + user.setUserName(username); + user.setUserStoreDomain(userStoreDomain); + user.setTenantDomain(getTenantDomain(tenantId)); + return user; + } +} diff --git a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/service/impl/UserProfileInformationProvider.java b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/service/impl/UserProfileInformationProvider.java new file mode 100644 index 0000000000..f5d1513be8 --- /dev/null +++ b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/service/impl/UserProfileInformationProvider.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2023, 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.user.export.core.service.impl; + +import org.apache.commons.lang.ArrayUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.wso2.carbon.identity.user.export.core.UserExportException; +import org.wso2.carbon.identity.user.export.core.dto.UserInformationDTO; +import org.wso2.carbon.identity.user.export.core.internal.UserProfileExportDataHolder; +import org.wso2.carbon.identity.user.export.core.internal.service.impl.AbstractUserInformationProvider; +import org.wso2.carbon.identity.user.export.core.utils.Utils; +import org.wso2.carbon.user.api.Claim; +import org.wso2.carbon.user.api.ClaimMapping; +import org.wso2.carbon.user.core.UserStoreException; +import org.wso2.carbon.user.core.UserStoreManager; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * This is used to provide the profile information of user in the user profile export API. + */ +public class UserProfileInformationProvider extends AbstractUserInformationProvider { + + private static final Log LOG = LogFactory.getLog(UserProfileInformationProvider.class); + private static final String ROLES_URIS_CLAIM = "roles"; + + @Override + public UserInformationDTO getRetainedUserInformation(String username, String userStoreDomain, int tenantId) + throws UserExportException { + + Claim[] userClaimValues; + UserStoreManager userStoreManager; + try { + userStoreManager = getUserStoreManager(tenantId, userStoreDomain); + userClaimValues = userStoreManager.getUserClaimValues(username, null); + } catch (UserStoreException e) { + throw new UserExportException("Error while getting user claims", e); + } + + if (ArrayUtils.isEmpty(userClaimValues)) { + return new UserInformationDTO(); + } + + Map userProfileAttributes = new HashMap<>(); + List claimsToInclude = getClaimsToInclude(tenantId); + List claimsToExclude = Utils.getRestrictedClaims(); + for (Claim claim : userClaimValues) { + String claimURI = claim.getClaimUri(); + String claimValue = claim.getValue(); + String claimName; + if (!claimsToInclude.contains(claimURI) || claimsToExclude.contains(claimURI)) { + // If the claim is not configured as supported by default in the org level or configured in the toml + // config, + // or configured as a restricted claim, + // those won't be exposed in the profile API. + continue; + } + if (!claimURI.contains(WSO2_IDENTITY_CLAIM_URI)) { + claimName = claimURI.replace(WSO2_CLAIM_URI, ""); + } else { + claimName = claimURI.replace(WSO2_IDENTITY_CLAIM_URI, ""); + } + userProfileAttributes.put(claimName, claimValue); + } + return new UserInformationDTO(userProfileAttributes); + } + + + @Override + public String getType() { + + return "user_profile"; + } + + /** + * Get all the claims to include in the user profile export API. This will return the list of the claims that + * are enabled via the toml config and user profile. + * + * @param tenantId tenant Id + * @return list of all the claims to include in the user profile export API + */ + private List getClaimsToInclude(int tenantId) { + + List supportedClaims = getSupportedClaims(tenantId); + List additionalClaimsToInclude = Utils.getAdditionalClaimsToInclude(); + + return Stream.concat(supportedClaims.stream(), additionalClaimsToInclude.stream()) + .distinct() + .collect(Collectors.toList()); + } + + /** + * Get the claims that are enabled in the user profile. + * + * @param tenantId tenant Id. + * @return List of the claims that are enabled in the user profile. + */ + private List getSupportedClaims(int tenantId) { + + ClaimMapping[] claims; + List supportedClaims = new ArrayList<>(); + + try { + claims = UserProfileExportDataHolder.getRealmService().getTenantUserRealm(tenantId).getClaimManager() + .getAllSupportClaimMappingsByDefault(); + for (ClaimMapping claimMapping : claims) { + if (claimMapping.getClaim().getClaimUri().contains(WSO2_IDENTITY_CLAIM_URI) || + claimMapping.getClaim().getClaimUri().contains(WSO2_RUN_TIME_CLAIM_URI)) { + if (LOG.isDebugEnabled()) { + LOG.debug("Claim URI: " + claimMapping.getClaim().getClaimUri() + " is either Identity claim" + + " or a runtime claim. It should be enabled via config. Hence ignoring this claim"); + } + continue; + } + supportedClaims.add(claimMapping.getClaim().getClaimUri()); + } + return supportedClaims; + } catch (org.wso2.carbon.user.api.UserStoreException e) { + throw new RuntimeException(e); + } + } +} diff --git a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/utils/Utils.java b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/utils/Utils.java index 3187902871..063c4773c4 100644 --- a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/utils/Utils.java +++ b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/utils/Utils.java @@ -1,8 +1,8 @@ /* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2018, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, - * Version 2.0 (the "License"); you may not use this file except + * 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 * @@ -19,6 +19,7 @@ package org.wso2.carbon.identity.user.export.core.utils; import org.wso2.carbon.consent.mgt.core.model.Receipt; +import org.wso2.carbon.identity.core.util.IdentityConfigParser; import org.wso2.carbon.identity.user.export.core.dto.AddressDTO; import org.wso2.carbon.identity.user.export.core.dto.ConsentReceiptDTO; import org.wso2.carbon.identity.user.export.core.dto.PiiCategoryDTO; @@ -26,6 +27,10 @@ import org.wso2.carbon.identity.user.export.core.dto.PurposeDTO; import org.wso2.carbon.identity.user.export.core.dto.ServiceDTO; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; public class Utils { @@ -99,4 +104,44 @@ public static ConsentReceiptDTO getConsentReceiptDTO(Receipt receipt) { }).collect(Collectors.toList())); return consentReceiptDTO; } + + /** + * Return the additional claims that need to be added in the user profile export API. + * By default, User profile export API shows the claims that are exposed in the user profile UI view. If there are + * any additional claims required in the export API, they can be configured in the server level via this config. + * + * @return The list of additional claims. + */ + public static List getAdditionalClaimsToInclude() { + + return getConfigs("UserProfileExport.AdditionalClaims.AdditionalClaim"); + } + + /** + * Return the claims that need to be restricted in the user profile export API. + * By default, User profile export API shows the claims that are exposed in the user profile UI view. If there are + * any claims required to be excluded in the export API, they can be configured in the server level via this config. + * + * @return The list of restricted claims. + */ + public static List getRestrictedClaims() { + + return getConfigs("UserProfileExport.RestrictedClaims.RestrictedClaim"); + } + + private static List getConfigs(String configPath) { + + Map configuration = IdentityConfigParser.getInstance().getConfiguration(); + Object elements = configuration.get(configPath); + if (elements != null) { + List configValues = new ArrayList<>(); + if (elements instanceof List) { + configValues.addAll((List) elements); + } else { + configValues.add(elements.toString()); + } + return configValues; + } + return Collections.emptyList(); + } } diff --git a/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/BasicUserInformationProviderTest.java b/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/BasicUserInformationProviderTest.java index 536696ef5b..dc97b718b2 100644 --- a/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/BasicUserInformationProviderTest.java +++ b/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/BasicUserInformationProviderTest.java @@ -22,11 +22,13 @@ import org.testng.annotations.Test; import org.wso2.carbon.identity.user.export.core.UserExportException; import org.wso2.carbon.identity.user.export.core.dto.UserInformationDTO; +import org.wso2.carbon.identity.user.export.core.internal.UserProfileExportDataHolder; import org.wso2.carbon.user.core.UserCoreConstants; import org.wso2.carbon.user.core.UserRealm; import org.wso2.carbon.user.core.UserStoreException; import org.wso2.carbon.user.core.UserStoreManager; import org.wso2.carbon.user.core.claim.Claim; +import org.wso2.carbon.user.core.common.AbstractUserStoreManager; import org.wso2.carbon.user.core.service.RealmService; import org.wso2.carbon.user.core.tenant.TenantManager; import org.wso2.carbon.utils.multitenancy.MultitenantConstants; @@ -57,7 +59,7 @@ public void testGetUserAttributes() throws Exception { when(tenantManager.getDomain(anyInt())).thenReturn(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); UserRealm userRealm = mock(UserRealm.class); - UserStoreManager userStoreManager = mock(UserStoreManager.class); + AbstractUserStoreManager userStoreManager = mock(AbstractUserStoreManager.class); UserStoreManager secUserStoreManager = mock(UserStoreManager.class); when(userStoreManager.getSecondaryUserStoreManager(anyString())).thenReturn(secUserStoreManager); @@ -69,7 +71,7 @@ public void testGetUserAttributes() throws Exception { when(secUserStoreManager.getUserClaimValues(USERNAME_CLAIM_VALUE, null)).thenReturn(claims); BasicUserInformationProvider basicUserInformationProvider = new BasicUserInformationProvider(); - basicUserInformationProvider.setRealmService(realmService); + UserProfileExportDataHolder.setRealmService(realmService); UserInformationDTO userAttributesObj = basicUserInformationProvider.getRetainedUserInformation(USERNAME_CLAIM_VALUE, UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME, -1234); if (userAttributesObj != null && userAttributesObj.getData() instanceof Map) { @@ -91,7 +93,7 @@ public void testGetUserAttributesEmpty() throws Exception { when(tenantManager.getDomain(anyInt())).thenReturn(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); UserRealm userRealm = mock(UserRealm.class); - UserStoreManager userStoreManager = mock(UserStoreManager.class); + AbstractUserStoreManager userStoreManager = mock(AbstractUserStoreManager.class); UserStoreManager secUserStoreManager = mock(UserStoreManager.class); when(userStoreManager.getSecondaryUserStoreManager(anyString())).thenReturn(secUserStoreManager); @@ -102,7 +104,7 @@ public void testGetUserAttributesEmpty() throws Exception { when(secUserStoreManager.getUserClaimValues(USERNAME_CLAIM_VALUE, null)).thenReturn(null); BasicUserInformationProvider basicUserInformationProvider = new BasicUserInformationProvider(); - basicUserInformationProvider.setRealmService(realmService); + UserProfileExportDataHolder.setRealmService(realmService); UserInformationDTO userAttributesObj = basicUserInformationProvider.getRetainedUserInformation(USERNAME_CLAIM_VALUE, UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME, -1234); if (userAttributesObj.isInformationAvailable()) { @@ -133,7 +135,7 @@ public void testGetUserAttributesExceptionOnGetRealmByTenantDomain() throws Exce when(secUserStoreManager.getUserClaimValues(USERNAME_CLAIM_VALUE, null)).thenReturn(claims); BasicUserInformationProvider basicUserInformationProvider = new BasicUserInformationProvider(); - basicUserInformationProvider.setRealmService(realmService); + UserProfileExportDataHolder.setRealmService(realmService); basicUserInformationProvider.getRetainedUserInformation(USERNAME_CLAIM_VALUE, UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME, -1234); } @@ -160,7 +162,7 @@ public void testGetUserAttributesExceptionOnGetUserStoreManager() throws Excepti when(secUserStoreManager.getUserClaimValues(USERNAME_CLAIM_VALUE, null)).thenReturn(claims); BasicUserInformationProvider basicUserInformationProvider = new BasicUserInformationProvider(); - basicUserInformationProvider.setRealmService(realmService); + UserProfileExportDataHolder.setRealmService(realmService); basicUserInformationProvider.getRetainedUserInformation(USERNAME_CLAIM_VALUE, UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME, -1234); } @@ -174,7 +176,7 @@ public void testGetUserAttributesExceptionOnGetUserClaimValues() throws Exceptio when(tenantManager.getDomain(anyInt())).thenReturn(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME); UserRealm userRealm = mock(UserRealm.class); - UserStoreManager userStoreManager = mock(UserStoreManager.class); + AbstractUserStoreManager userStoreManager = mock(AbstractUserStoreManager.class); UserStoreManager secUserStoreManager = mock(UserStoreManager.class); when(userStoreManager.getSecondaryUserStoreManager(anyString())).thenReturn(secUserStoreManager); @@ -185,7 +187,7 @@ public void testGetUserAttributesExceptionOnGetUserClaimValues() throws Exceptio when(secUserStoreManager.getUserClaimValues(anyString(), isNull())).thenThrow(new UserStoreException()); BasicUserInformationProvider basicUserInformationProvider = new BasicUserInformationProvider(); - basicUserInformationProvider.setRealmService(realmService); + UserProfileExportDataHolder.setRealmService(realmService); basicUserInformationProvider.getRetainedUserInformation(USERNAME_CLAIM_VALUE, UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME, -1234); } diff --git a/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/ConsentInformationProviderTest.java b/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/ConsentInformationProviderTest.java index ddad96bf94..386cdcd4ba 100644 --- a/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/ConsentInformationProviderTest.java +++ b/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/ConsentInformationProviderTest.java @@ -1,3 +1,21 @@ +/* + * Copyright (c) 2018, 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.user.export.core.internal.service.impl; import org.testng.Assert; @@ -9,6 +27,7 @@ import org.wso2.carbon.identity.user.export.core.UserExportException; import org.wso2.carbon.identity.user.export.core.dto.ConsentReceiptDTO; import org.wso2.carbon.identity.user.export.core.dto.UserInformationDTO; +import org.wso2.carbon.identity.user.export.core.internal.UserProfileExportDataHolder; import org.wso2.carbon.user.api.UserStoreException; import org.wso2.carbon.user.core.UserCoreConstants; import org.wso2.carbon.user.core.service.RealmService; @@ -46,14 +65,14 @@ public void testGetRetainedUserInformation() throws Exception { when(consentManager.searchReceipts(eq(100), eq(0), anyString(), anyString(), isNull(), anyString())) .thenReturn(receiptListResponses); when(consentManager.searchReceipts(eq(100), eq(100), anyString(), anyString(), isNull(), anyString())) - .thenReturn(new ArrayList()); + .thenReturn(new ArrayList<>()); Receipt mockReceipt = mock(Receipt.class); when(mockReceipt.getPiiPrincipalId()).thenReturn(USERNAME_CLAIM_VALUE); when(consentManager.getReceipt(anyString())).thenReturn(mockReceipt); ConsentInformationProvider consentInformationProvider = new ConsentInformationProvider(); - consentInformationProvider.setRealmService(realmService); - consentInformationProvider.setConsentManager(consentManager); + UserProfileExportDataHolder.setRealmService(realmService); + UserProfileExportDataHolder.setConsentManager(consentManager); UserInformationDTO retainedUserInformationObj = consentInformationProvider.getRetainedUserInformation (USERNAME_CLAIM_VALUE, UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME, -1234); @@ -89,8 +108,8 @@ public void testGetRetainedUserInformationSearchReceiptsException() throws Excep when(consentManager.getReceipt(anyString())).thenReturn(mockReceipt); ConsentInformationProvider consentInformationProvider = new ConsentInformationProvider(); - consentInformationProvider.setRealmService(realmService); - consentInformationProvider.setConsentManager(consentManager); + UserProfileExportDataHolder.setRealmService(realmService); + UserProfileExportDataHolder.setConsentManager(consentManager); consentInformationProvider.getRetainedUserInformation(USERNAME_CLAIM_VALUE, UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME, -1234); } @@ -117,8 +136,8 @@ public void testGetRetainedUserInformationGetDomainException() throws Exception when(consentManager.getReceipt(anyString())).thenReturn(mockReceipt); ConsentInformationProvider consentInformationProvider = new ConsentInformationProvider(); - consentInformationProvider.setRealmService(realmService); - consentInformationProvider.setConsentManager(consentManager); + UserProfileExportDataHolder.setRealmService(realmService); + UserProfileExportDataHolder.setConsentManager(consentManager); consentInformationProvider.getRetainedUserInformation(USERNAME_CLAIM_VALUE, UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME, -1234); } diff --git a/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/MockUserInformationProvider.java b/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/MockUserInformationProvider.java index 45ad0ffde8..55e0449a46 100644 --- a/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/MockUserInformationProvider.java +++ b/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/MockUserInformationProvider.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2018, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, + * 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 @@ -21,7 +21,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.identity.user.export.core.dto.UserInformationDTO; -import org.wso2.carbon.identity.user.export.core.service.UserInformationProvider; import java.util.HashMap; import java.util.Map; diff --git a/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/UserInformationServiceImplTest.java b/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/UserInformationServiceImplTest.java index 4010611cf0..482b283367 100644 --- a/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/UserInformationServiceImplTest.java +++ b/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/internal/service/impl/UserInformationServiceImplTest.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2018, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2018, WSO2 LLC. (http://www.wso2.com). * - * WSO2 Inc. licenses this file to you under the Apache License, + * 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 @@ -20,6 +20,7 @@ import org.testng.Assert; import org.testng.annotations.Test; +import org.wso2.carbon.identity.user.export.core.internal.UserProfileExportDataHolder; import java.util.Map; @@ -28,8 +29,8 @@ public class UserInformationServiceImplTest { @Test public void testGetRetainedUserInformation() throws Exception { + UserProfileExportDataHolder.getUserInformationProviders().add(new MockUserInformationProvider()); UserInformationServiceImpl userInformationService = new UserInformationServiceImpl(); - userInformationService.setUserAttributeProvider(new MockUserInformationProvider()); Map retainedUserInformation = userInformationService.getRetainedUserInformation ("admin", "PRIMARY", -1234); diff --git a/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/service/impl/LinkedAccountsProviderTest.java b/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/service/impl/LinkedAccountsProviderTest.java new file mode 100644 index 0000000000..d03473a50a --- /dev/null +++ b/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/service/impl/LinkedAccountsProviderTest.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2023, 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.user.export.core.service.impl; + +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeTest; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; +import org.wso2.carbon.identity.application.common.model.User; +import org.wso2.carbon.identity.user.export.core.dto.UserInformationDTO; +import org.wso2.carbon.identity.user.export.core.internal.UserProfileExportDataHolder; +import org.wso2.carbon.identity.user.profile.mgt.association.federation.FederatedAssociationManager; +import org.wso2.carbon.identity.user.profile.mgt.association.federation.model.AssociatedIdentityProvider; +import org.wso2.carbon.identity.user.profile.mgt.association.federation.model.FederatedAssociation; +import org.wso2.carbon.user.api.UserStoreException; +import org.wso2.carbon.user.core.service.RealmService; +import org.wso2.carbon.user.core.tenant.TenantManager; + +import java.util.ArrayList; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class LinkedAccountsProviderTest { + + private static final String USERNAME_CLAIM_VALUE = "tom"; + private static final String USERSTORE_NAME = "primary"; + private static final String TENANT_NAME = "carbon.super"; + private static final int TENANT_ID = -1234; + + private LinkedAccountsProvider linkedAccountsProvider; + private FederatedAssociationManager federatedAssociationManager; + private RealmService realmService; + private TenantManager tenantManager; + + @BeforeTest + public void beforeTest() { + + federatedAssociationManager = mock(FederatedAssociationManager.class); + realmService = mock(RealmService.class); + tenantManager = mock(TenantManager.class); + UserProfileExportDataHolder.setFederatedAssociationManager(federatedAssociationManager); + UserProfileExportDataHolder.setRealmService(realmService); + } + + @AfterTest + public void afterTest() { + + federatedAssociationManager = null; + realmService = null; + tenantManager = null; + UserProfileExportDataHolder.setFederatedAssociationManager(null); + UserProfileExportDataHolder.setRealmService(null); + } + + @BeforeMethod + public void setUp() { + + MockitoAnnotations.openMocks(this); + linkedAccountsProvider = new LinkedAccountsProvider(); + UserProfileExportDataHolder.getUserInformationProviders().add(linkedAccountsProvider); + } + + @AfterMethod + public void tearDown() { + + } + + @DataProvider + public static Object[][] dataProviderWithValidSocialAccounts() { + + User user = new AuthenticatedUser(); + user.setUserName(USERNAME_CLAIM_VALUE); + user.setUserStoreDomain(USERSTORE_NAME); + user.setTenantDomain(TENANT_NAME); + + AssociatedIdentityProvider googleIdp = new AssociatedIdentityProvider(); + googleIdp.setName("google"); + googleIdp.setDisplayName("google"); + googleIdp.setId("uuid-1234"); + + AssociatedIdentityProvider microsoftIdp = new AssociatedIdentityProvider(); + microsoftIdp.setName("microsoft"); + microsoftIdp.setDisplayName("microsoft"); + microsoftIdp.setId("uuid-123456"); + + FederatedAssociation[] federatedAssociations1 = new FederatedAssociation[2]; + federatedAssociations1[0] = new FederatedAssociation("1234", googleIdp, "AAA2345"); + federatedAssociations1[1] = new FederatedAssociation("123456", microsoftIdp, "AAA2345"); + + FederatedAssociation[] federatedAssociations2 = new FederatedAssociation[1]; + federatedAssociations2[0] = new FederatedAssociation("1234", googleIdp, "AAA2345"); + + return new Object[][]{ + {federatedAssociations1, 2}, + {federatedAssociations2, 1} + }; + } + + @Test(dataProvider = "dataProviderWithValidSocialAccounts") + public void testGetLinkedAccounts(FederatedAssociation[] federatedAssociations, int expectedAssociations) + throws Exception { + + mockObject(); + when(federatedAssociationManager.getFederatedAssociationsOfUser(any())).thenReturn(federatedAssociations); + + UserInformationDTO userAttributesObj = linkedAccountsProvider.getRetainedUserInformation(USERNAME_CLAIM_VALUE, + USERSTORE_NAME, TENANT_ID); + + if (!userAttributesObj.isInformationAvailable()) { + Assert.fail(); + } else { + Assert.assertTrue(userAttributesObj.getData() instanceof ArrayList); + if (userAttributesObj.getData() instanceof ArrayList) { + ArrayList userInformation = (ArrayList) userAttributesObj.getData(); + Assert.assertEquals(userInformation.size(), expectedAssociations); + } + } + } + + @DataProvider + public static Object[][] dataProviderWithZeroSocialAccounts() { + + User user = new AuthenticatedUser(); + user.setUserName(USERNAME_CLAIM_VALUE); + user.setUserStoreDomain(USERSTORE_NAME); + user.setTenantDomain(TENANT_NAME); + + FederatedAssociation[] federatedAssociations = {}; + + return new Object[][]{ + {federatedAssociations} + }; + } + + @Test(dataProvider = "dataProviderWithZeroSocialAccounts") + public void testGetLinkedAccountsWithEmptyAccounts(FederatedAssociation[] federatedAssociations) throws Exception { + + mockObject(); + when(federatedAssociationManager.getFederatedAssociationsOfUser(any())).thenReturn(federatedAssociations); + + UserInformationDTO userAttributesObj = linkedAccountsProvider.getRetainedUserInformation(USERNAME_CLAIM_VALUE, + USERSTORE_NAME, TENANT_ID); + + if (userAttributesObj.isInformationAvailable()) { + Assert.fail(); + } + } + + @DataProvider + public static Object[][] dataProviderWithInvalidSocialAccounts() { + + User user = new AuthenticatedUser(); + user.setUserName(USERNAME_CLAIM_VALUE); + user.setUserStoreDomain(USERSTORE_NAME); + user.setTenantDomain(TENANT_NAME); + + FederatedAssociation[] federatedAssociations = null; + + return new Object[][]{ + {federatedAssociations} + }; + } + + @Test(dataProvider = "dataProviderWithInvalidSocialAccounts") + public void testGetLinkedAccountsWithInvalidIdP(FederatedAssociation[] federatedAssociations) throws Exception { + + mockObject(); + when(federatedAssociationManager.getFederatedAssociationsOfUser(any())).thenReturn(federatedAssociations); + + UserInformationDTO userAttributesObj = linkedAccountsProvider.getRetainedUserInformation(USERNAME_CLAIM_VALUE, + USERSTORE_NAME, TENANT_ID); + + if (userAttributesObj.isInformationAvailable()) { + Assert.fail(); + } + } + + private void mockObject() throws UserStoreException { + + when(realmService.getTenantManager()).thenReturn(tenantManager); + when(tenantManager.getDomain(anyInt())).thenReturn(TENANT_NAME); + } +} diff --git a/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/service/impl/UserProfileInformationProviderTest.java b/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/service/impl/UserProfileInformationProviderTest.java new file mode 100644 index 0000000000..f866667ee2 --- /dev/null +++ b/components/org.wso2.carbon.identity.user.export.core/src/test/java/org/wso2/carbon/identity/user/export/core/service/impl/UserProfileInformationProviderTest.java @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2023, 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.user.export.core.service.impl; + +import org.mockito.MockedStatic; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.testng.Assert; +import org.testng.annotations.AfterTest; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Test; +import org.wso2.carbon.identity.user.export.core.UserExportException; +import org.wso2.carbon.identity.user.export.core.dto.UserInformationDTO; +import org.wso2.carbon.identity.user.export.core.internal.UserProfileExportDataHolder; +import org.wso2.carbon.identity.user.export.core.utils.Utils; +import org.wso2.carbon.user.api.ClaimMapping; +import org.wso2.carbon.user.core.UserCoreConstants; +import org.wso2.carbon.user.core.UserRealm; +import org.wso2.carbon.user.core.UserStoreException; +import org.wso2.carbon.user.core.UserStoreManager; +import org.wso2.carbon.user.core.claim.Claim; +import org.wso2.carbon.user.core.claim.ClaimManager; +import org.wso2.carbon.user.core.common.AbstractUserStoreManager; +import org.wso2.carbon.user.core.service.RealmService; + +import java.util.Collections; +import java.util.HashMap; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class UserProfileInformationProviderTest { + + private static final String USERNAME_CLAIM_URI = "http://wso2.org/claims/username"; + private static final String GIVEN_NAME_CLAIM_URI = "http://wso2.org/claims/givenname"; + private static final String LAST_NAME_CLAIM_URI = "http://wso2.org/claims/lastname"; + private static final String USERNAME_CLAIM_VALUE = "username1"; + private static final String GIVEN_NAME_CLAIM_VALUE = "givenName1"; + private static final String LAST_NAME_CLAIM_VALUE = "lastName1"; + + private UserProfileInformationProvider userProfileInformationProvider; + private AbstractUserStoreManager userStoreManager; + private UserStoreManager secUserStoreManager; + private RealmService realmService; + private UserRealm userRealm; + private org.wso2.carbon.user.api.UserRealm userRlm; + private ClaimManager claimManager; + + @BeforeMethod + public void setUp() { + + MockitoAnnotations.openMocks(this); + userProfileInformationProvider = new UserProfileInformationProvider(); + UserProfileExportDataHolder.getUserInformationProviders().add(userProfileInformationProvider); + + realmService = mock(RealmService.class); + userRealm = mock(UserRealm.class); + userStoreManager = mock(AbstractUserStoreManager.class); + secUserStoreManager = mock(UserStoreManager.class); + userRlm = mock(org.wso2.carbon.user.api.UserRealm.class); + claimManager = mock(ClaimManager.class); + UserProfileExportDataHolder.setRealmService(realmService); + } + + @AfterTest + public void afterTest() { + + realmService = null; + userRealm = null; + userStoreManager = null; + secUserStoreManager = null; + userRlm = null; + claimManager = null; + UserProfileExportDataHolder.setRealmService(null); + } + + @DataProvider + public static Object[][] dataProviderWithDifferentClaimValues() { + + Claim[] claimsWithTwoInput = new Claim[2]; + Claim[] claimsWithThreeInput = new Claim[3]; + + Claim claim1 = new Claim(); + claim1.setClaimUri(USERNAME_CLAIM_URI); + claim1.setValue(USERNAME_CLAIM_VALUE); + claimsWithTwoInput[0] = claim1; + claimsWithThreeInput[0] = claim1; + + Claim claim2 = new Claim(); + claim2.setClaimUri(GIVEN_NAME_CLAIM_URI); + claim2.setValue(GIVEN_NAME_CLAIM_VALUE); + claimsWithTwoInput[1] = claim2; + claimsWithThreeInput[1] = claim2; + + Claim claim3 = new Claim(); + claim3.setClaimUri(LAST_NAME_CLAIM_URI); + claim3.setValue(LAST_NAME_CLAIM_VALUE); + claimsWithThreeInput[2] = claim3; + + return new Object[][]{ + {claimsWithTwoInput, 2}, + {claimsWithThreeInput, 3} + }; + } + + @Test(dataProvider = "dataProviderWithDifferentClaimValues") + public void testGetUserAttributes(Claim[] claims, int expectedNumberOfClaimsInResponse) throws Exception { + + try (MockedStatic utils = Mockito.mockStatic(Utils.class)) { + utils.when(Utils::getAdditionalClaimsToInclude).thenReturn(Collections.EMPTY_LIST); + mockObjects(claims, getSuppportedClaims()); + UserInformationDTO userAttributesObj = userProfileInformationProvider + .getRetainedUserInformation(USERNAME_CLAIM_VALUE, UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME, -1234); + + if (!userAttributesObj.isInformationAvailable()) { + Assert.fail(); + } else { + Assert.assertTrue(userAttributesObj.getData() instanceof HashMap); + if (userAttributesObj.getData() instanceof HashMap) { + HashMap userInformation = (HashMap) userAttributesObj.getData(); + Assert.assertEquals(userInformation.size(), expectedNumberOfClaimsInResponse); + } + } + } + } + + @Test + public void testGetEmptyUserAttributes() throws Exception { + + try (MockedStatic utils = Mockito.mockStatic(Utils.class)) { + utils.when(Utils::getAdditionalClaimsToInclude).thenReturn(Collections.EMPTY_LIST); + Claim[] claims = {}; + mockObjects(claims, getSuppportedClaims()); + UserInformationDTO userAttributesObj = userProfileInformationProvider + .getRetainedUserInformation(USERNAME_CLAIM_VALUE, UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME, + -1234); + + if (userAttributesObj.isInformationAvailable()) { + Assert.fail(); + } + } + } + + @Test + public void testGetInvalidUserAttributes() throws Exception { + + mockObjects(null, getSuppportedClaims()); + UserInformationDTO userAttributesObj = userProfileInformationProvider + .getRetainedUserInformation(USERNAME_CLAIM_VALUE, UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME, -1234); + + if (userAttributesObj.isInformationAvailable()) { + Assert.fail(); + } + } + + @Test(expectedExceptions = UserExportException.class) + public void testGetUserAttributesExceptionOnGetUserStoreManager() throws Exception { + + Claim[] claims = getClaims(); + + mockObjectsToThrowUserStoreException(claims); + userProfileInformationProvider.getRetainedUserInformation + (USERNAME_CLAIM_VALUE, UserCoreConstants.PRIMARY_DEFAULT_DOMAIN_NAME, -1234); + } + + private Claim[] getClaims() { + + Claim[] claims = new Claim[2]; + Claim claim1 = new Claim(); + claim1.setClaimUri(USERNAME_CLAIM_URI); + claim1.setValue(USERNAME_CLAIM_VALUE); + claims[0] = claim1; + + Claim claim2 = new Claim(); + claim2.setClaimUri(GIVEN_NAME_CLAIM_URI); + claim2.setValue(GIVEN_NAME_CLAIM_VALUE); + claims[1] = claim2; + + return claims; + } + + + private ClaimMapping[] getSuppportedClaims() { + + ClaimMapping[] claimMappings = new ClaimMapping[3]; + Claim claim1 = new Claim(); + claim1.setClaimUri(USERNAME_CLAIM_URI); + claim1.setValue(USERNAME_CLAIM_VALUE); + ClaimMapping claimMapping1 = new ClaimMapping(claim1, "username"); + + Claim claim2 = new Claim(); + claim2.setClaimUri(GIVEN_NAME_CLAIM_URI); + claim2.setValue(GIVEN_NAME_CLAIM_VALUE); + ClaimMapping claimMapping2 = new ClaimMapping(claim2, "given_name"); + + Claim claim3 = new Claim(); + claim3.setClaimUri(LAST_NAME_CLAIM_URI); + claim3.setValue(LAST_NAME_CLAIM_VALUE); + ClaimMapping claimMapping3 = new ClaimMapping(claim3, "last_name"); + + + claimMappings[0] = claimMapping1; + claimMappings[1] = claimMapping2; + claimMappings[2] = claimMapping3; + return claimMappings; + } + + private void mockObjects(Claim[] claims, ClaimMapping[] claimMappings) throws Exception { + + when(realmService.getTenantUserRealm(anyInt())).thenReturn(userRlm); + when(userRlm.getUserStoreManager()).thenReturn(userStoreManager); + when(userStoreManager.getSecondaryUserStoreManager(anyString())).thenReturn(secUserStoreManager); + when(userRlm.getClaimManager()).thenReturn(claimManager); + when(claimManager.getAllSupportClaimMappingsByDefault()).thenReturn(claimMappings); + when(secUserStoreManager.getUserClaimValues(USERNAME_CLAIM_VALUE, null)).thenReturn(claims); + } + + private void mockObjectsToThrowUserStoreException(Claim[] claims) throws Exception { + + when(userStoreManager.getSecondaryUserStoreManager(anyString())).thenReturn(secUserStoreManager); + when(userRealm.getUserStoreManager()).thenThrow(new UserStoreException()); + + when(realmService.getTenantUserRealm(anyInt())).thenReturn(userRealm); + + when(secUserStoreManager.getUserClaimValues(USERNAME_CLAIM_VALUE, null)).thenReturn(claims); + } +} diff --git a/components/org.wso2.carbon.identity.user.export.core/src/test/resources/testng.xml b/components/org.wso2.carbon.identity.user.export.core/src/test/resources/testng.xml index 9e81b97982..434b82bf37 100644 --- a/components/org.wso2.carbon.identity.user.export.core/src/test/resources/testng.xml +++ b/components/org.wso2.carbon.identity.user.export.core/src/test/resources/testng.xml @@ -25,6 +25,8 @@ + + From d6a3b98a3f13ef80326a72f0c677152f1e97b350 Mon Sep 17 00:00:00 2001 From: Maduranga Siriwardena Date: Mon, 18 Sep 2023 15:10:57 +0530 Subject: [PATCH 2/2] Fix PR comments --- .../export/core/internal/UserProfileExportServiceComponent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/UserProfileExportServiceComponent.java b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/UserProfileExportServiceComponent.java index 6bc4f6fd85..07c10c5bbe 100644 --- a/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/UserProfileExportServiceComponent.java +++ b/components/org.wso2.carbon.identity.user.export.core/src/main/java/org/wso2/carbon/identity/user/export/core/internal/UserProfileExportServiceComponent.java @@ -78,7 +78,7 @@ protected void activate(ComponentContext ctxt) { ctxt.getBundleContext().registerService(UserInformationProvider.class.getName(), securityInformationProvider, null); } catch (Exception e) { - LOG.error(e.getMessage(), e); + LOG.error("Error while activating UserProfileExportServiceComponent", e); } }