From 47a9d86afbf713503cefff250f5be779c78c7c4e Mon Sep 17 00:00:00 2001 From: Yasasr1 Date: Wed, 1 Nov 2023 09:08:16 +0530 Subject: [PATCH 1/5] update token exchange tests --- .../AbstractIdentityFederationTestCase.java | 23 ++ .../OAuth2TokenExchangeGrantTypeTestCase.java | 240 +++++++++++++++++- .../test/utils/IdentityConstants.java | 7 + 3 files changed, 264 insertions(+), 6 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/application/mgt/AbstractIdentityFederationTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/application/mgt/AbstractIdentityFederationTestCase.java index 0aa3429c295..f8d4a39698c 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/application/mgt/AbstractIdentityFederationTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/application/mgt/AbstractIdentityFederationTestCase.java @@ -40,7 +40,9 @@ import org.wso2.carbon.identity.sso.saml.stub.types.SAMLSSOServiceProviderDTO; import org.wso2.carbon.identity.sso.saml.stub.types.SAMLSSOServiceProviderInfoDTO; import org.wso2.carbon.integration.common.admin.client.AuthenticatorClient; +import org.wso2.carbon.user.mgt.stub.types.carbon.ClaimValue; import org.wso2.identity.integration.common.clients.Idp.IdentityProviderMgtServiceClient; +import org.wso2.identity.integration.common.clients.UserManagementClient; import org.wso2.identity.integration.common.clients.application.mgt.ApplicationManagementServiceClient; import org.wso2.identity.integration.common.clients.oauth.OauthAdminClient; import org.wso2.identity.integration.common.clients.sso.saml.SAMLSSOConfigServiceClient; @@ -62,6 +64,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.Map; @@ -73,6 +76,7 @@ public abstract class AbstractIdentityFederationTestCase extends ISIntegrationTe private Map oauthAdminClients; private Map applicationManagementRestClients; private Map identityProviderMgtRestClients; + private Map userManagementClients; protected Map automationContextMap; private MultipleServersManager manager; protected static final int DEFAULT_PORT = CommonConstants.IS_DEFAULT_HTTPS_PORT; @@ -87,6 +91,7 @@ public void initTest() throws Exception { identityProviderMgtServiceClients = new HashMap<>(); samlSSOConfigServiceClients = new HashMap<>(); oauthAdminClients = new HashMap<>(); + userManagementClients = new HashMap<>(); automationContextMap = testDataHolder.getAutomationContextMap(); manager = testDataHolder.getManager(); @@ -144,6 +149,8 @@ public void createServiceClients(int portOffset, String sessionCookie, samlSSOConfigServiceClients.put(portOffset, new SAMLSSOConfigServiceClient(serviceUrl, sessionCookie)); } else if (IdentityConstants.ServiceClientType.OAUTH_ADMIN.equals(clientType)) { oauthAdminClients.put(portOffset, new OauthAdminClient(serviceUrl, sessionCookie)); + } else if (IdentityConstants.ServiceClientType.USER_MGT.equals(clientType)) { + userManagementClients.put(portOffset, new UserManagementClient(serviceUrl, sessionCookie)); } } } @@ -169,6 +176,22 @@ public void createServiceClients(int portOffset, IdentityConstants.ServiceClient } } + public void addUser(int portOffset, String username, String password, String[] roles, + String profileName, ClaimValue[] claims) throws Exception { + + userManagementClients.get(portOffset).addUser(username, password, roles, profileName, claims); + } + + public void deleteUser(int portOffset, String username) throws Exception { + + userManagementClients.get(portOffset).deleteUser(username); + } + + public HashSet getUserList(int portOffset) throws Exception { + + return userManagementClients.get(portOffset).getUserList(); + } + public void addServiceProvider(int portOffset, String applicationName) throws Exception { ServiceProvider serviceProvider = new ServiceProvider(); diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java index c5412874012..0ab3729c659 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java @@ -17,6 +17,7 @@ */ package org.wso2.identity.integration.test.oauth2; +import com.nimbusds.jwt.SignedJWT; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpResponse; @@ -45,6 +46,8 @@ import org.testng.annotations.Test; import org.wso2.carbon.automation.engine.context.AutomationContext; import org.wso2.carbon.automation.engine.context.TestUserMode; +import org.wso2.carbon.identity.application.common.model.xsd.Claim; +import org.wso2.carbon.identity.application.common.model.xsd.ClaimMapping; import org.wso2.carbon.identity.application.common.model.idp.xsd.IdentityProvider; import org.wso2.carbon.identity.application.common.model.idp.xsd.IdentityProviderProperty; import org.wso2.carbon.identity.application.common.model.xsd.InboundAuthenticationRequestConfig; @@ -52,13 +55,18 @@ import org.wso2.carbon.identity.application.common.model.xsd.ServiceProvider; import org.wso2.carbon.identity.oauth.stub.dto.OAuthConsumerAppDTO; import org.wso2.carbon.integration.common.admin.client.AuthenticatorClient; +import org.wso2.carbon.user.mgt.stub.types.carbon.ClaimValue; +import org.wso2.carbon.utils.multitenancy.MultitenantUtils; import org.wso2.identity.integration.common.clients.oauth.OauthAdminClient; import org.wso2.identity.integration.test.application.mgt.AbstractIdentityFederationTestCase; import org.wso2.identity.integration.test.oidc.bean.OIDCApplication; import org.wso2.identity.integration.test.utils.IdentityConstants; import org.wso2.identity.integration.test.utils.OAuth2Constant; +import org.wso2.identity.integration.test.utils.UserUtil; +import java.text.ParseException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; public class OAuth2TokenExchangeGrantTypeTestCase extends AbstractIdentityFederationTestCase { @@ -69,6 +77,10 @@ public class OAuth2TokenExchangeGrantTypeTestCase extends AbstractIdentityFedera private static final String SECONDARY_IS_SP_NAME = "secondarySP"; private static final String SECONDARY_IS_TOKEN_ENDPOINT = "https://localhost:9854/oauth2/token"; private static final String SECONDARY_IS_JWKS_URI = "https://localhost:9854/oauth2/jwks"; + private static final String NEW_USER_USERNAME = "secondaryUser"; + private static final String NEW_USER_EMAIL = "secondaryUser@gmail.com"; + private static final String NEW_USER_PASSWORD = "Wso2@123"; + public static final String EMAIL_CLAIM_URI = "http://wso2.org/claims/emailaddress"; protected OauthAdminClient adminClient; private String secondaryISClientID; @@ -79,9 +91,12 @@ public class OAuth2TokenExchangeGrantTypeTestCase extends AbstractIdentityFedera private final String userPassword; private final AutomationContext context; private String accessTokenFromSecondaryIS; + private String primaryISUserId; + private String secondaryISUserId; private static final int PORT_OFFSET_0 = 0; private static final int PORT_OFFSET_1 = 1; + private static final String DEFAULT_PROFILE = "default"; CookieStore cookieStore; private CloseableHttpClient client; @@ -114,16 +129,20 @@ public void initTest() throws Exception { new IdentityConstants.ServiceClientType[]{ IdentityConstants.ServiceClientType.APPLICATION_MANAGEMENT, IdentityConstants.ServiceClientType.IDENTITY_PROVIDER_MGT, + IdentityConstants.ServiceClientType.USER_MGT, IdentityConstants.ServiceClientType.OAUTH_ADMIN}); super.createServiceClients(PORT_OFFSET_1, null, new IdentityConstants.ServiceClientType[]{ IdentityConstants.ServiceClientType.APPLICATION_MANAGEMENT, + IdentityConstants.ServiceClientType.USER_MGT, IdentityConstants.ServiceClientType.OAUTH_ADMIN}); createServiceProviderInSecondaryIS(); createServiceProviderInPrimaryIS(); createIdentityProviderInPrimaryIS(); + createUser(PORT_OFFSET_1); + updateServiceProviderRequestedClaimsInSecondaryIS(); cookieStore = new BasicCookieStore(); Lookup cookieSpecRegistry = RegistryBuilder.create() @@ -153,34 +172,243 @@ public void endTest() throws Exception { } } - @Test(groups = "wso2.is", description = "Get a Access Token From Secondary IS") - public void testGetAccessTokenFromSecondaryIS() throws Exception { + private void getAccessTokenFromSecondaryIS(String username, String password) throws Exception { List postParameters = new ArrayList<>(); postParameters.add(new BasicNameValuePair("username", username)); - postParameters.add(new BasicNameValuePair("password", userPassword)); + postParameters.add(new BasicNameValuePair("password", password)); postParameters.add(new BasicNameValuePair("grant_type", OAuth2Constant.OAUTH2_GRANT_TYPE_RESOURCE_OWNER)); + postParameters.add(new BasicNameValuePair("scope", "email")); JSONObject responseObject = sendPOSTMessage(SECONDARY_IS_TOKEN_ENDPOINT, secondaryISClientID, secondaryISClientSecret, postParameters); accessTokenFromSecondaryIS = responseObject.get("access_token").toString(); Assert.assertNotNull(accessTokenFromSecondaryIS, "Access token is null."); + secondaryISUserId = getTokenSubject(accessTokenFromSecondaryIS); } - @Test(groups = "wso2.is", description = "Exchange Access Token", dependsOnMethods = { - "testGetAccessTokenFromSecondaryIS"}) - public void testTokenExchange() throws Exception { + @Test(groups = "wso2.is", description = "Exchange access token for federated user") + public void testTokenExchangeForFederatedUser() throws Exception { + + // get an access token for a user that doesn't exist in primary IS + getAccessTokenFromSecondaryIS(NEW_USER_USERNAME, NEW_USER_PASSWORD); + + List postParameters = getTokenExchangePostParameters(); + + // assert local subject identifier config is disabled + AssertExchangedTokenForFederatedUser(postParameters); + + // assert local subject identifier config is optional, no local user available + updateAssertLocalSubjectIdentifierConfig(IdentityConstants.AssertLocalSubjectMode.OPTIONAL); + AssertExchangedTokenForFederatedUser(postParameters); + + // create a similar user in primary IS + createUser(PORT_OFFSET_0); + primaryISUserId = UserUtil.getUserId(MultitenantUtils.getTenantAwareUsername(NEW_USER_USERNAME), + isServer.getContextTenant()); + + //assert local subject identifier config is optional, local user is available and implicit association config is disabled + AssertExchangedTokenForFederatedUser(postParameters); + } + + @Test(groups = "wso2.is", description = "Exchange access token for local user", + dependsOnMethods = "testTokenExchangeForFederatedUser") + public void testTokenExchangeForLocalUser() throws Exception { + + //enable implicit association config and set lookup attribute to email + updateIdentityProviderAssociationConfig(true); + List postParameters = getTokenExchangePostParameters(); + AssertExchangedTokenForLocalUser(postParameters); + } + + @Test(groups = "wso2.is", description = "Exchange access token for local user with implicit association config disabled", + dependsOnMethods = "testTokenExchangeForLocalUser") + public void testTokenExchangeForLocalUserWithImplicitAssociationConfigDisabled() throws Exception { + + //assert local subject identifier config is mandatory, implicit association config disabled + updateIdentityProviderAssociationConfig(false); + updateAssertLocalSubjectIdentifierConfig(IdentityConstants.AssertLocalSubjectMode.MANDATORY); + List postParameters = getTokenExchangePostParameters(); + AssertUnauthorizedResponse(postParameters); + } + + @Test(groups = "wso2.is", description = "Exchange access token for local user with no local account", + dependsOnMethods = "testTokenExchangeForLocalUserWithImplicitAssociationConfigDisabled") + public void testTokenExchangeForLocalUserWithNoLocalAccount() throws Exception { + + //assert local subject identifier config is mandatory, no matching local user account + deleteUser(PORT_OFFSET_0, NEW_USER_USERNAME); + List postParameters = getTokenExchangePostParameters(); + AssertUnauthorizedResponse(postParameters); + } + + private List getTokenExchangePostParameters() { List postParameters = new ArrayList<>(); postParameters.add(new BasicNameValuePair("subject_token", accessTokenFromSecondaryIS)); postParameters.add(new BasicNameValuePair("subject_token_type", "urn:ietf:params:oauth:token-type:jwt")); postParameters.add(new BasicNameValuePair("requested_token_type", "urn:ietf:params:oauth:token-type:jwt")); postParameters.add(new BasicNameValuePair("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange")); + return postParameters; + } + + private void AssertExchangedTokenForFederatedUser(List postParameters) throws Exception { + JSONObject responseObject = sendPOSTMessage(PRIMARY_IS_TOKEN_ENDPOINT, primaryISClientID, primaryISClientSecret, postParameters); String exchangedToken = responseObject.get("access_token").toString(); + Assert.assertNotNull(exchangedToken, "Access token is null."); + Assert.assertEquals(getTokenSubject(exchangedToken), secondaryISUserId, "Subject of the exchanged " + + "token should be the same as the subject of the subject token."); + } + + private void AssertExchangedTokenForLocalUser(List postParameters) throws Exception { + JSONObject responseObject = sendPOSTMessage(PRIMARY_IS_TOKEN_ENDPOINT, primaryISClientID, primaryISClientSecret, + postParameters); + String exchangedToken = responseObject.get("access_token").toString(); Assert.assertNotNull(exchangedToken, "Access token is null."); + Assert.assertEquals(getTokenSubject(exchangedToken), primaryISUserId, "Subject of the exchanged " + + "token should be the same as the subject of the matching local user."); + } + + private void AssertUnauthorizedResponse(List postParameters) throws Exception { + + HttpPost httpPost = new HttpPost(PRIMARY_IS_TOKEN_ENDPOINT); + httpPost.setHeader("Authorization", "Basic " + getBase64EncodedString(primaryISClientID, primaryISClientSecret)); + httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded"); + httpPost.setEntity(new UrlEncodedFormEntity(postParameters)); + HttpResponse response = client.execute(httpPost); + Assert.assertEquals(response.getStatusLine().getStatusCode(), 401, "401 response expected but got: " + response + .getStatusLine().getStatusCode()); + } + + private String getTokenSubject(String token) throws Exception { + + SignedJWT signedJWT; + try { + signedJWT = SignedJWT.parse(token); + } catch (ParseException e) { + throw new Exception("Error while parsing the JWT", e); + } + + return signedJWT.getJWTClaimsSet().getSubject(); + } + + private void createUser(int portOffset) throws Exception { + + List claimValues = new ArrayList<>(); + ClaimValue claimValue = new ClaimValue(); + claimValue.setClaimURI(EMAIL_CLAIM_URI); + claimValue.setValue(NEW_USER_EMAIL); + claimValues.add(claimValue); + super.addUser(portOffset, OAuth2TokenExchangeGrantTypeTestCase.NEW_USER_USERNAME, + OAuth2TokenExchangeGrantTypeTestCase.NEW_USER_PASSWORD, null, DEFAULT_PROFILE, claimValues.toArray(new ClaimValue[0])); + HashSet users = super.getUserList(PORT_OFFSET_1); + Assert.assertTrue(users.contains(OAuth2TokenExchangeGrantTypeTestCase.NEW_USER_USERNAME), "User creation failed in IS: " + + portOffset); + } + + private void updateAssertLocalSubjectIdentifierConfig(IdentityConstants.AssertLocalSubjectMode updateMode) throws Exception { + + ServiceProvider serviceProvider = getServiceProvider(PORT_OFFSET_0, PRIMARY_IS_SP_NAME); + Assert.assertNotNull(serviceProvider, "Failed to get service provider 'primarySP' in primary IS"); + + switch (updateMode) { + case OPTIONAL: + serviceProvider.getClaimConfig().setAlwaysSendMappedLocalSubjectId(true); + serviceProvider.getClaimConfig().setMappedLocalSubjectMandatory(false); + break; + case MANDATORY: + serviceProvider.getClaimConfig().setAlwaysSendMappedLocalSubjectId(true); + serviceProvider.getClaimConfig().setMappedLocalSubjectMandatory(true); + break; + default: + serviceProvider.getClaimConfig().setAlwaysSendMappedLocalSubjectId(false); + serviceProvider.getClaimConfig().setMappedLocalSubjectMandatory(false); + } + + super.updateServiceProvider(PORT_OFFSET_0, serviceProvider); + + ServiceProvider updatedServiceProvider = getServiceProvider(PORT_OFFSET_0, PRIMARY_IS_SP_NAME); + + switch (updateMode) { + case OPTIONAL: + Assert.assertTrue(updatedServiceProvider.getClaimConfig().getAlwaysSendMappedLocalSubjectId(), + "Always send mapped local subject id is not updated properly"); + Assert.assertFalse(updatedServiceProvider.getClaimConfig().getMappedLocalSubjectMandatory(), + "Mapped local subject mandatory is not updated properly"); + break; + case MANDATORY: + Assert.assertTrue(updatedServiceProvider.getClaimConfig().getAlwaysSendMappedLocalSubjectId(), + "Always send mapped local subject id is not updated properly"); + Assert.assertTrue(updatedServiceProvider.getClaimConfig().getMappedLocalSubjectMandatory(), + "Mapped local subject mandatory is not updated properly"); + break; + default: + Assert.assertFalse(updatedServiceProvider.getClaimConfig().getAlwaysSendMappedLocalSubjectId(), + "Always send mapped local subject id is not updated properly"); + Assert.assertFalse(updatedServiceProvider.getClaimConfig().getMappedLocalSubjectMandatory(), + "Mapped local subject mandatory is not updated properly"); + } + } + + private void updateIdentityProviderAssociationConfig(boolean enabled) throws Exception { + + IdentityProvider identityProvider = super.getIdentityProvider(PORT_OFFSET_0, PRIMARY_IS_IDP_NAME); + Assert.assertNotNull(identityProvider, "Failed to get identity provider 'trustedIdP' in primary IS"); + + identityProvider.getFederatedAssociationConfig().setEnabled(enabled); + if (enabled) { + identityProvider.getFederatedAssociationConfig().setLookupAttributes(new String[]{EMAIL_CLAIM_URI}); + + } + + super.updateIdentityProvider(PORT_OFFSET_0, PRIMARY_IS_IDP_NAME, identityProvider); + + IdentityProvider updatedIdentityProvider = super.getIdentityProvider(PORT_OFFSET_0, PRIMARY_IS_IDP_NAME); + Assert.assertNotNull(updatedIdentityProvider, "Failed to get identity provider 'trustedIdP' in primary IS"); + if (enabled) { + Assert.assertTrue(updatedIdentityProvider.getFederatedAssociationConfig().getEnabled(), "Federated " + + "association config is not updated properly"); + Assert.assertEquals(updatedIdentityProvider.getFederatedAssociationConfig().getLookupAttributes()[0], + EMAIL_CLAIM_URI, "Federated association config is not updated properly"); + } else { + Assert.assertFalse(updatedIdentityProvider.getFederatedAssociationConfig().getEnabled(), "Federated " + + "association config is not updated properly"); + } + + } + + private void updateServiceProviderRequestedClaimsInSecondaryIS() throws Exception { + + ServiceProvider serviceProvider = getServiceProvider(PORT_OFFSET_1, SECONDARY_IS_SP_NAME); + Assert.assertNotNull(serviceProvider, "Failed to get service provider 'primarySP' in primary IS"); + + List claimMappings = getClaimMappings(); + serviceProvider.getClaimConfig().setClaimMappings(claimMappings.toArray(new ClaimMapping[0])); + + super.updateServiceProvider(PORT_OFFSET_1, serviceProvider); + ServiceProvider updatedServiceProvider = getServiceProvider(PORT_OFFSET_1, SECONDARY_IS_SP_NAME); + Assert.assertNotNull(updatedServiceProvider, "Failed to get service provider 'primarySP' in primary IS"); + Assert.assertNotNull(updatedServiceProvider.getClaimConfig().getClaimMappings(), "Claim mappings are not " + + "updated properly"); + } + + private List getClaimMappings() { + + List claimMappings = new ArrayList<>(); + ClaimMapping claimMapping = new ClaimMapping(); + Claim localClaim = new Claim(); + Claim remoteClaim = new Claim(); + + localClaim.setClaimUri(EMAIL_CLAIM_URI); + remoteClaim.setClaimUri(EMAIL_CLAIM_URI); + claimMapping.setLocalClaim(localClaim); + claimMapping.setRemoteClaim(remoteClaim); + claimMapping.setRequested(true); + claimMappings.add(claimMapping); + return claimMappings; } private JSONObject sendPOSTMessage(String endpoint, String clientID, String clientSecret, diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/IdentityConstants.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/IdentityConstants.java index 9fe0be9e1bb..d256e274eea 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/IdentityConstants.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/utils/IdentityConstants.java @@ -55,5 +55,12 @@ public static enum ServiceClientType { IDENTITY_PROVIDER_MGT, SAML_SSO_CONFIG, OAUTH_ADMIN, + USER_MGT, + } + + public static enum AssertLocalSubjectMode { + DISABLED, + OPTIONAL, + MANDATORY } } From 0ba86048d3dc1f60b33987d2ce658b7aaa73894d Mon Sep 17 00:00:00 2001 From: Yasasr1 Date: Tue, 7 Nov 2023 09:37:53 +0530 Subject: [PATCH 2/5] refactor tests --- .../OAuth2TokenExchangeGrantTypeTestCase.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java index 0ab3729c659..18a4ca921cc 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java @@ -172,11 +172,12 @@ public void endTest() throws Exception { } } - private void getAccessTokenFromSecondaryIS(String username, String password) throws Exception { + @Test(groups = "wso2.is", description = "Get a Access Token From Secondary IS") + public void testGetAccessTokenFromSecondaryIS() throws Exception { List postParameters = new ArrayList<>(); - postParameters.add(new BasicNameValuePair("username", username)); - postParameters.add(new BasicNameValuePair("password", password)); + postParameters.add(new BasicNameValuePair("username", OAuth2TokenExchangeGrantTypeTestCase.NEW_USER_USERNAME)); + postParameters.add(new BasicNameValuePair("password", OAuth2TokenExchangeGrantTypeTestCase.NEW_USER_PASSWORD)); postParameters.add(new BasicNameValuePair("grant_type", OAuth2Constant.OAUTH2_GRANT_TYPE_RESOURCE_OWNER)); postParameters.add(new BasicNameValuePair("scope", "email")); JSONObject responseObject = sendPOSTMessage(SECONDARY_IS_TOKEN_ENDPOINT, secondaryISClientID, @@ -187,12 +188,10 @@ private void getAccessTokenFromSecondaryIS(String username, String password) thr secondaryISUserId = getTokenSubject(accessTokenFromSecondaryIS); } - @Test(groups = "wso2.is", description = "Exchange access token for federated user") + @Test(groups = "wso2.is", description = "Exchange access token for federated user", + dependsOnMethods = "testGetAccessTokenFromSecondaryIS") public void testTokenExchangeForFederatedUser() throws Exception { - // get an access token for a user that doesn't exist in primary IS - getAccessTokenFromSecondaryIS(NEW_USER_USERNAME, NEW_USER_PASSWORD); - List postParameters = getTokenExchangePostParameters(); // assert local subject identifier config is disabled From 75ace2037227dfc5018c6c9afff5b3e83995533d Mon Sep 17 00:00:00 2001 From: Yasasr1 Date: Wed, 8 Nov 2023 11:40:10 +0530 Subject: [PATCH 3/5] address review comments --- .../OAuth2TokenExchangeGrantTypeTestCase.java | 164 +++++++++++------- 1 file changed, 103 insertions(+), 61 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java index 18a4ca921cc..a81f1a5e744 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java @@ -66,8 +66,8 @@ import java.text.ParseException; import java.util.ArrayList; -import java.util.HashSet; import java.util.List; +import java.util.Set; public class OAuth2TokenExchangeGrantTypeTestCase extends AbstractIdentityFederationTestCase { @@ -192,14 +192,20 @@ public void testGetAccessTokenFromSecondaryIS() throws Exception { dependsOnMethods = "testGetAccessTokenFromSecondaryIS") public void testTokenExchangeForFederatedUser() throws Exception { + String exchangedToken; List postParameters = getTokenExchangePostParameters(); // assert local subject identifier config is disabled - AssertExchangedTokenForFederatedUser(postParameters); + exchangedToken = exchangeToken(postParameters); + Assert.assertEquals(getTokenSubject(exchangedToken), secondaryISUserId, "Subject of the exchanged " + + "token should be the same as the subject of the federated user"); + // assert local subject identifier config is optional, no local user available updateAssertLocalSubjectIdentifierConfig(IdentityConstants.AssertLocalSubjectMode.OPTIONAL); - AssertExchangedTokenForFederatedUser(postParameters); + exchangedToken = exchangeToken(postParameters); + Assert.assertEquals(getTokenSubject(exchangedToken), secondaryISUserId, "Subject of the exchanged " + + "token should be the same as the subject of the federated user"); // create a similar user in primary IS createUser(PORT_OFFSET_0); @@ -207,38 +213,58 @@ public void testTokenExchangeForFederatedUser() throws Exception { isServer.getContextTenant()); //assert local subject identifier config is optional, local user is available and implicit association config is disabled - AssertExchangedTokenForFederatedUser(postParameters); + exchangedToken = exchangeToken(postParameters); + Assert.assertEquals(getTokenSubject(exchangedToken), secondaryISUserId, "Subject of the exchanged " + + "token should be the same as the subject of the federated user"); } - @Test(groups = "wso2.is", description = "Exchange access token for local user", + @Test(groups = "wso2.is", description = "Exchange access token for local user with implicit association config disabled", dependsOnMethods = "testTokenExchangeForFederatedUser") + public void testTokenExchangeForLocalUserWithImplicitAssociationConfigDisabled() throws Exception { + + //assert local subject identifier config is mandatory, implicit association config disabled, no associations + updateIdentityProviderAssociationConfig(false); + updateAssertLocalSubjectIdentifierConfig(IdentityConstants.AssertLocalSubjectMode.MANDATORY); + List postParameters = getTokenExchangePostParameters(); + int responseCode = getResponseStatus(postParameters); + Assert.assertEquals(responseCode, 401, "401 response expected but got: " + responseCode); + + } + + @Test(groups = "wso2.is", description = "Exchange access token for local user", + dependsOnMethods = "testTokenExchangeForLocalUserWithImplicitAssociationConfigDisabled") public void testTokenExchangeForLocalUser() throws Exception { //enable implicit association config and set lookup attribute to email updateIdentityProviderAssociationConfig(true); List postParameters = getTokenExchangePostParameters(); - AssertExchangedTokenForLocalUser(postParameters); + String exchangedToken = exchangeToken(postParameters); + Assert.assertEquals(getTokenSubject(exchangedToken), primaryISUserId, "Subject of the exchanged " + + "token should be the same as the subject of the matching local user."); } @Test(groups = "wso2.is", description = "Exchange access token for local user with implicit association config disabled", dependsOnMethods = "testTokenExchangeForLocalUser") - public void testTokenExchangeForLocalUserWithImplicitAssociationConfigDisabled() throws Exception { + public void testTokenExchangeForAssociatedLocalUserWithImplicitAssociationConfigDisabled() throws Exception { - //assert local subject identifier config is mandatory, implicit association config disabled + //assert local subject identifier config is mandatory, implicit association config disabled, association exists updateIdentityProviderAssociationConfig(false); updateAssertLocalSubjectIdentifierConfig(IdentityConstants.AssertLocalSubjectMode.MANDATORY); List postParameters = getTokenExchangePostParameters(); - AssertUnauthorizedResponse(postParameters); + String exchangedToken = exchangeToken(postParameters); + Assert.assertEquals(getTokenSubject(exchangedToken), primaryISUserId, "Subject of the exchanged " + + "token should be the same as the subject of the matching local user."); } @Test(groups = "wso2.is", description = "Exchange access token for local user with no local account", - dependsOnMethods = "testTokenExchangeForLocalUserWithImplicitAssociationConfigDisabled") + dependsOnMethods = "testTokenExchangeForAssociatedLocalUserWithImplicitAssociationConfigDisabled") public void testTokenExchangeForLocalUserWithNoLocalAccount() throws Exception { //assert local subject identifier config is mandatory, no matching local user account deleteUser(PORT_OFFSET_0, NEW_USER_USERNAME); List postParameters = getTokenExchangePostParameters(); - AssertUnauthorizedResponse(postParameters); + int responseCode = getResponseStatus(postParameters); + Assert.assertEquals(responseCode, 401, "401 response expected but got: " + responseCode); } private List getTokenExchangePostParameters() { @@ -251,35 +277,26 @@ private List getTokenExchangePostParameters() { return postParameters; } - private void AssertExchangedTokenForFederatedUser(List postParameters) throws Exception { + private String exchangeToken(List postParameters) throws Exception { JSONObject responseObject = sendPOSTMessage(PRIMARY_IS_TOKEN_ENDPOINT, primaryISClientID, primaryISClientSecret, postParameters); String exchangedToken = responseObject.get("access_token").toString(); - Assert.assertNotNull(exchangedToken, "Access token is null."); - Assert.assertEquals(getTokenSubject(exchangedToken), secondaryISUserId, "Subject of the exchanged " + - "token should be the same as the subject of the subject token."); - } - - private void AssertExchangedTokenForLocalUser(List postParameters) throws Exception { + if (StringUtils.isBlank(exchangedToken)) { + throw new Exception("Access token is null."); + } - JSONObject responseObject = sendPOSTMessage(PRIMARY_IS_TOKEN_ENDPOINT, primaryISClientID, primaryISClientSecret, - postParameters); - String exchangedToken = responseObject.get("access_token").toString(); - Assert.assertNotNull(exchangedToken, "Access token is null."); - Assert.assertEquals(getTokenSubject(exchangedToken), primaryISUserId, "Subject of the exchanged " + - "token should be the same as the subject of the matching local user."); + return exchangedToken; } - private void AssertUnauthorizedResponse(List postParameters) throws Exception { + private int getResponseStatus(List postParameters) throws Exception { HttpPost httpPost = new HttpPost(PRIMARY_IS_TOKEN_ENDPOINT); httpPost.setHeader("Authorization", "Basic " + getBase64EncodedString(primaryISClientID, primaryISClientSecret)); httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded"); httpPost.setEntity(new UrlEncodedFormEntity(postParameters)); HttpResponse response = client.execute(httpPost); - Assert.assertEquals(response.getStatusLine().getStatusCode(), 401, "401 response expected but got: " + response - .getStatusLine().getStatusCode()); + return response.getStatusLine().getStatusCode(); } private String getTokenSubject(String token) throws Exception { @@ -303,15 +320,18 @@ private void createUser(int portOffset) throws Exception { claimValues.add(claimValue); super.addUser(portOffset, OAuth2TokenExchangeGrantTypeTestCase.NEW_USER_USERNAME, OAuth2TokenExchangeGrantTypeTestCase.NEW_USER_PASSWORD, null, DEFAULT_PROFILE, claimValues.toArray(new ClaimValue[0])); - HashSet users = super.getUserList(PORT_OFFSET_1); - Assert.assertTrue(users.contains(OAuth2TokenExchangeGrantTypeTestCase.NEW_USER_USERNAME), "User creation failed in IS: " + - portOffset); + Set users = super.getUserList(PORT_OFFSET_1); + if (users == null || !users.contains(OAuth2TokenExchangeGrantTypeTestCase.NEW_USER_USERNAME)) { + throw new Exception("User creation failed in IS: " + portOffset); + } } private void updateAssertLocalSubjectIdentifierConfig(IdentityConstants.AssertLocalSubjectMode updateMode) throws Exception { ServiceProvider serviceProvider = getServiceProvider(PORT_OFFSET_0, PRIMARY_IS_SP_NAME); - Assert.assertNotNull(serviceProvider, "Failed to get service provider 'primarySP' in primary IS"); + if (serviceProvider == null) { + throw new Exception("Failed to get service provider 'primarySP' in primary IS"); + } switch (updateMode) { case OPTIONAL: @@ -333,29 +353,31 @@ private void updateAssertLocalSubjectIdentifierConfig(IdentityConstants.AssertLo switch (updateMode) { case OPTIONAL: - Assert.assertTrue(updatedServiceProvider.getClaimConfig().getAlwaysSendMappedLocalSubjectId(), - "Always send mapped local subject id is not updated properly"); - Assert.assertFalse(updatedServiceProvider.getClaimConfig().getMappedLocalSubjectMandatory(), - "Mapped local subject mandatory is not updated properly"); + if (!updatedServiceProvider.getClaimConfig().getAlwaysSendMappedLocalSubjectId() || + updatedServiceProvider.getClaimConfig().getMappedLocalSubjectMandatory()) { + throw new Exception("Assert local subject identifier configuration is not updated properly"); + } break; case MANDATORY: - Assert.assertTrue(updatedServiceProvider.getClaimConfig().getAlwaysSendMappedLocalSubjectId(), - "Always send mapped local subject id is not updated properly"); - Assert.assertTrue(updatedServiceProvider.getClaimConfig().getMappedLocalSubjectMandatory(), - "Mapped local subject mandatory is not updated properly"); + if (!updatedServiceProvider.getClaimConfig().getAlwaysSendMappedLocalSubjectId() || + !updatedServiceProvider.getClaimConfig().getMappedLocalSubjectMandatory()) { + throw new Exception("Assert local subject identifier configuration is not updated properly"); + } break; default: - Assert.assertFalse(updatedServiceProvider.getClaimConfig().getAlwaysSendMappedLocalSubjectId(), - "Always send mapped local subject id is not updated properly"); - Assert.assertFalse(updatedServiceProvider.getClaimConfig().getMappedLocalSubjectMandatory(), - "Mapped local subject mandatory is not updated properly"); + if (updatedServiceProvider.getClaimConfig().getAlwaysSendMappedLocalSubjectId() || + updatedServiceProvider.getClaimConfig().getMappedLocalSubjectMandatory()) { + throw new Exception("Assert local subject identifier configuration is not updated properly"); + } } } private void updateIdentityProviderAssociationConfig(boolean enabled) throws Exception { IdentityProvider identityProvider = super.getIdentityProvider(PORT_OFFSET_0, PRIMARY_IS_IDP_NAME); - Assert.assertNotNull(identityProvider, "Failed to get identity provider 'trustedIdP' in primary IS"); + if (identityProvider == null) { + throw new Exception("Failed to get identity provider 'trustedIdP' in primary IS"); + } identityProvider.getFederatedAssociationConfig().setEnabled(enabled); if (enabled) { @@ -366,15 +388,18 @@ private void updateIdentityProviderAssociationConfig(boolean enabled) throws Exc super.updateIdentityProvider(PORT_OFFSET_0, PRIMARY_IS_IDP_NAME, identityProvider); IdentityProvider updatedIdentityProvider = super.getIdentityProvider(PORT_OFFSET_0, PRIMARY_IS_IDP_NAME); - Assert.assertNotNull(updatedIdentityProvider, "Failed to get identity provider 'trustedIdP' in primary IS"); + if (updatedIdentityProvider == null) { + throw new Exception("Failed to get updated identity provider 'trustedIdP' in primary IS"); + } if (enabled) { - Assert.assertTrue(updatedIdentityProvider.getFederatedAssociationConfig().getEnabled(), "Federated " + - "association config is not updated properly"); - Assert.assertEquals(updatedIdentityProvider.getFederatedAssociationConfig().getLookupAttributes()[0], - EMAIL_CLAIM_URI, "Federated association config is not updated properly"); + if (!updatedIdentityProvider.getFederatedAssociationConfig().getEnabled() || + !EMAIL_CLAIM_URI.equals(updatedIdentityProvider.getFederatedAssociationConfig().getLookupAttributes()[0])) { + throw new Exception("Federated association config is not updated properly"); + } } else { - Assert.assertFalse(updatedIdentityProvider.getFederatedAssociationConfig().getEnabled(), "Federated " + - "association config is not updated properly"); + if (updatedIdentityProvider.getFederatedAssociationConfig().getEnabled()) { + throw new Exception("Federated association config is not updated properly"); + } } } @@ -382,16 +407,22 @@ private void updateIdentityProviderAssociationConfig(boolean enabled) throws Exc private void updateServiceProviderRequestedClaimsInSecondaryIS() throws Exception { ServiceProvider serviceProvider = getServiceProvider(PORT_OFFSET_1, SECONDARY_IS_SP_NAME); - Assert.assertNotNull(serviceProvider, "Failed to get service provider 'primarySP' in primary IS"); + if (serviceProvider == null) { + throw new Exception("Failed to get service provider 'secondarySP' in secondary IS"); + } List claimMappings = getClaimMappings(); serviceProvider.getClaimConfig().setClaimMappings(claimMappings.toArray(new ClaimMapping[0])); super.updateServiceProvider(PORT_OFFSET_1, serviceProvider); ServiceProvider updatedServiceProvider = getServiceProvider(PORT_OFFSET_1, SECONDARY_IS_SP_NAME); - Assert.assertNotNull(updatedServiceProvider, "Failed to get service provider 'primarySP' in primary IS"); - Assert.assertNotNull(updatedServiceProvider.getClaimConfig().getClaimMappings(), "Claim mappings are not " + - "updated properly"); + if (updatedServiceProvider == null) { + throw new Exception("Failed to get updated service provider 'secondarySP' in secondary IS"); + } + + if (updatedServiceProvider.getClaimConfig().getClaimMappings() == null) { + throw new Exception("Claim mappings are not updated properly"); + } } private List getClaimMappings() { @@ -440,7 +471,9 @@ private void createServiceProviderInPrimaryIS() throws Exception { super.addServiceProvider(PORT_OFFSET_0, PRIMARY_IS_SP_NAME); ServiceProvider serviceProvider = getServiceProvider(PORT_OFFSET_0, PRIMARY_IS_SP_NAME); - Assert.assertNotNull(serviceProvider, "Failed to create service provider 'travelocity' in primary IS"); + if (serviceProvider == null) { + throw new Exception("Failed to create service provider 'travelocity' in primary IS"); + } updateServiceProviderWithOIDCConfigs(PORT_OFFSET_0, PRIMARY_IS_SP_NAME, serviceProvider); @@ -457,7 +490,10 @@ private void createServiceProviderInPrimaryIS() throws Exception { } } } - Assert.assertTrue(success, "Failed to update service provider with inbound OIDC configs in primary IS"); + + if (!success) { + throw new Exception("Failed to update service provider with inbound OIDC configs in primary IS"); + } } private void createServiceProviderInSecondaryIS() throws Exception { @@ -465,7 +501,9 @@ private void createServiceProviderInSecondaryIS() throws Exception { super.addServiceProvider(PORT_OFFSET_1, SECONDARY_IS_SP_NAME); ServiceProvider serviceProvider = getServiceProvider(PORT_OFFSET_1, SECONDARY_IS_SP_NAME); - Assert.assertNotNull(serviceProvider, "Failed to create service provider 'travelocity' in secondary IS"); + if (serviceProvider == null) { + throw new Exception("Failed to create service provider 'travelocity' in secondary IS"); + } updateServiceProviderWithOIDCConfigs(PORT_OFFSET_1, SECONDARY_IS_SP_NAME, serviceProvider); @@ -483,7 +521,10 @@ private void createServiceProviderInSecondaryIS() throws Exception { } } - Assert.assertTrue(success, "Failed to update service provider with inbound OIDC configs in secondary IS"); + + if(!success) { + throw new Exception("Failed to update service provider with inbound OIDC configs in secondary IS"); + } } private void createIdentityProviderInPrimaryIS() throws Exception { @@ -502,8 +543,9 @@ private void createIdentityProviderInPrimaryIS() throws Exception { identityProvider.setIdpProperties(properties); super.addIdentityProvider(PORT_OFFSET_0, identityProvider); - Assert.assertNotNull(getIdentityProvider(PORT_OFFSET_0, PRIMARY_IS_IDP_NAME), "Failed to create " + - "Identity Provider 'trustedIdP' in primary IS"); + if (getIdentityProvider(PORT_OFFSET_0, PRIMARY_IS_IDP_NAME) == null) { + throw new Exception("Failed to create Identity Provider 'trustedIdP' in primary IS"); + } } private OAuthConsumerAppDTO getOAuthConsumerAppDTO(OIDCApplication application) { From e22de736ffc31a4350459dbfb3151c8c1f150116 Mon Sep 17 00:00:00 2001 From: Yasasr1 Date: Wed, 8 Nov 2023 18:02:51 +0530 Subject: [PATCH 4/5] address review comments --- .../test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java index a81f1a5e744..221a4e6d0de 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java @@ -522,7 +522,7 @@ private void createServiceProviderInSecondaryIS() throws Exception { } } - if(!success) { + if (!success) { throw new Exception("Failed to update service provider with inbound OIDC configs in secondary IS"); } } From 51543b19a57571fbb50b3a9f6a7ba7d3c2e51d5a Mon Sep 17 00:00:00 2001 From: Yasasr1 Date: Tue, 14 Nov 2023 10:09:28 +0530 Subject: [PATCH 5/5] change expected response to 400 --- .../test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java index 221a4e6d0de..7c38b928861 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2TokenExchangeGrantTypeTestCase.java @@ -227,7 +227,7 @@ public void testTokenExchangeForLocalUserWithImplicitAssociationConfigDisabled() updateAssertLocalSubjectIdentifierConfig(IdentityConstants.AssertLocalSubjectMode.MANDATORY); List postParameters = getTokenExchangePostParameters(); int responseCode = getResponseStatus(postParameters); - Assert.assertEquals(responseCode, 401, "401 response expected but got: " + responseCode); + Assert.assertEquals(responseCode, 400, "400 response expected but got: " + responseCode); } @@ -264,7 +264,7 @@ public void testTokenExchangeForLocalUserWithNoLocalAccount() throws Exception { deleteUser(PORT_OFFSET_0, NEW_USER_USERNAME); List postParameters = getTokenExchangePostParameters(); int responseCode = getResponseStatus(postParameters); - Assert.assertEquals(responseCode, 401, "401 response expected but got: " + responseCode); + Assert.assertEquals(responseCode, 400, "400 response expected but got: " + responseCode); } private List getTokenExchangePostParameters() {