From 69aacefff9abfbcd226b538de85fd050607c6f3f Mon Sep 17 00:00:00 2001 From: Shenali Date: Mon, 16 Sep 2024 15:02:59 +0530 Subject: [PATCH 1/8] Add integration tests for pre issue access token auth code grant --- ...ssTokenClientCredentialsGrantTestCase.java | 2 +- .../PreIssueAccessTokenCodeGrantTestCase.java | 512 ++++++++++++++++++ ...IssueAccessTokenPasswordGrantTestCase.java | 3 +- .../actions/mockserver/ActionsMockServer.java | 187 ++++--- .../src/test/resources/testng.xml | 1 + 5 files changed, 614 insertions(+), 91 deletions(-) create mode 100644 modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java index 57b3af4cb9..e3c50f78d3 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java @@ -263,7 +263,7 @@ public void testTokenScopeOperations() throws Exception { Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_3)); Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_4)); Assert.assertFalse(ArrayUtils.contains(scopes, CUSTOM_SCOPE_3)); - Assert.assertFalse(ArrayUtils.contains(scopes, CUSTOM_SCOPE_2)); + Assert.assertFalse(ArrayUtils.contains(scopes, INTERNAL_ORG_USER_MANAGEMENT_CREATE)); } @Test(groups = "wso2.is", description = "Verify that the access token contains the updated 'aud' claims " + diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java new file mode 100644 index 0000000000..2b17e62d86 --- /dev/null +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java @@ -0,0 +1,512 @@ +/* + * Copyright (c) 2024, WSO2 LLC. (http://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.wso2.identity.integration.test.actions; + +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; +import org.apache.commons.lang.ArrayUtils; +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.config.CookieSpecs; +import org.apache.http.client.config.RequestConfig; +import org.apache.http.client.utils.URLEncodedUtils; +import org.apache.http.config.Lookup; +import org.apache.http.config.RegistryBuilder; +import org.apache.http.cookie.CookieSpecProvider; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.DefaultRedirectStrategy; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.cookie.RFC6265CookieSpecProvider; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.util.EntityUtils; +import org.json.JSONException; +import org.json.JSONObject; +import org.testng.Assert; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Test; +import org.wso2.carbon.automation.engine.context.TestUserMode; +import org.wso2.identity.integration.test.mocks.MockServer; +import org.wso2.identity.integration.test.oauth2.dataprovider.model.ApplicationConfig; +import org.wso2.identity.integration.test.oauth2.dataprovider.model.TokenScopes; +import org.wso2.identity.integration.test.oauth2.dataprovider.model.UserClaimConfig; +import org.wso2.identity.integration.test.rest.api.server.action.management.v1.model.ActionModel; +import org.wso2.identity.integration.test.rest.api.server.action.management.v1.model.AuthenticationType; +import org.wso2.identity.integration.test.rest.api.server.action.management.v1.model.Endpoint; +import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationResponseModel; +import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.OpenIDConnectConfiguration; +import org.wso2.identity.integration.test.rest.api.server.roles.v2.model.Audience; +import org.wso2.identity.integration.test.rest.api.server.roles.v2.model.Permission; +import org.wso2.identity.integration.test.rest.api.server.roles.v2.model.RoleV2; +import org.wso2.identity.integration.test.rest.api.user.common.model.Email; +import org.wso2.identity.integration.test.rest.api.user.common.model.ListObject; +import org.wso2.identity.integration.test.rest.api.user.common.model.Name; +import org.wso2.identity.integration.test.rest.api.user.common.model.PatchOperationRequestObject; +import org.wso2.identity.integration.test.rest.api.user.common.model.RoleItemAddGroupobj; +import org.wso2.identity.integration.test.rest.api.user.common.model.UserObject; +import org.wso2.identity.integration.test.restclients.SCIM2RestClient; +import org.wso2.identity.integration.test.utils.CarbonUtils; +import org.wso2.identity.integration.test.utils.DataExtractUtil; +import org.wso2.identity.integration.test.utils.OAuth2Constant; + +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertTrue; +import static org.wso2.identity.integration.test.utils.OAuth2Constant.ACCESS_TOKEN_ENDPOINT; +import static org.wso2.identity.integration.test.utils.OAuth2Constant.AUTHORIZATION_HEADER; +import static org.wso2.identity.integration.test.utils.OAuth2Constant.AUTHORIZE_ENDPOINT_URL; +import static org.wso2.identity.integration.test.utils.OAuth2Constant.OAUTH2_GRANT_TYPE_AUTHORIZATION_CODE; + +/** + * Integration test class for testing the pre issue access token flow with authorization code grant. + * This test case extends {@link ActionsBaseTestCase} and focuses on scenarios related + * to scopes and claims modifications through an external service. + */ +public class PreIssueAccessTokenCodeGrantTestCase extends ActionsBaseTestCase { + + private static final String USERS = "users"; + private static final String USERNAME_PROPERTY = "username"; + private static final String PASSWORD_PROPERTY = "password"; + private static final String TEST_USER = "test_user"; + private static final String ADMIN_WSO2 = "Admin@wso2"; + private static final String TEST_USER_FIRST_NAME = "test_user_given_name"; + private static final String REPLACED_FIRST_NAME = "replaced_given_name"; + private static final String TEST_USER_LAST_NAME = "test_user_last_name"; + private static final String TEST_USER_GMAIL_COM = "test.user@gmail.com"; + private static final String EXTERNAL_SERVICE_NAME = "TestExternalService"; + private static final String EXTERNAL_SERVICE_URI = "http://localhost:8587/test/action"; + private static final String PRE_ISSUE_ACCESS_TOKEN_API_PATH = "preIssueAccessToken"; + private static final String APPLICATION_AUDIENCE = "APPLICATION"; + private static final String TEST_ROLE_APPLICATION = "test_role_application"; + private static final String INTERNAL_ORG_USER_MANAGEMENT_LIST = "internal_org_user_mgt_list"; + private static final String INTERNAL_ORG_USER_MANAGEMENT_VIEW = "internal_org_user_mgt_view"; + private static final String INTERNAL_ORG_USER_MANAGEMENT_CREATE = "internal_org_user_mgt_create"; + private static final String INTERNAL_ORG_USER_MANAGEMENT_UPDATE = "internal_org_user_mgt_update"; + private static final String INTERNAL_ORG_USER_MANAGEMENT_DELETE = "internal_org_user_mgt_delete"; + private static final String CUSTOM_SCOPE_1 = "test_custom_scope_1"; + private static final String CUSTOM_SCOPE_2 = "test_custom_scope_2"; + private static final String CUSTOM_SCOPE_3 = "test_custom_scope_3"; + private static final String NEW_SCOPE_1 = "new_test_custom_scope_1"; + private static final String NEW_SCOPE_2 = "new_test_custom_scope_2"; + private static final String NEW_SCOPE_3 = "new_test_custom_scope_3"; + private static final String NEW_SCOPE_4 = "replaced_scope"; + private static final String CUSTOM_OIDC_SCOPE = "test_custom_oidc_scope"; + private static final String SCIM2_USERS_API = "/o/scim2/Users"; + private static final String ACTIONS_API = "/api/server/v1/actions"; + private static final String APPLICATION_MANAGEMENT_API = "/api/server/v1/applications"; + private static final String API_RESOURCE_MANAGEMENT_API = "/api/server/v1/api-resources"; + private static final String MOCK_SERVER_ENDPOINT = "/test/action"; + + private CloseableHttpClient client; + private SCIM2RestClient scim2RestClient; + private List permissions = new ArrayList<>(); + private TokenScopes appTokenScopes; + private String sessionDataKey; + private String authorizationCode; + private String accessToken; + private String clientId; + private String clientSecret; + private String actionId; + private String applicationId; + private String domainAPIId; + private String userId; + private String roleId; + private JWTClaimsSet jwtClaims; + + /** + * Initializes Test environment and sets up necessary configurations. + * + * @throws Exception If an error occurs during initialization + */ + @BeforeClass(alwaysRun = true) + public void testInit() throws Exception { + + super.init(TestUserMode.TENANT_USER); + + Lookup cookieSpecRegistry = RegistryBuilder.create() + .register(CookieSpecs.DEFAULT, new RFC6265CookieSpecProvider()) + .build(); + RequestConfig requestConfig = RequestConfig.custom() + .setCookieSpec(CookieSpecs.DEFAULT) + .build(); + client = HttpClientBuilder.create() + .setDefaultRequestConfig(requestConfig) + .setDefaultCookieSpecRegistry(cookieSpecRegistry) + .setRedirectStrategy(new DefaultRedirectStrategy() { + @Override + protected boolean isRedirectable(String method) { + + return false; + } + }).build(); + + scim2RestClient = new SCIM2RestClient(serverURL, tenantInfo); + + List customScopes = Arrays.asList(CUSTOM_SCOPE_1, CUSTOM_SCOPE_2, CUSTOM_SCOPE_3); + + applicationId = createOIDCAppWithClaims(); + + if (!CarbonUtils.isLegacyAuthzRuntimeEnabled()) { + authorizeSystemAPIs(applicationId, new ArrayList<>(Arrays.asList(SCIM2_USERS_API, ACTIONS_API, + APPLICATION_MANAGEMENT_API, API_RESOURCE_MANAGEMENT_API))); + } + domainAPIId = createDomainAPI(EXTERNAL_SERVICE_NAME, EXTERNAL_SERVICE_URI, customScopes); + authorizeDomainAPIs(applicationId, domainAPIId, customScopes); + + addUserWithRole(applicationId, customScopes); + + MockServer.createMockServer(MOCK_SERVER_ENDPOINT); + actionId = createPreIssueAccessTokenAction(); + } + + @AfterClass(alwaysRun = true) + public void atEnd() throws Exception { + + deleteAction(PRE_ISSUE_ACCESS_TOKEN_API_PATH, actionId); + deleteRole(roleId); + deleteApp(applicationId); + deleteDomainAPI(domainAPIId); + scim2RestClient.deleteUser(userId); + MockServer.shutDownMockServer(); + restClient.closeHttpClient(); + scim2RestClient.closeHttpClient(); + actionsRestClient.closeHttpClient(); + client.close(); + authorizationCode = null; + accessToken = null; + jwtClaims = null; + } + + @Test(groups = "wso2.is", description = "Initiate authorize request") + public void testSendAuthorizeRequest() throws Exception { + + List urlParameters = new ArrayList<>(); + urlParameters.add(new BasicNameValuePair("response_type", OAuth2Constant.OAUTH2_GRANT_TYPE_CODE)); + urlParameters.add(new BasicNameValuePair("client_id", clientId)); + urlParameters.add(new BasicNameValuePair("redirect_uri", OAuth2Constant.CALLBACK_URL)); + + permissions.addAll(appTokenScopes.getRequestedScopes()); + urlParameters.add(new BasicNameValuePair("scope", String.join(" ", permissions))); + + HttpResponse response = sendPostRequestWithParameters(client, urlParameters, + getTenantQualifiedURL(AUTHORIZE_ENDPOINT_URL, tenantInfo.getDomain())); + + Header locationHeader = response.getFirstHeader(OAuth2Constant.HTTP_RESPONSE_HEADER_LOCATION); + assertNotNull(locationHeader, "Location header expected for authorize request is not available"); + EntityUtils.consume(response.getEntity()); + + response = sendGetRequest(client, locationHeader.getValue()); + + Map keyPositionMap = new HashMap<>(1); + keyPositionMap.put("name=\"sessionDataKey\"", 1); + List keyValues = DataExtractUtil.extractDataFromResponse(response, keyPositionMap); + assertNotNull(keyValues, "SessionDataKey key value is null"); + + sessionDataKey = keyValues.get(0).getValue(); + assertNotNull(sessionDataKey, "Session data key is null"); + EntityUtils.consume(response.getEntity()); + } + + @Test(groups = "wso2.is", description = "Perform login", dependsOnMethods = "testSendAuthorizeRequest") + public void testSendLoginPost() throws Exception { + + HttpResponse response = sendLoginPostForCustomUsers(client, sessionDataKey, TEST_USER, ADMIN_WSO2); + + Header locationHeader = response.getFirstHeader(OAuth2Constant.HTTP_RESPONSE_HEADER_LOCATION); + assertNotNull(locationHeader, "Location header expected post login is not available."); + EntityUtils.consume(response.getEntity()); + + response = sendGetRequest(client, locationHeader.getValue()); + locationHeader = response.getFirstHeader(OAuth2Constant.HTTP_RESPONSE_HEADER_LOCATION); + assertNotNull(locationHeader, "Redirection URL to the application with authorization code is null."); + EntityUtils.consume(response.getEntity()); + + authorizationCode = getAuthorizationCodeFromURL(locationHeader.getValue()); + assertNotNull(authorizationCode); + } + + @Test(groups = "wso2.is", description = "Retrieve access token", dependsOnMethods = "testSendLoginPost") + public void testGetAccessTokenWithAuthCodeGrant() throws Exception { + + List urlParameters = new ArrayList<>(); + urlParameters.add(new BasicNameValuePair("code", authorizationCode)); + urlParameters.add(new BasicNameValuePair("grant_type", OAUTH2_GRANT_TYPE_AUTHORIZATION_CODE)); + urlParameters.add(new BasicNameValuePair("redirect_uri", OAuth2Constant.CALLBACK_URL)); + urlParameters.add(new BasicNameValuePair("client_id", clientId)); + + List
headers = new ArrayList<>(); + headers.add(new BasicHeader(AUTHORIZATION_HEADER, + OAuth2Constant.BASIC_HEADER + " " + getBase64EncodedString(clientId, clientSecret))); + headers.add(new BasicHeader("Content-Type", "application/x-www-form-urlencoded")); + headers.add(new BasicHeader("User-Agent", OAuth2Constant.USER_AGENT)); + + HttpResponse response = sendPostRequest(client, headers, urlParameters, + getTenantQualifiedURL(ACCESS_TOKEN_ENDPOINT, tenantInfo.getDomain())); + assertNotNull(response, "Failed to receive a response for access token request."); + + String responseString = EntityUtils.toString(response.getEntity(), "UTF-8"); + JSONObject jsonResponse = new JSONObject(responseString); + + assertTrue(jsonResponse.has("access_token"), "Access token not found in the token response."); + accessToken = jsonResponse.getString("access_token"); + assertNotNull(accessToken, "Access token is null."); + + jwtClaims = extractJwtClaims(accessToken); + assertNotNull(jwtClaims); + } + + @Test(groups = "wso2.is", description = "Verify that the access token contains the updated scopes " + + "after action execution", dependsOnMethods = "testGetAccessTokenWithAuthCodeGrant") + public void testTokenScopeOperations() throws Exception { + + String[] scopes = jwtClaims.getStringClaim("scope").split("\\s+"); + + Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_1)); + Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_2)); + Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_3)); + Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_4)); + Assert.assertFalse(ArrayUtils.contains(scopes, CUSTOM_SCOPE_3)); // replace - 7 + Assert.assertFalse(ArrayUtils.contains(scopes, INTERNAL_ORG_USER_MANAGEMENT_CREATE)); // remove - 8 + } + + @Test(groups = "wso2.is", description = "Verify that the access token contains the updated OIDC claims " + + "after action execution", dependsOnMethods = "testGetAccessTokenWithAuthCodeGrant") + public void testTokenOIDCScopeOperations() throws Exception { + + String firstName = jwtClaims.getStringClaim("given_name"); + String lastName = jwtClaims.getStringClaim("family_name"); + Assert.assertEquals(firstName, REPLACED_FIRST_NAME); + Assert.assertNotEquals(firstName, TEST_USER_FIRST_NAME); + Assert.assertNotEquals(lastName, TEST_USER_LAST_NAME); + } + + @Test(groups = "wso2.is", description = "Verify that the access token contains the updated 'aud' claims " + + "after action execution", dependsOnMethods = "testGetAccessTokenWithAuthCodeGrant") + public void testTokenAUDClaimOperations() throws Exception { + + String[] audValueArray = jwtClaims.getStringArrayClaim("aud"); + + Assert.assertTrue(ArrayUtils.contains(audValueArray, "zzz1.com")); + Assert.assertTrue(ArrayUtils.contains(audValueArray, "zzz2.com")); + Assert.assertTrue(ArrayUtils.contains(audValueArray, "zzz3.com")); + Assert.assertTrue(ArrayUtils.contains(audValueArray, "zzzR.com")); + Assert.assertFalse(ArrayUtils.contains(audValueArray, clientId)); + } + + @Test(groups = "wso2.is", description = "Verify the presence of the specified custom string claim in the access " + + "token", dependsOnMethods = "testGetAccessTokenWithAuthCodeGrant") + public void testTokenStringClaimAddOperation() throws Exception { + + String claimStr = jwtClaims.getStringClaim("custom_claim_string_1"); + Assert.assertEquals(claimStr, "testCustomClaim1"); + } + + @Test(groups = "wso2.is", description = "Verify the presence of the specified custom number claim in the access " + + "token", dependsOnMethods = "testGetAccessTokenWithAuthCodeGrant") + public void testTokenNumberClaimAddOperation() throws Exception { + + Number claimValue = jwtClaims.getIntegerClaim("custom_claim_number_1"); + Assert.assertEquals(claimValue, 78); + } + + @Test(groups = "wso2.is", description = "Verify the presence of the specified custom boolean claim in the access " + + "token", dependsOnMethods = "testGetAccessTokenWithAuthCodeGrant") + public void testTokenBooleanClaimAddOperation() throws Exception { + + Boolean claimValue = jwtClaims.getBooleanClaim("custom_claim_boolean_1"); + Assert.assertTrue(claimValue); + } + + @Test(groups = "wso2.is", description = "Verify the presence of the specified custom string array claim in the " + + "access token", dependsOnMethods = "testGetAccessTokenWithAuthCodeGrant") + public void testTokenStringArrayClaimAddOperation() + throws Exception { + + String[] expectedClaimArrayInToken = {"TestCustomClaim1", "TestCustomClaim2", "TestCustomClaim3"}; + + String[] addedClaimArrayToToken = jwtClaims.getStringArrayClaim("custom_claim_string_array_1"); + Assert.assertEquals(addedClaimArrayToToken, expectedClaimArrayInToken); + } + + @Test(groups = "wso2.is", description = "Verify the replacement of the 'expires_in' claim in the access token", + dependsOnMethods = "testGetAccessTokenWithAuthCodeGrant") + public void testTokenExpiresInClaimReplaceOperation() throws Exception { + + Date exp = jwtClaims.getDateClaim("exp"); + Date iat = jwtClaims.getDateClaim("iat"); + long expiresIn = (exp.getTime() - iat.getTime()) / 1000; + + Assert.assertEquals(expiresIn, 7200); + } + + /** + * Get authorization code from the provided URL. + * + * @param location Location header + * @return Authorization code + */ + private String getAuthorizationCodeFromURL(String location) { + + URI uri = URI.create(location); + return URLEncodedUtils.parse(uri, StandardCharsets.UTF_8).stream() + .filter(param -> "code".equals(param.getName())) + .map(NameValuePair::getValue) + .findFirst() + .orElse(null); + } + + /** + * Creates an action for pre-issuing an access token with basic authentication. + * + * @return ID of the created action + * @throws IOException If an error occurred while creating the action + */ + private String createPreIssueAccessTokenAction() throws IOException { + + AuthenticationType authenticationType = new AuthenticationType(); + authenticationType.setType(AuthenticationType.TypeEnum.BASIC); + Map authProperties = new HashMap<>(); + authProperties.put(USERNAME_PROPERTY, TEST_USER); + authProperties.put(PASSWORD_PROPERTY, ADMIN_WSO2); + authenticationType.setProperties(authProperties); + + Endpoint endpoint = new Endpoint(); + endpoint.setUri(EXTERNAL_SERVICE_URI); + endpoint.setAuthentication(authenticationType); + + ActionModel actionModel = new ActionModel(); + actionModel.setName("Access Token Pre Issue"); + actionModel.setDescription("This is a test pre issue access token type"); + actionModel.setEndpoint(endpoint); + + return createAction(PRE_ISSUE_ACCESS_TOKEN_API_PATH, actionModel); + } + + /** + * Extracts the JWT claims set from a given JWT token. + * + * @param jwtToken JWT token from which claims are to be extracted + * @return JWTClaimsSet extracted from the provided JWT token + * @throws ParseException If there is an error in parsing the JWT token + */ + private JWTClaimsSet extractJwtClaims(String jwtToken) throws ParseException { + + SignedJWT signedJWT = SignedJWT.parse(jwtToken); + return signedJWT.getJWTClaimsSet(); + } + + /** + * Adds a user with a role and specific permissions based on custom scopes. + * + * @param appID Application ID to which the role is associated + * @param customScopes The custom scopes based on which permissions are added + * @throws JSONException If there is an error in processing JSON + * @throws IOException If there is an IO exception during user or role creation + */ + private void addUserWithRole(String appID, List customScopes) throws Exception { + // Creates roles + List userPermissions = addPermissions(customScopes); + Audience roleAudience = new Audience(APPLICATION_AUDIENCE, appID); + RoleV2 role = new RoleV2(roleAudience, TEST_ROLE_APPLICATION, userPermissions, Collections.emptyList()); + roleId = addRole(role); + + // Creates user + UserObject userInfo = new UserObject(); + userInfo.setUserName(TEST_USER); + userInfo.setPassword(ADMIN_WSO2); + userInfo.setName(new Name().givenName(TEST_USER_FIRST_NAME)); + userInfo.getName().setFamilyName(TEST_USER_LAST_NAME); + userInfo.addEmail(new Email().value(TEST_USER_GMAIL_COM)); + userId = scim2RestClient.createUser(userInfo); + + // Assigns role to the created user + RoleItemAddGroupobj rolePatchReqObject = new RoleItemAddGroupobj(); + rolePatchReqObject.setOp(RoleItemAddGroupobj.OpEnum.ADD); + rolePatchReqObject.setPath(USERS); + rolePatchReqObject.addValue(new ListObject().value(userId)); + scim2RestClient.updateUserRole(new PatchOperationRequestObject().addOperations(rolePatchReqObject), roleId); + } + + /** + * Adds permissions based on the provided custom scopes. + * + * @param customScopes A list of custom scopes to add as permissions + * @return A list of permissions including both predefined and custom scope-based permissions + */ + private List addPermissions(List customScopes) { + + List userPermissions = new ArrayList<>(); + Collections.addAll(permissions, + INTERNAL_ORG_USER_MANAGEMENT_CREATE, + INTERNAL_ORG_USER_MANAGEMENT_LIST, + INTERNAL_ORG_USER_MANAGEMENT_VIEW, + INTERNAL_ORG_USER_MANAGEMENT_UPDATE, + INTERNAL_ORG_USER_MANAGEMENT_DELETE + ); + permissions.addAll(customScopes); + permissions.forEach(permission -> userPermissions.add(new Permission(permission))); + + return userPermissions; + } + + private String createOIDCAppWithClaims() throws Exception { + + List userClaimConfigs = Arrays.asList( + new UserClaimConfig.Builder().localClaimUri("http://wso2.org/claims/givenname"). + oidcClaimUri("given_name").build(), + new UserClaimConfig.Builder().localClaimUri("http://wso2.org/claims/lastname"). + oidcClaimUri("family_name").build() + ); + + ApplicationConfig applicationConfig = new ApplicationConfig.Builder() + .claimsList(userClaimConfigs) + .grantTypes(new ArrayList<>(Collections.singleton(OAUTH2_GRANT_TYPE_AUTHORIZATION_CODE))) + .tokenType(ApplicationConfig.TokenType.JWT) + .expiryTime(3600) + .skipConsent(true) + .build(); + + appTokenScopes = new TokenScopes.Builder().requestedScopes(Arrays.asList("openid", "profile", + CUSTOM_OIDC_SCOPE)) + .grantedScopes(Arrays.asList("openid", "profile")).build(); + + ApplicationResponseModel application = addApplication(applicationConfig); + String applicationId = application.getId(); + + OpenIDConnectConfiguration oidcConfig = getOIDCInboundDetailsOfApplication(applicationId); + clientId = oidcConfig.getClientId(); + clientSecret = oidcConfig.getClientSecret(); + + return applicationId; + } +} + diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java index d3745d8a7e..59977e92e5 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java @@ -212,6 +212,7 @@ protected boolean isRedirectable(String method) { subjectType = oidcConfig.getSubject().getSubjectType(); tokenType = oidcConfig.getAccessToken().getType(); + if (!CarbonUtils.isLegacyAuthzRuntimeEnabled()) { authorizeSystemAPIs(applicationId, Collections.singletonList(SCIM2_USERS_API)); } @@ -313,7 +314,7 @@ public void testTokenScopeOperations() throws Exception { Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_3)); Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_4)); Assert.assertFalse(ArrayUtils.contains(scopes, CUSTOM_SCOPE_3)); - Assert.assertFalse(ArrayUtils.contains(scopes, CUSTOM_SCOPE_2)); + Assert.assertFalse(ArrayUtils.contains(scopes, INTERNAL_ORG_USER_MANAGEMENT_CREATE)); } @Test(groups = "wso2.is", dependsOnMethods = "testPreIssueAccessTokenActionRequest", description = diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java index d5b34470f2..0f9f4279ed 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java @@ -94,97 +94,106 @@ public void createMockServer(String mockEndpoint) throws Exception { String jsonResponse = "{\n" + " \"actionStatus\": \"SUCCESS\",\n" + " \"operations\": [\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/scopes/-\",\n" + - " \"value\": \"new_test_custom_scope_1\"\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/scopes/-\",\n" + - " \"value\": \"new_test_custom_scope_2\"\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/scopes/-\",\n" + - " \"value\": \"new_test_custom_scope_3\"\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/aud/-\",\n" + - " \"value\": \"zzz1.com\"\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/aud/-\",\n" + - " \"value\": \"zzz2.com\"\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/aud/-\",\n" + - " \"value\": \"zzz3.com\"\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/-\",\n" + - " \"value\": {\n" + - " \"name\": \"custom_claim_string_1\",\n" + - " \"value\": \"testCustomClaim1\"\n" + + " {\n" + + " \"op\": \"add\",\n" + + " \"path\": \"/accessToken/scopes/-\",\n" + + " \"value\": \"new_test_custom_scope_1\"\n" + + " },\n" + + " {\n" + + " \"op\": \"add\",\n" + + " \"path\": \"/accessToken/scopes/-\",\n" + + " \"value\": \"new_test_custom_scope_2\"\n" + + " },\n" + + " {\n" + + " \"op\": \"add\",\n" + + " \"path\": \"/accessToken/scopes/-\",\n" + + " \"value\": \"new_test_custom_scope_3\"\n" + + " },\n" + + " {\n" + + " \"op\": \"add\",\n" + + " \"path\": \"/accessToken/claims/aud/-\",\n" + + " \"value\": \"zzz1.com\"\n" + + " },\n" + + " {\n" + + " \"op\": \"add\",\n" + + " \"path\": \"/accessToken/claims/aud/-\",\n" + + " \"value\": \"zzz2.com\"\n" + + " },\n" + + " {\n" + + " \"op\": \"add\",\n" + + " \"path\": \"/accessToken/claims/aud/-\",\n" + + " \"value\": \"zzz3.com\"\n" + + " },\n" + + " {\n" + + " \"op\": \"add\",\n" + + " \"path\": \"/accessToken/claims/-\",\n" + + " \"value\": {\n" + + " \"name\": \"custom_claim_string_1\",\n" + + " \"value\": \"testCustomClaim1\"\n" + + " }\n" + + " },\n" + + " {\n" + + " \"op\": \"add\",\n" + + " \"path\": \"/accessToken/claims/-\",\n" + + " \"value\": {\n" + + " \"name\": \"custom_claim_number_1\",\n" + + " \"value\": 78\n" + + " }\n" + + " },\n" + + " {\n" + + " \"op\": \"add\",\n" + + " \"path\": \"/accessToken/claims/-\",\n" + + " \"value\": {\n" + + " \"name\": \"custom_claim_boolean_1\",\n" + + " \"value\": true\n" + + " }\n" + + " },\n" + + " {\n" + + " \"op\": \"add\",\n" + + " \"path\": \"/accessToken/claims/-\",\n" + + " \"value\": {\n" + + " \"name\": \"custom_claim_string_array_1\",\n" + + " \"value\": [\n" + + " \"TestCustomClaim1\",\n" + + " \"TestCustomClaim2\",\n" + + " \"TestCustomClaim3\"\n" + + " ]\n" + + " }\n" + + " },\n" + + " {\n" + + " \"op\": \"replace\",\n" + + " \"path\": \"/accessToken/scopes/-\",\n" + + " \"value\": \"replaced_scope\"\n" + + " },\n" + + " {\n" + + " \"op\": \"replace\",\n" + + " \"path\": \"/accessToken/claims/aud/-\",\n" + + " \"value\": \"zzzR.com\"\n" + + " },\n" + + " {\n" + + " \"op\": \"replace\",\n" + + " \"path\": \"/accessToken/claims/expires_in\",\n" + + " \"value\": 7200\n" + + " },\n" + + " {\n" + + " \"op\": \"replace\",\n" + + " \"path\": \"/accessToken/claims/given_name\",\n" + + " \"value\": \"replaced_given_name\"\n" + + " },\n" + + " {\n" + + " \"op\": \"remove\",\n" + + " \"path\": \"/accessToken/scopes/0\"\n" + + " },\n" + + " {\n" + + " \"op\": \"remove\",\n" + + " \"path\": \"/accessToken/claims/aud/-\"\n" + + " },\n" + + " {\n" + + " \"op\": \"remove\",\n" + + " \"path\": \"/accessToken/claims/family_name\"\n" + " }\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/-\",\n" + - " \"value\": {\n" + - " \"name\": \"custom_claim_number_1\",\n" + - " \"value\": 78\n" + - " }\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/-\",\n" + - " \"value\": {\n" + - " \"name\": \"custom_claim_boolean_1\",\n" + - " \"value\": true\n" + - " }\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/-\",\n" + - " \"value\": {\n" + - " \"name\": \"custom_claim_string_array_1\",\n" + - " \"value\": [\n" + - " \"TestCustomClaim1\",\n" + - " \"TestCustomClaim2\",\n" + - " \"TestCustomClaim3\"\n" + - " ]\n" + - " }\n" + - " },\n" + - " {\n" + - " \"op\": \"replace\",\n" + - " \"path\": \"/accessToken/scopes/7\",\n" + - " \"value\": \"replaced_scope\"\n" + - " },\n" + - " {\n" + - " \"op\": \"replace\",\n" + - " \"path\": \"/accessToken/claims/aud/-\",\n" + - " \"value\": \"zzzR.com\"\n" + - " },\n" + - " {\n" + - " \"op\": \"replace\",\n" + - " \"path\": \"/accessToken/claims/expires_in\",\n" + - " \"value\": 7200\n" + - " },\n" + - " {\n" + - " \"op\": \"remove\",\n" + - " \"path\": \"/accessToken/scopes/6\"\n" + - " },\n" + - " {\n" + - " \"op\": \"remove\",\n" + - " \"path\": \"/accessToken/claims/aud/-\"\n" + - " }\n" + " ]\n" + - " }"; + "}\n"; // TODO: Handle status codes related to different scenarios wireMockServer.stubFor(post(urlEqualTo(mockEndpoint)) diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml b/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml index f5a8e557b5..e8dbf096a9 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/testng.xml @@ -138,6 +138,7 @@ + From 355aa444753b54f8abd9ba45610871522ccf7d30 Mon Sep 17 00:00:00 2001 From: Shenali Date: Mon, 16 Sep 2024 22:49:36 +0530 Subject: [PATCH 2/8] Update mock server instantiation --- .../actions/PreIssueAccessTokenCodeGrantTestCase.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java index 2b17e62d86..3e72aca526 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java @@ -44,7 +44,7 @@ import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import org.wso2.carbon.automation.engine.context.TestUserMode; -import org.wso2.identity.integration.test.mocks.MockServer; +import org.wso2.identity.integration.test.actions.mockserver.ActionsMockServer; import org.wso2.identity.integration.test.oauth2.dataprovider.model.ApplicationConfig; import org.wso2.identity.integration.test.oauth2.dataprovider.model.TokenScopes; import org.wso2.identity.integration.test.oauth2.dataprovider.model.UserClaimConfig; @@ -141,6 +141,7 @@ public class PreIssueAccessTokenCodeGrantTestCase extends ActionsBaseTestCase { private String userId; private String roleId; private JWTClaimsSet jwtClaims; + private ActionsMockServer actionsMockServer; /** * Initializes Test environment and sets up necessary configurations. @@ -184,7 +185,10 @@ protected boolean isRedirectable(String method) { addUserWithRole(applicationId, customScopes); - MockServer.createMockServer(MOCK_SERVER_ENDPOINT); + actionsMockServer = new ActionsMockServer(); + + actionsMockServer.createMockServer(MOCK_SERVER_ENDPOINT); + actionId = createPreIssueAccessTokenAction(); } @@ -196,7 +200,7 @@ public void atEnd() throws Exception { deleteApp(applicationId); deleteDomainAPI(domainAPIId); scim2RestClient.deleteUser(userId); - MockServer.shutDownMockServer(); + actionsMockServer.shutDownMockServer(); restClient.closeHttpClient(); scim2RestClient.closeHttpClient(); actionsRestClient.closeHttpClient(); From 6d73f320f299b733cae30fbf569fad8c42e5e606 Mon Sep 17 00:00:00 2001 From: Shenali Date: Tue, 17 Sep 2024 00:19:17 +0530 Subject: [PATCH 3/8] Update formatting --- ...IssueAccessTokenClientCredentialsGrantTestCase.java | 6 +++++- .../actions/PreIssueAccessTokenCodeGrantTestCase.java | 10 +++++++--- .../test/actions/mockserver/ActionsMockServer.java | 3 --- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java index e3c50f78d3..857d4a722e 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java @@ -197,16 +197,20 @@ protected boolean isRedirectable(String method) { @AfterClass(alwaysRun = true) public void atEnd() throws Exception { + actionsMockServer.startServer(); + deleteAction(PRE_ISSUE_ACCESS_TOKEN_API_PATH, actionId); deleteRole(roleId); deleteApp(applicationId); deleteDomainAPI(domainAPIId); scim2RestClient.deleteUser(userId); - actionsMockServer.shutDownMockServer(); + restClient.closeHttpClient(); scim2RestClient.closeHttpClient(); actionsRestClient.closeHttpClient(); client.close(); + + actionsMockServer = null; accessToken = null; jwtClaims = null; } diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java index 3e72aca526..b8d39863fe 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java @@ -195,16 +195,20 @@ protected boolean isRedirectable(String method) { @AfterClass(alwaysRun = true) public void atEnd() throws Exception { + actionsMockServer.startServer(); + deleteAction(PRE_ISSUE_ACCESS_TOKEN_API_PATH, actionId); deleteRole(roleId); deleteApp(applicationId); deleteDomainAPI(domainAPIId); scim2RestClient.deleteUser(userId); - actionsMockServer.shutDownMockServer(); + restClient.closeHttpClient(); scim2RestClient.closeHttpClient(); actionsRestClient.closeHttpClient(); client.close(); + + actionsMockServer = null; authorizationCode = null; accessToken = null; jwtClaims = null; @@ -298,8 +302,8 @@ public void testTokenScopeOperations() throws Exception { Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_2)); Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_3)); Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_4)); - Assert.assertFalse(ArrayUtils.contains(scopes, CUSTOM_SCOPE_3)); // replace - 7 - Assert.assertFalse(ArrayUtils.contains(scopes, INTERNAL_ORG_USER_MANAGEMENT_CREATE)); // remove - 8 + Assert.assertFalse(ArrayUtils.contains(scopes, CUSTOM_SCOPE_3)); + Assert.assertFalse(ArrayUtils.contains(scopes, INTERNAL_ORG_USER_MANAGEMENT_CREATE)); } @Test(groups = "wso2.is", description = "Verify that the access token contains the updated OIDC claims " + diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java index 0f9f4279ed..d77a4998bc 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java @@ -19,16 +19,13 @@ package org.wso2.identity.integration.test.actions.mockserver; import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; -import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; import com.github.tomakehurst.wiremock.verification.LoggedRequest; import org.apache.commons.lang.StringUtils; import java.util.List; import static com.github.tomakehurst.wiremock.client.WireMock.aResponse; -import static com.github.tomakehurst.wiremock.client.WireMock.equalToJson; import static com.github.tomakehurst.wiremock.client.WireMock.matching; import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; From cf4afdc72659f9bc0c34bdb582d94190790b5bf2 Mon Sep 17 00:00:00 2001 From: Shenali Date: Wed, 18 Sep 2024 12:46:31 +0530 Subject: [PATCH 4/8] Refactor mock server response --- .../response/pre-issue-access-token-response.json | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/actions/response/pre-issue-access-token-response.json b/modules/integration/tests-integration/tests-backend/src/test/resources/actions/response/pre-issue-access-token-response.json index e2feae3bd6..20d6d2e68a 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/resources/actions/response/pre-issue-access-token-response.json +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/actions/response/pre-issue-access-token-response.json @@ -77,6 +77,11 @@ "path": "/accessToken/claims/aud/-", "value": "zzzR.com" }, + { + "op": "replace", + "path": "/accessToken/claims/given_name", + "value": "replaced_given_name" + }, { "op": "replace", "path": "/accessToken/claims/expires_in", @@ -84,11 +89,15 @@ }, { "op": "remove", - "path": "/accessToken/scopes/6" + "path": "/accessToken/scopes/0" }, { "op": "remove", "path": "/accessToken/claims/aud/-" + }, + { + "op": "remove", + "path": "/accessToken/claims/family_name" } ] -} \ No newline at end of file +} From 5a88e0c4637e39a1add332bed9978e49ba9af96b Mon Sep 17 00:00:00 2001 From: Shenali Date: Thu, 19 Sep 2024 01:54:39 +0530 Subject: [PATCH 5/8] Refactor mock server implementation --- ...ssTokenClientCredentialsGrantTestCase.java | 212 ++++++++++++--- .../PreIssueAccessTokenCodeGrantTestCase.java | 254 +++++++++++++++--- ...IssueAccessTokenPasswordGrantTestCase.java | 2 +- .../actions/mockserver/ActionsMockServer.java | 138 ---------- .../model/PreIssueAccessTokenEvent.java | 16 +- .../pre-issue-access-token-response.json | 2 +- 6 files changed, 403 insertions(+), 221 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java index 857d4a722e..79b0768de7 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java @@ -18,6 +18,7 @@ package org.wso2.identity.integration.test.actions; +import com.fasterxml.jackson.databind.ObjectMapper; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; import org.apache.commons.lang.ArrayUtils; @@ -41,9 +42,21 @@ import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; import org.testng.annotations.Test; import org.wso2.carbon.automation.engine.context.TestUserMode; import org.wso2.identity.integration.test.actions.mockserver.ActionsMockServer; +import org.wso2.identity.integration.test.actions.model.AccessToken; +import org.wso2.identity.integration.test.actions.model.ActionType; +import org.wso2.identity.integration.test.actions.model.AllowedOperation; +import org.wso2.identity.integration.test.actions.model.Operation; +import org.wso2.identity.integration.test.actions.model.PreIssueAccessTokenActionRequest; +import org.wso2.identity.integration.test.actions.model.PreIssueAccessTokenEvent; +import org.wso2.identity.integration.test.actions.model.Tenant; +import org.wso2.identity.integration.test.actions.model.TokenRequest; +import org.wso2.identity.integration.test.actions.model.User; +import org.wso2.identity.integration.test.actions.model.UserStore; import org.wso2.identity.integration.test.rest.api.server.action.management.v1.model.ActionModel; import org.wso2.identity.integration.test.rest.api.server.action.management.v1.model.AuthenticationType; import org.wso2.identity.integration.test.rest.api.server.action.management.v1.model.Endpoint; @@ -60,12 +73,15 @@ import org.wso2.identity.integration.test.rest.api.user.common.model.UserObject; import org.wso2.identity.integration.test.restclients.SCIM2RestClient; import org.wso2.identity.integration.test.utils.CarbonUtils; +import org.wso2.identity.integration.test.utils.FileUtils; import org.wso2.identity.integration.test.utils.OAuth2Constant; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -73,10 +89,12 @@ import java.util.Map; import java.util.stream.Collectors; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.wso2.identity.integration.test.utils.OAuth2Constant.ACCESS_TOKEN_ENDPOINT; import static org.wso2.identity.integration.test.utils.OAuth2Constant.AUTHORIZATION_HEADER; +import static org.wso2.identity.integration.test.utils.OAuth2Constant.OAUTH2_GRANT_TYPE_CLIENT_CREDENTIALS; /** * Integration test class for testing the pre issue access token flow with client credentials grant. @@ -100,19 +118,11 @@ public class PreIssueAccessTokenClientCredentialsGrantTestCase extends ActionsBa private static final String APPLICATION_AUDIENCE = "APPLICATION"; private static final String TEST_ROLE_APPLICATION = "test_role_application"; - private static final String INTERNAL_ACTION_MANAGEMENT_VIEW = "internal_action_mgt_view"; - private static final String INTERNAL_ACTION_MANAGEMENT_CREATE = "internal_action_mgt_create"; - private static final String INTERNAL_ACTION_MANAGEMENT_UPDATE = "internal_action_mgt_update"; - private static final String INTERNAL_ACTION_MANAGEMENT_DELETE = "internal_action_mgt_delete"; private static final String INTERNAL_ORG_USER_MANAGEMENT_LIST = "internal_org_user_mgt_list"; private static final String INTERNAL_ORG_USER_MANAGEMENT_VIEW = "internal_org_user_mgt_view"; private static final String INTERNAL_ORG_USER_MANAGEMENT_CREATE = "internal_org_user_mgt_create"; private static final String INTERNAL_ORG_USER_MANAGEMENT_UPDATE = "internal_org_user_mgt_update"; private static final String INTERNAL_ORG_USER_MANAGEMENT_DELETE = "internal_org_user_mgt_delete"; - private static final String INTERNAL_APPLICATION_MANAGEMENT_VIEW = "internal_application_mgt_view"; - private static final String INTERNAL_APPLICATION_MANAGEMENT_UPDATE = "internal_application_mgt_update"; - private static final String INTERNAL_API_RESOURCE_VIEW = "internal_api_resource_view"; - private static final String INTERNAL_API_RESOURCE_CREATE = "internal_api_resource_create"; private static final String CUSTOM_SCOPE_1 = "test_custom_scope_1"; private static final String CUSTOM_SCOPE_2 = "test_custom_scope_2"; private static final String CUSTOM_SCOPE_3 = "test_custom_scope_3"; @@ -122,27 +132,51 @@ public class PreIssueAccessTokenClientCredentialsGrantTestCase extends ActionsBa private static final String NEW_SCOPE_4 = "replaced_scope"; private static final String SCIM2_USERS_API = "/o/scim2/Users"; - private static final String ACTIONS_API = "/api/server/v1/actions"; - private static final String APPLICATION_MANAGEMENT_API = "/api/server/v1/applications"; - private static final String API_RESOURCE_MANAGEMENT_API = "/api/server/v1/api-resources"; - private static final String MOCK_SERVER_ENDPOINT = "/test/action"; - + private static final String CLAIMS_PATH_PREFIX = "/accessToken/claims/"; + private static final String SCOPES_PATH_PREFIX = "/accessToken/scopes/"; + private static final String MOCK_SERVER_ENDPOINT_RESOURCE_PATH = "/test/action"; + + private static final int UPDATED_EXPIRY_TIME_PERIOD = 7200; + private static final int CURRENT_EXPIRY_TIME_PERIOD = 3600; + private static final String MOCK_SERVER_AUTH_BASIC_USERNAME = "test"; + private static final String MOCK_SERVER_AUTH_BASIC_PASSWORD = "test"; private Lookup cookieSpecRegistry; private RequestConfig requestConfig; private CloseableHttpClient client; private SCIM2RestClient scim2RestClient; private List customScopes; + private List requestedScopes; private String accessToken; private String clientId; private String clientSecret; + private String subjectType; + private String tokenType; private String actionId; private String applicationId; private String domainAPIId; private String userId; private String roleId; + private String tenantId; private JWTClaimsSet jwtClaims; + private TestUserMode userMode; private ActionsMockServer actionsMockServer; + @Factory(dataProvider = "testExecutionContextProvider") + public PreIssueAccessTokenClientCredentialsGrantTestCase(TestUserMode testUserMode) { + + this.userMode = testUserMode; + this.tenantId = testUserMode == TestUserMode.SUPER_TENANT_USER ? "-1234" : "1"; + } + + @DataProvider(name = "testExecutionContextProvider") + public static Object[][] getTestExecutionContext() { + + return new Object[][]{ + {TestUserMode.SUPER_TENANT_USER}, + {TestUserMode.TENANT_USER} + }; + } + /** * Initializes Test environment and sets up necessary configurations. * @@ -151,7 +185,7 @@ public class PreIssueAccessTokenClientCredentialsGrantTestCase extends ActionsBa @BeforeClass(alwaysRun = true) public void testInit() throws Exception { - super.init(TestUserMode.TENANT_USER); + super.init(userMode); cookieSpecRegistry = RegistryBuilder.create() .register(CookieSpecs.DEFAULT, new RFC6265CookieSpecProvider()) @@ -179,25 +213,38 @@ protected boolean isRedirectable(String method) { OpenIDConnectConfiguration oidcConfig = getOIDCInboundDetailsOfApplication(applicationId); clientId = oidcConfig.getClientId(); clientSecret = oidcConfig.getClientSecret(); + subjectType = oidcConfig.getSubject().getSubjectType(); + tokenType = oidcConfig.getAccessToken().getType(); + if (!CarbonUtils.isLegacyAuthzRuntimeEnabled()) { - authorizeSystemAPIs(applicationId, new ArrayList<>(Arrays.asList(SCIM2_USERS_API, ACTIONS_API, - APPLICATION_MANAGEMENT_API, API_RESOURCE_MANAGEMENT_API))); + authorizeSystemAPIs(applicationId, Collections.singletonList(SCIM2_USERS_API)); } domainAPIId = createDomainAPI(EXTERNAL_SERVICE_NAME, EXTERNAL_SERVICE_URI, customScopes); authorizeDomainAPIs(applicationId, domainAPIId, customScopes); - addUserWithRole(applicationId, customScopes); - actionsMockServer = new ActionsMockServer(); + requestedScopes = new ArrayList<>(); + Collections.addAll(requestedScopes, + INTERNAL_ORG_USER_MANAGEMENT_LIST, + INTERNAL_ORG_USER_MANAGEMENT_VIEW, + INTERNAL_ORG_USER_MANAGEMENT_CREATE, + INTERNAL_ORG_USER_MANAGEMENT_UPDATE, + INTERNAL_ORG_USER_MANAGEMENT_DELETE); + requestedScopes.addAll(customScopes); - actionsMockServer.createMockServer(MOCK_SERVER_ENDPOINT); actionId = createPreIssueAccessTokenAction(); + + actionsMockServer = new ActionsMockServer(); + actionsMockServer.startServer(); + actionsMockServer.setupStub(MOCK_SERVER_ENDPOINT_RESOURCE_PATH, + "Basic " + getBase64EncodedString(MOCK_SERVER_AUTH_BASIC_USERNAME, MOCK_SERVER_AUTH_BASIC_PASSWORD), + FileUtils.readFileInClassPathAsString("actions/response/pre-issue-access-token-response.json")); } @AfterClass(alwaysRun = true) public void atEnd() throws Exception { - actionsMockServer.startServer(); + actionsMockServer.stopServer(); deleteAction(PRE_ISSUE_ACCESS_TOKEN_API_PATH, actionId); deleteRole(roleId); @@ -221,19 +268,7 @@ public void testGetAccessTokenWithClientCredentialsGrant() throws Exception { List parameters = new ArrayList<>(); parameters.add(new BasicNameValuePair("grant_type", OAuth2Constant.OAUTH2_GRANT_TYPE_CLIENT_CREDENTIALS)); - List permissions = new ArrayList<>(); - Collections.addAll(permissions, - INTERNAL_ORG_USER_MANAGEMENT_LIST, - INTERNAL_ORG_USER_MANAGEMENT_VIEW, - INTERNAL_ORG_USER_MANAGEMENT_CREATE, - INTERNAL_ORG_USER_MANAGEMENT_UPDATE, - INTERNAL_ORG_USER_MANAGEMENT_DELETE - ); - permissions.addAll(customScopes); - - String scopes = permissions.stream() - .map(String::toLowerCase) - .collect(Collectors.joining(" ")); + String scopes = String.join(" ", requestedScopes); parameters.add(new BasicNameValuePair("scope", scopes)); List
headers = new ArrayList<>(); @@ -256,6 +291,19 @@ public void testGetAccessTokenWithClientCredentialsGrant() throws Exception { assertNotNull(jwtClaims); } + @Test(groups = "wso2.is", dependsOnMethods = "testGetAccessTokenWithClientCredentialsGrant", description = + "Verify the pre issue access token action request") + public void testPreIssueAccessTokenActionRequest() throws Exception { + + String actualRequestPayload = actionsMockServer.getReceivedRequestPayload(MOCK_SERVER_ENDPOINT_RESOURCE_PATH); + PreIssueAccessTokenActionRequest actualRequest = + new ObjectMapper().readValue(actualRequestPayload, PreIssueAccessTokenActionRequest.class); + + PreIssueAccessTokenActionRequest expectedRequest = getRequest(); + + assertEquals(actualRequest, expectedRequest); + } + @Test(groups = "wso2.is", description = "Verify that the access token contains the updated scopes " + "after action execution", dependsOnMethods = "testGetAccessTokenWithClientCredentialsGrant") public void testTokenScopeOperations() throws Exception { @@ -266,7 +314,7 @@ public void testTokenScopeOperations() throws Exception { Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_2)); Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_3)); Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_4)); - Assert.assertFalse(ArrayUtils.contains(scopes, CUSTOM_SCOPE_3)); + Assert.assertFalse(ArrayUtils.contains(scopes, INTERNAL_ORG_USER_MANAGEMENT_DELETE)); Assert.assertFalse(ArrayUtils.contains(scopes, INTERNAL_ORG_USER_MANAGEMENT_CREATE)); } @@ -326,7 +374,95 @@ public void testTokenExpiresInClaimReplaceOperation() throws Exception { Date iat = jwtClaims.getDateClaim("iat"); long expiresIn = (exp.getTime() - iat.getTime()) / 1000; - Assert.assertEquals(expiresIn, 7200); + Assert.assertEquals(expiresIn, UPDATED_EXPIRY_TIME_PERIOD); + } + + /** + * Retrieves pre issue access token action request. + * + * @return pre issue access token request object + */ + private PreIssueAccessTokenActionRequest getRequest() { + + TokenRequest tokenRequest = createTokenRequest(); + AccessToken accessTokenInRequest = createAccessToken(); + + Tenant tenant = new Tenant(tenantId, tenantInfo.getDomain()); + User user = new User(userId); + UserStore userStore = + new UserStore(Base64.getEncoder().encodeToString("PRIMARY".getBytes(StandardCharsets.UTF_8)), + "PRIMARY"); + + PreIssueAccessTokenEvent event = new PreIssueAccessTokenEvent.Builder() + .request(tokenRequest) + .accessToken(accessTokenInRequest) + .tenant(tenant) + .organization(null) + .user(user) + .userStore(userStore) + .build(); + + List allowedOperations = Arrays.asList( + createAllowedOperation(Operation.ADD, Arrays.asList(CLAIMS_PATH_PREFIX, SCOPES_PATH_PREFIX, + CLAIMS_PATH_PREFIX + AccessToken.ClaimNames.AUD.getName() + "/")), + createAllowedOperation(Operation.REMOVE, Arrays.asList(SCOPES_PATH_PREFIX, + CLAIMS_PATH_PREFIX + AccessToken.ClaimNames.AUD.getName() + "/")), + createAllowedOperation(Operation.REPLACE, Arrays.asList(SCOPES_PATH_PREFIX, + CLAIMS_PATH_PREFIX + AccessToken.ClaimNames.AUD.getName() + "/", + CLAIMS_PATH_PREFIX + AccessToken.ClaimNames.EXPIRES_IN.getName())) + ); + + return new PreIssueAccessTokenActionRequest.Builder() + .actionType(ActionType.PRE_ISSUE_ACCESS_TOKEN) + .event(event) + .allowedOperations(allowedOperations) + .build(); + } + + /** + * Creates token request. + * + * @return token request object + */ + private TokenRequest createTokenRequest() { + + return new TokenRequest.Builder() + .grantType(OAUTH2_GRANT_TYPE_CLIENT_CREDENTIALS) + .scopes(requestedScopes) + .clientId(clientId) + .build(); + } + + /** + * Creates access token. + * + * @return access token object + */ + private AccessToken createAccessToken() { + + List claims = new ArrayList<>(); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.ISS.getName(), + getTenantQualifiedURL(ACCESS_TOKEN_ENDPOINT, tenantInfo.getDomain()))); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.CLIENT_ID.getName(), clientId)); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.AUTHORIZED_USER_TYPE.getName(), "APPLICATION")); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.EXPIRES_IN.getName(), CURRENT_EXPIRY_TIME_PERIOD)); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.AUD.getName(), Collections.singletonList(clientId))); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.SUBJECT_TYPE.getName(), subjectType)); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.SUB.getName(), clientId)); + + return new AccessToken.Builder() + .tokenType(tokenType) + .claims(claims) + .scopes(requestedScopes) + .build(); + } + + private AllowedOperation createAllowedOperation(Operation op, List paths) { + + AllowedOperation operation = new AllowedOperation(); + operation.setOp(op); + operation.setPaths(new ArrayList<>(paths)); + return operation; } /** @@ -340,8 +476,8 @@ private String createPreIssueAccessTokenAction() throws IOException { AuthenticationType authenticationType = new AuthenticationType(); authenticationType.setType(AuthenticationType.TypeEnum.BASIC); Map authProperties = new HashMap<>(); - authProperties.put(USERNAME_PROPERTY, TEST_USER); - authProperties.put(PASSWORD_PROPERTY, ADMIN_WSO2); + authProperties.put(USERNAME_PROPERTY, MOCK_SERVER_AUTH_BASIC_USERNAME); + authProperties.put(PASSWORD_PROPERTY, MOCK_SERVER_AUTH_BASIC_PASSWORD); authenticationType.setProperties(authProperties); Endpoint endpoint = new Endpoint(); @@ -410,6 +546,7 @@ private void addUserWithRole(String appID, List customScopes) throws Exc private List addPermissions(List customScopes) { List userPermissions = new ArrayList<>(); + Collections.addAll(userPermissions, new Permission(INTERNAL_ORG_USER_MANAGEMENT_LIST), new Permission(INTERNAL_ORG_USER_MANAGEMENT_VIEW), @@ -417,6 +554,7 @@ private List addPermissions(List customScopes) { new Permission(INTERNAL_ORG_USER_MANAGEMENT_UPDATE), new Permission(INTERNAL_ORG_USER_MANAGEMENT_DELETE) ); + customScopes.forEach(scope -> userPermissions.add(new Permission(scope))); return userPermissions; diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java index b8d39863fe..e9b00e4fcf 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java @@ -18,6 +18,7 @@ package org.wso2.identity.integration.test.actions; +import com.fasterxml.jackson.databind.ObjectMapper; import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; import org.apache.commons.lang.ArrayUtils; @@ -42,9 +43,21 @@ import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; import org.testng.annotations.Test; import org.wso2.carbon.automation.engine.context.TestUserMode; import org.wso2.identity.integration.test.actions.mockserver.ActionsMockServer; +import org.wso2.identity.integration.test.actions.model.AccessToken; +import org.wso2.identity.integration.test.actions.model.ActionType; +import org.wso2.identity.integration.test.actions.model.AllowedOperation; +import org.wso2.identity.integration.test.actions.model.Operation; +import org.wso2.identity.integration.test.actions.model.PreIssueAccessTokenActionRequest; +import org.wso2.identity.integration.test.actions.model.PreIssueAccessTokenEvent; +import org.wso2.identity.integration.test.actions.model.Tenant; +import org.wso2.identity.integration.test.actions.model.TokenRequest; +import org.wso2.identity.integration.test.actions.model.User; +import org.wso2.identity.integration.test.actions.model.UserStore; import org.wso2.identity.integration.test.oauth2.dataprovider.model.ApplicationConfig; import org.wso2.identity.integration.test.oauth2.dataprovider.model.TokenScopes; import org.wso2.identity.integration.test.oauth2.dataprovider.model.UserClaimConfig; @@ -65,6 +78,7 @@ import org.wso2.identity.integration.test.restclients.SCIM2RestClient; import org.wso2.identity.integration.test.utils.CarbonUtils; import org.wso2.identity.integration.test.utils.DataExtractUtil; +import org.wso2.identity.integration.test.utils.FileUtils; import org.wso2.identity.integration.test.utils.OAuth2Constant; import java.io.IOException; @@ -73,12 +87,14 @@ import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; +import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; import static org.testng.Assert.assertTrue; import static org.wso2.identity.integration.test.utils.OAuth2Constant.ACCESS_TOKEN_ENDPOINT; @@ -104,9 +120,10 @@ public class PreIssueAccessTokenCodeGrantTestCase extends ActionsBaseTestCase { private static final String TEST_USER_GMAIL_COM = "test.user@gmail.com"; private static final String EXTERNAL_SERVICE_NAME = "TestExternalService"; private static final String EXTERNAL_SERVICE_URI = "http://localhost:8587/test/action"; - private static final String PRE_ISSUE_ACCESS_TOKEN_API_PATH = "preIssueAccessToken"; private static final String APPLICATION_AUDIENCE = "APPLICATION"; private static final String TEST_ROLE_APPLICATION = "test_role_application"; + private static final String OPENID_SCOPE = "openid"; + private static final String PROFILE_SCOPE = "profile"; private static final String INTERNAL_ORG_USER_MANAGEMENT_LIST = "internal_org_user_mgt_list"; private static final String INTERNAL_ORG_USER_MANAGEMENT_VIEW = "internal_org_user_mgt_view"; private static final String INTERNAL_ORG_USER_MANAGEMENT_CREATE = "internal_org_user_mgt_create"; @@ -120,29 +137,57 @@ public class PreIssueAccessTokenCodeGrantTestCase extends ActionsBaseTestCase { private static final String NEW_SCOPE_3 = "new_test_custom_scope_3"; private static final String NEW_SCOPE_4 = "replaced_scope"; private static final String CUSTOM_OIDC_SCOPE = "test_custom_oidc_scope"; + private static final String FIRST_NAME_CLAIM = "given_name"; + private static final String LAST_NAME_CLAIM = "family_name"; + private static final String PRE_ISSUE_ACCESS_TOKEN_API_PATH = "preIssueAccessToken"; private static final String SCIM2_USERS_API = "/o/scim2/Users"; - private static final String ACTIONS_API = "/api/server/v1/actions"; - private static final String APPLICATION_MANAGEMENT_API = "/api/server/v1/applications"; - private static final String API_RESOURCE_MANAGEMENT_API = "/api/server/v1/api-resources"; - private static final String MOCK_SERVER_ENDPOINT = "/test/action"; - + private static final String CLAIMS_PATH_PREFIX = "/accessToken/claims/"; + private static final String SCOPES_PATH_PREFIX = "/accessToken/scopes/"; + private static final String MOCK_SERVER_ENDPOINT_RESOURCE_PATH = "/test/action"; + private static final int UPDATED_EXPIRY_TIME_PERIOD = 7200; + private static final int CURRENT_EXPIRY_TIME_PERIOD = 3600; + private static final String MOCK_SERVER_AUTH_BASIC_USERNAME = "test"; + private static final String MOCK_SERVER_AUTH_BASIC_PASSWORD = "test"; private CloseableHttpClient client; private SCIM2RestClient scim2RestClient; - private List permissions = new ArrayList<>(); + private Lookup cookieSpecRegistry; + private RequestConfig requestConfig; + private List customScopes; + private List requestedScopes; private TokenScopes appTokenScopes; private String sessionDataKey; private String authorizationCode; private String accessToken; private String clientId; private String clientSecret; + private String subjectType; + private String tokenType; private String actionId; private String applicationId; private String domainAPIId; private String userId; private String roleId; + private String tenantId; private JWTClaimsSet jwtClaims; + private TestUserMode userMode; private ActionsMockServer actionsMockServer; + @Factory(dataProvider = "testExecutionContextProvider") + public PreIssueAccessTokenCodeGrantTestCase(TestUserMode testUserMode) { + + this.userMode = testUserMode; + this.tenantId = testUserMode == TestUserMode.SUPER_TENANT_USER ? "-1234" : "1"; + } + + @DataProvider(name = "testExecutionContextProvider") + public static Object[][] getTestExecutionContext() { + + return new Object[][]{ + {TestUserMode.SUPER_TENANT_USER}, + {TestUserMode.TENANT_USER} + }; + } + /** * Initializes Test environment and sets up necessary configurations. * @@ -151,12 +196,12 @@ public class PreIssueAccessTokenCodeGrantTestCase extends ActionsBaseTestCase { @BeforeClass(alwaysRun = true) public void testInit() throws Exception { - super.init(TestUserMode.TENANT_USER); + super.init(userMode); - Lookup cookieSpecRegistry = RegistryBuilder.create() + cookieSpecRegistry = RegistryBuilder.create() .register(CookieSpecs.DEFAULT, new RFC6265CookieSpecProvider()) .build(); - RequestConfig requestConfig = RequestConfig.custom() + requestConfig = RequestConfig.custom() .setCookieSpec(CookieSpecs.DEFAULT) .build(); client = HttpClientBuilder.create() @@ -172,30 +217,44 @@ protected boolean isRedirectable(String method) { scim2RestClient = new SCIM2RestClient(serverURL, tenantInfo); - List customScopes = Arrays.asList(CUSTOM_SCOPE_1, CUSTOM_SCOPE_2, CUSTOM_SCOPE_3); + customScopes = Arrays.asList(CUSTOM_SCOPE_1, CUSTOM_SCOPE_2, CUSTOM_SCOPE_3); applicationId = createOIDCAppWithClaims(); + OpenIDConnectConfiguration oidcConfig = getOIDCInboundDetailsOfApplication(applicationId); + subjectType = oidcConfig.getSubject().getSubjectType(); + tokenType = oidcConfig.getAccessToken().getType(); if (!CarbonUtils.isLegacyAuthzRuntimeEnabled()) { - authorizeSystemAPIs(applicationId, new ArrayList<>(Arrays.asList(SCIM2_USERS_API, ACTIONS_API, - APPLICATION_MANAGEMENT_API, API_RESOURCE_MANAGEMENT_API))); + authorizeSystemAPIs(applicationId, Collections.singletonList(SCIM2_USERS_API)); } domainAPIId = createDomainAPI(EXTERNAL_SERVICE_NAME, EXTERNAL_SERVICE_URI, customScopes); authorizeDomainAPIs(applicationId, domainAPIId, customScopes); - addUserWithRole(applicationId, customScopes); - actionsMockServer = new ActionsMockServer(); - - actionsMockServer.createMockServer(MOCK_SERVER_ENDPOINT); + requestedScopes = new ArrayList<>(); + Collections.addAll(requestedScopes, + INTERNAL_ORG_USER_MANAGEMENT_LIST, + INTERNAL_ORG_USER_MANAGEMENT_VIEW, + INTERNAL_ORG_USER_MANAGEMENT_CREATE, + INTERNAL_ORG_USER_MANAGEMENT_UPDATE, + INTERNAL_ORG_USER_MANAGEMENT_DELETE, + OPENID_SCOPE, + PROFILE_SCOPE); + requestedScopes.addAll(customScopes); actionId = createPreIssueAccessTokenAction(); + + actionsMockServer = new ActionsMockServer(); + actionsMockServer.startServer(); + actionsMockServer.setupStub(MOCK_SERVER_ENDPOINT_RESOURCE_PATH, + "Basic " + getBase64EncodedString(MOCK_SERVER_AUTH_BASIC_USERNAME, MOCK_SERVER_AUTH_BASIC_PASSWORD), + FileUtils.readFileInClassPathAsString("actions/response/pre-issue-access-token-response.json")); } @AfterClass(alwaysRun = true) public void atEnd() throws Exception { - actionsMockServer.startServer(); + actionsMockServer.stopServer(); deleteAction(PRE_ISSUE_ACCESS_TOKEN_API_PATH, actionId); deleteRole(roleId); @@ -222,8 +281,8 @@ public void testSendAuthorizeRequest() throws Exception { urlParameters.add(new BasicNameValuePair("client_id", clientId)); urlParameters.add(new BasicNameValuePair("redirect_uri", OAuth2Constant.CALLBACK_URL)); - permissions.addAll(appTokenScopes.getRequestedScopes()); - urlParameters.add(new BasicNameValuePair("scope", String.join(" ", permissions))); + String scopes = String.join(" ", requestedScopes); + urlParameters.add(new BasicNameValuePair("scope", scopes)); HttpResponse response = sendPostRequestWithParameters(client, urlParameters, getTenantQualifiedURL(AUTHORIZE_ENDPOINT_URL, tenantInfo.getDomain())); @@ -271,6 +330,9 @@ public void testGetAccessTokenWithAuthCodeGrant() throws Exception { urlParameters.add(new BasicNameValuePair("redirect_uri", OAuth2Constant.CALLBACK_URL)); urlParameters.add(new BasicNameValuePair("client_id", clientId)); + String scopes = String.join(" ", requestedScopes); + urlParameters.add(new BasicNameValuePair("scope", scopes)); + List
headers = new ArrayList<>(); headers.add(new BasicHeader(AUTHORIZATION_HEADER, OAuth2Constant.BASIC_HEADER + " " + getBase64EncodedString(clientId, clientSecret))); @@ -292,6 +354,19 @@ public void testGetAccessTokenWithAuthCodeGrant() throws Exception { assertNotNull(jwtClaims); } + @Test(groups = "wso2.is", dependsOnMethods = "testGetAccessTokenWithAuthCodeGrant", description = + "Verify the pre issue access token action request") + public void testPreIssueAccessTokenActionRequest() throws Exception { + + String actualRequestPayload = actionsMockServer.getReceivedRequestPayload(MOCK_SERVER_ENDPOINT_RESOURCE_PATH); + PreIssueAccessTokenActionRequest actualRequest = + new ObjectMapper().readValue(actualRequestPayload, PreIssueAccessTokenActionRequest.class); + + PreIssueAccessTokenActionRequest expectedRequest = getRequest(); + + assertEquals(actualRequest, expectedRequest); + } + @Test(groups = "wso2.is", description = "Verify that the access token contains the updated scopes " + "after action execution", dependsOnMethods = "testGetAccessTokenWithAuthCodeGrant") public void testTokenScopeOperations() throws Exception { @@ -302,7 +377,7 @@ public void testTokenScopeOperations() throws Exception { Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_2)); Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_3)); Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_4)); - Assert.assertFalse(ArrayUtils.contains(scopes, CUSTOM_SCOPE_3)); + Assert.assertFalse(ArrayUtils.contains(scopes, INTERNAL_ORG_USER_MANAGEMENT_DELETE)); Assert.assertFalse(ArrayUtils.contains(scopes, INTERNAL_ORG_USER_MANAGEMENT_CREATE)); } @@ -310,8 +385,8 @@ public void testTokenScopeOperations() throws Exception { "after action execution", dependsOnMethods = "testGetAccessTokenWithAuthCodeGrant") public void testTokenOIDCScopeOperations() throws Exception { - String firstName = jwtClaims.getStringClaim("given_name"); - String lastName = jwtClaims.getStringClaim("family_name"); + String firstName = jwtClaims.getStringClaim(FIRST_NAME_CLAIM); + String lastName = jwtClaims.getStringClaim(LAST_NAME_CLAIM); Assert.assertEquals(firstName, REPLACED_FIRST_NAME); Assert.assertNotEquals(firstName, TEST_USER_FIRST_NAME); Assert.assertNotEquals(lastName, TEST_USER_LAST_NAME); @@ -373,7 +448,7 @@ public void testTokenExpiresInClaimReplaceOperation() throws Exception { Date iat = jwtClaims.getDateClaim("iat"); long expiresIn = (exp.getTime() - iat.getTime()) / 1000; - Assert.assertEquals(expiresIn, 7200); + Assert.assertEquals(expiresIn, UPDATED_EXPIRY_TIME_PERIOD); } /** @@ -392,6 +467,107 @@ private String getAuthorizationCodeFromURL(String location) { .orElse(null); } + /** + * Retrieves pre issue access token action request. + * + * @return pre issue access token request object + */ + private PreIssueAccessTokenActionRequest getRequest() { + + TokenRequest tokenRequest = createTokenRequest(); + AccessToken accessTokenInRequest = createAccessToken(); + + Tenant tenant = new Tenant(tenantId, tenantInfo.getDomain()); + User user = new User(userId); + UserStore userStore = + new UserStore(Base64.getEncoder().encodeToString("PRIMARY".getBytes(StandardCharsets.UTF_8)), + "PRIMARY"); + + PreIssueAccessTokenEvent event = new PreIssueAccessTokenEvent.Builder() + .request(tokenRequest) + .accessToken(accessTokenInRequest) + .tenant(tenant) + .organization(null) + .user(user) + .userStore(userStore) + .build(); + + List allowedOperations = Arrays.asList( + createAllowedOperation(Operation.ADD, Arrays.asList(CLAIMS_PATH_PREFIX, SCOPES_PATH_PREFIX, + CLAIMS_PATH_PREFIX + AccessToken.ClaimNames.AUD.getName() + "/")), + createAllowedOperation(Operation.REMOVE, Arrays.asList(CLAIMS_PATH_PREFIX + FIRST_NAME_CLAIM, + CLAIMS_PATH_PREFIX + LAST_NAME_CLAIM, + SCOPES_PATH_PREFIX, + CLAIMS_PATH_PREFIX + AccessToken.ClaimNames.AUD.getName() + "/")), + createAllowedOperation(Operation.REPLACE, Arrays.asList(CLAIMS_PATH_PREFIX + FIRST_NAME_CLAIM, + CLAIMS_PATH_PREFIX + LAST_NAME_CLAIM, + SCOPES_PATH_PREFIX, + CLAIMS_PATH_PREFIX + AccessToken.ClaimNames.AUD.getName() + "/", + CLAIMS_PATH_PREFIX + AccessToken.ClaimNames.EXPIRES_IN.getName())) + ); + + return new PreIssueAccessTokenActionRequest.Builder() + .actionType(ActionType.PRE_ISSUE_ACCESS_TOKEN) + .event(event) + .allowedOperations(allowedOperations) + .build(); + } + + /** + * Creates token request. + * + * @return token request object + */ + private TokenRequest createTokenRequest() { + + return new TokenRequest.Builder() + .grantType(OAUTH2_GRANT_TYPE_AUTHORIZATION_CODE) + .scopes(requestedScopes) + .clientId(clientId) + .build(); + } + + /** + * Creates access token. + * + * @return access token object + */ + private AccessToken createAccessToken() { + + List claims = new ArrayList<>(); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.ISS.getName(), + getTenantQualifiedURL(ACCESS_TOKEN_ENDPOINT, tenantInfo.getDomain()))); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.CLIENT_ID.getName(), clientId)); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.AUTHORIZED_USER_TYPE.getName(), "APPLICATION_USER")); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.EXPIRES_IN.getName(), CURRENT_EXPIRY_TIME_PERIOD)); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.AUD.getName(), Collections.singletonList(clientId))); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.SUBJECT_TYPE.getName(), subjectType)); + claims.add(new AccessToken.Claim(AccessToken.ClaimNames.SUB.getName(), userId)); + claims.add(new AccessToken.Claim(FIRST_NAME_CLAIM, TEST_USER_FIRST_NAME)); + claims.add(new AccessToken.Claim(LAST_NAME_CLAIM, TEST_USER_LAST_NAME)); + + return new AccessToken.Builder() + .tokenType(tokenType) + .claims(claims) + .scopes(requestedScopes) + .build(); + } + + /** + * Creates allowed operations. + * + * @param op operations allowed + * @param paths operation paths to be modified + * @return allowed operations object + */ + private AllowedOperation createAllowedOperation(Operation op, List paths) { + + AllowedOperation operation = new AllowedOperation(); + operation.setOp(op); + operation.setPaths(new ArrayList<>(paths)); + return operation; + } + /** * Creates an action for pre-issuing an access token with basic authentication. * @@ -403,8 +579,8 @@ private String createPreIssueAccessTokenAction() throws IOException { AuthenticationType authenticationType = new AuthenticationType(); authenticationType.setType(AuthenticationType.TypeEnum.BASIC); Map authProperties = new HashMap<>(); - authProperties.put(USERNAME_PROPERTY, TEST_USER); - authProperties.put(PASSWORD_PROPERTY, ADMIN_WSO2); + authProperties.put(USERNAME_PROPERTY, MOCK_SERVER_AUTH_BASIC_USERNAME); + authProperties.put(PASSWORD_PROPERTY, MOCK_SERVER_AUTH_BASIC_PASSWORD); authenticationType.setProperties(authProperties); Endpoint endpoint = new Endpoint(); @@ -473,15 +649,16 @@ private void addUserWithRole(String appID, List customScopes) throws Exc private List addPermissions(List customScopes) { List userPermissions = new ArrayList<>(); - Collections.addAll(permissions, - INTERNAL_ORG_USER_MANAGEMENT_CREATE, - INTERNAL_ORG_USER_MANAGEMENT_LIST, - INTERNAL_ORG_USER_MANAGEMENT_VIEW, - INTERNAL_ORG_USER_MANAGEMENT_UPDATE, - INTERNAL_ORG_USER_MANAGEMENT_DELETE + + Collections.addAll(userPermissions, + new Permission(INTERNAL_ORG_USER_MANAGEMENT_LIST), + new Permission(INTERNAL_ORG_USER_MANAGEMENT_VIEW), + new Permission(INTERNAL_ORG_USER_MANAGEMENT_CREATE), + new Permission(INTERNAL_ORG_USER_MANAGEMENT_UPDATE), + new Permission(INTERNAL_ORG_USER_MANAGEMENT_DELETE) ); - permissions.addAll(customScopes); - permissions.forEach(permission -> userPermissions.add(new Permission(permission))); + + customScopes.forEach(scope -> userPermissions.add(new Permission(scope))); return userPermissions; } @@ -490,9 +667,9 @@ private String createOIDCAppWithClaims() throws Exception { List userClaimConfigs = Arrays.asList( new UserClaimConfig.Builder().localClaimUri("http://wso2.org/claims/givenname"). - oidcClaimUri("given_name").build(), + oidcClaimUri(FIRST_NAME_CLAIM).build(), new UserClaimConfig.Builder().localClaimUri("http://wso2.org/claims/lastname"). - oidcClaimUri("family_name").build() + oidcClaimUri(LAST_NAME_CLAIM).build() ); ApplicationConfig applicationConfig = new ApplicationConfig.Builder() @@ -503,9 +680,9 @@ private String createOIDCAppWithClaims() throws Exception { .skipConsent(true) .build(); - appTokenScopes = new TokenScopes.Builder().requestedScopes(Arrays.asList("openid", "profile", + appTokenScopes = new TokenScopes.Builder().requestedScopes(Arrays.asList(OPENID_SCOPE, PROFILE_SCOPE, CUSTOM_OIDC_SCOPE)) - .grantedScopes(Arrays.asList("openid", "profile")).build(); + .grantedScopes(Arrays.asList(OPENID_SCOPE, PROFILE_SCOPE, CUSTOM_OIDC_SCOPE)).build(); ApplicationResponseModel application = addApplication(applicationConfig); String applicationId = application.getId(); @@ -517,4 +694,3 @@ private String createOIDCAppWithClaims() throws Exception { return applicationId; } } - diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java index 59977e92e5..908360be7a 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java @@ -313,7 +313,7 @@ public void testTokenScopeOperations() throws Exception { Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_2)); Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_3)); Assert.assertTrue(ArrayUtils.contains(scopes, NEW_SCOPE_4)); - Assert.assertFalse(ArrayUtils.contains(scopes, CUSTOM_SCOPE_3)); + Assert.assertFalse(ArrayUtils.contains(scopes, INTERNAL_ORG_USER_MANAGEMENT_DELETE)); Assert.assertFalse(ArrayUtils.contains(scopes, INTERNAL_ORG_USER_MANAGEMENT_CREATE)); } diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java index d77a4998bc..e9c782e321 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java @@ -73,142 +73,4 @@ public String getReceivedRequestPayload(String url) { return requestList.get(0).getBodyAsString(); } - - /** - * Create a mock server with wiremock. - * - * @throws Exception If an error occurred while creating the server - */ - public void createMockServer(String mockEndpoint) throws Exception { - - wireMockServer = new WireMockServer(wireMockConfig().port(8587)); - - wireMockServer.start(); - - try { - // TODO: Read the response from a file - // TODO: Filter the response from the action type - String jsonResponse = "{\n" + - " \"actionStatus\": \"SUCCESS\",\n" + - " \"operations\": [\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/scopes/-\",\n" + - " \"value\": \"new_test_custom_scope_1\"\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/scopes/-\",\n" + - " \"value\": \"new_test_custom_scope_2\"\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/scopes/-\",\n" + - " \"value\": \"new_test_custom_scope_3\"\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/aud/-\",\n" + - " \"value\": \"zzz1.com\"\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/aud/-\",\n" + - " \"value\": \"zzz2.com\"\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/aud/-\",\n" + - " \"value\": \"zzz3.com\"\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/-\",\n" + - " \"value\": {\n" + - " \"name\": \"custom_claim_string_1\",\n" + - " \"value\": \"testCustomClaim1\"\n" + - " }\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/-\",\n" + - " \"value\": {\n" + - " \"name\": \"custom_claim_number_1\",\n" + - " \"value\": 78\n" + - " }\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/-\",\n" + - " \"value\": {\n" + - " \"name\": \"custom_claim_boolean_1\",\n" + - " \"value\": true\n" + - " }\n" + - " },\n" + - " {\n" + - " \"op\": \"add\",\n" + - " \"path\": \"/accessToken/claims/-\",\n" + - " \"value\": {\n" + - " \"name\": \"custom_claim_string_array_1\",\n" + - " \"value\": [\n" + - " \"TestCustomClaim1\",\n" + - " \"TestCustomClaim2\",\n" + - " \"TestCustomClaim3\"\n" + - " ]\n" + - " }\n" + - " },\n" + - " {\n" + - " \"op\": \"replace\",\n" + - " \"path\": \"/accessToken/scopes/-\",\n" + - " \"value\": \"replaced_scope\"\n" + - " },\n" + - " {\n" + - " \"op\": \"replace\",\n" + - " \"path\": \"/accessToken/claims/aud/-\",\n" + - " \"value\": \"zzzR.com\"\n" + - " },\n" + - " {\n" + - " \"op\": \"replace\",\n" + - " \"path\": \"/accessToken/claims/expires_in\",\n" + - " \"value\": 7200\n" + - " },\n" + - " {\n" + - " \"op\": \"replace\",\n" + - " \"path\": \"/accessToken/claims/given_name\",\n" + - " \"value\": \"replaced_given_name\"\n" + - " },\n" + - " {\n" + - " \"op\": \"remove\",\n" + - " \"path\": \"/accessToken/scopes/0\"\n" + - " },\n" + - " {\n" + - " \"op\": \"remove\",\n" + - " \"path\": \"/accessToken/claims/aud/-\"\n" + - " },\n" + - " {\n" + - " \"op\": \"remove\",\n" + - " \"path\": \"/accessToken/claims/family_name\"\n" + - " }\n" + - " ]\n" + - "}\n"; - - // TODO: Handle status codes related to different scenarios - wireMockServer.stubFor(post(urlEqualTo(mockEndpoint)) - .willReturn(aResponse() - .withStatus(200) - .withHeader("Content-Type", "application/json") - .withBody(jsonResponse))); - - } catch (Exception e) { - throw new Exception("Error occurred while creating the mock server: " + e); - } - } - - /** - * Shut down the wiremock server instance. - */ - public void shutDownMockServer() { - - wireMockServer.stop(); - } } diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/model/PreIssueAccessTokenEvent.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/model/PreIssueAccessTokenEvent.java index e293edf1d6..385bf1983f 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/model/PreIssueAccessTokenEvent.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/model/PreIssueAccessTokenEvent.java @@ -54,15 +54,21 @@ public AccessToken getAccessToken() { @Override public boolean equals(Object o) { - if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; + PreIssueAccessTokenEvent that = (PreIssueAccessTokenEvent) o; - return Objects.equals(request, that.request) && + + boolean isEqualGeneral = Objects.equals(request, that.request) && Objects.equals(accessToken, that.accessToken) && - Objects.equals(tenant, that.tenant) && - Objects.equals(user, that.user) && - Objects.equals(userStore, that.userStore); + Objects.equals(tenant, that.tenant); + + if (!"client_credentials".equals(that.request.getGrantType())) { + return isEqualGeneral && + Objects.equals(user, that.user) && + Objects.equals(userStore, that.userStore); + } + return isEqualGeneral; } @Override diff --git a/modules/integration/tests-integration/tests-backend/src/test/resources/actions/response/pre-issue-access-token-response.json b/modules/integration/tests-integration/tests-backend/src/test/resources/actions/response/pre-issue-access-token-response.json index 20d6d2e68a..40779284b4 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/resources/actions/response/pre-issue-access-token-response.json +++ b/modules/integration/tests-integration/tests-backend/src/test/resources/actions/response/pre-issue-access-token-response.json @@ -69,7 +69,7 @@ }, { "op": "replace", - "path": "/accessToken/scopes/7", + "path": "/accessToken/scopes/1", "value": "replaced_scope" }, { From c68ebe898e8a0950bf97d8c9f2b662edcf821dd5 Mon Sep 17 00:00:00 2001 From: Shenali Date: Fri, 20 Sep 2024 11:33:05 +0530 Subject: [PATCH 6/8] Add thread sleeping to handle mock server overloading --- .../PreIssueAccessTokenClientCredentialsGrantTestCase.java | 7 ++++++- .../test/actions/PreIssueAccessTokenCodeGrantTestCase.java | 5 +++++ .../actions/PreIssueAccessTokenPasswordGrantTestCase.java | 6 +++++- .../test/actions/mockserver/ActionsMockServer.java | 1 - 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java index 79b0768de7..57e98e9ed3 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java @@ -87,7 +87,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertNotNull; @@ -234,6 +233,12 @@ protected boolean isRedirectable(String method) { actionId = createPreIssueAccessTokenAction(); + try { + Thread.sleep(3600); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + actionsMockServer = new ActionsMockServer(); actionsMockServer.startServer(); actionsMockServer.setupStub(MOCK_SERVER_ENDPOINT_RESOURCE_PATH, diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java index e9b00e4fcf..d51d9dbf5b 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java @@ -244,6 +244,11 @@ protected boolean isRedirectable(String method) { actionId = createPreIssueAccessTokenAction(); + try { + Thread.sleep(3600); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } actionsMockServer = new ActionsMockServer(); actionsMockServer.startServer(); actionsMockServer.setupStub(MOCK_SERVER_ENDPOINT_RESOURCE_PATH, diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java index 908360be7a..a8d45a0747 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java @@ -212,7 +212,6 @@ protected boolean isRedirectable(String method) { subjectType = oidcConfig.getSubject().getSubjectType(); tokenType = oidcConfig.getAccessToken().getType(); - if (!CarbonUtils.isLegacyAuthzRuntimeEnabled()) { authorizeSystemAPIs(applicationId, Collections.singletonList(SCIM2_USERS_API)); } @@ -231,6 +230,11 @@ protected boolean isRedirectable(String method) { actionId = createPreIssueAccessTokenAction(); + try { + Thread.sleep(3600); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } actionsMockServer = new ActionsMockServer(); actionsMockServer.startServer(); actionsMockServer.setupStub(MOCK_SERVER_ENDPOINT_RESOURCE_PATH, diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java index e9c782e321..2a8902f4e9 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java @@ -30,7 +30,6 @@ import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor; import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; /** * Provides a mock server using WireMock for testing purposes. From 546a593bf0a469c41a9229e886472a9b30d3abe5 Mon Sep 17 00:00:00 2001 From: Shenali Date: Fri, 20 Sep 2024 16:15:49 +0530 Subject: [PATCH 7/8] Remove user object in client credential grant --- .../PreIssueAccessTokenClientCredentialsGrantTestCase.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java index 57e98e9ed3..a7fc8f8c9f 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java @@ -393,18 +393,12 @@ private PreIssueAccessTokenActionRequest getRequest() { AccessToken accessTokenInRequest = createAccessToken(); Tenant tenant = new Tenant(tenantId, tenantInfo.getDomain()); - User user = new User(userId); - UserStore userStore = - new UserStore(Base64.getEncoder().encodeToString("PRIMARY".getBytes(StandardCharsets.UTF_8)), - "PRIMARY"); PreIssueAccessTokenEvent event = new PreIssueAccessTokenEvent.Builder() .request(tokenRequest) .accessToken(accessTokenInRequest) .tenant(tenant) .organization(null) - .user(user) - .userStore(userStore) .build(); List allowedOperations = Arrays.asList( From e641385fd8a50b37b7b3090ff41135d479266800 Mon Sep 17 00:00:00 2001 From: Shenali Date: Mon, 23 Sep 2024 15:39:12 +0530 Subject: [PATCH 8/8] Add Connection: Close header to wiremock response --- ...ssTokenClientCredentialsGrantTestCase.java | 88 ------------------- .../PreIssueAccessTokenCodeGrantTestCase.java | 12 +-- ...IssueAccessTokenPasswordGrantTestCase.java | 5 -- .../actions/mockserver/ActionsMockServer.java | 2 +- 4 files changed, 2 insertions(+), 105 deletions(-) diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java index a7fc8f8c9f..b9803ae552 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenClientCredentialsGrantTestCase.java @@ -37,7 +37,6 @@ import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; -import org.json.JSONException; import org.json.JSONObject; import org.testng.Assert; import org.testng.annotations.AfterClass; @@ -55,33 +54,20 @@ import org.wso2.identity.integration.test.actions.model.PreIssueAccessTokenEvent; import org.wso2.identity.integration.test.actions.model.Tenant; import org.wso2.identity.integration.test.actions.model.TokenRequest; -import org.wso2.identity.integration.test.actions.model.User; -import org.wso2.identity.integration.test.actions.model.UserStore; import org.wso2.identity.integration.test.rest.api.server.action.management.v1.model.ActionModel; import org.wso2.identity.integration.test.rest.api.server.action.management.v1.model.AuthenticationType; import org.wso2.identity.integration.test.rest.api.server.action.management.v1.model.Endpoint; import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationResponseModel; import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.OpenIDConnectConfiguration; -import org.wso2.identity.integration.test.rest.api.server.roles.v2.model.Audience; -import org.wso2.identity.integration.test.rest.api.server.roles.v2.model.Permission; -import org.wso2.identity.integration.test.rest.api.server.roles.v2.model.RoleV2; -import org.wso2.identity.integration.test.rest.api.user.common.model.Email; -import org.wso2.identity.integration.test.rest.api.user.common.model.ListObject; -import org.wso2.identity.integration.test.rest.api.user.common.model.Name; -import org.wso2.identity.integration.test.rest.api.user.common.model.PatchOperationRequestObject; -import org.wso2.identity.integration.test.rest.api.user.common.model.RoleItemAddGroupobj; -import org.wso2.identity.integration.test.rest.api.user.common.model.UserObject; import org.wso2.identity.integration.test.restclients.SCIM2RestClient; import org.wso2.identity.integration.test.utils.CarbonUtils; import org.wso2.identity.integration.test.utils.FileUtils; import org.wso2.identity.integration.test.utils.OAuth2Constant; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Base64; import java.util.Collections; import java.util.Date; import java.util.HashMap; @@ -102,20 +88,12 @@ */ public class PreIssueAccessTokenClientCredentialsGrantTestCase extends ActionsBaseTestCase { - private static final String USERS = "users"; private static final String USERNAME_PROPERTY = "username"; private static final String PASSWORD_PROPERTY = "password"; - private static final String TEST_USER = "test_user"; - private static final String ADMIN_WSO2 = "Admin@wso2"; - private static final String TEST_USER_GIVEN = "test_user_given"; - private static final String TEST_USER_GMAIL_COM = "test.user@gmail.com"; private static final String EXTERNAL_SERVICE_NAME = "TestExternalService"; private static final String EXTERNAL_SERVICE_URI = "http://localhost:8587/test/action"; private static final String PRE_ISSUE_ACCESS_TOKEN_API_PATH = "preIssueAccessToken"; - private static final String CLIENT_CREDENTIALS_GRANT_TYPE = "client_credentials"; - private static final String APPLICATION_AUDIENCE = "APPLICATION"; - private static final String TEST_ROLE_APPLICATION = "test_role_application"; private static final String INTERNAL_ORG_USER_MANAGEMENT_LIST = "internal_org_user_mgt_list"; private static final String INTERNAL_ORG_USER_MANAGEMENT_VIEW = "internal_org_user_mgt_view"; @@ -153,8 +131,6 @@ public class PreIssueAccessTokenClientCredentialsGrantTestCase extends ActionsBa private String actionId; private String applicationId; private String domainAPIId; - private String userId; - private String roleId; private String tenantId; private JWTClaimsSet jwtClaims; private TestUserMode userMode; @@ -220,7 +196,6 @@ protected boolean isRedirectable(String method) { } domainAPIId = createDomainAPI(EXTERNAL_SERVICE_NAME, EXTERNAL_SERVICE_URI, customScopes); authorizeDomainAPIs(applicationId, domainAPIId, customScopes); - addUserWithRole(applicationId, customScopes); requestedScopes = new ArrayList<>(); Collections.addAll(requestedScopes, @@ -233,12 +208,6 @@ protected boolean isRedirectable(String method) { actionId = createPreIssueAccessTokenAction(); - try { - Thread.sleep(3600); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - actionsMockServer = new ActionsMockServer(); actionsMockServer.startServer(); actionsMockServer.setupStub(MOCK_SERVER_ENDPOINT_RESOURCE_PATH, @@ -252,10 +221,8 @@ public void atEnd() throws Exception { actionsMockServer.stopServer(); deleteAction(PRE_ISSUE_ACCESS_TOKEN_API_PATH, actionId); - deleteRole(roleId); deleteApp(applicationId); deleteDomainAPI(domainAPIId); - scim2RestClient.deleteUser(userId); restClient.closeHttpClient(); scim2RestClient.closeHttpClient(); @@ -503,59 +470,4 @@ private JWTClaimsSet extractJwtClaims(String jwtToken) throws ParseException { SignedJWT signedJWT = SignedJWT.parse(jwtToken); return signedJWT.getJWTClaimsSet(); } - - /** - * Adds a user with a role and specific permissions based on custom scopes. - * - * @param appID Application ID to which the role is associated - * @param customScopes The custom scopes based on which permissions are added - * @return A list of permissions that were added to the role - * @throws JSONException If there is an error in processing JSON - * @throws IOException If there is an IO exception during user or role creation - */ - private void addUserWithRole(String appID, List customScopes) throws Exception { - // Creates roles - List permissions = addPermissions(customScopes); - Audience roleAudience = new Audience(APPLICATION_AUDIENCE, appID); - RoleV2 role = new RoleV2(roleAudience, TEST_ROLE_APPLICATION, permissions, Collections.emptyList()); - roleId = addRole(role); - - // Creates user - UserObject userInfo = new UserObject(); - userInfo.setUserName(TEST_USER); - userInfo.setPassword(ADMIN_WSO2); - userInfo.setName(new Name().givenName(TEST_USER_GIVEN)); - userInfo.addEmail(new Email().value(TEST_USER_GMAIL_COM)); - userId = scim2RestClient.createUser(userInfo); - - // Assigns role to the created user - RoleItemAddGroupobj rolePatchReqObject = new RoleItemAddGroupobj(); - rolePatchReqObject.setOp(RoleItemAddGroupobj.OpEnum.ADD); - rolePatchReqObject.setPath(USERS); - rolePatchReqObject.addValue(new ListObject().value(userId)); - scim2RestClient.updateUserRole(new PatchOperationRequestObject().addOperations(rolePatchReqObject), roleId); - } - - /** - * Adds permissions based on the provided custom scopes. - * - * @param customScopes A list of custom scopes to add as permissions - * @return A list of permissions including both predefined and custom scope-based permissions - */ - private List addPermissions(List customScopes) { - - List userPermissions = new ArrayList<>(); - - Collections.addAll(userPermissions, - new Permission(INTERNAL_ORG_USER_MANAGEMENT_LIST), - new Permission(INTERNAL_ORG_USER_MANAGEMENT_VIEW), - new Permission(INTERNAL_ORG_USER_MANAGEMENT_CREATE), - new Permission(INTERNAL_ORG_USER_MANAGEMENT_UPDATE), - new Permission(INTERNAL_ORG_USER_MANAGEMENT_DELETE) - ); - - customScopes.forEach(scope -> userPermissions.add(new Permission(scope))); - - return userPermissions; - } } diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java index d51d9dbf5b..ca71adf674 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenCodeGrantTestCase.java @@ -136,7 +136,6 @@ public class PreIssueAccessTokenCodeGrantTestCase extends ActionsBaseTestCase { private static final String NEW_SCOPE_2 = "new_test_custom_scope_2"; private static final String NEW_SCOPE_3 = "new_test_custom_scope_3"; private static final String NEW_SCOPE_4 = "replaced_scope"; - private static final String CUSTOM_OIDC_SCOPE = "test_custom_oidc_scope"; private static final String FIRST_NAME_CLAIM = "given_name"; private static final String LAST_NAME_CLAIM = "family_name"; private static final String PRE_ISSUE_ACCESS_TOKEN_API_PATH = "preIssueAccessToken"; @@ -154,7 +153,6 @@ public class PreIssueAccessTokenCodeGrantTestCase extends ActionsBaseTestCase { private RequestConfig requestConfig; private List customScopes; private List requestedScopes; - private TokenScopes appTokenScopes; private String sessionDataKey; private String authorizationCode; private String accessToken; @@ -244,16 +242,12 @@ protected boolean isRedirectable(String method) { actionId = createPreIssueAccessTokenAction(); - try { - Thread.sleep(3600); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } actionsMockServer = new ActionsMockServer(); actionsMockServer.startServer(); actionsMockServer.setupStub(MOCK_SERVER_ENDPOINT_RESOURCE_PATH, "Basic " + getBase64EncodedString(MOCK_SERVER_AUTH_BASIC_USERNAME, MOCK_SERVER_AUTH_BASIC_PASSWORD), FileUtils.readFileInClassPathAsString("actions/response/pre-issue-access-token-response.json")); + } @AfterClass(alwaysRun = true) @@ -685,10 +679,6 @@ private String createOIDCAppWithClaims() throws Exception { .skipConsent(true) .build(); - appTokenScopes = new TokenScopes.Builder().requestedScopes(Arrays.asList(OPENID_SCOPE, PROFILE_SCOPE, - CUSTOM_OIDC_SCOPE)) - .grantedScopes(Arrays.asList(OPENID_SCOPE, PROFILE_SCOPE, CUSTOM_OIDC_SCOPE)).build(); - ApplicationResponseModel application = addApplication(applicationConfig); String applicationId = application.getId(); diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java index a8d45a0747..c030bfcb70 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java @@ -230,11 +230,6 @@ protected boolean isRedirectable(String method) { actionId = createPreIssueAccessTokenAction(); - try { - Thread.sleep(3600); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } actionsMockServer = new ActionsMockServer(); actionsMockServer.startServer(); actionsMockServer.setupStub(MOCK_SERVER_ENDPOINT_RESOURCE_PATH, diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java index 2a8902f4e9..d49b0e36c5 100644 --- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java +++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/mockserver/ActionsMockServer.java @@ -39,7 +39,6 @@ public class ActionsMockServer { private WireMockServer wireMockServer; - public void startServer() { wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig().port(8587)); @@ -60,6 +59,7 @@ public void setupStub(String url, String authMethod, String responseBody) { .willReturn(aResponse() .withStatus(200) .withHeader("Content-Type", "application/json") + .withHeader("Connection", "Close") .withBody(responseBody))); }