diff --git a/modules/integration/tests-integration/tests-backend/pom.xml b/modules/integration/tests-integration/tests-backend/pom.xml
index 08f1be8d61..20cdd8663f 100644
--- a/modules/integration/tests-integration/tests-backend/pom.xml
+++ b/modules/integration/tests-integration/tests-backend/pom.xml
@@ -647,6 +647,11 @@
org.apache.httpcomponents
httpclient
+
+ org.wiremock
+ wiremock
+ test
+
io.rest-assured
rest-assured
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/ActionsBaseTestCase.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/ActionsBaseTestCase.java
new file mode 100644
index 0000000000..fdbed9d873
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/ActionsBaseTestCase.java
@@ -0,0 +1,77 @@
+/*
+ * 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 org.wso2.carbon.automation.engine.context.TestUserMode;
+import org.wso2.identity.integration.test.oauth2.OAuth2ServiceAbstractIntegrationTest;
+import org.wso2.identity.integration.test.rest.api.server.action.management.v1.model.ActionModel;
+import org.wso2.identity.integration.test.restclients.ActionsRestClient;
+
+import java.io.IOException;
+
+/**
+ * Base test case for action-related tests.
+ * This class extends {@link OAuth2ServiceAbstractIntegrationTest} and provides the necessary setup
+ * and utility methods for testing actions via the {@link ActionsRestClient}.
+ */
+public class ActionsBaseTestCase extends OAuth2ServiceAbstractIntegrationTest {
+
+ protected ActionsRestClient restClient;
+
+ /**
+ * Initialize the test case.
+ *
+ * @param userMode User Mode
+ * @throws Exception If an error occurred while initializing the clients.
+ */
+ protected void init(TestUserMode userMode) throws Exception {
+
+ super.init(userMode);
+
+ restClient = new ActionsRestClient(serverURL, tenantInfo);
+
+ setSystemproperties();
+ }
+
+ /**
+ * Create action of different types.
+ *
+ * @param actionType Type of action
+ * @param actionModel Request object to create the action
+ * @return Status code of the action creation
+ * @throws IOException If an error occurred while creating the action
+ */
+ public String createAction(String actionType, ActionModel actionModel) throws IOException {
+
+ return restClient.createActionType(actionModel, actionType);
+ }
+
+ /**
+ * Delete an action.
+ *
+ * @param actionType Type of action
+ * @param actionId ID of the action
+ * @return Status code of the action creation
+ * @throws IOException If an error occurred while deleting the action
+ */
+ public int deleteAction(String actionType, String actionId) throws IOException {
+
+ return restClient.deleteActionType(actionType, actionId);
+ }
+}
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
new file mode 100644
index 0000000000..2f6cbce001
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/actions/PreIssueAccessTokenPasswordGrantTestCase.java
@@ -0,0 +1,373 @@
+/*
+ * 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.json.JSONException;
+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.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.ActionsRestClient;
+import org.wso2.identity.integration.test.restclients.SCIM2RestClient;
+import org.wso2.identity.integration.test.utils.CarbonUtils;
+import org.wso2.identity.integration.test.utils.OAuth2Constant;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Integration test class for testing the pre issue access token flow with password grant.
+ * This test case extends {@link ActionsBaseTestCase} and focuses on scenarios related
+ * to scopes and claims modifications through an external service.
+ */
+public class PreIssueAccessTokenPasswordGrantTestCase 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 PASSWORD_GRANT_TYPE = "password";
+ 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";
+ 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 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";
+
+ protected SCIM2RestClient scim2RestClient;
+ private String accessToken;
+ private String clientId;
+ 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);
+
+ scim2RestClient = new SCIM2RestClient(serverURL, tenantInfo);
+ restClient = new ActionsRestClient(serverURL, tenantInfo);
+ // TODO: Review if ActionsRestClient should be instantiated, or if the superclass initialization is sufficient
+
+ List customScopes = Arrays.asList(CUSTOM_SCOPE_1, CUSTOM_SCOPE_2, CUSTOM_SCOPE_3);
+
+ ApplicationResponseModel application = addApplicationWithGrantType(PASSWORD_GRANT_TYPE);
+ applicationId = application.getId();
+ 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();
+
+ accessToken = retrieveAccessToken(application.getId(), customScopes);
+ jwtClaims = extractJwtClaims(accessToken);
+ }
+
+ @AfterClass(alwaysRun = true)
+ public void atEnd() throws Exception {
+
+ deleteAction(PRE_ISSUE_ACCESS_TOKEN_API_PATH, actionId);
+ restClient = null;
+ deleteRole(roleId);
+ deleteApp(applicationId);
+ deleteDomainAPI(domainAPIId);
+ scim2RestClient.deleteUser(userId);
+ scim2RestClient = null;
+ MockServer.shutDownMockServer();
+ accessToken = null;
+ jwtClaims = null;
+ }
+
+ @Test(groups = "wso2.is", description = "Verify the presence of the updated scopes in the access token")
+ 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));
+ Assert.assertFalse(ArrayUtils.contains(scopes, CUSTOM_SCOPE_2));
+ }
+
+ @Test(groups = "wso2.is", description = "Verify the presence of the updated aud claims in the access token")
+ 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")
+ 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")
+ 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")
+ 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")
+ public void testTokenStringArrayClaimAddOperation()
+ throws Exception {
+
+ String[] claimArray1 = {"TestCustomClaim1", "TestCustomClaim2", "TestCustomClaim3"};
+
+ String[] claimArray = jwtClaims.getStringArrayClaim("custom_claim_string_array_1");
+ Assert.assertEquals(claimArray, claimArray1);
+ }
+
+ @Test(groups = "wso2.is", description = "Verify the replacement of the 'expires_in' claim in the access token")
+ public void testTokenExpiresInClaimReplaceOperation() throws Exception {
+
+ if (jwtClaims.getClaim("expires_in") != null) {
+ Object expValue = jwtClaims.getLongClaim("expires_in");
+ Assert.assertEquals(expValue, 7200);
+ }
+ }
+
+ /**
+ * Creates an action for pre-issuing an access token with basic authentication.
+ */
+ private String createPreIssueAccessTokenAction() {
+
+ AuthenticationType authenticationType = new AuthenticationType();
+ authenticationType.setType(AuthenticationType.TypeEnum.BASIC); // todo handle mock server authorization
+ 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);
+
+ try {
+ return createAction(PRE_ISSUE_ACCESS_TOKEN_API_PATH, actionModel);
+ } catch (IOException e) {
+ throw new RuntimeException("Error while creating pre issue access token " + actionModel.getName());
+ }
+ }
+
+ /**
+ * Retrieves an access token for the application.
+ *
+ * @param applicationId ID of the application
+ * @param customScopes Custom scopes related to the integrated domain APIs
+ * @return Access token
+ * @throws Exception If error occurred wile requesting access token
+ */
+ private String retrieveAccessToken(String applicationId, List customScopes) throws Exception {
+
+ OpenIDConnectConfiguration oidcConfig = getOIDCInboundDetailsOfApplication(applicationId);
+ clientId = oidcConfig.getClientId();
+ String tenantedTokenURI = getTenantQualifiedURL(OAuth2Constant.ACCESS_TOKEN_ENDPOINT, tenantInfo.getDomain());
+
+ List permissions = new ArrayList<>();
+ Collections.addAll(permissions,
+ 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 -> permissions.add(new Permission(scope)));
+
+ return requestAccessToken(clientId, oidcConfig.getClientSecret(), tenantedTokenURI,
+ TEST_USER, ADMIN_WSO2, permissions);
+ }
+
+ /**
+ * 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
+ * @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_ACTION_MANAGEMENT_VIEW),
+ new Permission(INTERNAL_ACTION_MANAGEMENT_CREATE),
+ new Permission(INTERNAL_ACTION_MANAGEMENT_UPDATE),
+ new Permission(INTERNAL_ACTION_MANAGEMENT_DELETE),
+
+ 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),
+
+ new Permission(INTERNAL_APPLICATION_MANAGEMENT_VIEW),
+ new Permission(INTERNAL_APPLICATION_MANAGEMENT_UPDATE),
+
+ new Permission(INTERNAL_API_RESOURCE_VIEW),
+ new Permission(INTERNAL_API_RESOURCE_CREATE)
+ );
+
+ customScopes.forEach(scope -> userPermissions.add(new Permission(scope)));
+
+ return userPermissions;
+ }
+ // TODO: Validate the changes with the "enable_password_grant_enhancements" configuration enabled.
+}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/mocks/MockServer.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/mocks/MockServer.java
new file mode 100644
index 0000000000..74fbbaf6e1
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/mocks/MockServer.java
@@ -0,0 +1,145 @@
+package org.wso2.identity.integration.test.mocks;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+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.
+ * This class starts a mock server on a specified port and sets up predefined
+ * responses for POST requests to simulate various operations relation to action execution.
+ */
+public class MockServer {
+
+ private static WireMockServer wireMockServer;
+
+ /**
+ * Create a mock server with wiremock.
+ *
+ * @throws Exception If an error occurred while creating the server
+ */
+ public static 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/7\",\n" +
+ " \"value\": \"replaced_scope\"\n" +
+ " },\n" +
+ " {\n" +
+ " \"op\": \"replace\",\n" +
+ " \"path\": \"/accessToken/claims/aud/-\",\n" +
+ " \"value\": \"zzzR.com\"\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))
+ .withRequestBody(matchingJsonPath("$.event.request.grantType", equalTo("password")))
+ .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 static void shutDownMockServer() {
+
+ wireMockServer.stop();
+ }
+}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java
index 425bec8c2d..386b97836b 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/oauth2/OAuth2ServiceAbstractIntegrationTest.java
@@ -54,6 +54,7 @@
import org.wso2.identity.integration.common.utils.ISIntegrationTest;
import org.wso2.identity.integration.test.rest.api.server.api.resource.v1.model.APIResourceListItem;
import org.wso2.identity.integration.test.rest.api.server.api.resource.v1.model.ScopeGetModel;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.AccessTokenConfiguration;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.AdvancedApplicationConfiguration;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationModel;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationPatchModel;
@@ -63,6 +64,7 @@
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ClaimConfiguration;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ClaimConfiguration.DialectEnum;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ClaimMappings;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.DomainAPICreationModel;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.InboundProtocols;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.OpenIDConnectConfiguration;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.RequestedClaimConfiguration;
@@ -105,7 +107,7 @@ public class OAuth2ServiceAbstractIntegrationTest extends ISIntegrationTest {
public static final String OIDC = "oidc";
public static final String SAML = "saml";
private final static int TOMCAT_PORT = 8490;
-
+ private static final boolean REQUIRES_AUTHORIZATION = true;
protected ApplicationManagementServiceClient appMgtclient;
protected OauthAdminClient adminClient;
protected RemoteUserStoreManagerServiceClient remoteUSMServiceClient;
@@ -173,6 +175,35 @@ public ApplicationResponseModel addApplication() throws Exception {
return getApplication(appId);
}
+ public ApplicationResponseModel addApplicationWithGrantType(String grantType) throws Exception {
+
+ ApplicationModel application = new ApplicationModel();
+
+ List grantTypes = new ArrayList<>();
+ Collections.addAll(grantTypes, grantType);
+
+ List callBackUrls = new ArrayList<>();
+ Collections.addAll(callBackUrls, OAuth2Constant.CALLBACK_URL);
+
+ OpenIDConnectConfiguration oidcConfig = new OpenIDConnectConfiguration();
+ oidcConfig.setGrantTypes(grantTypes);
+ oidcConfig.setCallbackURLs(callBackUrls);
+ AccessTokenConfiguration accessTokenConfig = new AccessTokenConfiguration().type("JWT");
+ accessTokenConfig.setUserAccessTokenExpiryInSeconds(3600L);
+ accessTokenConfig.setApplicationAccessTokenExpiryInSeconds(3600L);
+ oidcConfig.setAccessToken(accessTokenConfig);
+
+ InboundProtocols inboundProtocolsConfig = new InboundProtocols();
+ inboundProtocolsConfig.setOidc(oidcConfig);
+
+ application.setInboundProtocolConfiguration(inboundProtocolsConfig);
+ application.setName(SERVICE_PROVIDER_NAME);
+ application.setIsManagementApp(true);
+ String appId = addApplication(application);
+
+ return getApplication(appId);
+ }
+
protected ClaimConfiguration setApplicationClaimConfig() {
ClaimMappings emailClaim = new ClaimMappings().applicationClaim(EMAIL_CLAIM_URI);
@@ -1078,4 +1109,90 @@ public String getRoleV2ResourceId(String roleName, String audienceType, String O
}
return null;
}
+
+ /**
+ * Create a domain API.
+ *
+ * @param domainAPICreationModel Domain API creation request model
+ * @return ID of the created Domain API
+ */
+ public String createDomainAPI(DomainAPICreationModel domainAPICreationModel) {
+
+ try {
+ return restClient.createDomainAPIResource(domainAPICreationModel);
+ } catch (Exception e) {
+ throw new RuntimeException("Error while creating domain API " +
+ domainAPICreationModel.getName());
+ }
+ }
+
+ /**
+ * Create a domain API with an external service integrated.
+ *
+ * @param externalServiceName Name of the external service to be integrated
+ * @param externalServiceURI URL of the external service
+ * @param domainScopes Custom scopes related to the domain API
+ * @return ID of the created domain API resource
+ */
+ public String createDomainAPI(String externalServiceName, String externalServiceURI,
+ List domainScopes) {
+
+ DomainAPICreationModel domainAPICreationModel = new DomainAPICreationModel();
+ domainAPICreationModel.setName(externalServiceName);
+ domainAPICreationModel.setIdentifier(externalServiceURI);
+ domainAPICreationModel.setDescription("This is a test external service");
+ domainAPICreationModel.setRequiresAuthorization(REQUIRES_AUTHORIZATION);
+ List newScopes = new ArrayList<>();
+ domainScopes.forEach(scope -> {
+ ScopeGetModel newCustomScope = new ScopeGetModel();
+ newCustomScope.setName(scope);
+ newCustomScope.setDescription("This is a test scope");
+ newCustomScope.setDisplayName(scope);
+ newScopes.add(newCustomScope);
+ });
+ domainAPICreationModel.setScopes(newScopes);
+ try {
+ return restClient.createDomainAPIResource(domainAPICreationModel);
+ } catch (Exception e) {
+ throw new RuntimeException("Error while creating domain API " +
+ domainAPICreationModel.getName());
+ }
+ }
+
+ /**
+ * Delete a domain API.
+ *
+ * @param domainAPIId ID of the domain API
+ * @return Status code of the domain API deletion
+ */
+ public int deleteDomainAPI(String domainAPIId) {
+
+ try {
+ return restClient.deleteDomainAPIResource(domainAPIId);
+ } catch (IOException e) {
+ throw new RuntimeException("Error while deleting domain API of Id " + domainAPIId);
+ }
+ }
+
+ /**
+ * Authorize a domain API to an application.
+ *
+ * @param applicationId ID of the application
+ * @param domainAPIId ID of the domain API to be authorized
+ * @param domainScopes Custom scopes related to the domain API
+ */
+ public void authorizeDomainAPIs(String applicationId, String domainAPIId, List domainScopes) {
+
+ AuthorizedAPICreationModel authorizedDomainAPICreationModel = new AuthorizedAPICreationModel();
+ authorizedDomainAPICreationModel.setId(domainAPIId);
+ authorizedDomainAPICreationModel.setPolicyIdentifier("RBAC");
+ authorizedDomainAPICreationModel.setScopes(domainScopes);
+ try {
+ restClient.addAPIAuthorizationToApplication(applicationId, authorizedDomainAPICreationModel);
+ } catch (Exception e) {
+ throw new RuntimeException("Error while authorizing domain API " +
+ authorizedDomainAPICreationModel.getId() +
+ " to application " + applicationId, e);
+ }
+ }
}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/model/AuthorizedDomainAPIResponse.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/model/AuthorizedDomainAPIResponse.java
new file mode 100644
index 0000000000..881d04d9c6
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/model/AuthorizedDomainAPIResponse.java
@@ -0,0 +1,168 @@
+/*
+ * 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.rest.api.server.application.management.v1.model;
+
+import org.wso2.identity.integration.test.rest.api.server.api.resource.v1.model.ScopeGetModel;
+
+import java.util.List;
+import java.util.Objects;
+
+public class AuthorizedDomainAPIResponse {
+
+ private String id;
+ private String name;
+ private String description;
+ private String identifier;
+ private String type;
+ private boolean requiresAuthorization;
+ private List scopes = null;
+ private List properties = null;
+
+ public String getId() {
+
+ return id;
+ }
+
+ public void setId(String id) {
+
+ this.id = id;
+ }
+
+ public String getName() {
+
+ return name;
+ }
+
+ public void setName(String name) {
+
+ this.name = name;
+ }
+
+ public String getDescription() {
+
+ return description;
+ }
+
+ public void setDescription(String description) {
+
+ this.description = description;
+ }
+
+ public String getIdentifier() {
+
+ return identifier;
+ }
+
+ public void setIdentifier(String identifier) {
+
+ this.identifier = identifier;
+ }
+
+ public String getType() {
+
+ return type;
+ }
+
+ public void setType(String type) {
+
+ this.type = type;
+ }
+
+ public boolean isRequiresAuthorization() {
+
+ return requiresAuthorization;
+ }
+
+ public void setRequiresAuthorization(boolean requiresAuthorization) {
+
+ this.requiresAuthorization = requiresAuthorization;
+ }
+
+ public List getScopes() {
+
+ return scopes;
+ }
+
+ public void setScopes(List scopes) {
+
+ this.scopes = scopes;
+ }
+
+ public List getProperties() {
+
+ return properties;
+ }
+
+ public void setProperties(List properties) {
+
+ this.properties = properties;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ AuthorizedDomainAPIResponse that = (AuthorizedDomainAPIResponse) o;
+ return requiresAuthorization == that.requiresAuthorization &&
+ Objects.equals(id, that.id) &&
+ Objects.equals(name, that.name) &&
+ Objects.equals(description, that.description) &&
+ Objects.equals(identifier, that.identifier) &&
+ Objects.equals(type, that.type) &&
+ Objects.equals(scopes, that.scopes) &&
+ Objects.equals(properties, that.properties);
+ }
+
+ @Override
+ public int hashCode() {
+
+ return Objects.hash(id, name, description, identifier, type, requiresAuthorization, scopes, properties);
+ }
+
+ @Override
+ public String toString() {
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("class AuthorizedDomainAPIResponse {\n");
+
+ sb.append(" id: ").append(toIndentedString(id)).append("\n");
+ sb.append(" name: ").append(toIndentedString(name)).append("\n");
+ sb.append(" description: ").append(toIndentedString(description)).append("\n");
+ sb.append(" identifier: ").append(toIndentedString(identifier)).append("\n");
+ sb.append(" type: ").append(toIndentedString(type)).append("\n");
+ sb.append(" requiresAuthorization: ").append(toIndentedString(requiresAuthorization)).append("\n");
+ sb.append(" scopes: ").append(toIndentedString(scopes)).append("\n");
+ sb.append(" properties: ").append(toIndentedString(properties)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ private String toIndentedString(Object o) {
+
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/model/DomainAPICreationModel.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/model/DomainAPICreationModel.java
new file mode 100644
index 0000000000..b6930aac26
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/rest/api/server/application/management/v1/model/DomainAPICreationModel.java
@@ -0,0 +1,133 @@
+/*
+ * 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.rest.api.server.application.management.v1.model;
+
+import org.wso2.identity.integration.test.rest.api.server.api.resource.v1.model.ScopeGetModel;
+
+import java.util.List;
+import java.util.Objects;
+
+public class DomainAPICreationModel {
+
+ private String name;
+ private String identifier;
+ private String description;
+ private boolean requiresAuthorization;
+ private List scopes = null;
+
+ public String getName() {
+
+ return name;
+ }
+
+ public void setName(String name) {
+
+ this.name = name;
+ }
+
+ public String getIdentifier() {
+
+ return identifier;
+ }
+
+ public void setIdentifier(String identifier) {
+
+ this.identifier = identifier;
+ }
+
+ public String getDescription() {
+
+ return description;
+ }
+
+ public void setDescription(String description) {
+
+ this.description = description;
+ }
+
+ public Boolean getRequiresAuthorization() {
+
+ return requiresAuthorization;
+ }
+
+ public void setRequiresAuthorization(Boolean requiresAuthorization) {
+
+ this.requiresAuthorization = requiresAuthorization;
+ }
+
+ public List getScopes() {
+
+ return scopes;
+ }
+
+ public void setScopes(List scopes) {
+
+ this.scopes = scopes;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ DomainAPICreationModel domainAPICreationModel = (DomainAPICreationModel) o;
+ return Objects.equals(this.name, domainAPICreationModel.name) &&
+ Objects.equals(this.description, domainAPICreationModel.description) &&
+ Objects.equals(this.identifier, domainAPICreationModel.identifier) &&
+ Objects.equals(this.requiresAuthorization, domainAPICreationModel.requiresAuthorization) &&
+ Objects.equals(this.scopes, domainAPICreationModel.scopes);
+ }
+
+ @Override
+ public int hashCode() {
+
+ return Objects.hash(name, description, identifier, requiresAuthorization, scopes);
+ }
+
+ @Override
+ public String toString() {
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("class DomainAPICreationModel {\n");
+
+ sb.append(" name: ").append(toIndentedString(name)).append("\n");
+ sb.append(" description: ").append(toIndentedString(description)).append("\n");
+ sb.append(" identifier: ").append(toIndentedString(identifier)).append("\n");
+ sb.append(" requiresAuthorization: ").append(toIndentedString(requiresAuthorization)).append("\n");
+ sb.append(" scopes: ").append(toIndentedString(scopes)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces
+ * (except the first line).
+ */
+ private String toIndentedString(Object o) {
+
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/ActionsRestClient.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/ActionsRestClient.java
new file mode 100644
index 0000000000..e2c47b0e7d
--- /dev/null
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/ActionsRestClient.java
@@ -0,0 +1,146 @@
+/*
+ * 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.restclients;
+
+import io.restassured.http.ContentType;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.Header;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.message.BasicHeader;
+import org.wso2.carbon.automation.engine.context.beans.Tenant;
+import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
+import org.wso2.identity.integration.test.rest.api.server.action.management.v1.model.ActionModel;
+import org.wso2.identity.integration.test.utils.OAuth2Constant;
+
+import java.io.IOException;
+
+/**
+ * Rest client which provides methods to interact with the Actions REST API.
+ * This client is responsible for managing actions of various types.
+ */
+public class ActionsRestClient extends RestBaseClient {
+
+ private static final String PRE_ISSUE_ACCESS_TOKEN_TYPE = "preIssueAccessToken";
+ private static final String ACTIONS_PATH = "/actions";
+ private static final String PRE_ISSUE_ACCESS_TOKEN_PATH = "/preIssueAccessToken";
+ private final String serverUrl;
+ private final String tenantDomain;
+ private final String username;
+ private final String password;
+ private final String actionsBasePath;
+
+ public ActionsRestClient(String serverUrl, Tenant tenantInfo) {
+
+ this.serverUrl = serverUrl;
+ this.tenantDomain = tenantInfo.getContextUser().getUserDomain();
+ this.username = tenantInfo.getContextUser().getUserName();
+ this.password = tenantInfo.getContextUser().getPassword();
+
+ actionsBasePath = getActionsPath(serverUrl, tenantDomain);
+ }
+
+ /**
+ * Create an action of the specified type.
+ *
+ * @param actionModel Request object to create the action
+ * @param actionType Type of the action
+ * @return Status code of the action creation
+ * @throws IOException If an error occurred while creating the action
+ */
+ public String createActionType(ActionModel actionModel, String actionType) throws IOException {
+
+ String jsonRequestBody = toJSONString(actionModel);
+
+ String endPointUrl;
+ endPointUrl = getActionEndpointOfType(actionType);
+
+ try (CloseableHttpResponse response = getResponseOfHttpPost(endPointUrl, jsonRequestBody, getHeaders())) {
+ String[] locationElements = response.getHeaders(LOCATION_HEADER)[0].toString().split(PATH_SEPARATOR);
+ return locationElements[locationElements.length - 1];
+ }
+ }
+
+ /**
+ * Delete an action of the specified type by the provided ID.
+ *
+ * @param actionType Type of action
+ * @param actionId ID of the action
+ * @return Status code of the action deletion
+ * @throws IOException If an error occurred while deleting the action
+ */
+ public int deleteActionType(String actionType, String actionId) throws IOException {
+
+ String endPointUrl;
+ endPointUrl = getActionEndpointOfType(actionType) + "/" + actionId;
+
+ try (CloseableHttpResponse response = getResponseOfHttpDelete(endPointUrl, getHeaders())) {
+ return response.getStatusLine().getStatusCode();
+ }
+ }
+
+ /**
+ * Retrieve the action endpoint according to the action type.
+ *
+ * @param actionType Type of action
+ * @return Action endpoint
+ */
+ private String getActionEndpointOfType(String actionType) {
+
+ switch (actionType) {
+ case PRE_ISSUE_ACCESS_TOKEN_TYPE:
+ return actionsBasePath + PRE_ISSUE_ACCESS_TOKEN_PATH;
+ default:
+ return StringUtils.EMPTY;
+ }
+ }
+
+ /**
+ * Get path of the action endpoint.
+ *
+ * @param serverUrl Server URL
+ * @param tenantDomain Tenant Domain
+ * @return Path of the action endpoint
+ */
+ private String getActionsPath(String serverUrl, String tenantDomain) {
+
+ if (tenantDomain.equals(MultitenantConstants.SUPER_TENANT_DOMAIN_NAME)) {
+ return serverUrl + API_SERVER_PATH + ACTIONS_PATH;
+ } else {
+ return serverUrl + TENANT_PATH + tenantDomain + PATH_SEPARATOR + API_SERVER_PATH +
+ ACTIONS_PATH;
+ }
+ }
+
+ /**
+ * Retrieve headers.
+ *
+ * @return An array of headers
+ */
+ private Header[] getHeaders() {
+
+ Header[] headerList = new Header[3];
+ headerList[0] = new BasicHeader(USER_AGENT_ATTRIBUTE, OAuth2Constant.USER_AGENT);
+ headerList[1] = new BasicHeader(AUTHORIZATION_ATTRIBUTE, BASIC_AUTHORIZATION_ATTRIBUTE +
+ Base64.encodeBase64String((username + ":" + password).getBytes()).trim());
+ headerList[2] = new BasicHeader(CONTENT_TYPE_ATTRIBUTE, String.valueOf(ContentType.JSON));
+
+ return headerList;
+ }
+}
diff --git a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java
index c88855ca45..914083d0ca 100644
--- a/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java
+++ b/modules/integration/tests-integration/tests-backend/src/test/java/org/wso2/identity/integration/test/restclients/OAuth2RestClient.java
@@ -39,10 +39,12 @@
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationListItem;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationListResponse;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationModel;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.DomainAPICreationModel;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.ApplicationPatchModel;
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.ApplicationSharePOSTRequest;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.AuthorizedAPICreationModel;
+import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.AuthorizedDomainAPIResponse;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.OpenIDConnectConfiguration;
import org.wso2.identity.integration.test.rest.api.server.application.management.v1.model.SAML2ServiceProvider;
import org.wso2.identity.integration.test.rest.api.server.roles.v2.model.RoleV2;
@@ -52,6 +54,7 @@
import java.io.IOException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -486,6 +489,39 @@ public List getAPIResourceScopes(String apiIdentifier) throws IOE
}
}
+ /**
+ * Creates a domain API.
+ *
+ * @param domainAPICreationModel Domain API create request model
+ * @return ID of the created domain API resource
+ */
+ public String createDomainAPIResource(DomainAPICreationModel domainAPICreationModel) throws IOException {
+
+ String jsonRequestBody = toJSONString(domainAPICreationModel);
+
+ try (CloseableHttpResponse response = getResponseOfHttpPost(apiResourceManagementApiBasePath, jsonRequestBody,
+ getHeaders())) {
+ String[] locationElements = response.getHeaders(LOCATION_HEADER)[0].toString().split(PATH_SEPARATOR);
+ return locationElements[locationElements.length - 1];
+ }
+ }
+
+ /**
+ * Deletes a domain API.
+ *
+ * @param domainAPIId ID of the domain API to be deleted
+ * @return Status code of the action creation
+ * @throws IOException If an error occurred while deleting the domain API
+ */
+ public int deleteDomainAPIResource(String domainAPIId) throws IOException {
+
+ String endpointUrl = apiResourceManagementApiBasePath + "/" + domainAPIId;
+
+ try (CloseableHttpResponse response = getResponseOfHttpDelete(endpointUrl, getHeaders())) {
+ return response.getStatusLine().getStatusCode();
+ }
+ }
+
public List getRoles(String roleName, String audienceType, String audienceId) throws Exception {
String endPointUrl = buildRoleSearchEndpoint(roleName, audienceType, audienceId);
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 6dd7f4df98..fd48b6b588 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
@@ -136,6 +136,7 @@
+
diff --git a/pom.xml b/pom.xml
index 4abe5fb379..1e3faec6f9 100755
--- a/pom.xml
+++ b/pom.xml
@@ -2059,6 +2059,18 @@
${rest.assured.version}
test
+
+ org.wiremock
+ wiremock
+ ${wiremock.version}
+ test
+
+
+ org.yaml
+ snakeyaml
+ ${snakeyaml.version}
+ test
+
io.swagger
swagger-annotations
@@ -2561,6 +2573,8 @@
6.13
2.0.0.AM26
2.0.0.AM4
+ 3.9.1
+ 2.2
5.0.0
1.5.22