From f4d26b2f2b48475f36363ec1dccfa48e853b1ade Mon Sep 17 00:00:00 2001 From: Indeewai Wijesiri Date: Wed, 4 Dec 2024 15:00:20 +0530 Subject: [PATCH 1/3] implementing the user attribute handlig for implicit flow --- .../JWTAccessTokenOIDCClaimsHandler.java | 33 ++++++++- .../JWTAccessTokenOIDCClaimsHandlerTest.java | 68 ++++++++++++++++++- 2 files changed, 98 insertions(+), 3 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandler.java b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandler.java index ede19a67f6..9c91b7c8a6 100644 --- a/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandler.java +++ b/components/org.wso2.carbon.identity.oauth/src/main/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandler.java @@ -87,8 +87,20 @@ public JWTClaimsSet handleCustomClaims(JWTClaimsSet.Builder builder, OAuthTokenR public JWTClaimsSet handleCustomClaims(JWTClaimsSet.Builder builder, OAuthAuthzReqMessageContext request) throws IdentityOAuth2Exception { - // TODO : Implement this method for implicit flow and hybrid flow. - return builder.build(); + /* + Handling the user attributes for the access token. There is no requirement of the consent + to manage user attributes for the access token. + */ + String clientId = request.getAuthorizationReqDTO().getConsumerKey(); + String spTenantDomain = getServiceProviderTenantDomain(request); + AuthenticatedUser authenticatedUser = request.getAuthorizationReqDTO().getUser(); + + Map claims = getAccessTokenUserClaims(authenticatedUser, clientId, spTenantDomain); + if (claims == null || claims.isEmpty()) { + return builder.build(); + } + Map filteredClaims = handleClaimsFormat(claims, clientId, spTenantDomain); + return setClaimsToJwtClaimSet(builder, filteredClaims); } private Map getAccessTokenUserClaims(AuthenticatedUser authenticatedUser, String clientId, @@ -298,4 +310,21 @@ private String getServiceProviderTenantDomain(OAuthTokenReqMessageContext reques } return spTenantDomain; } + + /** + * Retrieves the service provider tenant domain from the OAuthAuthzReqMessageContext. + * + * @param requestMsgCtx OAuthAuthzReqMessageContext containing the tenant domain. + * @return The tenant domain. + */ + private String getServiceProviderTenantDomain(OAuthAuthzReqMessageContext requestMsgCtx) { + + String spTenantDomain = (String) requestMsgCtx.getProperty(MultitenantConstants.TENANT_DOMAIN); + // There are certain flows where tenant domain is not added as a message context property. + if (spTenantDomain == null) { + spTenantDomain = requestMsgCtx.getAuthorizationReqDTO().getTenantDomain(); + } + return spTenantDomain; + } + } diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandlerTest.java index e1ad12bad8..a86baca2a3 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandlerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandlerTest.java @@ -54,8 +54,10 @@ import org.wso2.carbon.identity.oauth.config.OAuthServerConfiguration; import org.wso2.carbon.identity.oauth.dao.OAuthAppDO; import org.wso2.carbon.identity.oauth2.IdentityOAuth2Exception; +import org.wso2.carbon.identity.oauth2.authz.OAuthAuthzReqMessageContext; import org.wso2.carbon.identity.oauth2.dao.OAuthTokenPersistenceFactory; import org.wso2.carbon.identity.oauth2.dto.OAuth2AccessTokenReqDTO; +import org.wso2.carbon.identity.oauth2.dto.OAuth2AuthorizeReqDTO; import org.wso2.carbon.identity.oauth2.internal.OAuth2ServiceComponentHolder; import org.wso2.carbon.identity.oauth2.token.OAuthTokenReqMessageContext; import org.wso2.carbon.identity.oauth2.util.AuthzUtil; @@ -364,6 +366,41 @@ public void testHandleCustomClaimsWithAddressClaimForOAuthTokenReqMsgContext() t } } + @Test + public void testHandleCustomClaimsForOAuthAuthzReqMsgContext() throws Exception { + + try (MockedStatic jdbcPersistenceManager = mockStatic(JDBCPersistenceManager.class); + MockedStatic oAuthServerConfiguration = mockStatic( + OAuthServerConfiguration.class); + MockedStatic claimMetadataHandler = mockStatic(ClaimMetadataHandler.class)) { + OAuthServerConfiguration oauthServerConfigurationMock = mock(OAuthServerConfiguration.class); + oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance) + .thenReturn(oauthServerConfigurationMock); + try (MockedStatic oAuth2Util = mockStatic(OAuth2Util.class); + MockedStatic authzUtil = mockStatic(AuthzUtil.class); + MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class); + MockedStatic identityUtil = mockStatic(IdentityUtil.class, Mockito.CALLS_REAL_METHODS)) { + identityUtil.when(IdentityUtil::isGroupsVsRolesSeparationImprovementsEnabled).thenReturn(true); + oAuth2Util.when(() -> OAuth2Util.getAppInformationByClientId(any(), any())).thenReturn( + getoAuthAppDO(jwtAccessTokenClaims)); + Map mappings = getOIDCtoLocalClaimsMapping(); + claimMetadataHandler.when(ClaimMetadataHandler::getInstance).thenReturn(mockClaimMetadataHandler); + lenient().when(mockClaimMetadataHandler.getMappingsMapFromOtherDialectToCarbon( + anyString(), isNull(), anyString(), anyBoolean())).thenReturn(mappings); + OAuthAuthzReqMessageContext requestMsgCtx = getOAuthAuthzReqMessageContextForLocalUser(); + mockApplicationManagementService(); + authzUtil.when(() -> AuthzUtil.getUserRoles(any(), anyString())).thenReturn(new ArrayList<>()); + UserRealm userRealm = getUserRealmWithUserClaims(USER_CLAIMS_MAP); + mockUserRealm(requestMsgCtx.getAuthorizationReqDTO().getUser().toString(), userRealm, identityTenantUtil); + JWTClaimsSet.Builder jwtClaimsSetBuilder = new JWTClaimsSet.Builder(); + JWTClaimsSet jwtClaimsSet = getJwtClaimSet(jwtClaimsSetBuilder, requestMsgCtx, jdbcPersistenceManager, + oAuthServerConfiguration); + assertNotNull(jwtClaimsSet); + assertFalse(jwtClaimsSet.getClaims().isEmpty()); + } + } + } + private static Map getOIDCtoLocalClaimsMapping() { Map mappings = new HashMap<>(); @@ -405,6 +442,26 @@ private JWTClaimsSet getJwtClaimSet(JWTClaimsSet.Builder jwtClaimsSetBuilder, MockedStatic oAuthServerConfiguration) throws IdentityOAuth2Exception { + JWTAccessTokenOIDCClaimsHandler jWTAccessTokenOIDCClaimsHandler = + getJwtAccessTokenOIDCClaimsHandler(jdbcPersistenceManager, oAuthServerConfiguration); + return jWTAccessTokenOIDCClaimsHandler.handleCustomClaims(jwtClaimsSetBuilder, requestMsgCtx); + } + + private JWTClaimsSet getJwtClaimSet(JWTClaimsSet.Builder jwtClaimsSetBuilder, + OAuthAuthzReqMessageContext requestMsgCtx, + MockedStatic jdbcPersistenceManager, + MockedStatic oAuthServerConfiguration) + throws IdentityOAuth2Exception { + + JWTAccessTokenOIDCClaimsHandler jWTAccessTokenOIDCClaimsHandler = + getJwtAccessTokenOIDCClaimsHandler(jdbcPersistenceManager, oAuthServerConfiguration); + return jWTAccessTokenOIDCClaimsHandler.handleCustomClaims(jwtClaimsSetBuilder, requestMsgCtx); + } + + private JWTAccessTokenOIDCClaimsHandler getJwtAccessTokenOIDCClaimsHandler( + MockedStatic jdbcPersistenceManager, + MockedStatic oAuthServerConfiguration) { + OAuthServerConfiguration mockOAuthServerConfiguration = mock(OAuthServerConfiguration.class); oAuthServerConfiguration.when(OAuthServerConfiguration::getInstance).thenReturn(mockOAuthServerConfiguration); DataSource dataSource = mock(DataSource.class); @@ -434,7 +491,7 @@ private JWTClaimsSet getJwtClaimSet(JWTClaimsSet.Builder jwtClaimsSetBuilder, JWTAccessTokenOIDCClaimsHandler jWTAccessTokenOIDCClaimsHandler = new JWTAccessTokenOIDCClaimsHandler(); - return jWTAccessTokenOIDCClaimsHandler.handleCustomClaims(jwtClaimsSetBuilder, requestMsgCtx); + return jWTAccessTokenOIDCClaimsHandler; } private OAuthTokenReqMessageContext getTokenReqMessageContextForLocalUser() { @@ -515,4 +572,13 @@ private void setPrivateField(Object object, String fieldName, Object value) thro field.set(object, value); } + private OAuthAuthzReqMessageContext getOAuthAuthzReqMessageContextForLocalUser() { + + OAuth2AuthorizeReqDTO oAuth2AuthorizeReqDTO = new OAuth2AuthorizeReqDTO(); + oAuth2AuthorizeReqDTO.setTenantDomain(TENANT_DOMAIN); + oAuth2AuthorizeReqDTO.setConsumerKey(DUMMY_CLIENT_ID); + oAuth2AuthorizeReqDTO.setUser(getDefaultAuthenticatedLocalUser()); + + return new OAuthAuthzReqMessageContext(oAuth2AuthorizeReqDTO); + } } From 8f4ba1d8e73b6a0afdbdc8a5f7484b15c12d890f Mon Sep 17 00:00:00 2001 From: Indeewai Wijesiri Date: Wed, 4 Dec 2024 16:01:24 +0530 Subject: [PATCH 2/3] Fixing styling --- .../openidconnect/JWTAccessTokenOIDCClaimsHandlerTest.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandlerTest.java b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandlerTest.java index a86baca2a3..408459fdc0 100644 --- a/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandlerTest.java +++ b/components/org.wso2.carbon.identity.oauth/src/test/java/org/wso2/carbon/identity/openidconnect/JWTAccessTokenOIDCClaimsHandlerTest.java @@ -391,7 +391,8 @@ public void testHandleCustomClaimsForOAuthAuthzReqMsgContext() throws Exception mockApplicationManagementService(); authzUtil.when(() -> AuthzUtil.getUserRoles(any(), anyString())).thenReturn(new ArrayList<>()); UserRealm userRealm = getUserRealmWithUserClaims(USER_CLAIMS_MAP); - mockUserRealm(requestMsgCtx.getAuthorizationReqDTO().getUser().toString(), userRealm, identityTenantUtil); + mockUserRealm(requestMsgCtx.getAuthorizationReqDTO().getUser().toString(), userRealm, + identityTenantUtil); JWTClaimsSet.Builder jwtClaimsSetBuilder = new JWTClaimsSet.Builder(); JWTClaimsSet jwtClaimsSet = getJwtClaimSet(jwtClaimsSetBuilder, requestMsgCtx, jdbcPersistenceManager, oAuthServerConfiguration); @@ -489,9 +490,7 @@ private JWTAccessTokenOIDCClaimsHandler getJwtAccessTokenOIDCClaimsHandler( jdbcPersistenceManager.when(JDBCPersistenceManager::getInstance).thenReturn(mockJdbcPersistenceManager); lenient().when(mockJdbcPersistenceManager.getDataSource()).thenReturn(dataSource); - JWTAccessTokenOIDCClaimsHandler jWTAccessTokenOIDCClaimsHandler = - new JWTAccessTokenOIDCClaimsHandler(); - return jWTAccessTokenOIDCClaimsHandler; + return new JWTAccessTokenOIDCClaimsHandler(); } private OAuthTokenReqMessageContext getTokenReqMessageContextForLocalUser() { From 0a9904ade420856bde0f697367eb6fc396c7da5c Mon Sep 17 00:00:00 2001 From: Indeewai Wijesiri Date: Thu, 5 Dec 2024 07:09:53 +0530 Subject: [PATCH 3/3] Adding the test class to testng file --- .../org.wso2.carbon.identity.oauth/src/test/resources/testng.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml b/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml index 0f4c1fe1ed..a537de4912 100755 --- a/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml +++ b/components/org.wso2.carbon.identity.oauth/src/test/resources/testng.xml @@ -199,6 +199,7 @@ +