From 93f5d311ff5f9224162d48057b6a9a09ad8c10cc Mon Sep 17 00:00:00 2001 From: Amanda Ariyaratne Date: Tue, 22 Oct 2024 16:26:51 +0530 Subject: [PATCH 1/6] resolve merge conflicts --- .../internal/OAuth2ServiceComponent.java | 30 ++++++ .../OAuth2ServiceComponentHolder.java | 23 +++- .../identity/oauth2/util/OAuth2Util.java | 22 +++- .../identity/oauth2/util/OAuth2UtilTest.java | 102 +++++++++++++++++- 4 files changed, 172 insertions(+), 5 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponent.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponent.java index 4e3a7cd9966..ef4ebcd2777 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponent.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponent.java @@ -40,6 +40,7 @@ import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; import org.wso2.carbon.identity.application.mgt.AuthorizedAPIManagementService; import org.wso2.carbon.identity.application.mgt.listener.ApplicationMgtListener; +import org.wso2.carbon.identity.claim.metadata.mgt.ClaimMetadataManagementService; import org.wso2.carbon.identity.configuration.mgt.core.ConfigurationManager; import org.wso2.carbon.identity.consent.server.configs.mgt.services.ConsentServerConfigsManagementService; import org.wso2.carbon.identity.core.SAMLSSOServiceProviderManager; @@ -1632,4 +1633,33 @@ protected void unsetAccountLockService(AccountLockService accountLockService) { OAuth2ServiceComponentHolder.setAccountLockService(null); log.debug("AccountLockService unset in OAuth2ServiceComponent bundle."); } + + /** + * Set the ClaimMetadataManagementService. + * + * @param claimMetadataManagementService The {@code ClaimMetadataManagementService} instance. + */ + @Reference( + name = "claim.metadata.mgt.service", + service = ClaimMetadataManagementService.class, + cardinality = ReferenceCardinality.MANDATORY, + policy = ReferencePolicy.DYNAMIC, + unbind = "unregisterClaimMetadataManagementService" + ) + protected void registerClaimMetadataManagementService( + ClaimMetadataManagementService claimMetadataManagementService) { + + OAuth2ServiceComponentHolder.getInstance().setClaimMetadataManagementService(claimMetadataManagementService); + } + + /** + * Unset the ClaimMetadataManagementService. + * + * @param claimMetadataManagementService The {@code ClaimMetadataManagementService} instance. + */ + protected void unregisterClaimMetadataManagementService( + ClaimMetadataManagementService claimMetadataManagementService) { + + OAuth2ServiceComponentHolder.getInstance().setClaimMetadataManagementService(null); + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponentHolder.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponentHolder.java index 1f5f5b0b95a..efa96b896e3 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponentHolder.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/internal/OAuth2ServiceComponentHolder.java @@ -24,6 +24,7 @@ import org.wso2.carbon.identity.application.authentication.framework.UserSessionManagementService; import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; import org.wso2.carbon.identity.application.mgt.AuthorizedAPIManagementService; +import org.wso2.carbon.identity.claim.metadata.mgt.ClaimMetadataManagementService; import org.wso2.carbon.identity.configuration.mgt.core.ConfigurationManager; import org.wso2.carbon.identity.consent.server.configs.mgt.services.ConsentServerConfigsManagementService; import org.wso2.carbon.identity.core.SAMLSSOServiceProviderManager; @@ -124,7 +125,7 @@ public class OAuth2ServiceComponentHolder { private List impersonationValidators = new ArrayList<>(); private ConfigurationManager configurationManager; private static AccountLockService accountLockService; - + private ClaimMetadataManagementService claimMetadataManagementService; private OAuth2ServiceComponentHolder() { @@ -911,4 +912,24 @@ public static AccountLockService getAccountLockService() { return OAuth2ServiceComponentHolder.accountLockService; } + + /** + * Set the ClaimMetadataManagementService instance. + * + * @param claimMetadataManagementService ClaimMetadataManagementService instance. + */ + public void setClaimMetadataManagementService(ClaimMetadataManagementService claimMetadataManagementService) { + + this.claimMetadataManagementService = claimMetadataManagementService; + } + + /** + * Get the ClaimMetadataManagementService instance. + * + * @return ClaimMetadataManagementService instance. + */ + public ClaimMetadataManagementService getClaimMetadataManagementService() { + + return claimMetadataManagementService; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java index 52e1855fdb5..2f31c32ee0b 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java @@ -84,6 +84,9 @@ import org.wso2.carbon.identity.base.IdentityException; import org.wso2.carbon.identity.central.log.mgt.utils.LogConstants; import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils; +import org.wso2.carbon.identity.claim.metadata.mgt.ClaimMetadataManagementService; +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; import org.wso2.carbon.identity.consent.server.configs.mgt.exceptions.ConsentServerConfigsMgtException; import org.wso2.carbon.identity.core.ServiceURLBuilder; import org.wso2.carbon.identity.core.URLBuilderException; @@ -2107,13 +2110,30 @@ public static void initiateOIDCScopes(int tenantId) { List scopeClaimsList = OAuth2ServiceComponentHolder.getInstance().getOIDCScopesClaims(); try { + String tenantDomain = IdentityTenantUtil.getTenantDomain(tenantId); + ClaimMetadataManagementService claimService = OAuth2ServiceComponentHolder.getInstance() + .getClaimMetadataManagementService(); + List oidcDialectClaims = claimService.getExternalClaims(OAuthConstants.OIDC_DIALECT, + tenantDomain); + Set oidcClaimsMappedToScopes = scopeClaimsList.stream() + .flatMap(scopeDTO -> Arrays.stream(scopeDTO.getClaim())) + .collect(Collectors.toSet()); + oidcDialectClaims.stream() + .filter(oidcClaim -> oidcClaimsMappedToScopes.contains(oidcClaim.getClaimURI())) + .forEach(oidcClaim -> { + try { + claimService.updateExternalClaim(oidcClaim, tenantDomain); + } catch (ClaimMetadataException e) { + log.error("Error updating OIDC claim: " + oidcClaim.getClaimURI(), e); + } + }); OAuthTokenPersistenceFactory.getInstance().getScopeClaimMappingDAO().initScopeClaimMapping(tenantId, scopeClaimsList); } catch (IdentityOAuth2ClientException e) { if (log.isDebugEnabled()) { log.debug(e.getMessage(), e); } - } catch (IdentityOAuth2Exception e) { + } catch (IdentityOAuth2Exception | ClaimMetadataException e) { log.error(e.getMessage(), e); } } diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java index e2fb35e256e..924d7bbb1f8 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java @@ -52,6 +52,9 @@ import org.wso2.carbon.identity.application.common.util.IdentityApplicationManagementUtil; import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils; +import org.wso2.carbon.identity.claim.metadata.mgt.ClaimMetadataManagementService; +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; import org.wso2.carbon.identity.common.testng.WithCarbonHome; import org.wso2.carbon.identity.core.internal.IdentityCoreServiceComponent; import org.wso2.carbon.identity.core.util.IdentityConfigParser; @@ -124,9 +127,12 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; +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; @@ -135,8 +141,11 @@ import static org.testng.Assert.assertTrue; import static org.testng.Assert.fail; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OAuthError.AuthorizationResponsei18nKey.APPLICATION_NOT_FOUND; +import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OIDC_DIALECT; import static org.wso2.carbon.identity.oauth2.util.OAuth2Util.getIdTokenIssuer; import static org.wso2.carbon.identity.openidconnect.util.TestUtils.getKeyStoreFromFile; +import static org.wso2.carbon.utils.multitenancy.MultitenantConstants.SUPER_TENANT_DOMAIN_NAME; +import static org.wso2.carbon.utils.multitenancy.MultitenantConstants.SUPER_TENANT_ID; @Listeners(MockitoTestNGListener.class) @WithCarbonHome @@ -223,9 +232,6 @@ public class OAuth2UtilTest { @Mock private AccessTokenDAO accessTokenDAO; - @Mock - OAuth2ServiceComponentHolder mockOAuth2ServiceComponentHolder; - @Mock OAuthAdminServiceImpl oAuthAdminService; @@ -2838,6 +2844,96 @@ public void getSupportedTokenBindingTypes() { Assert.assertEquals(supportedTokenBindingTypes.size(), 3); } + @Test(dataProvider = "initiateOIDCScopesDataProvider") + public void testInitiateOIDCScopes(List scopeClaimsList, List oidcDialectClaims) + throws ClaimMetadataException, IdentityOAuth2Exception { + + try (MockedStatic mockedOAuthTokenPersistenceFactory = + mockStatic(OAuthTokenPersistenceFactory.class); + MockedStatic mockedOAuth2ServiceComponentHolder = + mockStatic(OAuth2ServiceComponentHolder.class)) { + + OAuth2ServiceComponentHolder mockServiceComponentHolder = mock(OAuth2ServiceComponentHolder.class); + OAuthTokenPersistenceFactory mockTokenPersistenceFactory = mock(OAuthTokenPersistenceFactory.class); + ClaimMetadataManagementService claimService = mock(ClaimMetadataManagementService.class); + ScopeClaimMappingDAO scopeClaimMappingDAO = mock(ScopeClaimMappingDAO.class); + + mockedOAuthTokenPersistenceFactory.when(OAuthTokenPersistenceFactory::getInstance) + .thenReturn(mockTokenPersistenceFactory); + mockedOAuth2ServiceComponentHolder.when(OAuth2ServiceComponentHolder::getInstance) + .thenReturn(mockServiceComponentHolder); + + when(mockTokenPersistenceFactory.getScopeClaimMappingDAO()).thenReturn(scopeClaimMappingDAO); + doNothing().when(scopeClaimMappingDAO).initScopeClaimMapping(SUPER_TENANT_ID, scopeClaimsList); + when(mockServiceComponentHolder.getClaimMetadataManagementService()).thenReturn(claimService); + when(claimService.getExternalClaims(OIDC_DIALECT, SUPER_TENANT_DOMAIN_NAME)).thenReturn(oidcDialectClaims); + when(mockServiceComponentHolder.getOIDCScopesClaims()).thenReturn(scopeClaimsList); + + OAuth2Util.initiateOIDCScopes(SUPER_TENANT_ID); + verify(scopeClaimMappingDAO, times(1)) + .initScopeClaimMapping(SUPER_TENANT_ID, scopeClaimsList); + verify(claimService, times(4)).updateExternalClaim(any(), anyString()); + } + } + + @DataProvider(name = "initiateOIDCScopesDataProvider") + public Object[][] initiateOIDCScopesDataProvider() { + + List scopeClaimsList = new ArrayList<>(); + + ScopeDTO scope1 = new ScopeDTO(); + scope1.setName("openid"); + scope1.setDescription("OpenID scope"); + scope1.setClaim(new String[] { + "http://wso2.org/oidc/claim/email", + "http://wso2.org/oidc/claim/profile" + }); + + ScopeDTO scope2 = new ScopeDTO(); + scope2.setName("profile"); + scope2.setDescription("Profile scope"); + scope2.setClaim(new String[] { + "http://wso2.org/oidc/claim/first_name", + "http://wso2.org/oidc/claim/last_name", + "http://wso2.org/oidc/claim/profile" + }); + + ScopeDTO scope3 = new ScopeDTO(); + scope3.setName("email"); + scope3.setDescription("Email scope"); + scope3.setClaim(new String[] { + "http://wso2.org/oidc/claim/email", + "http://wso2.org/oidc/claim/email_verified" + }); + + scopeClaimsList.add(scope1); + scopeClaimsList.add(scope2); + scopeClaimsList.add(scope3); + + List oidcDialectClaims = new ArrayList<>(); + + ExternalClaim claim1 = new ExternalClaim("http://wso2.org/oidc", + "http://wso2.org/oidc/claim/email", "http://wso2.org/claims/emailaddress"); + ExternalClaim claim2 = new ExternalClaim("http://wso2.org/oidc", + "http://wso2.org/oidc/claim/profile", "http://wso2.org/claims/url"); + ExternalClaim claim3 = new ExternalClaim("http://wso2.org/oidc", + "http://wso2.org/oidc/claim/first_name", "http://wso2.org/claims/givenname"); + ExternalClaim claim4 = new ExternalClaim("http://wso2.org/oidc", + "http://wso2.org/oidc/claim/last_name", "http://wso2.org/claims/lastname"); + ExternalClaim claim5 = new ExternalClaim("http://wso2.org/oidc", + "http://wso2.org/oidc/claim/phone_number", "http://wso2.org/claims/mobile"); + + oidcDialectClaims.add(claim1); + oidcDialectClaims.add(claim2); + oidcDialectClaims.add(claim3); + oidcDialectClaims.add(claim4); + oidcDialectClaims.add(claim5); + + return new Object[][]{ + {scopeClaimsList, oidcDialectClaims} + }; + } + private void setPrivateField(Object object, String fieldName, Object value) throws Exception { Field field = object.getClass().getDeclaredField(fieldName); From 2ec83d708ef2df82824c77d8b6f7c40e587ee344 Mon Sep 17 00:00:00 2001 From: Amanda Ariyaratne Date: Mon, 14 Oct 2024 12:06:14 +0530 Subject: [PATCH 2/6] improve unit test --- .../identity/oauth2/util/OAuth2UtilTest.java | 32 +++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java index 924d7bbb1f8..2de41c4c370 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java @@ -26,6 +26,8 @@ import org.apache.axis2.engine.AxisConfiguration; import org.apache.axis2.transport.http.HTTPConstants; import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.oltu.oauth2.common.utils.OAuthUtils; import org.mockito.Mock; import org.mockito.MockedConstruction; @@ -105,6 +107,7 @@ import org.wso2.carbon.utils.NetworkUtils; import java.lang.reflect.Field; +import java.lang.reflect.Modifier; import java.nio.charset.StandardCharsets; import java.nio.file.Paths; import java.security.KeyStore; @@ -127,6 +130,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; @@ -2846,22 +2850,26 @@ public void getSupportedTokenBindingTypes() { @Test(dataProvider = "initiateOIDCScopesDataProvider") public void testInitiateOIDCScopes(List scopeClaimsList, List oidcDialectClaims) - throws ClaimMetadataException, IdentityOAuth2Exception { + throws Exception { try (MockedStatic mockedOAuthTokenPersistenceFactory = mockStatic(OAuthTokenPersistenceFactory.class); MockedStatic mockedOAuth2ServiceComponentHolder = - mockStatic(OAuth2ServiceComponentHolder.class)) { + mockStatic(OAuth2ServiceComponentHolder.class); + MockedStatic mockedLogFactory = mockStatic(LogFactory.class)) { OAuth2ServiceComponentHolder mockServiceComponentHolder = mock(OAuth2ServiceComponentHolder.class); OAuthTokenPersistenceFactory mockTokenPersistenceFactory = mock(OAuthTokenPersistenceFactory.class); ClaimMetadataManagementService claimService = mock(ClaimMetadataManagementService.class); ScopeClaimMappingDAO scopeClaimMappingDAO = mock(ScopeClaimMappingDAO.class); + Log log = mock(Log.class); mockedOAuthTokenPersistenceFactory.when(OAuthTokenPersistenceFactory::getInstance) .thenReturn(mockTokenPersistenceFactory); mockedOAuth2ServiceComponentHolder.when(OAuth2ServiceComponentHolder::getInstance) .thenReturn(mockServiceComponentHolder); + mockedLogFactory.when(() -> LogFactory.getLog(any(Class.class))).thenReturn(log); + setPrivateStaticFinalField(OAuth2Util.class, "log", log); when(mockTokenPersistenceFactory.getScopeClaimMappingDAO()).thenReturn(scopeClaimMappingDAO); doNothing().when(scopeClaimMappingDAO).initScopeClaimMapping(SUPER_TENANT_ID, scopeClaimsList); @@ -2873,6 +2881,14 @@ public void testInitiateOIDCScopes(List scopeClaimsList, List clazz, String fieldName, Object value) throws Exception { + + Field field = clazz.getDeclaredField(fieldName); + field.setAccessible(true); + + Field modifiersField = Field.class.getDeclaredField("modifiers"); + modifiersField.setAccessible(true); + modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); + + field.set(null, value); + } } From 5f9674d751203e8e195a057467d1ae2c6c06cccc Mon Sep 17 00:00:00 2001 From: Amanda Ariyaratne Date: Mon, 14 Oct 2024 12:21:38 +0530 Subject: [PATCH 3/6] improve unit test to cover exceptions --- .../wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java index 2de41c4c370..287852a5c3b 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java @@ -132,6 +132,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; @@ -2876,14 +2877,20 @@ public void testInitiateOIDCScopes(List scopeClaimsList, List Date: Thu, 24 Oct 2024 17:01:51 +0530 Subject: [PATCH 4/6] add claims to db before scope add and update --- .../identity/oauth/OAuthAdminServiceImpl.java | 37 +++++- .../identity/oauth2/util/OAuth2Util.java | 14 +- .../oauth/OAuthAdminServiceImplTest.java | 123 ++++++++++++++++++ .../identity/oauth2/util/OAuth2UtilTest.java | 11 +- 4 files changed, 163 insertions(+), 22 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImpl.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImpl.java index 878c0450c9d..578bb3213a4 100755 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImpl.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImpl.java @@ -42,7 +42,9 @@ import org.wso2.carbon.identity.central.log.mgt.utils.LogConstants; import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils; import org.wso2.carbon.identity.claim.metadata.mgt.ClaimMetadataHandler; +import org.wso2.carbon.identity.claim.metadata.mgt.ClaimMetadataManagementService; import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.core.util.IdentityUtil; import org.wso2.carbon.identity.oauth.cache.AppInfoCache; @@ -1081,8 +1083,23 @@ public void addScope(ScopeDTO scope) throws IdentityOAuthAdminException { addScopePreValidation(scope); int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + String tenantDomain = IdentityTenantUtil.getTenantDomain(tenantId); + ClaimMetadataManagementService claimService = OAuth2ServiceComponentHolder.getInstance() + .getClaimMetadataManagementService(); try { + List oidcDialectClaims = claimService.getExternalClaims(OAuthConstants.OIDC_DIALECT, + tenantDomain); + List oidcClaimsMappedToScopes = Arrays.asList(scope.getClaim()); + for (ExternalClaim oidcClaim : oidcDialectClaims) { + if (oidcClaimsMappedToScopes.contains(oidcClaim.getClaimURI())) { + claimService.updateExternalClaim(oidcClaim, tenantDomain); + } + } OAuthTokenPersistenceFactory.getInstance().getScopeClaimMappingDAO().addScope(scope, tenantId); + } catch (ClaimMetadataException e) { + IdentityOAuth2Exception identityOAuth2Exception = new IdentityOAuth2Exception(String.format( + "Error while inserting OIDC scope: %s in tenant: %s", scope.getName(), tenantDomain), e); + throw handleErrorWithExceptionType(identityOAuth2Exception.getMessage(), identityOAuth2Exception); } catch (IdentityOAuth2Exception e) { throw handleErrorWithExceptionType(String.format("Error while inserting OIDC scope: %s, %s", scope.getName(), e.getMessage()), e); @@ -1248,13 +1265,27 @@ public void updateScope(String scope, String[] addClaims, String[] deleteClaims) public void updateScope(ScopeDTO updatedScope) throws IdentityOAuthAdminException { updateScopePreValidation(updatedScope); - // Check whether a scope exists with the provided scope name which to be deleted. + // Check whether a scope exists with the provided scope name which to be updated. validateScopeExistence(updatedScope.getName()); int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId(); + String tenantDomain = IdentityTenantUtil.getTenantDomain(tenantId); + ClaimMetadataManagementService claimService = OAuth2ServiceComponentHolder.getInstance() + .getClaimMetadataManagementService(); try { - OAuthTokenPersistenceFactory.getInstance().getScopeClaimMappingDAO(). - updateScope(updatedScope, tenantId); + List oidcDialectClaims = claimService.getExternalClaims(OAuthConstants.OIDC_DIALECT, + tenantDomain); + List oidcClaimsMappedToScopes = Arrays.asList(updatedScope.getClaim()); + for (ExternalClaim oidcClaim : oidcDialectClaims) { + if (oidcClaimsMappedToScopes.contains(oidcClaim.getClaimURI())) { + claimService.updateExternalClaim(oidcClaim, tenantDomain); + } + } + OAuthTokenPersistenceFactory.getInstance().getScopeClaimMappingDAO().updateScope(updatedScope, tenantId); + } catch (ClaimMetadataException e) { + IdentityOAuth2Exception identityOAuth2Exception = new IdentityOAuth2Exception(String.format( + "Error while updating the scope: %s in tenant: %s", updatedScope.getName(), tenantId), e); + throw handleErrorWithExceptionType(identityOAuth2Exception.getMessage(), identityOAuth2Exception); } catch (IdentityOAuth2Exception e) { throw handleErrorWithExceptionType(String.format("Error while updating the scope: %s in tenant: %s", updatedScope.getName(), tenantId), e); diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java index 2f31c32ee0b..5e26cd61be8 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/oauth2/util/OAuth2Util.java @@ -2118,15 +2118,11 @@ public static void initiateOIDCScopes(int tenantId) { Set oidcClaimsMappedToScopes = scopeClaimsList.stream() .flatMap(scopeDTO -> Arrays.stream(scopeDTO.getClaim())) .collect(Collectors.toSet()); - oidcDialectClaims.stream() - .filter(oidcClaim -> oidcClaimsMappedToScopes.contains(oidcClaim.getClaimURI())) - .forEach(oidcClaim -> { - try { - claimService.updateExternalClaim(oidcClaim, tenantDomain); - } catch (ClaimMetadataException e) { - log.error("Error updating OIDC claim: " + oidcClaim.getClaimURI(), e); - } - }); + for (ExternalClaim oidcClaim : oidcDialectClaims) { + if (oidcClaimsMappedToScopes.contains(oidcClaim.getClaimURI())) { + claimService.updateExternalClaim(oidcClaim, tenantDomain); + } + } OAuthTokenPersistenceFactory.getInstance().getScopeClaimMappingDAO().initScopeClaimMapping(tenantId, scopeClaimsList); } catch (IdentityOAuth2ClientException e) { diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java index 643bad39f0c..70e8a19542e 100755 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java @@ -36,6 +36,9 @@ import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.identity.application.authentication.framework.model.AuthenticatedUser; import org.wso2.carbon.identity.application.mgt.ApplicationManagementService; +import org.wso2.carbon.identity.claim.metadata.mgt.ClaimMetadataManagementService; +import org.wso2.carbon.identity.claim.metadata.mgt.exception.ClaimMetadataException; +import org.wso2.carbon.identity.claim.metadata.mgt.model.ExternalClaim; import org.wso2.carbon.identity.core.internal.IdentityCoreServiceComponent; import org.wso2.carbon.identity.core.util.IdentityTenantUtil; import org.wso2.carbon.identity.core.util.IdentityUtil; @@ -47,6 +50,7 @@ import org.wso2.carbon.identity.oauth.dto.OAuthAppRevocationRequestDTO; import org.wso2.carbon.identity.oauth.dto.OAuthConsumerAppDTO; import org.wso2.carbon.identity.oauth.dto.OAuthRevocationResponseDTO; +import org.wso2.carbon.identity.oauth.dto.ScopeDTO; import org.wso2.carbon.identity.oauth.internal.OAuthComponentServiceHolder; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; import org.wso2.carbon.identity.oauth2.TestConstants; @@ -56,6 +60,7 @@ import org.wso2.carbon.identity.oauth2.dao.TokenManagementDAOImpl; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; +import org.wso2.carbon.identity.openidconnect.dao.ScopeClaimMappingDAO; import org.wso2.carbon.user.api.RealmConfiguration; import org.wso2.carbon.user.api.Tenant; import org.wso2.carbon.user.api.UserRealm; @@ -90,8 +95,14 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; +import static org.testng.Assert.assertThrows; +import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OIDC_DIALECT; +import static org.wso2.carbon.utils.multitenancy.MultitenantConstants.SUPER_TENANT_DOMAIN_NAME; +import static org.wso2.carbon.utils.multitenancy.MultitenantConstants.SUPER_TENANT_ID; public class OAuthAdminServiceImplTest { @@ -1095,4 +1106,116 @@ private Object invokePrivateMethod(Object object, String methodName, Class[] method.setAccessible(true); return method.invoke(object, params); } + + @Test(dataProvider = "addScopeDataProvider") + public void testAddScope(ScopeDTO scope, List oidcDialectClaims) throws Exception { + + try (MockedStatic mockedOAuthTokenPersistenceFactory = + mockStatic(OAuthTokenPersistenceFactory.class); + MockedStatic mockedOAuth2ServiceComponentHolder = + mockStatic(OAuth2ServiceComponentHolder.class)) { + + OAuth2ServiceComponentHolder mockServiceComponentHolder = mock(OAuth2ServiceComponentHolder.class); + OAuthTokenPersistenceFactory mockTokenPersistenceFactory = mock(OAuthTokenPersistenceFactory.class); + ClaimMetadataManagementService claimService = mock(ClaimMetadataManagementService.class); + ScopeClaimMappingDAO scopeClaimMappingDAO = mock(ScopeClaimMappingDAO.class); + + mockedOAuthTokenPersistenceFactory.when(OAuthTokenPersistenceFactory::getInstance) + .thenReturn(mockTokenPersistenceFactory); + mockedOAuth2ServiceComponentHolder.when(OAuth2ServiceComponentHolder::getInstance) + .thenReturn(mockServiceComponentHolder); + + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(SUPER_TENANT_ID); + identityTenantUtil.when(() -> IdentityTenantUtil.getTenantDomain(SUPER_TENANT_ID)) + .thenReturn(SUPER_TENANT_DOMAIN_NAME); + when(mockTokenPersistenceFactory.getScopeClaimMappingDAO()).thenReturn(scopeClaimMappingDAO); + doNothing().when(scopeClaimMappingDAO).addScope(scope, SUPER_TENANT_ID); + when(mockServiceComponentHolder.getClaimMetadataManagementService()).thenReturn(claimService); + when(claimService.getExternalClaims(OIDC_DIALECT, SUPER_TENANT_DOMAIN_NAME)).thenReturn(oidcDialectClaims); + + OAuthAdminServiceImpl service = new OAuthAdminServiceImpl(); + service.addScope(scope); + verify(scopeClaimMappingDAO, times(1)).addScope(any(), anyInt()); + verify(claimService, times(2)).updateExternalClaim(any(), anyString()); + + ClaimMetadataException claimMetadataException = new ClaimMetadataException("error"); + when(claimService.getExternalClaims(OIDC_DIALECT, SUPER_TENANT_DOMAIN_NAME)) + .thenThrow(claimMetadataException); + assertThrows(IdentityOAuthAdminException.class, () -> service.addScope(scope)); + } + } + + @Test(dataProvider = "addScopeDataProvider") + public void testUpdateScope(ScopeDTO scope, List oidcDialectClaims) throws Exception { + + try (MockedStatic mockedOAuthTokenPersistenceFactory = + mockStatic(OAuthTokenPersistenceFactory.class); + MockedStatic mockedOAuth2ServiceComponentHolder = + mockStatic(OAuth2ServiceComponentHolder.class)) { + + OAuth2ServiceComponentHolder mockServiceComponentHolder = mock(OAuth2ServiceComponentHolder.class); + OAuthTokenPersistenceFactory mockTokenPersistenceFactory = mock(OAuthTokenPersistenceFactory.class); + ClaimMetadataManagementService claimService = mock(ClaimMetadataManagementService.class); + ScopeClaimMappingDAO scopeClaimMappingDAO = mock(ScopeClaimMappingDAO.class); + + mockedOAuthTokenPersistenceFactory.when(OAuthTokenPersistenceFactory::getInstance) + .thenReturn(mockTokenPersistenceFactory); + mockedOAuth2ServiceComponentHolder.when(OAuth2ServiceComponentHolder::getInstance) + .thenReturn(mockServiceComponentHolder); + + PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(SUPER_TENANT_ID); + identityTenantUtil.when(() -> IdentityTenantUtil.getTenantDomain(SUPER_TENANT_ID)) + .thenReturn(SUPER_TENANT_DOMAIN_NAME); + when(mockTokenPersistenceFactory.getScopeClaimMappingDAO()).thenReturn(scopeClaimMappingDAO); + doNothing().when(scopeClaimMappingDAO).addScope(scope, SUPER_TENANT_ID); + when(scopeClaimMappingDAO.isScopeExist(any(), anyInt())).thenReturn(true); + when(mockServiceComponentHolder.getClaimMetadataManagementService()).thenReturn(claimService); + when(claimService.getExternalClaims(OIDC_DIALECT, SUPER_TENANT_DOMAIN_NAME)).thenReturn(oidcDialectClaims); + + OAuthAdminServiceImpl service = new OAuthAdminServiceImpl(); + service.updateScope(scope); + verify(scopeClaimMappingDAO, times(1)).updateScope(any(), anyInt()); + verify(claimService, times(2)).updateExternalClaim(any(), anyString()); + + ClaimMetadataException claimMetadataException = new ClaimMetadataException("error"); + when(claimService.getExternalClaims(OIDC_DIALECT, SUPER_TENANT_DOMAIN_NAME)) + .thenThrow(claimMetadataException); + assertThrows(IdentityOAuthAdminException.class, () -> service.addScope(scope)); + } + } + + @DataProvider(name = "addScopeDataProvider") + public Object[][] addScopeDataProvider() { + + ScopeDTO scope = new ScopeDTO(); + scope.setName("dummy_claim"); + scope.setDisplayName("Dummy Claim"); + scope.setDescription("Dummy Claim Description"); + scope.setClaim(new String[] { + "http://wso2.org/oidc/claim/email", + "http://wso2.org/oidc/claim/profile" + }); + List oidcDialectClaims = new ArrayList<>(); + + ExternalClaim claim1 = new ExternalClaim("http://wso2.org/oidc", + "http://wso2.org/oidc/claim/email", "http://wso2.org/claims/emailaddress"); + ExternalClaim claim2 = new ExternalClaim("http://wso2.org/oidc", + "http://wso2.org/oidc/claim/profile", "http://wso2.org/claims/url"); + ExternalClaim claim3 = new ExternalClaim("http://wso2.org/oidc", + "http://wso2.org/oidc/claim/first_name", "http://wso2.org/claims/givenname"); + ExternalClaim claim4 = new ExternalClaim("http://wso2.org/oidc", + "http://wso2.org/oidc/claim/last_name", "http://wso2.org/claims/lastname"); + ExternalClaim claim5 = new ExternalClaim("http://wso2.org/oidc", + "http://wso2.org/oidc/claim/phone_number", "http://wso2.org/claims/mobile"); + + oidcDialectClaims.add(claim1); + oidcDialectClaims.add(claim2); + oidcDialectClaims.add(claim3); + oidcDialectClaims.add(claim4); + oidcDialectClaims.add(claim5); + + return new Object[][]{ + {scope, oidcDialectClaims} + }; + } } diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java index 287852a5c3b..196ee2d431b 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth2/util/OAuth2UtilTest.java @@ -130,9 +130,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; @@ -2877,20 +2875,13 @@ public void testInitiateOIDCScopes(List scopeClaimsList, List Date: Thu, 24 Oct 2024 17:34:44 +0530 Subject: [PATCH 5/6] fix unit test --- .../wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java index 70e8a19542e..9a9907c4738 100755 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java @@ -1163,6 +1163,7 @@ public void testUpdateScope(ScopeDTO scope, List oidcDialectClaim mockedOAuth2ServiceComponentHolder.when(OAuth2ServiceComponentHolder::getInstance) .thenReturn(mockServiceComponentHolder); + PrivilegedCarbonContext.startTenantFlow(); PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantId(SUPER_TENANT_ID); identityTenantUtil.when(() -> IdentityTenantUtil.getTenantDomain(SUPER_TENANT_ID)) .thenReturn(SUPER_TENANT_DOMAIN_NAME); From 1ce8cf28436603838c80af8908ef42c9a723f448 Mon Sep 17 00:00:00 2001 From: Amanda Ariyaratne Date: Mon, 28 Oct 2024 16:14:59 +0530 Subject: [PATCH 6/6] fix import order --- .../wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java index 0aa49b363f1..42b7ce4ac7c 100755 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/oauth/OAuthAdminServiceImplTest.java @@ -62,8 +62,8 @@ import org.wso2.carbon.identity.oauth2.dao.TokenManagementDAOImpl; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.model.AccessTokenDO; -import org.wso2.carbon.identity.openidconnect.dao.ScopeClaimMappingDAO; import org.wso2.carbon.identity.oauth2.util.OAuth2Util; +import org.wso2.carbon.identity.openidconnect.dao.ScopeClaimMappingDAO; import org.wso2.carbon.user.api.RealmConfiguration; import org.wso2.carbon.user.api.Tenant; import org.wso2.carbon.user.api.UserRealm; @@ -104,10 +104,10 @@ import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; import static org.testng.Assert.assertThrows; +import static org.wso2.carbon.identity.oauth.common.OAuthConstants.ENABLE_CLAIMS_SEPARATION_FOR_ACCESS_TOKEN; import static org.wso2.carbon.identity.oauth.common.OAuthConstants.OIDC_DIALECT; import static org.wso2.carbon.utils.multitenancy.MultitenantConstants.SUPER_TENANT_DOMAIN_NAME; import static org.wso2.carbon.utils.multitenancy.MultitenantConstants.SUPER_TENANT_ID; -import static org.wso2.carbon.identity.oauth.common.OAuthConstants.ENABLE_CLAIMS_SEPARATION_FOR_ACCESS_TOKEN; public class OAuthAdminServiceImplTest {