diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/pom.xml b/components/action-mgt/org.wso2.carbon.identity.action.execution/pom.xml
index f2c63a12284a..42f55775c818 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.execution/pom.xml
+++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.framework
action-mgt
- 7.6.10-SNAPSHOT
+ 7.7.63-SNAPSHOT
../pom.xml
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImpl.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImpl.java
index 94e054d0fecf..d4c1ffc4eee8 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImpl.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImpl.java
@@ -114,13 +114,10 @@ public ActionExecutionStatus> execute(ActionType actionType, Map execute(ActionType actionType, String[] actionId
validateActionIdList(actionType, actionIdList);
Action action = getActionByActionId(actionType, actionIdList[0], tenantDomain);
- DIAGNOSTIC_LOGGER.logActionInitiation(action);
try {
return execute(action, eventContext);
} catch (ActionExecutionRuntimeException e) {
- DIAGNOSTIC_LOGGER.logSkippedActionExecution(actionType);
LOG.debug("Skip executing actions for action type: " + actionType.name(), e);
- // Skip executing actions when no action available or due to a failure in retrieving actions,
- // is considered as action execution being successful.
+ // Skip executing actions when no action available is considered as action execution being successful.
return new SuccessStatus.Builder().setResponseContext(eventContext).build();
}
}
@@ -172,6 +166,7 @@ private ActionExecutionStatus> execute(Action action, Map even
ActionExecutionResponseProcessor actionExecutionResponseProcessor = getResponseProcessor(actionType);
if (action.getStatus() == Action.Status.ACTIVE) {
+ DIAGNOSTIC_LOGGER.logActionInitiation(action);
return executeAction(action, actionRequest, eventContext, actionExecutionResponseProcessor);
} else {
// If no active actions are detected, it is regarded as the action execution being successful.
@@ -191,13 +186,13 @@ private Action getActionByActionId(ActionType actionType, String actionId, Strin
}
private List getActionsByActionType(ActionType actionType, String tenantDomain) throws
- ActionExecutionRuntimeException {
+ ActionExecutionException {
try {
return ActionExecutionServiceComponentHolder.getInstance().getActionManagementService()
.getActionsByActionType(Action.ActionTypes.valueOf(actionType.name()).getPathParam(), tenantDomain);
} catch (ActionMgtException e) {
- throw new ActionExecutionRuntimeException("Error occurred while retrieving actions.", e);
+ throw new ActionExecutionException("Error occurred while retrieving actions.", e);
}
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java
index 02e3efc2a81d..94c1e40a3719 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponent.java
@@ -34,7 +34,7 @@
import org.wso2.carbon.identity.action.execution.impl.ActionExecutionRequestBuilderFactory;
import org.wso2.carbon.identity.action.execution.impl.ActionExecutionResponseProcessorFactory;
import org.wso2.carbon.identity.action.execution.impl.ActionExecutorServiceImpl;
-import org.wso2.carbon.identity.action.management.ActionManagementService;
+import org.wso2.carbon.identity.action.management.service.ActionManagementService;
/**
* OSGI service component for the Action execution.
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponentHolder.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponentHolder.java
index 83be753ef413..8163a538354a 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponentHolder.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/internal/ActionExecutionServiceComponentHolder.java
@@ -18,7 +18,7 @@
package org.wso2.carbon.identity.action.execution.internal;
-import org.wso2.carbon.identity.action.management.ActionManagementService;
+import org.wso2.carbon.identity.action.management.service.ActionManagementService;
/**
* This class holds references for dependent services required for Action Execution Service to function.
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/ActionExecutionDiagnosticLogger.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/ActionExecutionDiagnosticLogger.java
index 31a2f9c45cfd..4b3f750de2d7 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/ActionExecutionDiagnosticLogger.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/main/java/org/wso2/carbon/identity/action/execution/util/ActionExecutionDiagnosticLogger.java
@@ -21,7 +21,6 @@
import org.apache.http.client.methods.HttpPost;
import org.wso2.carbon.identity.action.execution.ActionExecutionLogConstants;
import org.wso2.carbon.identity.action.execution.model.ActionInvocationResponse;
-import org.wso2.carbon.identity.action.execution.model.ActionType;
import org.wso2.carbon.identity.action.management.model.Action;
import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils;
import org.wso2.carbon.utils.DiagnosticLog;
@@ -47,19 +46,6 @@ public void logActionInitiation(Action action) {
DiagnosticLog.ResultStatus.SUCCESS));
}
- public void logSkippedActionExecution(ActionType actionType) {
-
- if (!LoggerUtils.isDiagnosticLogsEnabled()) {
- return;
- }
-
- triggerLogEvent(
- initializeDiagnosticLogBuilder(
- ActionExecutionLogConstants.ActionIDs.EXECUTE_ACTION,
- "Skip executing action for " + actionType + " type.",
- DiagnosticLog.ResultStatus.FAILED));
- }
-
public void logActionRequest(Action action) {
if (!LoggerUtils.isDiagnosticLogsEnabled()) {
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java
index 5f1ece8a0c9e..f3414560a6e3 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.execution/src/test/java/org/wso2/carbon/identity/action/execution/impl/ActionExecutorServiceImplTest.java
@@ -60,11 +60,11 @@
import org.wso2.carbon.identity.action.execution.util.ActionExecutionDiagnosticLogger;
import org.wso2.carbon.identity.action.execution.util.ActionExecutorConfig;
import org.wso2.carbon.identity.action.execution.util.RequestFilter;
-import org.wso2.carbon.identity.action.management.ActionManagementService;
import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
import org.wso2.carbon.identity.action.management.model.Action;
import org.wso2.carbon.identity.action.management.model.Authentication;
import org.wso2.carbon.identity.action.management.model.EndpointConfig;
+import org.wso2.carbon.identity.action.management.service.ActionManagementService;
import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils;
import java.lang.reflect.Field;
@@ -230,6 +230,16 @@ public void testActionExecuteWithActionIdFailureWhenInvalidActionIdGiven() throw
actionExecutorService.execute(ActionType.PRE_ISSUE_ACCESS_TOKEN, new String[]{any()}, any(), any());
}
+ @Test(expectedExceptions = ActionExecutionException.class,
+ expectedExceptionsMessageRegExp = "Error occurred while retrieving actions.")
+ public void testActionExecuteWithActionFailureWhenInvalidActionGiven() throws Exception {
+
+ when(actionManagementService.getActionsByActionType(any(), any())).thenThrow(
+ new ActionMgtException("Error occurred while retrieving actions."));
+
+ actionExecutorService.execute(ActionType.PRE_ISSUE_ACCESS_TOKEN, any(), any());
+ }
+
@Test(expectedExceptions = ActionExecutionException.class,
expectedExceptionsMessageRegExp = "Failed to build the request payload for action type: " +
"PRE_ISSUE_ACCESS_TOKEN")
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/pom.xml b/components/action-mgt/org.wso2.carbon.identity.action.management/pom.xml
index 80cc06b93d9e..70c6ff373c9b 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/pom.xml
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/pom.xml
@@ -22,7 +22,7 @@
org.wso2.carbon.identity.framework
action-mgt
- 7.6.10-SNAPSHOT
+ 7.7.63-SNAPSHOT
../pom.xml
@@ -41,6 +41,10 @@
org.wso2.carbon.identity.framework
org.wso2.carbon.identity.secret.mgt.core
+
+ org.wso2.carbon.identity.framework
+ org.wso2.carbon.identity.certificate.management
+
org.json.wso2
json
@@ -54,6 +58,7 @@
org.mockito
mockito-core
+ test
org.wso2.carbon.identity.framework
@@ -84,19 +89,18 @@
${project.artifactId}
+ org.wso2.carbon.identity.action.management.constant,
+ org.wso2.carbon.identity.action.management.dao.*,
org.wso2.carbon.identity.action.management.internal,
- org.wso2.carbon.identity.action.management.cache,
- org.wso2.carbon.identity.action.management.dao,
- org.wso2.carbon.identity.action.management.dao.impl,
+ org.wso2.carbon.identity.action.management.service.impl,
org.wso2.carbon.identity.action.management.util
- !org.wso2.carbon.identity.action.management.internal,
- !org.wso2.carbon.identity.action.management.cache,
- !org.wso2.carbon.identity.action.management.dao,
- !org.wso2.carbon.identity.action.management.dao.impl,
- !org.wso2.carbon.identity.action.management.util,
- org.wso2.carbon.identity.action.management.*; version="${carbon.identity.package.export.version}"
+ org.wso2.carbon.identity.action.management.cache,
+ org.wso2.carbon.identity.action.management.constant.error,
+ org.wso2.carbon.identity.action.management.exception,
+ org.wso2.carbon.identity.action.management.model,
+ org.wso2.carbon.identity.action.management.service; version="${carbon.identity.package.export.version}"
org.apache.commons.lang; version="${commons-lang.wso2.osgi.version.range}",
@@ -175,16 +179,11 @@
LINE
COVEREDRATIO
-
- 0.70
+ 0.80
COMPLEXITY
COVEREDRATIO
-
0.60
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/cache/ActionCacheEntry.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/cache/ActionCacheEntry.java
index 4ed821e43765..cec36a14b47a 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/cache/ActionCacheEntry.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/cache/ActionCacheEntry.java
@@ -28,6 +28,7 @@
*/
public class ActionCacheEntry extends CacheEntry {
+ private static final long serialVersionUID = 2789265346825849739L;
private List actionsOfActionType;
public ActionCacheEntry(List actionsOfActionType) {
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/cache/ActionTypeCacheKey.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/cache/ActionTypeCacheKey.java
index 98fd51cf3dfc..76609a0e866d 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/cache/ActionTypeCacheKey.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/cache/ActionTypeCacheKey.java
@@ -25,6 +25,7 @@
*/
public class ActionTypeCacheKey extends CacheKey {
+ private static final long serialVersionUID = 8132735629148475983L;
private final String actionType;
public ActionTypeCacheKey(String actionType) {
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtConstants.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtConstants.java
index 5eff6fda6669..9da7b6b3f5c3 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtConstants.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtConstants.java
@@ -23,8 +23,8 @@
*/
public class ActionMgtConstants {
- public static final String URI_ATTRIBUTE = "uri";
- public static final String AUTHN_TYPE_ATTRIBUTE = "authnType";
+ public static final String URI_PROPERTY = "uri";
+ public static final String AUTHN_TYPE_PROPERTY = "authnType";
public static final String IDN_SECRET_TYPE_ACTION_SECRETS = "ACTION_API_ENDPOINT_AUTH_SECRETS";
public static final String ACTION_NAME_FIELD = "Action name";
@@ -36,84 +36,6 @@ public class ActionMgtConstants {
public static final String API_KEY_HEADER_FIELD = "API key header name";
public static final String API_KEY_VALUE_FIELD = "API key value";
- /**
- * Error messages.
- */
- public enum ErrorMessages {
-
- // Client errors.
- ERROR_INVALID_ACTION_TYPE("60001", "Invalid action type.",
- "Invalid action type used for path parameter."),
- ERROR_MAXIMUM_ACTIONS_PER_ACTION_TYPE_REACHED("60002", "Unable to create an Action.",
- "Maximum number of actions per action type is reached."),
- ERROR_NO_ACTION_CONFIGURED_ON_GIVEN_ACTION_TYPE_AND_ID("60003",
- "Unable to perform the operation.",
- "No Action is configured on the given Action Type and Id."),
- ERROR_EMPTY_ACTION_REQUEST_FIELD("60004", "Invalid request.",
- "%s is empty."),
- ERROR_INVALID_ACTION_REQUEST_FIELD("60005", "Invalid request.",
- "%s is invalid."),
-
- // Server errors.
- ERROR_WHILE_ADDING_ACTION("65001", "Error while adding Action.",
- "Error while persisting Action in the system."),
- ERROR_WHILE_ADDING_ENDPOINT_PROPERTIES("65002", "Error while adding Endpoint properties",
- "Error while persisting Action Endpoint properties in the system."),
- ERROR_WHILE_RETRIEVING_ACTION_ENDPOINT_PROPERTIES("65003",
- "Error while retrieving Action Endpoint properties",
- "Error while retrieving Action Endpoint properties from the system."),
- ERROR_WHILE_RETRIEVING_ACTIONS_BY_ACTION_TYPE("65004",
- "Error while retrieving Actions by Action Type",
- "Error while retrieving Actions by Action Type from the system."),
- ERROR_WHILE_UPDATING_ENDPOINT_PROPERTIES("65005",
- "Error while updating Action Endpoint properties",
- "Error while updating Action Endpoint properties in the system."),
- ERROR_WHILE_UPDATING_ACTION("65006", "Error while updating Action.",
- "Error while updating Action in the system."),
- ERROR_WHILE_DELETING_ACTION("65007", "Error while deleting Action.",
- "Error while deleting Action from the system."),
- ERROR_WHILE_UPDATING_ACTION_STATUS("65008", "Error while updating Action status.",
- "Error while updating Action status in the system."),
- ERROR_WHILE_RETRIEVING_ACTION_BY_ID("65009", "Error while retrieving Action by ID.",
- "Error while retrieving Action from the system."),
- ERROR_WHILE_RETRIEVING_ACTIONS_COUNT_PER_TYPE("65010",
- "Error while retrieving count of Actions per Action Type.",
- "Error while retrieving count of Actions per Action Type from the system."),
- ERROR_WHILE_RETRIEVING_ACTION_BASIC_INFO("65011", "Error while retrieving Action basic info.",
- "Error while retrieving Action basic info from the system."),
- ERROR_WHILE_DECRYPTING_ACTION_ENDPOINT_AUTH_PROPERTIES("65012",
- "Error while decrypting Action Endpoint Authentication properties",
- "Error while decrypting Action Endpoint Authentication properties in the system."),
- ERROR_NO_AUTHENTICATION_TYPE("65013",
- "Error while retrieving Action Endpoint Authentication configurations",
- "Authentication type is not defined for the Action Endpoint."),
- ERROR_WHILE_UPDATING_ACTION_BASIC_INFO("65014", "Error while updating basic Action information",
- "Error while updating basic Action information in the system.");
-
- private final String code;
- private final String message;
- private final String description;
-
- ErrorMessages(String code, String message, String description) {
-
- this.code = code;
- this.message = message;
- this.description = description;
- }
-
- public String getCode() {
-
- return code;
- }
-
- public String getMessage() {
-
- return message;
- }
-
- public String getDescription() {
-
- return description;
- }
+ private ActionMgtConstants() {
}
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtSQLConstants.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtSQLConstants.java
index b41fb5282228..8f6ae2c77200 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtSQLConstants.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/ActionMgtSQLConstants.java
@@ -38,9 +38,9 @@ public static class Column {
public static final String ACTION_DESCRIPTION = "DESCRIPTION";
public static final String ACTION_STATUS = "STATUS";
public static final String ACTION_COUNT = "COUNT";
- public static final String ACTION_ENDPOINT_UUID = "ACTION_UUID";
- public static final String ACTION_ENDPOINT_PROPERTY_NAME = "PROPERTY_NAME";
- public static final String ACTION_ENDPOINT_PROPERTY_VALUE = "PROPERTY_VALUE";
+ public static final String ACTION_PROPERTIES_UUID = "ACTION_UUID";
+ public static final String ACTION_PROPERTIES_PROPERTY_NAME = "PROPERTY_NAME";
+ public static final String ACTION_PROPERTIES_PROPERTY_VALUE = "PROPERTY_VALUE";
public static final String TENANT_ID = "TENANT_ID";
private Column() {
@@ -55,26 +55,26 @@ public static class Query {
public static final String ADD_ACTION_TO_ACTION_TYPE = "INSERT INTO IDN_ACTION (UUID, TYPE, NAME, " +
"DESCRIPTION, STATUS, TENANT_ID) VALUES (:UUID;, :TYPE;, :NAME;, :DESCRIPTION;, :STATUS;, :TENANT_ID;)";
- public static final String ADD_ACTION_ENDPOINT_PROPERTIES = "INSERT INTO IDN_ACTION_ENDPOINT (ACTION_UUID, " +
+ public static final String ADD_ACTION_PROPERTIES = "INSERT INTO IDN_ACTION_PROPERTIES (ACTION_UUID, " +
"PROPERTY_NAME, PROPERTY_VALUE, TENANT_ID) VALUES (:ACTION_UUID;, :PROPERTY_NAME;, :PROPERTY_VALUE;, " +
":TENANT_ID;)";
public static final String GET_ACTION_BASIC_INFO_BY_ID = "SELECT TYPE, NAME, DESCRIPTION, STATUS FROM " +
"IDN_ACTION WHERE TYPE = :TYPE; AND UUID = :UUID; AND TENANT_ID = :TENANT_ID;";
- public static final String GET_ACTION_ENDPOINT_INFO_BY_ID = "SELECT PROPERTY_NAME, PROPERTY_VALUE FROM " +
- "IDN_ACTION_ENDPOINT WHERE ACTION_UUID = :ACTION_UUID; AND TENANT_ID = :TENANT_ID;";
+ public static final String GET_ACTION_PROPERTIES_INFO_BY_ID = "SELECT PROPERTY_NAME, PROPERTY_VALUE FROM " +
+ "IDN_ACTION_PROPERTIES WHERE ACTION_UUID = :ACTION_UUID; AND TENANT_ID = :TENANT_ID;";
public static final String GET_ACTIONS_BASIC_INFO_BY_ACTION_TYPE = "SELECT UUID, TYPE, NAME, DESCRIPTION," +
" STATUS FROM IDN_ACTION WHERE TYPE = :TYPE; AND TENANT_ID = :TENANT_ID;";
public static final String UPDATE_ACTION_BASIC_INFO = "UPDATE IDN_ACTION SET NAME = :NAME;, DESCRIPTION = " +
":DESCRIPTION; WHERE UUID = :UUID; AND TYPE = :TYPE; AND TENANT_ID = :TENANT_ID;";
- public static final String DELETE_ACTION_ENDPOINT_PROPERTIES = "DELETE FROM IDN_ACTION_ENDPOINT WHERE " +
- "ACTION_UUID = :ACTION_UUID; AND TENANT_ID = :TENANT_ID;";
+ public static final String DELETE_ACTION_PROPERTY = "DELETE FROM IDN_ACTION_PROPERTIES WHERE " +
+ "PROPERTY_NAME = :PROPERTY_NAME; AND ACTION_UUID = :ACTION_UUID; AND TENANT_ID = :TENANT_ID;";
public static final String DELETE_ACTION = "DELETE FROM IDN_ACTION WHERE UUID = :UUID; AND TYPE = :TYPE;" +
" AND TENANT_ID = :TENANT_ID;";
public static final String CHANGE_ACTION_STATUS = "UPDATE IDN_ACTION SET STATUS = :STATUS; WHERE UUID = " +
":UUID; AND TYPE = :TYPE; AND TENANT_ID = :TENANT_ID;";
public static final String GET_ACTIONS_COUNT_PER_ACTION_TYPE = "SELECT TYPE, COUNT(UUID) AS COUNT" +
" FROM IDN_ACTION WHERE TENANT_ID = :TENANT_ID; GROUP BY TYPE";
- public static final String UPDATE_ACTION_ENDPOINT_PROPERTIES = "UPDATE IDN_ACTION_ENDPOINT SET " +
+ public static final String UPDATE_ACTION_PROPERTY = "UPDATE IDN_ACTION_PROPERTIES SET " +
"PROPERTY_VALUE = :PROPERTY_VALUE; WHERE ACTION_UUID = :ACTION_UUID; AND " +
"TENANT_ID = :TENANT_ID; AND PROPERTY_NAME = :PROPERTY_NAME;";
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/error/ErrorMessage.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/error/ErrorMessage.java
new file mode 100644
index 000000000000..f13e723d0110
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/constant/error/ErrorMessage.java
@@ -0,0 +1,85 @@
+/*
+ * 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.carbon.identity.action.management.constant.error;
+
+/**
+ * Error messages.
+ */
+public enum ErrorMessage {
+
+ // Client errors.
+ ERROR_INVALID_ACTION_TYPE("60001", "Invalid action type.",
+ "Invalid action type used for path parameter."),
+ ERROR_MAXIMUM_ACTIONS_PER_ACTION_TYPE_REACHED("60002", "Unable to create an Action.",
+ "Maximum number of actions per action type is reached."),
+ ERROR_NO_ACTION_CONFIGURED_ON_GIVEN_ACTION_TYPE_AND_ID("60003", "Unable to perform the operation.",
+ "No Action is configured on the given Action Type and Id."),
+ ERROR_EMPTY_ACTION_REQUEST_FIELD("60004", "Invalid request.", "%s is empty."),
+ ERROR_INVALID_ACTION_REQUEST_FIELD("60005", "Invalid request.", "%s is invalid."),
+ ERROR_INVALID_ACTION_PROPERTIES("60006", "Provided Action Properties are invalid.", "%s"),
+
+ // Server errors.
+ ERROR_WHILE_ADDING_ACTION("65001", "Error while adding Action.",
+ "Error while persisting Action in the system."),
+ ERROR_WHILE_RETRIEVING_ACTIONS_BY_ACTION_TYPE("65002",
+ "Error while retrieving Actions by Action Type",
+ "Error while retrieving Actions by Action Type from the system."),
+ ERROR_WHILE_RETRIEVING_ACTION_BY_ID("65003", "Error while retrieving Action by ID.",
+ "Error while retrieving Action from the system."),
+ ERROR_WHILE_UPDATING_ACTION("65004", "Error while updating Action.",
+ "Error while updating Action in the system."),
+ ERROR_WHILE_DELETING_ACTION("65005", "Error while deleting Action.",
+ "Error while deleting Action from the system."),
+ ERROR_WHILE_ACTIVATING_ACTION("65006", "Error while activating Action.",
+ "Error while updating Action status to ACTIVE."),
+ ERROR_WHILE_DEACTIVATING_ACTION("65007", "Error while deactivating Action.",
+ "Error while updating Action status to INACTIVE."),
+ ERROR_WHILE_RETRIEVING_ACTIONS_COUNT_PER_TYPE("65008",
+ "Error while retrieving count of Actions per Action Type.",
+ "Error while retrieving count of Actions per Action Type from the system."),
+ ERROR_WHILE_DECRYPTING_ACTION_ENDPOINT_AUTH_PROPERTIES("65009",
+ "Error while decrypting Action Endpoint Authentication properties",
+ "Error while decrypting Action Endpoint Authentication properties in the system.");
+
+ private final String code;
+ private final String message;
+ private final String description;
+
+ ErrorMessage(String code, String message, String description) {
+
+ this.code = code;
+ this.message = message;
+ this.description = description;
+ }
+
+ public String getCode() {
+
+ return code;
+ }
+
+ public String getMessage() {
+
+ return message;
+ }
+
+ public String getDescription() {
+
+ return description;
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAO.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAO.java
index 9def55c4247b..d61a94d5932d 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAO.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAO.java
@@ -19,29 +19,24 @@
package org.wso2.carbon.identity.action.management.dao;
import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
-import org.wso2.carbon.identity.action.management.model.Action;
-import org.wso2.carbon.identity.action.management.model.Authentication;
-import org.wso2.carbon.identity.action.management.model.EndpointConfig;
+import org.wso2.carbon.identity.action.management.model.ActionDTO;
import java.util.List;
import java.util.Map;
/**
- * This interface performs CRUD operations for {@link Action}.
+ * This interface performs CRUD operations for {@link ActionDTO}.
*/
public interface ActionManagementDAO {
/**
- * Create a new {@link Action}.
+ * Create a new {@link ActionDTO}.
*
- * @param actionType Action Type.
- * @param actionId Action Id.
- * @param action Action creation model.
- * @param tenantId Tenant Id.
- * @return Created Action
.
+ * @param actionDTO Action creation model.
+ * @param tenantId Tenant Id.
* @throws ActionMgtException If an error occurs while adding the Action.
*/
- Action addAction(String actionType, String actionId, Action action, Integer tenantId) throws ActionMgtException;
+ void addAction(ActionDTO actionDTO, Integer tenantId) throws ActionMgtException;
/**
* Retrieve the Actions configured for the given type.
@@ -51,46 +46,51 @@ public interface ActionManagementDAO {
* @return List of Action
.
* @throws ActionMgtException If an error occurs while retrieving the Actions of a given Action Type.
*/
- List getActionsByActionType(String actionType, Integer tenantId) throws ActionMgtException;
+ List getActionsByActionType(String actionType, Integer tenantId) throws ActionMgtException;
/**
- * Update {@link Action} by given Action type and Action ID.
+ * Get {@link ActionDTO} of a given Action Type and Action ID.
*
- * @param actionType Action Type.
- * @param actionId Action ID.
- * @param updatingAction Action update model.
- * @param existingAction Existing Action.
- * @param tenantId Tenant Id.
- * @return Updated Action
.
+ * @param actionId Action ID.
+ * @param tenantId Tenant Id.
+ * @return Action
.
+ * @throws ActionMgtException If an error occurs while retrieving the Action of a given Action ID.
+ */
+ ActionDTO getActionByActionId(String actionType, String actionId, Integer tenantId) throws ActionMgtException;
+
+ /**
+ * Update {@link ActionDTO} by given Action type and Action ID.
+ *
+ * @param updatingActionDTO Action update model.
+ * @param existingActionDTO Existing Action.
+ * @param tenantId Tenant Id.
* @throws ActionMgtException If an error occurs while updating the Action.
*/
- Action updateAction(String actionType, String actionId, Action updatingAction, Action existingAction,
- Integer tenantId) throws ActionMgtException;
+ void updateAction(ActionDTO updatingActionDTO, ActionDTO existingActionDTO, Integer tenantId)
+ throws ActionMgtException;
/**
- * Delete {@link Action} by given Action Type.
+ * Delete {@link ActionDTO} by given Action Type.
*
- * @param actionType Action Type.
- * @param actionId Action Id.
- * @param action Action to be deleted.
- * @param tenantId Tenant Id.
+ * @param deletingActionDTO Action to be deleted.
+ * @param tenantId Tenant Id.
* @throws ActionMgtException If an error occurs while deleting Action.
*/
- void deleteAction(String actionType, String actionId, Action action, Integer tenantId) throws ActionMgtException;
+ void deleteAction(ActionDTO deletingActionDTO, Integer tenantId) throws ActionMgtException;
/**
- * Activate {@link Action} by given Action Type and Action ID.
+ * Activate {@link org.wso2.carbon.identity.action.management.model.Action} by given Action Type and Action ID.
*
- * @param actionType Action Type.
- * @param actionId Action ID.
+ * @param actionType Action Type.
+ * @param actionId Action ID.
* @param tenantId Tenant Id.
* @return Activated Action
.
* @throws ActionMgtException If an error occurs while activating the Action.
*/
- Action activateAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException;
+ ActionDTO activateAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException;
/**
- * Deactivate {@link Action} by given Action Type and Action ID.
+ * Deactivate {@link org.wso2.carbon.identity.action.management.model.Action} by given Action Type and Action ID.
*
* @param actionType Action Type.
* @param actionId Action ID.
@@ -98,7 +98,7 @@ Action updateAction(String actionType, String actionId, Action updatingAction, A
* @return Deactivated Action
.
* @throws ActionMgtException If an error occurs while deactivating the Action.
*/
- Action deactivateAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException;
+ ActionDTO deactivateAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException;
/**
* Get Actions count per Action Type.
@@ -108,40 +108,4 @@ Action updateAction(String actionType, String actionId, Action updatingAction, A
* @throws ActionMgtException If an error occurs while retrieving the Actions count.
*/
Map getActionsCountPerType(Integer tenantId) throws ActionMgtException;
-
- /**
- * Get {@link Action} of a given Action Type and Action ID.
- *
- * @param actionId Action ID.
- * @param tenantId Tenant Id.
- * @return Action
.
- * @throws ActionMgtException If an error occurs while retrieving the Action of a given Action ID.
- */
- Action getActionByActionId(String actionType, String actionId, Integer tenantId) throws ActionMgtException;
-
- /**
- * Update the endpoint authentication properties of an {@link Action} by given Action ID.
- *
- * @param actionId Action ID.
- * @param authentication Authentication information to be updated.
- * @param tenantId Tenant Id.
- * @return Updated Action
.
- * @throws ActionMgtException If an error occurs while updating the Action endpoint authentication properties.
- */
- Action updateActionEndpointAuthProperties(String actionType, String actionId, Authentication authentication,
- int tenantId) throws ActionMgtException;
-
- /**
- * Update the endpoint authentication properties of an {@link Action} by given Action ID.
- *
- * @param actionType Action Type.
- * @param actionId Action ID.
- * @param endpoint Endpoint information to be updated.
- * @param currentAuthentication Current Action endpoint authentication information.
- * @param tenantId Tenant Id.
- * @return Updated Action
.
- * @throws ActionMgtException If an error occurs while updating the Action endpoint.
- */
- Action updateActionEndpoint(String actionType, String actionId, EndpointConfig endpoint,
- Authentication currentAuthentication, int tenantId) throws ActionMgtException;
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionDTOModelResolverFactory.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionDTOModelResolverFactory.java
new file mode 100644
index 000000000000..be9285259a11
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionDTOModelResolverFactory.java
@@ -0,0 +1,61 @@
+/*
+ * 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.carbon.identity.action.management.dao.impl;
+
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.service.ActionDTOModelResolver;
+
+import java.util.EnumMap;
+import java.util.Map;
+
+/**
+ * This class defines the ActionDTO Model Resolver Factory.
+ * ActionDTO Model Resolver Factory is the component that is responsible for providing the
+ * {@link ActionDTOModelResolver} based on the action type.
+ */
+public class ActionDTOModelResolverFactory {
+
+ private static final Map actionDTOModelResolvers =
+ new EnumMap<>(Action.ActionTypes.class);
+
+ private ActionDTOModelResolverFactory() {
+ }
+
+ public static ActionDTOModelResolver getActionDTOModelResolver(Action.ActionTypes actionType) {
+
+ switch (actionType) {
+ case PRE_UPDATE_PASSWORD:
+ return actionDTOModelResolvers.get(Action.ActionTypes.PRE_UPDATE_PASSWORD);
+ case PRE_ISSUE_ACCESS_TOKEN:
+ return actionDTOModelResolvers.get(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN);
+ default:
+ return null;
+ }
+ }
+
+ public static void registerActionDTOModelResolver(ActionDTOModelResolver actionDTOModelResolver) {
+
+ actionDTOModelResolvers.put(actionDTOModelResolver.getSupportedActionType(), actionDTOModelResolver);
+ }
+
+ public static void unregisterActionDTOModelResolver(ActionDTOModelResolver actionDTOModelResolver) {
+
+ actionDTOModelResolvers.remove(actionDTOModelResolver.getSupportedActionType());
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOFacade.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOFacade.java
new file mode 100644
index 000000000000..76ca02ba9aea
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOFacade.java
@@ -0,0 +1,418 @@
+/*
+ * 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.carbon.identity.action.management.dao.impl;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.database.utils.jdbc.NamedJdbcTemplate;
+import org.wso2.carbon.database.utils.jdbc.exceptions.TransactionException;
+import org.wso2.carbon.identity.action.management.constant.error.ErrorMessage;
+import org.wso2.carbon.identity.action.management.dao.ActionManagementDAO;
+import org.wso2.carbon.identity.action.management.exception.ActionDTOModelResolverClientException;
+import org.wso2.carbon.identity.action.management.exception.ActionDTOModelResolverException;
+import org.wso2.carbon.identity.action.management.exception.ActionMgtClientException;
+import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
+import org.wso2.carbon.identity.action.management.exception.ActionMgtServerException;
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.ActionDTO;
+import org.wso2.carbon.identity.action.management.model.AuthProperty;
+import org.wso2.carbon.identity.action.management.model.Authentication;
+import org.wso2.carbon.identity.action.management.model.EndpointConfig;
+import org.wso2.carbon.identity.action.management.service.ActionDTOModelResolver;
+import org.wso2.carbon.identity.action.management.util.ActionDTOBuilder;
+import org.wso2.carbon.identity.action.management.util.ActionManagementExceptionHandler;
+import org.wso2.carbon.identity.action.management.util.ActionSecretProcessor;
+import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil;
+import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
+import org.wso2.carbon.identity.secret.mgt.core.exception.SecretManagementException;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Facade class for Action Management DAO.
+ * ActionManagementDAOFacade is responsible for handling external service integrations.
+ */
+public class ActionManagementDAOFacade implements ActionManagementDAO {
+
+ private static final Log LOG = LogFactory.getLog(ActionManagementDAOFacade.class);
+
+ private final ActionManagementDAO actionManagementDAO;
+ private final ActionSecretProcessor actionSecretProcessor;
+
+ public ActionManagementDAOFacade(ActionManagementDAO actionManagementDAO) {
+
+ this.actionManagementDAO = actionManagementDAO;
+ this.actionSecretProcessor = new ActionSecretProcessor();
+ }
+
+ @Override
+ public void addAction(ActionDTO actionDTO, Integer tenantId) throws ActionMgtException {
+
+ NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
+ try {
+ jdbcTemplate.withTransaction(template -> {
+ ActionDTOBuilder actionDTOBuilder = new ActionDTOBuilder(actionDTO);
+ // Encrypt authentication secrets
+ encryptAddingAuthSecrets(actionDTOBuilder);
+ // Resolve action properties
+ ActionDTO resolvedActionDTO = getResolvedActionDTOForAddOperation(actionDTOBuilder.build(),
+ tenantId);
+
+ actionManagementDAO.addAction(resolvedActionDTO, tenantId);
+ return null;
+ });
+ } catch (TransactionException e) {
+ // Since exceptions thrown are wrapped with TransactionException, extracting the actual cause.
+ handleActionPropertyResolverClientException(e.getCause());
+ LOG.debug("Error while creating the Action of Action Type: " + actionDTO.getType().getDisplayName() +
+ " in Tenant Domain: " + IdentityTenantUtil.getTenantDomain(tenantId) +
+ ". Rolling back created action information, authentication secrets and action properties.");
+ throw ActionManagementExceptionHandler.handleServerException(ErrorMessage.ERROR_WHILE_ADDING_ACTION, e);
+ }
+ }
+
+ @Override
+ public List getActionsByActionType(String actionType, Integer tenantId) throws ActionMgtException {
+
+ try {
+ List actionDTOS = actionManagementDAO.getActionsByActionType(actionType, tenantId);
+
+ return getResolvedActionDTOsForGetOperation(actionType, actionDTOS, tenantId);
+ } catch (ActionMgtException | ActionDTOModelResolverException e) {
+ throw ActionManagementExceptionHandler.handleServerException(
+ ErrorMessage.ERROR_WHILE_RETRIEVING_ACTIONS_BY_ACTION_TYPE, e);
+ }
+ }
+
+ @Override
+ public ActionDTO getActionByActionId(String actionType, String actionId, Integer tenantId)
+ throws ActionMgtException {
+
+ try {
+ ActionDTO actionDTO = actionManagementDAO.getActionByActionId(actionType, actionId, tenantId);
+ if (actionDTO == null) {
+ return null;
+ }
+
+ // Populate action properties
+ return getResolvedActionDTOForGetOperation(actionDTO, tenantId);
+ } catch (ActionMgtException | ActionDTOModelResolverException e) {
+ throw ActionManagementExceptionHandler.handleServerException(
+ ErrorMessage.ERROR_WHILE_RETRIEVING_ACTION_BY_ID, e);
+ }
+ }
+
+ @Override
+ public void updateAction(ActionDTO updatingActionDTO, ActionDTO existingActionDTO, Integer tenantId)
+ throws ActionMgtException {
+
+ NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
+ try {
+ jdbcTemplate.withTransaction(template -> {
+ ActionDTOBuilder updatingActionDTOBuilder = new ActionDTOBuilder(updatingActionDTO);
+ // Encrypt authentication secrets
+ encryptUpdatingAuthSecrets(updatingActionDTOBuilder, existingActionDTO);
+ // Resolve action properties
+ ActionDTO resolvedUpdatingActionDTO =
+ getResolvedActionDTOForUpdateOperation(updatingActionDTOBuilder.build(), existingActionDTO,
+ tenantId);
+
+ actionManagementDAO.updateAction(resolvedUpdatingActionDTO, existingActionDTO, tenantId);
+ return null;
+ });
+ } catch (TransactionException e) {
+ // Since exceptions thrown are wrapped with TransactionException, extracting the actual cause.
+ handleActionPropertyResolverClientException(e.getCause());
+ LOG.debug("Error while updating the Action of Action Type: " +
+ updatingActionDTO.getType().getDisplayName() + " and Action ID: " + updatingActionDTO.getId() +
+ " in Tenant Domain: " + IdentityTenantUtil.getTenantDomain(tenantId) +
+ ". Rolling back updated action information");
+ throw ActionManagementExceptionHandler.handleServerException(ErrorMessage.ERROR_WHILE_UPDATING_ACTION, e);
+ }
+ }
+
+ @Override
+ public void deleteAction(ActionDTO deletingActionDTO, Integer tenantId) throws ActionMgtException {
+
+ NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
+ try {
+ jdbcTemplate.withTransaction(template -> {
+ actionManagementDAO.deleteAction(deletingActionDTO, tenantId);
+ // Encrypt authentication secrets
+ deleteAuthenticationSecrets(deletingActionDTO);
+ // Resolve action properties
+ deleteProperties(deletingActionDTO, tenantId);
+
+ return null;
+ });
+ } catch (TransactionException e) {
+ LOG.debug("Error while deleting the Action of Action Type: " +
+ deletingActionDTO.getType().getDisplayName() + " and Action ID: " + deletingActionDTO.getId() +
+ " in Tenant Domain: " + IdentityTenantUtil.getTenantDomain(tenantId) +
+ ". Rolling back deleted action information");
+ throw ActionManagementExceptionHandler.handleServerException(ErrorMessage.ERROR_WHILE_DELETING_ACTION, e);
+ }
+ }
+
+ @Override
+ public ActionDTO activateAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException {
+
+ try {
+ return actionManagementDAO.activateAction(actionType, actionId, tenantId);
+ } catch (ActionMgtException e) {
+ throw ActionManagementExceptionHandler.handleServerException(ErrorMessage.ERROR_WHILE_ACTIVATING_ACTION, e);
+ }
+ }
+
+ @Override
+ public ActionDTO deactivateAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException {
+
+ try {
+ return actionManagementDAO.deactivateAction(actionType, actionId, tenantId);
+ } catch (ActionMgtException e) {
+ throw ActionManagementExceptionHandler.handleServerException(
+ ErrorMessage.ERROR_WHILE_DEACTIVATING_ACTION, e);
+ }
+ }
+
+ @Override
+ public Map getActionsCountPerType(Integer tenantId) throws ActionMgtException {
+
+ try {
+ return actionManagementDAO.getActionsCountPerType(tenantId);
+ } catch (ActionMgtException e) {
+ throw ActionManagementExceptionHandler.handleServerException(
+ ErrorMessage.ERROR_WHILE_RETRIEVING_ACTIONS_COUNT_PER_TYPE, e);
+ }
+ }
+
+ /**
+ * Encrypt and store the authentication secrets of the Action Endpoint Authentication.
+ *
+ * @param actionDTOBuilder ActionDTOBuilder object.
+ * @throws ActionMgtException If an error occurs while encrypting the authentication secrets.
+ */
+ private void encryptAddingAuthSecrets(ActionDTOBuilder actionDTOBuilder) throws ActionMgtException {
+
+ try {
+ List encryptedProperties = actionSecretProcessor.encryptAssociatedSecrets(
+ actionDTOBuilder.getEndpoint().getAuthentication(), actionDTOBuilder.getId());
+
+ addEncryptedAuthSecretsToBuilder(actionDTOBuilder, encryptedProperties);
+ } catch (SecretManagementException e) {
+ throw new ActionMgtServerException("Error while encrypting Action Endpoint Authentication Secrets.", e);
+ }
+ }
+
+ /**
+ * Encrypt and update the authentication secrets of the Action Endpoint Authentication.
+ * If the authentication type is changed, delete the existing authentication secrets and add new secrets.
+ * If the authentication properties are updated, update the existing authentication secrets.
+ *
+ * @param updatingActionDTOBuilder ActionDTOBuilder object.
+ * @param existingActionDTO Existing ActionDTO object.
+ * @throws ActionMgtException If an error occurs while encrypting the authentication secrets.
+ */
+ private void encryptUpdatingAuthSecrets(ActionDTOBuilder updatingActionDTOBuilder,
+ ActionDTO existingActionDTO)
+ throws ActionMgtException {
+
+ if (updatingActionDTOBuilder.getEndpoint() == null ||
+ updatingActionDTOBuilder.getEndpoint().getAuthentication() == null) {
+ return;
+ }
+
+ Authentication updatingAuthentication = updatingActionDTOBuilder.getEndpoint().getAuthentication();
+ Authentication existingAuthentication = existingActionDTO.getEndpoint().getAuthentication();
+
+ try {
+ if (updatingAuthentication.getType() != existingAuthentication.getType()) {
+ actionSecretProcessor.deleteAssociatedSecrets(existingAuthentication, existingActionDTO.getId());
+ }
+ List encryptedProperties = actionSecretProcessor.encryptAssociatedSecrets(
+ updatingAuthentication, updatingActionDTOBuilder.getId());
+
+ addEncryptedAuthSecretsToBuilder(updatingActionDTOBuilder, encryptedProperties);
+ } catch (SecretManagementException e) {
+ throw new ActionMgtServerException("Error while updating Action Endpoint Authentication Secrets.", e);
+ }
+ }
+
+ /**
+ * Delete the authentication secrets of the Action Endpoint Authentication.
+ *
+ * @param deletingActionDTO ActionDTO object.
+ * @throws ActionMgtException If an error occurs while deleting the authentication secrets.
+ */
+ private void deleteAuthenticationSecrets(ActionDTO deletingActionDTO) throws ActionMgtException {
+
+ try {
+ actionSecretProcessor.deleteAssociatedSecrets(deletingActionDTO.getEndpoint().getAuthentication(),
+ deletingActionDTO.getId());
+ } catch (SecretManagementException e) {
+ throw new ActionMgtServerException("Error while deleting Action Endpoint Authentication Secrets.", e);
+ }
+ }
+
+ /**
+ * Add the encrypted authentication secrets and replace the input authentication properties in the ActionDTOBuilder
+ * object.
+ *
+ * @param actionDTOBuilder ActionDTOBuilder object.
+ * @param encryptedProperties List of encrypted AuthProperty objects.
+ */
+ private void addEncryptedAuthSecretsToBuilder(ActionDTOBuilder actionDTOBuilder,
+ List encryptedProperties) {
+
+ Map encryptedPropertyMap = encryptedProperties.stream()
+ .collect(Collectors.toMap(AuthProperty::getName, AuthProperty::getValue));
+
+ actionDTOBuilder.endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(actionDTOBuilder.getEndpoint().getUri())
+ .authentication(new Authentication.AuthenticationBuilder()
+ .type(actionDTOBuilder.getEndpoint().getAuthentication().getType())
+ .properties(encryptedPropertyMap)
+ .build())
+ .build());
+ }
+
+ /**
+ * Get the ActionDTO with resolved adding properties that needs to be added in the Action Management Service.
+ *
+ * @param actionDTO ActionDTO object.
+ * @param tenantId Tenant ID.
+ * @return ActionDTO object with resolved adding properties.
+ * @throws ActionDTOModelResolverException If an error occurs while resolving the adding properties.
+ */
+ private ActionDTO getResolvedActionDTOForAddOperation(ActionDTO actionDTO, Integer tenantId)
+ throws ActionDTOModelResolverException {
+
+ ActionDTOModelResolver actionDTOModelResolver =
+ ActionDTOModelResolverFactory.getActionDTOModelResolver(actionDTO.getType());
+ if (actionDTOModelResolver == null) {
+ return actionDTO;
+ }
+
+ return actionDTOModelResolver.resolveForAddOperation(actionDTO, IdentityTenantUtil.getTenantDomain(tenantId));
+ }
+
+ /**
+ * Get the ActionDTO list with populated properties according to the references stored in the Action Management
+ * Service.
+ *
+ * @param actionType Action type.
+ * @param actionDTOs List of ActionDTO objects.
+ * @param tenantId Tenant ID.
+ * @return List of ActionDTO objects with populated properties.
+ * @throws ActionDTOModelResolverException If an error occurs while populating the properties.
+ */
+ private List getResolvedActionDTOsForGetOperation(String actionType, List actionDTOs,
+ Integer tenantId)
+ throws ActionDTOModelResolverException {
+
+ ActionDTOModelResolver actionDTOModelResolver =
+ ActionDTOModelResolverFactory.getActionDTOModelResolver(Action.ActionTypes.valueOf(actionType));
+ if (actionDTOModelResolver == null) {
+ return actionDTOs;
+ }
+
+ return actionDTOModelResolver.resolveForGetOperation(actionDTOs, IdentityTenantUtil.getTenantDomain(tenantId));
+ }
+
+ /**
+ * Get the ActionDTO with populated properties according to the references stored in the Action Management Service.
+ *
+ * @param actionDTO ActionDTO object.
+ * @param tenantId Tenant ID.
+ * @return ActionDTO object with populated properties.
+ * @throws ActionDTOModelResolverException If an error occurs while populating the properties.
+ */
+ private ActionDTO getResolvedActionDTOForGetOperation(ActionDTO actionDTO, Integer tenantId)
+ throws ActionDTOModelResolverException {
+
+ ActionDTOModelResolver actionDTOModelResolver =
+ ActionDTOModelResolverFactory.getActionDTOModelResolver(actionDTO.getType());
+ if (actionDTOModelResolver == null) {
+ return actionDTO;
+ }
+
+ return actionDTOModelResolver.resolveForGetOperation(actionDTO, IdentityTenantUtil.getTenantDomain(tenantId));
+ }
+
+ /**
+ * Get the ActionDTO with resolved updating properties that needs to be updated in the Action Management Service.
+ *
+ * @param updatingActionDTO Updating ActionDTO object.
+ * @param existingActionDTO Existing ActionDTO object.
+ * @param tenantId Tenant ID.
+ * @return ActionDTO object with resolved updating properties.
+ * @throws ActionDTOModelResolverException If an error occurs while resolving the updating properties.
+ */
+ private ActionDTO getResolvedActionDTOForUpdateOperation(ActionDTO updatingActionDTO,
+ ActionDTO existingActionDTO, Integer tenantId)
+ throws ActionDTOModelResolverException {
+
+ ActionDTOModelResolver actionDTOModelResolver =
+ ActionDTOModelResolverFactory.getActionDTOModelResolver(updatingActionDTO.getType());
+ if (actionDTOModelResolver == null) {
+ return updatingActionDTO;
+ }
+
+ return actionDTOModelResolver.resolveForUpdateOperation(updatingActionDTO, existingActionDTO,
+ IdentityTenantUtil.getTenantDomain(tenantId));
+ }
+
+ /**
+ * Delete the properties that are deleted in the Action Management Service.
+ *
+ * @param deletingActionDTO Deleting ActionDTO object.
+ * @param tenantId Tenant ID.
+ * @throws ActionDTOModelResolverException If an error occurs while deleting the properties.
+ */
+ private void deleteProperties(ActionDTO deletingActionDTO, Integer tenantId)
+ throws ActionDTOModelResolverException {
+
+ ActionDTOModelResolver actionDTOModelResolver =
+ ActionDTOModelResolverFactory.getActionDTOModelResolver(deletingActionDTO.getType());
+ if (actionDTOModelResolver == null) {
+ return;
+ }
+
+ actionDTOModelResolver.resolveForDeleteOperation(deletingActionDTO,
+ IdentityTenantUtil.getTenantDomain(tenantId));
+ }
+
+ /**
+ * Handle the ActionPropertyResolverClientException and throw the relevant ActionMgtClientException.
+ *
+ * @param throwable Throwable object.
+ * @throws ActionMgtClientException If an error occurs while handling the ActionPropertyResolverClientException.
+ */
+ private static void handleActionPropertyResolverClientException(Throwable throwable)
+ throws ActionMgtClientException {
+
+ if (throwable instanceof ActionDTOModelResolverClientException) {
+ ActionDTOModelResolverClientException clientException = (ActionDTOModelResolverClientException) throwable;
+ throw new ActionMgtClientException(clientException.getMessage(), clientException.getDescription(),
+ ErrorMessage.ERROR_INVALID_ACTION_PROPERTIES.getCode());
+ }
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java
index 95bc2f54917a..59850e7efc8d 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/ActionManagementDAOImpl.java
@@ -18,182 +18,140 @@
package org.wso2.carbon.identity.action.management.dao.impl;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.database.utils.jdbc.NamedJdbcTemplate;
-import org.wso2.carbon.database.utils.jdbc.exceptions.DataAccessException;
+import org.wso2.carbon.database.utils.jdbc.NamedPreparedStatement;
import org.wso2.carbon.database.utils.jdbc.exceptions.TransactionException;
-import org.wso2.carbon.identity.action.management.ActionSecretProcessor;
-import org.wso2.carbon.identity.action.management.constant.ActionMgtConstants;
import org.wso2.carbon.identity.action.management.constant.ActionMgtSQLConstants;
import org.wso2.carbon.identity.action.management.dao.ActionManagementDAO;
import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
-import org.wso2.carbon.identity.action.management.exception.ActionMgtRuntimeException;
import org.wso2.carbon.identity.action.management.exception.ActionMgtServerException;
import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.ActionDTO;
import org.wso2.carbon.identity.action.management.model.AuthProperty;
import org.wso2.carbon.identity.action.management.model.Authentication;
import org.wso2.carbon.identity.action.management.model.EndpointConfig;
-import org.wso2.carbon.identity.action.management.util.ActionManagementUtil;
+import org.wso2.carbon.identity.action.management.util.ActionDTOBuilder;
import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil;
-import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
+import static org.wso2.carbon.identity.action.management.constant.ActionMgtConstants.AUTHN_TYPE_PROPERTY;
+import static org.wso2.carbon.identity.action.management.constant.ActionMgtConstants.URI_PROPERTY;
+
/**
* This class implements the {@link ActionManagementDAO} interface.
*/
public class ActionManagementDAOImpl implements ActionManagementDAO {
- private static final Log LOG = LogFactory.getLog(ActionManagementDAOImpl.class);
- private final ActionSecretProcessor actionSecretProcessor;
-
- public ActionManagementDAOImpl() {
-
- this.actionSecretProcessor = new ActionSecretProcessor();
+ @Override
+ public void addAction(ActionDTO actionDTO, Integer tenantId) throws ActionMgtException {
+
+ // Add action basic information.
+ addBasicInfo(actionDTO, tenantId);
+ // Add action endpoint.
+ addEndpoint(actionDTO, tenantId);
+ // Add action properties.
+ addProperties(actionDTO, tenantId);
}
@Override
- public Action addAction(String actionType, String actionId, Action action, Integer tenantId)
- throws ActionMgtException {
-
- NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
- try {
- jdbcTemplate.withTransaction(template -> {
- template.executeInsert(ActionMgtSQLConstants.Query.ADD_ACTION_TO_ACTION_TYPE,
- statement -> {
- statement.setString(ActionMgtSQLConstants.Column.ACTION_UUID, actionId);
- statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE, actionType);
- statement.setString(ActionMgtSQLConstants.Column.ACTION_NAME, action.getName());
- statement.setString(ActionMgtSQLConstants.Column.ACTION_DESCRIPTION, action.getDescription());
- statement.setString(ActionMgtSQLConstants.Column.ACTION_STATUS,
- String.valueOf(Action.Status.ACTIVE));
- statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
- }, action, false);
-
- // Encrypt secrets.
- List encryptedAuthProperties = actionSecretProcessor
- .encryptAssociatedSecrets(action.getEndpoint().getAuthentication(), actionId);
-
- // Add Endpoint configuration properties.
- addEndpointProperties(actionId, getEndpointProperties(action.getEndpoint().getUri(),
- action.getEndpoint().getAuthentication().getType().name(), encryptedAuthProperties), tenantId);
-
- return null;
- });
-
- return getActionByActionId(actionType, actionId, tenantId);
- } catch (TransactionException e) {
- if (LOG.isDebugEnabled()) {
- LOG.debug(String.format("Error while creating the Action of Action Type: %s in Tenant Domain: %s." +
- " Rolling back created action information and deleting added secrets.", actionType,
- IdentityTenantUtil.getTenantDomain(tenantId)));
+ public List getActionsByActionType(String actionType, Integer tenantId) throws ActionMgtException {
+
+ List actionDTOS = new ArrayList<>();
+ try (Connection dbConnection = IdentityDatabaseUtil.getDBConnection(false);
+ NamedPreparedStatement statement = new NamedPreparedStatement(dbConnection,
+ ActionMgtSQLConstants.Query.GET_ACTIONS_BASIC_INFO_BY_ACTION_TYPE)) {
+
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE, actionType);
+ statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
+
+ try (ResultSet rs = statement.executeQuery()) {
+ while (rs.next()) {
+ String actionId = rs.getString(ActionMgtSQLConstants.Column.ACTION_UUID);
+ ActionDTO actionDTO = new ActionDTOBuilder()
+ .id(actionId)
+ .type(org.wso2.carbon.identity.action.management.model.Action.ActionTypes.valueOf(
+ rs.getString(ActionMgtSQLConstants.Column.ACTION_TYPE)))
+ .name(rs.getString(ActionMgtSQLConstants.Column.ACTION_NAME))
+ .description(rs.getString(ActionMgtSQLConstants.Column.ACTION_DESCRIPTION))
+ .status(org.wso2.carbon.identity.action.management.model.Action.Status.valueOf(
+ rs.getString(ActionMgtSQLConstants.Column.ACTION_STATUS)))
+ .setEndpointAndProperties(getActionPropertiesFromDB(actionId, tenantId))
+ .build();
+
+ actionDTOS.add(actionDTO);
+ }
}
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_ADDING_ACTION, e);
+
+ return actionDTOS;
+ } catch (SQLException e) {
+ throw new ActionMgtServerException("Error while retrieving Actions information by Action Type from " +
+ "the system.", e);
}
}
@Override
- public List getActionsByActionType(String actionType, Integer tenantId) throws ActionMgtException {
+ public ActionDTO getActionByActionId(String actionType, String actionId, Integer tenantId)
+ throws ActionMgtException {
- NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
- try {
- return jdbcTemplate.executeQuery(ActionMgtSQLConstants.Query.GET_ACTIONS_BASIC_INFO_BY_ACTION_TYPE,
- (resultSet, rowNumber) -> new Action.ActionResponseBuilder()
- .id(resultSet.getString(ActionMgtSQLConstants.Column.ACTION_UUID))
- .type(Action.ActionTypes
- .valueOf(resultSet.getString(ActionMgtSQLConstants.Column.ACTION_TYPE)))
- .name(resultSet.getString(ActionMgtSQLConstants.Column.ACTION_NAME))
- .description(resultSet.getString(ActionMgtSQLConstants.Column.ACTION_DESCRIPTION))
- .status(Action.Status
- .valueOf(resultSet.getString(ActionMgtSQLConstants.Column.ACTION_STATUS)))
- .endpoint(getActionEndpointConfigById(
- resultSet.getString(ActionMgtSQLConstants.Column.ACTION_UUID), tenantId))
- .build(),
- statement -> {
- statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE, actionType);
- statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
- });
- } catch (ActionMgtRuntimeException | DataAccessException e) {
- /**
- * Handling {@link ActionMgtRuntimeException}, which is intentionally thrown to represent underlying
- * exceptions from the {@link #getActionEndpointConfigById(String, Integer)} method.
- */
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_RETRIEVING_ACTIONS_BY_ACTION_TYPE, e);
+ ActionDTOBuilder actionBuilder = getBasicInfo(actionType, actionId, tenantId);
+ if (actionBuilder == null) {
+ return null;
}
+ actionBuilder.setEndpointAndProperties(getActionPropertiesFromDB(actionId, tenantId));
+
+ return actionBuilder.build();
}
@Override
- public Action updateAction(String actionType, String actionId, Action updatingAction, Action existingAction,
- Integer tenantId) throws ActionMgtException {
-
- NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
- try {
- jdbcTemplate.withTransaction(template -> {
- // Update Basic Info.
- updateBasicInfo(actionType, actionId, updatingAction, existingAction, tenantId);
- // Update Endpoint URI and Authentication.
- updateEndpointUriAndAuthentication(actionId, updatingAction, existingAction, tenantId);
-
- return null;
- });
+ public void updateAction(ActionDTO updatingActionDTO, ActionDTO existingActionDTO, Integer tenantId)
+ throws ActionMgtException {
- return getActionByActionId(actionType, actionId, tenantId);
- } catch (TransactionException e) {
- if (LOG.isDebugEnabled()) {
- LOG.debug(String.format("Error while updating the Action of Action Type: %s and Action ID: %s in" +
- " Tenant Domain: %s. Rolling back updated action information.", actionType, actionId,
- IdentityTenantUtil.getTenantDomain(tenantId)));
- }
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_UPDATING_ACTION, e);
- }
+ // Update action basic information.
+ updateBasicInfo(updatingActionDTO, existingActionDTO, tenantId);
+ // Update Action Endpoint.
+ updateEndpoint(updatingActionDTO, existingActionDTO, tenantId);
+ // Update Action Properties.
+ updateProperties(updatingActionDTO, existingActionDTO, tenantId);
}
@Override
- public void deleteAction(String actionType, String actionId, Action action, Integer tenantId)
- throws ActionMgtException {
+ public void deleteAction(ActionDTO deletingActionDTO, Integer tenantId) throws ActionMgtException {
NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
try {
jdbcTemplate.withTransaction(template -> {
template.executeUpdate(ActionMgtSQLConstants.Query.DELETE_ACTION,
statement -> {
- statement.setString(ActionMgtSQLConstants.Column.ACTION_UUID, actionId);
- statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE, actionType);
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_UUID, deletingActionDTO.getId());
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE,
+ deletingActionDTO.getType().getActionType());
statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
});
- // Delete action endpoint authentication related secrets.
- actionSecretProcessor.deleteAssociatedSecrets(action.getEndpoint().getAuthentication(), actionId);
return null;
});
} catch (TransactionException e) {
- if (LOG.isDebugEnabled()) {
- LOG.debug(String.format("Error while deleting the Action of Action Type: %s and Action ID: %s in" +
- " Tenant Domain: %s. Rolling back deleted action information.", actionType, actionId,
- IdentityTenantUtil.getTenantDomain(tenantId)));
- }
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_DELETING_ACTION, e);
+ throw new ActionMgtServerException("Error while deleting Action information in the system.", e);
}
}
@Override
- public Action activateAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException {
+ public ActionDTO activateAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException {
return changeActionStatus(actionType, actionId, String.valueOf(Action.Status.ACTIVE), tenantId);
-
}
@Override
- public Action deactivateAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException {
+ public ActionDTO deactivateAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException {
return changeActionStatus(actionType, actionId, String.valueOf(Action.Status.INACTIVE), tenantId);
}
@@ -203,433 +161,455 @@ public Map getActionsCountPerType(Integer tenantId) throws Acti
Map actionTypesCountMap = new HashMap<>();
NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
try {
- jdbcTemplate.executeQuery(ActionMgtSQLConstants.Query.GET_ACTIONS_COUNT_PER_ACTION_TYPE,
- (resultSet, rowNumber) -> {
- actionTypesCountMap.put(resultSet.getString(ActionMgtSQLConstants.Column.ACTION_TYPE),
- resultSet.getInt(ActionMgtSQLConstants.Column.ACTION_COUNT));
- return null;
- }, statement -> statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId));
+ jdbcTemplate.withTransaction(template ->
+ template.executeQuery(ActionMgtSQLConstants.Query.GET_ACTIONS_COUNT_PER_ACTION_TYPE,
+ (resultSet, rowNumber) -> {
+ actionTypesCountMap.put(resultSet.getString(ActionMgtSQLConstants.Column.ACTION_TYPE),
+ resultSet.getInt(ActionMgtSQLConstants.Column.ACTION_COUNT));
+ return null;
+ }, statement -> statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId)));
return actionTypesCountMap;
- } catch (DataAccessException e) {
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_RETRIEVING_ACTIONS_COUNT_PER_TYPE, e);
+ } catch (TransactionException e) {
+ throw new ActionMgtServerException("Error while retrieving Actions count per Action Type from the system.",
+ e);
}
}
- @Override
- public Action getActionByActionId(String actionType, String actionId, Integer tenantId) throws ActionMgtException {
+ /**
+ * Add Basic Information of an {@link ActionDTO} to the Database.
+ *
+ * @param actionDTO ActionDTO object with basic information.
+ * @param tenantId Tenant ID.
+ * @throws ActionMgtException If an error occurs while adding action basic information in the database.
+ */
+ private void addBasicInfo(ActionDTO actionDTO, Integer tenantId) throws ActionMgtException {
+ NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
try {
- Action action = getActionBasicInfoById(actionType, actionId, tenantId);
- if (action != null) {
- action = new Action.ActionResponseBuilder()
- .id(actionId)
- .type(Action.ActionTypes.valueOf(actionType))
- .name(action.getName())
- .description(action.getDescription())
- .status(action.getStatus())
- .endpoint(getActionEndpointConfigById(actionId, tenantId))
- .build();
- }
-
- return action;
- } catch (ActionMgtException | ActionMgtRuntimeException e) {
- /**
- * Handling {@link ActionMgtRuntimeException}, which is intentionally thrown to represent underlying
- * exceptions from the {@link #getActionEndpointConfigById(String, Integer)} method.
- */
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_RETRIEVING_ACTION_BY_ID, e);
+ jdbcTemplate.withTransaction(template ->
+ template.executeInsert(ActionMgtSQLConstants.Query.ADD_ACTION_TO_ACTION_TYPE,
+ statement -> {
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_UUID, actionDTO.getId());
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE,
+ actionDTO.getType().getActionType());
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_NAME, actionDTO.getName());
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_DESCRIPTION,
+ actionDTO.getDescription());
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_STATUS,
+ String.valueOf(Action.Status.ACTIVE));
+ statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
+ }, actionDTO, false));
+ } catch (TransactionException e) {
+ throw new ActionMgtServerException("Error while adding Action Basic information in the system.", e);
}
}
- @Override
- public Action updateActionEndpointAuthProperties(String actionType, String actionId, Authentication authentication,
- int tenantId) throws ActionMgtException {
-
- updateActionEndpointAuthProperties(actionId, authentication, tenantId);
- return getActionByActionId(actionType, actionId, tenantId);
- }
-
- @Override
- public Action updateActionEndpoint(String actionType, String actionId, EndpointConfig endpoint,
- Authentication currentAuthentication, int tenantId)
- throws ActionMgtException {
-
- updateActionEndpoint(actionId, endpoint, currentAuthentication, tenantId);
- return getActionByActionId(actionType, actionId, tenantId);
- }
-
/**
- * Update the endpoint authentication properties of an {@link Action} by given Action ID.
+ * Update the basic information of an {@link ActionDTO} by given Action ID.
*
- * @param actionId Action ID.
- * @param authentication Authentication information to be updated.
- * @param tenantId Tenant Id.
- * @throws ActionMgtServerException If an error occurs while updating the Action endpoint authentication properties.
+ * @param updatingActionDTO Information to be updated.
+ * @param existingActionDTO Existing Action information.
+ * @param tenantId Tenant ID.
+ * @throws ActionMgtException If an error occurs while updating the Action basic information in the database.
*/
- private void updateActionEndpointAuthProperties(String actionId, Authentication authentication, int tenantId)
- throws ActionMgtServerException {
+ private void updateBasicInfo(ActionDTO updatingActionDTO, ActionDTO existingActionDTO, Integer tenantId)
+ throws ActionMgtException {
+
+ if (updatingActionDTO.getName() == null && updatingActionDTO.getDescription() == null) {
+ return;
+ }
NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
try {
- Map nonSecretEndpointProperties = authentication.getProperties().stream()
- .filter(property -> !property.getIsConfidential())
- .collect(Collectors.toMap(AuthProperty::getName, AuthProperty::getValue));
-
jdbcTemplate.withTransaction(template -> {
- // Update non-secret endpoint properties.
- updateActionEndpointProperties(actionId, nonSecretEndpointProperties, tenantId);
- // Encrypt and update secret endpoint properties.
- actionSecretProcessor.encryptAssociatedSecrets(authentication, actionId);
+ template.executeUpdate(ActionMgtSQLConstants.Query.UPDATE_ACTION_BASIC_INFO,
+ statement -> {
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_NAME,
+ updatingActionDTO.getName() == null ? existingActionDTO.getName()
+ : updatingActionDTO.getName());
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_DESCRIPTION,
+ updatingActionDTO.getDescription() == null ? existingActionDTO.getDescription()
+ : updatingActionDTO.getDescription());
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_UUID, updatingActionDTO.getId());
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE,
+ updatingActionDTO.getType().getActionType());
+ statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
+ });
+
return null;
});
} catch (TransactionException e) {
- if (LOG.isDebugEnabled()) {
- LOG.debug(String.format("Error while updating the Action Endpoint Authentication Properties of " +
- "Auth type: %s and Action ID: %s in Tenant Domain: %s. Rolling back updated action" +
- " endpoint authentication properties.", authentication.getType(), actionId,
- IdentityTenantUtil.getTenantDomain(tenantId)));
- }
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_UPDATING_ENDPOINT_PROPERTIES, e);
+ throw new ActionMgtServerException("Error while updating Action Basic information in the system.", e);
}
}
/**
- * Update the endpoint information of an {@link Action} by given Action ID.
+ * Get Action Basic Info by Action ID.
*
- * @param actionId Action ID.
- * @param endpoint Endpoint information to be updated.
- * @param currentAuthentication Current Action endpoint authentication information.
- * @param tenantId Tenant Id.
- * @throws ActionMgtServerException If an error occurs while updating the Action endpoint.
+ * @param actionId UUID of the created Action.
+ * @param tenantId Tenant ID.
+ * @return ActionDTO Builder with action basic information.
+ * @throws ActionMgtException If an error occurs while retrieving action basic info from the database.
*/
- private void updateActionEndpoint(String actionId, EndpointConfig endpoint, Authentication currentAuthentication,
- int tenantId) throws ActionMgtServerException {
+ private ActionDTOBuilder getBasicInfo(String actionType, String actionId, Integer tenantId)
+ throws ActionMgtException {
NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
try {
- jdbcTemplate.withTransaction(template -> {
- template.executeUpdate(ActionMgtSQLConstants.Query.DELETE_ACTION_ENDPOINT_PROPERTIES,
+ return jdbcTemplate.withTransaction(template ->
+ template.fetchSingleRecord(ActionMgtSQLConstants.Query.GET_ACTION_BASIC_INFO_BY_ID,
+ (resultSet, rowNumber) -> new ActionDTOBuilder()
+ .id(actionId)
+ .type(Action.ActionTypes.valueOf(
+ resultSet.getString(ActionMgtSQLConstants.Column.ACTION_TYPE)))
+ .name(resultSet.getString(ActionMgtSQLConstants.Column.ACTION_NAME))
+ .description(resultSet.getString(ActionMgtSQLConstants.Column.ACTION_DESCRIPTION))
+ .status(Action.Status.valueOf(
+ resultSet.getString(ActionMgtSQLConstants.Column.ACTION_STATUS))),
statement -> {
- statement.setString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_UUID, actionId);
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE, actionType);
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_UUID, actionId);
statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
- });
-
- // Add new Endpoint configuration properties.
- Map propertiesMap = getEndpointProperties(endpoint.getUri(),
- endpoint.getAuthentication().getType().name(),
- endpoint.getAuthentication().getPropertiesWithSecretReferences(actionId));
- addEndpointProperties(actionId, propertiesMap, tenantId);
- // Encrypt and add new endpoint properties secrets.
- actionSecretProcessor.encryptAssociatedSecrets(endpoint.getAuthentication(), actionId);
-
- // Delete old secrets.
- actionSecretProcessor.deleteAssociatedSecrets(currentAuthentication, actionId);
- return null;
- });
+ }));
} catch (TransactionException e) {
- if (LOG.isDebugEnabled()) {
- LOG.debug(String.format("Error while updating the Action Endpoint Authentication from Auth type: %s" +
- " to Auth type: %s of Action ID: %s in Tenant Domain: %s. Rolling back updated" +
- " action endpoint authentication.", currentAuthentication.getType(),
- endpoint.getAuthentication().getType(), actionId,
- IdentityTenantUtil.getTenantDomain(tenantId)));
- }
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_UPDATING_ENDPOINT_PROPERTIES, e);
+ throw new ActionMgtServerException("Error while retrieving Action Basic information from the system.", e);
}
}
/**
- * Add Action Endpoint properties to the Database.
+ * Add Action Endpoint Configurations.
*
- * @param actionId UUID of the created Action.
- * @param endpointProperties Endpoint properties of the Action.
- * @param tenantId Tenant ID.
- * @throws ActionMgtServerException If an error occurs while adding endpoint properties to the database.
+ * @param actionDTO ActionDTO object with endpoint information.
+ * @param tenantId Tenant ID.
+ * @throws ActionMgtException If an error occurs while adding action endpoint.
*/
- private void addEndpointProperties(String actionId, Map endpointProperties, Integer tenantId)
- throws ActionMgtException {
+ private void addEndpoint(ActionDTO actionDTO, Integer tenantId) throws ActionMgtException {
- NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
+ EndpointConfig endpoint = actionDTO.getEndpoint();
+ Map endpointProperties = new HashMap<>();
try {
- jdbcTemplate.withTransaction(template -> {
- template.executeBatchInsert(ActionMgtSQLConstants.Query.ADD_ACTION_ENDPOINT_PROPERTIES,
- statement -> {
- for (Map.Entry property : endpointProperties.entrySet()) {
- statement.setString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_UUID, actionId);
- statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
- statement.setString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_PROPERTY_NAME,
- property.getKey());
- statement.setString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_PROPERTY_VALUE,
- property.getValue());
- statement.addBatch();
- }
- }, null);
- return null;
- });
+ endpointProperties.put(URI_PROPERTY, endpoint.getUri());
+ endpointProperties.put(AUTHN_TYPE_PROPERTY, endpoint.getAuthentication().getType().name());
+ endpoint.getAuthentication().getProperties().forEach(
+ authProperty -> endpointProperties.put(authProperty.getName(), authProperty.getValue()));
+
+ addActionPropertiesToDB(actionDTO.getId(), endpointProperties, tenantId);
} catch (TransactionException e) {
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_ADDING_ENDPOINT_PROPERTIES, e);
+ throw new ActionMgtServerException("Error while adding Action Endpoint configurations in the system.", e);
}
}
/**
- * Get Action Basic Info by Action ID.
+ * Update Action Endpoint Configurations.
*
- * @param actionId UUID of the created Action.
- * @param tenantId Tenant ID.
- * @return Action Basic Info.
- * @throws ActionMgtException If an error occurs while retrieving action basic info from the database.
+ * @param updatingActionDTO Updating ActionDTO object with endpoint information.
+ * @param existingActionDTO Existing ActionDTO object with endpoint information.
+ * @param tenantId Tenant ID.
+ * @throws ActionMgtException If an error occurs while updating action endpoint.
*/
- private Action getActionBasicInfoById(String actionType, String actionId, Integer tenantId)
+ private void updateEndpoint(ActionDTO updatingActionDTO, ActionDTO existingActionDTO, Integer tenantId)
throws ActionMgtException {
- NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
+ EndpointConfig updatingEndpoint = updatingActionDTO.getEndpoint();
+ if (updatingEndpoint == null) {
+ return;
+ }
+
try {
- return jdbcTemplate.fetchSingleRecord(ActionMgtSQLConstants.Query.GET_ACTION_BASIC_INFO_BY_ID,
- (resultSet, rowNumber) -> new Action.ActionResponseBuilder()
- .id(actionId)
- .type(Action.ActionTypes.valueOf(resultSet.getString(ActionMgtSQLConstants.Column.ACTION_TYPE)))
- .name(resultSet.getString(ActionMgtSQLConstants.Column.ACTION_NAME))
- .description(resultSet.getString(ActionMgtSQLConstants.Column.ACTION_DESCRIPTION))
- .status(Action.Status.valueOf(resultSet.getString(ActionMgtSQLConstants.Column.ACTION_STATUS)))
- .build(),
- statement -> {
- statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE, actionType);
- statement.setString(ActionMgtSQLConstants.Column.ACTION_UUID, actionId);
- statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
- });
- } catch (DataAccessException e) {
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_RETRIEVING_ACTION_BASIC_INFO, e);
+ if (updatingEndpoint.getUri() != null) {
+ updateActionPropertiesInDB(updatingActionDTO.getId(),
+ Collections.singletonMap(URI_PROPERTY, updatingEndpoint.getUri()), tenantId);
+ }
+
+ updateEndpointAuthentication(updatingActionDTO.getId(), updatingEndpoint.getAuthentication(),
+ existingActionDTO.getEndpoint().getAuthentication(), tenantId);
+ } catch (ActionMgtException | TransactionException e) {
+ throw new ActionMgtServerException("Error while updating Action Endpoint information in the system.", e);
}
}
/**
- * Get Action Endpoint properties by ID.
+ * Update Action Endpoint Authentication.
*
- * @param actionUUID UUID of the created Action.
- * @param tenantId Tenant ID.
- * @return Endpoint Configuration.
- * @throws ActionMgtRuntimeException If an error occurs while retrieving endpoint properties from the database.
+ * @param actionId UUID of the created Action.
+ * @param updatingAuthentication Authentication object with updated configurations.
+ * @param existingAuthentication Existing Authentication object.
+ * @param tenantId Tenant ID.
+ * @throws ActionMgtException If an error occurs while updating action endpoint authentication.
*/
- private EndpointConfig getActionEndpointConfigById(String actionUUID, Integer tenantId)
- throws ActionMgtRuntimeException {
+ private void updateEndpointAuthentication(String actionId, Authentication updatingAuthentication,
+ Authentication existingAuthentication, Integer tenantId)
+ throws ActionMgtException {
- NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
- try {
- Map actionEndpointProperties = new HashMap<>();
- jdbcTemplate.executeQuery(ActionMgtSQLConstants.Query.GET_ACTION_ENDPOINT_INFO_BY_ID,
- (resultSet, rowNumber) -> {
- actionEndpointProperties.put(
- resultSet.getString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_PROPERTY_NAME),
- resultSet.getString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_PROPERTY_VALUE));
- return null;
- },
- statement -> {
- statement.setString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_UUID, actionUUID);
- statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
- });
+ if (updatingAuthentication == null) {
+ return;
+ }
- Authentication authentication = null;
- if (actionEndpointProperties.containsKey(ActionMgtConstants.AUTHN_TYPE_ATTRIBUTE)) {
- authentication = new Authentication.AuthenticationBuilder()
- .type(Authentication.Type.valueOf(
- actionEndpointProperties.get(ActionMgtConstants.AUTHN_TYPE_ATTRIBUTE)))
- .properties(actionEndpointProperties)
- .build();
+ try {
+ if (updatingAuthentication.getType() == existingAuthentication.getType()) {
+ updateAuthentication(actionId, updatingAuthentication, tenantId);
} else {
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_NO_AUTHENTICATION_TYPE, null);
+ // Delete existing authentication configurations.
+ deleteAuthentication(actionId, existingAuthentication, tenantId);
+ // Add new authentication configurations.
+ addAuthentication(actionId, updatingAuthentication, tenantId);
}
-
- return new EndpointConfig.EndpointConfigBuilder()
- .uri(actionEndpointProperties.get(ActionMgtConstants.URI_ATTRIBUTE))
- .authentication(authentication).build();
- } catch (ActionMgtServerException | DataAccessException e) {
- /**
- * Throwing a runtime exception because {@link ActionMgtServerException} and {@link DataAccessException}
- * is not handled in {@link org.wso2.carbon.database.utils.jdbc.RowMapper} of
- * {@link NamedJdbcTemplate#executeQuery(String, org.wso2.carbon.database.utils.jdbc.RowMapper,
- * org.wso2.carbon.database.utils.jdbc.NamedQueryFilter)}
- */
- throw ActionManagementUtil.handleRuntimeException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_RETRIEVING_ACTION_ENDPOINT_PROPERTIES.getMessage(), e);
+ } catch (TransactionException e) {
+ throw new ActionMgtServerException("Error while updating Action Endpoint Authentication.", e);
}
}
/**
- * Get Action Endpoint properties Map.
+ * Add Authentication Configurations of a new Authentication type.
*
- * @param endpointUri Endpoint URI of the Action.
- * @param authType Authentication Type of the Action.
- * @param authProperties Authentication Properties of the Endpoint.
- * @return Endpoint Properties Map.
+ * @param actionId UUID of the created Action.
+ * @param updatingAuthentication Authentication object with updated configurations.
+ * @param tenantId Tenant ID.
+ * @throws TransactionException If an error occurs while adding action authentication.
*/
- private Map getEndpointProperties(String endpointUri, String authType,
- List authProperties) {
+ private void addAuthentication(String actionId, Authentication updatingAuthentication, Integer tenantId)
+ throws TransactionException {
- Map endpointProperties = new HashMap<>();
- if (endpointUri != null) {
- endpointProperties.put(ActionMgtConstants.URI_ATTRIBUTE, endpointUri);
+ Map authenticationProperties = updatingAuthentication.getProperties().stream()
+ .collect(Collectors.toMap(AuthProperty::getName, AuthProperty::getValue));
+ authenticationProperties.put(AUTHN_TYPE_PROPERTY, updatingAuthentication.getType().name());
+
+ addActionPropertiesToDB(actionId, authenticationProperties, tenantId);
+ }
+
+ /**
+ * Delete Authentication Configurations of an existing Authentication type.
+ *
+ * @param actionId UUID of the created Action.
+ * @param existingAuthentication Existing Authentication object.
+ * @param tenantId Tenant ID.
+ * @throws TransactionException If an error occurs while deleting action authentication.
+ */
+ private void deleteAuthentication(String actionId, Authentication existingAuthentication, Integer tenantId)
+ throws TransactionException {
+
+ List deletingProperties = existingAuthentication.getProperties().stream()
+ .map(AuthProperty::getName)
+ .collect(Collectors.toList());
+ deletingProperties.add(AUTHN_TYPE_PROPERTY);
+
+ deleteActionPropertiesInDB(actionId, deletingProperties, tenantId);
+ }
+
+ /**
+ * Update Authentication Configurations of an existing Authentication type.
+ *
+ * @param actionId UUID of the created Action.
+ * @param updatingAuthentication Authentication object with updated configurations.
+ * @param tenantId Tenant ID.
+ * @throws TransactionException If an error occurs while updating action authentication.
+ */
+ private void updateAuthentication(String actionId, Authentication updatingAuthentication, Integer tenantId)
+ throws TransactionException {
+
+ Map nonSecretAuthenticationProperties = updatingAuthentication.getProperties().stream()
+ .filter(property -> !property.getIsConfidential())
+ .collect(Collectors.toMap(AuthProperty::getName, AuthProperty::getValue));
+ // Update non-secret endpoint properties.
+ updateActionPropertiesInDB(actionId, nonSecretAuthenticationProperties, tenantId);
+ }
+
+ /**
+ * Add Action properties.
+ *
+ * @param actionDTO ActionDTO object with properties.
+ * @param tenantId Tenant ID.
+ * @throws ActionMgtException If an error occurs while adding action properties.
+ */
+ private void addProperties(ActionDTO actionDTO, Integer tenantId) throws ActionMgtException {
+
+ Map propertiesMap = actionDTO.getProperties();
+ if (propertiesMap == null) {
+ return;
}
- if (authType != null) {
- endpointProperties.put(ActionMgtConstants.AUTHN_TYPE_ATTRIBUTE, authType);
+
+ Map actionProperties = propertiesMap.entrySet().stream()
+ .collect(Collectors.toMap(Map.Entry::getKey, entry -> (String) entry.getValue()));
+ try {
+ addActionPropertiesToDB(actionDTO.getId(), actionProperties, tenantId);
+ } catch (TransactionException e) {
+ throw new ActionMgtServerException("Error while adding Action Properties in the system.", e);
}
- if (authProperties != null) {
- for (AuthProperty property : authProperties) {
- endpointProperties.put(property.getName(), property.getValue());
- }
+ }
+
+ /**
+ * Update Action properties.
+ *
+ * @param updatingActionDTO Updating ActionDTO object with properties.
+ * @param existingActionDTO Existing ActionDTO object with properties.
+ * @param tenantId Tenant ID.
+ * @throws ActionMgtException If an error occurs while updating action properties.
+ */
+ private void updateProperties(ActionDTO updatingActionDTO, ActionDTO existingActionDTO,
+ Integer tenantId) throws ActionMgtException {
+
+ Map propertiesMap = updatingActionDTO.getProperties();
+ if (propertiesMap == null) {
+ return;
}
- return endpointProperties;
+ Map updatingProperties = propertiesMap.entrySet().stream()
+ .collect(Collectors.toMap(Map.Entry::getKey, entry -> (String) entry.getValue()));
+ try {
+ // Delete existing properties.
+ deleteActionPropertiesInDB(updatingActionDTO.getId(),
+ new ArrayList<>(existingActionDTO.getProperties().keySet()), tenantId);
+ // Add updated properties.
+ addActionPropertiesToDB(updatingActionDTO.getId(), updatingProperties, tenantId);
+ } catch (TransactionException e) {
+ throw new ActionMgtServerException("Error while updating Action Properties in the system.", e);
+ }
}
/**
- * Update Action Endpoint properties.
+ * Add Action properties to the Database.
*
- * @param actionId UUID of the created Action.
- * @param endpointProperties Endpoint Properties to be updated.
- * @param tenantId Tenant ID.
+ * @param actionId UUID of the created Action.
+ * @param actionProperties Properties of the Action.
+ * @param tenantId Tenant ID.
+ * @throws TransactionException If an error occurs while persisting action properties to the database.
*/
- private void updateActionEndpointProperties(String actionId, Map endpointProperties,
- Integer tenantId) throws ActionMgtException {
+ private void addActionPropertiesToDB(String actionId, Map actionProperties, Integer tenantId)
+ throws TransactionException {
NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
- try {
- jdbcTemplate.withTransaction(template -> {
- template.executeBatchInsert(ActionMgtSQLConstants.Query.UPDATE_ACTION_ENDPOINT_PROPERTIES,
+ jdbcTemplate.withTransaction(template -> {
+ template.executeBatchInsert(ActionMgtSQLConstants.Query.ADD_ACTION_PROPERTIES,
statement -> {
- for (Map.Entry property : endpointProperties.entrySet()) {
- statement.setString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_PROPERTY_VALUE,
- property.getValue());
- statement.setString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_PROPERTY_NAME,
- property.getKey());
- statement.setString(ActionMgtSQLConstants.Column.ACTION_ENDPOINT_UUID, actionId);
+ for (Map.Entry property : actionProperties.entrySet()) {
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_PROPERTIES_UUID, actionId);
statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_PROPERTIES_PROPERTY_NAME,
+ property.getKey());
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_PROPERTIES_PROPERTY_VALUE,
+ property.getValue());
statement.addBatch();
}
}, null);
- return null;
- });
- } catch (TransactionException e) {
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_UPDATING_ENDPOINT_PROPERTIES, e);
- }
+ return null;
+ });
}
/**
- * Update Action Status.
+ * Get Action properties by ID.
*
- * @param actionType Action Type.
- * @param actionId UUID of the Action.
- * @param status Action status to be updated.
- * @param tenantId Tenant ID.
- * @throws ActionMgtException If an error occurs while updating the Action status.
+ * @param actionId UUID of the created Action.
+ * @param tenantId Tenant ID.
+ * @return A map of action properties, including any additional data based on action type.
+ * @throws ActionMgtException If an error occurs while retrieving action properties from the database.
*/
- private Action changeActionStatus(String actionType, String actionId, String status, Integer tenantId)
- throws ActionMgtException {
+ private Map getActionPropertiesFromDB(String actionId, Integer tenantId) throws ActionMgtException {
NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
+ Map actionEndpointProperties = new HashMap<>();
try {
- jdbcTemplate.executeUpdate(ActionMgtSQLConstants.Query.CHANGE_ACTION_STATUS,
- statement -> {
- statement.setString(ActionMgtSQLConstants.Column.ACTION_STATUS, status);
- statement.setString(ActionMgtSQLConstants.Column.ACTION_UUID, actionId);
- statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE, actionType);
- statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
- });
+ jdbcTemplate.withTransaction(template ->
+ template.executeQuery(ActionMgtSQLConstants.Query.GET_ACTION_PROPERTIES_INFO_BY_ID,
+ (resultSet, rowNumber) -> {
+ actionEndpointProperties.put(
+ resultSet.getString(ActionMgtSQLConstants.Column.ACTION_PROPERTIES_PROPERTY_NAME),
+ resultSet.getString(ActionMgtSQLConstants.Column.ACTION_PROPERTIES_PROPERTY_VALUE));
+ return null;
+ },
+ statement -> {
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_PROPERTIES_UUID, actionId);
+ statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
+ }));
- return getActionBasicInfoById(actionType, actionId, tenantId);
- } catch (DataAccessException e) {
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_UPDATING_ACTION_STATUS, e);
+ return actionEndpointProperties;
+ } catch (TransactionException e) {
+ throw new ActionMgtServerException("Error while retrieving Action Properties from the system.", e);
}
}
/**
- * Update the basic information of an {@link Action} by given Action ID.
+ * Update the given property of an {@link ActionDTO} by given Action ID.
*
- * @param actionType Action Type.
- * @param actionId Action ID.
- * @param updatingAction Information to be updated.
- * @param existingAction Existing Action information.
- * @param tenantId Tenant ID.
- * @throws ActionMgtServerException If an error occurs while updating the Action basic information.
+ * @param actionId UUID of the created Action.
+ * @param updatingProperties Action properties to be updated.
+ * @param tenantId Tenant ID.
+ * @throws TransactionException If an error occurs while updating the Action properties in the database.
*/
- private void updateBasicInfo(String actionType, String actionId, Action updatingAction, Action existingAction,
- Integer tenantId) throws ActionMgtServerException {
+ private void updateActionPropertiesInDB(String actionId, Map updatingProperties,
+ Integer tenantId) throws TransactionException {
- if (updatingAction.getName() == null && updatingAction.getDescription() == null) {
- return;
- }
+ NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
+ jdbcTemplate.withTransaction(template ->
+ template.executeBatchInsert(ActionMgtSQLConstants.Query.UPDATE_ACTION_PROPERTY,
+ statement -> {
+ for (Map.Entry property : updatingProperties.entrySet()) {
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_PROPERTIES_PROPERTY_VALUE,
+ property.getValue());
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_PROPERTIES_PROPERTY_NAME,
+ property.getKey());
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_PROPERTIES_UUID, actionId);
+ statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
+ statement.addBatch();
+ }
+ }, null));
+ }
+
+ /**
+ * Delete the given properties of an {@link ActionDTO} by given Action ID.
+ *
+ * @param actionId UUID of the created Action.
+ * @param deletingProperties Action properties to be deleted.
+ * @param tenantId Tenant ID.
+ * @throws TransactionException If an error occurs while deleting the Action properties in the database.
+ */
+ private void deleteActionPropertiesInDB(String actionId, List deletingProperties, Integer tenantId)
+ throws TransactionException {
NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
- try {
- jdbcTemplate.executeUpdate(ActionMgtSQLConstants.Query.UPDATE_ACTION_BASIC_INFO,
+ jdbcTemplate.withTransaction(template ->
+ template.executeBatchInsert(ActionMgtSQLConstants.Query.DELETE_ACTION_PROPERTY,
statement -> {
- statement.setString(ActionMgtSQLConstants.Column.ACTION_NAME,
- updatingAction.getName() == null ? existingAction.getName() : updatingAction.getName());
- statement.setString(ActionMgtSQLConstants.Column.ACTION_DESCRIPTION,
- updatingAction.getDescription() == null ? existingAction.getDescription()
- : updatingAction.getDescription());
- statement.setString(ActionMgtSQLConstants.Column.ACTION_UUID, actionId);
- statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE, actionType);
- statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
- });
- } catch (DataAccessException e) {
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_UPDATING_ACTION_BASIC_INFO, e);
- }
+ for (String property : deletingProperties) {
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_PROPERTIES_PROPERTY_NAME,
+ property);
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_PROPERTIES_UUID, actionId);
+ statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
+ statement.addBatch();
+ }
+ }, null));
}
/**
- * Update the endpoint URI and authentication properties of an {@link Action} by given Action ID.
+ * Update Action Status.
*
- * @param actionId Action ID.
- * @param updatingAction Information to be updated.
- * @param existingAction Existing Action information.
- * @param tenantId Tenant ID.
- * @throws ActionMgtException If an error occurs while updating the Action endpoint.
+ * @param actionType Action Type.
+ * @param actionId UUID of the Action.
+ * @param status Action status to be updated.
+ * @param tenantId Tenant ID.
+ * @return Updated ActionDTO with basic information.
+ * @throws ActionMgtException If an error occurs while updating the Action status.
*/
- private void updateEndpointUriAndAuthentication(String actionId, Action updatingAction, Action existingAction,
- Integer tenantId) throws ActionMgtException {
+ private ActionDTO changeActionStatus(String actionType, String actionId, String status, Integer tenantId)
+ throws ActionMgtException {
- EndpointConfig updatingEndpoint = updatingAction.getEndpoint();
- if (updatingEndpoint == null) {
- // No update needed if there's no endpoint configuration in the updating action.
- return;
- }
+ NamedJdbcTemplate jdbcTemplate = new NamedJdbcTemplate(IdentityDatabaseUtil.getDataSource());
+ try {
+ jdbcTemplate.withTransaction(template -> {
+ template.executeUpdate(ActionMgtSQLConstants.Query.CHANGE_ACTION_STATUS,
+ statement -> {
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_STATUS, status);
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_UUID, actionId);
+ statement.setString(ActionMgtSQLConstants.Column.ACTION_TYPE, actionType);
+ statement.setInt(ActionMgtSQLConstants.Column.TENANT_ID, tenantId);
+ });
- Authentication updatingAuthentication = updatingEndpoint.getAuthentication();
- if (updatingAuthentication == null) {
- // When updating action, updates the URI only.
- updateActionEndpointProperties(actionId, getEndpointProperties(updatingEndpoint.getUri(), null,
- null), tenantId);
- return;
- }
+ return null;
+ });
- Authentication existingAuthentication = existingAction.getEndpoint().getAuthentication();
- if (updatingAuthentication.getType().equals(existingAuthentication.getType())) {
- // When updating action, updates the URI and the authentication properties only.
- if (updatingEndpoint.getUri() != null) {
- updateActionEndpointProperties(actionId, getEndpointProperties(updatingEndpoint.getUri(), null,
- null), tenantId);
- }
- updateActionEndpointAuthProperties(actionId, updatingAuthentication, tenantId);
- return;
+ return getBasicInfo(actionType, actionId, tenantId).build();
+ } catch (TransactionException e) {
+ throw new ActionMgtServerException("Error while updating Action Status to " + status, e);
}
-
- // When updating action, updates the entire endpoint.
- updatingEndpoint = StringUtils.isNotEmpty(updatingEndpoint.getUri()) ? updatingEndpoint :
- new EndpointConfig.EndpointConfigBuilder()
- .uri(existingAction.getEndpoint().getUri())
- .authentication(updatingAuthentication)
- .build();
- updateActionEndpoint(actionId, updatingEndpoint, existingAuthentication, tenantId);
}
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionDTOModelResolverClientException.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionDTOModelResolverClientException.java
new file mode 100644
index 000000000000..f8d4700358d5
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionDTOModelResolverClientException.java
@@ -0,0 +1,32 @@
+/*
+ * 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.carbon.identity.action.management.exception;
+
+/**
+ * Client Exception class for ActionDTO Model Resolver.
+ * This exception is thrown when there is any validation failures or client error in performing action type
+ * specific operations.
+ */
+public class ActionDTOModelResolverClientException extends ActionDTOModelResolverException {
+
+ public ActionDTOModelResolverClientException(String message, String description) {
+
+ super(message, description);
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionDTOModelResolverException.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionDTOModelResolverException.java
new file mode 100644
index 000000000000..c144ff388164
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionDTOModelResolverException.java
@@ -0,0 +1,45 @@
+/*
+ * 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.carbon.identity.action.management.exception;
+
+/**
+ * Exception class for ActionDTO Model Resolver.
+ * This exception is thrown when there is an issue in performing action type specific operations.
+ */
+public class ActionDTOModelResolverException extends Exception {
+
+ private final String description;
+
+ public ActionDTOModelResolverException(String message, String description) {
+
+ super(message);
+ this.description = description;
+ }
+
+ public ActionDTOModelResolverException(String message, String description, Throwable cause) {
+
+ super(message, cause);
+ this.description = description;
+ }
+
+ public String getDescription() {
+
+ return this.description;
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionDTOModelResolverServerException.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionDTOModelResolverServerException.java
new file mode 100644
index 000000000000..e8861ae0aff1
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionDTOModelResolverServerException.java
@@ -0,0 +1,36 @@
+/*
+ * 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.carbon.identity.action.management.exception;
+
+/**
+ * Server Exception class for ActionDTO Model Resolver.
+ * This exception is thrown when there is an issue in performing action type specific operations in the system.
+ */
+public class ActionDTOModelResolverServerException extends ActionDTOModelResolverException {
+
+ public ActionDTOModelResolverServerException(String message, String description) {
+
+ super(message, description);
+ }
+
+ public ActionDTOModelResolverServerException(String message, String description, Throwable cause) {
+
+ super(message, description, cause);
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionMgtException.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionMgtException.java
index 4b922602e35c..dc7ebd6886da 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionMgtException.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionMgtException.java
@@ -31,16 +31,9 @@ public ActionMgtException(String message) {
super(message);
}
- public ActionMgtException(String message, String errorCode) {
-
- super(message);
- this.errorCode = errorCode;
- }
-
- public ActionMgtException(String message, String errorCode, Throwable cause) {
+ public ActionMgtException(String message, Throwable cause) {
super(message, cause);
- this.errorCode = errorCode;
}
public ActionMgtException(String message, String description, String errorCode) {
@@ -62,18 +55,8 @@ public String getErrorCode() {
return this.errorCode;
}
- public void setErrorCode(String errorCode) {
-
- this.errorCode = errorCode;
- }
-
public String getDescription() {
return this.description;
}
-
- public void setDescription(String description) {
-
- this.description = description;
- }
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionMgtServerException.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionMgtServerException.java
index 3692b83eae40..95a83586ad8a 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionMgtServerException.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/exception/ActionMgtServerException.java
@@ -23,29 +23,18 @@
*/
public class ActionMgtServerException extends ActionMgtException {
- public ActionMgtServerException(String message, String errorCode) {
-
- super(message, errorCode);
- }
-
- public ActionMgtServerException(String message, String description, String errorCode) {
+ public ActionMgtServerException(String message) {
- super(message, description, errorCode);
+ super(message);
}
- public ActionMgtServerException(String message, String errorCode, Throwable cause) {
+ public ActionMgtServerException(String message, Throwable cause) {
- super(message, errorCode, cause);
+ super(message, cause);
}
- public ActionMgtServerException(String message, String description, String errorCode,
- Throwable cause) {
+ public ActionMgtServerException(String message, String description, String errorCode, Throwable cause) {
super(message, description, errorCode, cause);
}
-
- public ActionMgtServerException(String message) {
-
- super(message);
- }
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponent.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponent.java
index 44fe7f894eac..8da0688e5a86 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponent.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/internal/ActionMgtServiceComponent.java
@@ -28,8 +28,12 @@
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
-import org.wso2.carbon.identity.action.management.ActionManagementService;
-import org.wso2.carbon.identity.action.management.ActionManagementServiceImpl;
+import org.wso2.carbon.identity.action.management.dao.impl.ActionDTOModelResolverFactory;
+import org.wso2.carbon.identity.action.management.service.ActionConverter;
+import org.wso2.carbon.identity.action.management.service.ActionDTOModelResolver;
+import org.wso2.carbon.identity.action.management.service.ActionManagementService;
+import org.wso2.carbon.identity.action.management.service.impl.ActionConverterFactory;
+import org.wso2.carbon.identity.action.management.service.impl.CacheBackedActionManagementService;
import org.wso2.carbon.identity.secret.mgt.core.SecretManager;
import org.wso2.carbon.identity.secret.mgt.core.SecretResolveManager;
@@ -49,7 +53,8 @@ protected void activate(ComponentContext context) {
try {
BundleContext bundleCtx = context.getBundleContext();
- bundleCtx.registerService(ActionManagementService.class, ActionManagementServiceImpl.getInstance(), null);
+ bundleCtx.registerService(ActionManagementService.class, CacheBackedActionManagementService.getInstance(),
+ null);
LOG.debug("Action management bundle is activated");
} catch (Throwable e) {
LOG.error("Error while initializing Action management component.", e);
@@ -68,6 +73,55 @@ protected void deactivate(ComponentContext context) {
}
}
+ @Reference(
+ name = "action.converter",
+ service = ActionConverter.class,
+ cardinality = ReferenceCardinality.MULTIPLE,
+ policy = ReferencePolicy.DYNAMIC,
+ unbind = "unsetActionConverter"
+ )
+ protected void setActionConverter(ActionConverter actionConverter) {
+
+ LOG.debug("Registering ActionConverter: " + actionConverter.getClass().getName() +
+ " in the ActionMgtServiceComponent.");
+ ActionConverterFactory.registerActionConverter(actionConverter);
+ }
+
+ protected void unsetActionConverter(ActionConverter actionConverter) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Unregistering ActionConverter: " + actionConverter.getClass().getName() +
+ " in the ActionMgtServiceComponent.");
+ }
+
+ ActionConverterFactory.unregisterActionConverter(actionConverter);
+ }
+
+ @Reference(
+ name = "action.property.resolver",
+ service = ActionDTOModelResolver.class,
+ cardinality = ReferenceCardinality.MULTIPLE,
+ policy = ReferencePolicy.DYNAMIC,
+ unbind = "unsetActionPropertyResolver"
+ )
+ protected void setActionPropertyResolver(ActionDTOModelResolver actionDTOModelResolver) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Registering ActionPropertyResolver: " + actionDTOModelResolver.getClass().getName() +
+ " in the ActionMgtServiceComponent.");
+ }
+ ActionDTOModelResolverFactory.registerActionDTOModelResolver(actionDTOModelResolver);
+ }
+
+ protected void unsetActionPropertyResolver(ActionDTOModelResolver actionDTOModelResolver) {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Unregistering ActionPropertyResolver: " + actionDTOModelResolver.getClass().getName() +
+ " in the ActionMgtServiceComponent.");
+ }
+ ActionDTOModelResolverFactory.unregisterActionDTOModelResolver(actionDTOModelResolver);
+ }
+
@Reference(
name = "org.wso2.carbon.identity.secret.mgt.core.SecretManager",
service = SecretManager.class,
@@ -78,11 +132,13 @@ protected void deactivate(ComponentContext context) {
private void setSecretManager(SecretManager secretManager) {
ActionMgtServiceComponentHolder.getInstance().setSecretManager(secretManager);
+ LOG.debug("SecretManager set in ActionMgtServiceComponentHolder bundle.");
}
private void unsetSecretManager(SecretManager secretManager) {
ActionMgtServiceComponentHolder.getInstance().setSecretManager(null);
+ LOG.debug("SecretManager unset in ActionMgtServiceComponentHolder bundle.");
}
@Reference(
@@ -95,10 +151,12 @@ private void unsetSecretManager(SecretManager secretManager) {
private void setSecretResolveManager(SecretResolveManager secretResolveManager) {
ActionMgtServiceComponentHolder.getInstance().setSecretResolveManager(secretResolveManager);
+ LOG.debug("SecretResolveManager set in ActionMgtServiceComponentHolder bundle.");
}
private void unsetSecretResolveManager(SecretResolveManager secretResolveManager) {
ActionMgtServiceComponentHolder.getInstance().setSecretResolveManager(null);
+ LOG.debug("SecretResolveManager unset in ActionMgtServiceComponentHolder bundle.");
}
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/Action.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/Action.java
index 99fa95aee93d..dc1f3030bf47 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/Action.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/Action.java
@@ -115,7 +115,7 @@ public static ActionTypes[] filterByCategory(Category category) {
*/
public enum Category {
PRE_POST,
- IN_FLOW;
+ IN_FLOW
}
}
@@ -124,30 +124,10 @@ public enum Category {
*/
public enum Status {
- ACTIVE("ACTIVE"),
- INACTIVE("INACTIVE");
-
- private final String value;
-
- Status(String v) {
- this.value = v;
- }
-
- public String value() {
- return value;
- }
-
- public static Status fromValue(String value) {
- for (Status b : Status.values()) {
- if (b.value.equals(value)) {
- return b;
- }
- }
- throw new IllegalArgumentException("Unexpected value '" + value + "'");
- }
+ ACTIVE,
+ INACTIVE
}
-
private String id;
private ActionTypes type;
private String name;
@@ -155,9 +135,6 @@ public static Status fromValue(String value) {
private Status status;
private EndpointConfig endpointConfig;
- public Action() {
- }
-
public Action(ActionResponseBuilder actionResponseBuilder) {
this.id = actionResponseBuilder.id;
@@ -205,11 +182,6 @@ public EndpointConfig getEndpoint() {
return endpointConfig;
}
- public void setEndpoint(EndpointConfig endpointConfig) {
-
- this.endpointConfig = endpointConfig;
- }
-
/**
* ActionResponseBuilder.
*/
@@ -222,9 +194,6 @@ public static class ActionResponseBuilder {
private Status status;
private EndpointConfig endpointConfig;
- public ActionResponseBuilder() {
- }
-
public ActionResponseBuilder id(String id) {
this.id = id;
@@ -276,9 +245,6 @@ public static class ActionRequestBuilder {
private String description;
private EndpointConfig endpointConfig;
- public ActionRequestBuilder() {
- }
-
public ActionRequestBuilder name(String name) {
this.name = name;
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/ActionDTO.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/ActionDTO.java
new file mode 100644
index 000000000000..3351ee606f1b
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/ActionDTO.java
@@ -0,0 +1,136 @@
+/*
+ * 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.carbon.identity.action.management.model;
+
+import java.util.Map;
+
+/**
+ * Action Data Transfer Object.
+ */
+public class ActionDTO {
+
+ private final String id;
+ private final Action.ActionTypes type;
+ private final String name;
+ private final String description;
+ private final Action.Status status;
+ private final EndpointConfig endpoint;
+ private final Map properties;
+
+ public ActionDTO(Builder builder) {
+
+ this.id = builder.id;
+ this.type = builder.type;
+ this.name = builder.name;
+ this.description = builder.description;
+ this.status = builder.status;
+ this.endpoint = builder.endpoint;
+ this.properties = builder.properties;
+ }
+
+ public String getId() {
+
+ return id;
+ }
+
+ public Action.ActionTypes getType() {
+
+ return type;
+ }
+
+ public String getName() {
+
+ return name;
+ }
+
+ public String getDescription() {
+
+ return description;
+ }
+
+ public Action.Status getStatus() {
+
+ return status;
+ }
+
+ public EndpointConfig getEndpoint() {
+
+ return endpoint;
+ }
+
+ public Map getProperties() {
+
+ return properties;
+ }
+
+ public Object getProperty(String propertyName) {
+
+ if (properties == null) {
+ return null;
+ }
+
+ return properties.get(propertyName);
+ }
+
+ /**
+ * Builder for ActionDTO.
+ */
+ public static class Builder {
+
+ private final String id;
+ private final Action.ActionTypes type;
+ private final String name;
+ private final String description;
+ private final Action.Status status;
+ private final EndpointConfig endpoint;
+ private Map properties;
+
+ public Builder(ActionDTO actionDTO) {
+
+ this.id = actionDTO.getId();
+ this.type = actionDTO.getType();
+ this.name = actionDTO.getName();
+ this.description = actionDTO.getDescription();
+ this.status = actionDTO.getStatus();
+ this.endpoint = actionDTO.getEndpoint();
+ this.properties = actionDTO.getProperties();
+ }
+
+ public Builder(Action action) {
+
+ this.id = action.getId();
+ this.type = action.getType();
+ this.name = action.getName();
+ this.description = action.getDescription();
+ this.status = action.getStatus();
+ this.endpoint = action.getEndpoint();
+ }
+
+ public Builder properties(Map properties) {
+
+ this.properties = properties;
+ return this;
+ }
+
+ public ActionDTO build() {
+
+ return new ActionDTO(this);
+ }
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/Authentication.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/Authentication.java
index 5608107befc7..98f34f31adcd 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/Authentication.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/model/Authentication.java
@@ -20,10 +20,10 @@
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
-import org.wso2.carbon.identity.action.management.ActionSecretProcessor;
-import org.wso2.carbon.identity.action.management.constant.ActionMgtConstants;
+import org.wso2.carbon.identity.action.management.constant.error.ErrorMessage;
import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
-import org.wso2.carbon.identity.action.management.util.ActionManagementUtil;
+import org.wso2.carbon.identity.action.management.util.ActionManagementExceptionHandler;
+import org.wso2.carbon.identity.action.management.util.ActionSecretProcessor;
import org.wso2.carbon.identity.secret.mgt.core.exception.SecretManagementException;
import java.util.ArrayList;
@@ -140,10 +140,10 @@ public List getPropertiesWithDecryptedValues(String actionId) thro
try {
return CollectionUtils.isEmpty(properties) ? properties :
- secretProcessor.decryptAssociatedSecrets(properties, type.getName(), actionId);
+ secretProcessor.decryptAssociatedSecrets(this, actionId);
} catch (SecretManagementException e) {
- throw ActionManagementUtil.handleServerException(
- ActionMgtConstants.ErrorMessages.ERROR_WHILE_DECRYPTING_ACTION_ENDPOINT_AUTH_PROPERTIES, e);
+ throw ActionManagementExceptionHandler.handleServerException(
+ ErrorMessage.ERROR_WHILE_DECRYPTING_ACTION_ENDPOINT_AUTH_PROPERTIES, e);
}
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/ActionConverter.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/ActionConverter.java
new file mode 100644
index 000000000000..dc46635bb5a1
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/ActionConverter.java
@@ -0,0 +1,48 @@
+/*
+ * 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.carbon.identity.action.management.service;
+
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.ActionDTO;
+
+/**
+ * This interface defines the Action ActionConverter.
+ * Action ActionConverter is the component that is responsible for the conversions between Action and ExtendedAction
+ * objects.
+ */
+public interface ActionConverter {
+
+ Action.ActionTypes getSupportedActionType();
+
+ /**
+ * Convert Action object into ActionDTO object.
+ *
+ * @param action Action object.
+ * @return ActionDTO object.
+ */
+ ActionDTO buildActionDTO(Action action);
+
+ /**
+ * Convert ActionDTO object into Action object.
+ *
+ * @param actionDTO ActionDTO object.
+ * @return Action object.
+ */
+ Action buildAction(ActionDTO actionDTO);
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/ActionDTOModelResolver.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/ActionDTOModelResolver.java
new file mode 100644
index 000000000000..abfc30170b09
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/ActionDTOModelResolver.java
@@ -0,0 +1,102 @@
+/*
+ * 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.carbon.identity.action.management.service;
+
+import org.wso2.carbon.identity.action.management.exception.ActionDTOModelResolverException;
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.ActionDTO;
+
+import java.util.List;
+
+/**
+ * This interface defines the Action Property Resolver.
+ * Action Property Resolver is the component that is responsible for handling action type specific operations.
+ */
+public interface ActionDTOModelResolver {
+
+ Action.ActionTypes getSupportedActionType();
+
+ /**
+ * Resolve the properties that need to be added in the Action Management Service.
+ * This method is responsible for performing necessary CRUD operations for the properties that need to be added
+ * using other external services.
+ * The Action Management Service ensures that only the properties returned by this method are stored.
+ *
+ * @param actionDTO ActionDTO object.
+ * @param tenantDomain Tenant domain.
+ * @return ActionDTO object with resolved properties.
+ * @throws ActionDTOModelResolverException If an error occurs while resolving the properties.
+ */
+ ActionDTO resolveForAddOperation(ActionDTO actionDTO, String tenantDomain) throws ActionDTOModelResolverException;
+
+ /**
+ * Populate the properties according to the references stored in the Action Management Service.
+ * This method is responsible for populating the properties that need to be retrieved using other external services.
+ * The Action Management Service ensures that only the properties populated by this method are included in the
+ * returned ActionDTO object.
+ *
+ * @param actionDTO ActionDTO object with properties references.
+ * @param tenantDomain Tenant domain.
+ * @return ActionDTO object with populated properties.
+ * @throws ActionDTOModelResolverException If an error occurs while populating the properties.
+ */
+ ActionDTO resolveForGetOperation(ActionDTO actionDTO, String tenantDomain) throws ActionDTOModelResolverException;
+
+ /**
+ * Populate the properties of the given ActionDTO list according to the references stored in the Action Management
+ * Service.
+ * This method is responsible for populating the properties that need to be retrieved using other external services.
+ * The Action Management Service ensures that only the properties populated by this method are included in the
+ * returned ActionDTO object list.
+ *
+ * @param actionDTOList List of ActionDTO objects with properties references.
+ * @param tenantDomain Tenant domain.
+ * @return List of ActionDTO objects with populated properties.
+ * @throws ActionDTOModelResolverException If an error occurs while populating the properties.
+ */
+ List resolveForGetOperation(List actionDTOList, String tenantDomain)
+ throws ActionDTOModelResolverException;
+
+ /**
+ * Resolve the properties that need to be updated in the Action Management Service.
+ * This method is responsible for performing necessary CRUD operations for the properties that need to be updated
+ * using other external services.
+ * The Action Management Service ensures that only the properties returned by this method are updated.
+ *
+ * @param updatingActionDTO ActionDTO object with updated properties.
+ * @param existingActionDTO ActionDTO object with existing properties.
+ * @param tenantDomain Tenant domain.
+ * @return ActionDTO object with resolved properties.
+ * @throws ActionDTOModelResolverException If an error occurs while resolving the properties.
+ */
+ ActionDTO resolveForUpdateOperation(ActionDTO updatingActionDTO, ActionDTO existingActionDTO, String tenantDomain)
+ throws ActionDTOModelResolverException;
+
+ /**
+ * Delete the properties that need to be deleted in the Action Management Service.
+ * This method is responsible for performing necessary CRUD operations for the properties that need to be deleted
+ * using other external services.
+ *
+ * @param deletingActionDTO ActionDTO object with properties to be deleted.
+ * @param tenantDomain Tenant domain.
+ * @throws ActionDTOModelResolverException If an error occurs while deleting the properties.
+ */
+ void resolveForDeleteOperation(ActionDTO deletingActionDTO, String tenantDomain)
+ throws ActionDTOModelResolverException;
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementService.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/ActionManagementService.java
similarity index 98%
rename from components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementService.java
rename to components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/ActionManagementService.java
index fe1851cb1b13..62b121127510 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementService.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/ActionManagementService.java
@@ -16,7 +16,7 @@
* under the License.
*/
-package org.wso2.carbon.identity.action.management;
+package org.wso2.carbon.identity.action.management.service;
import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
import org.wso2.carbon.identity.action.management.model.Action;
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/impl/ActionConverterFactory.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/impl/ActionConverterFactory.java
new file mode 100644
index 000000000000..43388a915d6c
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/impl/ActionConverterFactory.java
@@ -0,0 +1,60 @@
+/*
+ * 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.carbon.identity.action.management.service.impl;
+
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.service.ActionConverter;
+
+import java.util.EnumMap;
+import java.util.Map;
+
+/**
+ * This class defines the Action Converter Factory.
+ * Action Converter Factory is the component that is responsible for providing the {@link ActionConverter}
+ * based on the action type.
+ */
+public class ActionConverterFactory {
+
+ private static final Map actionConverters =
+ new EnumMap<>(Action.ActionTypes.class);
+
+ private ActionConverterFactory() {
+ }
+
+ public static ActionConverter getActionConverter(Action.ActionTypes actionType) {
+
+ switch (actionType) {
+ case PRE_UPDATE_PASSWORD:
+ return actionConverters.get(Action.ActionTypes.PRE_UPDATE_PASSWORD);
+ case PRE_ISSUE_ACCESS_TOKEN:
+ default:
+ return null;
+ }
+ }
+
+ public static void registerActionConverter(ActionConverter actionConverter) {
+
+ actionConverters.put(actionConverter.getSupportedActionType(), actionConverter);
+ }
+
+ public static void unregisterActionConverter(ActionConverter actionConverter) {
+
+ actionConverters.remove(actionConverter.getSupportedActionType());
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImpl.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/impl/ActionManagementServiceImpl.java
similarity index 69%
rename from components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImpl.java
rename to components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/impl/ActionManagementServiceImpl.java
index 33fd7ca6a465..aaa8168b30e0 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImpl.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/impl/ActionManagementServiceImpl.java
@@ -16,20 +16,25 @@
* under the License.
*/
-package org.wso2.carbon.identity.action.management;
+package org.wso2.carbon.identity.action.management.service.impl;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.identity.action.management.constant.ActionMgtConstants;
+import org.wso2.carbon.identity.action.management.constant.error.ErrorMessage;
+import org.wso2.carbon.identity.action.management.dao.impl.ActionManagementDAOFacade;
import org.wso2.carbon.identity.action.management.dao.impl.ActionManagementDAOImpl;
-import org.wso2.carbon.identity.action.management.dao.impl.CacheBackedActionMgtDAO;
import org.wso2.carbon.identity.action.management.exception.ActionMgtClientException;
import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.ActionDTO;
import org.wso2.carbon.identity.action.management.model.Authentication;
import org.wso2.carbon.identity.action.management.model.EndpointConfig;
+import org.wso2.carbon.identity.action.management.service.ActionConverter;
+import org.wso2.carbon.identity.action.management.service.ActionManagementService;
+import org.wso2.carbon.identity.action.management.util.ActionDTOBuilder;
import org.wso2.carbon.identity.action.management.util.ActionManagementAuditLogger;
-import org.wso2.carbon.identity.action.management.util.ActionManagementUtil;
+import org.wso2.carbon.identity.action.management.util.ActionManagementExceptionHandler;
import org.wso2.carbon.identity.action.management.util.ActionValidator;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
import org.wso2.carbon.identity.core.util.IdentityUtil;
@@ -38,6 +43,7 @@
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import java.util.stream.Collectors;
/**
* Action management service.
@@ -45,20 +51,10 @@
public class ActionManagementServiceImpl implements ActionManagementService {
private static final Log LOG = LogFactory.getLog(ActionManagementServiceImpl.class);
- private static final ActionManagementService INSTANCE = new ActionManagementServiceImpl();
- private static final CacheBackedActionMgtDAO CACHE_BACKED_DAO =
- new CacheBackedActionMgtDAO(new ActionManagementDAOImpl());
+ private static final ActionManagementDAOFacade DAO_FACADE =
+ new ActionManagementDAOFacade(new ActionManagementDAOImpl());
private static final ActionValidator ACTION_VALIDATOR = new ActionValidator();
private static final ActionManagementAuditLogger auditLogger = new ActionManagementAuditLogger();
- private static final ActionSecretProcessor ACTION_SECRET_PROCESSOR = new ActionSecretProcessor();
-
- private ActionManagementServiceImpl() {
- }
-
- public static ActionManagementService getInstance() {
-
- return INSTANCE;
- }
/**
* Create a new action of the specified type in the given tenant.
@@ -76,13 +72,16 @@ public Action addAction(String actionType, Action action, String tenantDomain) t
LOG.debug(String.format("Adding Action for Action Type: %s.", actionType));
}
String resolvedActionType = getActionTypeFromPath(actionType);
+ doPreAddActionValidations(action);
// Check whether the maximum allowed actions per type is reached.
validateMaxActionsPerType(resolvedActionType, tenantDomain);
- doPreAddActionValidations(action);
String generatedActionId = UUID.randomUUID().toString();
- Action createdAction = CACHE_BACKED_DAO.addAction(resolvedActionType, generatedActionId, action,
- IdentityTenantUtil.getTenantId(tenantDomain));
- auditLogger.printAuditLog(ActionManagementAuditLogger.Operation.ADD, createdAction);
+ ActionDTO creatingActionDTO = buildActionDTO(resolvedActionType, generatedActionId, action);
+
+ DAO_FACADE.addAction(creatingActionDTO, IdentityTenantUtil.getTenantId(tenantDomain));
+ Action createdAction = getActionByActionId(actionType, generatedActionId, tenantDomain);
+ auditLogger.printAuditLog(ActionManagementAuditLogger.Operation.ADD, creatingActionDTO);
+
return createdAction;
}
@@ -100,8 +99,36 @@ public List getActionsByActionType(String actionType, String tenantDomai
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Retrieving Actions for Action Type: %s.", actionType));
}
- return CACHE_BACKED_DAO.getActionsByActionType(getActionTypeFromPath(actionType),
+ String resolvedActionType = getActionTypeFromPath(actionType);
+ List actionDTOS = DAO_FACADE.getActionsByActionType(resolvedActionType,
+ IdentityTenantUtil.getTenantId(tenantDomain));
+
+ return actionDTOS.stream()
+ .map(actionDTO -> buildAction(resolvedActionType, actionDTO))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Retrieve an action by action ID.
+ *
+ * @param actionType Action type.
+ * @param actionId Action ID.
+ * @param tenantDomain Tenant domain.
+ * @return Action object.
+ * @throws ActionMgtException if an error occurred while retrieving the action.
+ */
+ @Override
+ public Action getActionByActionId(String actionType, String actionId, String tenantDomain)
+ throws ActionMgtException {
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(String.format("Retrieving Action of Action ID: %s", actionId));
+ }
+ String resolvedActionType = getActionTypeFromPath(actionType);
+ ActionDTO actionDTO = DAO_FACADE.getActionByActionId(resolvedActionType, actionId,
IdentityTenantUtil.getTenantId(tenantDomain));
+
+ return buildAction(resolvedActionType, actionDTO);
}
/**
@@ -125,12 +152,13 @@ public Action updateAction(String actionType, String actionId, Action action, St
LOG.debug(String.format("Updating Action for Action Type: %s and Action ID: %s.", actionType, actionId));
}
String resolvedActionType = getActionTypeFromPath(actionType);
- Action existingAction = checkIfActionExists(resolvedActionType, actionId, tenantDomain);
doPreUpdateActionValidations(action);
- Action updatedAction = CACHE_BACKED_DAO.updateAction(resolvedActionType, actionId, action, existingAction,
- IdentityTenantUtil.getTenantId(tenantDomain));
- auditLogger.printAuditLog(ActionManagementAuditLogger.Operation.UPDATE, actionId, action);
- return updatedAction;
+ ActionDTO existingActionDTO = checkIfActionExists(resolvedActionType, actionId, tenantDomain);
+ ActionDTO updatingActionDTO = buildActionDTO(resolvedActionType, actionId, action);
+
+ DAO_FACADE.updateAction(updatingActionDTO, existingActionDTO, IdentityTenantUtil.getTenantId(tenantDomain));
+ auditLogger.printAuditLog(ActionManagementAuditLogger.Operation.UPDATE, updatingActionDTO);
+ return getActionByActionId(actionType, actionId, tenantDomain);
}
/**
@@ -147,11 +175,12 @@ public void deleteAction(String actionType, String actionId, String tenantDomain
if (LOG.isDebugEnabled()) {
LOG.debug(String.format("Deleting Action for Action Type: %s and Action ID: %s", actionType, actionId));
}
- String resolvedActionType = getActionTypeFromPath(actionType);
- Action action = checkIfActionExists(resolvedActionType, actionId, tenantDomain);
- CACHE_BACKED_DAO.deleteAction(resolvedActionType, actionId, action,
+ ActionDTO existingActionDTO = DAO_FACADE.getActionByActionId(getActionTypeFromPath(actionType), actionId,
IdentityTenantUtil.getTenantId(tenantDomain));
- auditLogger.printAuditLog(ActionManagementAuditLogger.Operation.DELETE, actionType, actionId);
+ if (existingActionDTO != null) {
+ DAO_FACADE.deleteAction(existingActionDTO, IdentityTenantUtil.getTenantId(tenantDomain));
+ auditLogger.printAuditLog(ActionManagementAuditLogger.Operation.DELETE, actionType, actionId);
+ }
}
/**
@@ -161,7 +190,7 @@ public void deleteAction(String actionType, String actionId, String tenantDomain
* @param actionId Action ID.
* @param tenantDomain Tenant domain.
* @return Activated action.
- * @throws ActionMgtException if an error occurred while activating the action.
+ * @throws ActionMgtException If an error occurred while activating the action.
*/
@Override
public Action activateAction(String actionType, String actionId, String tenantDomain) throws ActionMgtException {
@@ -171,10 +200,10 @@ public Action activateAction(String actionType, String actionId, String tenantDo
}
String resolvedActionType = getActionTypeFromPath(actionType);
checkIfActionExists(resolvedActionType, actionId, tenantDomain);
- Action activatedAction = CACHE_BACKED_DAO.activateAction(resolvedActionType, actionId,
+ ActionDTO activatedActionDTO = DAO_FACADE.activateAction(resolvedActionType, actionId,
IdentityTenantUtil.getTenantId(tenantDomain));
auditLogger.printAuditLog(ActionManagementAuditLogger.Operation.ACTIVATE, actionType, actionId);
- return activatedAction;
+ return buildAction(resolvedActionType, activatedActionDTO);
}
/**
@@ -184,7 +213,7 @@ public Action activateAction(String actionType, String actionId, String tenantDo
* @param actionId Action ID.
* @param tenantDomain Tenant domain.
* @return deactivated action.
- * @throws ActionMgtException if an error occurred while deactivating the action.
+ * @throws ActionMgtException If an error occurred while deactivating the action.
*/
@Override
public Action deactivateAction(String actionType, String actionId, String tenantDomain) throws ActionMgtException {
@@ -195,10 +224,10 @@ public Action deactivateAction(String actionType, String actionId, String tenant
}
String resolvedActionType = getActionTypeFromPath(actionType);
checkIfActionExists(resolvedActionType, actionId, tenantDomain);
- Action deactivatedAction = CACHE_BACKED_DAO.deactivateAction(resolvedActionType, actionId,
+ ActionDTO deactivatedActionDTO = DAO_FACADE.deactivateAction(resolvedActionType, actionId,
IdentityTenantUtil.getTenantId(tenantDomain));
auditLogger.printAuditLog(ActionManagementAuditLogger.Operation.DEACTIVATE, actionType, actionId);
- return deactivatedAction;
+ return buildAction(resolvedActionType, deactivatedActionDTO);
}
/**
@@ -214,27 +243,7 @@ public Map getActionsCountPerType(String tenantDomain) throws A
if (LOG.isDebugEnabled()) {
LOG.debug("Retrieving Actions count per Type.");
}
- return CACHE_BACKED_DAO.getActionsCountPerType(IdentityTenantUtil.getTenantId(tenantDomain));
- }
-
- /**
- * Retrieve an action by action ID.
- *
- * @param actionType Action type.
- * @param actionId Action ID.
- * @param tenantDomain Tenant domain.
- * @return Action object.
- * @throws ActionMgtException if an error occurred while retrieving the action.
- */
- @Override
- public Action getActionByActionId(String actionType, String actionId, String tenantDomain)
- throws ActionMgtException {
-
- if (LOG.isDebugEnabled()) {
- LOG.debug(String.format("Retrieving Action of Action ID: %s", actionId));
- }
- return CACHE_BACKED_DAO.getActionByActionId(getActionTypeFromPath(actionType), actionId,
- IdentityTenantUtil.getTenantId(tenantDomain));
+ return DAO_FACADE.getActionsCountPerType(IdentityTenantUtil.getTenantId(tenantDomain));
}
/**
@@ -251,16 +260,13 @@ public Action getActionByActionId(String actionType, String actionId, String ten
public Action updateActionEndpointAuthentication(String actionType, String actionId, Authentication authentication,
String tenantDomain) throws ActionMgtException {
- String resolvedActionType = getActionTypeFromPath(actionType);
- Action existingAction = checkIfActionExists(resolvedActionType, actionId, tenantDomain);
- doEndpointAuthenticationValidation(authentication);
- if (existingAction.getEndpoint().getAuthentication().getType().equals(authentication.getType())) {
- // Only need to update the properties since the authentication type is same.
- return updateEndpointAuthenticationProperties(resolvedActionType, actionId, authentication, tenantDomain);
- } else {
- // Need to update the authentication type and properties.
- return updateEndpoint(resolvedActionType, actionId, existingAction, authentication, tenantDomain);
- }
+ Action updatingAction = new Action.ActionRequestBuilder()
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .authentication(authentication)
+ .build())
+ .build();
+
+ return updateAction(actionType, actionId, updatingAction, tenantDomain);
}
/**
@@ -276,8 +282,8 @@ private String getActionTypeFromPath(String actionType) throws ActionMgtClientEx
.filter(type -> type.getPathParam().equals(actionType))
.map(Action.ActionTypes::getActionType)
.findFirst()
- .orElseThrow(() -> ActionManagementUtil.handleClientException(
- ActionMgtConstants.ErrorMessages.ERROR_INVALID_ACTION_TYPE));
+ .orElseThrow(() ->
+ ActionManagementExceptionHandler.handleClientException(ErrorMessage.ERROR_INVALID_ACTION_TYPE));
}
/**
@@ -289,11 +295,15 @@ private String getActionTypeFromPath(String actionType) throws ActionMgtClientEx
*/
private void validateMaxActionsPerType(String actionType, String tenantDomain) throws ActionMgtException {
+ // In-flow actions are not limited by the maximum actions per action type; eg: AUTHENTICATION action type.
+ if (Action.ActionTypes.Category.IN_FLOW.equals(Action.ActionTypes.valueOf(actionType).getCategory())) {
+ return;
+ }
Map actionsCountPerType = getActionsCountPerType(tenantDomain);
if (actionsCountPerType.containsKey(actionType) &&
actionsCountPerType.get(actionType) >= IdentityUtil.getMaximumActionsPerActionType()) {
- throw ActionManagementUtil.handleClientException(
- ActionMgtConstants.ErrorMessages.ERROR_MAXIMUM_ACTIONS_PER_ACTION_TYPE_REACHED);
+ throw ActionManagementExceptionHandler.handleClientException(
+ ErrorMessage.ERROR_MAXIMUM_ACTIONS_PER_ACTION_TYPE_REACHED);
}
}
@@ -303,75 +313,27 @@ private void validateMaxActionsPerType(String actionType, String tenantDomain) t
* @param actionType Action Type.
* @param actionId Action ID.
* @param tenantDomain Tenant Domain.
+ * @return ActionDTO if the action exists.
* @throws ActionMgtException If the action does not exist.
*/
- private Action checkIfActionExists(String actionType, String actionId, String tenantDomain)
+ private ActionDTO checkIfActionExists(String actionType, String actionId, String tenantDomain)
throws ActionMgtException {
- Action action = CACHE_BACKED_DAO.getActionByActionId(actionType, actionId,
+ ActionDTO actionDTO = DAO_FACADE.getActionByActionId(actionType, actionId,
IdentityTenantUtil.getTenantId(tenantDomain));
- if (action == null || !actionType.equals(action.getType().name())) {
- throw ActionManagementUtil.handleClientException(
- ActionMgtConstants.ErrorMessages.ERROR_NO_ACTION_CONFIGURED_ON_GIVEN_ACTION_TYPE_AND_ID);
+ if (actionDTO == null || !actionType.equals(actionDTO.getType().name())) {
+ throw ActionManagementExceptionHandler.handleClientException(
+ ErrorMessage.ERROR_NO_ACTION_CONFIGURED_ON_GIVEN_ACTION_TYPE_AND_ID);
}
- return action;
- }
-
- /**
- * Update the authentication type and properties of the action endpoint.
- *
- * @param actionType Action Type.
- * @param actionId Action Id.
- * @param existingAction Existing Action Information.
- * @param authentication Authentication Information to be updated.
- * @param tenantDomain Tenant Domain.
- * @return Action response after update.
- * @throws ActionMgtException If an error occurs while updating action endpoint authentication.
- */
- private Action updateEndpoint(String actionType, String actionId, Action existingAction,
- Authentication authentication, String tenantDomain)
- throws ActionMgtException {
-
- if (LOG.isDebugEnabled()) {
- LOG.debug(String.format("Updating endpoint authentication of Action Type: %s " +
- "and Action ID: %s to Authentication Type: %s", actionType, actionId,
- authentication.getType().name()));
- }
- EndpointConfig endpoint = new EndpointConfig.EndpointConfigBuilder()
- .uri(existingAction.getEndpoint().getUri())
- .authentication(authentication).build();
- return CACHE_BACKED_DAO.updateActionEndpoint(actionType, actionId, endpoint,
- existingAction.getEndpoint().getAuthentication(), IdentityTenantUtil.getTenantId(tenantDomain));
- }
-
- /**
- * Update the authentication properties of the action endpoint.
- *
- * @param actionType Action Type.
- * @param actionId Action Id.
- * @param authentication Authentication Information to be updated.
- * @param tenantDomain Tenant domain.
- * @return Action response after update.
- * @throws ActionMgtException If an error occurs while updating action endpoint authentication properties.
- */
- private Action updateEndpointAuthenticationProperties(String actionType, String actionId,
- Authentication authentication, String tenantDomain)
- throws ActionMgtException {
- if (LOG.isDebugEnabled()) {
- LOG.debug(String.format("Updating endpoint authentication properties of Action Type: %s " +
- "Action ID: %s and Authentication Type: %s", actionType, actionId,
- authentication.getType().name()));
- }
- return CACHE_BACKED_DAO.updateActionEndpointAuthProperties(actionType, actionId, authentication,
- IdentityTenantUtil.getTenantId(tenantDomain));
+ return actionDTO;
}
/**
* Perform pre validations on action model when creating an action.
*
- * @param action Action create model.
- * @throws ActionMgtException if action model is invalid.
+ * @param action Action creation model.
+ * @throws ActionMgtClientException if action model is invalid.
*/
private void doPreAddActionValidations(Action action) throws ActionMgtClientException {
@@ -384,8 +346,7 @@ private void doPreAddActionValidations(Action action) throws ActionMgtClientExce
/**
* Perform pre validations on action model when updating an existing action.
- * This is specifically used during HTTP PATCH operation and
- * only validate non-null and non-empty fields.
+ * This is specifically used during HTTP PATCH operation and only validate non-null and non-empty fields.
*
* @param action Action update model.
* @throws ActionMgtClientException if action model is invalid.
@@ -432,6 +393,50 @@ private void doEndpointAuthenticationValidation(Authentication authentication) t
ACTION_VALIDATOR.validateForBlank(ActionMgtConstants.API_KEY_VALUE_FIELD,
authentication.getProperty(Authentication.Property.VALUE).getValue());
break;
+ case NONE:
+ default:
+ break;
+ }
+ }
+
+ private ActionDTO buildActionDTO(String actionType, String actionId, Action action) {
+
+ ActionConverter actionConverter =
+ ActionConverterFactory.getActionConverter(Action.ActionTypes.valueOf(actionType));
+ if (actionConverter != null) {
+ ActionDTO actionDTO = actionConverter.buildActionDTO(action);
+
+ return new ActionDTOBuilder(actionDTO)
+ .id(actionId)
+ .type(Action.ActionTypes.valueOf(actionType))
+ .build();
+ }
+
+ return new ActionDTOBuilder(action)
+ .id(actionId)
+ .type(Action.ActionTypes.valueOf(actionType))
+ .build();
+ }
+
+ private Action buildAction(String actionType, ActionDTO actionDTO) {
+
+ if (actionDTO == null) {
+ return null;
}
+
+ ActionConverter actionConverter =
+ ActionConverterFactory.getActionConverter(Action.ActionTypes.valueOf(actionType));
+ if (actionConverter != null) {
+ return actionConverter.buildAction(actionDTO);
+ }
+
+ return new Action.ActionResponseBuilder()
+ .id(actionDTO.getId())
+ .type(actionDTO.getType())
+ .name(actionDTO.getName())
+ .description(actionDTO.getDescription())
+ .status(actionDTO.getStatus())
+ .endpoint(actionDTO.getEndpoint())
+ .build();
}
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/CacheBackedActionMgtDAO.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/impl/CacheBackedActionManagementService.java
similarity index 63%
rename from components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/CacheBackedActionMgtDAO.java
rename to components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/impl/CacheBackedActionManagementService.java
index 1ef2ff2d3ca3..616678aeb8e7 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/dao/impl/CacheBackedActionMgtDAO.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/service/impl/CacheBackedActionManagementService.java
@@ -16,7 +16,7 @@
* under the License.
*/
-package org.wso2.carbon.identity.action.management.dao.impl;
+package org.wso2.carbon.identity.action.management.service.impl;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
@@ -24,43 +24,47 @@
import org.wso2.carbon.identity.action.management.cache.ActionCacheByType;
import org.wso2.carbon.identity.action.management.cache.ActionCacheEntry;
import org.wso2.carbon.identity.action.management.cache.ActionTypeCacheKey;
-import org.wso2.carbon.identity.action.management.dao.ActionManagementDAO;
import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
import org.wso2.carbon.identity.action.management.model.Action;
import org.wso2.carbon.identity.action.management.model.Authentication;
-import org.wso2.carbon.identity.action.management.model.EndpointConfig;
+import org.wso2.carbon.identity.action.management.service.ActionManagementService;
import java.util.List;
import java.util.Map;
/**
- * This class implements the {@link ActionManagementDAO} interface.
+ * CacheBackedActionManagementService act as the caching layer for the Action Management Service.
*/
-public class CacheBackedActionMgtDAO implements ActionManagementDAO {
+public class CacheBackedActionManagementService implements ActionManagementService {
- private static final Log LOG = LogFactory.getLog(CacheBackedActionMgtDAO.class);
+ private static final CacheBackedActionManagementService INSTANCE = new CacheBackedActionManagementService();
+ private static final Log LOG = LogFactory.getLog(CacheBackedActionManagementService.class);
+ private static final ActionManagementServiceImpl ACTION_MGT_SERVICE = new ActionManagementServiceImpl();
private final ActionCacheByType actionCacheByType;
- private final ActionManagementDAO actionManagementDAO;
- public CacheBackedActionMgtDAO(ActionManagementDAO actionManagementDAO) {
+ private CacheBackedActionManagementService() {
- this.actionManagementDAO = actionManagementDAO;
actionCacheByType = ActionCacheByType.getInstance();
}
+ public static CacheBackedActionManagementService getInstance() {
+
+ return INSTANCE;
+ }
+
@Override
- public Action addAction(String actionType, String actionId, Action action, Integer tenantId)
- throws ActionMgtException {
+ public Action addAction(String actionType, Action action, String tenantDomain) throws ActionMgtException {
- actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantId);
- return actionManagementDAO.addAction(actionType, actionId, action, tenantId);
+ Action createdAction = ACTION_MGT_SERVICE.addAction(actionType, action, tenantDomain);
+ actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantDomain);
+ return createdAction;
}
@Override
- public List getActionsByActionType(String actionType, Integer tenantId) throws ActionMgtException {
+ public List getActionsByActionType(String actionType, String tenantDomain) throws ActionMgtException {
ActionTypeCacheKey cacheKey = new ActionTypeCacheKey(actionType);
- ActionCacheEntry entry = actionCacheByType.getValueFromCache(cacheKey, tenantId);
+ ActionCacheEntry entry = actionCacheByType.getValueFromCache(cacheKey, tenantDomain);
if (entry != null) {
if (LOG.isDebugEnabled()) {
@@ -68,72 +72,37 @@ public List getActionsByActionType(String actionType, Integer tenantId)
}
return entry.getActions();
}
-
if (LOG.isDebugEnabled()) {
LOG.debug("Cache entry not found for Action Type " + actionType + ". Fetching entry from DB.");
}
- List actions = actionManagementDAO.getActionsByActionType(actionType, tenantId);
+ List actions = ACTION_MGT_SERVICE.getActionsByActionType(actionType, tenantDomain);
if (actions != null && !actions.isEmpty()) {
if (LOG.isDebugEnabled()) {
LOG.debug("Entry fetched from DB for Action Type " + actionType + ". Updating cache.");
}
- actionCacheByType.addToCache(cacheKey, new ActionCacheEntry(actions), tenantId);
+ actionCacheByType.addToCache(cacheKey, new ActionCacheEntry(actions), tenantDomain);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Entry for Action Type " + actionType + " not found in cache or DB.");
}
}
- return actions;
- }
-
- @Override
- public Action updateAction(String actionType, String actionId, Action updatingAction, Action existingAction,
- Integer tenantId) throws ActionMgtException {
- actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantId);
- return actionManagementDAO.updateAction(actionType, actionId, updatingAction, existingAction, tenantId);
+ return actions;
}
@Override
- public void deleteAction(String actionType, String actionId, Action action, Integer tenantId)
+ public Action getActionByActionId(String actionType, String actionId, String tenantDomain)
throws ActionMgtException {
- actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantId);
- actionManagementDAO.deleteAction(actionType, actionId, action, tenantId);
- }
-
- @Override
- public Action activateAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException {
-
- actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantId);
- return actionManagementDAO.activateAction(actionType, actionId, tenantId);
- }
-
- @Override
- public Action deactivateAction(String actionType, String actionId, Integer tenantId) throws ActionMgtException {
-
- actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantId);
- return actionManagementDAO.deactivateAction(actionType, actionId, tenantId);
- }
-
- @Override
- public Map getActionsCountPerType(Integer tenantId) throws ActionMgtException {
-
- return actionManagementDAO.getActionsCountPerType(tenantId);
- }
-
- @Override
- public Action getActionByActionId(String actionType, String actionId, Integer tenantId) throws ActionMgtException {
-
ActionTypeCacheKey cacheKey = new ActionTypeCacheKey(actionType);
- ActionCacheEntry entry = actionCacheByType.getValueFromCache(cacheKey, tenantId);
+ ActionCacheEntry entry = actionCacheByType.getValueFromCache(cacheKey, tenantDomain);
/* If the entry for the given action type is not null, get the action list from cache and iterate to get the
action by matching action id. */
if (entry != null) {
- for (Action action: entry.getActions()) {
+ for (Action action : entry.getActions()) {
if (StringUtils.equals(action.getId(), actionId)) {
LOG.debug("Action is found from the cache with action Id " + actionId);
return action;
@@ -145,9 +114,9 @@ public Action getActionByActionId(String actionType, String actionId, Integer te
LOG.debug("Action is not found from the cache with action Id " + actionId + ". Fetching entry from DB.");
}
- Action action = actionManagementDAO.getActionByActionId(actionType, actionId, tenantId);
+ Action action = ACTION_MGT_SERVICE.getActionByActionId(actionType, actionId, tenantDomain);
if (action != null) {
- updateCache(action, entry, cacheKey, tenantId);
+ updateCache(action, entry, cacheKey, tenantDomain);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Action with action Id " + actionId + " is not found in cache or DB.");
@@ -158,23 +127,54 @@ public Action getActionByActionId(String actionType, String actionId, Integer te
}
@Override
- public Action updateActionEndpointAuthProperties(String actionType, String actionId, Authentication authentication,
- int tenantId) throws ActionMgtException {
+ public Action updateAction(String actionType, String actionId, Action action, String tenantDomain)
+ throws ActionMgtException {
- return actionManagementDAO.updateActionEndpointAuthProperties(actionType, actionId, authentication, tenantId);
+ Action updatedAction = ACTION_MGT_SERVICE.updateAction(actionType, actionId, action, tenantDomain);
+ actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantDomain);
+ return updatedAction;
}
@Override
- public Action updateActionEndpoint(String actionType, String actionId, EndpointConfig endpoint,
- Authentication currentAuthentication, int tenantId)
- throws ActionMgtException {
+ public void deleteAction(String actionType, String actionId, String tenantDomain) throws ActionMgtException {
+
+ actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantDomain);
+ ACTION_MGT_SERVICE.deleteAction(actionType, actionId, tenantDomain);
+ }
+
+ @Override
+ public Action activateAction(String actionType, String actionId, String tenantDomain) throws ActionMgtException {
+
+ Action activatedAction = ACTION_MGT_SERVICE.activateAction(actionType, actionId, tenantDomain);
+ actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantDomain);
+ return activatedAction;
+ }
+
+ @Override
+ public Action deactivateAction(String actionType, String actionId, String tenantDomain) throws ActionMgtException {
+
+ Action deactivatedAction = ACTION_MGT_SERVICE.deactivateAction(actionType, actionId, tenantDomain);
+ actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantDomain);
+ return deactivatedAction;
+ }
+
+ @Override
+ public Map getActionsCountPerType(String tenantDomain) throws ActionMgtException {
+
+ return ACTION_MGT_SERVICE.getActionsCountPerType(tenantDomain);
+ }
+
+ @Override
+ public Action updateActionEndpointAuthentication(String actionType, String actionId, Authentication authentication,
+ String tenantDomain) throws ActionMgtException {
- actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantId);
- return actionManagementDAO.updateActionEndpoint(actionType, actionId, endpoint, currentAuthentication,
- tenantId);
+ Action updatedAction = ACTION_MGT_SERVICE.updateActionEndpointAuthentication(actionType, actionId,
+ authentication, tenantDomain);
+ actionCacheByType.clearCacheEntry(new ActionTypeCacheKey(actionType), tenantDomain);
+ return updatedAction;
}
- private void updateCache(Action action, ActionCacheEntry entry, ActionTypeCacheKey cacheKey, int tenantId) {
+ private void updateCache(Action action, ActionCacheEntry entry, ActionTypeCacheKey cacheKey, String tenantDomain) {
if (LOG.isDebugEnabled()) {
LOG.debug("Entry fetched from DB for Action Id " + action.getId() + ". Updating cache.");
@@ -184,8 +184,8 @@ private void updateCache(Action action, ActionCacheEntry entry, ActionTypeCacheK
if (entry != null) {
List actionsFromCache = entry.getActions();
actionsFromCache.add(action);
- actionCacheByType.clearCacheEntry(cacheKey, tenantId);
- actionCacheByType.addToCache(cacheKey, new ActionCacheEntry(actionsFromCache), tenantId);
+ actionCacheByType.clearCacheEntry(cacheKey, tenantDomain);
+ actionCacheByType.addToCache(cacheKey, new ActionCacheEntry(actionsFromCache), tenantDomain);
}
}
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionDTOBuilder.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionDTOBuilder.java
new file mode 100644
index 000000000000..9e852ee1aee2
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionDTOBuilder.java
@@ -0,0 +1,208 @@
+/*
+ * 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.carbon.identity.action.management.util;
+
+import org.wso2.carbon.identity.action.management.constant.ActionMgtConstants;
+import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
+import org.wso2.carbon.identity.action.management.exception.ActionMgtServerException;
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.ActionDTO;
+import org.wso2.carbon.identity.action.management.model.Authentication;
+import org.wso2.carbon.identity.action.management.model.EndpointConfig;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * Internal Builder class for ActionDTO.
+ */
+public class ActionDTOBuilder {
+
+ private String id;
+ private Action.ActionTypes type;
+ private String name;
+ private String description;
+ private Action.Status status;
+ private EndpointConfig endpoint;
+ private Map properties;
+
+ public ActionDTOBuilder() {
+
+ }
+
+ public ActionDTOBuilder(ActionDTO actionDTO) {
+
+ this.id = actionDTO.getId();
+ this.type = actionDTO.getType();
+ this.name = actionDTO.getName();
+ this.description = actionDTO.getDescription();
+ this.status = actionDTO.getStatus();
+ this.endpoint = actionDTO.getEndpoint();
+ this.properties = actionDTO.getProperties();
+ }
+
+ public ActionDTOBuilder(Action action) {
+
+ this.id = action.getId();
+ this.type = action.getType();
+ this.name = action.getName();
+ this.description = action.getDescription();
+ this.status = action.getStatus();
+ this.endpoint = action.getEndpoint();
+ }
+
+ public ActionDTOBuilder id(String id) {
+
+ this.id = id;
+ return this;
+ }
+
+ public String getId() {
+
+ return this.id;
+ }
+
+ public ActionDTOBuilder type(Action.ActionTypes type) {
+
+ this.type = type;
+ return this;
+ }
+
+ public Action.ActionTypes getType() {
+
+ return this.type;
+ }
+
+ public ActionDTOBuilder name(String name) {
+
+ this.name = name;
+ return this;
+ }
+
+ public String getName() {
+
+ return this.name;
+ }
+
+ public ActionDTOBuilder description(String description) {
+
+ this.description = description;
+ return this;
+ }
+
+ public String getDescription() {
+
+ return this.description;
+ }
+
+ public ActionDTOBuilder status(Action.Status status) {
+
+ this.status = status;
+ return this;
+ }
+
+ public Action.Status getStatus() {
+
+ return this.status;
+ }
+
+ public ActionDTOBuilder endpoint(EndpointConfig endpoint) {
+
+ this.endpoint = endpoint;
+ return this;
+ }
+
+ public EndpointConfig getEndpoint() {
+
+ return this.endpoint;
+ }
+
+ public ActionDTOBuilder setEndpointAndProperties(Map properties) throws
+ ActionMgtException {
+
+ Authentication authentication;
+ Authentication.Type authnType =
+ Authentication.Type.valueOf(properties.remove(ActionMgtConstants.AUTHN_TYPE_PROPERTY));
+ switch (authnType) {
+ case BASIC:
+ authentication = new Authentication.BasicAuthBuilder(
+ properties.remove(Authentication.Property.USERNAME.getName()),
+ properties.remove(Authentication.Property.PASSWORD.getName())).build();
+ break;
+ case BEARER:
+ authentication = new Authentication.BearerAuthBuilder(
+ properties.remove(Authentication.Property.ACCESS_TOKEN.getName())).build();
+ break;
+ case API_KEY:
+ authentication = new Authentication.APIKeyAuthBuilder(
+ properties.remove(Authentication.Property.HEADER.getName()),
+ properties.remove(Authentication.Property.VALUE.getName())).build();
+ break;
+ case NONE:
+ authentication = new Authentication.NoneAuthBuilder().build();
+ break;
+ default:
+ throw new ActionMgtServerException("Authentication type is not defined for the Action Endpoint.");
+ }
+
+ this.endpoint = new EndpointConfig.EndpointConfigBuilder()
+ .uri(properties.remove(ActionMgtConstants.URI_PROPERTY))
+ .authentication(authentication)
+ .build();
+ // Add remaining properties as action properties.
+ this.properties = properties.entrySet().stream()
+ .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
+ return this;
+ }
+
+ public ActionDTOBuilder properties(Map properties) {
+
+ this.properties = properties;
+ return this;
+ }
+
+ public Map getProperties() {
+
+ return this.properties;
+ }
+
+ public ActionDTOBuilder property(String propertyName, Object propertyValue) {
+
+ if (this.properties == null) {
+ this.properties = new HashMap<>();
+ }
+ this.properties.put(propertyName, propertyValue);
+ return this;
+ }
+
+ public ActionDTO build() {
+
+ Action action = new Action.ActionResponseBuilder()
+ .id(this.id)
+ .type(this.type)
+ .name(this.name)
+ .description(this.description)
+ .status(this.status)
+ .endpoint(this.endpoint)
+ .build();
+
+ return new ActionDTO.Builder(action).properties(this.properties).build();
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionManagementAuditLogger.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionManagementAuditLogger.java
index e28920ae8f2e..7dfd313fe95f 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionManagementAuditLogger.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionManagementAuditLogger.java
@@ -22,7 +22,7 @@
import org.json.JSONObject;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.context.CarbonContext;
-import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.ActionDTO;
import org.wso2.carbon.identity.action.management.model.Authentication;
import org.wso2.carbon.identity.action.management.model.EndpointConfig;
import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils;
@@ -31,6 +31,8 @@
import org.wso2.carbon.utils.AuditLog;
import org.wso2.carbon.utils.multitenancy.MultitenantUtils;
+import java.util.Map;
+
import static org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils.jsonObjectToMap;
import static org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils.triggerAuditLogEvent;
@@ -43,30 +45,14 @@ public class ActionManagementAuditLogger {
* Print action audit log related to the operation.
*
* @param operation Operation associated with the state change.
- * @param action Action object to be logged.
- */
- public void printAuditLog(Operation operation, Action action) {
-
- if (!LoggerUtils.isEnableV2AuditLogs()) {
- return;
- }
- JSONObject data = createAuditLogEntry(action);
- buildAuditLog(operation, data);
- }
-
- /**
- * Print action audit log related to the operation by action ID.
- *
- * @param operation Operation associated with the state change.
- * @param actionId ID of the action to be logged.
- * @param action Action object to be logged.
+ * @param actionDTO Action object to be logged.
*/
- public void printAuditLog(Operation operation, String actionId, Action action) {
+ public void printAuditLog(Operation operation, ActionDTO actionDTO) {
if (!LoggerUtils.isEnableV2AuditLogs()) {
return;
}
- JSONObject data = createAuditLogEntry(actionId, action);
+ JSONObject data = createAuditLogEntry(actionDTO);
buildAuditLog(operation, data);
}
@@ -103,44 +89,28 @@ private void buildAuditLog(Operation operation, JSONObject data) {
triggerAuditLogEvent(auditLogBuilder);
}
- /**
- * Create audit log data with action.
- * This method expects all the action fields to be non-null/non-empty.
- *
- * @param action Action to be logged.
- * @return audit log data.
- */
- private JSONObject createAuditLogEntry(Action action) {
-
- JSONObject data = new JSONObject();
- data.put(LogConstants.ACTION_TYPE_FIELD, action.getType());
- data.put(LogConstants.ACTION_ID_FIELD, action.getId());
- data.put(LogConstants.ACTION_NAME_FIELD, action.getName());
- data.put(LogConstants.ACTION_DESCRIPTION_FIELD, action.getDescription());
- data.put(LogConstants.ACTION_STATUS_FIELD, action.getStatus());
- data.put(LogConstants.ENDPOINT_CONFIG_FIELD, getAllEndpointData(action.getEndpoint()));
- return data;
- }
-
/**
* Create audit log data with action and ID.
* This method expects null/empty action fields.
*
- * @param actionId ID of the action to be logged.
- * @param action Action to be logged.
+ * @param actionDTO Action to be logged.
* @return audit log data.
*/
- private JSONObject createAuditLogEntry(String actionId, Action action) {
+ private JSONObject createAuditLogEntry(ActionDTO actionDTO) {
JSONObject data = new JSONObject();
- data.put(LogConstants.ACTION_TYPE_FIELD, action.getType() != null ? action.getType() : JSONObject.NULL);
- data.put(LogConstants.ACTION_ID_FIELD, actionId);
- data.put(LogConstants.ACTION_NAME_FIELD, action.getName() != null ? action.getName() : JSONObject.NULL);
+ data.put(LogConstants.ACTION_TYPE_FIELD, actionDTO.getType() != null ? actionDTO.getType() : JSONObject.NULL);
+ data.put(LogConstants.ACTION_ID_FIELD, actionDTO.getId() != null ? actionDTO.getId() : JSONObject.NULL);
+ data.put(LogConstants.ACTION_NAME_FIELD, actionDTO.getName() != null ? actionDTO.getName() : JSONObject.NULL);
data.put(LogConstants.ACTION_DESCRIPTION_FIELD,
- action.getDescription() != null ? action.getDescription() : JSONObject.NULL);
- data.put(LogConstants.ACTION_STATUS_FIELD, action.getStatus() != null ? action.getStatus() : JSONObject.NULL);
- if (action.getEndpoint() != null) {
- data.put(LogConstants.ENDPOINT_CONFIG_FIELD, getEndpointData(action.getEndpoint()));
+ actionDTO.getDescription() != null ? actionDTO.getDescription() : JSONObject.NULL);
+ data.put(LogConstants.ACTION_STATUS_FIELD, actionDTO.getStatus() != null ? actionDTO.getStatus()
+ : JSONObject.NULL);
+ if (actionDTO.getEndpoint() != null) {
+ data.put(LogConstants.ENDPOINT_CONFIG_FIELD, getEndpointData(actionDTO.getEndpoint()));
+ }
+ if (actionDTO.getProperties() != null && !actionDTO.getProperties().isEmpty()) {
+ data.put(LogConstants.ACTION_PROPERTIES, getPropertiesData(actionDTO.getProperties()));
}
return data;
}
@@ -161,36 +131,17 @@ private JSONObject createAuditLogEntry(String actionType, String actionId) {
}
/**
- * Retrieve complete endpoint configuration data to be logged.
+ * Retrieve properties data to be logged.
+ * All the properties will be masked.
*
- * @param endpointConfig Endpoint data to be logged.
- * @return endpoint config data.
+ * @param properties Properties to be logged.
+ * @return properties data.
*/
- private JSONObject getAllEndpointData(EndpointConfig endpointConfig) {
+ private JSONObject getPropertiesData(Map properties) {
- JSONObject endpointData = new JSONObject();
- endpointData.put(LogConstants.ENDPOINT_URI_FIELD, endpointConfig.getUri());
- Authentication authentication = endpointConfig.getAuthentication();
- endpointData.put(LogConstants.AUTHENTICATION_SCHEME_FIELD, authentication.getType().getName());
- switch (authentication.getType()) {
- case BASIC:
- endpointData.put(LogConstants.USERNAME_FIELD, LoggerUtils.getMaskedContent(authentication.
- getProperty(Authentication.Property.USERNAME).getValue()));
- endpointData.put(LogConstants.PASSWORD_FIELD, LoggerUtils.getMaskedContent(authentication.
- getProperty(Authentication.Property.PASSWORD).getValue()));
- break;
- case BEARER:
- endpointData.put(LogConstants.ACCESS_TOKEN_FIELD, LoggerUtils.getMaskedContent(authentication.
- getProperty(Authentication.Property.ACCESS_TOKEN).getValue()));
- break;
- case API_KEY:
- endpointData.put(LogConstants.API_KEY_HEADER_FIELD, LoggerUtils.getMaskedContent(authentication.
- getProperty(Authentication.Property.HEADER).getValue()));
- endpointData.put(LogConstants.API_KEY_VALUE_FIELD, LoggerUtils.getMaskedContent(authentication.
- getProperty(Authentication.Property.VALUE).getValue()));
- break;
- }
- return endpointData;
+ JSONObject propertiesData = new JSONObject();
+ properties.forEach((key, value) -> propertiesData.put(key, LoggerUtils.getMaskedContent(value.toString())));
+ return propertiesData;
}
/**
@@ -210,26 +161,20 @@ private JSONObject getEndpointData(EndpointConfig endpointConfig) {
endpointData.put(LogConstants.AUTHENTICATION_SCHEME_FIELD, authentication.getType());
switch (authentication.getType()) {
case BASIC:
- endpointData.put(LogConstants.USERNAME_FIELD, LoggerUtils.getMaskedContent(
- authentication.getProperty(Authentication.Property.USERNAME) != null
- ? authentication.getProperty(Authentication.Property.USERNAME).getValue() : ""));
- endpointData.put(LogConstants.PASSWORD_FIELD, LoggerUtils.getMaskedContent(
- authentication.getProperty(Authentication.Property.PASSWORD) != null
- ? authentication.getProperty(Authentication.Property.PASSWORD).getValue() : ""));
+ endpointData.put(LogConstants.USERNAME_FIELD, LoggerUtils.getMaskedContent(authentication.
+ getProperty(Authentication.Property.USERNAME).getValue()));
+ endpointData.put(LogConstants.PASSWORD_FIELD, LoggerUtils.getMaskedContent(authentication.
+ getProperty(Authentication.Property.PASSWORD).getValue()));
break;
case BEARER:
- endpointData.put(LogConstants.ACCESS_TOKEN_FIELD, LoggerUtils.getMaskedContent(
- authentication.getProperty(Authentication.Property.ACCESS_TOKEN) != null
- ? authentication.getProperty(Authentication.Property.ACCESS_TOKEN).
- getValue() : ""));
+ endpointData.put(LogConstants.ACCESS_TOKEN_FIELD, LoggerUtils.getMaskedContent(authentication.
+ getProperty(Authentication.Property.ACCESS_TOKEN).getValue()));
break;
case API_KEY:
- endpointData.put(LogConstants.API_KEY_HEADER_FIELD, LoggerUtils.getMaskedContent(
- authentication.getProperty(Authentication.Property.HEADER) != null
- ? authentication.getProperty(Authentication.Property.HEADER).getValue() : ""));
- endpointData.put(LogConstants.API_KEY_VALUE_FIELD, LoggerUtils.getMaskedContent(
- authentication.getProperty(Authentication.Property.VALUE) != null
- ? authentication.getProperty(Authentication.Property.VALUE).getValue() : ""));
+ endpointData.put(LogConstants.API_KEY_HEADER_FIELD, LoggerUtils.getMaskedContent(authentication.
+ getProperty(Authentication.Property.HEADER).getValue()));
+ endpointData.put(LogConstants.API_KEY_VALUE_FIELD, LoggerUtils.getMaskedContent(authentication.
+ getProperty(Authentication.Property.VALUE).getValue()));
break;
}
}
@@ -310,6 +255,7 @@ private static class LogConstants {
public static final String ACTION_DESCRIPTION_FIELD = "ActionDescription";
public static final String ACTION_STATUS_FIELD = "ActionStatus";
public static final String ENDPOINT_CONFIG_FIELD = "EndpointConfiguration";
+ public static final String ACTION_PROPERTIES = "Properties";
public static final String ENDPOINT_URI_FIELD = "EndpointUri";
public static final String AUTHENTICATION_SCHEME_FIELD = "AuthenticationScheme";
public static final String USERNAME_FIELD = "Username";
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionManagementUtil.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionManagementExceptionHandler.java
similarity index 75%
rename from components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionManagementUtil.java
rename to components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionManagementExceptionHandler.java
index 2ba8cf79da7e..87ece6d5aa6b 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionManagementUtil.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionManagementExceptionHandler.java
@@ -19,15 +19,17 @@
package org.wso2.carbon.identity.action.management.util;
import org.apache.commons.lang.ArrayUtils;
-import org.wso2.carbon.identity.action.management.constant.ActionMgtConstants;
+import org.wso2.carbon.identity.action.management.constant.error.ErrorMessage;
import org.wso2.carbon.identity.action.management.exception.ActionMgtClientException;
-import org.wso2.carbon.identity.action.management.exception.ActionMgtRuntimeException;
import org.wso2.carbon.identity.action.management.exception.ActionMgtServerException;
/**
* Utility class for Action Management.
*/
-public class ActionManagementUtil {
+public class ActionManagementExceptionHandler {
+
+ private ActionManagementExceptionHandler() {
+ }
/**
* Handle Action Management client exceptions.
@@ -36,8 +38,7 @@ public class ActionManagementUtil {
* @param data Data.
* @return ActionMgtClientException.
*/
- public static ActionMgtClientException handleClientException(
- ActionMgtConstants.ErrorMessages error, String... data) {
+ public static ActionMgtClientException handleClientException(ErrorMessage error, String... data) {
String description = error.getDescription();
if (ArrayUtils.isNotEmpty(data)) {
@@ -55,8 +56,7 @@ public static ActionMgtClientException handleClientException(
* @param data Data.
* @return ActionMgtServerException.
*/
- public static ActionMgtServerException handleServerException(
- ActionMgtConstants.ErrorMessages error, Throwable e, String... data) {
+ public static ActionMgtServerException handleServerException(ErrorMessage error, Throwable e, String... data) {
String description = error.getDescription();
if (ArrayUtils.isNotEmpty(data)) {
@@ -65,15 +65,4 @@ public static ActionMgtServerException handleServerException(
return new ActionMgtServerException(error.getMessage(), description, error.getCode(), e);
}
-
- /**
- * Handle Action Management runtime exceptions.
- *
- * @param e Throwable.
- * @return ActionMgtRuntimeException.
- */
- public static ActionMgtRuntimeException handleRuntimeException(String errorMessage, Throwable e) {
-
- return new ActionMgtRuntimeException(errorMessage, e);
- }
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionSecretProcessor.java
similarity index 95%
rename from components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java
rename to components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionSecretProcessor.java
index 6bbb598350f7..4709faf7d0df 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/ActionSecretProcessor.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionSecretProcessor.java
@@ -16,7 +16,7 @@
* under the License.
*/
-package org.wso2.carbon.identity.action.management;
+package org.wso2.carbon.identity.action.management.util;
import org.wso2.carbon.identity.action.management.internal.ActionMgtServiceComponentHolder;
import org.wso2.carbon.identity.action.management.model.AuthProperty;
@@ -36,9 +36,6 @@
*/
public class ActionSecretProcessor {
- public ActionSecretProcessor() {
- }
-
public List encryptAssociatedSecrets(Authentication authentication, String actionId)
throws SecretManagementException {
@@ -54,15 +51,15 @@ public List encryptAssociatedSecrets(Authentication authentication
return encryptedAuthProperties;
}
- public List decryptAssociatedSecrets(List authProperties, String authType,
- String actionId) throws SecretManagementException {
+ public List decryptAssociatedSecrets(Authentication authentication, String actionId)
+ throws SecretManagementException {
List decryptedAuthProperties = new ArrayList<>();
- for (AuthProperty authProperty : authProperties) {
+ for (AuthProperty authProperty : authentication.getProperties()) {
if (!authProperty.getIsConfidential()) {
decryptedAuthProperties.add(authProperty);
} else {
- decryptedAuthProperties.add(decryptProperty(authProperty, authType, actionId));
+ decryptedAuthProperties.add(decryptProperty(authProperty, authentication.getType().name(), actionId));
}
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionValidator.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionValidator.java
index 9de2ed68c026..54851f654ed2 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionValidator.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/main/java/org/wso2/carbon/identity/action/management/util/ActionValidator.java
@@ -20,6 +20,7 @@
import org.apache.commons.lang.StringUtils;
import org.wso2.carbon.identity.action.management.constant.ActionMgtConstants;
+import org.wso2.carbon.identity.action.management.constant.error.ErrorMessage;
import org.wso2.carbon.identity.action.management.exception.ActionMgtClientException;
import java.util.regex.Pattern;
@@ -35,9 +36,9 @@ public class ActionValidator {
// and should start with an alphanumeric character.
private static final String HEADER_REGEX = "^[a-zA-Z0-9][a-zA-Z0-9-.]+$";
- private Pattern actionNameRegexPattern = Pattern.compile(ACTION_NAME_REGEX);
- private Pattern endpointUriRegexPattern = Pattern.compile(ENDPOINT_URI_REGEX);
- private Pattern headerRegexPattern = Pattern.compile(HEADER_REGEX);
+ private final Pattern actionNameRegexPattern = Pattern.compile(ACTION_NAME_REGEX);
+ private final Pattern endpointUriRegexPattern = Pattern.compile(ENDPOINT_URI_REGEX);
+ private final Pattern headerRegexPattern = Pattern.compile(HEADER_REGEX);
/**
* Validate whether required fields exist.
@@ -48,8 +49,8 @@ public class ActionValidator {
public void validateForBlank(String fieldName, String fieldValue) throws ActionMgtClientException {
if (StringUtils.isBlank(fieldValue)) {
- throw ActionManagementUtil.handleClientException(ActionMgtConstants.ErrorMessages.
- ERROR_EMPTY_ACTION_REQUEST_FIELD, fieldName);
+ throw ActionManagementExceptionHandler.handleClientException(ErrorMessage.ERROR_EMPTY_ACTION_REQUEST_FIELD,
+ fieldName);
}
}
@@ -63,8 +64,8 @@ public void validateActionName(String name) throws ActionMgtClientException {
boolean isValidName = actionNameRegexPattern.matcher(name).matches();
if (!isValidName) {
- throw ActionManagementUtil.handleClientException(ActionMgtConstants.ErrorMessages.
- ERROR_INVALID_ACTION_REQUEST_FIELD, ActionMgtConstants.ACTION_NAME_FIELD);
+ throw ActionManagementExceptionHandler.handleClientException(
+ ErrorMessage.ERROR_INVALID_ACTION_REQUEST_FIELD, ActionMgtConstants.ACTION_NAME_FIELD);
}
}
@@ -78,8 +79,8 @@ public void validateEndpointUri(String uri) throws ActionMgtClientException {
boolean isValidUri = endpointUriRegexPattern.matcher(uri).matches();
if (!isValidUri) {
- throw ActionManagementUtil.handleClientException(ActionMgtConstants.ErrorMessages.
- ERROR_INVALID_ACTION_REQUEST_FIELD, ActionMgtConstants.ENDPOINT_URI_FIELD);
+ throw ActionManagementExceptionHandler.handleClientException(
+ ErrorMessage.ERROR_INVALID_ACTION_REQUEST_FIELD, ActionMgtConstants.ENDPOINT_URI_FIELD);
}
}
@@ -93,8 +94,8 @@ public void validateHeader(String header) throws ActionMgtClientException {
boolean isValidHeader = headerRegexPattern.matcher(header).matches();
if (!isValidHeader) {
- throw ActionManagementUtil.handleClientException(ActionMgtConstants.ErrorMessages.
- ERROR_INVALID_ACTION_REQUEST_FIELD, ActionMgtConstants.API_KEY_HEADER_FIELD);
+ throw ActionManagementExceptionHandler.handleClientException(
+ ErrorMessage.ERROR_INVALID_ACTION_REQUEST_FIELD, ActionMgtConstants.API_KEY_HEADER_FIELD);
}
}
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImplTest.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImplTest.java
deleted file mode 100644
index 949efc721833..000000000000
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/ActionManagementServiceImplTest.java
+++ /dev/null
@@ -1,369 +0,0 @@
-/*
- * 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.carbon.identity.action.management;
-
-import org.mockito.MockedStatic;
-import org.testng.Assert;
-import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.Test;
-import org.wso2.carbon.context.CarbonContext;
-import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
-import org.wso2.carbon.identity.action.management.internal.ActionMgtServiceComponentHolder;
-import org.wso2.carbon.identity.action.management.model.Action;
-import org.wso2.carbon.identity.action.management.model.AuthProperty;
-import org.wso2.carbon.identity.action.management.model.Authentication;
-import org.wso2.carbon.identity.action.management.model.EndpointConfig;
-import org.wso2.carbon.identity.common.testng.WithCarbonHome;
-import org.wso2.carbon.identity.common.testng.WithH2Database;
-import org.wso2.carbon.identity.common.testng.WithRealmService;
-import org.wso2.carbon.identity.core.internal.IdentityCoreServiceDataHolder;
-import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil;
-import org.wso2.carbon.identity.secret.mgt.core.SecretManagerImpl;
-import org.wso2.carbon.identity.secret.mgt.core.exception.SecretManagementException;
-import org.wso2.carbon.identity.secret.mgt.core.model.SecretType;
-
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-/**
- * This class is a test suite for the ActionManagementServiceImpl class.
- * It contains unit tests to verify the functionality of the methods
- * in the ActionManagementServiceImpl class.
- */
-@WithCarbonHome
-@WithH2Database(files = {"dbscripts/h2.sql"})
-@WithRealmService(injectToSingletons = {IdentityCoreServiceDataHolder.class})
-public class ActionManagementServiceImplTest {
-
- private MockedStatic identityDatabaseUtil;
- private Action action;
- private String tenantDomain;
- private ActionManagementService serviceImpl;
- private Map secretProperties;
- private static final String ACCESS_TOKEN = "6e47f1f7-bd29-41e9-b5dc-e9dd70ac22b7";
- private static final String PRE_ISSUE_ACCESS_TOKEN = Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN.getPathParam();
-
- @BeforeClass
- public void setUpClass() {
-
- serviceImpl = ActionManagementServiceImpl.getInstance();
- tenantDomain = CarbonContext.getThreadLocalCarbonContext().getTenantDomain();
- }
-
- @BeforeMethod
- public void setUp() throws SecretManagementException {
-
- SecretManagerImpl secretManager = mock(SecretManagerImpl.class);
- SecretType secretType = mock(SecretType.class);
- ActionMgtServiceComponentHolder.getInstance().setSecretManager(secretManager);
- when(secretType.getId()).thenReturn("secretId");
- when(secretManager.getSecretType(any())).thenReturn(secretType);
- }
-
- @Test(priority = 1)
- public void testAddAction() throws ActionMgtException, SecretManagementException {
-
- Action creatingAction = buildMockAction(
- "PreIssueAccessToken",
- "To configure PreIssueAccessToken",
- "https://example.com",
- buildMockBasicAuthentication("admin", "admin"));
- action = serviceImpl.addAction(PRE_ISSUE_ACCESS_TOKEN, creatingAction,
- tenantDomain);
- Assert.assertNotNull(action.getId());
- Assert.assertEquals(creatingAction.getName(), action.getName());
- Assert.assertEquals(creatingAction.getDescription(), action.getDescription());
- Assert.assertEquals(Action.Status.ACTIVE, action.getStatus());
- Assert.assertEquals(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN.getActionType(),
- action.getType().getActionType());
- Assert.assertEquals(creatingAction.getEndpoint().getUri(), action.getEndpoint().getUri());
- Assert.assertEquals(creatingAction.getEndpoint().getAuthentication().getType(),
- action.getEndpoint().getAuthentication().getType());
- Assert.assertEquals(creatingAction.getEndpoint().getAuthentication().getProperties().size(),
- action.getEndpoint().getAuthentication().getProperties().size());
- Assert.assertEquals(creatingAction.getEndpoint().getAuthentication().getProperties().size(),
- action.getEndpoint().getAuthentication().getPropertiesWithSecretReferences(action.getId()).size());
- secretProperties = mapActionAuthPropertiesWithSecrets(action);
- Assert.assertEquals(
- action.getEndpoint().getAuthentication().getProperty(Authentication.Property.USERNAME).getValue(),
- secretProperties.get(Authentication.Property.USERNAME.getName()));
- Assert.assertEquals(
- action.getEndpoint().getAuthentication().getProperty(Authentication.Property.PASSWORD).getValue(),
- secretProperties.get(Authentication.Property.PASSWORD.getName()));
- }
-
- @Test(priority = 2, expectedExceptions = ActionMgtException.class,
- expectedExceptionsMessageRegExp = "Unable to create an Action.")
- public void testAddActionWithInvalidData() throws ActionMgtException {
- Action creatingAction = buildMockAction(
- "PreIssueAccessToken_#1",
- "To configure PreIssueAccessToken",
- "https://example.com",
- buildMockAPIKeyAuthentication("-test-header", "thisisapikey"));
- Action action = serviceImpl.addAction(PRE_ISSUE_ACCESS_TOKEN, creatingAction, tenantDomain);
- Assert.assertNull(action);
- }
-
- @Test(priority = 3, expectedExceptions = ActionMgtException.class,
- expectedExceptionsMessageRegExp = "Unable to create an Action.")
- public void testAddActionWithEmptyData() throws ActionMgtException {
- Action creatingAction = buildMockAction(
- "",
- "To configure PreIssueAccessToken",
- "https://example.com",
- buildMockBasicAuthentication(null, "admin"));
- Action action = serviceImpl.addAction(PRE_ISSUE_ACCESS_TOKEN, creatingAction, tenantDomain);
- Assert.assertNull(action);
- }
-
- @Test(priority = 4, expectedExceptions = ActionMgtException.class,
- expectedExceptionsMessageRegExp = "Unable to create an Action.")
- public void testAddMaximumActionsPerType() throws ActionMgtException {
-
- Action creatingAction = buildMockAction(
- "PreIssueAccessToken",
- "To configure PreIssueAccessToken",
- "https://example.com",
- buildMockBasicAuthentication("admin", "admin"));
- action = serviceImpl.addAction(PRE_ISSUE_ACCESS_TOKEN, creatingAction,
- tenantDomain);
- }
-
- @Test(priority = 5)
- public void testGetActionsByActionType() throws ActionMgtException, SecretManagementException {
-
- List actions = serviceImpl.getActionsByActionType(PRE_ISSUE_ACCESS_TOKEN, tenantDomain);
- Assert.assertEquals(1, actions.size());
- for (Action result: actions) {
- Assert.assertEquals(action.getId(), result.getId());
- Assert.assertEquals(action.getName(), result.getName());
- Assert.assertEquals(action.getDescription(), result.getDescription());
- Assert.assertEquals(action.getType().getActionType(), result.getType().getActionType());
- Assert.assertEquals(action.getStatus(), result.getStatus());
- Assert.assertEquals(action.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(action.getEndpoint().getAuthentication().getType(),
- result.getEndpoint().getAuthentication().getType());
- secretProperties = mapActionAuthPropertiesWithSecrets(result);
- Assert.assertEquals(
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.USERNAME).getValue(),
- secretProperties.get(Authentication.Property.USERNAME.getName()));
- Assert.assertEquals(
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.PASSWORD).getValue(),
- secretProperties.get(Authentication.Property.PASSWORD.getName()));
- }
- }
-
- @Test(priority = 6)
- public void testGetActionByActionId() throws ActionMgtException, SecretManagementException {
-
- Action result = serviceImpl.getActionByActionId(action.getType().getPathParam(), action.getId(), tenantDomain);
- Assert.assertEquals(action.getId(), result.getId());
- Assert.assertEquals(action.getName(), result.getName());
- Assert.assertEquals(action.getDescription(), result.getDescription());
- Assert.assertEquals(action.getType(), result.getType());
- Assert.assertEquals(action.getStatus(), result.getStatus());
- Assert.assertEquals(action.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(action.getEndpoint().getAuthentication().getType(),
- result.getEndpoint().getAuthentication().getType());
- secretProperties = mapActionAuthPropertiesWithSecrets(result);
- Assert.assertEquals(
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.USERNAME).getValue(),
- secretProperties.get(Authentication.Property.USERNAME.getName()));
- Assert.assertEquals(
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.PASSWORD).getValue(),
- secretProperties.get(Authentication.Property.PASSWORD.getName()));
- }
-
- @Test(priority = 7)
- public void testGetActionsByActionTypeFromCache() throws ActionMgtException, SecretManagementException {
-
- // Verify that the action is retrieved from the cache based on action type.
- List actions = serviceImpl.getActionsByActionType(
- PRE_ISSUE_ACCESS_TOKEN, tenantDomain);
- Assert.assertEquals(1, actions.size());
- Action result = actions.get(0);
- Assert.assertEquals(action.getId(), result.getId());
- Assert.assertEquals(action.getName(), result.getName());
- Assert.assertEquals(action.getDescription(), result.getDescription());
- Assert.assertEquals(action.getType(), result.getType());
- Assert.assertEquals(action.getStatus(), result.getStatus());
- Assert.assertEquals(action.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(action.getEndpoint().getAuthentication().getType(),
- result.getEndpoint().getAuthentication().getType());
- secretProperties = mapActionAuthPropertiesWithSecrets(result);
- Assert.assertEquals(
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.USERNAME).getValue(),
- secretProperties.get(Authentication.Property.USERNAME.getName()));
- Assert.assertEquals(
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.PASSWORD).getValue(),
- secretProperties.get(Authentication.Property.PASSWORD.getName()));
- }
-
- @Test(priority = 8)
- public void testUpdateAction() throws ActionMgtException, SecretManagementException {
-
- Action updatingAction = buildMockAction(
- "Pre Issue Access Token",
- "To update configuration pre issue access token",
- "https://sample.com",
- buildMockAPIKeyAuthentication("header", "value"));
- Action result = serviceImpl.updateAction(PRE_ISSUE_ACCESS_TOKEN, action.getId(), updatingAction, tenantDomain);
- Assert.assertEquals(action.getId(), result.getId());
- Assert.assertEquals(updatingAction.getName(), result.getName());
- Assert.assertEquals(updatingAction.getDescription(), result.getDescription());
- Assert.assertEquals(action.getType(), result.getType());
- Assert.assertEquals(action.getStatus(), result.getStatus());
- Assert.assertEquals(updatingAction.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(
- updatingAction.getEndpoint().getAuthentication().getType(),
- result.getEndpoint().getAuthentication().getType());
- Assert.assertEquals(
- updatingAction.getEndpoint().getAuthentication().getProperty(Authentication.Property.HEADER).getValue(),
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.HEADER).getValue());
- secretProperties = mapActionAuthPropertiesWithSecrets(result);
- Assert.assertEquals(
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.VALUE).getValue(),
- secretProperties.get(Authentication.Property.VALUE.getName()));
- action = result;
- }
-
- @Test(priority = 9)
- public void testDeactivateAction() throws ActionMgtException {
-
- Assert.assertEquals(Action.Status.ACTIVE, action.getStatus());
- Action deactivatedAction = serviceImpl.deactivateAction(
- PRE_ISSUE_ACCESS_TOKEN, action.getId(), tenantDomain);
- Assert.assertEquals(Action.Status.INACTIVE, deactivatedAction.getStatus());
- }
-
- @Test(priority = 10)
- public void testActivateAction() throws ActionMgtException {
-
- Action result = serviceImpl.activateAction(
- PRE_ISSUE_ACCESS_TOKEN, action.getId(), tenantDomain);
- Assert.assertEquals(Action.Status.ACTIVE, result.getStatus());
- }
-
- @Test(priority = 11)
- public void testGetActionsCountPerType() throws ActionMgtException {
-
- Map actionMap = serviceImpl.getActionsCountPerType(tenantDomain);
- Assert.assertNull(actionMap.get(Action.ActionTypes.PRE_UPDATE_PASSWORD.getActionType()));
- Assert.assertNull(actionMap.get(Action.ActionTypes.PRE_UPDATE_PROFILE.getActionType()));
- Assert.assertNull(actionMap.get(Action.ActionTypes.PRE_REGISTRATION.getActionType()));
- Assert.assertNull(actionMap.get(Action.ActionTypes.AUTHENTICATION.getActionType()));
- for (Map.Entry entry: actionMap.entrySet()) {
- Assert.assertEquals(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN.getActionType(), entry.getKey());
- Assert.assertEquals(1, entry.getValue().intValue());
- }
- }
-
- @Test(priority = 12)
- public void testUpdateEndpointConfigWithSameAuthenticationType()
- throws ActionMgtException, SecretManagementException {
-
- Authentication authentication = buildMockAPIKeyAuthentication("newheader", "newvalue");
- Action result = serviceImpl.updateActionEndpointAuthentication(
- PRE_ISSUE_ACCESS_TOKEN, action.getId(), authentication, tenantDomain);
- Assert.assertEquals(Authentication.Type.API_KEY, result.getEndpoint().getAuthentication().getType());
- Assert.assertEquals(authentication.getProperty(Authentication.Property.HEADER).getValue(),
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.HEADER).getValue());
- secretProperties = mapActionAuthPropertiesWithSecrets(result);
- Assert.assertEquals(
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.VALUE).getValue(),
- secretProperties.get(Authentication.Property.VALUE.getName()));
- }
-
- @Test(priority = 13)
- public void testUpdateEndpointConfigWithDifferentAuthenticationType()
- throws ActionMgtException, SecretManagementException {
-
- Authentication authentication = buildMockBearerAuthentication(ACCESS_TOKEN);
- Action result = serviceImpl.updateActionEndpointAuthentication(
- PRE_ISSUE_ACCESS_TOKEN, action.getId(), authentication, tenantDomain);
- Assert.assertEquals(Authentication.Type.BEARER, result.getEndpoint().getAuthentication().getType());
- secretProperties = mapActionAuthPropertiesWithSecrets(result);
- Assert.assertEquals(
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.ACCESS_TOKEN).getValue(),
- secretProperties.get(Authentication.Property.ACCESS_TOKEN.getName()));
- }
-
- @Test(priority = 14)
- public void testDeleteAction() throws ActionMgtException {
-
- serviceImpl.deleteAction(PRE_ISSUE_ACCESS_TOKEN, action.getId(), tenantDomain);
- Assert.assertNull(serviceImpl.getActionByActionId(action.getType().getPathParam(), action.getId(),
- tenantDomain));
- Map actions = serviceImpl.getActionsCountPerType(tenantDomain);
- Assert.assertNull(actions.get(PRE_ISSUE_ACCESS_TOKEN));
- }
-
- private Map mapActionAuthPropertiesWithSecrets(Action action) throws SecretManagementException {
-
- return action.getEndpoint().getAuthentication()
- .getPropertiesWithSecretReferences(action.getId())
- .stream()
- .collect(Collectors.toMap(AuthProperty::getName, AuthProperty::getValue));
- }
-
- private Authentication buildMockBasicAuthentication(String username, String password) {
-
- return new Authentication.BasicAuthBuilder(username, password).build();
- }
-
- private Authentication buildMockBearerAuthentication(String accessToken) {
-
- return new Authentication.BearerAuthBuilder(accessToken).build();
- }
-
- private Authentication buildMockAPIKeyAuthentication(String header, String value) {
-
- return new Authentication.APIKeyAuthBuilder(header, value).build();
- }
-
- private EndpointConfig buildMockEndpointConfig(String uri, Authentication authentication) {
-
- if (uri == null && authentication == null) {
- return null;
- }
-
- return new EndpointConfig.EndpointConfigBuilder()
- .uri(uri)
- .authentication(authentication)
- .build();
- }
-
- private Action buildMockAction(String name,
- String description,
- String uri,
- Authentication authentication) {
-
- return new Action.ActionRequestBuilder()
- .name(name)
- .description(description)
- .endpoint(buildMockEndpointConfig(uri, authentication))
- .build();
- }
-}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/dao/ActionDTOModelResolverFactoryTest.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/dao/ActionDTOModelResolverFactoryTest.java
new file mode 100644
index 000000000000..23171e048ad2
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/dao/ActionDTOModelResolverFactoryTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.carbon.identity.action.management.dao;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.wso2.carbon.identity.action.management.dao.impl.ActionDTOModelResolverFactory;
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.service.ActionDTOModelResolver;
+
+import static org.mockito.Mockito.doReturn;
+
+/**
+ * ActionDTO Model Resolver Factory Test.
+ */
+public class ActionDTOModelResolverFactoryTest {
+
+ private final Action.ActionTypes actionType = Action.ActionTypes.PRE_UPDATE_PASSWORD;
+ @Mock
+ private ActionDTOModelResolver mockActionDTOModelResolver;
+
+ @BeforeMethod
+ public void setUp() {
+
+ MockitoAnnotations.openMocks(this);
+ doReturn(actionType).when(mockActionDTOModelResolver).getSupportedActionType();
+ }
+
+ @Test
+ public void testRegisterActionDTOModelResolver() {
+
+ ActionDTOModelResolverFactory.registerActionDTOModelResolver(mockActionDTOModelResolver);
+ ActionDTOModelResolver registeredResult = ActionDTOModelResolverFactory.getActionDTOModelResolver(actionType);
+ Assert.assertEquals(registeredResult, mockActionDTOModelResolver);
+ }
+
+ @Test(dependsOnMethods = {"testRegisterActionDTOModelResolver"})
+ public void testUnregisterActionDTOModelResolver() {
+
+ ActionDTOModelResolverFactory.unregisterActionDTOModelResolver(mockActionDTOModelResolver);
+ ActionDTOModelResolver unregisteredResult = ActionDTOModelResolverFactory.getActionDTOModelResolver(actionType);
+ Assert.assertNull(unregisteredResult);
+ }
+
+ @Test(dependsOnMethods = {"testUnregisterActionDTOModelResolver"})
+ public void testGetActionDTOModelResolverNotFound() {
+
+ ActionDTOModelResolver result = ActionDTOModelResolverFactory.getActionDTOModelResolver(actionType);
+ Assert.assertNull(result);
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAOFacadeTest.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAOFacadeTest.java
new file mode 100644
index 000000000000..8aa13fc9e089
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAOFacadeTest.java
@@ -0,0 +1,403 @@
+/*
+ * 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.carbon.identity.action.management.dao;
+
+import org.apache.commons.lang.StringUtils;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.MockitoAnnotations;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.wso2.carbon.identity.action.management.constant.error.ErrorMessage;
+import org.wso2.carbon.identity.action.management.dao.impl.ActionDTOModelResolverFactory;
+import org.wso2.carbon.identity.action.management.dao.impl.ActionManagementDAOFacade;
+import org.wso2.carbon.identity.action.management.dao.impl.ActionManagementDAOImpl;
+import org.wso2.carbon.identity.action.management.exception.ActionDTOModelResolverClientException;
+import org.wso2.carbon.identity.action.management.exception.ActionDTOModelResolverException;
+import org.wso2.carbon.identity.action.management.exception.ActionDTOModelResolverServerException;
+import org.wso2.carbon.identity.action.management.exception.ActionMgtClientException;
+import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
+import org.wso2.carbon.identity.action.management.exception.ActionMgtServerException;
+import org.wso2.carbon.identity.action.management.internal.ActionMgtServiceComponentHolder;
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.ActionDTO;
+import org.wso2.carbon.identity.action.management.model.Authentication;
+import org.wso2.carbon.identity.action.management.model.EndpointConfig;
+import org.wso2.carbon.identity.action.management.service.ActionDTOModelResolver;
+import org.wso2.carbon.identity.action.management.util.ActionDTOBuilder;
+import org.wso2.carbon.identity.action.management.util.TestUtil;
+import org.wso2.carbon.identity.certificate.management.model.Certificate;
+import org.wso2.carbon.identity.common.testng.WithCarbonHome;
+import org.wso2.carbon.identity.common.testng.WithH2Database;
+import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
+import org.wso2.carbon.identity.secret.mgt.core.SecretManagerImpl;
+import org.wso2.carbon.identity.secret.mgt.core.exception.SecretManagementException;
+import org.wso2.carbon.identity.secret.mgt.core.model.SecretType;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.CERTIFICATE_PROPERTY_NAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PASSWORD_SHARING_TYPE_PROPERTY_NAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_ISSUE_ACCESS_TOKEN_ACTION_ID;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_ISSUE_ACCESS_TOKEN_TYPE;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_UPDATE_PASSWORD_ACTION_ID;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_UPDATE_PASSWORD_TYPE;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TENANT_DOMAIN;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TENANT_ID;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACCESS_TOKEN;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_DESCRIPTION;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_DESCRIPTION_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_NAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_NAME_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_URI;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_URI_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_CERTIFICATE;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_PASSWORD;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_PASSWORD_SHARING_TYPE;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_PASSWORD_SHARING_TYPE_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_USERNAME;
+
+/**
+ * This class is a test suite for the ActionManagementDAOFacade class.
+ * It contains unit tests to verify the functionality of the methods in the ActionManagementDAOFacade class which is
+ * responsible for handling external services.
+ */
+@WithH2Database(files = {"dbscripts/h2.sql"})
+@WithCarbonHome
+public class ActionManagementDAOFacadeTest {
+
+ @Mock
+ private ActionDTOModelResolver mockedActionDTOModelResolver;
+ private TestActionDTOModelResolver testActionPropertyResolver;
+ private MockedStatic actionPropertyResolverFactory;
+ private MockedStatic identityTenantUtil;
+
+ private ActionManagementDAOFacade daoFacade;
+ private ActionDTO creatingActionDTO;
+ private ActionDTO createdActionDTO;
+
+ @BeforeClass
+ public void setUpClass() {
+
+ daoFacade = new ActionManagementDAOFacade(new ActionManagementDAOImpl());
+ creatingActionDTO = new ActionDTOBuilder()
+ .id(PRE_UPDATE_PASSWORD_ACTION_ID)
+ .type(Action.ActionTypes.PRE_UPDATE_PASSWORD)
+ .name(TEST_ACTION_NAME)
+ .description(TEST_ACTION_DESCRIPTION)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TEST_ACTION_URI)
+ .authentication(TestUtil.buildMockBasicAuthentication(TEST_USERNAME, TEST_PASSWORD))
+ .build())
+ .property(PASSWORD_SHARING_TYPE_PROPERTY_NAME, TEST_PASSWORD_SHARING_TYPE)
+ .property(CERTIFICATE_PROPERTY_NAME,
+ new Certificate.Builder().certificateContent(TEST_CERTIFICATE).build())
+ .build();
+ testActionPropertyResolver = new TestActionDTOModelResolver();
+ }
+
+ @BeforeMethod
+ public void setUp() throws SecretManagementException {
+
+ SecretManagerImpl secretManager = mock(SecretManagerImpl.class);
+ SecretType secretType = mock(SecretType.class);
+ ActionMgtServiceComponentHolder.getInstance().setSecretManager(secretManager);
+ when(secretType.getId()).thenReturn(TestUtil.TEST_SECRET_TYPE_ID);
+ when(secretManager.getSecretType(any())).thenReturn(secretType);
+
+ identityTenantUtil = mockStatic(IdentityTenantUtil.class);
+ identityTenantUtil.when(()-> IdentityTenantUtil.getTenantDomain(anyInt())).thenReturn(TENANT_DOMAIN);
+
+ MockitoAnnotations.openMocks(this);
+ actionPropertyResolverFactory = mockStatic(ActionDTOModelResolverFactory.class);
+ }
+
+ @AfterMethod
+ public void tearDown() {
+
+ mockedActionDTOModelResolver = null;
+ identityTenantUtil.close();
+ actionPropertyResolverFactory.close();
+ }
+
+ @Test(priority = 1)
+ public void testAddActionWithActionPropertyResolverClientException() throws ActionDTOModelResolverException {
+
+ mockActionPropertyResolver(mockedActionDTOModelResolver);
+ doThrow(new ActionDTOModelResolverClientException("Invalid Certificate.", "Invalid PEM format."))
+ .when(mockedActionDTOModelResolver).resolveForAddOperation(any(), any());
+
+ try {
+ daoFacade.addAction(creatingActionDTO, TENANT_ID);
+ Assert.fail("Successful addition of the action without an exception is considered as a failure");
+ } catch (ActionMgtException e) {
+ Assert.assertEquals(e.getClass(), ActionMgtClientException.class);
+ Assert.assertEquals(e.getErrorCode(), ErrorMessage.ERROR_INVALID_ACTION_PROPERTIES.getCode());
+ Assert.assertEquals(e.getMessage(), "Invalid Certificate.");
+ Assert.assertEquals(e.getDescription(), "Invalid PEM format.");
+ }
+ }
+
+ @Test(priority = 2)
+ public void testAddActionWithActionPropertyResolverServerException() throws ActionDTOModelResolverException {
+
+ mockActionPropertyResolver(mockedActionDTOModelResolver);
+ doThrow(new ActionDTOModelResolverServerException("Error adding Certificate.", null, new Throwable()))
+ .when(mockedActionDTOModelResolver).resolveForAddOperation(any(), any());
+
+ try {
+ daoFacade.addAction(creatingActionDTO, TENANT_ID);
+ Assert.fail("Successful addition of the action without an exception is considered as a failure");
+ } catch (ActionMgtException e) {
+ Assert.assertEquals(e.getClass(), ActionMgtServerException.class);
+ Assert.assertEquals(e.getMessage(), ErrorMessage.ERROR_WHILE_ADDING_ACTION.getMessage());
+ for (Throwable cause = e.getCause(); cause != null; cause = cause.getCause()) {
+ if (cause instanceof ActionDTOModelResolverServerException) {
+ return;
+ }
+ }
+ Assert.fail("Expected ActionPropertyResolverServerException was not found in the exception chain");
+ }
+ }
+
+ @Test(priority = 3)
+ public void testAddAction() throws ActionMgtException {
+
+ mockActionPropertyResolver(testActionPropertyResolver);
+ try {
+ daoFacade.addAction(creatingActionDTO, TENANT_ID);
+ } catch (Exception e) {
+ Assert.fail();
+ }
+
+ createdActionDTO = daoFacade.getActionByActionId(PRE_UPDATE_PASSWORD_TYPE, PRE_UPDATE_PASSWORD_ACTION_ID,
+ TENANT_ID);
+ Assert.assertEquals(createdActionDTO.getId(), creatingActionDTO.getId());
+ Assert.assertEquals(createdActionDTO.getType(), creatingActionDTO.getType());
+ Assert.assertEquals(createdActionDTO.getName(), creatingActionDTO.getName());
+ Assert.assertEquals(createdActionDTO.getDescription(), creatingActionDTO.getDescription());
+ Assert.assertEquals(createdActionDTO.getStatus(), Action.Status.ACTIVE);
+ Assert.assertEquals(createdActionDTO.getEndpoint().getUri(), creatingActionDTO.getEndpoint().getUri());
+
+ Authentication createdAuthentication = createdActionDTO.getEndpoint().getAuthentication();
+ Assert.assertEquals(createdAuthentication.getType(),
+ creatingActionDTO.getEndpoint().getAuthentication().getType());
+ Assert.assertEquals(createdAuthentication.getProperties().size(),
+ creatingActionDTO.getEndpoint().getAuthentication().getProperties().size());
+ Assert.assertEquals(createdAuthentication.getProperty(Authentication.Property.USERNAME).getValue(),
+ TestUtil.buildSecretName(PRE_UPDATE_PASSWORD_ACTION_ID, Authentication.Type.BASIC,
+ Authentication.Property.USERNAME));
+ Assert.assertEquals(createdAuthentication.getProperty(Authentication.Property.PASSWORD).getValue(),
+ TestUtil.buildSecretName(PRE_UPDATE_PASSWORD_ACTION_ID, Authentication.Type.BASIC,
+ Authentication.Property.PASSWORD));
+
+ Assert.assertEquals(createdActionDTO.getProperties().size(), creatingActionDTO.getProperties().size());
+ Assert.assertTrue(createdActionDTO.getProperties().containsKey(PASSWORD_SHARING_TYPE_PROPERTY_NAME));
+ Assert.assertTrue(createdActionDTO.getProperties().containsKey(CERTIFICATE_PROPERTY_NAME));
+ Assert.assertEquals(createdActionDTO.getProperty(PASSWORD_SHARING_TYPE_PROPERTY_NAME),
+ creatingActionDTO.getProperty(PASSWORD_SHARING_TYPE_PROPERTY_NAME));
+ Assert.assertEquals(((Certificate) createdActionDTO.getProperty(CERTIFICATE_PROPERTY_NAME))
+ .getCertificateContent(), TEST_CERTIFICATE);
+ }
+
+ @Test(priority = 4)
+ public void testGetActionsByType() throws ActionMgtException {
+
+ mockActionPropertyResolver(testActionPropertyResolver);
+ List actionDTOs = daoFacade.getActionsByActionType(PRE_UPDATE_PASSWORD_TYPE, TENANT_ID);
+ ActionDTO result = actionDTOs.get(0);
+ Assert.assertEquals(result.getId(), createdActionDTO.getId());
+ Assert.assertEquals(result.getType(), createdActionDTO.getType());
+ Assert.assertEquals(result.getName(), createdActionDTO.getName());
+ Assert.assertEquals(result.getDescription(), createdActionDTO.getDescription());
+ Assert.assertEquals(result.getStatus(), createdActionDTO.getStatus());
+ Assert.assertEquals(result.getEndpoint().getUri(), createdActionDTO.getEndpoint().getUri());
+
+ Authentication resultAuthentication = result.getEndpoint().getAuthentication();
+ Assert.assertEquals(resultAuthentication.getType(),
+ createdActionDTO.getEndpoint().getAuthentication().getType());
+ Assert.assertEquals(resultAuthentication.getProperties().size(),
+ createdActionDTO.getEndpoint().getAuthentication().getProperties().size());
+ Assert.assertEquals(resultAuthentication.getProperty(Authentication.Property.USERNAME).getValue(),
+ createdActionDTO.getEndpoint().getAuthentication().getProperty(Authentication.Property.USERNAME)
+ .getValue());
+ Assert.assertEquals(resultAuthentication.getProperty(Authentication.Property.PASSWORD).getValue(),
+ createdActionDTO.getEndpoint().getAuthentication().getProperty(Authentication.Property.PASSWORD)
+ .getValue());
+
+ Assert.assertEquals(result.getProperties().size(), createdActionDTO.getProperties().size());
+ Assert.assertTrue(createdActionDTO.getProperties().containsKey(PASSWORD_SHARING_TYPE_PROPERTY_NAME));
+ Assert.assertTrue(createdActionDTO.getProperties().containsKey(CERTIFICATE_PROPERTY_NAME));
+ Assert.assertEquals(result.getProperty(PASSWORD_SHARING_TYPE_PROPERTY_NAME),
+ createdActionDTO.getProperty(PASSWORD_SHARING_TYPE_PROPERTY_NAME));
+ Assert.assertEquals(((Certificate) result.getProperty(CERTIFICATE_PROPERTY_NAME)).getCertificateContent(),
+ ((Certificate) createdActionDTO.getProperty(CERTIFICATE_PROPERTY_NAME)).getCertificateContent());
+ }
+
+ @Test(priority = 5)
+ public void testUpdateActionPropertyResolverClientException() throws ActionDTOModelResolverException {
+
+ mockActionPropertyResolver(mockedActionDTOModelResolver);
+ doThrow(new ActionDTOModelResolverClientException("Invalid Certificate.", "Invalid PEM format."))
+ .when(mockedActionDTOModelResolver).resolveForUpdateOperation(any(), any(), any());
+
+ try {
+ daoFacade.updateAction(creatingActionDTO, createdActionDTO, TENANT_ID);
+ Assert.fail("Successful update of the actions without an exception is considered as a failure");
+ } catch (ActionMgtException e) {
+ Assert.assertEquals(e.getClass(), ActionMgtClientException.class);
+ Assert.assertEquals(e.getErrorCode(), ErrorMessage.ERROR_INVALID_ACTION_PROPERTIES.getCode());
+ Assert.assertEquals(e.getMessage(), "Invalid Certificate.");
+ Assert.assertEquals(e.getDescription(), "Invalid PEM format.");
+ }
+ }
+
+ @Test(priority = 6)
+ public void testUpdateActionWithActionPropertyResolverServerException() throws ActionDTOModelResolverException {
+
+ mockActionPropertyResolver(mockedActionDTOModelResolver);
+ doThrow(new ActionDTOModelResolverServerException("Error updating Certificate.", null)).when(
+ mockedActionDTOModelResolver)
+ .resolveForUpdateOperation(any(), any(), any());
+
+ try {
+ daoFacade.updateAction(creatingActionDTO, createdActionDTO, TENANT_ID);
+ Assert.fail("Successful update of the actions without an exception is considered as a failure");
+ } catch (ActionMgtException e) {
+ Assert.assertEquals(e.getClass(), ActionMgtServerException.class);
+ Assert.assertEquals(e.getMessage(), ErrorMessage.ERROR_WHILE_UPDATING_ACTION.getMessage());
+ for (Throwable cause = e.getCause(); cause != null; cause = cause.getCause()) {
+ if (cause instanceof ActionDTOModelResolverServerException) {
+ return;
+ }
+ }
+ Assert.fail("Expected ActionPropertyResolverServerException was not found in the exception chain");
+ }
+ }
+
+ @Test(priority = 7, dependsOnMethods = "testAddAction")
+ public void testUpdateCompleteAction() throws ActionMgtException {
+
+ mockActionPropertyResolver(testActionPropertyResolver);
+ // Update action with certificate property deletion.
+ ActionDTO updatingAction = new ActionDTOBuilder()
+ .id(createdActionDTO.getId())
+ .type(Action.ActionTypes.PRE_UPDATE_PASSWORD)
+ .name(TEST_ACTION_NAME_UPDATED)
+ .description(TEST_ACTION_DESCRIPTION_UPDATED)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TEST_ACTION_URI_UPDATED)
+ .authentication(TestUtil.buildMockBearerAuthentication(TEST_ACCESS_TOKEN))
+ .build())
+ .property(PASSWORD_SHARING_TYPE_PROPERTY_NAME, TEST_PASSWORD_SHARING_TYPE_UPDATED)
+ .property(CERTIFICATE_PROPERTY_NAME,
+ new Certificate.Builder().certificateContent(StringUtils.EMPTY).build())
+ .build();
+
+ try {
+ daoFacade.updateAction(updatingAction, createdActionDTO, TENANT_ID);
+ } catch (Exception e) {
+ Assert.fail();
+ }
+
+ ActionDTO result = daoFacade.getActionByActionId(PRE_UPDATE_PASSWORD_TYPE, updatingAction.getId(), TENANT_ID);
+ Assert.assertEquals(result.getId(), createdActionDTO.getId());
+ Assert.assertEquals(result.getType(), createdActionDTO.getType());
+ Assert.assertEquals(result.getName(), updatingAction.getName());
+ Assert.assertEquals(result.getDescription(), updatingAction.getDescription());
+ Assert.assertEquals(result.getStatus(), createdActionDTO.getStatus());
+ Assert.assertEquals(result.getEndpoint().getUri(), updatingAction.getEndpoint().getUri());
+
+ Authentication updatedAuthentication = result.getEndpoint().getAuthentication();
+ Assert.assertEquals(updatedAuthentication.getType(),
+ updatingAction.getEndpoint().getAuthentication().getType());
+ Assert.assertEquals(updatedAuthentication.getProperties().size(),
+ updatingAction.getEndpoint().getAuthentication().getProperties().size());
+ Assert.assertEquals(updatedAuthentication.getProperty(Authentication.Property.ACCESS_TOKEN).getValue(),
+ TestUtil.buildSecretName(PRE_UPDATE_PASSWORD_ACTION_ID, Authentication.Type.BEARER,
+ Authentication.Property.ACCESS_TOKEN));
+
+ // Check whether the certificate is removed.
+ Assert.assertEquals(result.getProperties().size(), updatingAction.getProperties().size() - 1);
+
+ Assert.assertTrue(updatingAction.getProperties().containsKey(PASSWORD_SHARING_TYPE_PROPERTY_NAME));
+ Assert.assertTrue(updatingAction.getProperties().containsKey(CERTIFICATE_PROPERTY_NAME));
+ Assert.assertEquals(result.getProperty(PASSWORD_SHARING_TYPE_PROPERTY_NAME),
+ updatingAction.getProperty(PASSWORD_SHARING_TYPE_PROPERTY_NAME));
+ Assert.assertNull(result.getProperty(CERTIFICATE_PROPERTY_NAME));
+ createdActionDTO = result;
+ }
+
+ @Test(priority = 8)
+ public void testDeactivateAction() throws ActionMgtException {
+
+ Assert.assertEquals(createdActionDTO.getStatus(), Action.Status.ACTIVE);
+ ActionDTO deactivatedActionDTO = daoFacade.deactivateAction(PRE_UPDATE_PASSWORD_TYPE, createdActionDTO.getId(),
+ TENANT_ID);
+ Assert.assertEquals(deactivatedActionDTO.getStatus(), Action.Status.INACTIVE);
+ }
+
+ @Test(priority = 9)
+ public void testActivateAction() throws ActionMgtException {
+
+ ActionDTO activatedActionDTO = daoFacade.activateAction(PRE_UPDATE_PASSWORD_TYPE, createdActionDTO.getId(),
+ TENANT_ID);
+ Assert.assertEquals(activatedActionDTO.getStatus(), Action.Status.ACTIVE);
+ }
+
+ @Test(priority = 10)
+ public void testGetActionsCountPerType() throws ActionMgtException {
+
+ Map actionMap = daoFacade.getActionsCountPerType(TENANT_ID);
+ Assert.assertTrue(actionMap.containsKey(PRE_UPDATE_PASSWORD_TYPE));
+ Assert.assertEquals(actionMap.get(PRE_UPDATE_PASSWORD_TYPE).intValue(), 1);
+ }
+
+ @Test(priority = 11)
+ public void testDeleteAction() throws ActionMgtException {
+
+ mockActionPropertyResolver(testActionPropertyResolver);
+ try {
+ daoFacade.deleteAction(createdActionDTO, TENANT_ID);
+ } catch (Exception e) {
+ Assert.fail();
+ }
+ Assert.assertNull(daoFacade.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_TYPE, PRE_ISSUE_ACCESS_TOKEN_ACTION_ID,
+ TENANT_ID));
+ Assert.assertEquals(daoFacade.getActionsCountPerType(TENANT_ID), Collections.emptyMap());
+ }
+
+ private void mockActionPropertyResolver(ActionDTOModelResolver actionDTOModelResolver) {
+
+ actionPropertyResolverFactory.when(
+ () -> ActionDTOModelResolverFactory.getActionDTOModelResolver(Action.ActionTypes.PRE_UPDATE_PASSWORD))
+ .thenReturn(actionDTOModelResolver);
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAOImplTest.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAOImplTest.java
index 2c3a5237ee5a..2f40c18b674d 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAOImplTest.java
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/dao/ActionManagementDAOImplTest.java
@@ -18,48 +18,42 @@
package org.wso2.carbon.identity.action.management.dao;
-import org.junit.Assert;
-import org.mockito.MockedStatic;
-import org.testng.annotations.AfterMethod;
+import org.testng.Assert;
import org.testng.annotations.BeforeClass;
-import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import org.wso2.carbon.identity.action.management.dao.impl.ActionManagementDAOImpl;
import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
-import org.wso2.carbon.identity.action.management.internal.ActionMgtServiceComponentHolder;
import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.ActionDTO;
import org.wso2.carbon.identity.action.management.model.Authentication;
import org.wso2.carbon.identity.action.management.model.EndpointConfig;
+import org.wso2.carbon.identity.action.management.util.ActionDTOBuilder;
+import org.wso2.carbon.identity.action.management.util.TestUtil;
import org.wso2.carbon.identity.common.testng.WithCarbonHome;
import org.wso2.carbon.identity.common.testng.WithH2Database;
-import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
-import org.wso2.carbon.identity.secret.mgt.core.SecretManagerImpl;
-import org.wso2.carbon.identity.secret.mgt.core.exception.SecretManagementException;
-import org.wso2.carbon.identity.secret.mgt.core.model.SecretType;
+import java.util.List;
import java.util.Map;
import java.util.UUID;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.mockStatic;
-import static org.mockito.Mockito.when;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_ISSUE_ACCESS_TOKEN_ACTION_ID;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_ISSUE_ACCESS_TOKEN_TYPE;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_UPDATE_PASSWORD_ACTION_ID;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_UPDATE_PASSWORD_TYPE;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TENANT_ID;
/**
* This class is a test suite for the ActionManagementDAOImpl class.
- * It contains unit tests to verify the functionality of the methods
- * in the ActionManagementDAOImpl class.
+ * It contains unit tests to verify the functionality of the methods in the ActionManagementDAOImpl class.
+ * This test class will utilize {@link TestActionDTOModelResolver} class as the test implementation for
+ * ActionPropertyResolver interface.
*/
@WithH2Database(files = {"dbscripts/h2.sql"})
@WithCarbonHome
public class ActionManagementDAOImplTest {
private ActionManagementDAOImpl daoImpl;
- private MockedStatic identityTenantUtil;
- private static final String PRE_ISSUE_ACCESS_TOKEN = "PRE_ISSUE_ACCESS_TOKEN";
- private static final int TENANT_ID = 2;
- private Action action;
+ private ActionDTO createdActionDTO;
@BeforeClass
public void setUpClass() {
@@ -67,372 +61,492 @@ public void setUpClass() {
daoImpl = new ActionManagementDAOImpl();
}
- @BeforeMethod
- public void setUp() throws SecretManagementException {
-
- identityTenantUtil = mockStatic(IdentityTenantUtil.class);
- SecretManagerImpl secretManager = mock(SecretManagerImpl.class);
- SecretType secretType = mock(SecretType.class);
- ActionMgtServiceComponentHolder.getInstance().setSecretManager(secretManager);
- identityTenantUtil.when(()-> IdentityTenantUtil.getTenantId(anyString())).thenReturn(TENANT_ID);
- when(secretType.getId()).thenReturn("secretId");
- when(secretManager.getSecretType(any())).thenReturn(secretType);
- }
-
- @AfterMethod
- public void tearDown() {
-
- identityTenantUtil.close();
- }
-
@Test(priority = 1)
public void testAddAction() throws ActionMgtException {
- String id = String.valueOf(UUID.randomUUID());
- Action creatingAction = buildMockAction(
- "PreIssueAccessToken",
- "To configure PreIssueAccessToken",
- "https://example.com",
- buildMockBasicAuthentication("admin", "admin"));
- action = daoImpl.addAction(PRE_ISSUE_ACCESS_TOKEN, id, creatingAction, TENANT_ID);
- Assert.assertEquals(id, action.getId());
- Assert.assertEquals(creatingAction.getName(), action.getName());
- Assert.assertEquals(creatingAction.getDescription(), action.getDescription());
- Assert.assertEquals(PRE_ISSUE_ACCESS_TOKEN, action.getType().getActionType());
- Assert.assertEquals(Action.Status.ACTIVE, action.getStatus());
- Assert.assertEquals(creatingAction.getEndpoint().getUri(), action.getEndpoint().getUri());
- Assert.assertEquals(creatingAction.getEndpoint().getAuthentication().getType(),
- action.getEndpoint().getAuthentication().getType());
+ ActionDTO creatingActionDTO = new ActionDTOBuilder()
+ .id(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID)
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .name(TestUtil.TEST_ACTION_NAME)
+ .description(TestUtil.TEST_ACTION_DESCRIPTION)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TestUtil.TEST_ACTION_URI)
+ .authentication(TestUtil.buildMockBasicAuthentication(TestUtil.TEST_USERNAME_SECRET_REFERENCE,
+ TestUtil.TEST_PASSWORD_SECRET_REFERENCE))
+ .build())
+ .property(TestUtil.TEST_ACTION_PROPERTY_NAME_1, TestUtil.TEST_ACTION_PROPERTY_VALUE_1)
+ .property(TestUtil.TEST_ACTION_PROPERTY_NAME_2, TestUtil.TEST_ACTION_PROPERTY_VALUE_2)
+ .build();
+
+ try {
+ daoImpl.addAction(creatingActionDTO, TENANT_ID);
+ } catch (Exception e) {
+ Assert.fail();
+ }
+ createdActionDTO = daoImpl.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_TYPE, PRE_ISSUE_ACCESS_TOKEN_ACTION_ID,
+ TENANT_ID);
+ Assert.assertEquals(createdActionDTO.getId(), creatingActionDTO.getId());
+ Assert.assertEquals(createdActionDTO.getType(), creatingActionDTO.getType());
+ Assert.assertEquals(createdActionDTO.getName(), creatingActionDTO.getName());
+ Assert.assertEquals(createdActionDTO.getDescription(), creatingActionDTO.getDescription());
+ Assert.assertEquals(createdActionDTO.getStatus(), Action.Status.ACTIVE);
+ Assert.assertEquals(createdActionDTO.getEndpoint().getUri(), creatingActionDTO.getEndpoint().getUri());
+
+ Authentication createdAuthentication = createdActionDTO.getEndpoint().getAuthentication();
+ Assert.assertEquals(createdAuthentication.getType(),
+ creatingActionDTO.getEndpoint().getAuthentication().getType());
+ Assert.assertEquals(createdAuthentication.getProperties().size(),
+ creatingActionDTO.getEndpoint().getAuthentication().getProperties().size());
+ Assert.assertEquals(createdAuthentication.getProperty(Authentication.Property.USERNAME).getValue(),
+ TestUtil.TEST_USERNAME_SECRET_REFERENCE);
+ Assert.assertEquals(createdAuthentication.getProperty(Authentication.Property.PASSWORD).getValue(),
+ TestUtil.TEST_PASSWORD_SECRET_REFERENCE);
+
+ Assert.assertEquals(createdActionDTO.getProperties().size(), creatingActionDTO.getProperties().size());
+ Assert.assertEquals(createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1),
+ creatingActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1));
+ Assert.assertEquals(createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2),
+ creatingActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2));
}
@Test(priority = 2, expectedExceptions = ActionMgtException.class,
- expectedExceptionsMessageRegExp = "Error while adding Action.")
+ expectedExceptionsMessageRegExp = "Error while adding Action Basic information in the system.")
public void testAddActionWithoutName() throws ActionMgtException {
- Action action = buildMockAction(
- null,
- "To configure PreIssueAccessToken",
- "https://example.com",
- buildMockBasicAuthentication("admin", "admin"));
- this.action = daoImpl.addAction(PRE_ISSUE_ACCESS_TOKEN, action.getId(), action, TENANT_ID);
+ ActionDTO creatingActionDTO = new ActionDTOBuilder()
+ .id(String.valueOf(UUID.randomUUID()))
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .name(null)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TestUtil.TEST_ACTION_URI)
+ .authentication(TestUtil.buildMockBasicAuthentication(TestUtil.TEST_USERNAME_SECRET_REFERENCE,
+ TestUtil.TEST_PASSWORD_SECRET_REFERENCE))
+ .build())
+ .build();
+
+ daoImpl.addAction(creatingActionDTO, TENANT_ID);
}
@Test(priority = 3)
public void testGetActionsByActionType() throws ActionMgtException {
- Assert.assertEquals(1, daoImpl.getActionsByActionType(PRE_ISSUE_ACCESS_TOKEN, TENANT_ID).size());
- Action result = daoImpl.getActionsByActionType(PRE_ISSUE_ACCESS_TOKEN, TENANT_ID).get(0);
- Assert.assertEquals(action.getId(), result.getId());
- Assert.assertEquals(action.getName(), result.getName());
- Assert.assertEquals(action.getDescription(), result.getDescription());
- Assert.assertEquals(action.getType(), result.getType());
- Assert.assertEquals(action.getStatus(), result.getStatus());
- Assert.assertEquals(action.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(action.getEndpoint().getAuthentication().getType(),
- result.getEndpoint().getAuthentication().getType());
+ List actionDTOList = daoImpl.getActionsByActionType(PRE_ISSUE_ACCESS_TOKEN_TYPE, TENANT_ID);
+ Assert.assertEquals(actionDTOList.size(), 1);
+ ActionDTO result = actionDTOList.get(0);
+ Assert.assertEquals(result.getId(), createdActionDTO.getId());
+ Assert.assertEquals(result.getType(), createdActionDTO.getType());
+ Assert.assertEquals(result.getName(), createdActionDTO.getName());
+ Assert.assertEquals(result.getDescription(), createdActionDTO.getDescription());
+ Assert.assertEquals(result.getStatus(), createdActionDTO.getStatus());
+ Assert.assertEquals(result.getEndpoint().getUri(), createdActionDTO.getEndpoint().getUri());
+ Assert.assertEquals(result.getEndpoint().getAuthentication().getType(),
+ createdActionDTO.getEndpoint().getAuthentication().getType());
+
+ Authentication createdAuthentication = result.getEndpoint().getAuthentication();
+ Assert.assertEquals(createdAuthentication.getType(),
+ createdActionDTO.getEndpoint().getAuthentication().getType());
+ Assert.assertEquals(createdAuthentication.getProperties().size(),
+ createdActionDTO.getEndpoint().getAuthentication().getProperties().size());
+ Assert.assertEquals(createdAuthentication.getProperty(Authentication.Property.USERNAME).getValue(),
+ TestUtil.TEST_USERNAME_SECRET_REFERENCE);
+ Assert.assertEquals(createdAuthentication.getProperty(Authentication.Property.PASSWORD).getValue(),
+ TestUtil.TEST_PASSWORD_SECRET_REFERENCE);
+
+ Assert.assertEquals(result.getProperties().size(), createdActionDTO.getProperties().size());
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1),
+ createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1));
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2),
+ createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2));
}
@Test(priority = 4)
- public void testGetActionByActionId() throws ActionMgtException {
-
- Action result = daoImpl.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN, action.getId(), TENANT_ID);
- Assert.assertEquals(action.getId(), result.getId());
- Assert.assertEquals(action.getName(), result.getName());
- Assert.assertEquals(action.getDescription(), result.getDescription());
- Assert.assertEquals(action.getType(), result.getType());
- Assert.assertEquals(action.getStatus(), result.getStatus());
- Assert.assertEquals(action.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(action.getEndpoint().getAuthentication().getType(),
- result.getEndpoint().getAuthentication().getType());
- }
-
- @Test(priority = 5)
public void testDeleteAction() throws ActionMgtException {
- daoImpl.deleteAction(PRE_ISSUE_ACCESS_TOKEN, action.getId(), action, TENANT_ID);
- Assert.assertNull(daoImpl.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN, action.getId(), TENANT_ID));
+ try {
+ daoImpl.deleteAction(createdActionDTO, TENANT_ID);
+ } catch (Exception e) {
+ Assert.fail();
+ }
+ Assert.assertNull(daoImpl.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_TYPE, PRE_ISSUE_ACCESS_TOKEN_ACTION_ID,
+ TENANT_ID));
}
- @Test(priority = 6)
+ @Test(priority = 5)
public void testAddActionWithoutDescription() throws ActionMgtException {
- String id = String.valueOf(UUID.randomUUID());
- Action creatingAction = buildMockAction(
- "PreIssueAccessToken",
- null,
- "https://example.com",
- buildMockBasicAuthentication("admin", "admin"));
- action = daoImpl.addAction(PRE_ISSUE_ACCESS_TOKEN, id, creatingAction, TENANT_ID);
- Assert.assertEquals(id, action.getId());
- Assert.assertEquals(creatingAction.getName(), action.getName());
- Assert.assertNull(null, action.getDescription());
- Assert.assertEquals(PRE_ISSUE_ACCESS_TOKEN, action.getType().getActionType());
- Assert.assertEquals(Action.Status.ACTIVE, action.getStatus());
- Assert.assertEquals(creatingAction.getEndpoint().getUri(), action.getEndpoint().getUri());
- Assert.assertEquals(creatingAction.getEndpoint().getAuthentication().getType(),
- action.getEndpoint().getAuthentication().getType());
+ ActionDTO creatingActionDTO = new ActionDTOBuilder()
+ .id(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID)
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .name(TestUtil.TEST_ACTION_NAME)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TestUtil.TEST_ACTION_URI)
+ .authentication(TestUtil.buildMockBasicAuthentication(TestUtil.TEST_USERNAME_SECRET_REFERENCE,
+ TestUtil.TEST_PASSWORD_SECRET_REFERENCE))
+ .build())
+ .property(TestUtil.TEST_ACTION_PROPERTY_NAME_1, TestUtil.TEST_ACTION_PROPERTY_VALUE_1)
+ .property(TestUtil.TEST_ACTION_PROPERTY_NAME_2, TestUtil.TEST_ACTION_PROPERTY_VALUE_2)
+ .build();
+ try {
+ daoImpl.addAction(creatingActionDTO, TENANT_ID);
+ } catch (Exception e) {
+ Assert.fail();
+ }
+ createdActionDTO = daoImpl.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_TYPE, PRE_ISSUE_ACCESS_TOKEN_ACTION_ID,
+ TENANT_ID);
+ Assert.assertEquals(createdActionDTO.getId(), creatingActionDTO.getId());
+ Assert.assertEquals(createdActionDTO.getType(), creatingActionDTO.getType());
+ Assert.assertEquals(createdActionDTO.getName(), creatingActionDTO.getName());
+ Assert.assertNull(createdActionDTO.getDescription());
+ Assert.assertEquals(createdActionDTO.getStatus(), Action.Status.ACTIVE);
+ Assert.assertEquals(createdActionDTO.getEndpoint().getUri(), creatingActionDTO.getEndpoint().getUri());
+
+ Authentication createdAuthentication = createdActionDTO.getEndpoint().getAuthentication();
+ Assert.assertEquals(createdAuthentication.getType(),
+ creatingActionDTO.getEndpoint().getAuthentication().getType());
+ Assert.assertEquals(createdAuthentication.getProperties().size(),
+ creatingActionDTO.getEndpoint().getAuthentication().getProperties().size());
+ Assert.assertEquals(createdAuthentication.getProperty(Authentication.Property.USERNAME).getValue(),
+ TestUtil.TEST_USERNAME_SECRET_REFERENCE);
+ Assert.assertEquals(createdAuthentication.getProperty(Authentication.Property.PASSWORD).getValue(),
+ TestUtil.TEST_PASSWORD_SECRET_REFERENCE);
+
+ Assert.assertEquals(createdActionDTO.getProperties().size(), creatingActionDTO.getProperties().size());
+ Assert.assertEquals(createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1),
+ creatingActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1));
+ Assert.assertEquals(createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2),
+ creatingActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2));
}
@Test(priority = 7, dependsOnMethods = "testAddActionWithoutDescription")
- public void testUpdateAction() throws ActionMgtException {
-
- Action updatingAction = buildMockAction(
- "Pre Issue Access Token",
- "To configure pre issue access token",
- "https://sample.com",
- buildMockBasicAuthentication("updatingadmin", "updatingadmin"));
- Action result = daoImpl.updateAction(PRE_ISSUE_ACCESS_TOKEN, action.getId(), updatingAction, action, TENANT_ID);
- Assert.assertEquals(action.getId(), result.getId());
- Assert.assertEquals(updatingAction.getName(), result.getName());
- Assert.assertEquals(updatingAction.getDescription(), result.getDescription());
- Assert.assertEquals(action.getType(), result.getType());
- Assert.assertEquals(action.getStatus(), result.getStatus());
- Assert.assertEquals(updatingAction.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(
- updatingAction.getEndpoint().getAuthentication().getType(),
- result.getEndpoint().getAuthentication().getType()
- );
- action = result;
+ public void testUpdateCompleteAction() throws ActionMgtException {
+
+ ActionDTO updatingAction = new ActionDTOBuilder()
+ .id(createdActionDTO.getId())
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .name(TestUtil.TEST_ACTION_NAME_UPDATED)
+ .description(TestUtil.TEST_ACTION_DESCRIPTION_UPDATED)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TestUtil.TEST_ACTION_URI_UPDATED)
+ .authentication(TestUtil.buildMockBearerAuthentication(
+ TestUtil.TEST_ACCESS_TOKEN_SECRET_REFERENCE))
+ .build())
+ .property(TestUtil.TEST_ACTION_PROPERTY_NAME_1, TestUtil.TEST_ACTION_PROPERTY_VALUE_1_UPDATED)
+ .property(TestUtil.TEST_ACTION_PROPERTY_NAME_2, TestUtil.TEST_ACTION_PROPERTY_VALUE_2_UPDATED)
+ .build();
+ try {
+ daoImpl.updateAction(updatingAction, createdActionDTO, TENANT_ID);
+ } catch (Exception e) {
+ Assert.fail();
+ }
+ ActionDTO result = daoImpl.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_TYPE, updatingAction.getId(), TENANT_ID);
+ Assert.assertEquals(result.getId(), createdActionDTO.getId());
+ Assert.assertEquals(result.getType(), createdActionDTO.getType());
+ Assert.assertEquals(result.getName(), updatingAction.getName());
+ Assert.assertEquals(result.getDescription(), updatingAction.getDescription());
+ Assert.assertEquals(result.getStatus(), createdActionDTO.getStatus());
+ Assert.assertEquals(result.getEndpoint().getUri(), updatingAction.getEndpoint().getUri());
+
+ Authentication updatedAuthentication = result.getEndpoint().getAuthentication();
+ Assert.assertEquals(updatedAuthentication.getType(),
+ updatingAction.getEndpoint().getAuthentication().getType());
+ Assert.assertEquals(updatedAuthentication.getProperties().size(),
+ updatingAction.getEndpoint().getAuthentication().getProperties().size());
+ Assert.assertEquals(updatedAuthentication.getProperty(Authentication.Property.ACCESS_TOKEN).getValue(),
+ TestUtil.TEST_ACCESS_TOKEN_SECRET_REFERENCE);
+
+ Assert.assertEquals(result.getProperties().size(), updatingAction.getProperties().size());
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1),
+ updatingAction.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1));
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2),
+ updatingAction.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2));
+ createdActionDTO = result;
}
@Test(priority = 8)
- public void testUpdateActionWithoutNameAndDescription() throws ActionMgtException {
-
- // TODO: 'Name' is a required attribute. Thus, DAO layer should throw an exception if name is null.
- // This should be fixed in DAO layer and test case needs to be updated accordingly.
- Action updatingAction = buildMockAction(
- null,
- null,
- "https://sample.com",
- buildMockBasicAuthentication("updatingadmin", "updatingadmin"));
- Action result = daoImpl.updateAction(PRE_ISSUE_ACCESS_TOKEN, action.getId(), updatingAction, action, TENANT_ID);
- Assert.assertEquals(action.getId(), result.getId());
- Assert.assertEquals(action.getName(), result.getName());
- Assert.assertEquals(action.getDescription(), result.getDescription());
- Assert.assertEquals(action.getType(), result.getType());
- Assert.assertEquals(action.getStatus(), result.getStatus());
- Assert.assertEquals(updatingAction.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(updatingAction.getEndpoint().getAuthentication().getType(),
- result.getEndpoint().getAuthentication().getType());
- }
+ public void testUpdateActionBasicInfo() throws ActionMgtException {
- @Test(priority = 9)
- public void testUpdateActionWithNameAndDescription() throws ActionMgtException {
-
- // TODO: 'Uri','AuthenticationType','AuthProperties' are required attributes. Thus, DAO layer should throw an
- // exception if those attributes are null. This should be fixed in DAO layer and test case needs to be updated
- // accordingly.
- Action updatingAction = buildMockAction(
- "Pre Issue Access Token",
- "To configure pre issue access token",
- null,
- null);
- Action result = daoImpl.updateAction(PRE_ISSUE_ACCESS_TOKEN, action.getId(), updatingAction, action, TENANT_ID);
- Assert.assertEquals(action.getId(), result.getId());
- Assert.assertEquals(updatingAction.getName(), result.getName());
- Assert.assertEquals(updatingAction.getDescription(), result.getDescription());
- Assert.assertEquals(action.getType(), result.getType());
- Assert.assertEquals(action.getStatus(), result.getStatus());
- Assert.assertEquals(action.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(action.getEndpoint().getAuthentication().getType(),
- result.getEndpoint().getAuthentication().getType());
- }
+ ActionDTO updatingAction = new ActionDTOBuilder()
+ .id(createdActionDTO.getId())
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .name(TestUtil.TEST_ACTION_NAME)
+ .description(TestUtil.TEST_ACTION_DESCRIPTION)
+ .build();
- @Test(priority = 10)
- public void testUpdateActionEndpointAuthSecretProperties() throws ActionMgtException {
-
- Authentication authentication = buildMockBasicAuthentication("newadmin", "newadmin");
- Action result = daoImpl.updateActionEndpointAuthProperties(PRE_ISSUE_ACCESS_TOKEN, action.getId(),
- authentication, TENANT_ID);
- Assert.assertEquals(Authentication.Type.BASIC, result.getEndpoint().getAuthentication().getType());
- Assert.assertEquals(
- action.getEndpoint().getAuthentication().getProperty(Authentication.Property.USERNAME).getValue(),
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.USERNAME).getValue());
- Assert.assertEquals(
- action.getEndpoint().getAuthentication().getProperty(Authentication.Property.PASSWORD).getValue(),
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.PASSWORD).getValue());
+ try {
+ daoImpl.updateAction(updatingAction, createdActionDTO, TENANT_ID);
+ } catch (Exception e) {
+ Assert.fail();
+ }
+ ActionDTO result = daoImpl.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_TYPE, updatingAction.getId(), TENANT_ID);
+ Assert.assertEquals(result.getId(), createdActionDTO.getId());
+ Assert.assertEquals(result.getType(), createdActionDTO.getType());
+ Assert.assertEquals(result.getName(), updatingAction.getName());
+ Assert.assertEquals(result.getDescription(), updatingAction.getDescription());
+ Assert.assertEquals(result.getStatus(), createdActionDTO.getStatus());
+ Assert.assertEquals(result.getEndpoint().getUri(), createdActionDTO.getEndpoint().getUri());
+
+ Authentication resultAuthentication = result.getEndpoint().getAuthentication();
+ Assert.assertEquals(resultAuthentication.getType(),
+ createdActionDTO.getEndpoint().getAuthentication().getType());
+ Assert.assertEquals(resultAuthentication.getProperties().size(),
+ createdActionDTO.getEndpoint().getAuthentication().getProperties().size());
+ Assert.assertEquals(resultAuthentication.getProperty(Authentication.Property.ACCESS_TOKEN).getValue(),
+ TestUtil.TEST_ACCESS_TOKEN_SECRET_REFERENCE);
+
+ Assert.assertEquals(result.getProperties().size(), createdActionDTO.getProperties().size());
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1),
+ createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1));
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2),
+ createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2));
+ createdActionDTO = result;
}
- @Test(priority = 11)
- public void testUpdateActionWithoutEndpointUri() throws ActionMgtException {
-
- // TODO: 'Uri' is a required attribute. Thus, DAO layer should throw an exception if Uri is null.
- // This should be fixed in DAO layer and test case needs to be updated accordingly.
- Action updatingAction = buildMockAction(
- "Pre Issue Access Token",
- "To configure pre issue access token",
- null,
- buildMockBasicAuthentication("updatingadmin", "updatingadmin"));
- Action result = daoImpl.updateAction(PRE_ISSUE_ACCESS_TOKEN, action.getId(), updatingAction, action, TENANT_ID);
- Assert.assertEquals(action.getId(), result.getId());
- Assert.assertEquals(updatingAction.getName(), result.getName());
- Assert.assertEquals(updatingAction.getDescription(), result.getDescription());
- Assert.assertEquals(action.getType(), result.getType());
- Assert.assertEquals(action.getStatus(), result.getStatus());
- Assert.assertEquals(action.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(updatingAction.getEndpoint().getAuthentication().getType(),
- result.getEndpoint().getAuthentication().getType());
- }
+ @Test(priority = 9)
+ public void testUpdateActionEndpoint() throws ActionMgtException {
- @Test(priority = 12)
- public void testUpdateActionWithAuthType() throws ActionMgtException {
-
- Action updatingAction = buildMockAction(
- "Pre Issue Access Token",
- "To configure pre issue access token",
- "https://sample.com",
- buildMockBearerAuthentication("57c7df90-cacc-4f56-9b0a-f14bfbff3076"));
- Action result = daoImpl.updateAction(PRE_ISSUE_ACCESS_TOKEN, action.getId(), updatingAction, action, TENANT_ID);
- Assert.assertEquals(action.getId(), result.getId());
- Assert.assertEquals(action.getName(), result.getName());
- Assert.assertEquals(action.getDescription(), result.getDescription());
- Assert.assertEquals(action.getType(), result.getType());
- Assert.assertEquals(action.getStatus(), result.getStatus());
- Assert.assertEquals(updatingAction.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(updatingAction.getEndpoint().getAuthentication().getType(),
- result.getEndpoint().getAuthentication().getType());
- action = result;
- }
+ ActionDTO updatingAction = new ActionDTOBuilder()
+ .id(createdActionDTO.getId())
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TestUtil.TEST_ACTION_URI)
+ .authentication(TestUtil.buildMockAPIKeyAuthentication(TestUtil.TEST_API_KEY_HEADER,
+ TestUtil.TEST_API_KEY_VALUE_SECRET_REFERENCE))
+ .build())
+ .build();
- @Test(priority = 13)
- public void testUpdateActionWithUri() throws ActionMgtException {
-
- // TODO: 'Name','AuthenticationType' and 'AuthProperties' are required attributes. Thus, DAO layer should throw
- // an exception if those attributes are null. This should be fixed in DAO layer and test case needs to be
- // updated accordingly.
- Action updatingAction = buildMockAction(
- null,
- null,
- "https://sample.com",
- null);
- Action result = daoImpl.updateAction(PRE_ISSUE_ACCESS_TOKEN, action.getId(), updatingAction, action, TENANT_ID);
- Assert.assertEquals(action.getId(), result.getId());
- Assert.assertEquals(action.getName(), result.getName());
- Assert.assertEquals(action.getDescription(), result.getDescription());
- Assert.assertEquals(action.getType(), result.getType());
- Assert.assertEquals(action.getStatus(), result.getStatus());
- Assert.assertEquals(updatingAction.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(action.getEndpoint().getAuthentication().getType(),
- result.getEndpoint().getAuthentication().getType());
- action = result;
+ try {
+ daoImpl.updateAction(updatingAction, createdActionDTO, TENANT_ID);
+ } catch (Exception e) {
+ Assert.fail();
+ }
+ ActionDTO result = daoImpl.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_TYPE, updatingAction.getId(), TENANT_ID);
+ Assert.assertEquals(result.getId(), createdActionDTO.getId());
+ Assert.assertEquals(result.getType(), createdActionDTO.getType());
+ Assert.assertEquals(result.getName(), createdActionDTO.getName());
+ Assert.assertEquals(result.getDescription(), createdActionDTO.getDescription());
+ Assert.assertEquals(result.getStatus(), createdActionDTO.getStatus());
+ Assert.assertEquals(result.getEndpoint().getUri(), updatingAction.getEndpoint().getUri());
+
+ Authentication updatedAuthentication = result.getEndpoint().getAuthentication();
+ Assert.assertEquals(updatedAuthentication.getType(),
+ updatingAction.getEndpoint().getAuthentication().getType());
+ Assert.assertEquals(updatedAuthentication.getProperties().size(),
+ updatingAction.getEndpoint().getAuthentication().getProperties().size());
+ Assert.assertEquals(updatedAuthentication.getProperty(Authentication.Property.HEADER).getValue(),
+ TestUtil.TEST_API_KEY_HEADER);
+ Assert.assertEquals(updatedAuthentication.getProperty(Authentication.Property.VALUE).getValue(),
+ TestUtil.TEST_API_KEY_VALUE_SECRET_REFERENCE);
+
+ Assert.assertEquals(result.getProperties().size(), createdActionDTO.getProperties().size());
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1),
+ createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1));
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2),
+ createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2));
+ createdActionDTO = result;
}
- @Test(priority = 14)
- public void testUpdateActionWithAuthTypeWithoutUri() throws ActionMgtException {
-
- // TODO: 'Uri' is a required attribute. Thus, DAO layer should throw an exception if uri is null.
- // This should be fixed in DAO layer and test case needs to be updated accordingly.
- Action updatingAction = buildMockAction(
- "Pre Issue Access Token",
- "To configure pre issue access token",
- null,
- buildMockBasicAuthentication("updatingadmin", "updatingadmin"));
- Action result = daoImpl.updateAction(PRE_ISSUE_ACCESS_TOKEN, action.getId(), updatingAction, action, TENANT_ID);
- Assert.assertEquals(action.getId(), result.getId());
- Assert.assertEquals(updatingAction.getName(), result.getName());
- Assert.assertEquals(updatingAction.getDescription(), result.getDescription());
- Assert.assertEquals(action.getType(), result.getType());
- Assert.assertEquals(action.getStatus(), result.getStatus());
- Assert.assertEquals(action.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(updatingAction.getEndpoint().getAuthentication().getType(),
- result.getEndpoint().getAuthentication().getType());
- }
+ @Test(priority = 10)
+ public void testUpdateActionEndpointUri() throws ActionMgtException {
+
+ ActionDTO updatingAction = new ActionDTOBuilder()
+ .id(createdActionDTO.getId())
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TestUtil.TEST_ACTION_URI_UPDATED)
+ .build())
+ .build();
- @Test(priority = 15)
- public void testUpdateActionEndpointAuthNonSecretProperties() throws ActionMgtException {
-
- Action sampleAction = buildMockAction(
- "Pre Issue Access Token",
- "To configure pre issue access token",
- "https://sample.com",
- buildMockAPIKeyAuthentication("header", "value"));
- Action updatingAction = daoImpl.updateAction(
- PRE_ISSUE_ACCESS_TOKEN, action.getId(), sampleAction, action, TENANT_ID);
- Authentication authentication = buildMockAPIKeyAuthentication("updatingheader", "updatingvalue");
- Action result = daoImpl.updateActionEndpointAuthProperties(PRE_ISSUE_ACCESS_TOKEN, updatingAction.getId(),
- authentication, TENANT_ID);
- Assert.assertEquals(Authentication.Type.API_KEY, result.getEndpoint().getAuthentication().getType());
- Assert.assertEquals(authentication.getProperty(Authentication.Property.HEADER).getValue(),
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.HEADER).getValue());
- Assert.assertEquals(
- updatingAction.getEndpoint().getAuthentication().getProperty(Authentication.Property.VALUE).getValue(),
- result.getEndpoint().getAuthentication().getProperty(Authentication.Property.VALUE).getValue());
+ try {
+ daoImpl.updateAction(updatingAction, createdActionDTO, TENANT_ID);
+ } catch (Exception e) {
+ Assert.fail();
+ }
+ ActionDTO result = daoImpl.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_TYPE, updatingAction.getId(), TENANT_ID);
+ Assert.assertEquals(result.getId(), createdActionDTO.getId());
+ Assert.assertEquals(result.getType(), createdActionDTO.getType());
+ Assert.assertEquals(result.getName(), createdActionDTO.getName());
+ Assert.assertEquals(result.getDescription(), createdActionDTO.getDescription());
+ Assert.assertEquals(result.getStatus(), createdActionDTO.getStatus());
+ Assert.assertEquals(result.getEndpoint().getUri(), updatingAction.getEndpoint().getUri());
+
+ Authentication resultAuthentication = result.getEndpoint().getAuthentication();
+ Assert.assertEquals(resultAuthentication.getType(),
+ createdActionDTO.getEndpoint().getAuthentication().getType());
+ Assert.assertEquals(resultAuthentication.getProperties().size(),
+ createdActionDTO.getEndpoint().getAuthentication().getProperties().size());
+ Assert.assertEquals(resultAuthentication.getProperty(Authentication.Property.HEADER).getValue(),
+ TestUtil.TEST_API_KEY_HEADER);
+ Assert.assertEquals(resultAuthentication.getProperty(Authentication.Property.VALUE).getValue(),
+ TestUtil.TEST_API_KEY_VALUE_SECRET_REFERENCE);
+
+ Assert.assertEquals(result.getProperties().size(), createdActionDTO.getProperties().size());
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1),
+ createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1));
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2),
+ createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2));
+ createdActionDTO = result;
}
- @Test(priority = 16)
- public void testDeactivateAction() throws ActionMgtException {
+ @Test(priority = 11)
+ public void testUpdateActionEndpointAuthenticationWithSameAuthType() throws ActionMgtException {
+
+ ActionDTO updatingAction = new ActionDTOBuilder()
+ .id(createdActionDTO.getId())
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .authentication(TestUtil.buildMockAPIKeyAuthentication(TestUtil.TEST_API_KEY_HEADER_UPDATED,
+ TestUtil.TEST_API_KEY_VALUE_SECRET_REFERENCE))
+ .build())
+ .build();
- Assert.assertEquals(Action.Status.ACTIVE, action.getStatus());
- Action deactivatedAction = daoImpl.deactivateAction(PRE_ISSUE_ACCESS_TOKEN, action.getId(), TENANT_ID);
- Assert.assertEquals(Action.Status.INACTIVE, deactivatedAction.getStatus());
+ try {
+ daoImpl.updateAction(updatingAction, createdActionDTO, TENANT_ID);
+ } catch (Exception e) {
+ Assert.fail();
+ }
+ ActionDTO result = daoImpl.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_TYPE, updatingAction.getId(), TENANT_ID);
+ Assert.assertEquals(result.getId(), createdActionDTO.getId());
+ Assert.assertEquals(result.getType(), createdActionDTO.getType());
+ Assert.assertEquals(result.getName(), createdActionDTO.getName());
+ Assert.assertEquals(result.getDescription(), createdActionDTO.getDescription());
+ Assert.assertEquals(result.getStatus(), createdActionDTO.getStatus());
+ Assert.assertEquals(result.getEndpoint().getUri(), createdActionDTO.getEndpoint().getUri());
+
+ Authentication updatedAuthentication = result.getEndpoint().getAuthentication();
+ Assert.assertEquals(updatedAuthentication.getType(),
+ updatingAction.getEndpoint().getAuthentication().getType());
+ Assert.assertEquals(updatedAuthentication.getProperties().size(),
+ updatingAction.getEndpoint().getAuthentication().getProperties().size());
+ Assert.assertEquals(updatedAuthentication.getProperty(Authentication.Property.HEADER).getValue(),
+ TestUtil.TEST_API_KEY_HEADER_UPDATED);
+ Assert.assertEquals(updatedAuthentication.getProperty(Authentication.Property.VALUE).getValue(),
+ TestUtil.TEST_API_KEY_VALUE_SECRET_REFERENCE);
+
+ Assert.assertEquals(result.getProperties().size(), createdActionDTO.getProperties().size());
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1),
+ createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1));
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2),
+ createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2));
+ createdActionDTO = result;
}
- @Test(priority = 17)
- public void testActivateAction() throws ActionMgtException {
+ @Test(priority = 12)
+ public void testUpdateActionEndpointAuthenticationWithDifferentAuthType() throws ActionMgtException {
+
+ ActionDTO updatingAction = new ActionDTOBuilder()
+ .id(createdActionDTO.getId())
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .authentication(new Authentication.NoneAuthBuilder().build())
+ .build())
+ .build();
- Action result = daoImpl.activateAction(PRE_ISSUE_ACCESS_TOKEN, action.getId(), TENANT_ID);
- Assert.assertEquals(Action.Status.ACTIVE, result.getStatus());
+ try {
+ daoImpl.updateAction(updatingAction, createdActionDTO, TENANT_ID);
+ } catch (Exception e) {
+ Assert.fail();
+ }
+ ActionDTO result = daoImpl.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_TYPE, updatingAction.getId(), TENANT_ID);
+ Assert.assertEquals(result.getId(), createdActionDTO.getId());
+ Assert.assertEquals(result.getType(), createdActionDTO.getType());
+ Assert.assertEquals(result.getName(), createdActionDTO.getName());
+ Assert.assertEquals(result.getDescription(), createdActionDTO.getDescription());
+ Assert.assertEquals(result.getStatus(), createdActionDTO.getStatus());
+ Assert.assertEquals(result.getEndpoint().getUri(), createdActionDTO.getEndpoint().getUri());
+
+ Authentication updatedAuthentication = result.getEndpoint().getAuthentication();
+ Assert.assertEquals(updatedAuthentication.getType(),
+ updatingAction.getEndpoint().getAuthentication().getType());
+ Assert.assertEquals(updatedAuthentication.getProperties().size(),
+ updatingAction.getEndpoint().getAuthentication().getProperties().size());
+
+ Assert.assertEquals(result.getProperties().size(), createdActionDTO.getProperties().size());
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1),
+ createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1));
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2),
+ createdActionDTO.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2));
+ createdActionDTO = result;
}
- @Test(priority = 18)
- public void testUpdateActionEndpoint() throws ActionMgtException {
-
- EndpointConfig endpointConfig = buildMockEndpointConfig("https://template.com",
- buildMockBearerAuthentication("c7fce95f-3f5b-4cda-8bb1-4cb7b3990f83"));
- Action result = daoImpl.updateActionEndpoint(
- PRE_ISSUE_ACCESS_TOKEN, action.getId(), endpointConfig, action.getEndpoint()
- .getAuthentication(), TENANT_ID);
- Assert.assertNotEquals(action.getEndpoint().getUri(), result.getEndpoint().getUri());
- Assert.assertEquals(Authentication.Type.BEARER.getName(),
- result.getEndpoint().getAuthentication().getType().getName());
- }
+ @Test(priority = 13)
+ public void testUpdateActionProperties() throws ActionMgtException {
- @Test(priority = 19)
- public void testGetActionsCountPerType() throws ActionMgtException {
+ ActionDTO updatingAction = new ActionDTOBuilder()
+ .id(createdActionDTO.getId())
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .property(TestUtil.TEST_ACTION_PROPERTY_NAME_1, TestUtil.TEST_ACTION_PROPERTY_VALUE_1)
+ .property(TestUtil.TEST_ACTION_PROPERTY_NAME_2, TestUtil.TEST_ACTION_PROPERTY_VALUE_2)
+ .build();
- Map actionMap = daoImpl.getActionsCountPerType(TENANT_ID);
- for (Map.Entry entry: actionMap.entrySet()) {
- Assert.assertEquals(PRE_ISSUE_ACCESS_TOKEN, entry.getKey());
- Assert.assertEquals(1, entry.getValue().intValue());
+ try {
+ daoImpl.updateAction(updatingAction, createdActionDTO, TENANT_ID);
+ } catch (Exception e) {
+ Assert.fail();
}
+ ActionDTO result = daoImpl.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_TYPE, updatingAction.getId(), TENANT_ID);
+ Assert.assertEquals(result.getId(), createdActionDTO.getId());
+ Assert.assertEquals(result.getType(), createdActionDTO.getType());
+ Assert.assertEquals(result.getName(), createdActionDTO.getName());
+ Assert.assertEquals(result.getDescription(), createdActionDTO.getDescription());
+ Assert.assertEquals(result.getStatus(), createdActionDTO.getStatus());
+ Assert.assertEquals(result.getEndpoint().getUri(), createdActionDTO.getEndpoint().getUri());
+
+ Authentication resultAuthentication = result.getEndpoint().getAuthentication();
+ Assert.assertEquals(resultAuthentication.getType(),
+ createdActionDTO.getEndpoint().getAuthentication().getType());
+ Assert.assertEquals(resultAuthentication.getProperties().size(),
+ createdActionDTO.getEndpoint().getAuthentication().getProperties().size());
+
+ Assert.assertEquals(result.getProperties().size(), updatingAction.getProperties().size());
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1),
+ updatingAction.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_1));
+ Assert.assertEquals(result.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2),
+ updatingAction.getProperty(TestUtil.TEST_ACTION_PROPERTY_NAME_2));
+ createdActionDTO = result;
}
- private Authentication buildMockBasicAuthentication(String username, String password) {
-
- return new Authentication.BasicAuthBuilder(username, password).build();
- }
- private Authentication buildMockBearerAuthentication(String accessToken) {
+ @Test(priority = 14)
+ public void testDeactivateAction() throws ActionMgtException {
- return new Authentication.BearerAuthBuilder(accessToken).build();
+ Assert.assertEquals(createdActionDTO.getStatus(), Action.Status.ACTIVE);
+ ActionDTO deactivatedActionDTO = daoImpl.deactivateAction(PRE_ISSUE_ACCESS_TOKEN_TYPE, createdActionDTO.getId(),
+ TENANT_ID);
+ Assert.assertEquals(deactivatedActionDTO.getStatus(), Action.Status.INACTIVE);
}
- private Authentication buildMockAPIKeyAuthentication(String header, String value) {
+ @Test(priority = 15)
+ public void testActivateAction() throws ActionMgtException {
- return new Authentication.APIKeyAuthBuilder(header, value).build();
+ ActionDTO activatedActionDTO = daoImpl.activateAction(PRE_ISSUE_ACCESS_TOKEN_TYPE, createdActionDTO.getId(),
+ TENANT_ID);
+ Assert.assertEquals(activatedActionDTO.getStatus(), Action.Status.ACTIVE);
}
- private EndpointConfig buildMockEndpointConfig(String uri, Authentication authentication) {
-
- if (uri == null && authentication == null) {
- return null;
- }
+ @Test(priority = 16)
+ public void testGetActionsCountPerType() throws ActionMgtException {
- return new EndpointConfig.EndpointConfigBuilder()
- .uri(uri)
- .authentication(authentication)
+ ActionDTO creatingPreUpdatePasswordActionDTO = new ActionDTOBuilder()
+ .id(PRE_UPDATE_PASSWORD_ACTION_ID)
+ .type(Action.ActionTypes.PRE_UPDATE_PASSWORD)
+ .name(TestUtil.TEST_ACTION_NAME)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TestUtil.TEST_ACTION_URI)
+ .authentication(new Authentication.NoneAuthBuilder().build())
+ .build())
.build();
- }
- private Action buildMockAction(String name,
- String description,
- String uri,
- Authentication authentication) {
+ daoImpl.addAction(creatingPreUpdatePasswordActionDTO, TENANT_ID);
+ ActionDTO createdPreUpdatePasswordActionDTO = daoImpl.getActionByActionId(PRE_UPDATE_PASSWORD_TYPE,
+ PRE_UPDATE_PASSWORD_ACTION_ID, TENANT_ID);
- return new Action.ActionRequestBuilder()
- .name(name)
- .description(description)
- .endpoint(buildMockEndpointConfig(uri, authentication))
- .build();
+ Map actionMap = daoImpl.getActionsCountPerType(TENANT_ID);
+ Assert.assertTrue(actionMap.containsKey(PRE_ISSUE_ACCESS_TOKEN_TYPE));
+ Assert.assertEquals(actionMap.get(PRE_ISSUE_ACCESS_TOKEN_TYPE).intValue(), 1);
+ Assert.assertTrue(actionMap.containsKey(PRE_UPDATE_PASSWORD_TYPE));
+ Assert.assertEquals(actionMap.get(PRE_UPDATE_PASSWORD_TYPE).intValue(), 1);
+
+ daoImpl.deleteAction(createdPreUpdatePasswordActionDTO, TENANT_ID);
+ daoImpl.deleteAction(createdActionDTO, TENANT_ID);
}
}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/dao/TestActionDTOModelResolver.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/dao/TestActionDTOModelResolver.java
new file mode 100644
index 000000000000..2b5424d40672
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/dao/TestActionDTOModelResolver.java
@@ -0,0 +1,111 @@
+/*
+ * 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.carbon.identity.action.management.dao;
+
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.ActionDTO;
+import org.wso2.carbon.identity.action.management.service.ActionDTOModelResolver;
+import org.wso2.carbon.identity.action.management.util.TestUtil;
+import org.wso2.carbon.identity.certificate.management.model.Certificate;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.wso2.carbon.identity.action.management.util.TestUtil.CERTIFICATE_NAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.CERTIFICATE_PROPERTY_NAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PASSWORD_SHARING_TYPE_PROPERTY_NAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_CERTIFICATE;
+
+/**
+ * Test implementation of {@link ActionDTOModelResolver}.
+ */
+public class TestActionDTOModelResolver implements ActionDTOModelResolver {
+
+ @Override
+ public Action.ActionTypes getSupportedActionType() {
+
+ return Action.ActionTypes.PRE_UPDATE_PASSWORD;
+ }
+
+ @Override
+ public ActionDTO resolveForAddOperation(ActionDTO actionDTO, String tenantDomain) {
+
+ Map properties = new HashMap<>();
+ properties.put(PASSWORD_SHARING_TYPE_PROPERTY_NAME, actionDTO.getProperty(PASSWORD_SHARING_TYPE_PROPERTY_NAME));
+ properties.put(CERTIFICATE_PROPERTY_NAME, TestUtil.CERTIFICATE_ID);
+
+ return new ActionDTO.Builder(actionDTO).properties(properties).build();
+ }
+
+ @Override
+ public ActionDTO resolveForGetOperation(ActionDTO actionDTO, String tenantDomain) {
+
+ Map properties = new HashMap<>();
+ properties.put(PASSWORD_SHARING_TYPE_PROPERTY_NAME,
+ actionDTO.getProperty(PASSWORD_SHARING_TYPE_PROPERTY_NAME));
+ if (actionDTO.getProperty(CERTIFICATE_PROPERTY_NAME) != null) {
+ properties.put(CERTIFICATE_PROPERTY_NAME, new Certificate.Builder()
+ .id((String) actionDTO.getProperty(CERTIFICATE_PROPERTY_NAME))
+ .name(CERTIFICATE_NAME)
+ .certificateContent(TEST_CERTIFICATE)
+ .build());
+ }
+
+ return new ActionDTO.Builder(actionDTO).properties(properties).build();
+ }
+
+ @Override
+ public List resolveForGetOperation(List actionDTOList, String tenantDomain) {
+
+ List resolvedActionDTOList = new ArrayList<>();
+ for (ActionDTO actionDTO : actionDTOList) {
+ Map properties = new HashMap<>();
+ properties.put(PASSWORD_SHARING_TYPE_PROPERTY_NAME,
+ actionDTO.getProperty(PASSWORD_SHARING_TYPE_PROPERTY_NAME));
+ properties.put(CERTIFICATE_PROPERTY_NAME, new Certificate.Builder()
+ .id((String) actionDTO.getProperty(CERTIFICATE_PROPERTY_NAME))
+ .name(CERTIFICATE_NAME)
+ .certificateContent(TEST_CERTIFICATE)
+ .build());
+
+ resolvedActionDTOList.add(new ActionDTO.Builder(actionDTO).properties(properties).build());
+ }
+
+ return resolvedActionDTOList;
+ }
+
+ @Override
+ public ActionDTO resolveForUpdateOperation(ActionDTO updatingActionDTO, ActionDTO existingActionDTO,
+ String tenantDomain) {
+
+ Map properties = new HashMap<>();
+ properties.put(PASSWORD_SHARING_TYPE_PROPERTY_NAME,
+ updatingActionDTO.getProperty(PASSWORD_SHARING_TYPE_PROPERTY_NAME));
+
+ return new ActionDTO.Builder(updatingActionDTO).properties(properties).build();
+ }
+
+ @Override
+ public void resolveForDeleteOperation(ActionDTO deletingActionDTO, String tenantDomain) {
+
+ // No need to resolve anything for delete operation since this is a test implementation.
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/service/ActionConverterFactoryTest.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/service/ActionConverterFactoryTest.java
new file mode 100644
index 000000000000..424926205532
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/service/ActionConverterFactoryTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.carbon.identity.action.management.service;
+
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.service.impl.ActionConverterFactory;
+
+import static org.mockito.Mockito.doReturn;
+
+/**
+ * Action Converter Factory Test.
+ */
+public class ActionConverterFactoryTest {
+
+ private final Action.ActionTypes actionType = Action.ActionTypes.PRE_UPDATE_PASSWORD;
+ @Mock
+ private ActionConverter mockActionConverter;
+
+ @BeforeMethod
+ public void setUp() {
+
+ MockitoAnnotations.openMocks(this);
+ doReturn(actionType).when(mockActionConverter).getSupportedActionType();
+ }
+
+ @Test
+ public void testRegisterActionConverter() {
+
+ ActionConverterFactory.registerActionConverter(mockActionConverter);
+ ActionConverter registeredResult = ActionConverterFactory.getActionConverter(actionType);
+ Assert.assertEquals(registeredResult, mockActionConverter);
+ }
+
+ @Test(dependsOnMethods = {"testRegisterActionConverter"})
+ public void testUnregisterActionConverter() {
+
+ ActionConverterFactory.unregisterActionConverter(mockActionConverter);
+ ActionConverter unregisteredResult = ActionConverterFactory.getActionConverter(actionType);
+ Assert.assertNull(unregisteredResult);
+ }
+
+ @Test(dependsOnMethods = {"testUnregisterActionConverter"})
+ public void testGetActionConverterNotFound() {
+
+ ActionConverter result = ActionConverterFactory.getActionConverter(actionType);
+ Assert.assertNull(result);
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/service/ActionManagementServiceImplTest.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/service/ActionManagementServiceImplTest.java
new file mode 100644
index 000000000000..1d159ec3bcde
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/service/ActionManagementServiceImplTest.java
@@ -0,0 +1,330 @@
+/*
+ * 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.carbon.identity.action.management.service;
+
+import org.apache.commons.lang.StringUtils;
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.wso2.carbon.identity.action.management.exception.ActionMgtClientException;
+import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
+import org.wso2.carbon.identity.action.management.internal.ActionMgtServiceComponentHolder;
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.AuthProperty;
+import org.wso2.carbon.identity.action.management.model.Authentication;
+import org.wso2.carbon.identity.action.management.service.impl.ActionManagementServiceImpl;
+import org.wso2.carbon.identity.action.management.util.TestUtil;
+import org.wso2.carbon.identity.common.testng.WithCarbonHome;
+import org.wso2.carbon.identity.common.testng.WithH2Database;
+import org.wso2.carbon.identity.common.testng.WithRealmService;
+import org.wso2.carbon.identity.core.internal.IdentityCoreServiceDataHolder;
+import org.wso2.carbon.identity.secret.mgt.core.SecretManagerImpl;
+import org.wso2.carbon.identity.secret.mgt.core.exception.SecretManagementException;
+import org.wso2.carbon.identity.secret.mgt.core.model.SecretType;
+
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_ISSUE_ACCESS_TOKEN_PATH;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TENANT_DOMAIN;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACCESS_TOKEN;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_DESCRIPTION;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_DESCRIPTION_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_NAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_NAME_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_URI;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_API_KEY_HEADER;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_API_KEY_HEADER_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_API_KEY_VALUE;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_API_KEY_VALUE_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_INVALID_ACTION_NAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_INVALID_API_KEY_HEADER;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_PASSWORD;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_USERNAME;
+
+/**
+ * This class is a test suite for the ActionManagementServiceImpl class.
+ * It contains unit tests to verify the functionality of the methods
+ * in the ActionManagementServiceImpl class.
+ */
+@WithCarbonHome
+@WithH2Database(files = {"dbscripts/h2.sql"})
+@WithRealmService(injectToSingletons = {IdentityCoreServiceDataHolder.class})
+public class ActionManagementServiceImplTest {
+
+ private ActionManagementService actionManagementService;
+ private Action sampleAction;
+
+ @BeforeClass
+ public void setUpClass() {
+
+ actionManagementService = new ActionManagementServiceImpl();
+ }
+
+ @BeforeMethod
+ public void setUp() throws SecretManagementException {
+
+ SecretManagerImpl secretManager = mock(SecretManagerImpl.class);
+ SecretType secretType = mock(SecretType.class);
+ ActionMgtServiceComponentHolder.getInstance().setSecretManager(secretManager);
+ when(secretType.getId()).thenReturn(TestUtil.TEST_SECRET_TYPE_ID);
+ when(secretManager.getSecretType(any())).thenReturn(secretType);
+ }
+
+ @Test(priority = 1)
+ public void testAddAction() throws ActionMgtException, SecretManagementException {
+
+ Action creatingAction = TestUtil.buildMockAction(
+ TEST_ACTION_NAME,
+ TEST_ACTION_DESCRIPTION,
+ TEST_ACTION_URI,
+ TestUtil.buildMockBasicAuthentication(TEST_USERNAME, TEST_PASSWORD));
+ sampleAction = actionManagementService.addAction(PRE_ISSUE_ACCESS_TOKEN_PATH, creatingAction, TENANT_DOMAIN);
+
+ Assert.assertNotNull(sampleAction.getId());
+ Assert.assertEquals(sampleAction.getName(), creatingAction.getName());
+ Assert.assertEquals(sampleAction.getDescription(), creatingAction.getDescription());
+ Assert.assertEquals(sampleAction.getStatus(), Action.Status.ACTIVE);
+ Assert.assertEquals(sampleAction.getType(), Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN);
+ Assert.assertEquals(sampleAction.getEndpoint().getUri(), creatingAction.getEndpoint().getUri());
+
+ Authentication sampleActionAuth = sampleAction.getEndpoint().getAuthentication();
+ Authentication creatingActionAuth = creatingAction.getEndpoint().getAuthentication();
+ Map secretProperties = resolveAuthPropertiesMap(creatingActionAuth, sampleAction.getId());
+
+ Assert.assertEquals(sampleActionAuth.getType(), creatingActionAuth.getType());
+ Assert.assertEquals(sampleActionAuth.getProperties().size(), creatingActionAuth.getProperties().size());
+ Assert.assertEquals(sampleActionAuth.getProperty(Authentication.Property.USERNAME).getValue(),
+ secretProperties.get(Authentication.Property.USERNAME.getName()));
+ Assert.assertEquals(sampleActionAuth.getProperty(Authentication.Property.PASSWORD).getValue(),
+ secretProperties.get(Authentication.Property.PASSWORD.getName()));
+ }
+
+ @Test(priority = 2, expectedExceptions = ActionMgtClientException.class,
+ expectedExceptionsMessageRegExp = "Invalid request.")
+ public void testAddActionWithInvalidData() throws ActionMgtException {
+ Action creatingAction = TestUtil.buildMockAction(
+ TEST_INVALID_ACTION_NAME,
+ TEST_ACTION_DESCRIPTION,
+ TEST_ACTION_URI,
+ TestUtil.buildMockAPIKeyAuthentication(TEST_INVALID_API_KEY_HEADER, TEST_API_KEY_VALUE));
+ Action action = actionManagementService.addAction(PRE_ISSUE_ACCESS_TOKEN_PATH, creatingAction, TENANT_DOMAIN);
+ Assert.assertNull(action);
+ }
+
+ @Test(priority = 3, expectedExceptions = ActionMgtClientException.class,
+ expectedExceptionsMessageRegExp = "Invalid request.")
+ public void testAddActionWithEmptyData() throws ActionMgtException {
+ Action creatingAction = TestUtil.buildMockAction(
+ StringUtils.EMPTY,
+ TEST_ACTION_DESCRIPTION,
+ TEST_ACTION_URI,
+ TestUtil.buildMockBasicAuthentication(null, TEST_PASSWORD));
+ Action action = actionManagementService.addAction(PRE_ISSUE_ACCESS_TOKEN_PATH, creatingAction, TENANT_DOMAIN);
+ Assert.assertNull(action);
+ }
+
+ @Test(priority = 4, expectedExceptions = ActionMgtException.class,
+ expectedExceptionsMessageRegExp = "Unable to create an Action.")
+ public void testAddMaximumActionsPerType() throws ActionMgtException {
+
+ Action creatingAction = TestUtil.buildMockAction(
+ TEST_ACTION_NAME,
+ TEST_ACTION_DESCRIPTION,
+ TEST_ACTION_URI,
+ TestUtil.buildMockBasicAuthentication(TEST_USERNAME, TEST_PASSWORD));
+ sampleAction = actionManagementService.addAction(PRE_ISSUE_ACCESS_TOKEN_PATH, creatingAction,
+ TENANT_DOMAIN);
+ }
+
+ @Test(priority = 5)
+ public void testGetActionsByActionType() throws ActionMgtException {
+
+ List actions = actionManagementService.getActionsByActionType(PRE_ISSUE_ACCESS_TOKEN_PATH,
+ TENANT_DOMAIN);
+ Assert.assertEquals(actions.size(), 1);
+ Action result = actions.get(0);
+ Assert.assertEquals(result.getId(), sampleAction.getId());
+ Assert.assertEquals(result.getName(), sampleAction.getName());
+ Assert.assertEquals(result.getDescription(), sampleAction.getDescription());
+ Assert.assertEquals(result.getType().getActionType(), sampleAction.getType().getActionType());
+ Assert.assertEquals(result.getStatus(), sampleAction.getStatus());
+ Assert.assertEquals(result.getEndpoint().getUri(), sampleAction.getEndpoint().getUri());
+
+ Authentication resultActionAuth = result.getEndpoint().getAuthentication();
+ Authentication sampleActionAuth = sampleAction.getEndpoint().getAuthentication();
+
+ Assert.assertEquals(resultActionAuth.getType(), sampleActionAuth.getType());
+ Assert.assertEquals(resultActionAuth.getProperty(Authentication.Property.USERNAME).getValue(),
+ sampleActionAuth.getProperty(Authentication.Property.USERNAME).getValue());
+ Assert.assertEquals(resultActionAuth.getProperty(Authentication.Property.PASSWORD).getValue(),
+ sampleActionAuth.getProperty(Authentication.Property.PASSWORD).getValue());
+ }
+
+ @Test(priority = 6)
+ public void testGetActionByActionId() throws ActionMgtException {
+
+ Action result = actionManagementService.getActionByActionId(sampleAction.getType().getPathParam(),
+ sampleAction.getId(), TENANT_DOMAIN);
+ Assert.assertEquals(result.getId(), sampleAction.getId());
+ Assert.assertEquals(result.getName(), sampleAction.getName());
+ Assert.assertEquals(result.getDescription(), sampleAction.getDescription());
+ Assert.assertEquals(result.getType(), sampleAction.getType());
+ Assert.assertEquals(result.getStatus(), sampleAction.getStatus());
+ Assert.assertEquals(result.getEndpoint().getUri(), sampleAction.getEndpoint().getUri());
+
+ Authentication resultActionAuth = result.getEndpoint().getAuthentication();
+ Authentication sampleActionAuth = sampleAction.getEndpoint().getAuthentication();
+
+ Assert.assertEquals(resultActionAuth.getType(), sampleActionAuth.getType());
+ Assert.assertEquals(resultActionAuth.getProperty(Authentication.Property.USERNAME).getValue(),
+ sampleActionAuth.getProperty(Authentication.Property.USERNAME).getValue());
+ Assert.assertEquals(resultActionAuth.getProperty(Authentication.Property.PASSWORD).getValue(),
+ sampleActionAuth.getProperty(Authentication.Property.PASSWORD).getValue());
+ }
+
+ @Test(priority = 7)
+ public void testUpdateAction() throws ActionMgtException, SecretManagementException {
+
+ Action updatingAction = TestUtil.buildMockAction(
+ TEST_ACTION_NAME_UPDATED,
+ TEST_ACTION_DESCRIPTION_UPDATED,
+ TEST_ACTION_URI,
+ TestUtil.buildMockAPIKeyAuthentication(TEST_API_KEY_HEADER, TEST_API_KEY_VALUE));
+ Action result = actionManagementService.updateAction(PRE_ISSUE_ACCESS_TOKEN_PATH, sampleAction.getId(),
+ updatingAction, TENANT_DOMAIN);
+
+ Assert.assertEquals(result.getId(), sampleAction.getId());
+ Assert.assertEquals(result.getName(), updatingAction.getName());
+ Assert.assertEquals(result.getDescription(), updatingAction.getDescription());
+ Assert.assertEquals(result.getType(), sampleAction.getType());
+ Assert.assertEquals(result.getStatus(), sampleAction.getStatus());
+ Assert.assertEquals(result.getEndpoint().getUri(), updatingAction.getEndpoint().getUri());
+
+ Authentication resultActionAuth = result.getEndpoint().getAuthentication();
+ Authentication updatingActionAuth = updatingAction.getEndpoint().getAuthentication();
+ Map secretProperties = resolveAuthPropertiesMap(updatingActionAuth, sampleAction.getId());
+
+ Assert.assertEquals(resultActionAuth.getType(), updatingActionAuth.getType());
+ Assert.assertEquals(resultActionAuth.getProperty(Authentication.Property.HEADER).getValue(),
+ secretProperties.get(Authentication.Property.HEADER.getName()));
+ Assert.assertEquals(resultActionAuth.getProperty(Authentication.Property.VALUE).getValue(),
+ secretProperties.get(Authentication.Property.VALUE.getName()));
+ sampleAction = result;
+ }
+
+ @Test(priority = 8)
+ public void testDeactivateAction() throws ActionMgtException {
+
+ Assert.assertEquals(sampleAction.getStatus(), Action.Status.ACTIVE);
+ Action deactivatedAction = actionManagementService.deactivateAction(PRE_ISSUE_ACCESS_TOKEN_PATH,
+ sampleAction.getId(), TENANT_DOMAIN);
+ Assert.assertEquals(deactivatedAction.getStatus(), Action.Status.INACTIVE);
+ }
+
+ @Test(priority = 9)
+ public void testActivateAction() throws ActionMgtException {
+
+ Action activatedAction = actionManagementService.activateAction(PRE_ISSUE_ACCESS_TOKEN_PATH,
+ sampleAction.getId(), TENANT_DOMAIN);
+ Assert.assertEquals(activatedAction.getStatus(), Action.Status.ACTIVE);
+ }
+
+ @Test(priority = 10)
+ public void testGetActionsCountPerType() throws ActionMgtException {
+
+ Map actionMap = actionManagementService.getActionsCountPerType(TENANT_DOMAIN);
+ Assert.assertNull(actionMap.get(Action.ActionTypes.PRE_UPDATE_PASSWORD.getActionType()));
+ Assert.assertNull(actionMap.get(Action.ActionTypes.PRE_UPDATE_PROFILE.getActionType()));
+ Assert.assertNull(actionMap.get(Action.ActionTypes.PRE_REGISTRATION.getActionType()));
+ Assert.assertNull(actionMap.get(Action.ActionTypes.AUTHENTICATION.getActionType()));
+ for (Map.Entry entry: actionMap.entrySet()) {
+ Assert.assertEquals(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN.getActionType(), entry.getKey());
+ Assert.assertEquals(entry.getValue().intValue(), 1);
+ }
+ }
+
+ @Test(priority = 11)
+ public void testUpdateEndpointConfigWithSameAuthenticationType() throws ActionMgtException,
+ SecretManagementException {
+
+ Authentication updatingAuthentication = TestUtil.buildMockAPIKeyAuthentication(TEST_API_KEY_HEADER_UPDATED,
+ TEST_API_KEY_VALUE_UPDATED);
+ Action result = actionManagementService.updateActionEndpointAuthentication(PRE_ISSUE_ACCESS_TOKEN_PATH,
+ sampleAction.getId(), updatingAuthentication, TENANT_DOMAIN);
+
+ Authentication resultActionAuth = result.getEndpoint().getAuthentication();
+ Map secretProperties = resolveAuthPropertiesMap(updatingAuthentication, sampleAction.getId());
+
+ Assert.assertEquals(resultActionAuth.getType(), updatingAuthentication.getType());
+ Assert.assertEquals(resultActionAuth.getProperty(Authentication.Property.HEADER).getValue(),
+ secretProperties.get(Authentication.Property.HEADER.getName()));
+ Assert.assertEquals(resultActionAuth.getProperty(Authentication.Property.VALUE).getValue(),
+ secretProperties.get(Authentication.Property.VALUE.getName()));
+ }
+
+ @Test(priority = 12)
+ public void testUpdateEndpointConfigWithDifferentAuthenticationType()
+ throws ActionMgtException, SecretManagementException {
+
+ Authentication updatingAuthentication = TestUtil.buildMockBearerAuthentication(TEST_ACCESS_TOKEN);
+ Action result = actionManagementService.updateActionEndpointAuthentication(PRE_ISSUE_ACCESS_TOKEN_PATH,
+ sampleAction.getId(), updatingAuthentication, TENANT_DOMAIN);
+
+ Authentication resultActionAuth = result.getEndpoint().getAuthentication();
+ Map secretProperties = resolveAuthPropertiesMap(updatingAuthentication, sampleAction.getId());
+
+ Assert.assertEquals(resultActionAuth.getType(), updatingAuthentication.getType());
+ Assert.assertEquals(resultActionAuth.getProperty(Authentication.Property.ACCESS_TOKEN).getValue(),
+ secretProperties.get(Authentication.Property.ACCESS_TOKEN.getName()));
+ }
+
+ @Test(priority = 13)
+ public void testDeleteAction() throws ActionMgtException {
+
+ actionManagementService.deleteAction(PRE_ISSUE_ACCESS_TOKEN_PATH, sampleAction.getId(), TENANT_DOMAIN);
+ Assert.assertNull(actionManagementService.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_PATH, sampleAction.getId(),
+ TENANT_DOMAIN));
+ Map actions = actionManagementService.getActionsCountPerType(TENANT_DOMAIN);
+ Assert.assertNull(actions.get(PRE_ISSUE_ACCESS_TOKEN_PATH));
+ }
+
+ @Test(priority = 14)
+ public void testDeleteNonExistingAction() {
+
+ try {
+ actionManagementService.deleteAction(PRE_ISSUE_ACCESS_TOKEN_PATH, "invalid_id", TENANT_DOMAIN);
+ } catch (Exception e) {
+ Assert.fail();
+ }
+ }
+
+ private Map resolveAuthPropertiesMap(Authentication authentication, String actionId)
+ throws SecretManagementException {
+
+ return authentication.getPropertiesWithSecretReferences(actionId)
+ .stream()
+ .collect(Collectors.toMap(AuthProperty::getName, AuthProperty::getValue));
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/service/CacheBackedActionManagementServiceTest.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/service/CacheBackedActionManagementServiceTest.java
new file mode 100644
index 000000000000..29fb849cac01
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/service/CacheBackedActionManagementServiceTest.java
@@ -0,0 +1,309 @@
+/*
+ * 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.carbon.identity.action.management.service;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.wso2.carbon.identity.action.management.exception.ActionMgtException;
+import org.wso2.carbon.identity.action.management.internal.ActionMgtServiceComponentHolder;
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.Authentication;
+import org.wso2.carbon.identity.action.management.service.impl.ActionManagementServiceImpl;
+import org.wso2.carbon.identity.action.management.service.impl.CacheBackedActionManagementService;
+import org.wso2.carbon.identity.action.management.util.TestUtil;
+import org.wso2.carbon.identity.common.testng.WithCarbonHome;
+import org.wso2.carbon.identity.common.testng.WithH2Database;
+import org.wso2.carbon.identity.common.testng.WithRealmService;
+import org.wso2.carbon.identity.core.internal.IdentityCoreServiceDataHolder;
+import org.wso2.carbon.identity.secret.mgt.core.SecretManagerImpl;
+import org.wso2.carbon.identity.secret.mgt.core.model.SecretType;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_ISSUE_ACCESS_TOKEN_ACTION_ID;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_ISSUE_ACCESS_TOKEN_PATH;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TENANT_DOMAIN;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_DESCRIPTION;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_NAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_URI;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_PASSWORD;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_USERNAME;
+
+/**
+ * Test class for CacheBackedActionManagement.
+ */
+@WithCarbonHome
+@WithH2Database(files = {"dbscripts/h2.sql"})
+@WithRealmService(injectToSingletons = {IdentityCoreServiceDataHolder.class})
+public class CacheBackedActionManagementServiceTest {
+
+ private ActionManagementServiceImpl actionManagementServiceImpl;
+ private CacheBackedActionManagementService cacheBackedActionManagementService;
+
+ private final List mockedActionsList = new ArrayList<>();
+ private Action mockedAction;
+
+ @BeforeClass
+ public void setUpClass() {
+
+ cacheBackedActionManagementService = CacheBackedActionManagementService.getInstance();
+ mockedAction = new Action.ActionResponseBuilder()
+ .id(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID)
+ .name(TEST_ACTION_NAME)
+ .description(TEST_ACTION_DESCRIPTION)
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .status(Action.Status.ACTIVE)
+ .endpoint(TestUtil.buildMockEndpointConfig(TEST_ACTION_URI,
+ TestUtil.buildMockBasicAuthentication(TEST_USERNAME, TEST_PASSWORD)))
+ .build();
+ mockedActionsList.add(mockedAction);
+ }
+
+ @BeforeMethod
+ public void setUp() throws Exception {
+
+ SecretManagerImpl secretManager = mock(SecretManagerImpl.class);
+ SecretType secretType = mock(SecretType.class);
+ ActionMgtServiceComponentHolder.getInstance().setSecretManager(secretManager);
+ when(secretType.getId()).thenReturn(TestUtil.TEST_SECRET_TYPE_ID);
+ when(secretManager.getSecretType(any())).thenReturn(secretType);
+
+ actionManagementServiceImpl = mock(ActionManagementServiceImpl.class);
+ // Set ACTION_MGT_SERVICE field using reflection
+ setFinalField(cacheBackedActionManagementService, "ACTION_MGT_SERVICE", actionManagementServiceImpl);
+ }
+
+ @Test(priority = 1)
+ public void testGetActionsByActionTypeFromDB() throws ActionMgtException {
+
+ doReturn(mockedActionsList).when(actionManagementServiceImpl).getActionsByActionType(any(), any());
+
+ List actions = cacheBackedActionManagementService.getActionsByActionType(PRE_ISSUE_ACCESS_TOKEN_PATH,
+ TENANT_DOMAIN);
+ verify(actionManagementServiceImpl, times(1)).getActionsByActionType(any(), any());
+ Assert.assertEquals(actions.size(), mockedActionsList.size());
+ Action result = actions.get(0);
+ assertAction(result);
+ }
+
+ @Test(priority = 2, dependsOnMethods = "testGetActionsByActionTypeFromDB")
+ public void testGetActionsByActionTypeFromCache() throws ActionMgtException {
+
+ doReturn(null).when(actionManagementServiceImpl).getActionsByActionType(any(), any());
+
+ List actions = cacheBackedActionManagementService.getActionsByActionType(PRE_ISSUE_ACCESS_TOKEN_PATH,
+ TENANT_DOMAIN);
+ verify(actionManagementServiceImpl, never()).getActionsByActionType(any(), any());
+ Assert.assertNotNull(actions);
+ Assert.assertEquals(actions.size(), mockedActionsList.size());
+ Action result = actions.get(0);
+ assertAction(result);
+ }
+
+ @Test(priority = 3, dependsOnMethods = "testGetActionsByActionTypeFromDB")
+ public void testGetActionsByActionIdFromCache() throws ActionMgtException {
+
+ doReturn(null).when(actionManagementServiceImpl).getActionByActionId(any(), any(), any());
+
+ Action action = cacheBackedActionManagementService.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_PATH,
+ PRE_ISSUE_ACCESS_TOKEN_ACTION_ID, TENANT_DOMAIN);
+ verify(actionManagementServiceImpl, never()).getActionByActionId(any(), any(), any());
+ Assert.assertNotNull(action);
+ assertAction(action);
+ }
+
+ @Test(priority = 4)
+ public void testAddAction() throws ActionMgtException {
+
+ doReturn(mockedAction).when(actionManagementServiceImpl).addAction(any(), any(), any());
+
+ Action action = cacheBackedActionManagementService.addAction(PRE_ISSUE_ACCESS_TOKEN_PATH,
+ mockedAction, TENANT_DOMAIN);
+ verify(actionManagementServiceImpl, times(1)).addAction(any(), any(), any());
+ Assert.assertNotNull(action);
+ checkCacheInvalidation();
+ }
+
+ @Test(priority = 5)
+ public void testGetActionsByActionIdFromDB() throws ActionMgtException {
+
+ doReturn(mockedAction).when(actionManagementServiceImpl).getActionByActionId(any(), any(), any());
+
+ Action action = cacheBackedActionManagementService.getActionByActionId(PRE_ISSUE_ACCESS_TOKEN_PATH,
+ PRE_ISSUE_ACCESS_TOKEN_ACTION_ID, TENANT_DOMAIN);
+ verify(actionManagementServiceImpl, times(1)).getActionByActionId(any(), any(), any());
+ Assert.assertNotNull(action);
+ assertAction(action);
+ }
+
+ @Test(priority = 6)
+ public void testUpdateAction() throws ActionMgtException {
+
+ doReturn(mockedAction).when(actionManagementServiceImpl).updateAction(any(), any(), any(), any());
+
+ Action action = cacheBackedActionManagementService.updateAction(PRE_ISSUE_ACCESS_TOKEN_PATH,
+ PRE_ISSUE_ACCESS_TOKEN_ACTION_ID, mockedAction, TENANT_DOMAIN);
+ verify(actionManagementServiceImpl, times(1)).updateAction(any(), any(), any(), any());
+ Assert.assertNotNull(action);
+ checkCacheInvalidation();
+ }
+
+ @Test(priority = 7)
+ public void testDeactivateAction() throws ActionMgtException {
+
+ // Update cache.
+ doReturn(mockedActionsList).when(actionManagementServiceImpl).getActionsByActionType(any(), any());
+ cacheBackedActionManagementService.getActionsByActionType(PRE_ISSUE_ACCESS_TOKEN_PATH, TENANT_DOMAIN);
+
+ cacheBackedActionManagementService.deactivateAction(PRE_ISSUE_ACCESS_TOKEN_PATH,
+ PRE_ISSUE_ACCESS_TOKEN_ACTION_ID, TENANT_DOMAIN);
+ verify(actionManagementServiceImpl, times(1)).deactivateAction(any(), any(), any());
+ checkCacheInvalidation();
+ }
+
+ @Test(priority = 8)
+ public void testActivateAction() throws ActionMgtException {
+
+ // Update cache.
+ doReturn(mockedActionsList).when(actionManagementServiceImpl).getActionsByActionType(any(), any());
+ cacheBackedActionManagementService.getActionsByActionType(PRE_ISSUE_ACCESS_TOKEN_PATH, TENANT_DOMAIN);
+
+ cacheBackedActionManagementService.activateAction(PRE_ISSUE_ACCESS_TOKEN_PATH,
+ PRE_ISSUE_ACCESS_TOKEN_ACTION_ID, TENANT_DOMAIN);
+ verify(actionManagementServiceImpl, times(1)).activateAction(any(), any(), any());
+ checkCacheInvalidation();
+ }
+
+ @Test(priority = 9)
+ public void testUpdateActionEndpointAuthentication() throws ActionMgtException {
+
+ // Update cache.
+ doReturn(mockedAction).when(actionManagementServiceImpl).updateActionEndpointAuthentication(any(), any(),
+ any(), any());
+
+ Action action = cacheBackedActionManagementService.updateActionEndpointAuthentication(
+ PRE_ISSUE_ACCESS_TOKEN_PATH, PRE_ISSUE_ACCESS_TOKEN_ACTION_ID,
+ mockedAction.getEndpoint().getAuthentication(), TENANT_DOMAIN);
+ verify(actionManagementServiceImpl, times(1)).updateActionEndpointAuthentication(any(),
+ any(), any(), any());
+ Assert.assertNotNull(action);
+ checkCacheInvalidation();
+ }
+
+ @Test(priority = 14)
+ public void testDeleteAction() throws ActionMgtException {
+
+ // Update cache.
+ doNothing().when(actionManagementServiceImpl).deleteAction(any(), any(), any());
+
+ cacheBackedActionManagementService.deleteAction(PRE_ISSUE_ACCESS_TOKEN_PATH, mockedAction.getId(),
+ TENANT_DOMAIN);
+ verify(actionManagementServiceImpl, times(1)).deleteAction(any(), any(), any());
+ checkCacheInvalidation();
+ }
+
+ @Test(priority = 10)
+ public void testGetActionsCountPerType() throws ActionMgtException {
+
+ Map mockedActionMap = new HashMap<>();
+ mockedActionMap.put(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN.getActionType(), 1);
+ mockedActionMap.put(Action.ActionTypes.PRE_UPDATE_PASSWORD.getActionType(), 2);
+ doReturn(mockedActionMap).when(actionManagementServiceImpl).getActionsCountPerType(any());
+
+ Map actionMap = cacheBackedActionManagementService.getActionsCountPerType(TENANT_DOMAIN);
+ Assert.assertNotNull(actionMap.get(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN.getActionType()));
+ Assert.assertNotNull(actionMap.get(Action.ActionTypes.PRE_UPDATE_PASSWORD.getActionType()));
+ Assert.assertNull(actionMap.get(Action.ActionTypes.PRE_UPDATE_PROFILE.getActionType()));
+ Assert.assertNull(actionMap.get(Action.ActionTypes.PRE_REGISTRATION.getActionType()));
+ Assert.assertNull(actionMap.get(Action.ActionTypes.AUTHENTICATION.getActionType()));
+
+ Assert.assertEquals(actionMap.get(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN.getActionType()).intValue(), 1);
+ Assert.assertEquals(actionMap.get(Action.ActionTypes.PRE_UPDATE_PASSWORD.getActionType()).intValue(), 2);
+ }
+
+ private void checkCacheInvalidation() throws ActionMgtException {
+
+ reset(actionManagementServiceImpl);
+ doReturn(null).when(actionManagementServiceImpl).getActionsByActionType(any(), any());
+ doReturn(null).when(actionManagementServiceImpl).getActionByActionId(any(), any(), any());
+
+ List actions = cacheBackedActionManagementService.getActionsByActionType(
+ mockedAction.getType().getPathParam(), TENANT_DOMAIN);
+ Assert.assertNull(actions);
+ verify(actionManagementServiceImpl, times(1)).getActionsByActionType(any(), any());
+
+ Action action = cacheBackedActionManagementService.getActionByActionId(mockedAction.getType().getPathParam(),
+ mockedAction.getId(), TENANT_DOMAIN);
+ Assert.assertNull(action);
+ verify(actionManagementServiceImpl, times(1)).getActionByActionId(any(), any(), any());
+ }
+
+ private void assertAction(Action action) {
+
+ Assert.assertEquals(action.getId(), mockedAction.getId());
+ Assert.assertEquals(action.getName(), mockedAction.getName());
+ Assert.assertEquals(action.getDescription(), mockedAction.getDescription());
+ Assert.assertEquals(action.getType(), mockedAction.getType());
+ Assert.assertEquals(action.getStatus(), mockedAction.getStatus());
+ Assert.assertEquals(action.getEndpoint().getUri(), mockedAction.getEndpoint().getUri());
+
+ Authentication actionAuth = action.getEndpoint().getAuthentication();
+ Authentication mockedActionAuth = mockedAction.getEndpoint().getAuthentication();
+
+ Assert.assertEquals(actionAuth.getType(), mockedActionAuth.getType());
+ Assert.assertEquals(actionAuth.getProperty(Authentication.Property.USERNAME).getValue(),
+ mockedActionAuth.getProperty(Authentication.Property.USERNAME).getValue());
+ Assert.assertEquals(actionAuth.getProperty(Authentication.Property.PASSWORD).getValue(),
+ mockedActionAuth.getProperty(Authentication.Property.PASSWORD).getValue());
+ }
+
+ private void setFinalField(Object target, String fieldName, Object value) throws Exception {
+
+ Field field;
+ try {
+ field = target.getClass().getDeclaredField(fieldName);
+ } catch (NoSuchFieldException e) {
+ field = target.getClass().getSuperclass().getDeclaredField(fieldName);
+ }
+
+ field.setAccessible(true);
+
+ Field modifiersField = Field.class.getDeclaredField("modifiers");
+ modifiersField.setAccessible(true);
+ modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
+
+ field.set(target, value);
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/util/ActionManagementAuditLoggerTest.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/util/ActionManagementAuditLoggerTest.java
new file mode 100644
index 000000000000..eead34bd7a05
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/util/ActionManagementAuditLoggerTest.java
@@ -0,0 +1,447 @@
+/*
+ * 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.carbon.identity.action.management.util;
+
+import org.json.JSONObject;
+import org.mockito.ArgumentCaptor;
+import org.mockito.MockedStatic;
+import org.mockito.MockitoAnnotations;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.wso2.carbon.context.CarbonContext;
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.ActionDTO;
+import org.wso2.carbon.identity.action.management.model.Authentication;
+import org.wso2.carbon.identity.action.management.model.EndpointConfig;
+import org.wso2.carbon.identity.central.log.mgt.utils.LoggerUtils;
+import org.wso2.carbon.identity.certificate.management.model.Certificate;
+import org.wso2.carbon.identity.common.testng.WithCarbonHome;
+import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
+import org.wso2.carbon.identity.core.util.IdentityUtil;
+import org.wso2.carbon.utils.AuditLog;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.when;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.CERTIFICATE_ID;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.CERTIFICATE_NAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.CERTIFICATE_PROPERTY_NAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PASSWORD_SHARING_TYPE_PROPERTY_NAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_ISSUE_ACCESS_TOKEN_ACTION_ID;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_UPDATE_PASSWORD_ACTION_ID;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACCESS_TOKEN;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_DESCRIPTION;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_DESCRIPTION_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_NAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_NAME_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_URI;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACTION_URI_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_API_KEY_HEADER;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_API_KEY_VALUE;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_CERTIFICATE;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_CERTIFICATE_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_PASSWORD;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_PASSWORD_SHARING_TYPE;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_PASSWORD_SHARING_TYPE_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_USERNAME;
+
+/**
+ * Unit test class for ActionManagementAuditLogger class.
+ */
+@WithCarbonHome
+public class ActionManagementAuditLoggerTest {
+
+ private ActionManagementAuditLogger auditLogger;
+ private ActionDTO actionDTO;
+ private CarbonContext carbonContext;
+ private MockedStatic carbonContextMockedStatic;
+ private MockedStatic identityUtil;
+ private MockedStatic identityTenantUtil;
+ private MockedStatic loggerUtilsMockedStatic;
+
+ private static final String ADD_ACTION = "add-action";
+ private static final String UPDATE_ACTION = "update-action";
+ private static final String DELETE_ACTION = "delete-action";
+
+ @BeforeMethod
+ public void setUp() throws NoSuchFieldException, IllegalAccessException {
+
+ MockitoAnnotations.openMocks(this);
+ auditLogger = new ActionManagementAuditLogger();
+ identityUtil = mockStatic(IdentityUtil.class);
+ identityTenantUtil = mockStatic(IdentityTenantUtil.class);
+
+ carbonContextMockedStatic = mockStatic(CarbonContext.class);
+ carbonContext = mock(CarbonContext.class);
+ carbonContextMockedStatic.when(CarbonContext::getThreadLocalCarbonContext).thenReturn(carbonContext);
+ when(carbonContext.getUsername()).thenReturn("testUser");
+ when(carbonContext.getTenantDomain()).thenReturn("carbon.super");
+ identityUtil.when(() -> IdentityUtil.getInitiatorId("testUser", "carbon.super")).
+ thenReturn("initiator-id-test");
+
+ loggerUtilsMockedStatic = mockStatic(LoggerUtils.class);
+ loggerUtilsMockedStatic.when(LoggerUtils::isEnableV2AuditLogs).thenReturn(true);
+ loggerUtilsMockedStatic.when(() -> LoggerUtils.jsonObjectToMap(any(JSONObject.class))).thenCallRealMethod();
+ loggerUtilsMockedStatic.when(() -> LoggerUtils.getMaskedContent(any(String.class))).thenCallRealMethod();
+
+ Map actionProperties = new HashMap<>();
+ actionProperties.put(PASSWORD_SHARING_TYPE_PROPERTY_NAME, TEST_PASSWORD_SHARING_TYPE);
+ actionProperties.put(CERTIFICATE_PROPERTY_NAME, new Certificate.Builder()
+ .id(CERTIFICATE_ID).name(CERTIFICATE_NAME)
+ .certificateContent(TEST_CERTIFICATE).build());
+
+ actionDTO = new ActionDTOBuilder()
+ .id(PRE_UPDATE_PASSWORD_ACTION_ID)
+ .name(TEST_ACTION_NAME)
+ .description(TEST_ACTION_DESCRIPTION)
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .status(Action.Status.ACTIVE)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TEST_ACTION_URI)
+ .authentication(new Authentication.BearerAuthBuilder(TEST_ACCESS_TOKEN).build())
+ .build())
+ .properties(actionProperties)
+ .build();
+ }
+
+ @AfterMethod
+ public void tearDown() {
+
+ auditLogger = null;
+ actionDTO = null;
+ carbonContextMockedStatic.close();
+ identityUtil.close();
+ identityTenantUtil.close();
+ loggerUtilsMockedStatic.close();
+ }
+
+ @DataProvider
+ public Object[][] actionDataProvider() {
+
+ Map actionProperties = new HashMap<>();
+ actionProperties.put(PASSWORD_SHARING_TYPE_PROPERTY_NAME, TEST_PASSWORD_SHARING_TYPE);
+ actionProperties.put(CERTIFICATE_PROPERTY_NAME, new Certificate.Builder()
+ .id(CERTIFICATE_ID).name(CERTIFICATE_NAME)
+ .certificateContent(TEST_CERTIFICATE).build());
+
+ Map updatedActionProperties = new HashMap<>();
+ updatedActionProperties.put(PASSWORD_SHARING_TYPE_PROPERTY_NAME, TEST_PASSWORD_SHARING_TYPE_UPDATED);
+ updatedActionProperties.put(CERTIFICATE_PROPERTY_NAME, new Certificate.Builder()
+ .id(CERTIFICATE_ID).name(CERTIFICATE_NAME)
+ .certificateContent(TEST_CERTIFICATE_UPDATED).build());
+
+ return new Object[][]{
+ // Create object with all the fields.
+ {ActionManagementAuditLogger.Operation.ADD,
+ new ActionDTOBuilder()
+ .id(PRE_UPDATE_PASSWORD_ACTION_ID)
+ .name(TEST_ACTION_NAME)
+ .description(TEST_ACTION_DESCRIPTION)
+ .type(Action.ActionTypes.PRE_UPDATE_PASSWORD)
+ .status(Action.Status.ACTIVE)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TEST_ACTION_URI)
+ .authentication(new Authentication.BearerAuthBuilder(TEST_ACCESS_TOKEN).build())
+ .build())
+ .properties(actionProperties)
+ .build()
+ },
+ // Create object without properties
+ {ActionManagementAuditLogger.Operation.ADD,
+ new ActionDTOBuilder()
+ .id(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID)
+ .name(TEST_ACTION_NAME)
+ .description(TEST_ACTION_DESCRIPTION)
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .status(Action.Status.ACTIVE)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TEST_ACTION_URI)
+ .authentication(new Authentication.BasicAuthBuilder(TEST_USERNAME, TEST_PASSWORD)
+ .build())
+ .build())
+ .build()
+ },
+ // Update Objects
+ {ActionManagementAuditLogger.Operation.UPDATE,
+ new ActionDTOBuilder()
+ .id(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID)
+ .name(TEST_ACTION_NAME_UPDATED)
+ .description(TEST_ACTION_DESCRIPTION_UPDATED)
+ .type(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN)
+ .status(Action.Status.ACTIVE)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TEST_ACTION_URI_UPDATED)
+ .authentication(new Authentication.APIKeyAuthBuilder(TEST_API_KEY_HEADER,
+ TEST_API_KEY_VALUE).build())
+ .build())
+ .properties(updatedActionProperties)
+ .build()
+ },
+ {ActionManagementAuditLogger.Operation.UPDATE,
+ new ActionDTOBuilder()
+ .id(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID)
+ .name(TEST_ACTION_NAME_UPDATED)
+ .build()
+ },
+ {ActionManagementAuditLogger.Operation.UPDATE,
+ new ActionDTOBuilder()
+ .id(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID)
+ .description(TEST_ACTION_DESCRIPTION_UPDATED)
+ .build()
+ },
+ {ActionManagementAuditLogger.Operation.UPDATE,
+ new ActionDTOBuilder()
+ .id(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TEST_ACTION_URI)
+ .authentication(new Authentication.NoneAuthBuilder().build())
+ .build())
+ .build()
+ },
+ {ActionManagementAuditLogger.Operation.UPDATE,
+ new ActionDTOBuilder()
+ .id(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .uri(TEST_ACTION_URI)
+ .build())
+ .build()
+ },
+ {ActionManagementAuditLogger.Operation.UPDATE,
+ new ActionDTOBuilder()
+ .id(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID)
+ .endpoint(new EndpointConfig.EndpointConfigBuilder()
+ .authentication(new Authentication.BearerAuthBuilder(TEST_ACCESS_TOKEN).build())
+ .build())
+ .build()
+ },
+ {ActionManagementAuditLogger.Operation.UPDATE,
+ new ActionDTOBuilder()
+ .id(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID)
+ .properties(updatedActionProperties)
+ .build()
+ }
+ };
+ }
+
+ @Test(dataProvider = "actionDataProvider")
+ public void testPrintAuditLogWithAction(ActionManagementAuditLogger.Operation operation, ActionDTO actionDTO)
+ throws NoSuchFieldException, IllegalAccessException {
+
+ auditLogger.printAuditLog(operation, actionDTO);
+ AuditLog.AuditLogBuilder capturedArg = captureTriggerAuditLogEventArgs();
+
+ Assert.assertNotNull(capturedArg);
+ assertActionData(capturedArg, actionDTO);
+ assertAuditLoggerData(capturedArg, operation.getLogAction());
+ }
+
+ @Test
+ public void testPrintAuditLogWithActionTypeAndId() throws NoSuchFieldException, IllegalAccessException {
+
+ ActionManagementAuditLogger.Operation operation = ActionManagementAuditLogger.Operation.DELETE;
+ auditLogger.printAuditLog(operation, actionDTO.getType().name(), actionDTO.getId());
+ AuditLog.AuditLogBuilder capturedArg = captureTriggerAuditLogEventArgs();
+
+ Assert.assertNotNull(capturedArg);
+ Assert.assertEquals(extractMapByField("ActionId", capturedArg), actionDTO.getId());
+ Assert.assertEquals(extractMapByField("ActionType", capturedArg),
+ Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN.getActionType());
+ assertAuditLoggerData(capturedArg, DELETE_ACTION);
+
+ }
+
+ /**
+ * Capture the arguments passed to the triggerAuditLogEvent method in the {@link LoggerUtils} class.
+ * The captured {@code AuditLogBuilder} contains all the necessary
+ * information that will be logged, allowing verification of audit log data.
+ *
+ * @return The captured {@link AuditLog.AuditLogBuilder} instance containing the data to be logged.
+ */
+ private AuditLog.AuditLogBuilder captureTriggerAuditLogEventArgs() {
+
+ ArgumentCaptor auditLogBuilderCaptor = ArgumentCaptor.
+ forClass(AuditLog.AuditLogBuilder.class);
+ loggerUtilsMockedStatic.verify(() -> LoggerUtils.triggerAuditLogEvent(auditLogBuilderCaptor.capture()));
+ return auditLogBuilderCaptor.getValue();
+ }
+
+ /**
+ * Extract the specific field name from the provided {@link AuditLog.AuditLogBuilder} instance.
+ *
+ * @param fieldName Name of the field to be extracted.
+ * @param auditLogBuilder {@link AuditLog.AuditLogBuilder} instance.
+ * @return Value of the extracted field.
+ * @throws NoSuchFieldException if the provided field does not exist.
+ * @throws IllegalAccessException if the provided field is not accessible.
+ */
+ private String extractMapByField(String fieldName, AuditLog.AuditLogBuilder auditLogBuilder)
+ throws NoSuchFieldException, IllegalAccessException {
+
+ Field dataField = AuditLog.AuditLogBuilder.class.getDeclaredField("data");
+ dataField.setAccessible(true);
+ Map dataMap = (Map) dataField.get(auditLogBuilder);
+ return (String) dataMap.get(fieldName);
+ }
+
+ /**
+ * Extract field.
+ *
+ * @param fieldName Name of the field to be extracted.
+ * @param auditLogBuilder {@link AuditLog.AuditLogBuilder} instance.
+ * @return Value of the extracted field.
+ * @throws NoSuchFieldException if the provided field does not exist.
+ * @throws IllegalAccessException if the provided field is not accessible.
+ */
+ private String extractField(String fieldName, AuditLog.AuditLogBuilder auditLogBuilder)
+ throws NoSuchFieldException, IllegalAccessException {
+
+ Field dataField = AuditLog.AuditLogBuilder.class.getDeclaredField(fieldName);
+ dataField.setAccessible(true);
+ return (String) dataField.get(auditLogBuilder);
+ }
+
+ /**
+ * Assert data fields related to the Action object of the captured audit logger.
+ *
+ * @param auditLogBuilder {@link AuditLog.AuditLogBuilder} instance.
+ * @param actionDTO {@link ActionDTO} instance.
+ * @throws NoSuchFieldException if the provided field does not exist.
+ * @throws IllegalAccessException if the provided field is not accessible.
+ */
+ private void assertActionData(AuditLog.AuditLogBuilder auditLogBuilder, ActionDTO actionDTO)
+ throws NoSuchFieldException, IllegalAccessException {
+
+ Field dataField = AuditLog.AuditLogBuilder.class.getDeclaredField("data");
+ dataField.setAccessible(true);
+ Map dataMap = (Map) dataField.get(auditLogBuilder);
+ Map endpointConfigMap = (Map) dataMap.get("EndpointConfiguration");
+ Map propertiesMap = (Map) dataMap.get("Properties");
+
+ String id = actionDTO.getId();
+ String name = actionDTO.getName();
+ String description = actionDTO.getDescription();
+ String type = actionDTO.getType() != null ? actionDTO.getType().name() : null;
+ String status = actionDTO.getStatus() != null ? actionDTO.getStatus().name() : null;
+ String uri = actionDTO.getEndpoint() != null && actionDTO.getEndpoint().getUri() != null ?
+ actionDTO.getEndpoint().getUri() : null;
+ String authenticationScheme = actionDTO.getEndpoint() != null &&
+ actionDTO.getEndpoint().getAuthentication() != null &&
+ actionDTO.getEndpoint().getAuthentication().getType() != null ?
+ actionDTO.getEndpoint().getAuthentication().getType().getName() : null;
+
+ assertField(id != null, dataMap, "ActionId", id);
+ assertField(name != null, dataMap, "ActionName", name);
+ assertField(description != null, dataMap, "ActionDescription", description);
+ assertField(type != null, dataMap, "ActionType", type);
+ assertField(status != null, dataMap, "ActionStatus", status);
+ assertField(uri != null, endpointConfigMap, "EndpointUri", uri);
+ assertField(authenticationScheme != null, endpointConfigMap, "AuthenticationScheme",
+ authenticationScheme);
+
+ if (authenticationScheme != null) {
+ switch (actionDTO.getEndpoint().getAuthentication().getType()) {
+ case BASIC:
+ assertMasked(endpointConfigMap.get("Username").toString());
+ assertMasked(endpointConfigMap.get("Password").toString());
+ break;
+ case BEARER:
+ assertMasked(endpointConfigMap.get("AccessToken").toString());
+ break;
+ case API_KEY:
+ assertMasked(endpointConfigMap.get("ApiKeyHeader").toString());
+ assertMasked(endpointConfigMap.get("ApiKeyValue").toString());
+ break;
+ case NONE:
+ default:
+ break;
+ }
+ }
+
+ if (actionDTO.getProperties() != null && actionDTO.getProperty(PASSWORD_SHARING_TYPE_PROPERTY_NAME) != null) {
+ assertMasked(propertiesMap.get(PASSWORD_SHARING_TYPE_PROPERTY_NAME).toString());
+ }
+ if (actionDTO.getProperties() != null && actionDTO.getProperty(CERTIFICATE_PROPERTY_NAME) != null) {
+ assertMasked(propertiesMap.get(CERTIFICATE_PROPERTY_NAME).toString());
+ }
+ }
+
+ /**
+ * Assert field.
+ *
+ * @param isFieldExist Field existence.
+ * @param dataMap Data map.
+ * @param fieldName Field name.
+ * @param value Value to be asserted.
+ */
+ private void assertField(boolean isFieldExist, Map dataMap, String fieldName, String value) {
+
+ if (isFieldExist) {
+ Assert.assertEquals(dataMap.get(fieldName).toString(), value);
+ } else {
+ Assert.assertTrue(dataMap == null || dataMap.get(fieldName) == null);
+ }
+ }
+
+ /**
+ * Assert masked data fields.
+ *
+ * @param value Value to be asserted.
+ */
+ private void assertMasked(String value) {
+
+ Assert.assertTrue(value.contains("*"));
+ }
+
+ /**
+ * Assert generic data fields in audit logger.
+ *
+ * @param auditLogBuilder {@link AuditLog.AuditLogBuilder} instance.
+ * @param operation Operation to be logged.
+ * @throws NoSuchFieldException if the provided field does not exist.
+ * @throws IllegalAccessException if the provided field is not accessible.
+ */
+ private void assertAuditLoggerData(AuditLog.AuditLogBuilder auditLogBuilder,
+ String operation)
+ throws NoSuchFieldException, IllegalAccessException {
+
+ Assert.assertEquals(extractField("initiatorId", auditLogBuilder), "initiator-id-test");
+ Assert.assertEquals(extractField("targetId", auditLogBuilder), "System");
+ Assert.assertEquals(extractField("targetType", auditLogBuilder), "Action");
+ switch (operation) {
+ case ADD_ACTION:
+ Assert.assertEquals(extractField("action", auditLogBuilder), "add-action");
+ break;
+ case UPDATE_ACTION:
+ Assert.assertEquals(extractField("action", auditLogBuilder), "update-action");
+ break;
+ case DELETE_ACTION:
+ Assert.assertEquals(extractField("action", auditLogBuilder), "delete-action");
+ break;
+ }
+ }
+}
+
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/util/ActionSecretProcessorTest.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/util/ActionSecretProcessorTest.java
new file mode 100644
index 000000000000..ef38040fe208
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/util/ActionSecretProcessorTest.java
@@ -0,0 +1,222 @@
+/*
+ * 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.carbon.identity.action.management.util;
+
+import org.testng.Assert;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+import org.wso2.carbon.identity.action.management.internal.ActionMgtServiceComponentHolder;
+import org.wso2.carbon.identity.action.management.model.AuthProperty;
+import org.wso2.carbon.identity.action.management.model.Authentication;
+import org.wso2.carbon.identity.secret.mgt.core.SecretManager;
+import org.wso2.carbon.identity.secret.mgt.core.SecretManagerImpl;
+import org.wso2.carbon.identity.secret.mgt.core.SecretResolveManager;
+import org.wso2.carbon.identity.secret.mgt.core.exception.SecretManagementException;
+import org.wso2.carbon.identity.secret.mgt.core.model.ResolvedSecret;
+import org.wso2.carbon.identity.secret.mgt.core.model.SecretType;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.PRE_ISSUE_ACCESS_TOKEN_ACTION_ID;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACCESS_TOKEN;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_ACCESS_TOKEN_UPDATED;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_API_KEY_HEADER;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_API_KEY_VALUE;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_PASSWORD;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_SECRET_TYPE_ID;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.TEST_USERNAME;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.buildMockAPIKeyAuthentication;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.buildMockBasicAuthentication;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.buildMockBearerAuthentication;
+import static org.wso2.carbon.identity.action.management.util.TestUtil.buildSecretName;
+
+/**
+ * Test class for Action secrets processor.
+ */
+public class ActionSecretProcessorTest {
+
+ private SecretManager secretManager;
+ private SecretResolveManager secretResolveManager;
+ private ActionSecretProcessor actionSecretProcessor;
+
+ @BeforeClass
+ public void setUpClass() {
+
+ actionSecretProcessor = new ActionSecretProcessor();
+ }
+
+ @BeforeMethod
+ public void setUp() throws SecretManagementException {
+
+ secretManager = mock(SecretManagerImpl.class);
+ secretResolveManager = mock(SecretResolveManager.class);
+ ActionMgtServiceComponentHolder.getInstance().setSecretManager(secretManager);
+ ActionMgtServiceComponentHolder.getInstance().setSecretResolveManager(secretResolveManager);
+
+ SecretType secretType = mock(SecretType.class);
+ doReturn(TEST_SECRET_TYPE_ID).when(secretType).getId();
+ doReturn(secretType).when(secretManager).getSecretType(any());
+
+ }
+
+ @DataProvider
+ public Object[] provideAuthentication() {
+
+ return new Object[]{
+ buildMockBearerAuthentication(TEST_ACCESS_TOKEN),
+ buildMockBasicAuthentication(TEST_USERNAME, TEST_PASSWORD),
+ buildMockAPIKeyAuthentication(TEST_API_KEY_HEADER, TEST_API_KEY_VALUE)
+ };
+ }
+
+ @Test(dataProvider = "provideAuthentication")
+ public void testEncryptAssociatedSecrets(Authentication authentication) throws SecretManagementException {
+
+ doReturn(false).when(secretManager).isSecretExist(any(), any());
+ doReturn(null).when(secretManager).addSecret(any(), any());
+
+ List encryptedProperties = actionSecretProcessor.encryptAssociatedSecrets(authentication,
+ PRE_ISSUE_ACCESS_TOKEN_ACTION_ID);
+
+ Assert.assertEquals(encryptedProperties.size(), authentication.getProperties().size());
+ for (AuthProperty authProperty : encryptedProperties) {
+ Authentication.Property property = Arrays.stream(Authentication.Property.values())
+ .filter(prop -> prop.getName().equals(authProperty.getName()))
+ .findFirst()
+ .orElse(null);
+ AuthProperty inputAuthProperty = authentication.getProperty(property);
+
+ Assert.assertNotNull(property);
+ Assert.assertEquals(authProperty.getName(), authentication.getProperty(property).getName());
+ Assert.assertEquals(authProperty.getIsConfidential(), inputAuthProperty.getIsConfidential());
+ if (authProperty.getIsConfidential()) {
+ Assert.assertEquals(authProperty.getValue(),
+ TestUtil.buildSecretName(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID, authentication.getType(), property));
+ } else {
+ Assert.assertEquals(authProperty.getValue(), inputAuthProperty.getValue());
+ }
+ }
+ }
+
+ @Test
+ public void testUpdateSecret() throws SecretManagementException {
+
+ ResolvedSecret resolvedSecret = mock(ResolvedSecret.class);
+ doReturn(TEST_ACCESS_TOKEN).when(resolvedSecret).getResolvedSecretValue();
+ doReturn(resolvedSecret).when(secretResolveManager).getResolvedSecret(any(), any());
+ doReturn(true).when(secretManager).isSecretExist(any(), any());
+ doReturn(null).when(secretManager).updateSecretValue(any(), any(), any());
+
+ Authentication authentication = buildMockBearerAuthentication(TEST_ACCESS_TOKEN_UPDATED);
+ List encryptedProperties = actionSecretProcessor.encryptAssociatedSecrets(authentication,
+ PRE_ISSUE_ACCESS_TOKEN_ACTION_ID);
+
+ Assert.assertEquals(encryptedProperties.size(), authentication.getProperties().size());
+ Assert.assertEquals(encryptedProperties.get(0).getName(), authentication.getProperties().get(0).getName());
+ Assert.assertEquals(encryptedProperties.get(0).getName(), authentication.getProperties().get(0).getName());
+ Assert.assertEquals(encryptedProperties.get(0).getValue(), buildSecretName(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID,
+ Authentication.Type.BEARER, Authentication.Property.ACCESS_TOKEN));
+ }
+
+ @Test
+ public void testDecryptAssociatedSecrets() throws SecretManagementException {
+
+ ResolvedSecret resolvedSecret = mock(ResolvedSecret.class);
+ doReturn(TEST_ACCESS_TOKEN).when(resolvedSecret).getResolvedSecretValue();
+ doReturn(resolvedSecret).when(secretResolveManager).getResolvedSecret(any(), any());
+ doReturn(true).when(secretManager).isSecretExist(any(), any());
+
+ Authentication authentication = buildMockBearerAuthentication(buildSecretName(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID,
+ Authentication.Type.BEARER, Authentication.Property.ACCESS_TOKEN));
+
+ List decryptedProperties = actionSecretProcessor.decryptAssociatedSecrets(authentication,
+ PRE_ISSUE_ACCESS_TOKEN_ACTION_ID);
+
+ Assert.assertEquals(decryptedProperties.size(), authentication.getProperties().size());
+ Assert.assertEquals(decryptedProperties.get(0).getName(), authentication.getProperties().get(0).getName());
+ Assert.assertEquals(decryptedProperties.get(0).getIsConfidential(),
+ authentication.getProperties().get(0).getIsConfidential());
+ Assert.assertEquals(decryptedProperties.get(0).getValue(), TEST_ACCESS_TOKEN);
+ }
+
+ @Test
+ public void testDecryptAssociatedSecretsForNonSecret() throws SecretManagementException {
+
+ ResolvedSecret resolvedSecret = mock(ResolvedSecret.class);
+ doReturn(TEST_API_KEY_VALUE).when(resolvedSecret).getResolvedSecretValue();
+ doReturn(resolvedSecret).when(secretResolveManager).getResolvedSecret(any(), any());
+ doReturn(true).when(secretManager).isSecretExist(any(), any());
+
+ Authentication authentication = buildMockAPIKeyAuthentication(TEST_API_KEY_HEADER,
+ buildSecretName(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID, Authentication.Type.API_KEY,
+ Authentication.Property.VALUE));
+
+ List decryptedProperties = actionSecretProcessor.decryptAssociatedSecrets(authentication,
+ PRE_ISSUE_ACCESS_TOKEN_ACTION_ID);
+
+ for (AuthProperty authProperty : decryptedProperties) {
+ Authentication.Property property = Arrays.stream(Authentication.Property.values())
+ .filter(prop -> prop.getName().equals(authProperty.getName()))
+ .findFirst()
+ .orElse(null);
+ AuthProperty inputAuthProperty = authentication.getProperty(property);
+
+ Assert.assertEquals(authProperty.getName(), authentication.getProperty(property).getName());
+ Assert.assertEquals(authProperty.getIsConfidential(), inputAuthProperty.getIsConfidential());
+ if (authProperty.getIsConfidential()) {
+ Assert.assertEquals(authProperty.getValue(), TEST_API_KEY_VALUE);
+ } else {
+ Assert.assertEquals(authProperty.getValue(), TEST_API_KEY_HEADER);
+ }
+ }
+ }
+
+ @Test(expectedExceptions = SecretManagementException.class)
+ public void testDecryptAssociatedSecretsForNonExistingSecret() throws SecretManagementException {
+
+ doReturn(false).when(secretManager).isSecretExist(any(), any());
+ Authentication authentication = buildMockBearerAuthentication(buildSecretName(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID,
+ Authentication.Type.BEARER, Authentication.Property.ACCESS_TOKEN));
+
+ actionSecretProcessor.decryptAssociatedSecrets(authentication, PRE_ISSUE_ACCESS_TOKEN_ACTION_ID);
+ }
+
+ @Test
+ public void testDeleteAssociatedSecrets() throws SecretManagementException {
+
+ doReturn(true).when(secretManager).isSecretExist(any(), any());
+ doNothing().when(secretManager).deleteSecret(any(), any());
+
+ Authentication authentication = buildMockAPIKeyAuthentication(TEST_API_KEY_HEADER,
+ buildSecretName(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID, Authentication.Type.API_KEY,
+ Authentication.Property.VALUE));
+
+ actionSecretProcessor.deleteAssociatedSecrets(authentication, PRE_ISSUE_ACCESS_TOKEN_ACTION_ID);
+ verify(secretManager, times(1)).deleteSecret(any(), any());
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/util/TestUtil.java b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/util/TestUtil.java
new file mode 100644
index 000000000000..a235877c7147
--- /dev/null
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/java/org/wso2/carbon/identity/action/management/util/TestUtil.java
@@ -0,0 +1,127 @@
+/*
+ * 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.carbon.identity.action.management.util;
+
+import org.wso2.carbon.identity.action.management.model.Action;
+import org.wso2.carbon.identity.action.management.model.Authentication;
+import org.wso2.carbon.identity.action.management.model.EndpointConfig;
+
+import java.util.UUID;
+
+/**
+ * Utility class for Action Management Tests.
+ */
+public class TestUtil {
+
+ public static final int TENANT_ID = 2;
+ public static final String TENANT_DOMAIN = "carbon.super";
+
+ public static final String PRE_ISSUE_ACCESS_TOKEN_TYPE = Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN.getActionType();
+ public static final String PRE_UPDATE_PASSWORD_TYPE = Action.ActionTypes.PRE_UPDATE_PASSWORD.getActionType();
+
+ public static final String PRE_ISSUE_ACCESS_TOKEN_PATH = Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN.getPathParam();
+
+ public static final String PRE_ISSUE_ACCESS_TOKEN_ACTION_ID = String.valueOf(UUID.randomUUID());
+ public static final String PRE_UPDATE_PASSWORD_ACTION_ID = String.valueOf(UUID.randomUUID());
+
+ public static final String TEST_SECRET_TYPE_ID = "fcaf81a9-0d58-4cf4-98c8-fde2f3ba8df2";
+
+ public static final String TEST_ACTION_NAME = "Test Action Name";
+ public static final String TEST_ACTION_NAME_UPDATED = "Updated Test Action Name";
+ public static final String TEST_INVALID_ACTION_NAME = "PreIssueAccessToken_#1";
+ public static final String TEST_ACTION_DESCRIPTION = "Test Action description";
+ public static final String TEST_ACTION_DESCRIPTION_UPDATED = "Updated Test Action description";
+ public static final String TEST_ACTION_URI = "https://example.com";
+ public static final String TEST_ACTION_URI_UPDATED = "https://sample.com";
+
+ public static final String TEST_USERNAME = "sampleUsername";
+ public static final String TEST_USERNAME_SECRET_REFERENCE = buildSecretName(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID,
+ Authentication.Type.BASIC, Authentication.Property.USERNAME);
+ public static final String TEST_PASSWORD = "samplePassword";
+ public static final String TEST_PASSWORD_SECRET_REFERENCE = buildSecretName(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID,
+ Authentication.Type.BASIC, Authentication.Property.PASSWORD);
+ public static final String TEST_ACCESS_TOKEN = "5e482c2a-e83a-3afe-bc6a-ff79e1fdaaba";
+ public static final String TEST_ACCESS_TOKEN_UPDATED = "fe326c2a-e83a-41fe-bc6a-ee79e1feabba";
+ public static final String TEST_ACCESS_TOKEN_SECRET_REFERENCE = buildSecretName(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID,
+ Authentication.Type.BEARER, Authentication.Property.ACCESS_TOKEN);
+ public static final String TEST_API_KEY_HEADER = "sampleHeader";
+ public static final String TEST_API_KEY_HEADER_UPDATED = "UpdatedSampleHeader";
+ public static final String TEST_INVALID_API_KEY_HEADER = "-test-header";
+ public static final String TEST_API_KEY_VALUE = "sampleValue";
+ public static final String TEST_API_KEY_VALUE_UPDATED = "UpdatedSampleValue";
+ public static final String TEST_API_KEY_VALUE_SECRET_REFERENCE = buildSecretName(PRE_ISSUE_ACCESS_TOKEN_ACTION_ID,
+ Authentication.Type.API_KEY, Authentication.Property.VALUE);
+
+ public static final String TEST_ACTION_PROPERTY_NAME_1 = "samplePropertyName";
+ public static final String TEST_ACTION_PROPERTY_VALUE_1 = "samplePropertyValue";
+ public static final String TEST_ACTION_PROPERTY_VALUE_1_UPDATED = "UpdatedSamplePropertyValue";
+ public static final String TEST_ACTION_PROPERTY_NAME_2 = "samplePropertyName2";
+ public static final String TEST_ACTION_PROPERTY_VALUE_2 = "samplePropertyValue2";
+ public static final String TEST_ACTION_PROPERTY_VALUE_2_UPDATED = "UpdatedSamplePropertyValue2";
+ public static final String PASSWORD_SHARING_TYPE_PROPERTY_NAME = "passwordSharingType";
+ public static final String TEST_PASSWORD_SHARING_TYPE = "PLAIN_TEXT";
+ public static final String TEST_PASSWORD_SHARING_TYPE_UPDATED = "SHA256_HASHED";
+ public static final String CERTIFICATE_PROPERTY_NAME = "certificate";
+ public static final String TEST_CERTIFICATE = "sampleCertificate";
+ public static final String TEST_CERTIFICATE_UPDATED = "UpdatedSampleCertificate";
+ public static final String CERTIFICATE_ID = String.valueOf(UUID.randomUUID());
+ public static final String CERTIFICATE_NAME = "ACTIONS:" + PRE_UPDATE_PASSWORD_ACTION_ID;
+
+ public static Action buildMockAction(String name, String description, String uri, Authentication authentication) {
+
+ return new Action.ActionRequestBuilder()
+ .name(name)
+ .description(description)
+ .endpoint(buildMockEndpointConfig(uri, authentication))
+ .build();
+ }
+
+ public static String buildSecretName(String actionId, Authentication.Type authType,
+ Authentication.Property authProperty) {
+
+ return TEST_SECRET_TYPE_ID + ":" + actionId + ":" + authType.getName() + ":" + authProperty.getName();
+ }
+
+ public static Authentication buildMockBasicAuthentication(String username, String password) {
+
+ return new Authentication.BasicAuthBuilder(username, password).build();
+ }
+
+ public static Authentication buildMockBearerAuthentication(String accessToken) {
+
+ return new Authentication.BearerAuthBuilder(accessToken).build();
+ }
+
+ public static Authentication buildMockAPIKeyAuthentication(String header, String value) {
+
+ return new Authentication.APIKeyAuthBuilder(header, value).build();
+ }
+
+ public static EndpointConfig buildMockEndpointConfig(String uri, Authentication authentication) {
+
+ if (uri == null && authentication == null) {
+ return null;
+ }
+
+ return new EndpointConfig.EndpointConfigBuilder()
+ .uri(uri)
+ .authentication(authentication)
+ .build();
+ }
+}
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/resources/dbscripts/h2.sql b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/resources/dbscripts/h2.sql
index 776921371a60..9bf8470be8e8 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/resources/dbscripts/h2.sql
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/resources/dbscripts/h2.sql
@@ -8,7 +8,7 @@ CREATE TABLE IF NOT EXISTS IDN_ACTION (
PRIMARY KEY (UUID)
);
-CREATE TABLE IF NOT EXISTS IDN_ACTION_ENDPOINT (
+CREATE TABLE IF NOT EXISTS IDN_ACTION_PROPERTIES (
ACTION_UUID CHAR(36) NOT NULL,
PROPERTY_NAME VARCHAR(100) NOT NULL,
PROPERTY_VALUE VARCHAR(255) NOT NULL,
diff --git a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/resources/testng.xml b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/resources/testng.xml
index 60acc4cb2749..d9b62e751a03 100644
--- a/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/resources/testng.xml
+++ b/components/action-mgt/org.wso2.carbon.identity.action.management/src/test/resources/testng.xml
@@ -21,10 +21,16 @@
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/components/action-mgt/pom.xml b/components/action-mgt/pom.xml
index 68368957e296..90a50fe3901e 100644
--- a/components/action-mgt/pom.xml
+++ b/components/action-mgt/pom.xml
@@ -22,7 +22,7 @@
org.wso2.carbon.identity.framework
identity-framework
- 7.6.10-SNAPSHOT
+ 7.7.63-SNAPSHOT
../../pom.xml
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/pom.xml b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/pom.xml
new file mode 100644
index 000000000000..667885425533
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/pom.xml
@@ -0,0 +1,211 @@
+
+
+
+
+ 4.0.0
+
+ org.wso2.carbon.identity.framework
+ ai-services-mgt
+ 7.6.10-SNAPSHOT
+ ../pom.xml
+
+
+ org.wso2.carbon.ai.service.mgt
+ bundle
+ WSO2 Carbon - AI Service Management Bundle
+ This is a Carbon bundle that represents the AI Service Management Bundle.
+ http://wso2.org
+
+
+
+ org.ops4j.pax.logging
+ pax-logging-api
+
+
+ org.wso2.carbon.identity.framework
+ org.wso2.carbon.identity.core
+
+
+ org.wso2.orbit.org.apache.httpcomponents
+ httpasyncclient
+
+
+ org.apache.httpcomponents.wso2
+ httpcore
+ provided
+
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ org.mockito
+ mockito-core
+
+
+ org.testng
+ testng
+ test
+
+
+ org.slf4j
+ slf4j-api
+
+
+ org.apache.logging.log4j
+ log4j-core
+ test
+
+
+ org.wiremock
+ wiremock
+ test
+
+
+
+ org.ops4j.pax.logging
+ pax-logging-api
+
+
+
+
+
+
+
+ org.apache.felix
+ maven-bundle-plugin
+ true
+
+
+
+ ${project.artifactId}
+
+ ${project.artifactId}
+
+ org.osgi.framework; version="${osgi.framework.imp.pkg.version.range}",
+ org.osgi.service.component; version="${osgi.service.component.imp.pkg.version.range}",
+ com.google.gson;version="${com.google.code.gson.osgi.version.range}",
+ org.wso2.carbon.identity.core.util; version="${carbon.identity.package.import.version.range}",
+ org.apache.commons.lang; version="${commons-lang.wso2.osgi.version.range}",
+ org.apache.commons.logging; version="${import.package.version.commons.logging}",
+ com.fasterxml.jackson.databind.*; version="${com.fasterxml.jackson.annotation.version.range}",
+ org.wso2.carbon.context; version="${carbon.kernel.package.import.version.range}",
+
+ org.apache.http; version="${httpcore.version.osgi.import.range}",
+ org.apache.http.client; version="${httpcomponents-httpclient.imp.pkg.version.range}",
+ org.apache.http.client.methods; version="${httpcomponents-httpclient.imp.pkg.version.range}",
+ org.apache.http.entity; version="${httpcore.version.osgi.import.range}",
+ org.apache.http.message; version="${httpcore.version.osgi.import.range}",
+ org.apache.http.protocol; version="${httpcore.version.osgi.import.range}",
+ org.apache.http.util; version="${httpcore.version.osgi.import.range}",
+ org.apache.http.impl.client; version="${httpcomponents-httpclient.imp.pkg.version.range}",
+ org.apache.http.impl.nio.client; version="${httpasyncclient.version.osgi.import.range}",
+ org.apache.http.impl.nio.reactor; version="${httpasyncclient.version.osgi.import.range}",
+ org.apache.http.impl.nio.conn; version="${httpasyncclient.version.osgi.import.range}",
+ org.apache.http.concurrent; version="${httpcore.version.osgi.import.range}",
+ org.apache.http.nio.reactor; version="${httpasyncclient.version.osgi.import.range}",
+ org.apache.http.nio.conn; version="${httpasyncclient.version.osgi.import.range}",
+
+
+ org.wso2.carbon.ai.service.mgt.*; version="${carbon.identity.package.export.version}"
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ ${maven.surefire.plugin.version}
+
+
+
+ ${argLine}
+ --add-opens=java.base/java.lang=ALL-UNNAMED
+ --add-opens=java.base/java.util=ALL-UNNAMED
+ --add-opens java.xml/jdk.xml.internal=ALL-UNNAMED
+ --add-opens=java.base/java.io=ALL-UNNAMED
+ --add-opens=java.base/sun.nio.fs=ALL-UNNAMED
+
+
+ src/test/resources/testng.xml
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ ${jacoco.version}
+
+
+ default-prepare-agent
+
+ prepare-agent
+
+
+
+ default-prepare-agent-integration
+
+ prepare-agent-integration
+
+
+
+ default-report
+
+ report
+
+
+
+ default-report-integration
+
+ report-integration
+
+
+
+ default-check
+
+ check
+
+
+
+
+ BUNDLE
+
+
+ COMPLEXITY
+ COVEREDRATIO
+ 0.77
+
+
+
+
+
+
+
+
+
+ com.github.spotbugs
+ spotbugs-maven-plugin
+
+ High
+
+
+
+
+
+
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/constants/AIConstants.java b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/constants/AIConstants.java
new file mode 100644
index 000000000000..252fd02f35f6
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/constants/AIConstants.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2025, 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.carbon.ai.service.mgt.constants;
+
+/**
+ * Constants for the LoginFlowAI module.
+ */
+public class AIConstants {
+
+ public static final String AI_SERVICE_KEY_PROPERTY_NAME = "AIServices.Key";
+ public static final String AI_TOKEN_ENDPOINT_PROPERTY_NAME = "AIServices.TokenEndpoint";
+ public static final String AI_TOKEN_SERVICE_MAX_RETRIES_PROPERTY_NAME = "AIServices.TokenRequestMaxRetries";
+ public static final String AI_TOKEN_SERVICE_TIMEOUT_PROPERTY_NAME = "AIServices.TokenRequestTimeout";
+ public static final String HTTP_CONNECTION_POOL_SIZE_PROPERTY_NAME = "AIServices.HTTPConnectionPoolSize";
+ public static final String HTTP_CONNECTION_TIMEOUT_PROPERTY_NAME = "AIServices.HTTPConnectionTimeout";
+
+ // Http constants.
+ public static final String HTTP_BASIC = "Basic";
+ public static final String HTTP_BEARER = "Bearer";
+ public static final String CONTENT_TYPE_FORM_URLENCODED = "application/x-www-form-urlencoded";
+ public static final String CONTENT_TYPE_JSON = "application/json";
+
+ // Access Token response constants.
+ public static final String ACCESS_TOKEN_KEY = "access_token";
+
+ public static final String TENANT_CONTEXT_PREFIX = "/t/";
+
+ /**
+ * Enums for error messages.
+ */
+ public enum ErrorMessages {
+
+ MAXIMUM_RETRIES_EXCEEDED("AI_10000", "Maximum retries exceeded to retrieve the access token."),
+ UNABLE_TO_ACCESS_AI_SERVICE_WITH_RENEW_ACCESS_TOKEN("AI_10003", "Unable to access the " +
+ "AI service with the renewed access token."),
+ REQUEST_TIMEOUT("AI_10004", "Request to the AI service timed out."),
+ ERROR_RETRIEVING_ACCESS_TOKEN("AI_10007", "Error occurred while retrieving the " +
+ "access token."),
+ CLIENT_ERROR_WHILE_CONNECTING_TO_AI_SERVICE("AI_10008", "Client error occurred " +
+ "for %s tenant while connecting to AI service."),
+ SERVER_ERROR_WHILE_CONNECTING_TO_AI_SERVICE("AI_10009", "Server error occurred " +
+ "for %s tenant while connecting to AI service.");
+
+
+ private final String code;
+ private final String message;
+
+ ErrorMessages(String code, String message) {
+
+ this.code = code;
+ this.message = message;
+ }
+
+ public String getCode() {
+
+ return code;
+ }
+
+ public String getMessage() {
+
+ return message;
+ }
+
+ @Override
+ public String toString() {
+
+ return code + ":" + message;
+ }
+ }
+}
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/exceptions/AIClientException.java b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/exceptions/AIClientException.java
new file mode 100644
index 000000000000..3272e573177e
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/exceptions/AIClientException.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2025, 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.carbon.ai.service.mgt.exceptions;
+
+import org.wso2.carbon.ai.service.mgt.util.AIHttpClientUtil;
+
+/**
+ * Client Exception class for AI service.
+ */
+public class AIClientException extends Exception {
+
+ private final String errorCode;
+ private AIHttpClientUtil.HttpResponseWrapper loginFlowAIResponse;
+
+ public AIClientException(String message, String errorCode) {
+
+ super(message);
+ this.errorCode = errorCode;
+ }
+
+ public AIClientException(AIHttpClientUtil.HttpResponseWrapper httpResponseWrapper,
+ String message, String errorCode) {
+
+ super(message);
+ this.errorCode = errorCode;
+ this.loginFlowAIResponse = httpResponseWrapper;
+ }
+
+ public AIClientException(String message, String errorCode, Throwable cause) {
+
+ super(message, cause);
+ this.errorCode = errorCode;
+ }
+
+ public String getErrorCode() {
+
+ return errorCode;
+ }
+
+ public AIHttpClientUtil.HttpResponseWrapper getLoginFlowAIResponse() {
+
+ return loginFlowAIResponse;
+ }
+}
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/exceptions/AIServerException.java b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/exceptions/AIServerException.java
new file mode 100644
index 000000000000..1bdadca5a81e
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/exceptions/AIServerException.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2025, 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.carbon.ai.service.mgt.exceptions;
+
+import org.wso2.carbon.ai.service.mgt.util.AIHttpClientUtil;
+
+/**
+ * Client Exception class for AI service.
+ */
+public class AIServerException extends Exception {
+
+ private String errorCode;
+ private AIHttpClientUtil.HttpResponseWrapper loginFlowAIResponse;
+
+ public AIServerException(String message, String errorCode) {
+
+ super(message);
+ this.errorCode = errorCode;
+ }
+
+ public AIServerException(AIHttpClientUtil.HttpResponseWrapper httpResponseWrapper,
+ String message, String errorCode) {
+
+ super(message);
+ this.errorCode = errorCode;
+ this.loginFlowAIResponse = httpResponseWrapper;
+ }
+
+ public AIServerException(String message, Throwable cause) {
+
+ super(message, cause);
+ }
+
+ public AIServerException(String message, String errorCode, Throwable cause) {
+
+ super(message, cause);
+ this.errorCode = errorCode;
+ }
+
+ public String getErrorCode() {
+
+ return errorCode;
+ }
+
+ public AIHttpClientUtil.HttpResponseWrapper getBrandingAIResponse() {
+
+ return loginFlowAIResponse;
+ }
+}
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/token/AIAccessTokenManager.java b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/token/AIAccessTokenManager.java
new file mode 100644
index 000000000000..d4c06c6c8c28
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/token/AIAccessTokenManager.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2025, 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.carbon.ai.service.mgt.token;
+
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonSyntaxException;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.concurrent.FutureCallback;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
+import org.apache.http.impl.nio.client.HttpAsyncClients;
+import org.apache.http.message.BasicHeader;
+import org.apache.http.protocol.HTTP;
+import org.apache.http.util.EntityUtils;
+import org.wso2.carbon.ai.service.mgt.exceptions.AIServerException;
+import org.wso2.carbon.identity.core.util.IdentityUtil;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.axis2.transport.http.HTTPConstants.HEADER_CONTENT_TYPE;
+import static org.apache.http.HttpHeaders.AUTHORIZATION;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.ACCESS_TOKEN_KEY;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.AI_SERVICE_KEY_PROPERTY_NAME;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.AI_TOKEN_ENDPOINT_PROPERTY_NAME;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.AI_TOKEN_SERVICE_MAX_RETRIES_PROPERTY_NAME;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.AI_TOKEN_SERVICE_TIMEOUT_PROPERTY_NAME;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.CONTENT_TYPE_FORM_URLENCODED;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.ErrorMessages.MAXIMUM_RETRIES_EXCEEDED;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.HTTP_BASIC;
+import static org.wso2.carbon.identity.core.util.IdentityTenantUtil.getTenantDomainFromContext;
+
+/**
+ * The purpose of this class is to retrieve an active token to access the AI service.
+ */
+public class AIAccessTokenManager {
+
+ private static volatile AIAccessTokenManager instance; // Volatile for thread safety.
+ private static final Object lock = new Object(); // Lock for synchronization.
+
+ private static final Log LOG = LogFactory.getLog(AIAccessTokenManager.class);
+
+ private static final String AI_KEY = IdentityUtil.getProperty(AI_SERVICE_KEY_PROPERTY_NAME);
+ private static final String AI_TOKEN_ENDPOINT = IdentityUtil.getProperty(AI_TOKEN_ENDPOINT_PROPERTY_NAME);
+
+ private AccessTokenRequestHelper accessTokenRequestHelper;
+
+ private String accessToken;
+ private final String clientId;
+
+ private AIAccessTokenManager() {
+
+ byte[] decodedBytes = Base64.getDecoder().decode(AI_KEY);
+ String decodedString = new String(decodedBytes, StandardCharsets.UTF_8);
+ String[] parts = decodedString.split(":");
+ if (parts.length == 2) {
+ this.clientId = parts[0]; // Extract clientId.
+ } else {
+ throw new IllegalArgumentException("Invalid AI service key.");
+ }
+ }
+
+ /**
+ * Get the singleton instance of the AIAccessTokenManager.
+ *
+ * @return The singleton instance.
+ */
+ public static AIAccessTokenManager getInstance() {
+
+ if (instance == null) {
+ synchronized (lock) {
+ if (instance == null) {
+ instance = new AIAccessTokenManager();
+ }
+ }
+ }
+ return instance;
+ }
+
+ /**
+ * Set the access token request helper.
+ *
+ * @param helper The access token request helper.
+ */
+ protected void setAccessTokenRequestHelper(AccessTokenRequestHelper helper) {
+
+ this.accessTokenRequestHelper = helper;
+ }
+
+ /**
+ * Get the access token.
+ *
+ * @param renewAccessToken Whether to renew the access token.
+ * @return The access token.
+ * @throws AIServerException If an error occurs while obtaining the access token.
+ */
+ public String getAccessToken(boolean renewAccessToken) throws AIServerException {
+
+ if (StringUtils.isEmpty(accessToken) || renewAccessToken) {
+ synchronized (AIAccessTokenManager.class) {
+ if (StringUtils.isEmpty(accessToken) || renewAccessToken) {
+ this.accessToken = accessTokenRequestHelper != null ?
+ accessTokenRequestHelper.requestAccessToken() : createDefaultHelper().requestAccessToken();
+ }
+ }
+ }
+ return this.accessToken;
+ }
+
+ private AccessTokenRequestHelper createDefaultHelper() {
+
+ return new AccessTokenRequestHelper(AI_KEY, AI_TOKEN_ENDPOINT,
+ // Here we keep the default HTTP client to send the token request.
+ // We open and close it for each request.
+ HttpAsyncClients.createDefault());
+ }
+
+ /**
+ * Get the client ID.
+ *
+ * @return The client ID.
+ */
+ public String getClientId() {
+
+ return this.clientId;
+ }
+
+ /**
+ * Helper class to request access token from the AI services.
+ */
+ protected static class AccessTokenRequestHelper {
+
+ private final CloseableHttpAsyncClient client;
+ private final Gson gson;
+ private final String key;
+ private final String aiServiceTokenEndpoint;
+ private static final int MAX_RETRIES = IdentityUtil.getProperty(
+ AI_TOKEN_SERVICE_MAX_RETRIES_PROPERTY_NAME) != null ?
+ Integer.parseInt(IdentityUtil.getProperty(AI_TOKEN_SERVICE_MAX_RETRIES_PROPERTY_NAME)) : 3;
+ private static final long TIMEOUT = IdentityUtil.getProperty(AI_TOKEN_SERVICE_TIMEOUT_PROPERTY_NAME) != null ?
+ Long.parseLong(IdentityUtil.getProperty(AI_TOKEN_SERVICE_TIMEOUT_PROPERTY_NAME)) : 3000;
+
+ AccessTokenRequestHelper(String key, String tokenEndpoint, CloseableHttpAsyncClient client) {
+
+ this.client = client;
+ this.gson = new GsonBuilder().create();
+ this.key = key;
+ this.aiServiceTokenEndpoint = tokenEndpoint;
+ }
+
+ /**
+ * Request access token to access the AI services.
+ *
+ * @return the JWT access token.
+ * @throws AIServerException If an error occurs while requesting the access token.
+ */
+ public String requestAccessToken() throws AIServerException {
+
+ String tenantDomain = getTenantDomainFromContext();
+ LOG.info("Initiating access token request for AI services from tenant: " + tenantDomain);
+ try {
+ client.start();
+ for (int attempt = 0; attempt < MAX_RETRIES; attempt++) {
+ HttpPost post = new HttpPost(aiServiceTokenEndpoint);
+ post.setHeader(AUTHORIZATION, HTTP_BASIC + " " + key);
+ post.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_FORM_URLENCODED);
+
+ StringEntity entity = new StringEntity("grant_type=client_credentials&tokenBindingId=" +
+ UUID.randomUUID());
+ entity.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, CONTENT_TYPE_FORM_URLENCODED));
+ post.setEntity(entity);
+
+ CountDownLatch latch = new CountDownLatch(1);
+ final String[] accessToken = new String[1];
+ client.execute(post, new FutureCallback() {
+ @Override
+ public void completed(HttpResponse response) {
+
+ try {
+ if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
+ String responseBody = EntityUtils.toString(response.getEntity());
+ Map responseMap = gson.fromJson(responseBody, Map.class);
+ accessToken[0] = (String) responseMap.get(ACCESS_TOKEN_KEY);
+ } else {
+ LOG.error("Token request failed with status code: " +
+ response.getStatusLine().getStatusCode());
+ }
+ } catch (IOException | JsonSyntaxException e) {
+ LOG.warn("Error parsing token response: " + e.getMessage(), e);
+ } finally {
+ latch.countDown();
+ }
+ }
+
+ @Override
+ public void failed(Exception e) {
+
+ LOG.warn("Token request failed: " + e.getMessage(), e);
+ latch.countDown();
+ }
+
+ @Override
+ public void cancelled() {
+
+ LOG.warn("Token request was cancelled");
+ latch.countDown();
+ }
+ });
+
+ if (latch.await(TIMEOUT, TimeUnit.MILLISECONDS)) {
+ if (accessToken[0] != null) {
+ return accessToken[0];
+ }
+ } else {
+ LOG.warn("Token request timed out");
+ }
+ // Wait before retrying.
+ TimeUnit.MILLISECONDS.sleep(500);
+ }
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new AIServerException("Token request interrupted: " + e.getMessage(), e);
+ } catch (UnsupportedEncodingException e) {
+ throw new AIServerException("Error creating token request: " + e.getMessage(), e);
+ } finally {
+ try {
+ client.close();
+ } catch (IOException e) {
+ LOG.error("Failed to close HTTP client: " + e.getMessage(), e);
+ }
+ }
+ // If it reaches this point.
+ throw new AIServerException("Failed to obtain access token after " + MAX_RETRIES +
+ " attempts.", MAXIMUM_RETRIES_EXCEEDED.getCode());
+ }
+ }
+}
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/util/AIHttpClientUtil.java b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/util/AIHttpClientUtil.java
new file mode 100644
index 000000000000..f4d8aa73292d
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/main/java/org/wso2/carbon/ai/service/mgt/util/AIHttpClientUtil.java
@@ -0,0 +1,286 @@
+/*
+ * Copyright (c) 2025, 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.carbon.ai.service.mgt.util;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.httpclient.HttpStatus;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.concurrent.FutureCallback;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
+import org.apache.http.impl.nio.client.HttpAsyncClients;
+import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
+import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;
+import org.apache.http.impl.nio.reactor.IOReactorConfig;
+import org.apache.http.nio.reactor.ConnectingIOReactor;
+import org.apache.http.util.EntityUtils;
+import org.wso2.carbon.ai.service.mgt.exceptions.AIClientException;
+import org.wso2.carbon.ai.service.mgt.exceptions.AIServerException;
+import org.wso2.carbon.ai.service.mgt.token.AIAccessTokenManager;
+import org.wso2.carbon.context.PrivilegedCarbonContext;
+import org.wso2.carbon.identity.core.util.IdentityUtil;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+import static org.apache.axis2.transport.http.HTTPConstants.HEADER_CONTENT_TYPE;
+import static org.apache.http.HttpHeaders.AUTHORIZATION;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.CONTENT_TYPE_JSON;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.ErrorMessages.CLIENT_ERROR_WHILE_CONNECTING_TO_AI_SERVICE;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.ErrorMessages.ERROR_RETRIEVING_ACCESS_TOKEN;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.ErrorMessages.SERVER_ERROR_WHILE_CONNECTING_TO_AI_SERVICE;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.ErrorMessages.UNABLE_TO_ACCESS_AI_SERVICE_WITH_RENEW_ACCESS_TOKEN;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.HTTP_BEARER;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.HTTP_CONNECTION_POOL_SIZE_PROPERTY_NAME;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.HTTP_CONNECTION_TIMEOUT_PROPERTY_NAME;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.TENANT_CONTEXT_PREFIX;
+
+/**
+ * Utility class for AI Services to send HTTP requests.
+ */
+public class AIHttpClientUtil {
+
+ private static final Log LOG = LogFactory.getLog(AIHttpClientUtil.class);
+ private static final ObjectMapper objectMapper = new ObjectMapper();
+
+ private static final int HTTP_CONNECTION_POOL_SIZE = IdentityUtil.getProperty(
+ HTTP_CONNECTION_POOL_SIZE_PROPERTY_NAME) != null ? Integer.parseInt(IdentityUtil.getProperty(
+ HTTP_CONNECTION_POOL_SIZE_PROPERTY_NAME)) : 20;
+ private static final int HTTP_CONNECTION_TIMEOUT = IdentityUtil.getProperty(
+ HTTP_CONNECTION_TIMEOUT_PROPERTY_NAME) != null ? Integer.parseInt(IdentityUtil.getProperty(
+ HTTP_CONNECTION_TIMEOUT_PROPERTY_NAME)) : 60000; // Making the default timeout 60 seconds.
+
+
+ // Singleton instance of CloseableHttpAsyncClient with connection pooling.
+ private static final CloseableHttpAsyncClient httpClient;
+
+ static {
+ // Configure the IO reactor.
+ IOReactorConfig ioReactorConfig = IOReactorConfig.custom()
+ .setIoThreadCount(Runtime.getRuntime().availableProcessors())
+ .setConnectTimeout(HTTP_CONNECTION_TIMEOUT)
+ .build();
+ ConnectingIOReactor ioReactor;
+ try {
+ // Create the IO reactor.
+ ioReactor = new DefaultConnectingIOReactor(ioReactorConfig);
+ } catch (IOException e) {
+ throw new RuntimeException("Error initializing IO Reactor", e);
+ }
+ // Create a connection manager with the IO reactor.
+ PoolingNHttpClientConnectionManager connectionManager = new PoolingNHttpClientConnectionManager(ioReactor);
+ // Maximum total connections.
+ connectionManager.setMaxTotal(HTTP_CONNECTION_POOL_SIZE);
+ // Initialize the HttpClient with the connection manager.
+ httpClient = HttpAsyncClients.custom()
+ .setConnectionManager(connectionManager)
+ .build();
+ // Start the HttpClient.
+ httpClient.start();
+ // Add a shutdown hook to close the client when the application stops.
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ try {
+ httpClient.close();
+ } catch (IOException e) {
+ LOG.error("Error while shutting down HTTP client: " + e.getMessage());
+ }
+ }));
+ }
+
+
+
+ /**
+ * Execute a request to the AI service.
+ *
+ * @param path The endpoint to which the request should be sent.
+ * @param requestType The type of the request (GET, POST).
+ * @param requestBody The request body(Only for POST requests).
+ * @param aiServiceEndpoint The endpoint of the AI service.
+ * @return The response from the AI service as a map.
+ * @throws AIServerException If a server error occurred while accessing the AI service.
+ * @throws AIClientException If a client error occurred while accessing the AI service.
+ */
+ public static Map executeRequest(String aiServiceEndpoint, String path,
+ Class extends HttpUriRequest> requestType, Object requestBody)
+ throws AIServerException, AIClientException {
+
+ String tenantDomain = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantDomain();
+
+ try {
+ String accessToken = AIAccessTokenManager.getInstance().getAccessToken(false);
+ String orgName = AIAccessTokenManager.getInstance().getClientId();
+
+ HttpUriRequest request = createRequest(aiServiceEndpoint + TENANT_CONTEXT_PREFIX + orgName + path,
+ requestType, accessToken, requestBody);
+ HttpResponseWrapper aiServiceResponse = executeRequestWithRetry(request);
+
+ int statusCode = aiServiceResponse.getStatusCode();
+ String responseBody = aiServiceResponse.getResponseBody();
+
+ if (statusCode >= 400) {
+ handleErrorResponse(statusCode, responseBody, tenantDomain);
+ }
+ return convertJsonStringToMap(responseBody);
+ } catch (IOException | ExecutionException e) {
+ throw new AIServerException("An error occurred while connecting to the AI Service.",
+ SERVER_ERROR_WHILE_CONNECTING_TO_AI_SERVICE.getCode(), e);
+ } catch (InterruptedException e) {
+ // Restore the interrupted status of the thread to ensure it is not swallowed
+ // and can be handled appropriately by other parts of the program. This is
+ // important for proper thread coordination and graceful shutdown in a
+ // multithreaded environment.
+ Thread.currentThread().interrupt();
+
+ // Wrap and rethrow the exception as a custom AIServerException to provide
+ // a meaningful error message and maintain the original exception for debugging.
+ throw new AIServerException("An error occurred while connecting to the AI Service.",
+ SERVER_ERROR_WHILE_CONNECTING_TO_AI_SERVICE.getCode(), e);
+ }
+ }
+
+ private static HttpUriRequest createRequest(String url, Class extends HttpUriRequest> requestType,
+ String accessToken, Object requestBody) throws IOException {
+
+ HttpUriRequest request;
+ if (requestType == HttpPost.class) {
+ HttpPost post = new HttpPost(url);
+ if (requestBody != null) {
+ post.setEntity(new StringEntity(objectMapper.writeValueAsString(requestBody)));
+ }
+ request = post;
+ } else if (requestType == HttpGet.class) {
+ request = new HttpGet(url);
+ } else {
+ throw new IllegalArgumentException("Unsupported request type: " + requestType.getName());
+ }
+
+ request.setHeader(AUTHORIZATION, HTTP_BEARER + " " + accessToken);
+ request.setHeader(HEADER_CONTENT_TYPE, CONTENT_TYPE_JSON);
+ return request;
+ }
+
+ protected static HttpResponseWrapper executeRequestWithRetry(HttpUriRequest request)
+ throws InterruptedException, ExecutionException, IOException, AIServerException {
+
+ HttpResponseWrapper response = executeHttpRequest(request);
+
+ if (response.getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
+ String newAccessToken = AIAccessTokenManager.getInstance().getAccessToken(true);
+ if (newAccessToken == null) {
+ throw new AIServerException("Failed to renew access token.", ERROR_RETRIEVING_ACCESS_TOKEN.getCode());
+ }
+ request.setHeader(AUTHORIZATION, HTTP_BEARER + " " + newAccessToken);
+ response = executeHttpRequest(request);
+ }
+ return response;
+ }
+
+ private static void handleErrorResponse(int statusCode, String responseBody, String tenantDomain)
+ throws AIServerException, AIClientException {
+
+ if (statusCode == HttpStatus.SC_UNAUTHORIZED) {
+ throw new AIServerException("Failed to access AI service with renewed access token for " +
+ "the tenant domain: " + tenantDomain,
+ UNABLE_TO_ACCESS_AI_SERVICE_WITH_RENEW_ACCESS_TOKEN.getCode());
+ } else if (statusCode >= 400 && statusCode < 500) {
+ throw new AIClientException(new HttpResponseWrapper(statusCode, responseBody),
+ "Client error occurred from tenant: " + tenantDomain + " with status code: '" + statusCode
+ + "' while accessing AI service.", CLIENT_ERROR_WHILE_CONNECTING_TO_AI_SERVICE.getCode());
+ } else if (statusCode >= 500) {
+ throw new AIServerException(new HttpResponseWrapper(statusCode, responseBody),
+ "Server error occurred from tenant: " + tenantDomain + " with status code: '" + statusCode
+ + "' while accessing AI service.", SERVER_ERROR_WHILE_CONNECTING_TO_AI_SERVICE.getCode());
+ }
+ }
+
+ private static Map convertJsonStringToMap(String jsonString) throws AIServerException {
+
+ try {
+ return objectMapper.readValue(jsonString, Map.class);
+ } catch (IOException e) {
+ throw new AIServerException("Error occurred while parsing the JSON response from the AI service.", e);
+ }
+ }
+
+ protected static HttpResponseWrapper executeHttpRequest(HttpUriRequest httpRequest)
+ throws InterruptedException, ExecutionException, IOException, AIServerException {
+
+ Future apiResponse = AIHttpClientUtil.httpClient.execute(httpRequest,
+ new FutureCallback() {
+ @Override
+ public void completed(HttpResponse response) {
+
+ LOG.info("API request completed with status code: " + response.getStatusLine().getStatusCode());
+ }
+
+ @Override
+ public void failed(Exception e) {
+
+ LOG.error("API request failed: " + e.getMessage(), e);
+ }
+
+ @Override
+ public void cancelled() {
+
+ LOG.warn("API request was cancelled");
+ }
+ });
+ if (apiResponse == null) {
+ throw new AIServerException("Unable to get the response from the AI service.",
+ SERVER_ERROR_WHILE_CONNECTING_TO_AI_SERVICE.getCode());
+ }
+ HttpResponse httpResponse = apiResponse.get();
+ int status = httpResponse.getStatusLine().getStatusCode();
+ String response = EntityUtils.toString(httpResponse.getEntity());
+ return new HttpResponseWrapper(status, response);
+ }
+
+ /**
+ * Wrapper class for HTTP response.
+ */
+ public static class HttpResponseWrapper implements Serializable {
+
+ private final int statusCode;
+ private final String responseBody;
+
+ public HttpResponseWrapper(int statusCode, String responseBody) {
+
+ this.statusCode = statusCode;
+ this.responseBody = responseBody;
+ }
+
+ public int getStatusCode() {
+
+ return statusCode;
+ }
+
+ public String getResponseBody() {
+
+ return responseBody;
+ }
+ }
+}
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/constants/AIConstantsTest.java b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/constants/AIConstantsTest.java
new file mode 100644
index 000000000000..7eaf4ce9fca0
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/constants/AIConstantsTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.carbon.ai.service.mgt.constants;
+
+import org.testng.annotations.Test;
+
+import static org.testng.AssertJUnit.assertEquals;
+
+/**
+ * Test class for AIConstants.
+ */
+public class AIConstantsTest {
+
+ @Test
+ public void testErrorMessages() {
+ AIConstants.ErrorMessages errorMessage = AIConstants.ErrorMessages.MAXIMUM_RETRIES_EXCEEDED;
+ assertEquals(errorMessage.getCode(), "AI_10000");
+ assertEquals(errorMessage.getMessage(), "Maximum retries exceeded to retrieve the access token.");
+ assertEquals(errorMessage.toString(), "AI_10000:Maximum retries exceeded to retrieve the access token.");
+
+ errorMessage = AIConstants.ErrorMessages.UNABLE_TO_ACCESS_AI_SERVICE_WITH_RENEW_ACCESS_TOKEN;
+ assertEquals(errorMessage.getCode(), "AI_10003");
+ assertEquals(errorMessage.getMessage(), "Unable to access the AI service with the renewed access token.");
+ assertEquals(errorMessage.toString(), "AI_10003:Unable to access the AI service with " +
+ "the renewed access token.");
+
+ errorMessage = AIConstants.ErrorMessages.REQUEST_TIMEOUT;
+ assertEquals(errorMessage.getCode(), "AI_10004");
+ assertEquals(errorMessage.getMessage(), "Request to the AI service timed out.");
+ assertEquals(errorMessage.toString(), "AI_10004:Request to the AI service timed out.");
+
+ errorMessage = AIConstants.ErrorMessages.ERROR_RETRIEVING_ACCESS_TOKEN;
+ assertEquals(errorMessage.getCode(), "AI_10007");
+ assertEquals(errorMessage.getMessage(), "Error occurred while retrieving the access token.");
+ assertEquals(errorMessage.toString(), "AI_10007:Error occurred while retrieving the access token.");
+
+ errorMessage = AIConstants.ErrorMessages.CLIENT_ERROR_WHILE_CONNECTING_TO_AI_SERVICE;
+ assertEquals(errorMessage.getCode(), "AI_10008");
+ assertEquals(errorMessage.getMessage(), "Client error occurred for %s tenant while connecting to AI service.");
+ assertEquals(errorMessage.toString(), "AI_10008:Client error occurred for %s tenant while" +
+ " connecting to AI service.");
+
+ errorMessage = AIConstants.ErrorMessages.SERVER_ERROR_WHILE_CONNECTING_TO_AI_SERVICE;
+ assertEquals(errorMessage.getCode(), "AI_10009");
+ assertEquals(errorMessage.getMessage(), "Server error occurred for %s tenant while connecting to AI service.");
+ assertEquals(errorMessage.toString(), "AI_10009:Server error occurred for %s tenant while " +
+ "connecting to AI service.");
+ }
+}
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/exceptions/AIClientExceptionTest.java b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/exceptions/AIClientExceptionTest.java
new file mode 100644
index 000000000000..1fd73f24c95b
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/exceptions/AIClientExceptionTest.java
@@ -0,0 +1,61 @@
+/*
+ * 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.carbon.ai.service.mgt.exceptions;
+
+import org.testng.annotations.Test;
+import org.wso2.carbon.ai.service.mgt.util.AIHttpClientUtil;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNull;
+
+/**
+ * Test class for AIClientException.
+ */
+public class AIClientExceptionTest {
+
+ @Test
+ public void testAIClientExceptionWithMessageAndErrorCode() {
+
+ AIClientException exception = new AIClientException("Test message", "AI_10001");
+ assertEquals("Test message", exception.getMessage());
+ assertEquals("AI_10001", exception.getErrorCode());
+ assertNull(exception.getLoginFlowAIResponse());
+ }
+
+ @Test
+ public void testAIClientExceptionWithHttpResponseWrapperMessageAndErrorCode() {
+
+ AIHttpClientUtil.HttpResponseWrapper responseWrapper = new AIHttpClientUtil.HttpResponseWrapper(
+ 400, "Test response");
+ AIClientException exception = new AIClientException(responseWrapper, "Test message", "AI_10002");
+ assertEquals("Test message", exception.getMessage());
+ assertEquals("AI_10002", exception.getErrorCode());
+ assertEquals(responseWrapper, exception.getLoginFlowAIResponse());
+ }
+
+ @Test
+ public void testAIClientExceptionWithMessageErrorCodeAndCause() {
+ Throwable cause = new Throwable("Cause message");
+ AIClientException exception = new AIClientException("Test message", "AI_10003", cause);
+ assertEquals("Test message", exception.getMessage());
+ assertEquals("AI_10003", exception.getErrorCode());
+ assertEquals(cause, exception.getCause());
+ assertNull(exception.getLoginFlowAIResponse());
+ }
+}
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/exceptions/AIServerExceptionTest.java b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/exceptions/AIServerExceptionTest.java
new file mode 100644
index 000000000000..17a4c992b509
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/exceptions/AIServerExceptionTest.java
@@ -0,0 +1,71 @@
+/*
+ * 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.carbon.ai.service.mgt.exceptions;
+
+import org.testng.annotations.Test;
+import org.wso2.carbon.ai.service.mgt.util.AIHttpClientUtil;
+
+import static org.testng.AssertJUnit.assertEquals;
+import static org.testng.AssertJUnit.assertNull;
+
+/**
+ * Test class for AIServerException.
+ */
+public class AIServerExceptionTest {
+
+ @Test
+ public void testAIServerExceptionWithMessageAndErrorCode() {
+
+ AIServerException exception = new AIServerException("Test message", "AI_20001");
+ assertEquals("Test message", exception.getMessage());
+ assertEquals("AI_20001", exception.getErrorCode());
+ assertNull(exception.getBrandingAIResponse());
+ }
+
+ @Test
+ public void testAIServerExceptionWithHttpResponseWrapperMessageAndErrorCode() {
+
+ AIHttpClientUtil.HttpResponseWrapper responseWrapper = new AIHttpClientUtil.HttpResponseWrapper(
+ 500, "Test response");
+ AIServerException exception = new AIServerException(responseWrapper, "Test message", "AI_20002");
+ assertEquals("Test message", exception.getMessage());
+ assertEquals("AI_20002", exception.getErrorCode());
+ assertEquals(responseWrapper, exception.getBrandingAIResponse());
+ }
+
+ @Test
+ public void testAIServerExceptionWithMessageAndCause() {
+ Throwable cause = new Throwable("Cause message");
+ AIServerException exception = new AIServerException("Test message", cause);
+ assertEquals("Test message", exception.getMessage());
+ assertEquals(cause, exception.getCause());
+ assertNull(exception.getBrandingAIResponse());
+ }
+
+ @Test
+ public void testAIServerExceptionWithMessageErrorCodeAndCause() {
+
+ Throwable cause = new Throwable("Cause message");
+ AIServerException exception = new AIServerException("Test message", "AI_20003", cause);
+ assertEquals("Test message", exception.getMessage());
+ assertEquals("AI_20003", exception.getErrorCode());
+ assertEquals(cause, exception.getCause());
+ assertNull(exception.getBrandingAIResponse());
+ }
+}
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/token/AIAccessTokenManagerTest.java b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/token/AIAccessTokenManagerTest.java
new file mode 100644
index 000000000000..3f4fad6f7332
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/token/AIAccessTokenManagerTest.java
@@ -0,0 +1,276 @@
+/*
+ * 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.carbon.ai.service.mgt.token;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.StatusLine;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.concurrent.FutureCallback;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.wso2.carbon.ai.service.mgt.exceptions.AIServerException;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.Base64;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+/**
+ * Test class for AIAccessTokenManager.
+ */
+public class AIAccessTokenManagerTest {
+
+ @Mock
+ private CloseableHttpAsyncClient mockHttpClient;
+
+ @Mock
+ private Future mockFuture;
+
+ @Mock
+ private HttpResponse mockResponse;
+
+ @Mock
+ private StatusLine mockStatusLine;
+
+ private AIAccessTokenManager tokenManager;
+ private TestAccessTokenRequestHelper testHelper;
+ private AIAccessTokenManager.AccessTokenRequestHelper helper;
+
+ @BeforeMethod
+ public void setUp() throws NoSuchFieldException, IllegalAccessException {
+
+ MockitoAnnotations.openMocks(this);
+ testHelper = new TestAccessTokenRequestHelper(mockHttpClient);
+ String key = Base64.getEncoder().encodeToString("testClientId:testClientSecret".getBytes());
+ assignAIKey(key);
+ tokenManager = AIAccessTokenManager.getInstance();
+ tokenManager.setAccessTokenRequestHelper(testHelper);
+
+ helper = new AIAccessTokenManager.AccessTokenRequestHelper(key, "endpoint", mockHttpClient);
+ }
+
+ @AfterMethod
+ public void tearDown() {
+
+ // Reset other mocks and state.
+ tokenManager = null;
+ testHelper = null;
+ }
+
+ @Test
+ public void testGetInstance() {
+
+ AIAccessTokenManager instance1 = AIAccessTokenManager.getInstance();
+ AIAccessTokenManager instance2 = AIAccessTokenManager.getInstance();
+ Assert.assertSame(instance1, instance2, "getInstance should always return the same instance");
+ }
+
+ @Test
+ public void testGetAccessToken_Success() throws Exception {
+
+ String expectedToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjbGllbnRfaWQiOiJ0ZXN0Q2xpZW50SWQifQ.signature";
+ setupMockHttpResponse(HttpStatus.SC_OK, "{\"access_token\":\"" + expectedToken + "\"}");
+
+ String token = tokenManager.getAccessToken(true);
+ Assert.assertEquals(token, expectedToken);
+ Assert.assertEquals(tokenManager.getClientId(), "testClientId");
+ }
+
+ @Test
+ public void testGetAccessToken_Renewal() throws Exception {
+
+ setupMockHttpResponse(HttpStatus.SC_OK, "{\"access_token\":\"oldToken\"}");
+ String token1 = tokenManager.getAccessToken(false);
+
+ setupMockHttpResponse(HttpStatus.SC_OK, "{\"access_token\":\"newToken\"}");
+ String token2 = tokenManager.getAccessToken(true);
+
+ Assert.assertNotEquals(token1, token2, "Tokens should be different after renewal");
+ }
+
+ @Test(expectedExceptions = AIServerException.class)
+ public void testGetAccessToken_HttpError() throws Exception {
+
+ setupMockHttpResponse(HttpStatus.SC_INTERNAL_SERVER_ERROR, "Internal Server Error");
+ tokenManager.getAccessToken(false);
+ }
+
+ @Test(expectedExceptions = AIServerException.class)
+ public void testGetAccessToken_Timeout() throws Exception {
+
+ when(mockHttpClient.execute(any(HttpPost.class), any(FutureCallback.class))).thenReturn(mockFuture);
+ when(mockFuture.get()).thenThrow(new InterruptedException("Timeout"));
+ tokenManager.getAccessToken(true);
+ }
+
+ @Test(expectedExceptions = AIServerException.class)
+ public void testGetAccessToken_MaxRetriesExceeded() throws Exception {
+ setupMockHttpResponse(HttpStatus.SC_BAD_REQUEST, "Bad Request");
+ tokenManager.getAccessToken(false);
+ }
+
+ @Test(expectedExceptions = AIServerException.class)
+ public void testGetAccessToken_InterruptedDuringRequest() throws Exception {
+ when(mockHttpClient.execute(any(HttpPost.class), any(FutureCallback.class))).thenAnswer(invocation -> {
+ Thread.currentThread().interrupt();
+ throw new InterruptedException("Request interrupted");
+ });
+
+ try {
+ tokenManager.getAccessToken(false);
+ } finally {
+ Assert.assertTrue(Thread.interrupted(), "Thread interrupt flag should be cleared");
+ }
+ }
+
+ @Test
+ public void completed_InvalidJsonResponse() throws Exception {
+ setupMockHttpResponse(HttpStatus.SC_OK, "Invalid JSON");
+
+ try {
+ tokenManager.getAccessToken(true);
+ Assert.fail("Expected AIServerException to be thrown");
+ } catch (AIServerException e) {
+ Assert.assertTrue(e.getMessage().contains("Failed to obtain access token after 3 attempts."));
+ }
+ }
+
+ @Test
+ public void testFailedScenario() throws Exception {
+ ArgumentCaptor> captor = ArgumentCaptor.forClass(FutureCallback.class);
+ doNothing().when(mockHttpClient).start();
+ doAnswer(invocation -> {
+ FutureCallback callback = captor.getValue();
+ callback.failed(new Exception("Test Exception"));
+ return null;
+ }).when(mockHttpClient).execute(any(), captor.capture());
+
+ try {
+ helper.requestAccessToken();
+ } catch (AIServerException e) {
+ assertEquals("Failed to obtain access token after 3 attempts.", e.getMessage());
+ }
+
+ verify(mockHttpClient, times(1)).start();
+ verify(mockHttpClient, times(3)).execute(any(), any(FutureCallback.class));
+ }
+
+ @Test
+ public void testCancelledScenario() throws Exception {
+
+ ArgumentCaptor> captor = ArgumentCaptor.forClass(FutureCallback.class);
+ doNothing().when(mockHttpClient).start();
+ doAnswer(invocation -> {
+ FutureCallback callback = captor.getValue();
+ callback.cancelled();
+ return null;
+ }).when(mockHttpClient).execute(any(), captor.capture());
+
+ try {
+ helper.requestAccessToken();
+ } catch (AIServerException e) {
+ assertEquals("Failed to obtain access token after 3 attempts.", e.getMessage());
+ }
+
+ verify(mockHttpClient, times(1)).start();
+ verify(mockHttpClient, times(3)).execute(any(), any(FutureCallback.class));
+ }
+
+ @Test(expectedExceptions = AIServerException.class)
+ public void testRequestAccessToken_IOException() throws Exception {
+
+ CloseableHttpAsyncClient mockClient = mock(CloseableHttpAsyncClient.class);
+ doThrow(new IOException("Test IOException")).when(mockClient).close();
+
+ AIAccessTokenManager.AccessTokenRequestHelper helper =
+ new AIAccessTokenManager.AccessTokenRequestHelper("key", "endpoint", mockClient);
+
+ helper.requestAccessToken();
+ }
+
+ private void setupMockHttpResponse(int statusCode, String responseBody) throws Exception {
+
+ when(mockHttpClient.execute(any(HttpPost.class), any(FutureCallback.class))).thenAnswer(invocation -> {
+ FutureCallback callback = invocation.getArgument(1);
+ when(mockResponse.getStatusLine()).thenReturn(mockStatusLine);
+ when(mockStatusLine.getStatusCode()).thenReturn(statusCode);
+ when(mockResponse.getEntity()).thenReturn(new StringEntity(responseBody));
+ callback.completed(mockResponse);
+ return mockFuture;
+ });
+ when(mockFuture.get()).thenReturn(mockResponse);
+ }
+
+ // Custom AccessTokenRequestHelper for testing.
+ private class TestAccessTokenRequestHelper extends AIAccessTokenManager.AccessTokenRequestHelper {
+ public TestAccessTokenRequestHelper(CloseableHttpAsyncClient client) {
+ super("testKey", "https://test.endpoint", client);
+ }
+
+ @Override
+ public String requestAccessToken() throws AIServerException {
+ try {
+ return super.requestAccessToken();
+ } catch (AIServerException e) {
+ // Rethrow AIServerException directly for testing purposes.
+ throw e;
+ } catch (Exception e) {
+ throw new AIServerException("Test exception", e);
+ }
+ }
+ }
+
+ private static void assignAIKey(String key) throws NoSuchFieldException, IllegalAccessException {
+
+ // Target class and field.
+ Class> targetClass = AIAccessTokenManager.class;
+ Field aiKeyField = targetClass.getDeclaredField("AI_KEY");
+
+ // Make the field accessible.
+ aiKeyField.setAccessible(true);
+
+ // Remove the "final" modifier.
+ Field modifiersField = Field.class.getDeclaredField("modifiers");
+ modifiersField.setAccessible(true);
+ modifiersField.setInt(aiKeyField, aiKeyField.getModifiers() & ~Modifier.FINAL);
+
+ // Set the new value.
+ aiKeyField.set(null, key); // null because it's a static field.
+ }
+}
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/util/AIHttpClientUtilTest.java b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/util/AIHttpClientUtilTest.java
new file mode 100644
index 000000000000..f364e2a635a4
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/java/org/wso2/carbon/ai/service/mgt/util/AIHttpClientUtilTest.java
@@ -0,0 +1,494 @@
+/*
+ * 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.carbon.ai.service.mgt.util;
+
+import com.github.tomakehurst.wiremock.WireMockServer;
+import com.github.tomakehurst.wiremock.http.Fault;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import org.wso2.carbon.ai.service.mgt.exceptions.AIClientException;
+import org.wso2.carbon.ai.service.mgt.exceptions.AIServerException;
+import org.wso2.carbon.ai.service.mgt.token.AIAccessTokenManager;
+import org.wso2.carbon.base.CarbonBaseConstants;
+import org.wso2.carbon.context.PrivilegedCarbonContext;
+
+import java.nio.file.Paths;
+import java.util.HashMap;
+import java.util.Map;
+
+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.equalToJson;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+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;
+import static com.github.tomakehurst.wiremock.stubbing.Scenario.STARTED;
+import static org.mockito.Mockito.mockStatic;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import static org.mockito.MockitoAnnotations.openMocks;
+import static org.wso2.carbon.ai.service.mgt.constants.AIConstants.TENANT_CONTEXT_PREFIX;
+
+/**
+ * Test class for AIHttpClientUtil.
+ */
+public class AIHttpClientUtilTest {
+
+ private WireMockServer wireMockServer;
+ private final String clientId = "testClientId";
+
+ @Mock
+ private AIAccessTokenManager mockTokenManager;
+
+ private MockedStatic aiAccessTokenManagerMockedStatic;
+
+ @BeforeMethod
+ public void setUp() throws Exception {
+
+ openMocks(this);
+ setCarbonHome();
+ setCarbonContextForTenant();
+
+ aiAccessTokenManagerMockedStatic = mockStatic(AIAccessTokenManager.class);
+ when(AIAccessTokenManager.getInstance()).thenReturn(mockTokenManager);
+ when(mockTokenManager.getAccessToken(false)).thenReturn("testToken");
+ when(mockTokenManager.getClientId()).thenReturn(clientId);
+
+ // Start WireMock server on a random port.
+ wireMockServer = new WireMockServer(wireMockConfig().dynamicPort());
+ wireMockServer.start();
+
+ // Reset WireMock state for each test.
+ wireMockServer.resetAll();
+ }
+
+ @Test
+ public void testExecuteRequest_Success() throws Exception {
+
+ // Arrange: Mock a successful response.
+ String expectedResponse = "{\"result\":\"SUCCESS\"}";
+ String path = "/test-endpoint";
+ String fullPath = TENANT_CONTEXT_PREFIX + clientId + path; // This is the path that AIHttpClientUtil will use.
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader("Content-Type", "application/json")
+ .withBody(expectedResponse)));
+
+ // Act: Execute the HTTP request.
+ String baseUrl = wireMockServer.baseUrl();
+ Map resultMap = AIHttpClientUtil.executeRequest(
+ baseUrl,
+ path,
+ HttpGet.class,
+ null
+ );
+
+ // Assert: Verify the response.
+ Assert.assertEquals(resultMap.get("result"), "SUCCESS");
+ wireMockServer.verify(getRequestedFor(urlEqualTo(fullPath)));
+ }
+
+ @Test
+ public void testExecuteRequest_PostSuccess() throws Exception {
+
+ // Arrange: Mock a successful response.
+ String expectedResponse = "{\"result\":\"POST_SUCCESS\"}";
+ String path = "/test-endpoint";
+ String fullPath = TENANT_CONTEXT_PREFIX + clientId + path; // This is the path that AIHttpClientUtil will use.
+
+ // Define the request body.
+ String requestBody = "{\"key\":\"value\"}";
+
+ // Stub the POST request with the expected response.
+ wireMockServer.stubFor(post(urlEqualTo(fullPath))
+ .withHeader("Content-Type", equalTo("application/json"))
+ .withRequestBody(equalToJson(requestBody)) // Ensure the request body matches.
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader("Content-Type", "application/json")
+ .withBody(expectedResponse)));
+
+ // Act: Execute the HTTP request.
+ String baseUrl = wireMockServer.baseUrl();
+ Map requestBodyMap = new HashMap<>();
+ requestBodyMap.put("key", "value");
+ Map resultMap = AIHttpClientUtil.executeRequest(
+ baseUrl,
+ path,
+ HttpPost.class,
+ requestBodyMap // Pass the request body as a map.
+ );
+
+ // Assert: Verify the response.
+ Assert.assertEquals(resultMap.get("result"), "POST_SUCCESS");
+
+ // Verify that the POST request was made with the correct path and body.
+ wireMockServer.verify(postRequestedFor(urlEqualTo(fullPath))
+ .withHeader("Content-Type", equalTo("application/json"))
+ .withRequestBody(equalToJson(requestBody)));
+ }
+
+
+ @Test(expectedExceptions = AIClientException.class)
+ public void testExecuteRequest_ClientError() throws Exception {
+
+ // Arrange: Mock a client error response
+ String path = "/test-endpoint";
+ String fullPath = TENANT_CONTEXT_PREFIX + clientId + path; // This is the path that AIHttpClientUtil will use.
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .willReturn(aResponse()
+ .withStatus(400) // Client error status.
+ .withHeader("Content-Type", "application/json")
+ .withBody("Bad Request")));
+
+ // Act & Assert: Expect AIClientException.
+ String baseUrl = wireMockServer.baseUrl();
+ AIHttpClientUtil.executeRequest(
+ baseUrl,
+ path,
+ HttpGet.class,
+ null
+ );
+ }
+
+ @Test(expectedExceptions = AIServerException.class)
+ public void testExecuteRequest_ServerError() throws Exception {
+
+ // Arrange: Mock a server error response.
+ String path = "/test-endpoint";
+ String fullPath = TENANT_CONTEXT_PREFIX + clientId + path; // This is the path that AIHttpClientUtil will use.
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .willReturn(aResponse()
+ .withStatus(500) // Simulate a server error.
+ .withHeader("Content-Type", "text/plain")
+ .withBody("Internal Server Error")));
+
+ // Act & Assert: Execute the HTTP request and expect AIServerException.
+ String baseUrl = wireMockServer.baseUrl();
+ AIHttpClientUtil.executeRequest(
+ baseUrl,
+ path,
+ HttpGet.class,
+ null
+ );
+ }
+
+ @Test
+ public void testExecuteRequest_TokenRenewal() throws Exception {
+
+ // Mock the AccessTokenManager to simulate token renewal.
+ when(mockTokenManager.getAccessToken(true)).thenReturn("newToken");
+
+ // Arrange: Mock token renewal flow.
+ String expectedResponse = "{\"result\":\"SUCCESS\"}";
+ String path = "/test-endpoint";
+ String fullPath = TENANT_CONTEXT_PREFIX + clientId + path; // This is the path that AIHttpClientUtil will use.
+
+ // First response: 401 Unauthorized.
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .inScenario("Token Renewal")
+ .whenScenarioStateIs(STARTED)
+ .willReturn(aResponse()
+ .withStatus(401) // Unauthorized.
+ .withHeader("Content-Type", "application/json")
+ .withBody("Unauthorized"))
+ .willSetStateTo("Token Renewed")); // Transition to the next state.
+
+ // Second response: 200 OK.
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .inScenario("Token Renewal")
+ .whenScenarioStateIs("Token Renewed")
+ .willReturn(aResponse()
+ .withStatus(200) // Success
+ .withHeader("Content-Type", "application/json")
+ .withBody(expectedResponse)));
+
+ // Act: Execute the HTTP request.
+ String baseUrl = wireMockServer.baseUrl();
+ Map resultMap = AIHttpClientUtil.executeRequest(
+ baseUrl,
+ path,
+ HttpGet.class,
+ null
+ );
+
+ // Assert: Verify the response.
+ Assert.assertEquals(resultMap.get("result"), "SUCCESS");
+
+ // Verify the requests were made twice: once for 401 and once for 200.
+ wireMockServer.verify(2, getRequestedFor(urlEqualTo(fullPath)));
+
+ // Verify token renewal was called once.
+ verify(mockTokenManager, times(1)).getAccessToken(true);
+ }
+
+ @Test(expectedExceptions = AIClientException.class)
+ public void testExecuteRequest_TokenRenewal_ErrorAfterRenewal() throws Exception {
+ // Mock the AccessTokenManager to simulate token renewal.
+ when(mockTokenManager.getAccessToken(true)).thenReturn("newToken");
+
+ // Arrange: Define paths and mock token renewal flow.
+ String path = "/test-endpoint";
+ String fullPath = TENANT_CONTEXT_PREFIX + clientId + path; // This is the path that AIHttpClientUtil will use.
+
+ // First response: 401 Unauthorized.
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .inScenario("Token Renewal with Error")
+ .whenScenarioStateIs(STARTED)
+ .willReturn(aResponse()
+ .withStatus(401) // Unauthorized.
+ .withHeader("Content-Type", "application/json")
+ .withBody("Unauthorized"))
+ .willSetStateTo("Token Renewed")); // Transition to the next state.
+
+ // Second response: 400 Bad Request (or you can use 500 for Internal Server Error).
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .inScenario("Token Renewal with Error")
+ .whenScenarioStateIs("Token Renewed")
+ .willReturn(aResponse()
+ .withStatus(400) // Client-side error.
+ .withHeader("Content-Type", "application/json")
+ .withBody("{\"error\":\"Bad Request\"}"))); // Error response body.
+
+ // Act: Execute the HTTP request.
+ String baseUrl = wireMockServer.baseUrl();
+ AIHttpClientUtil.executeRequest(
+ baseUrl,
+ path,
+ HttpGet.class,
+ null
+ );
+ }
+
+ @Test(expectedExceptions = AIServerException.class)
+ public void testExecuteRequest_IOException() throws Exception {
+
+ // Arrange: Mock a server that simulates a connection reset.
+ String path = "/test-endpoint";
+ String fullPath = TENANT_CONTEXT_PREFIX + clientId + path; // This is the path that AIHttpClientUtil will use.
+
+ // Simulate a connection reset.
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .willReturn(aResponse()
+ .withFault(Fault.CONNECTION_RESET_BY_PEER))); // Simulates a connection reset.
+
+ // Act & Assert: Expect AIServerException due to simulated IOException (connection reset).
+ String baseUrl = wireMockServer.baseUrl();
+ AIHttpClientUtil.executeRequest(
+ baseUrl,
+ path,
+ HttpGet.class,
+ null
+ );
+ }
+
+ @Test(expectedExceptions = AIServerException.class)
+ public void testExecuteRequest_ExecutionException() throws Exception {
+
+ // Arrange: Mock a server that simulates an unexpected response.
+ String path = "/test-endpoint";
+ String fullPath = TENANT_CONTEXT_PREFIX + clientId + path; // This is the path that AIHttpClientUtil will use.
+
+ // Simulate an unexpected response that triggers an ExecutionException.
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .willReturn(aResponse()
+ .withFault(Fault.MALFORMED_RESPONSE_CHUNK))); // Simulates a malformed response
+
+ // Act & Assert: Expect AIServerException due to simulated ExecutionException.
+ String baseUrl = wireMockServer.baseUrl();
+ AIHttpClientUtil.executeRequest(
+ baseUrl,
+ path,
+ HttpGet.class,
+ null
+ );
+ }
+
+ @Test(expectedExceptions = AIServerException.class)
+ public void testExecuteRequest_InterruptedException() throws Exception {
+
+ // Arrange: Mock a server that responds but simulate thread interruption manually.
+ String path = "/test-endpoint";
+ String fullPath = TENANT_CONTEXT_PREFIX + clientId + path; // This is the path that AIHttpClientUtil will use.
+
+ // Simulate a valid server response to ensure interruption occurs in client code.
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .willReturn(aResponse()
+ .withStatus(200)
+ .withHeader("Content-Type", "application/json")
+ .withBody("{\"result\":\"SUCCESS\"}")));
+
+ // Simulate interruption in the thread executing the HTTP request.
+ Thread.currentThread().interrupt(); // Mark the thread as interrupted.
+
+ try {
+ // Act: Execute the HTTP request.
+ String baseUrl = wireMockServer.baseUrl();
+ AIHttpClientUtil.executeRequest(
+ baseUrl,
+ path,
+ HttpGet.class,
+ null
+ );
+ } finally {
+ // Assert: Verify that the thread is still marked as interrupted.
+ Assert.assertTrue(Thread.currentThread().isInterrupted(), "Thread should be marked as interrupted");
+ }
+ }
+
+ @Test(expectedExceptions = IllegalArgumentException.class)
+ public void testExecuteRequest_UnsupportedRequestType() throws Exception {
+
+ // Arrange: Define the path and base URL.
+ String path = "/test-endpoint";
+ String baseUrl = "https://ai-service.example.com";
+
+ // Act & Assert: Pass an unsupported request type and expect IllegalArgumentException.
+ AIHttpClientUtil.executeRequest(
+ baseUrl,
+ path,
+ HttpUriRequest.class, // Unsupported request type.
+ null
+ );
+ }
+
+ @Test(expectedExceptions = AIServerException.class)
+ public void testExecuteRequest_UnauthorizedAfterTokenRenewal() throws Exception {
+
+ // Mock the AccessTokenManager for token renewal.
+ when(mockTokenManager.getAccessToken(true)).thenReturn("newToken");
+
+ // Arrange: Define paths.
+ String path = "/test-endpoint";
+ String fullPath = TENANT_CONTEXT_PREFIX + clientId + path; // This is the path that AIHttpClientUtil will use.
+
+ // First response: 401 Unauthorized
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .inScenario("Token Renewal Fails")
+ .whenScenarioStateIs(STARTED)
+ .willReturn(aResponse()
+ .withStatus(401) // Unauthorized
+ .withHeader("Content-Type", "application/json")
+ .withBody("Unauthorized"))
+ .willSetStateTo("Retry"));
+
+ // Second response: 401 Unauthorized again
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .inScenario("Token Renewal Fails")
+ .whenScenarioStateIs("Retry")
+ .willReturn(aResponse()
+ .withStatus(401) // Still Unauthorized
+ .withHeader("Content-Type", "application/json")
+ .withBody("Still Unauthorized")));
+
+ // Act: Execute the HTTP request
+ String baseUrl = wireMockServer.baseUrl();
+ AIHttpClientUtil.executeRequest(
+ baseUrl,
+ path,
+ HttpGet.class,
+ null
+ );
+ }
+
+ @Test(expectedExceptions = AIServerException.class)
+ public void testExecuteRequest_JsonParsingError() throws Exception {
+
+ // Arrange: Define paths.
+ String path = "/test-endpoint";
+ String fullPath = TENANT_CONTEXT_PREFIX + clientId + path; // This is the path that AIHttpClientUtil will use.
+
+ // Mock the server to return invalid JSON.
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .willReturn(aResponse()
+ .withStatus(200) // Simulate a successful response.
+ .withHeader("Content-Type", "application/json")
+ .withBody("{ invalid json }"))); // Invalid JSON.
+
+ // Act: Execute the HTTP request, expecting AIServerException due to JSON parsing error.
+ String baseUrl = wireMockServer.baseUrl();
+ AIHttpClientUtil.executeRequest(
+ baseUrl,
+ path,
+ HttpGet.class,
+ null
+ );
+ }
+
+ @Test(expectedExceptions = AIServerException.class)
+ public void testExecuteRequest_FailedTokenRenewal() throws Exception {
+
+ // Mock the AccessTokenManager to simulate failed token renewal.
+ when(mockTokenManager.getAccessToken(false)).thenReturn("oldToken");
+ when(mockTokenManager.getAccessToken(true)).thenReturn(null); // Simulate failed token renewal.
+
+ // Arrange: Define paths.
+ String path = "/test-endpoint";
+ String fullPath = TENANT_CONTEXT_PREFIX + clientId + path; // This is the path that AIHttpClientUtil will use.
+
+ // Mock the server to return 401 Unauthorized.
+ wireMockServer.stubFor(get(urlEqualTo(fullPath))
+ .willReturn(aResponse()
+ .withStatus(401) // Unauthorized
+ .withHeader("Content-Type", "application/json")
+ .withBody("Unauthorized")));
+
+ // Act: Execute the HTTP request, expecting AIServerException due to failed token renewal.
+ String baseUrl = wireMockServer.baseUrl();
+ AIHttpClientUtil.executeRequest(
+ baseUrl,
+ path,
+ HttpGet.class,
+ null
+ );
+ }
+
+ private void setCarbonHome() {
+
+ String carbonHome = Paths.get(System.getProperty("user.dir"), "target", "test-classes").toString();
+ System.setProperty(CarbonBaseConstants.CARBON_HOME, carbonHome);
+ System.setProperty(CarbonBaseConstants.CARBON_CONFIG_DIR_PATH, Paths.get(carbonHome, "conf").toString());
+ }
+
+ private void setCarbonContextForTenant() {
+
+ PrivilegedCarbonContext.startTenantFlow();
+ PrivilegedCarbonContext.getThreadLocalCarbonContext().setTenantDomain(org.wso2.carbon.base.MultitenantConstants.SUPER_TENANT_DOMAIN_NAME);
+ }
+
+ @AfterMethod
+ public void tearDown() {
+
+ aiAccessTokenManagerMockedStatic.close();
+ PrivilegedCarbonContext.endTenantFlow();
+ wireMockServer.stop();
+ }
+}
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/conf/carbon.xml b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/conf/carbon.xml
new file mode 100755
index 000000000000..e2f7f02dc050
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/conf/carbon.xml
@@ -0,0 +1,686 @@
+
+
+
+
+
+
+
+ WSO2 Identity Server
+
+
+ IS
+
+
+ 5.3.0
+
+
+ localhost
+
+
+ localhost
+
+
+ local:/${carbon.context}/services/
+
+
+
+
+
+
+ IdentityServer
+
+
+
+
+
+
+ org.wso2.carbon
+
+
+ /
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+ 9999
+
+ 11111
+
+
+
+
+
+ 10389
+
+ 8000
+
+
+
+
+
+ 10500
+
+
+
+
+
+
+
+
+ org.wso2.carbon.tomcat.jndi.CarbonJavaURLContextFactory
+
+
+
+
+
+
+
+
+ java
+
+
+
+
+
+
+
+
+
+ false
+
+
+ false
+
+
+ 600
+
+
+
+ false
+
+
+
+
+
+
+
+ 30
+
+
+
+
+
+
+
+
+ 15
+
+
+
+
+
+ ${carbon.home}/repository/deployment/server/
+
+
+ 15
+
+
+ ${carbon.home}/repository/conf/axis2/axis2.xml
+
+
+ 30000
+
+
+ ${carbon.home}/repository/deployment/client/
+
+ ${carbon.home}/repository/conf/axis2/axis2_client.xml
+
+ true
+
+
+
+
+
+
+
+
+
+ admin
+ Default Administrator Role
+
+
+ user
+ Default User Role
+
+
+
+
+
+
+
+
+
+
+
+ ${carbon.home}/repository/resources/security/wso2carbon.jks
+
+ JKS
+
+ wso2carbon
+
+ wso2carbon
+
+ wso2carbon
+
+
+
+
+
+ ${carbon.home}/repository/resources/security/client-truststore.jks
+
+ JKS
+
+ wso2carbon
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ UserManager
+
+
+ false
+
+ org.wso2.carbon.identity.provider.AttributeCallbackHandler
+
+
+ org.wso2.carbon.identity.sts.store.DBTokenStore
+
+
+ true
+ allow
+
+
+
+
+
+
+claim_mgt_menu
+identity_mgt_emailtemplate_menu
+identity_security_questions_menu
+
+
+
+ ${carbon.home}/tmp/work
+
+
+
+
+
+ true
+
+
+ 10
+
+
+ 30
+
+
+
+
+
+ 100
+
+
+
+ keystore
+ certificate
+ *
+
+ org.wso2.carbon.ui.transports.fileupload.AnyFileUploadExecutor
+
+
+
+
+ jarZip
+
+ org.wso2.carbon.ui.transports.fileupload.JarZipUploadExecutor
+
+
+
+ dbs
+
+ org.wso2.carbon.ui.transports.fileupload.DBSFileUploadExecutor
+
+
+
+ tools
+
+ org.wso2.carbon.ui.transports.fileupload.ToolsFileUploadExecutor
+
+
+
+ toolsAny
+
+ org.wso2.carbon.ui.transports.fileupload.ToolsAnyFileUploadExecutor
+
+
+
+
+
+
+
+
+
+ - info
+ org.wso2.carbon.core.transports.util.InfoProcessor
+
+
+ - wsdl
+ org.wso2.carbon.core.transports.util.Wsdl11Processor
+
+
+ - wsdl2
+ org.wso2.carbon.core.transports.util.Wsdl20Processor
+
+
+ - xsd
+ org.wso2.carbon.core.transports.util.XsdProcessor
+
+
+
+
+
+ false
+ false
+ true
+ svn
+ http://svnrepo.example.com/repos/
+ username
+ password
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${require.carbon.servlet}
+
+
+
+
+ true
+
+
+
+
+
+
+ default repository
+ http://product-dist.wso2.com/p2/carbon/releases/wilkes/
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+ true
+
+
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/conf/identity/identity.xml b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/conf/identity/identity.xml
new file mode 100644
index 000000000000..1bf7cb28de20
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/conf/identity/identity.xml
@@ -0,0 +1,994 @@
+
+
+
+
+
+
+
+
+ jdbc/WSO2IdentityDB
+
+
+
+
+ true
+ true
+ 0
+
+ true
+ 20160
+ 1140
+
+
+ 50000
+
+
+ true
+
+
+
+ true
+
+ 20
+
+ 40
+
+
+
+
+
+
+ 15
+ 20160
+
+
+
+
+
+ ${carbon.home}/conf/keystores
+ SunX509
+ SunX509
+
+
+
+ localhost
+
+
+ SelfAndManaged
+ CertValidate
+
+
+
+
+
+
+
+
+
+
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/openidserver
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/openid
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/authenticationendpoint/openid_login.do
+
+ false
+
+ 7200
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth/request-token
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth/authorize-url
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth/access-token
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth2/authorize
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth2/token
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth2/revoke
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth2/introspect
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth2/userinfo
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/oidc/checksession
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/oidc/logout
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/authenticationendpoint/oauth2_authz.do
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/authenticationendpoint/oauth2_error.do
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/authenticationendpoint/oauth2_consent.do
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/authenticationendpoint/oauth2_logout_consent.do
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/authenticationendpoint/oauth2_logout.do
+
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/.well-known/webfinger
+
+
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/api/identity/oauth2/dcr/v1.1/register
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth2/jwks
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth2/oidcdiscovery
+
+
+ 300
+
+ 3600
+
+ 3600
+
+ 84600
+
+ 0
+
+ true
+
+ org.wso2.carbon.identity.oauth.tokenprocessor.PlainTextPersistenceProcessor
+
+ false
+
+ false
+
+
+
+ token
+ org.wso2.carbon.identity.oauth2.authz.handlers.AccessTokenResponseTypeHandler
+
+
+ code
+ org.wso2.carbon.identity.oauth2.authz.handlers.CodeResponseTypeHandler
+
+
+ id_token
+ org.wso2.carbon.identity.oauth2.authz.handlers.IDTokenResponseTypeHandler
+
+
+ id_token token
+ org.wso2.carbon.identity.oauth2.authz.handlers.IDTokenTokenResponseTypeHandler
+
+
+
+
+
+ authorization_code
+ org.wso2.carbon.identity.oauth2.token.handlers.grant.AuthorizationCodeGrantHandler
+
+
+ password
+ org.wso2.carbon.identity.oauth2.token.handlers.grant.PasswordGrantHandler
+
+
+ refresh_token
+ org.wso2.carbon.identity.oauth2.token.handlers.grant.RefreshGrantHandler
+
+
+ client_credentials
+ org.wso2.carbon.identity.oauth2.token.handlers.grant.ClientCredentialsGrantHandler
+ false
+ false
+
+
+ urn:ietf:params:oauth:grant-type:saml2-bearer
+ org.wso2.carbon.identity.oauth2.token.handlers.grant.saml.SAML2BearerGrantHandler
+
+
+ iwa:ntlm
+ org.wso2.carbon.identity.oauth2.token.handlers.grant.iwa.ntlm.NTLMAuthenticationGrantHandler
+
+
+ urn:ietf:params:oauth:grant-type:jwt-bearer
+ org.wso2.carbon.identity.oauth2.grant.jwt.JWTBearerGrantHandler
+ org.wso2.carbon.identity.oauth2.grant.jwt.JWTGrantValidator
+
+
+
+
+
+
+ authorization_code
+
+
+ implicit
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+
+
+
+
+
+
+ false
+
+
+
+ false
+ org.wso2.carbon.identity.oauth2.authcontext.JWTTokenGenerator
+ org.wso2.carbon.identity.oauth2.authcontext.DefaultClaimsRetriever
+ http://wso2.org/claims
+ SHA256withRSA
+ 15
+
+
+
+
+
+
+ FEDERATED
+
+
+
+
+ org.wso2.carbon.identity.openidconnect.DefaultIDTokenBuilder
+ SHA256withRSA
+
+
+ RSA-OAEP
+
+ A128GCM
+
+
+
+ RSA1_5
+ RSA-OAEP
+
+
+ A128GCM
+ A192GCM
+ A256GCM
+ A128CBC-HS256
+ A128CBC+HS256
+
+
+ true
+
+
+
+
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/oauth2/token
+ org.wso2.carbon.identity.openidconnect.SAMLAssertionClaimsCallback
+ 3600
+ SHA256withRSA
+ org.wso2.carbon.identity.oauth.endpoint.user.impl.UserInfoUserStoreClaimRetriever
+ org.wso2.carbon.identity.oauth.endpoint.user.impl.UserInforRequestDefaultValidator
+ org.wso2.carbon.identity.oauth.endpoint.user.impl.UserInfoISAccessTokenValidator
+ org.wso2.carbon.identity.oauth.endpoint.user.impl.UserInfoJSONResponseBuilder
+ false
+
+ false
+
+ 120
+
+
+
+
+ request_param_value_builder
+ org.wso2.carbon.identity.openidconnect.RequestParamRequestObjectBuilder
+
+
+
+
+ org.wso2.carbon.identity.openidconnect.RequestObjectValidatorImpl
+
+
+
+
+ true
+ 0
+ 5
+
+
+
+
+
+
+
+ gtalk
+ talk.google.com
+ 5222
+ gmail.com
+ multifactor1@gmail.com
+ wso2carbon
+
+
+
+
+
+ ${carbon.host}
+
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/samlsso
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/authenticationendpoint/samlsso_logout.do
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/authenticationendpoint/samlsso_notification.do
+ 5
+ 60000
+
+ false
+ http://wso2.org/claims
+
+ org.wso2.carbon.identity.sso.saml.builders.assertion.DefaultSAMLAssertionBuilder
+ org.wso2.carbon.identity.sso.saml.builders.encryption.DefaultSSOEncrypter
+ org.wso2.carbon.identity.sso.saml.builders.signature.DefaultSSOSigner
+ org.wso2.carbon.identity.sso.saml.validators.SAML2HTTPRedirectDeflateSignatureValidator
+
+
+
+ 5
+ false
+ http://www.w3.org/2000/09/xmldsig#rsa-sha1
+ http://www.w3.org/2000/09/xmldsig#sha1
+ http://www.w3.org/2001/04/xmlenc#aes256-cbc
+ http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p
+ true
+
+
+
+
+ true
+
+
+
+
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/services/wso2carbon-sts
+
+
+
+
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/passivests
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/authenticationendpoint/retry.do
+ org.wso2.carbon.identity.sts.passive.utils.NoPersistenceTokenStore
+ true
+
+
+
+
+ false
+ ${Ports.ThriftEntitlementReceivePort}
+ 10000
+
+ ${carbon.home}/repository/resources/security/wso2carbon.jks
+ wso2carbon
+
+
+ ${carbon.host}
+
+
+
+
+
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/wso2/scim/Users
+ ${carbon.protocol}://${carbon.host}:${carbon.management.port}/wso2/scim/Groups
+
+
+ 5
+
+
+ 10
+ local://services
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+
+ true
+ true
+
+
+ true
+
+
+
+
+
+
+
+
+
+ org.wso2.carbon.identity.governance.store.JDBCIdentityDataStore
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /permission/admin/manage/identity/identitymgt
+
+
+
+
+
+ /permission/admin/manage/identity/usermgt/view
+
+
+ /permission/admin/manage/identity/usermgt/view
+
+
+
+ /permission/admin/manage/identity/configmgt/list
+
+
+
+ /permission/admin/manage/identity/configmgt/add
+
+
+ /permission/admin/manage/identity/configmgt/update
+
+
+
+ /permission/admin/manage/identity/configmgt/delete
+
+
+
+ /permission/admin/manage/identity/configmgt/add
+
+
+ /permission/admin/manage/identity/configmgt/update
+
+
+
+ /permission/admin/manage/identity/configmgt/delete
+
+
+
+ /permission/admin/manage/identity/configmgt/add
+
+
+ /permission/admin/manage/identity/configmgt/update
+
+
+
+ /permission/admin/manage/identity/configmgt/delete
+
+
+
+
+
+
+ /permission/admin/manage/identity/consentmgt/add
+
+
+
+ /permission/admin/manage/identity/consentmgt/delete
+
+
+
+ /permission/admin/manage/identity/consentmgt/add
+
+
+
+ /permission/admin/manage/identity/consentmgt/delete
+
+
+
+ /permission/admin/manage/identity/consentmgt/add
+
+
+
+ /permission/admin/manage/identity/consentmgt/delete
+
+
+
+ /permission/admin/manage/identity/identitymgt
+
+
+
+ /permission/admin/manage/identity/applicationmgt/create
+
+
+ /permission/admin/manage/identity/applicationmgt/delete
+
+
+ /permission/admin/manage/identity/applicationmgt/update
+
+
+ /permission/admin/manage/identity/applicationmgt/view
+
+
+ /permission/admin/manage/identity/applicationmgt/delete
+
+
+ /permission/admin/manage/identity/applicationmgt/create
+
+
+ /permission/admin/manage/identity/applicationmgt/view
+
+
+ /permission/admin/manage/identity/pep
+
+
+ /permission/admin/manage/identity/usermgt/create
+
+
+ /permission/admin/manage/identity/usermgt/list
+
+
+ /permission/admin/manage/identity/rolemgt/create
+
+
+ /permission/admin/manage/identity/rolemgt/view
+
+
+ /permission/admin/manage/identity/usermgt/view
+
+
+ /permission/admin/manage/identity/usermgt/update
+
+
+ /permission/admin/manage/identity/usermgt/update
+
+
+ /permission/admin/manage/identity/usermgt/delete
+
+
+ /permission/admin/manage/identity/rolemgt/view
+
+
+ /permission/admin/manage/identity/rolemgt/update
+
+
+ /permission/admin/manage/identity/rolemgt/update
+
+
+ /permission/admin/manage/identity/rolemgt/delete
+
+
+ /permission/admin/login
+
+
+ /permission/admin/manage/identity/usermgt/delete
+
+
+ /permission/admin/login
+
+
+ /permission/admin/login
+
+
+ /permission/admin/manage/identity/usermgt/create
+
+
+
+
+
+
+
+
+ /permission/admin/manage/identity/usermgt
+
+
+ /permission/admin/manage/identity/applicationmgt
+
+
+
+
+
+
+ /permission/admin/manage/identity/usermgt/update
+
+
+
+
+
+ /permission/admin/manage/humantask/viewtasks
+
+
+ /permission/admin/login
+
+
+ /permission/admin/manage/identity/usermgt
+
+
+ /permission/admin/manage/identity/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /api/identity/user/v1.0/
+ /api/identity/consent-mgt/v1.0/
+ /api/identity/recovery/v0.9/
+ /oauth2/
+ /scim2/
+ /api/identity/entitlement/
+ /api/identity/oauth2/dcr/v1.1/
+
+
+ /identity/(.*)
+
+
+
+
+ 300
+
+
+
+ true
+
+ 1000
+ 1000
+ 51200
+
+
+
+
+
+ http://localhost:8280/
+
+ 5
+
+
+
+
+
+
+
+
+
+
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/dbscripts/identity.sql b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/dbscripts/identity.sql
new file mode 100644
index 000000000000..ff1e7a44b2d4
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/dbscripts/identity.sql
@@ -0,0 +1,1241 @@
+CREATE TABLE IF NOT EXISTS IDN_BASE_TABLE (
+ PRODUCT_NAME VARCHAR (20),
+ PRIMARY KEY (PRODUCT_NAME)
+);
+
+INSERT INTO IDN_BASE_TABLE values ('WSO2 Identity Server');
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH_CONSUMER_APPS (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ CONSUMER_KEY VARCHAR (255),
+ CONSUMER_SECRET VARCHAR (2048),
+ USERNAME VARCHAR (255),
+ TENANT_ID INTEGER DEFAULT 0,
+ USER_DOMAIN VARCHAR(50),
+ APP_NAME VARCHAR (255),
+ OAUTH_VERSION VARCHAR (128),
+ CALLBACK_URL VARCHAR (2048),
+ GRANT_TYPES VARCHAR (1024),
+ PKCE_MANDATORY CHAR(1) DEFAULT '0',
+ PKCE_SUPPORT_PLAIN CHAR(1) DEFAULT '0',
+ APP_STATE VARCHAR (25) DEFAULT 'ACTIVE',
+ USER_ACCESS_TOKEN_EXPIRE_TIME BIGINT DEFAULT 3600,
+ APP_ACCESS_TOKEN_EXPIRE_TIME BIGINT DEFAULT 3600,
+ REFRESH_TOKEN_EXPIRE_TIME BIGINT DEFAULT 84600,
+ ID_TOKEN_EXPIRE_TIME BIGINT DEFAULT 3600,
+ CONSTRAINT CONSUMER_KEY_CONSTRAINT UNIQUE (TENANT_ID, CONSUMER_KEY),
+ PRIMARY KEY (ID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_SCOPE_VALIDATORS (
+ APP_ID INTEGER NOT NULL,
+ SCOPE_VALIDATOR VARCHAR (128) NOT NULL,
+ PRIMARY KEY (APP_ID,SCOPE_VALIDATOR),
+ FOREIGN KEY (APP_ID) REFERENCES IDN_OAUTH_CONSUMER_APPS(ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH1A_REQUEST_TOKEN (
+ REQUEST_TOKEN VARCHAR (512),
+ REQUEST_TOKEN_SECRET VARCHAR (512),
+ CONSUMER_KEY_ID INTEGER,
+ CALLBACK_URL VARCHAR (2048),
+ SCOPE VARCHAR(2048),
+ AUTHORIZED VARCHAR (128),
+ OAUTH_VERIFIER VARCHAR (512),
+ AUTHZ_USER VARCHAR (512),
+ TENANT_ID INTEGER DEFAULT -1,
+ PRIMARY KEY (REQUEST_TOKEN),
+ FOREIGN KEY (CONSUMER_KEY_ID) REFERENCES IDN_OAUTH_CONSUMER_APPS(ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH1A_ACCESS_TOKEN (
+ ACCESS_TOKEN VARCHAR (512),
+ ACCESS_TOKEN_SECRET VARCHAR (512),
+ CONSUMER_KEY_ID INTEGER,
+ SCOPE VARCHAR(2048),
+ AUTHZ_USER VARCHAR (512),
+ TENANT_ID INTEGER DEFAULT -1,
+ PRIMARY KEY (ACCESS_TOKEN),
+ FOREIGN KEY (CONSUMER_KEY_ID) REFERENCES IDN_OAUTH_CONSUMER_APPS(ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_ACCESS_TOKEN (
+ TOKEN_ID VARCHAR (255),
+ ACCESS_TOKEN VARCHAR (2048),
+ REFRESH_TOKEN VARCHAR (2048),
+ CONSUMER_KEY_ID INTEGER,
+ AUTHZ_USER VARCHAR (100),
+ TENANT_ID INTEGER,
+ USER_DOMAIN VARCHAR(50),
+ USER_TYPE VARCHAR (25),
+ GRANT_TYPE VARCHAR (50),
+ TIME_CREATED TIMESTAMP DEFAULT 0,
+ REFRESH_TOKEN_TIME_CREATED TIMESTAMP DEFAULT 0,
+ VALIDITY_PERIOD BIGINT,
+ REFRESH_TOKEN_VALIDITY_PERIOD BIGINT,
+ TOKEN_SCOPE_HASH VARCHAR (32),
+ TOKEN_STATE VARCHAR (25) DEFAULT 'ACTIVE',
+ TOKEN_STATE_ID VARCHAR (128) DEFAULT 'NONE',
+ SUBJECT_IDENTIFIER VARCHAR(255),
+ ACCESS_TOKEN_HASH VARCHAR (512),
+ REFRESH_TOKEN_HASH VARCHAR (512),
+ IDP_ID INTEGER DEFAULT -1 NOT NULL,
+ TOKEN_BINDING_REF VARCHAR (32) DEFAULT 'NONE',
+ PRIMARY KEY (TOKEN_ID),
+ FOREIGN KEY (CONSUMER_KEY_ID) REFERENCES IDN_OAUTH_CONSUMER_APPS(ID) ON DELETE CASCADE,
+ CONSTRAINT CON_APP_KEY UNIQUE (CONSUMER_KEY_ID,AUTHZ_USER,TENANT_ID,USER_DOMAIN,USER_TYPE,TOKEN_SCOPE_HASH,
+ TOKEN_STATE,TOKEN_STATE_ID,IDP_ID,TOKEN_BINDING_REF)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_TOKEN_BINDING (
+ TOKEN_ID VARCHAR (255),
+ TOKEN_BINDING_TYPE VARCHAR (32),
+ TOKEN_BINDING_REF VARCHAR (32),
+ TOKEN_BINDING_VALUE VARCHAR (1024),
+ TENANT_ID INTEGER DEFAULT -1,
+ PRIMARY KEY (TOKEN_ID),
+ FOREIGN KEY (TOKEN_ID) REFERENCES IDN_OAUTH2_ACCESS_TOKEN(TOKEN_ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_ACCESS_TOKEN_AUDIT (
+ TOKEN_ID VARCHAR (255),
+ ACCESS_TOKEN VARCHAR(2048),
+ REFRESH_TOKEN VARCHAR(2048),
+ CONSUMER_KEY_ID INTEGER,
+ AUTHZ_USER VARCHAR (100),
+ TENANT_ID INTEGER,
+ USER_DOMAIN VARCHAR(50),
+ USER_TYPE VARCHAR (25),
+ GRANT_TYPE VARCHAR (50),
+ TIME_CREATED TIMESTAMP NULL,
+ REFRESH_TOKEN_TIME_CREATED TIMESTAMP NULL,
+ VALIDITY_PERIOD BIGINT,
+ REFRESH_TOKEN_VALIDITY_PERIOD BIGINT,
+ TOKEN_SCOPE_HASH VARCHAR(32),
+ TOKEN_STATE VARCHAR(25),
+ TOKEN_STATE_ID VARCHAR (128) ,
+ SUBJECT_IDENTIFIER VARCHAR(255),
+ ACCESS_TOKEN_HASH VARCHAR(512),
+ REFRESH_TOKEN_HASH VARCHAR(512),
+ INVALIDATED_TIME TIMESTAMP NULL,
+ IDP_ID INTEGER DEFAULT -1 NOT NULL
+);
+
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_AUTHORIZATION_CODE (
+ CODE_ID VARCHAR (255),
+ AUTHORIZATION_CODE VARCHAR (2048),
+ CONSUMER_KEY_ID INTEGER,
+ CALLBACK_URL VARCHAR (2048),
+ SCOPE VARCHAR(2048),
+ AUTHZ_USER VARCHAR (100),
+ TENANT_ID INTEGER,
+ USER_DOMAIN VARCHAR(50),
+ TIME_CREATED TIMESTAMP,
+ VALIDITY_PERIOD BIGINT,
+ STATE VARCHAR (25) DEFAULT 'ACTIVE',
+ TOKEN_ID VARCHAR(255),
+ SUBJECT_IDENTIFIER VARCHAR(255),
+ PKCE_CODE_CHALLENGE VARCHAR (255),
+ PKCE_CODE_CHALLENGE_METHOD VARCHAR(128),
+ AUTHORIZATION_CODE_HASH VARCHAR (512),
+ IDP_ID INTEGER DEFAULT -1 NOT NULL,
+ PRIMARY KEY (CODE_ID),
+ FOREIGN KEY (CONSUMER_KEY_ID) REFERENCES IDN_OAUTH_CONSUMER_APPS(ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_AUTHZ_CODE_SCOPE(
+ CODE_ID VARCHAR(255),
+ SCOPE VARCHAR(60),
+ TENANT_ID INTEGER DEFAULT -1,
+ PRIMARY KEY (CODE_ID, SCOPE),
+ FOREIGN KEY (CODE_ID) REFERENCES IDN_OAUTH2_AUTHORIZATION_CODE (CODE_ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_DEVICE_FLOW (
+ CODE_ID VARCHAR(255),
+ DEVICE_CODE VARCHAR(255),
+ USER_CODE VARCHAR(25),
+ CONSUMER_KEY_ID INTEGER,
+ LAST_POLL_TIME TIMESTAMP NOT NULL,
+ EXPIRY_TIME TIMESTAMP NOT NULL,
+ TIME_CREATED TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ POLL_TIME BIGINT,
+ STATUS VARCHAR (25) DEFAULT 'PENDING',
+ AUTHZ_USER VARCHAR (100),
+ TENANT_ID INTEGER,
+ USER_DOMAIN VARCHAR(50),
+ IDP_ID INTEGER,
+ SUBJECT_IDENTIFIER VARCHAR(255),
+ PRIMARY KEY (DEVICE_CODE),
+ UNIQUE (CODE_ID),
+ UNIQUE (USER_CODE),
+ FOREIGN KEY (CONSUMER_KEY_ID) REFERENCES IDN_OAUTH_CONSUMER_APPS(ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_DEVICE_FLOW_SCOPES (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ SCOPE_ID VARCHAR(255),
+ SCOPE VARCHAR(255),
+ PRIMARY KEY (ID),
+ FOREIGN KEY (SCOPE_ID) REFERENCES IDN_OAUTH2_DEVICE_FLOW(CODE_ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_ACCESS_TOKEN_SCOPE (
+ TOKEN_ID VARCHAR (255),
+ TOKEN_SCOPE VARCHAR (60),
+ TENANT_ID INTEGER DEFAULT -1,
+ PRIMARY KEY (TOKEN_ID, TOKEN_SCOPE),
+ FOREIGN KEY (TOKEN_ID) REFERENCES IDN_OAUTH2_ACCESS_TOKEN(TOKEN_ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_SCOPE (
+ SCOPE_ID INTEGER NOT NULL AUTO_INCREMENT,
+ NAME VARCHAR(255) NOT NULL,
+ DISPLAY_NAME VARCHAR(255) NOT NULL,
+ DESCRIPTION VARCHAR(512),
+ TENANT_ID INTEGER NOT NULL DEFAULT -1,
+ SCOPE_TYPE VARCHAR(255) NOT NULL,
+ PRIMARY KEY (SCOPE_ID),
+ UNIQUE (NAME, TENANT_ID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_SCOPE_BINDING (
+ SCOPE_ID INTEGER NOT NULL,
+ SCOPE_BINDING VARCHAR(255) NOT NULL,
+ BINDING_TYPE VARCHAR(255) NOT NULL,
+ FOREIGN KEY (SCOPE_ID) REFERENCES IDN_OAUTH2_SCOPE(SCOPE_ID) ON DELETE CASCADE,
+ UNIQUE (SCOPE_ID, SCOPE_BINDING, BINDING_TYPE)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_RESOURCE_SCOPE (
+ RESOURCE_PATH VARCHAR(255) NOT NULL,
+ SCOPE_ID INTEGER NOT NULL,
+ TENANT_ID INTEGER DEFAULT -1,
+ PRIMARY KEY (RESOURCE_PATH),
+ FOREIGN KEY (SCOPE_ID) REFERENCES IDN_OAUTH2_SCOPE (SCOPE_ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_SCIM_GROUP (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ TENANT_ID INTEGER NOT NULL,
+ ROLE_NAME VARCHAR(255) NOT NULL,
+ ATTR_NAME VARCHAR(1024) NOT NULL,
+ ATTR_VALUE VARCHAR(1024),
+ PRIMARY KEY (ID)
+);
+
+
+
+CREATE TABLE IF NOT EXISTS IDN_OPENID_REMEMBER_ME (
+ USER_NAME VARCHAR(255) NOT NULL,
+ TENANT_ID INTEGER DEFAULT 0,
+ COOKIE_VALUE VARCHAR(1024),
+ CREATED_TIME TIMESTAMP,
+ PRIMARY KEY (USER_NAME, TENANT_ID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OPENID_USER_RPS (
+ USER_NAME VARCHAR(255) NOT NULL,
+ TENANT_ID INTEGER DEFAULT 0,
+ RP_URL VARCHAR(255) NOT NULL,
+ TRUSTED_ALWAYS VARCHAR(128) DEFAULT 'FALSE',
+ LAST_VISIT DATE NOT NULL,
+ VISIT_COUNT INTEGER DEFAULT 0,
+ DEFAULT_PROFILE_NAME VARCHAR(255) DEFAULT 'DEFAULT',
+ PRIMARY KEY (USER_NAME, TENANT_ID, RP_URL)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OPENID_ASSOCIATIONS (
+ HANDLE VARCHAR(255) NOT NULL,
+ ASSOC_TYPE VARCHAR(255) NOT NULL,
+ EXPIRE_IN TIMESTAMP NOT NULL,
+ MAC_KEY VARCHAR(255) NOT NULL,
+ ASSOC_STORE VARCHAR(128) DEFAULT 'SHARED',
+ TENANT_ID INTEGER DEFAULT -1,
+ PRIMARY KEY (HANDLE)
+);
+
+CREATE TABLE IDN_STS_STORE (
+ ID INTEGER AUTO_INCREMENT,
+ TOKEN_ID VARCHAR(255) NOT NULL,
+ TOKEN_CONTENT BLOB(1024) NOT NULL,
+ CREATE_DATE TIMESTAMP NOT NULL,
+ EXPIRE_DATE TIMESTAMP NOT NULL,
+ STATE INTEGER DEFAULT 0,
+ PRIMARY KEY (ID)
+);
+
+CREATE TABLE IDN_IDENTITY_USER_DATA (
+ TENANT_ID INTEGER DEFAULT -1234,
+ USER_NAME VARCHAR(255) NOT NULL,
+ DATA_KEY VARCHAR(255) NOT NULL,
+ DATA_VALUE VARCHAR(2048),
+ PRIMARY KEY (TENANT_ID, USER_NAME, DATA_KEY)
+);
+
+CREATE TABLE IDN_IDENTITY_META_DATA (
+ USER_NAME VARCHAR(255) NOT NULL,
+ TENANT_ID INTEGER DEFAULT -1234,
+ METADATA_TYPE VARCHAR(255) NOT NULL,
+ METADATA VARCHAR(255) NOT NULL,
+ VALID VARCHAR(255) NOT NULL,
+ PRIMARY KEY (TENANT_ID, USER_NAME, METADATA_TYPE,METADATA)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_THRIFT_SESSION (
+ SESSION_ID VARCHAR(255) NOT NULL,
+ USER_NAME VARCHAR(255) NOT NULL,
+ CREATED_TIME VARCHAR(255) NOT NULL,
+ LAST_MODIFIED_TIME VARCHAR(255) NOT NULL,
+ TENANT_ID INTEGER DEFAULT -1,
+ PRIMARY KEY (SESSION_ID)
+);
+
+CREATE TABLE IDN_AUTH_SESSION_STORE (
+ SESSION_ID VARCHAR (100) NOT NULL,
+ SESSION_TYPE VARCHAR(100) NOT NULL,
+ OPERATION VARCHAR(10) NOT NULL,
+ SESSION_OBJECT BLOB,
+ TIME_CREATED BIGINT,
+ TENANT_ID INTEGER DEFAULT -1,
+ EXPIRY_TIME BIGINT,
+ PRIMARY KEY (SESSION_ID, SESSION_TYPE, TIME_CREATED, OPERATION)
+);
+
+
+CREATE TABLE IDN_AUTH_TEMP_SESSION_STORE (
+ SESSION_ID VARCHAR (100) NOT NULL,
+ SESSION_TYPE VARCHAR(100) NOT NULL,
+ OPERATION VARCHAR(10) NOT NULL,
+ SESSION_OBJECT BLOB,
+ TIME_CREATED BIGINT,
+ TENANT_ID INTEGER DEFAULT -1,
+ EXPIRY_TIME BIGINT,
+ PRIMARY KEY (SESSION_ID, SESSION_TYPE, TIME_CREATED, OPERATION)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_AUTH_USER (
+ USER_ID VARCHAR(255) NOT NULL,
+ USER_NAME VARCHAR(255) NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ DOMAIN_NAME VARCHAR(255) NOT NULL,
+ IDP_ID INTEGER NOT NULL,
+ PRIMARY KEY (USER_ID),
+ CONSTRAINT USER_STORE_CONSTRAINT UNIQUE (USER_NAME, TENANT_ID, DOMAIN_NAME, IDP_ID));
+
+CREATE TABLE IF NOT EXISTS IDN_AUTH_USER_SESSION_MAPPING (
+ USER_ID VARCHAR(255) NOT NULL,
+ SESSION_ID VARCHAR(255) NOT NULL,
+ CONSTRAINT USER_SESSION_STORE_CONSTRAINT UNIQUE (USER_ID, SESSION_ID));
+
+CREATE TABLE IF NOT EXISTS IDN_AUTH_SESSION_APP_INFO (
+ SESSION_ID VARCHAR (100) NOT NULL,
+ SUBJECT VARCHAR (100) NOT NULL,
+ APP_ID INTEGER NOT NULL,
+ INBOUND_AUTH_TYPE VARCHAR (255) NOT NULL,
+ PRIMARY KEY (SESSION_ID, SUBJECT, APP_ID, INBOUND_AUTH_TYPE));
+
+CREATE TABLE IF NOT EXISTS IDN_AUTH_SESSION_META_DATA (
+ SESSION_ID VARCHAR (100) NOT NULL,
+ PROPERTY_TYPE VARCHAR (100) NOT NULL,
+ `VALUE` VARCHAR (255) NOT NULL,
+ PRIMARY KEY (SESSION_ID, PROPERTY_TYPE, `VALUE`)
+ );
+
+CREATE TABLE IF NOT EXISTS SP_APP (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ TENANT_ID INTEGER NOT NULL,
+ APP_NAME VARCHAR (255) NOT NULL ,
+ USER_STORE VARCHAR (255) NOT NULL,
+ USERNAME VARCHAR (255) NOT NULL ,
+ DESCRIPTION VARCHAR (1024),
+ ROLE_CLAIM VARCHAR (512),
+ AUTH_TYPE VARCHAR (255) NOT NULL,
+ PROVISIONING_USERSTORE_DOMAIN VARCHAR (512),
+ IS_LOCAL_CLAIM_DIALECT CHAR(1) DEFAULT '1',
+ IS_SEND_LOCAL_SUBJECT_ID CHAR(1) DEFAULT '0',
+ IS_SEND_AUTH_LIST_OF_IDPS CHAR(1) DEFAULT '0',
+ IS_USE_TENANT_DOMAIN_SUBJECT CHAR(1) DEFAULT '1',
+ IS_USE_USER_DOMAIN_SUBJECT CHAR(1) DEFAULT '1',
+ ENABLE_AUTHORIZATION CHAR(1) DEFAULT '0',
+ SUBJECT_CLAIM_URI VARCHAR (512),
+ IS_SAAS_APP CHAR(1) DEFAULT '0',
+ IS_DUMB_MODE CHAR(1) DEFAULT '0',
+ UUID CHAR(36),
+ IMAGE_URL VARCHAR(1024),
+ ACCESS_URL VARCHAR(1024),
+ IS_DISCOVERABLE CHAR(1) DEFAULT '0',
+
+ PRIMARY KEY (ID));
+
+ALTER TABLE SP_APP ADD CONSTRAINT APPLICATION_NAME_CONSTRAINT UNIQUE(APP_NAME, TENANT_ID);
+ALTER TABLE SP_APP ADD CONSTRAINT APPLICATION_UUID_CONSTRAINT UNIQUE(UUID);
+
+CREATE TABLE IF NOT EXISTS SP_METADATA (
+ ID INTEGER AUTO_INCREMENT,
+ SP_ID INTEGER,
+ NAME VARCHAR(255) NOT NULL,
+ `VALUE` VARCHAR(255) NOT NULL,
+ DISPLAY_NAME VARCHAR(255),
+ TENANT_ID INTEGER DEFAULT -1,
+ PRIMARY KEY (ID),
+ CONSTRAINT SP_METADATA_CONSTRAINT UNIQUE (SP_ID, NAME),
+ FOREIGN KEY (SP_ID) REFERENCES SP_APP(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS SP_INBOUND_AUTH (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ TENANT_ID INTEGER NOT NULL,
+ INBOUND_AUTH_KEY VARCHAR (255),
+ INBOUND_AUTH_TYPE VARCHAR (255) NOT NULL,
+ INBOUND_CONFIG_TYPE VARCHAR (255) NOT NULL,
+ PROP_NAME VARCHAR (255),
+ PROP_VALUE VARCHAR (1024) ,
+ APP_ID INTEGER NOT NULL,
+ PRIMARY KEY (ID));
+
+ALTER TABLE SP_INBOUND_AUTH ADD CONSTRAINT APPLICATION_ID_CONSTRAINT FOREIGN KEY (APP_ID) REFERENCES SP_APP (ID) ON
+DELETE CASCADE;
+
+CREATE TABLE IF NOT EXISTS SP_AUTH_STEP (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ TENANT_ID INTEGER NOT NULL,
+ STEP_ORDER INTEGER DEFAULT 1,
+ APP_ID INTEGER NOT NULL ,
+ IS_SUBJECT_STEP CHAR(1) DEFAULT '0',
+ IS_ATTRIBUTE_STEP CHAR(1) DEFAULT '0',
+ PRIMARY KEY (ID));
+
+ALTER TABLE SP_AUTH_STEP ADD CONSTRAINT APPLICATION_ID_CONSTRAINT_STEP FOREIGN KEY (APP_ID) REFERENCES SP_APP (ID) ON
+DELETE CASCADE;
+
+CREATE TABLE IF NOT EXISTS SP_FEDERATED_IDP (
+ ID INTEGER NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ AUTHENTICATOR_ID INTEGER NOT NULL,
+ PRIMARY KEY (ID, AUTHENTICATOR_ID));
+
+ALTER TABLE SP_FEDERATED_IDP ADD CONSTRAINT STEP_ID_CONSTRAINT FOREIGN KEY (ID) REFERENCES SP_AUTH_STEP (ID) ON DELETE
+CASCADE;
+
+CREATE TABLE IF NOT EXISTS SP_CLAIM_DIALECT (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ TENANT_ID INTEGER NOT NULL,
+ SP_DIALECT VARCHAR (512) NOT NULL,
+ APP_ID INTEGER NOT NULL,
+ PRIMARY KEY (ID));
+
+ALTER TABLE SP_CLAIM_DIALECT ADD CONSTRAINT DIALECTID_APPID_CONSTRAINT FOREIGN KEY (APP_ID) REFERENCES SP_APP (ID) ON
+DELETE CASCADE;
+
+CREATE TABLE IF NOT EXISTS SP_CLAIM_MAPPING (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ TENANT_ID INTEGER NOT NULL,
+ IDP_CLAIM VARCHAR (512) NOT NULL ,
+ SP_CLAIM VARCHAR (512) NOT NULL ,
+ APP_ID INTEGER NOT NULL,
+ IS_REQUESTED VARCHAR(128) DEFAULT '0',
+ IS_MANDATORY VARCHAR(128) DEFAULT '0',
+ DEFAULT_VALUE VARCHAR(255),
+ PRIMARY KEY (ID));
+
+ALTER TABLE SP_CLAIM_MAPPING ADD CONSTRAINT CLAIMID_APPID_CONSTRAINT FOREIGN KEY (APP_ID) REFERENCES SP_APP (ID) ON
+DELETE CASCADE;
+
+CREATE TABLE IF NOT EXISTS SP_ROLE_MAPPING (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ TENANT_ID INTEGER NOT NULL,
+ IDP_ROLE VARCHAR (255) NOT NULL ,
+ SP_ROLE VARCHAR (255) NOT NULL ,
+ APP_ID INTEGER NOT NULL,
+ PRIMARY KEY (ID));
+
+ALTER TABLE SP_ROLE_MAPPING ADD CONSTRAINT ROLEID_APPID_CONSTRAINT FOREIGN KEY (APP_ID) REFERENCES SP_APP (ID) ON
+DELETE CASCADE;
+
+CREATE TABLE IF NOT EXISTS SP_REQ_PATH_AUTHENTICATOR (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ TENANT_ID INTEGER NOT NULL,
+ AUTHENTICATOR_NAME VARCHAR (255) NOT NULL ,
+ APP_ID INTEGER NOT NULL,
+ PRIMARY KEY (ID));
+
+ALTER TABLE SP_REQ_PATH_AUTHENTICATOR ADD CONSTRAINT REQ_AUTH_APPID_CONSTRAINT FOREIGN KEY (APP_ID) REFERENCES SP_APP
+(ID) ON DELETE CASCADE;
+
+CREATE TABLE IF NOT EXISTS SP_PROVISIONING_CONNECTOR (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ TENANT_ID INTEGER NOT NULL,
+ IDP_NAME VARCHAR (255) NOT NULL ,
+ CONNECTOR_NAME VARCHAR (255) NOT NULL ,
+ APP_ID INTEGER NOT NULL,
+ IS_JIT_ENABLED CHAR(1) NOT NULL DEFAULT '0',
+ BLOCKING CHAR(1) NOT NULL DEFAULT '0',
+ RULE_ENABLED CHAR(1) NOT NULL DEFAULT '0',
+ PRIMARY KEY (ID));
+
+ALTER TABLE SP_PROVISIONING_CONNECTOR ADD CONSTRAINT PRO_CONNECTOR_APPID_CONSTRAINT FOREIGN KEY (APP_ID) REFERENCES
+SP_APP (ID) ON DELETE CASCADE;
+
+CREATE TABLE IF NOT EXISTS SP_AUTH_SCRIPT (
+ ID INTEGER AUTO_INCREMENT NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ APP_ID INTEGER NOT NULL,
+ TYPE VARCHAR(255) NOT NULL,
+ CONTENT BLOB DEFAULT NULL,
+ IS_ENABLED CHAR(1) NOT NULL DEFAULT '0',
+ PRIMARY KEY (ID));
+
+CREATE TABLE SP_TEMPLATE (
+ ID INTEGER AUTO_INCREMENT NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ NAME VARCHAR(255) NOT NULL,
+ DESCRIPTION VARCHAR(1023),
+ CONTENT BLOB DEFAULT NULL,
+ PRIMARY KEY (ID),
+ CONSTRAINT SP_TEMPLATE_CONSTRAINT UNIQUE (TENANT_ID, NAME));
+
+CREATE TABLE IF NOT EXISTS SP_TRUSTED_APPS (
+ ID INTEGER AUTO_INCREMENT,
+ SP_ID INTEGER NOT NULL,
+ PLATFORM_TYPE VARCHAR(255) NOT NULL,
+ APP_IDENTIFIER VARCHAR(255) NOT NULL,
+ THUMBPRINTS VARCHAR(2048),
+ IS_FIDO_TRUSTED BOOLEAN DEFAULT FALSE,
+ TENANT_ID INTEGER DEFAULT -1,
+ PRIMARY KEY (ID),
+ UNIQUE (SP_ID, PLATFORM_TYPE),
+ FOREIGN KEY (SP_ID) REFERENCES SP_APP(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS IDN_AUTH_WAIT_STATUS (
+ ID INTEGER AUTO_INCREMENT NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ LONG_WAIT_KEY VARCHAR(255) NOT NULL,
+ WAIT_STATUS CHAR(1) NOT NULL DEFAULT '1',
+ TIME_CREATED TIMESTAMP DEFAULT 0,
+ EXPIRE_TIME TIMESTAMP DEFAULT 0,
+ PRIMARY KEY (ID),
+ CONSTRAINT IDN_AUTH_WAIT_STATUS_KEY UNIQUE (LONG_WAIT_KEY));
+
+CREATE TABLE IF NOT EXISTS IDP (
+ ID INTEGER AUTO_INCREMENT,
+ TENANT_ID INTEGER,
+ NAME VARCHAR(254) NOT NULL,
+ IS_ENABLED CHAR(1) NOT NULL DEFAULT '1',
+ IS_PRIMARY CHAR(1) NOT NULL DEFAULT '0',
+ HOME_REALM_ID VARCHAR(254),
+ IMAGE MEDIUMBLOB,
+ CERTIFICATE BLOB,
+ ALIAS VARCHAR(254),
+ INBOUND_PROV_ENABLED CHAR(1) NOT NULL DEFAULT '0',
+ INBOUND_PROV_USER_STORE_ID VARCHAR(254),
+ USER_CLAIM_URI VARCHAR(254),
+ ROLE_CLAIM_URI VARCHAR(254),
+ DESCRIPTION VARCHAR(1024),
+ DEFAULT_AUTHENTICATOR_NAME VARCHAR(254),
+ DEFAULT_PRO_CONNECTOR_NAME VARCHAR(254),
+ PROVISIONING_ROLE VARCHAR(128),
+ IS_FEDERATION_HUB CHAR(1) NOT NULL DEFAULT '0',
+ IS_LOCAL_CLAIM_DIALECT CHAR(1) NOT NULL DEFAULT '0',
+ DISPLAY_NAME VARCHAR(255),
+ IMAGE_URL VARCHAR(1024),
+ UUID CHAR(36) NOT NULL,
+ PRIMARY KEY (ID),
+ UNIQUE (TENANT_ID, NAME),
+ UNIQUE (UUID)
+);
+
+CREATE TABLE IF NOT EXISTS IDP_ROLE (
+ ID INTEGER AUTO_INCREMENT,
+ IDP_ID INTEGER,
+ TENANT_ID INTEGER,
+ ROLE VARCHAR(254),
+ PRIMARY KEY (ID),
+ UNIQUE (IDP_ID, ROLE),
+ FOREIGN KEY (IDP_ID) REFERENCES IDP(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS IDP_GROUP (
+ ID INTEGER AUTO_INCREMENT NOT NULL,
+ IDP_ID INTEGER NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ GROUP_NAME VARCHAR(255) NOT NULL,
+ UUID CHAR(36) NOT NULL,
+ PRIMARY KEY (ID),
+ UNIQUE (IDP_ID, GROUP_NAME),
+ UNIQUE (UUID),
+ FOREIGN KEY (IDP_ID) REFERENCES IDP(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS IDP_ROLE_MAPPING (
+ ID INTEGER AUTO_INCREMENT,
+ IDP_ROLE_ID INTEGER,
+ TENANT_ID INTEGER,
+ USER_STORE_ID VARCHAR (253),
+ LOCAL_ROLE VARCHAR(253),
+ PRIMARY KEY (ID),
+ UNIQUE (IDP_ROLE_ID, TENANT_ID, USER_STORE_ID, LOCAL_ROLE),
+ FOREIGN KEY (IDP_ROLE_ID) REFERENCES IDP_ROLE(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS IDP_CLAIM (
+ ID INTEGER AUTO_INCREMENT,
+ IDP_ID INTEGER,
+ TENANT_ID INTEGER,
+ CLAIM VARCHAR(254),
+ PRIMARY KEY (ID),
+ UNIQUE (IDP_ID, CLAIM),
+ FOREIGN KEY (IDP_ID) REFERENCES IDP(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS IDP_CLAIM_MAPPING (
+ ID INTEGER AUTO_INCREMENT,
+ IDP_CLAIM_ID INTEGER,
+ TENANT_ID INTEGER,
+ LOCAL_CLAIM VARCHAR(253),
+ DEFAULT_VALUE VARCHAR(255),
+ IS_REQUESTED VARCHAR(128) DEFAULT '0',
+ PRIMARY KEY (ID),
+ UNIQUE (IDP_CLAIM_ID, TENANT_ID, LOCAL_CLAIM),
+ FOREIGN KEY (IDP_CLAIM_ID) REFERENCES IDP_CLAIM(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS IDP_AUTHENTICATOR (
+ ID INTEGER AUTO_INCREMENT,
+ TENANT_ID INTEGER,
+ IDP_ID INTEGER,
+ NAME VARCHAR(255) NOT NULL,
+ IS_ENABLED CHAR (1) DEFAULT '1',
+ DISPLAY_NAME VARCHAR(255),
+ PRIMARY KEY (ID),
+ UNIQUE (TENANT_ID, IDP_ID, NAME),
+ FOREIGN KEY (IDP_ID) REFERENCES IDP(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS IDP_METADATA (
+ ID INTEGER AUTO_INCREMENT,
+ IDP_ID INTEGER,
+ NAME VARCHAR(255) NOT NULL,
+ `VALUE` VARCHAR(255) NOT NULL,
+ DISPLAY_NAME VARCHAR(255),
+ TENANT_ID INTEGER DEFAULT -1,
+ PRIMARY KEY (ID),
+ CONSTRAINT IDP_METADATA_CONSTRAINT UNIQUE (IDP_ID, NAME),
+ FOREIGN KEY (IDP_ID) REFERENCES IDP(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS IDP_AUTHENTICATOR_PROPERTY (
+ ID INTEGER AUTO_INCREMENT,
+ TENANT_ID INTEGER,
+ AUTHENTICATOR_ID INTEGER,
+ PROPERTY_KEY VARCHAR(255) NOT NULL,
+ PROPERTY_VALUE VARCHAR(2047),
+ IS_SECRET CHAR (1) DEFAULT '0',
+ PRIMARY KEY (ID),
+ UNIQUE (TENANT_ID, AUTHENTICATOR_ID, PROPERTY_KEY),
+ FOREIGN KEY (AUTHENTICATOR_ID) REFERENCES IDP_AUTHENTICATOR(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS IDP_PROVISIONING_CONFIG (
+ ID INTEGER AUTO_INCREMENT,
+ TENANT_ID INTEGER,
+ IDP_ID INTEGER,
+ PROVISIONING_CONNECTOR_TYPE VARCHAR(255) NOT NULL,
+ IS_ENABLED CHAR (1) DEFAULT '0',
+ IS_BLOCKING CHAR (1) DEFAULT '0',
+ IS_RULES_ENABLED CHAR (1) DEFAULT '0',
+ PRIMARY KEY (ID),
+ UNIQUE (TENANT_ID, IDP_ID, PROVISIONING_CONNECTOR_TYPE),
+ FOREIGN KEY (IDP_ID) REFERENCES IDP(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS IDP_PROV_CONFIG_PROPERTY (
+ ID INTEGER AUTO_INCREMENT,
+ TENANT_ID INTEGER,
+ PROVISIONING_CONFIG_ID INTEGER,
+ PROPERTY_KEY VARCHAR(255) NOT NULL,
+ PROPERTY_VALUE VARCHAR(2048),
+ PROPERTY_BLOB_VALUE BLOB,
+ PROPERTY_TYPE VARCHAR(32) NOT NULL,
+ IS_SECRET CHAR (1) DEFAULT '0',
+ PRIMARY KEY (ID),
+ UNIQUE (TENANT_ID, PROVISIONING_CONFIG_ID, PROPERTY_KEY),
+ FOREIGN KEY (PROVISIONING_CONFIG_ID) REFERENCES IDP_PROVISIONING_CONFIG(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS IDP_PROVISIONING_ENTITY (
+ ID INTEGER AUTO_INCREMENT,
+ PROVISIONING_CONFIG_ID INTEGER,
+ ENTITY_TYPE VARCHAR(255) NOT NULL,
+ ENTITY_LOCAL_USERSTORE VARCHAR(255) NOT NULL,
+ ENTITY_NAME VARCHAR(255) NOT NULL,
+ ENTITY_VALUE VARCHAR(255),
+ TENANT_ID INTEGER,
+ ENTITY_LOCAL_ID VARCHAR(255),
+ PRIMARY KEY (ID),
+ UNIQUE (ENTITY_TYPE, TENANT_ID, ENTITY_LOCAL_USERSTORE, ENTITY_NAME, PROVISIONING_CONFIG_ID),
+ UNIQUE (PROVISIONING_CONFIG_ID, ENTITY_TYPE, ENTITY_VALUE),
+ FOREIGN KEY (PROVISIONING_CONFIG_ID) REFERENCES IDP_PROVISIONING_CONFIG(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS IDP_LOCAL_CLAIM (
+ ID INTEGER AUTO_INCREMENT,
+ TENANT_ID INTEGER,
+ IDP_ID INTEGER,
+ CLAIM_URI VARCHAR(255) NOT NULL,
+ DEFAULT_VALUE VARCHAR(255),
+ IS_REQUESTED VARCHAR(128) DEFAULT '0',
+ PRIMARY KEY (ID),
+ UNIQUE (TENANT_ID, IDP_ID, CLAIM_URI),
+ FOREIGN KEY (IDP_ID) REFERENCES IDP(ID) ON DELETE CASCADE);
+
+CREATE TABLE IF NOT EXISTS IDN_ASSOCIATED_ID (
+ ID INTEGER AUTO_INCREMENT,
+ IDP_USER_ID VARCHAR(255) NOT NULL,
+ TENANT_ID INTEGER DEFAULT -1234,
+ IDP_ID INTEGER NOT NULL,
+ DOMAIN_NAME VARCHAR(255) NOT NULL,
+ USER_NAME VARCHAR(255) NOT NULL,
+ ASSOCIATION_ID CHAR(36) NOT NULL,
+ PRIMARY KEY (ID),
+ UNIQUE(IDP_USER_ID, TENANT_ID, IDP_ID),
+ FOREIGN KEY (IDP_ID) REFERENCES IDP(ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_USER_ACCOUNT_ASSOCIATION (
+ ASSOCIATION_KEY VARCHAR(255) NOT NULL,
+ TENANT_ID INTEGER,
+ DOMAIN_NAME VARCHAR(255) NOT NULL,
+ USER_NAME VARCHAR(255) NOT NULL,
+ PRIMARY KEY (TENANT_ID, DOMAIN_NAME, USER_NAME));
+
+CREATE TABLE IF NOT EXISTS FIDO_DEVICE_STORE (
+ TENANT_ID INTEGER,
+ DOMAIN_NAME VARCHAR(255) NOT NULL,
+ USER_NAME VARCHAR(45) NOT NULL,
+ TIME_REGISTERED TIMESTAMP,
+ KEY_HANDLE VARCHAR(200) NOT NULL,
+ DEVICE_DATA VARCHAR(2048) NOT NULL,
+ PRIMARY KEY (TENANT_ID, DOMAIN_NAME, USER_NAME, KEY_HANDLE));
+
+CREATE TABLE IF NOT EXISTS FIDO2_DEVICE_STORE (
+ TENANT_ID INTEGER,
+ DOMAIN_NAME VARCHAR(255) NOT NULL,
+ USER_NAME VARCHAR(45) NOT NULL,
+ TIME_REGISTERED TIMESTAMP,
+ USER_HANDLE VARCHAR(200) NOT NULL,
+ CREDENTIAL_ID VARCHAR(200) NOT NULL,
+ PUBLIC_KEY_COSE VARCHAR(2048) NOT NULL,
+ SIGNATURE_COUNT BIGINT,
+ USER_IDENTITY VARCHAR(200) NOT NULL,
+ DISPLAY_NAME VARCHAR(255),
+ IS_USERNAMELESS_SUPPORTED CHAR(1) DEFAULT '0',
+ PRIMARY KEY (TENANT_ID, DOMAIN_NAME, USER_NAME, USER_HANDLE));
+
+CREATE TABLE IF NOT EXISTS WF_REQUEST (
+ UUID VARCHAR (45),
+ CREATED_BY VARCHAR (255),
+ TENANT_ID INTEGER DEFAULT -1,
+ OPERATION_TYPE VARCHAR (50),
+ CREATED_AT TIMESTAMP,
+ UPDATED_AT TIMESTAMP,
+ STATUS VARCHAR (30),
+ REQUEST BLOB,
+ PRIMARY KEY (UUID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_RECOVERY_FLOW_DATA (
+ RECOVERY_FLOW_ID VARCHAR(255) NOT NULL,
+ CODE VARCHAR(255),
+ FAILED_ATTEMPTS INTEGER DEFAULT 0 NOT NULL,
+ RESEND_COUNT INTEGER DEFAULT 0 NOT NULL,
+ TIME_CREATED TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY(RECOVERY_FLOW_ID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_RECOVERY_DATA (
+ USER_NAME VARCHAR(255) NOT NULL,
+ USER_DOMAIN VARCHAR(127) NOT NULL,
+ TENANT_ID INTEGER DEFAULT -1,
+ CODE VARCHAR(255) NOT NULL,
+ SCENARIO VARCHAR(255) NOT NULL,
+ STEP VARCHAR(127) NOT NULL,
+ TIME_CREATED TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ REMAINING_SETS VARCHAR(2500) DEFAULT NULL,
+ RECOVERY_FLOW_ID VARCHAR(255),
+ PRIMARY KEY(USER_NAME, USER_DOMAIN, TENANT_ID, SCENARIO,STEP),
+ FOREIGN KEY (RECOVERY_FLOW_ID) REFERENCES IDN_RECOVERY_FLOW_DATA(RECOVERY_FLOW_ID) ON DELETE CASCADE,
+ UNIQUE(CODE)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_PASSWORD_HISTORY_DATA (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ USER_NAME VARCHAR(255) NOT NULL,
+ USER_DOMAIN VARCHAR(127) NOT NULL,
+ TENANT_ID INTEGER DEFAULT -1,
+ SALT_VALUE VARCHAR(255),
+ HASH VARCHAR(255) NOT NULL,
+ TIME_CREATED TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY (ID),
+ UNIQUE (USER_NAME,USER_DOMAIN,TENANT_ID,SALT_VALUE,HASH)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_CLAIM_DIALECT (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ DIALECT_URI VARCHAR (255) NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ PRIMARY KEY (ID),
+ CONSTRAINT DIALECT_URI_CONSTRAINT UNIQUE (DIALECT_URI, TENANT_ID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_CLAIM (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ DIALECT_ID INTEGER NOT NULL,
+ CLAIM_URI VARCHAR (255) NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ PRIMARY KEY (ID),
+ FOREIGN KEY (DIALECT_ID) REFERENCES IDN_CLAIM_DIALECT(ID) ON DELETE CASCADE,
+ CONSTRAINT CLAIM_URI_CONSTRAINT UNIQUE (DIALECT_ID, CLAIM_URI, TENANT_ID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_CLAIM_MAPPED_ATTRIBUTE (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ LOCAL_CLAIM_ID INTEGER,
+ USER_STORE_DOMAIN_NAME VARCHAR (255) NOT NULL,
+ ATTRIBUTE_NAME VARCHAR (255) NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ PRIMARY KEY (ID),
+ FOREIGN KEY (LOCAL_CLAIM_ID) REFERENCES IDN_CLAIM(ID) ON DELETE CASCADE,
+ CONSTRAINT USER_STORE_DOMAIN_CONSTRAINT UNIQUE (LOCAL_CLAIM_ID, USER_STORE_DOMAIN_NAME, TENANT_ID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_CLAIM_PROPERTY (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ LOCAL_CLAIM_ID INTEGER,
+ PROPERTY_NAME VARCHAR (255) NOT NULL,
+ PROPERTY_VALUE VARCHAR (255) NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ PRIMARY KEY (ID),
+ FOREIGN KEY (LOCAL_CLAIM_ID) REFERENCES IDN_CLAIM(ID) ON DELETE CASCADE,
+ CONSTRAINT PROPERTY_NAME_CONSTRAINT UNIQUE (LOCAL_CLAIM_ID, PROPERTY_NAME, TENANT_ID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_CLAIM_MAPPING (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ EXT_CLAIM_ID INTEGER NOT NULL,
+ MAPPED_LOCAL_CLAIM_ID INTEGER NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ PRIMARY KEY (ID),
+ FOREIGN KEY (EXT_CLAIM_ID) REFERENCES IDN_CLAIM(ID) ON DELETE CASCADE,
+ FOREIGN KEY (MAPPED_LOCAL_CLAIM_ID) REFERENCES IDN_CLAIM(ID) ON DELETE CASCADE,
+ CONSTRAINT EXT_TO_LOC_MAPPING_CONSTRN UNIQUE (EXT_CLAIM_ID, TENANT_ID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_SAML2_ASSERTION_STORE (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ SAML2_ID VARCHAR(255) ,
+ SAML2_ISSUER VARCHAR(255) ,
+ SAML2_SUBJECT VARCHAR(255) ,
+ SAML2_SESSION_INDEX VARCHAR(255) ,
+ SAML2_AUTHN_CONTEXT_CLASS_REF VARCHAR(255) ,
+ SAML2_ASSERTION VARCHAR(4096) ,
+ ASSERTION BLOB ,
+ PRIMARY KEY (ID)
+);
+
+CREATE TABLE IDN_SAML2_ARTIFACT_STORE (
+ ID INT NOT NULL AUTO_INCREMENT,
+ SOURCE_ID VARCHAR(255) NOT NULL,
+ MESSAGE_HANDLER VARCHAR(255) NOT NULL,
+ AUTHN_REQ_DTO BLOB NOT NULL,
+ SESSION_ID VARCHAR(255) NOT NULL,
+ INIT_TIMESTAMP TIMESTAMP NOT NULL,
+ EXP_TIMESTAMP TIMESTAMP NOT NULL,
+ ASSERTION_ID VARCHAR(255),
+ PRIMARY KEY (`ID`)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OIDC_JTI (
+ JWT_ID VARCHAR(255),
+ EXP_TIME TIMESTAMP NOT NULL ,
+ TIME_CREATED TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ,
+ PRIMARY KEY (JWT_ID)
+);
+
+
+CREATE TABLE IF NOT EXISTS IDN_OIDC_PROPERTY (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ TENANT_ID INTEGER,
+ CONSUMER_KEY VARCHAR(255) ,
+ PROPERTY_KEY VARCHAR(255) NOT NULL,
+ PROPERTY_VALUE VARCHAR(2047) ,
+ PRIMARY KEY (ID),
+ FOREIGN KEY (TENANT_ID, CONSUMER_KEY) REFERENCES IDN_OAUTH_CONSUMER_APPS(TENANT_ID, CONSUMER_KEY) ON DELETE CASCADE
+);
+CREATE TABLE IF NOT EXISTS IDN_OIDC_REQ_OBJECT_REFERENCE (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ CONSUMER_KEY_ID INTEGER ,
+ CODE_ID VARCHAR(255) ,
+ TOKEN_ID VARCHAR(255) ,
+ SESSION_DATA_KEY VARCHAR(255),
+ PRIMARY KEY (ID),
+ FOREIGN KEY (CONSUMER_KEY_ID) REFERENCES IDN_OAUTH_CONSUMER_APPS(ID) ON DELETE CASCADE,
+ FOREIGN KEY (TOKEN_ID) REFERENCES IDN_OAUTH2_ACCESS_TOKEN(TOKEN_ID) ON DELETE CASCADE,
+ FOREIGN KEY (CODE_ID) REFERENCES IDN_OAUTH2_AUTHORIZATION_CODE(CODE_ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OIDC_REQ_OBJECT_CLAIMS (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ REQ_OBJECT_ID INTEGER,
+ CLAIM_ATTRIBUTE VARCHAR(255) ,
+ ESSENTIAL CHAR(1) NOT NULL DEFAULT '0',
+ `VALUE` VARCHAR(255) ,
+ IS_USERINFO CHAR(1) NOT NULL DEFAULT '0',
+ PRIMARY KEY (ID),
+ FOREIGN KEY (REQ_OBJECT_ID) REFERENCES IDN_OIDC_REQ_OBJECT_REFERENCE (ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OIDC_REQ_OBJ_CLAIM_VALUES (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ REQ_OBJECT_CLAIMS_ID INTEGER ,
+ CLAIM_VALUES VARCHAR(255) ,
+ PRIMARY KEY (ID),
+ FOREIGN KEY (REQ_OBJECT_CLAIMS_ID) REFERENCES IDN_OIDC_REQ_OBJECT_CLAIMS(ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_CERTIFICATE (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ NAME VARCHAR(100),
+ CERTIFICATE_IN_PEM BLOB,
+ TENANT_ID INTEGER DEFAULT 0,
+ PRIMARY KEY(ID),
+ CONSTRAINT CERTIFICATE_UNIQUE_KEY UNIQUE (NAME, TENANT_ID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OIDC_SCOPE_CLAIM_MAPPING (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ SCOPE_ID INTEGER NOT NULL,
+ EXTERNAL_CLAIM_ID INTEGER NOT NULL,
+ PRIMARY KEY (ID),
+ FOREIGN KEY (SCOPE_ID) REFERENCES IDN_OAUTH2_SCOPE(SCOPE_ID) ON DELETE CASCADE,
+ FOREIGN KEY (EXTERNAL_CLAIM_ID) REFERENCES IDN_CLAIM(ID) ON DELETE CASCADE,
+ UNIQUE (SCOPE_ID, EXTERNAL_CLAIM_ID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_FUNCTION_LIBRARY (
+ NAME VARCHAR(255) NOT NULL,
+ DESCRIPTION VARCHAR(1023),
+ TYPE VARCHAR(255) NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ DATA BLOB NOT NULL,
+ PRIMARY KEY (TENANT_ID,NAME)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_CIBA_AUTH_CODE (
+ AUTH_CODE_KEY CHAR (36),
+ AUTH_REQ_ID CHAR (36),
+ ISSUED_TIME TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ CONSUMER_KEY VARCHAR(255),
+ LAST_POLLED_TIME TIMESTAMP NOT NULL,
+ POLLING_INTERVAL INTEGER,
+ EXPIRES_IN INTEGER,
+ AUTHENTICATED_USER_NAME VARCHAR(255),
+ USER_STORE_DOMAIN VARCHAR(100),
+ TENANT_ID INTEGER,
+ AUTH_REQ_STATUS VARCHAR (100) DEFAULT 'REQUESTED',
+ IDP_ID INTEGER,
+ UNIQUE(AUTH_REQ_ID),
+ PRIMARY KEY (AUTH_CODE_KEY),
+ FOREIGN KEY (TENANT_ID, CONSUMER_KEY) REFERENCES IDN_OAUTH_CONSUMER_APPS(TENANT_ID, CONSUMER_KEY) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_OAUTH2_CIBA_REQUEST_SCOPES (
+ AUTH_CODE_KEY CHAR (36),
+ SCOPE VARCHAR (255),
+ FOREIGN KEY (AUTH_CODE_KEY) REFERENCES IDN_OAUTH2_CIBA_AUTH_CODE(AUTH_CODE_KEY) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS IDN_FED_AUTH_SESSION_MAPPING (
+ IDP_SESSION_ID VARCHAR(255) NOT NULL,
+ SESSION_ID VARCHAR(255) NOT NULL,
+ IDP_NAME VARCHAR(255) NOT NULL,
+ AUTHENTICATOR_ID VARCHAR(255),
+ PROTOCOL_TYPE VARCHAR(255),
+ TIME_CREATED TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ PRIMARY KEY(IDP_SESSION_ID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_CONFIG_TYPE (
+ ID VARCHAR(255) NOT NULL,
+ NAME VARCHAR(255) NOT NULL,
+ DESCRIPTION VARCHAR(1023) NULL,
+ PRIMARY KEY (ID),
+ CONSTRAINT TYPE_NAME_CONSTRAINT UNIQUE (NAME)
+);
+
+INSERT INTO IDN_CONFIG_TYPE (ID, NAME, DESCRIPTION) VALUES
+('9ab0ef95-13e9-4ed5-afaf-d29bed62f7bd', 'IDP_TEMPLATE', 'Template type to uniquely identify IDP templates'),
+('3c4ac3d0-5903-4e3d-aaca-38df65b33bfd', 'APPLICATION_TEMPLATE',
+'Template type to uniquely identify Application templates'),
+('8ec6dbf1-218a-49bf-bc34-0d2db52d151c', 'CORS_CONFIGURATION',
+'A resource type to keep the tenant CORS configurations');
+
+CREATE TABLE IF NOT EXISTS IDN_CONFIG_RESOURCE (
+ ID VARCHAR(255) NOT NULL,
+ TENANT_ID INT NOT NULL,
+ NAME VARCHAR(255) NOT NULL,
+ CREATED_TIME TIMESTAMP NOT NULL,
+ LAST_MODIFIED TIMESTAMP NOT NULL,
+ HAS_FILE BOOLEAN NOT NULL,
+ HAS_ATTRIBUTE BOOLEAN NOT NULL,
+ TYPE_ID VARCHAR(255) NOT NULL,
+ UNIQUE (NAME, TENANT_ID, TYPE_ID),
+ PRIMARY KEY (ID)
+);
+ALTER TABLE IDN_CONFIG_RESOURCE
+ADD CONSTRAINT TYPE_ID_FOREIGN_CONSTRAINT FOREIGN KEY (TYPE_ID) REFERENCES IDN_CONFIG_TYPE (ID)
+ON DELETE CASCADE ON UPDATE CASCADE;
+
+CREATE TABLE IF NOT EXISTS IDN_CONFIG_ATTRIBUTE (
+ ID VARCHAR(255) NOT NULL,
+ RESOURCE_ID VARCHAR(255) NOT NULL,
+ ATTR_KEY VARCHAR(255) NOT NULL,
+ ATTR_VALUE VARCHAR(1023) NULL,
+ PRIMARY KEY (ID),
+ UNIQUE (RESOURCE_ID, ATTR_KEY)
+);
+ALTER TABLE IDN_CONFIG_ATTRIBUTE
+ADD CONSTRAINT RESOURCE_ID_ATTRIBUTE_FOREIGN_CONSTRAINT FOREIGN KEY (RESOURCE_ID) REFERENCES
+IDN_CONFIG_RESOURCE (ID) ON DELETE CASCADE ON UPDATE CASCADE;
+
+CREATE TABLE IF NOT EXISTS IDN_CONFIG_FILE (
+ ID VARCHAR(255) NOT NULL,
+ `VALUE` BLOB NULL,
+ RESOURCE_ID VARCHAR(255) NOT NULL,
+ NAME VARCHAR(255) NULL,
+ PRIMARY KEY (ID)
+);
+ALTER TABLE IDN_CONFIG_FILE
+ADD CONSTRAINT RESOURCE_ID_FILE_FOREIGN_CONSTRAINT FOREIGN KEY (RESOURCE_ID) REFERENCES
+IDN_CONFIG_RESOURCE (ID) ON DELETE CASCADE ON UPDATE CASCADE;
+
+CREATE TABLE IF NOT EXISTS IDN_REMOTE_FETCH_CONFIG (
+ ID VARCHAR(255) NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ IS_ENABLED CHAR(1) NOT NULL,
+ REPO_MANAGER_TYPE VARCHAR(255) NOT NULL,
+ ACTION_LISTENER_TYPE VARCHAR(255) NOT NULL,
+ CONFIG_DEPLOYER_TYPE VARCHAR(255) NOT NULL,
+ REMOTE_FETCH_NAME VARCHAR(255),
+ REMOTE_RESOURCE_URI VARCHAR(255) NOT NULL,
+ ATTRIBUTES_JSON MEDIUMTEXT NOT NULL,
+ PRIMARY KEY (ID),
+ CONSTRAINT UC_REMOTE_RESOURCE_TYPE UNIQUE (TENANT_ID, CONFIG_DEPLOYER_TYPE)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_REMOTE_FETCH_REVISIONS (
+ ID VARCHAR(255) NOT NULL,
+ CONFIG_ID VARCHAR(255) NOT NULL,
+ FILE_PATH VARCHAR(255) NOT NULL,
+ FILE_HASH VARCHAR(255),
+ DEPLOYED_DATE TIMESTAMP,
+ LAST_SYNC_TIME TIMESTAMP,
+ DEPLOYMENT_STATUS VARCHAR(255),
+ ITEM_NAME VARCHAR(255),
+ DEPLOY_ERR_LOG MEDIUMTEXT,
+ PRIMARY KEY (ID),
+ FOREIGN KEY (CONFIG_ID) REFERENCES IDN_REMOTE_FETCH_CONFIG(ID) ON DELETE CASCADE,
+ CONSTRAINT UC_REVISIONS UNIQUE (CONFIG_ID, ITEM_NAME)
+);
+
+
+CREATE TABLE IF NOT EXISTS IDN_USER_FUNCTIONALITY_MAPPING (
+ ID VARCHAR(255) NOT NULL,
+ USER_ID VARCHAR(255) NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ FUNCTIONALITY_ID VARCHAR(255) NOT NULL,
+ IS_FUNCTIONALITY_LOCKED BOOLEAN NOT NULL,
+ FUNCTIONALITY_UNLOCK_TIME BIGINT NOT NULL,
+ FUNCTIONALITY_LOCK_REASON VARCHAR(1023),
+ FUNCTIONALITY_LOCK_REASON_CODE VARCHAR(255),
+ PRIMARY KEY (ID),
+ CONSTRAINT IDN_USER_FUNCTIONALITY_MAPPING_CONSTRAINT UNIQUE (USER_ID, TENANT_ID, FUNCTIONALITY_ID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_USER_FUNCTIONALITY_PROPERTY (
+ ID VARCHAR(255) NOT NULL,
+ USER_ID VARCHAR(255) NOT NULL,
+ TENANT_ID INTEGER NOT NULL,
+ FUNCTIONALITY_ID VARCHAR(255) NOT NULL,
+ PROPERTY_NAME VARCHAR(255),
+ PROPERTY_VALUE VARCHAR(255),
+ PRIMARY KEY (ID),
+ CONSTRAINT IDN_USER_FUNCTIONALITY_PROPERTY_CONSTRAINT UNIQUE (USER_ID, TENANT_ID, FUNCTIONALITY_ID, PROPERTY_NAME)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_CORS_ORIGIN (
+ ID INT NOT NULL AUTO_INCREMENT,
+ TENANT_ID INT NOT NULL,
+ ORIGIN VARCHAR(2048) NOT NULL,
+ UUID CHAR(36) NOT NULL,
+
+ PRIMARY KEY (ID),
+ UNIQUE (TENANT_ID, ORIGIN),
+ UNIQUE (UUID)
+);
+
+CREATE TABLE IF NOT EXISTS IDN_CORS_ASSOCIATION (
+ IDN_CORS_ORIGIN_ID INT NOT NULL,
+ SP_APP_ID INT NOT NULL,
+
+ PRIMARY KEY (IDN_CORS_ORIGIN_ID, SP_APP_ID),
+ FOREIGN KEY (IDN_CORS_ORIGIN_ID) REFERENCES IDN_CORS_ORIGIN (ID) ON DELETE CASCADE,
+ FOREIGN KEY (SP_APP_ID) REFERENCES SP_APP (ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS SP_SHARED_APP (
+ ID INTEGER NOT NULL AUTO_INCREMENT,
+ MAIN_APP_ID CHAR(36) NOT NULL,
+ OWNER_ORG_ID CHAR(36) NOT NULL,
+ SHARED_APP_ID CHAR(36) NOT NULL,
+ SHARED_ORG_ID CHAR(36) NOT NULL,
+ SHARE_WITH_ALL_CHILDREN BOOLEAN DEFAULT FALSE,
+ PRIMARY KEY (ID),
+ FOREIGN KEY (MAIN_APP_ID) REFERENCES SP_APP(UUID) ON DELETE CASCADE,
+ FOREIGN KEY (SHARED_APP_ID) REFERENCES SP_APP(UUID) ON DELETE CASCADE,
+ UNIQUE (MAIN_APP_ID, OWNER_ORG_ID, SHARED_ORG_ID),
+ UNIQUE (SHARED_APP_ID)
+);
+
+CREATE TABLE IF NOT EXISTS API_RESOURCE (
+ ID VARCHAR(255) NOT NULL PRIMARY KEY,
+ CURSOR_KEY INTEGER NOT NULL AUTO_INCREMENT,
+ NAME VARCHAR(255) NOT NULL,
+ IDENTIFIER VARCHAR(255) NOT NULL,
+ TENANT_ID INT,
+ DESCRIPTION VARCHAR(255),
+ TYPE VARCHAR(255) NOT NULL,
+ REQUIRES_AUTHORIZATION BOOLEAN NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS API_RESOURCE_PROPERTY (
+ ID INTEGER AUTO_INCREMENT,
+ API_ID CHAR(36) NOT NULL,
+ NAME VARCHAR(255) NOT NULL,
+ `VALUE` VARCHAR(255) NOT NULL,
+ PRIMARY KEY (ID),
+ CONSTRAINT API_RESOURCE_PROPERTY_CONSTRAINT UNIQUE (API_ID, NAME),
+ FOREIGN KEY (API_ID) REFERENCES API_RESOURCE(ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS SCOPE (
+ ID VARCHAR(255) NOT NULL PRIMARY KEY,
+ CURSOR_KEY INTEGER NOT NULL AUTO_INCREMENT,
+ API_ID VARCHAR(255) NOT NULL,
+ NAME VARCHAR(255) NOT NULL,
+ DISPLAY_NAME VARCHAR(255) NOT NULL,
+ DESCRIPTION VARCHAR(300),
+ TENANT_ID INT,
+ FOREIGN KEY (API_ID) REFERENCES API_RESOURCE(ID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS AUTHORIZED_API(
+ APP_ID VARCHAR(255) NOT NULL,
+ API_ID VARCHAR(255) NOT NULL,
+ POLICY_ID VARCHAR(255) NOT NULL,
+ PRIMARY KEY (APP_ID, API_ID),
+ FOREIGN KEY (API_ID) REFERENCES API_RESOURCE(ID) ON DELETE CASCADE,
+ FOREIGN KEY (APP_ID) REFERENCES SP_APP(UUID) ON DELETE CASCADE
+);
+
+CREATE TABLE IF NOT EXISTS AUTHORIZED_SCOPE(
+ APP_ID CHAR(36) NOT NULL,
+ API_ID CHAR(36) NOT NULL,
+ SCOPE_ID CHAR(36) NOT NULL,
+ CONSTRAINT PK_APP_API_SCOPE PRIMARY KEY (APP_ID, API_ID, SCOPE_ID),
+ FOREIGN KEY (API_ID) REFERENCES API_RESOURCE(ID),
+ FOREIGN KEY (SCOPE_ID) REFERENCES SCOPE(ID) ON DELETE CASCADE,
+ FOREIGN KEY (APP_ID) REFERENCES SP_APP(UUID),
+ FOREIGN KEY (APP_ID, API_ID) REFERENCES AUTHORIZED_API(APP_ID, API_ID) ON DELETE CASCADE,
+ CONSTRAINT AUTHORIZED_SCOPE_UNIQUE UNIQUE (APP_ID, SCOPE_ID)
+);
+
+CREATE TABLE IF NOT EXISTS APP_ROLE_ASSOCIATION (
+ APP_ID CHAR(36) NOT NULL,
+ ROLE_ID VARCHAR(255) NOT NULL,
+ PRIMARY KEY (APP_ID, ROLE_ID),
+ FOREIGN KEY (APP_ID) REFERENCES SP_APP(UUID) ON DELETE CASCADE
+);
+
+-- --------------------------- INDEX CREATION -----------------------------
+-- IDN_OAUTH2_ACCESS_TOKEN --
+CREATE INDEX IDX_TC ON IDN_OAUTH2_ACCESS_TOKEN(TIME_CREATED);
+CREATE INDEX IDX_ATH ON IDN_OAUTH2_ACCESS_TOKEN(ACCESS_TOKEN_HASH);
+CREATE INDEX IDX_AT_TI_UD ON IDN_OAUTH2_ACCESS_TOKEN(AUTHZ_USER, TENANT_ID, TOKEN_STATE, USER_DOMAIN);
+CREATE INDEX IDX_AT_AT ON IDN_OAUTH2_ACCESS_TOKEN(ACCESS_TOKEN);
+CREATE INDEX IDX_AT_RTH ON IDN_OAUTH2_ACCESS_TOKEN(REFRESH_TOKEN_HASH);
+CREATE INDEX IDX_AT_RT ON IDN_OAUTH2_ACCESS_TOKEN(REFRESH_TOKEN);
+
+-- IDN_OAUTH2_AUTHORIZATION_CODE --
+CREATE INDEX IDX_AUTHORIZATION_CODE_HASH ON IDN_OAUTH2_AUTHORIZATION_CODE (AUTHORIZATION_CODE_HASH, CONSUMER_KEY_ID);
+CREATE INDEX IDX_AUTHORIZATION_CODE_AU_TI ON IDN_OAUTH2_AUTHORIZATION_CODE (AUTHZ_USER, TENANT_ID, USER_DOMAIN, STATE);
+CREATE INDEX IDX_AC_CKID ON IDN_OAUTH2_AUTHORIZATION_CODE(CONSUMER_KEY_ID);
+CREATE INDEX IDX_AC_TID ON IDN_OAUTH2_AUTHORIZATION_CODE(TOKEN_ID);
+CREATE INDEX IDX_AC_AC_CKID ON IDN_OAUTH2_AUTHORIZATION_CODE(AUTHORIZATION_CODE, CONSUMER_KEY_ID);
+CREATE INDEX IDX_AT_CKID_AU_TID_UD_TSH_TS ON IDN_OAUTH2_ACCESS_TOKEN(CONSUMER_KEY_ID, AUTHZ_USER, TENANT_ID,
+USER_DOMAIN, TOKEN_SCOPE_HASH, TOKEN_STATE);
+
+-- IDN_SCIM_GROUP --
+CREATE INDEX IDX_IDN_SCIM_GROUP_TI_RN ON IDN_SCIM_GROUP (TENANT_ID, ROLE_NAME);
+CREATE INDEX IDX_IDN_SCIM_GROUP_TI_RN_AN ON IDN_SCIM_GROUP (TENANT_ID, ROLE_NAME, ATTR_NAME);
+
+-- IDN_AUTH_SESSION_STORE --
+CREATE INDEX IDX_IDN_AUTH_SESSION_TIME ON IDN_AUTH_SESSION_STORE (TIME_CREATED);
+
+-- IDN_AUTH_TEMP_SESSION_STORE --
+CREATE INDEX IDX_IDN_AUTH_TMP_SESSION_TIME ON IDN_AUTH_TEMP_SESSION_STORE (TIME_CREATED);
+
+-- IDN_OIDC_SCOPE_CLAIM_MAPPING --
+CREATE INDEX IDX_AT_SI_ECI ON IDN_OIDC_SCOPE_CLAIM_MAPPING(SCOPE_ID, EXTERNAL_CLAIM_ID);
+
+-- IDN_OAUTH2_SCOPE --
+CREATE INDEX IDX_SC_TID ON IDN_OAUTH2_SCOPE(TENANT_ID);
+
+-- IDN_OAUTH2_SCOPE_BINDING --
+CREATE INDEX IDX_SB_SCPID ON IDN_OAUTH2_SCOPE_BINDING(SCOPE_ID);
+
+-- IDN_OIDC_REQ_OBJECT_REFERENCE --
+CREATE INDEX IDX_OROR_TID ON IDN_OIDC_REQ_OBJECT_REFERENCE(TOKEN_ID);
+
+-- IDN_OAUTH2_ACCESS_TOKEN_SCOPE --
+CREATE INDEX IDX_ATS_TID ON IDN_OAUTH2_ACCESS_TOKEN_SCOPE(TOKEN_ID);
+
+-- SP_TEMPLATE --
+CREATE INDEX IDX_SP_TEMPLATE ON SP_TEMPLATE (TENANT_ID, NAME);
+
+-- IDN_AUTH_USER --
+CREATE INDEX IDX_AUTH_USER_UN_TID_DN ON IDN_AUTH_USER (USER_NAME, TENANT_ID, DOMAIN_NAME);
+CREATE INDEX IDX_AUTH_USER_DN_TOD ON IDN_AUTH_USER (DOMAIN_NAME, TENANT_ID);
+
+-- IDN_AUTH_USER_SESSION_MAPPING --
+CREATE INDEX IDX_USER_ID ON IDN_AUTH_USER_SESSION_MAPPING (USER_ID);
+CREATE INDEX IDX_SESSION_ID ON IDN_AUTH_USER_SESSION_MAPPING (SESSION_ID);
+
+-- IDN_OAUTH_CONSUMER_APPS --
+CREATE INDEX IDX_OCA_UM_TID_UD_APN ON IDN_OAUTH_CONSUMER_APPS(USERNAME,TENANT_ID,USER_DOMAIN, APP_NAME);
+
+-- IDX_SPI_APP --
+CREATE INDEX IDX_SPI_APP ON SP_INBOUND_AUTH(APP_ID);
+
+-- IDN_OIDC_PROPERTY --
+CREATE INDEX IDX_IOP_CK ON IDN_OIDC_PROPERTY(TENANT_ID, CONSUMER_KEY);
+
+-- IDN_FIDO2_PROPERTY --
+CREATE INDEX IDX_FIDO2_STR ON FIDO2_DEVICE_STORE(USER_NAME, TENANT_ID, DOMAIN_NAME, CREDENTIAL_ID, USER_HANDLE);
+
+-- IDN_ASSOCIATED_ID --
+CREATE INDEX IDX_AI_DN_UN_AI ON IDN_ASSOCIATED_ID(DOMAIN_NAME, USER_NAME, ASSOCIATION_ID);
+
+-- IDN_OAUTH2_TOKEN_BINDING --
+CREATE INDEX IDX_IDN_AUTH_BIND ON IDN_OAUTH2_TOKEN_BINDING (TOKEN_BINDING_REF);
+
+-- IDN_FED_AUTH_SESSION_MAPPING --
+CREATE INDEX IDX_FEDERATED_AUTH_SESSION_ID ON IDN_FED_AUTH_SESSION_MAPPING (SESSION_ID);
+
+-- IDN_REMOTE_FETCH_REVISIONS --
+CREATE INDEX IDX_REMOTE_FETCH_REVISION_CONFIG_ID ON IDN_REMOTE_FETCH_REVISIONS (CONFIG_ID);
+
+-- IDN_CORS_ASSOCIATION --
+CREATE INDEX IDX_CORS_SP_APP_ID ON IDN_CORS_ASSOCIATION (SP_APP_ID);
+
+-- IDN_CORS_ASSOCIATION --
+CREATE INDEX IDX_CORS_ORIGIN_ID ON IDN_CORS_ASSOCIATION (IDN_CORS_ORIGIN_ID);
diff --git a/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/log4j.properties b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/log4j.properties
new file mode 100644
index 000000000000..5a83c3d02a16
--- /dev/null
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/log4j.properties
@@ -0,0 +1,26 @@
+#
+# 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.
+#
+
+# Root logger option
+log4j.rootLogger=INFO, stdout
+
+# Direct log messages to stdout
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
diff --git a/components/entitlement/org.wso2.carbon.identity.entitlement.common/src/test/resources/testng.xml b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/testng.xml
similarity index 57%
rename from components/entitlement/org.wso2.carbon.identity.entitlement.common/src/test/resources/testng.xml
rename to components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/testng.xml
index 65977e15934b..69d12f19d4d5 100644
--- a/components/entitlement/org.wso2.carbon.identity.entitlement.common/src/test/resources/testng.xml
+++ b/components/ai-services-mgt/org.wso2.carbon.ai.service.mgt/src/test/resources/testng.xml
@@ -18,9 +18,14 @@
-
-
+
+
+
+
+
+
+
diff --git a/components/ai-services-mgt/pom.xml b/components/ai-services-mgt/pom.xml
new file mode 100644
index 000000000000..65195c69b8b3
--- /dev/null
+++ b/components/ai-services-mgt/pom.xml
@@ -0,0 +1,44 @@
+
+
+
+
+ 4.0.0
+
+
+ org.wso2.carbon.identity.framework
+ identity-framework
+ 7.6.10-SNAPSHOT
+ ../../pom.xml
+
+
+ ai-services-mgt
+ pom
+ WSO2 Carbon - AI Management Aggregator Module
+
+ This is a Carbon bundle that represent the AI Management Aggregator Module.
+
+ http://wso2.org
+
+
+ org.wso2.carbon.ai.service.mgt
+
+
+
diff --git a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.collection.mgt/pom.xml b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.collection.mgt/pom.xml
index f8d5de5238ad..31247b348114 100644
--- a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.collection.mgt/pom.xml
+++ b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.collection.mgt/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.framework
api-resource-mgt
- 7.6.10-SNAPSHOT
+ 7.7.63-SNAPSHOT
../pom.xml
diff --git a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/pom.xml b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/pom.xml
index 992947c6d6b5..8c17ad730e25 100644
--- a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/pom.xml
+++ b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/pom.xml
@@ -21,7 +21,7 @@
org.wso2.carbon.identity.framework
api-resource-mgt
- 7.6.10-SNAPSHOT
+ 7.7.63-SNAPSHOT
../pom.xml
org.wso2.carbon.identity.api.resource.mgt
diff --git a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/constant/APIResourceManagementConstants.java b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/constant/APIResourceManagementConstants.java
index 1cae1164c087..ff39212152cb 100644
--- a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/constant/APIResourceManagementConstants.java
+++ b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/constant/APIResourceManagementConstants.java
@@ -142,7 +142,16 @@ public enum ErrorMessages {
"properties.", "Error while adding API resource properties to the database."),
ERROR_CODE_ERROR_WHILE_UPDATING_SCOPE_METADATA("65015", "Error while updating scope metadata.",
"Error while updating scope metadata in the database."),
- ;
+ ERROR_CODE_ERROR_WHILE_RESOLVING_ORGANIZATION_FOR_TENANT("65016", "Error while resolving organization",
+ "Error while resolving organization for tenant domain : %s"),
+ ERROR_CODE_ADDING_API_RESOURCE_NOT_SUPPORTED_FOR_ORGANIZATIONS("65017", "Unable to add API resources",
+ "Adding API resource is not supported for organizations."),
+ ERROR_CODE_DELETING_API_RESOURCE_NOT_SUPPORTED_FOR_ORGANIZATIONS("65018", "Unable to delete API resources",
+ "Deleting API resource is not supported for organizations."),
+ ERROR_CODE_ADDING_SCOPES_NOT_SUPPORTED_FOR_ORGANIZATIONS("65019", "Unable to add scopes",
+ "Adding scope is not supported for organizations."),
+ ERROR_CODE_DELETING_SCOPES_NOT_SUPPORTED_FOR_ORGANIZATIONS("65020", "Unable to add scopes",
+ "Deleting scope is not supported for organizations.");
private final String code;
private final String message;
diff --git a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/constant/SQLConstants.java b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/constant/SQLConstants.java
index 19458f21a30f..f4cce52c6213 100644
--- a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/constant/SQLConstants.java
+++ b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/constant/SQLConstants.java
@@ -65,10 +65,19 @@ public class SQLConstants {
"DESCRIPTION, TENANT_ID, TYPE, REQUIRES_AUTHORIZATION FROM API_RESOURCE WHERE ";
public static final String GET_API_RESOURCES_TAIL =
" (TENANT_ID = %d OR TENANT_ID IS NULL) ORDER BY CURSOR_KEY %s LIMIT %d";
+ public static final String GET_API_RESOURCES_TAIL_FOR_ORGANIZATIONS =
+ " (TENANT_ID = %d OR TENANT_ID IS NULL) AND TYPE NOT IN ('TENANT', 'SYSTEM', 'CONSOLE_FEATURE') " +
+ "ORDER BY CURSOR_KEY %s LIMIT %d";
public static final String GET_API_RESOURCES_TAIL_MSSQL =
" (TENANT_ID = %d OR TENANT_ID IS NULL) ORDER BY CURSOR_KEY %s";
+ public static final String GET_API_RESOURCES_TAIL_FOR_ORGANIZATIONS_MSSQL =
+ " (TENANT_ID = %d OR TENANT_ID IS NULL) AND TYPE NOT IN ('TENANT', 'SYSTEM', 'CONSOLE_FEATURE') ORDER " +
+ "BY CURSOR_KEY %s";
public static final String GET_API_RESOURCES_TAIL_ORACLE =
" (TENANT_ID = %d OR TENANT_ID IS NULL) ORDER BY CURSOR_KEY %s FETCH FIRST %d ROWS ONLY";
+ public static final String GET_API_RESOURCES_TAIL_FOR_ORGANIZATIONS_ORACLE =
+ " (TENANT_ID = %d OR TENANT_ID IS NULL) AND TYPE NOT IN ('TENANT', 'SYSTEM', 'CONSOLE_FEATURE') " +
+ "ORDER BY CURSOR_KEY %s FETCH FIRST %d ROWS ONLY";
public static final String GET_API_RESOURCES_WITH_PROPERTIES_SELECTION = "SELECT" +
" AR.ID AS API_RESOURCE_ID," +
" AR.CURSOR_KEY AS CURSOR_KEY," +
@@ -99,6 +108,8 @@ public class SQLConstants {
" LEFT JOIN API_RESOURCE_PROPERTY ARP ON AR.ID = ARP.API_ID ORDER BY CURSOR_KEY %s";
public static final String GET_API_RESOURCES_COUNT = "SELECT COUNT(DISTINCT(ID)) FROM API_RESOURCE WHERE ";
public static final String GET_API_RESOURCES_COUNT_TAIL = " (TENANT_ID = ? OR TENANT_ID IS NULL)";
+ public static final String GET_API_RESOURCES_COUNT_FOR_ORGANIZATIONS_TAIL =
+ " (TENANT_ID = ? OR TENANT_ID IS NULL) AND TYPE NOT IN ('TENANT', 'SYSTEM', 'CONSOLE_FEATURE')";
public static final String GET_API_RESOURCE_BY_ID = "SELECT" +
" AR.ID AS API_RESOURCE_ID," +
" AR.NAME AS API_RESOURCE_NAME," +
@@ -113,6 +124,20 @@ public class SQLConstants {
" S.DESCRIPTION AS SCOPE_DESCRIPTION" +
" FROM API_RESOURCE AR LEFT JOIN SCOPE S ON AR.ID = S.API_ID WHERE AR.ID = ? AND (AR.TENANT_ID = ?" +
" OR AR.TENANT_ID IS NULL)";
+ public static final String GET_API_RESOURCE_BY_ID_FOR_ORGANIZATIONS = "SELECT" +
+ " AR.ID AS API_RESOURCE_ID," +
+ " AR.NAME AS API_RESOURCE_NAME," +
+ " AR.IDENTIFIER AS API_RESOURCE_IDENTIFIER," +
+ " AR.DESCRIPTION AS API_RESOURCE_DESCRIPTION," +
+ " AR.TENANT_ID AS API_RESOURCE_TENANT_ID," +
+ " AR.TYPE AS API_RESOURCE_TYPE," +
+ " AR.REQUIRES_AUTHORIZATION AS REQUIRES_AUTHORIZATION," +
+ " S.ID AS SCOPE_ID," +
+ " S.NAME AS SCOPE_QUALIFIED_NAME," +
+ " S.DISPLAY_NAME AS SCOPE_DISPLAY_NAME," +
+ " S.DESCRIPTION AS SCOPE_DESCRIPTION" +
+ " FROM API_RESOURCE AR LEFT JOIN SCOPE S ON AR.ID = S.API_ID WHERE AR.ID = ? AND (AR.TENANT_ID = ?" +
+ " OR AR.TENANT_ID IS NULL) AND AR.TYPE NOT IN ('TENANT', 'SYSTEM', 'CONSOLE_FEATURE')";
public static final String GET_SCOPES_BY_API_ID = "SELECT ID, NAME, DISPLAY_NAME, DESCRIPTION, API_ID, TENANT_ID "
+ "FROM SCOPE WHERE API_ID = ? AND (TENANT_ID = ? OR TENANT_ID IS NULL)";
public static final String GET_API_RESOURCE_BY_IDENTIFIER = "SELECT" +
@@ -151,6 +176,12 @@ public class SQLConstants {
public static final String GET_SCOPES_BY_TENANT_ID = "SELECT ID, NAME, DISPLAY_NAME, DESCRIPTION, API_ID, " +
"TENANT_ID FROM SCOPE WHERE ";
public static final String GET_SCOPES_BY_TENANT_ID_TAIL = " (TENANT_ID = ? OR TENANT_ID IS NULL)";
+ public static final String GET_SCOPES_BY_TENANT_ID_FOR_ORGANIZATIONS =
+ "SELECT SC.ID, SC.NAME, SC.DISPLAY_NAME, SC.DESCRIPTION, SC.API_ID, SC.TENANT_ID FROM SCOPE SC" +
+ " JOIN API_RESOURCE AR ON AR.ID = SC.API_ID" +
+ " WHERE ";
+ public static final String GET_SCOPES_BY_TENANT_ID_FOR_ORGANIZATIONS_TAIL = "(AR.TENANT_ID = ? OR AR.TENANT_ID " +
+ "IS NULL) AND TYPE NOT IN ('TENANT', 'SYSTEM', 'CONSOLE_FEATURE')";
public static final String DELETE_SCOPE_BY_NAME = "DELETE FROM SCOPE WHERE NAME = ? AND TENANT_ID = ?";
public static final String GET_API_RESOURCE_PROPERTIES_BY_API_ID = "SELECT ID, NAME, VALUE FROM " +
"API_RESOURCE_PROPERTY WHERE API_ID = ?";
diff --git a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/dao/impl/APIResourceManagementDAOImpl.java b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/dao/impl/APIResourceManagementDAOImpl.java
index f69704d0abdd..14784f5ecde3 100644
--- a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/dao/impl/APIResourceManagementDAOImpl.java
+++ b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/dao/impl/APIResourceManagementDAOImpl.java
@@ -20,12 +20,14 @@
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
+import org.wso2.carbon.base.MultitenantConstants;
import org.wso2.carbon.identity.api.resource.mgt.APIResourceMgtClientException;
import org.wso2.carbon.identity.api.resource.mgt.APIResourceMgtException;
import org.wso2.carbon.identity.api.resource.mgt.APIResourceMgtServerException;
import org.wso2.carbon.identity.api.resource.mgt.constant.APIResourceManagementConstants;
import org.wso2.carbon.identity.api.resource.mgt.constant.SQLConstants;
import org.wso2.carbon.identity.api.resource.mgt.dao.APIResourceManagementDAO;
+import org.wso2.carbon.identity.api.resource.mgt.internal.APIResourceManagementServiceComponentHolder;
import org.wso2.carbon.identity.api.resource.mgt.model.FilterQueryBuilder;
import org.wso2.carbon.identity.api.resource.mgt.util.APIResourceManagementUtil;
import org.wso2.carbon.identity.application.common.model.APIResource;
@@ -35,6 +37,9 @@
import org.wso2.carbon.identity.core.model.ExpressionNode;
import org.wso2.carbon.identity.core.util.IdentityCoreConstants;
import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil;
+import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
+import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException;
+import org.wso2.carbon.identity.organization.management.service.util.OrganizationManagementUtil;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -94,6 +99,17 @@ public Integer getAPIResourcesCount(Integer tenantId, List expre
Map filterAttributeValue = filterQueryBuilder.getFilterAttributeValue();
String getAPIResourcesCountSqlStmtTail = SQLConstants.GET_API_RESOURCES_COUNT_TAIL;
+ try {
+ if (OrganizationManagementUtil.isOrganization(tenantId)) {
+ tenantId = getRootOrganizationTenantId(tenantId);
+ getAPIResourcesCountSqlStmtTail = SQLConstants.GET_API_RESOURCES_COUNT_FOR_ORGANIZATIONS_TAIL;
+ }
+ } catch (OrganizationManagementException e) {
+ throw APIResourceManagementUtil.handleServerException(APIResourceManagementConstants.ErrorMessages
+ .ERROR_CODE_ERROR_WHILE_RESOLVING_ORGANIZATION_FOR_TENANT, e,
+ IdentityTenantUtil.getTenantDomain(tenantId));
+ }
+
String sqlStmt = SQLConstants.GET_API_RESOURCES_COUNT + filterQueryBuilder.getFilterQuery() +
getAPIResourcesCountSqlStmtTail;
@@ -124,6 +140,16 @@ public Integer getAPIResourcesCount(Integer tenantId, List expre
@Override
public APIResource addAPIResource(APIResource apiResource, Integer tenantId) throws APIResourceMgtException {
+ try {
+ if (OrganizationManagementUtil.isOrganization(tenantId)) {
+ throw APIResourceManagementUtil.handleClientException(APIResourceManagementConstants.ErrorMessages
+ .ERROR_CODE_ADDING_API_RESOURCE_NOT_SUPPORTED_FOR_ORGANIZATIONS);
+ }
+ } catch (OrganizationManagementException e) {
+ throw APIResourceManagementUtil.handleServerException(APIResourceManagementConstants.ErrorMessages.
+ ERROR_CODE_ERROR_WHILE_RESOLVING_ORGANIZATION_FOR_TENANT, e,
+ IdentityTenantUtil.getTenantDomain(tenantId));
+ }
String generatedAPIId = UUID.randomUUID().toString();
try (Connection dbConnection = IdentityDatabaseUtil.getDBConnection(true)) {
try {
@@ -228,8 +254,19 @@ public boolean isAPIResourceExistById(String apiId, Integer tenantId) throws API
@Override
public APIResource getAPIResourceById(String apiId, Integer tenantId) throws APIResourceMgtException {
+ String query = SQLConstants.GET_API_RESOURCE_BY_ID;
+ try {
+ if (OrganizationManagementUtil.isOrganization(tenantId)) {
+ tenantId = getRootOrganizationTenantId(tenantId);
+ query = SQLConstants.GET_API_RESOURCE_BY_ID_FOR_ORGANIZATIONS;
+ }
+ } catch (OrganizationManagementException e) {
+ throw APIResourceManagementUtil.handleServerException(APIResourceManagementConstants.ErrorMessages.
+ ERROR_CODE_ERROR_WHILE_RESOLVING_ORGANIZATION_FOR_TENANT, e,
+ IdentityTenantUtil.getTenantDomain(tenantId));
+ }
try (Connection dbConnection = IdentityDatabaseUtil.getDBConnection(false);
- PreparedStatement preparedStatement = dbConnection.prepareStatement(SQLConstants.GET_API_RESOURCE_BY_ID)) {
+ PreparedStatement preparedStatement = dbConnection.prepareStatement(query)) {
preparedStatement.setString(1, apiId);
preparedStatement.setInt(2, tenantId);
ResultSet resultSet = preparedStatement.executeQuery();
@@ -326,6 +363,16 @@ public void updateScopeMetadata(Scope scope, APIResource apiResource, Integer te
@Override
public void deleteAPIResourceById(String apiId, Integer tenantId) throws APIResourceMgtException {
+ try {
+ if (OrganizationManagementUtil.isOrganization(tenantId)) {
+ throw APIResourceManagementUtil.handleClientException(APIResourceManagementConstants.ErrorMessages
+ .ERROR_CODE_DELETING_API_RESOURCE_NOT_SUPPORTED_FOR_ORGANIZATIONS);
+ }
+ } catch (OrganizationManagementException e) {
+ throw APIResourceManagementUtil.handleServerException(APIResourceManagementConstants.ErrorMessages.
+ ERROR_CODE_ERROR_WHILE_RESOLVING_ORGANIZATION_FOR_TENANT, e,
+ IdentityTenantUtil.getTenantDomain(tenantId));
+ }
try (Connection dbConnection = IdentityDatabaseUtil.getDBConnection(true)) {
try {
PreparedStatement prepStmt = dbConnection.prepareStatement(SQLConstants.DELETE_SCOPES_BY_API);
@@ -450,6 +497,19 @@ public List getScopesByTenantId(Integer tenantId, List ex
appendFilterQuery(expressionNodes, filterQueryBuilder, true);
String query = SQLConstants.GET_SCOPES_BY_TENANT_ID + filterQueryBuilder.getFilterQuery() +
SQLConstants.GET_SCOPES_BY_TENANT_ID_TAIL;
+ try {
+ if (OrganizationManagementUtil.isOrganization(tenantId)) {
+ FilterQueryBuilder filterQueryBuilderForOrg = new FilterQueryBuilder();
+ appendFilterQueryForOrganizations(expressionNodes, filterQueryBuilderForOrg, true);
+ tenantId = getRootOrganizationTenantId(tenantId);
+ query = SQLConstants.GET_SCOPES_BY_TENANT_ID_FOR_ORGANIZATIONS + filterQueryBuilderForOrg
+ .getFilterQuery() + SQLConstants.GET_SCOPES_BY_TENANT_ID_FOR_ORGANIZATIONS_TAIL;
+ }
+ } catch (OrganizationManagementException e) {
+ throw APIResourceManagementUtil.handleServerException(APIResourceManagementConstants.ErrorMessages
+ .ERROR_CODE_ERROR_WHILE_RESOLVING_ORGANIZATION_FOR_TENANT, e,
+ IdentityTenantUtil.getTenantDomain(tenantId));
+ }
PreparedStatement preparedStatement = dbConnection.prepareStatement(query);
preparedStatement.setInt(1, tenantId);
int filterAttrSize = 0;
@@ -483,6 +543,17 @@ public List getScopesByTenantId(Integer tenantId, List ex
@Override
public void addScopes(List scopes, String apiId, Integer tenantId) throws APIResourceMgtException {
+ try {
+ if (OrganizationManagementUtil.isOrganization(tenantId)) {
+ throw APIResourceManagementUtil.handleClientException(APIResourceManagementConstants.ErrorMessages
+ .ERROR_CODE_ADDING_SCOPES_NOT_SUPPORTED_FOR_ORGANIZATIONS);
+ }
+ } catch (OrganizationManagementException e) {
+ throw APIResourceManagementUtil.handleServerException(APIResourceManagementConstants.ErrorMessages.
+ ERROR_CODE_ERROR_WHILE_RESOLVING_ORGANIZATION_FOR_TENANT, e,
+ IdentityTenantUtil.getTenantDomain(tenantId));
+ }
+
try (Connection dbConnection = IdentityDatabaseUtil.getDBConnection(true)) {
addScopes(dbConnection, apiId, scopes, tenantId);
IdentityDatabaseUtil.commitTransaction(dbConnection);
@@ -495,6 +566,17 @@ public void addScopes(List scopes, String apiId, Integer tenantId) throws
@Override
public void deleteAllScopes(String apiId, Integer tenantId) throws APIResourceMgtException {
+ try {
+ if (OrganizationManagementUtil.isOrganization(tenantId)) {
+ throw APIResourceManagementUtil.handleClientException(APIResourceManagementConstants.ErrorMessages
+ .ERROR_CODE_DELETING_SCOPES_NOT_SUPPORTED_FOR_ORGANIZATIONS);
+ }
+ } catch (OrganizationManagementException e) {
+ throw APIResourceManagementUtil.handleServerException(APIResourceManagementConstants.ErrorMessages.
+ ERROR_CODE_ERROR_WHILE_RESOLVING_ORGANIZATION_FOR_TENANT, e,
+ IdentityTenantUtil.getTenantDomain(tenantId));
+ }
+
try (Connection dbConnection = IdentityDatabaseUtil.getDBConnection(true)) {
deleteScopeByAPIId(dbConnection, apiId, tenantId);
IdentityDatabaseUtil.commitTransaction(dbConnection);
@@ -507,6 +589,17 @@ public void deleteAllScopes(String apiId, Integer tenantId) throws APIResourceMg
@Override
public void deleteScope(String apiId, String scopeName, Integer tenantId) throws APIResourceMgtException {
+ try {
+ if (OrganizationManagementUtil.isOrganization(tenantId)) {
+ throw APIResourceManagementUtil.handleClientException(APIResourceManagementConstants.ErrorMessages
+ .ERROR_CODE_DELETING_SCOPES_NOT_SUPPORTED_FOR_ORGANIZATIONS);
+ }
+ } catch (OrganizationManagementException e) {
+ throw APIResourceManagementUtil.handleServerException(APIResourceManagementConstants.ErrorMessages.
+ ERROR_CODE_ERROR_WHILE_RESOLVING_ORGANIZATION_FOR_TENANT, e,
+ IdentityTenantUtil.getTenantDomain(tenantId));
+ }
+
try (Connection dbConnection = IdentityDatabaseUtil.getDBConnection(true)) {
deleteScopeByName(dbConnection, scopeName, tenantId);
IdentityDatabaseUtil.commitTransaction(dbConnection);
@@ -783,15 +876,38 @@ private static APIResource getApiResource(ResultSet resultSet, List expressionNodes, FilterQuery
attributeName = APIResourceManagementConstants.SCOPE_ATTRIBUTE_COLUMN_MAP.get(attributeValue);
}
- if (StringUtils.isNotBlank(attributeName) && StringUtils.isNotBlank(value) && StringUtils
- .isNotBlank(operation)) {
- switch (operation) {
- case APIResourceManagementConstants.EQ: {
- equalFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
- ++count;
- break;
- }
- case APIResourceManagementConstants.NE: {
- notEqualFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
- ++count;
- break;
- }
- case APIResourceManagementConstants.SW: {
- startWithFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
- ++count;
- break;
- }
- case APIResourceManagementConstants.EW: {
- endWithFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
- ++count;
- break;
- }
- case APIResourceManagementConstants.CO: {
- containsFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
- ++count;
- break;
- }
- case APIResourceManagementConstants.GE: {
- greaterThanOrEqualFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
- ++count;
- break;
- }
- case APIResourceManagementConstants.LE: {
- lessThanOrEqualFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
- ++count;
- break;
- }
- case APIResourceManagementConstants.GT: {
- greaterThanFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
- ++count;
- break;
- }
- case APIResourceManagementConstants.LT: {
- lessThanFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
- ++count;
- break;
- }
- default: {
- break;
- }
- }
- } else {
- throw APIResourceManagementUtil.handleClientException(
- APIResourceManagementConstants.ErrorMessages.ERROR_CODE_INVALID_FILTER_VALUE);
+ count = buildFilterBasedOnOperation(filterQueryBuilder, attributeName, value, operation, count, filter);
+ }
+ if (StringUtils.isBlank(filter.toString())) {
+ filterQueryBuilder.setFilterQuery(StringUtils.EMPTY);
+ } else {
+ filterQueryBuilder.setFilterQuery(filter.toString());
+ }
+ }
+ }
+
+ /**
+ * Append the filter query to the query builder for the organization level.
+ *
+ * @param expressionNodes List of expression nodes.
+ * @param filterQueryBuilder Filter query builder.
+ * @param isScopeFilter Whether the filter is for scopes.
+ * @throws APIResourceMgtClientException If an error occurs while appending the filter query.
+ */
+ private void appendFilterQueryForOrganizations(List expressionNodes,
+ FilterQueryBuilder filterQueryBuilder, boolean isScopeFilter)
+ throws APIResourceMgtClientException {
+
+ int count = 1;
+ StringBuilder filter = new StringBuilder();
+ if (CollectionUtils.isEmpty(expressionNodes)) {
+ filterQueryBuilder.setFilterQuery(StringUtils.EMPTY);
+ } else {
+ for (ExpressionNode expressionNode : expressionNodes) {
+ String operation = expressionNode.getOperation();
+ String value = expressionNode.getValue();
+ String attributeValue = expressionNode.getAttributeValue();
+ String attributeName = "AR." + APIResourceManagementConstants.ATTRIBUTE_COLUMN_MAP.get(attributeValue);
+
+ // If the filter is for scopes, get the column name from the scope attribute map.
+ if (isScopeFilter) {
+ attributeName = "SC." + APIResourceManagementConstants.SCOPE_ATTRIBUTE_COLUMN_MAP
+ .get(attributeValue);
}
+
+ count = buildFilterBasedOnOperation(filterQueryBuilder, attributeName, value, operation, count, filter);
}
if (StringUtils.isBlank(filter.toString())) {
filterQueryBuilder.setFilterQuery(StringUtils.EMPTY);
@@ -1122,6 +1223,69 @@ private void appendFilterQuery(List expressionNodes, FilterQuery
}
}
+ private int buildFilterBasedOnOperation(FilterQueryBuilder filterQueryBuilder, String attributeName,
+ String value, String operation, int count, StringBuilder filter)
+ throws APIResourceMgtClientException {
+
+ if (StringUtils.isNotBlank(attributeName) && StringUtils.isNotBlank(value) && StringUtils
+ .isNotBlank(operation)) {
+ switch (operation) {
+ case APIResourceManagementConstants.EQ: {
+ equalFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
+ ++count;
+ break;
+ }
+ case APIResourceManagementConstants.NE: {
+ notEqualFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
+ ++count;
+ break;
+ }
+ case APIResourceManagementConstants.SW: {
+ startWithFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
+ ++count;
+ break;
+ }
+ case APIResourceManagementConstants.EW: {
+ endWithFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
+ ++count;
+ break;
+ }
+ case APIResourceManagementConstants.CO: {
+ containsFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
+ ++count;
+ break;
+ }
+ case APIResourceManagementConstants.GE: {
+ greaterThanOrEqualFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
+ ++count;
+ break;
+ }
+ case APIResourceManagementConstants.LE: {
+ lessThanOrEqualFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
+ ++count;
+ break;
+ }
+ case APIResourceManagementConstants.GT: {
+ greaterThanFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
+ ++count;
+ break;
+ }
+ case APIResourceManagementConstants.LT: {
+ lessThanFilterBuilder(count, value, attributeName, filter, filterQueryBuilder);
+ ++count;
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ } else {
+ throw APIResourceManagementUtil.handleClientException(
+ APIResourceManagementConstants.ErrorMessages.ERROR_CODE_INVALID_FILTER_VALUE);
+ }
+ return count;
+ }
+
private void equalFilterBuilder(int count, String value, String attributeName, StringBuilder filter,
FilterQueryBuilder filterQueryBuilder) {
@@ -1193,4 +1357,16 @@ private void lessThanFilterBuilder(int count, String value, String attributeName
filter.append(attributeName).append(filterString);
filterQueryBuilder.setFilterAttributeValue(count, value);
}
+
+ private int getRootOrganizationTenantId(int tenantId) throws OrganizationManagementException {
+
+ String tenantDomain = IdentityTenantUtil.getTenantDomain(tenantId);
+ String orgId = APIResourceManagementServiceComponentHolder.getInstance().getOrganizationManager()
+ .resolveOrganizationId(tenantDomain);
+ String rootOrganizationId = APIResourceManagementServiceComponentHolder.getInstance()
+ .getOrganizationManager().getPrimaryOrganizationId(orgId);
+ String rootTenantDomain = APIResourceManagementServiceComponentHolder.getInstance()
+ .getOrganizationManager().resolveTenantDomain(rootOrganizationId);
+ return IdentityTenantUtil.getTenantId(rootTenantDomain);
+ }
}
diff --git a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/internal/APIResourceManagementServiceComponent.java b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/internal/APIResourceManagementServiceComponent.java
index deddfcc767a1..ac507baae419 100644
--- a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/internal/APIResourceManagementServiceComponent.java
+++ b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/internal/APIResourceManagementServiceComponent.java
@@ -97,13 +97,15 @@ protected void unsetIdentityCoreInitializedEventService(IdentityCoreInitializedE
unbind = "unsetOrganizationManager"
)
protected void setOrganizationManager(OrganizationManager organizationManager) {
- /* reference Organization Management service to guarantee that this component will wait until organization
- management service is started */
+
+ APIResourceManagementServiceComponentHolder.getInstance().setOrganizationManager(organizationManager);
+ LOG.debug("OrganizationManager set in API Resource Management bundle.");
}
protected void unsetOrganizationManager(OrganizationManager organizationManager) {
- /* reference Organization Management service to guarantee that this component will wait until organization
- management service is started */
+
+ APIResourceManagementServiceComponentHolder.getInstance().setOrganizationManager(null);
+ LOG.debug("OrganizationManager unset in API Resource Management bundle.");
}
@Reference(
diff --git a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/internal/APIResourceManagementServiceComponentHolder.java b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/internal/APIResourceManagementServiceComponentHolder.java
index 8a87368b08f8..75a26626d6bb 100644
--- a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/internal/APIResourceManagementServiceComponentHolder.java
+++ b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/main/java/org/wso2/carbon/identity/api/resource/mgt/internal/APIResourceManagementServiceComponentHolder.java
@@ -19,6 +19,7 @@
package org.wso2.carbon.identity.api.resource.mgt.internal;
import org.wso2.carbon.identity.event.services.IdentityEventService;
+import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
/**
* Service component holder for the API resource management.
@@ -26,6 +27,7 @@
public class APIResourceManagementServiceComponentHolder {
private IdentityEventService identityEventService;
+ private OrganizationManager organizationManager;
private static final APIResourceManagementServiceComponentHolder instance =
new APIResourceManagementServiceComponentHolder();
@@ -63,4 +65,24 @@ public void setIdentityEventService(IdentityEventService identityEventService) {
this.identityEventService = identityEventService;
}
+
+ /**
+ * Get the OrganizationManager.
+ *
+ * @return OrganizationManager instance.
+ */
+ public OrganizationManager getOrganizationManager() {
+
+ return organizationManager;
+ }
+
+ /**
+ * Set the OrganizationManager.
+ *
+ * @param organizationManager OrganizationManager instance.
+ */
+ public void setOrganizationManager(OrganizationManager organizationManager) {
+
+ this.organizationManager = organizationManager;
+ }
}
diff --git a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/test/java/org/wso2/carbon/identity/api/resource/mgt/dao/APIResourceManagementDAOImplTest.java b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/test/java/org/wso2/carbon/identity/api/resource/mgt/dao/APIResourceManagementDAOImplTest.java
index bb8cad66fd6b..c6a86c10c51b 100644
--- a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/test/java/org/wso2/carbon/identity/api/resource/mgt/dao/APIResourceManagementDAOImplTest.java
+++ b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/test/java/org/wso2/carbon/identity/api/resource/mgt/dao/APIResourceManagementDAOImplTest.java
@@ -27,13 +27,18 @@
import org.testng.annotations.BeforeClass;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
+import org.wso2.carbon.identity.api.resource.mgt.APIResourceMgtClientException;
import org.wso2.carbon.identity.api.resource.mgt.constant.APIResourceManagementConstants;
import org.wso2.carbon.identity.api.resource.mgt.dao.impl.APIResourceManagementDAOImpl;
+import org.wso2.carbon.identity.api.resource.mgt.internal.APIResourceManagementServiceComponentHolder;
import org.wso2.carbon.identity.application.common.model.APIResource;
import org.wso2.carbon.identity.application.common.model.Scope;
import org.wso2.carbon.identity.core.model.ExpressionNode;
import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
+import org.wso2.carbon.identity.organization.management.service.OrganizationManager;
+import org.wso2.carbon.identity.organization.management.service.exception.OrganizationManagementException;
+import org.wso2.carbon.identity.organization.management.service.util.OrganizationManagementUtil;
import java.nio.file.Paths;
import java.sql.Connection;
@@ -47,12 +52,17 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.mockStatic;
public class APIResourceManagementDAOImplTest {
private static final int TENANT_ID = 2;
private static final int INVALID_TENANT_ID = 3;
+ private static final int ORGANIZATION_TENANT_ID = 1001;
private static final String DB_NAME = "api_resource_mgt_dao_db";
public static final String APIRESOURCE_IDENTIFIER = "testAPIResource identifier ";
public static final String TEST_SCOPE_1 = "testScope1 ";
@@ -82,39 +92,62 @@ public void tearDown() throws Exception {
@DataProvider
public Object[][] getAPIResourcesCountData() {
return new Object[][]{
- {TENANT_ID, new ArrayList<>(), 2},
- {INVALID_TENANT_ID, new ArrayList<>(), 0},
+ {TENANT_ID, TENANT_ID, new ArrayList<>(), false, 2},
+ {TENANT_ID, ORGANIZATION_TENANT_ID, new ArrayList<>(), true, 2},
+ {INVALID_TENANT_ID, INVALID_TENANT_ID, new ArrayList<>(), false, 0},
};
}
@Test(dataProvider = "getAPIResourcesCountData")
- public void testGetAPIResourcesCount(Integer tenantId, List expressionNodes, int expected)
+ public void testGetAPIResourcesCount(Integer rootTenantId, Integer retrievingTenantId,
+ List expressionNodes, boolean isOrganization, int expected)
throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class);
+ MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class)) {
+ if (isOrganization) {
+ mockRootOrganizationExtraction(rootTenantId, identityTenantUtil);
+ }
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
.thenReturn(getConnection());
- Assert.assertEquals(daoImpl.getAPIResourcesCount(tenantId, expressionNodes).intValue(), expected);
+ organizationManagementUtil.when(() -> OrganizationManagementUtil.isOrganization(anyInt()))
+ .thenReturn(isOrganization);
+ Assert.assertEquals(daoImpl.getAPIResourcesCount(retrievingTenantId, expressionNodes).intValue(),
+ expected);
}
}
@DataProvider
public Object[][] getAPIResourcesData() {
return new Object[][]{
- {2, TENANT_ID, "ASC", new ArrayList<>(), 2},
- {1, TENANT_ID, "ASC", new ArrayList<>(), 1},
- {1, INVALID_TENANT_ID, "ASC", new ArrayList<>(), 0},
+ {2, TENANT_ID, TENANT_ID, false, "ASC", new ArrayList<>(), 2},
+ {2, TENANT_ID, ORGANIZATION_TENANT_ID, true, "ASC", new ArrayList<>(), 2},
+ {1, TENANT_ID, TENANT_ID, false, "ASC", new ArrayList<>(), 1},
+ {1, TENANT_ID, ORGANIZATION_TENANT_ID, true, "ASC", new ArrayList<>(), 1},
+ {1, INVALID_TENANT_ID, INVALID_TENANT_ID, false, "ASC", new ArrayList<>(), 0},
};
}
@Test(dataProvider = "getAPIResourcesData", priority = 1)
- public void testGetAPIResources(Integer limit, Integer tenantId, String sortOrder,
- List expressionNodes, int count) throws Exception {
+ public void testGetAPIResources(Integer limit, Integer rootTenantId, Integer retrievingTenantId,
+ boolean isOrganization, String sortOrder, List expressionNodes,
+ int count) throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class);
+ MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class)) {
+ if (isOrganization) {
+ mockRootOrganizationExtraction(rootTenantId, identityTenantUtil);
+ }
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
.thenReturn(getConnection());
- Assert.assertEquals(daoImpl.getAPIResources(limit, tenantId, sortOrder, expressionNodes).size(), count);
+ organizationManagementUtil.when(() -> OrganizationManagementUtil.isOrganization(anyInt()))
+ .thenReturn(isOrganization);
+ Assert.assertEquals(daoImpl.getAPIResources(limit, retrievingTenantId, sortOrder, expressionNodes).size(),
+ count);
}
}
@@ -122,21 +155,31 @@ public void testGetAPIResources(Integer limit, Integer tenantId, String sortOrde
public Object[][] addAPIResourceData() {
return new Object[][]{
- {"AddAPITest-1", TENANT_ID}
+ {"AddAPITest-1", TENANT_ID, false},
+ {"AddAPITest-1", TENANT_ID, true}
};
}
@Test(dataProvider = "addAPIResourceData", priority = 2)
- public void testAddAPIResource(String postfix, int tenantId) throws Exception {
+ public void testAddAPIResource(String postfix, int tenantId, boolean isOrganization) throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class)) {
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
.thenReturn(getConnection());
+ organizationManagementUtil.when(() -> OrganizationManagementUtil.isOrganization(anyInt()))
+ .thenReturn(isOrganization);
APIResource apiResource = createAPIResource(postfix);
- APIResource createdAPIResource = daoImpl.addAPIResource(apiResource, tenantId);
- Assert.assertNotNull(createdAPIResource);
- Assert.assertTrue(createdAPIResource.getName().contains(postfix));
- Assert.assertNotNull(createdAPIResource.getId());
+ if (!isOrganization) {
+ APIResource createdAPIResource = daoImpl.addAPIResource(apiResource, tenantId);
+ Assert.assertNotNull(createdAPIResource);
+ Assert.assertTrue(createdAPIResource.getName().contains(postfix));
+ Assert.assertNotNull(createdAPIResource.getId());
+ } else {
+ Assert.expectThrows(APIResourceMgtClientException.class, () ->
+ daoImpl.addAPIResource(apiResource, tenantId));
+ }
}
}
@@ -144,18 +187,29 @@ public void testAddAPIResource(String postfix, int tenantId) throws Exception {
public Object[][] getScopesByAPIData() {
// Define your test cases here
return new Object[][]{
- {"GetScopesTest", TENANT_ID, 2},
- {"GetScopesTest2", INVALID_TENANT_ID, 0}
+ {"GetScopesTest", TENANT_ID, TENANT_ID, false, 2},
+ {"GetScopesTest2", INVALID_TENANT_ID, INVALID_TENANT_ID, false, 0},
+ {"GetScopesTest3", TENANT_ID, ORGANIZATION_TENANT_ID, true, 2}
};
}
@Test(dataProvider = "getScopesByAPIData", priority = 3)
- public void testGetScopesByAPI(String name, Integer tenantId, int expected) throws Exception {
+ public void testGetScopesByAPI(String name, Integer rootTenantId, Integer retrievingTenantId,
+ boolean isOrganization, int expected) throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
- String apiId = addAPIResourceToDB(name, getConnection(), tenantId, identityDatabaseUtil).getId();
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class);
+ MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class)) {
+ if (isOrganization) {
+ mockRootOrganizationExtraction(rootTenantId, identityTenantUtil);
+ }
+ String apiId = addAPIResourceToDB(name, getConnection(), rootTenantId, identityDatabaseUtil,
+ organizationManagementUtil).getId();
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
.thenReturn(getConnection());
+ organizationManagementUtil.when(() -> OrganizationManagementUtil.isOrganization(anyInt()))
+ .thenReturn(isOrganization);
Assert.assertEquals(daoImpl.getScopesByAPI(apiId, TENANT_ID).size(), expected);
}
}
@@ -164,6 +218,7 @@ public void testGetScopesByAPI(String name, Integer tenantId, int expected) thro
public Object[][] isAPIResourceExistData() {
return new Object[][]{
{"identifier1", TENANT_ID, true},
+ {"identifier5", TENANT_ID, true},
{"identifier4", INVALID_TENANT_ID, false}
};
}
@@ -171,8 +226,11 @@ public Object[][] isAPIResourceExistData() {
@Test(dataProvider = "isAPIResourceExistData", priority = 4)
public void testIsAPIResourceExist(String identifierPostFix, Integer tenantId, boolean expected) throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
- addAPIResourceToDB(identifierPostFix, getConnection(), tenantId, identityDatabaseUtil);
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class)) {
+ addAPIResourceToDB(identifierPostFix, getConnection(), tenantId, identityDatabaseUtil,
+ organizationManagementUtil);
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
.thenReturn(getConnection());
Assert.assertEquals(daoImpl.isAPIResourceExist(APIRESOURCE_IDENTIFIER + identifierPostFix, TENANT_ID),
@@ -191,10 +249,13 @@ public Object[][] isAPIResourceExistByIdData() {
@Test(dataProvider = "isAPIResourceExistByIdData", priority = 5)
public void testIsAPIResourceExistById(Integer tenantId, boolean expected) throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
-
+ String namePostFix = "testIsAPIResourceExistById";
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class)) {
APIResource createdAPIResource =
- addAPIResourceToDB("testIsAPIResourceExistById", getConnection(), tenantId, identityDatabaseUtil);
+ addAPIResourceToDB(namePostFix, getConnection(), tenantId, identityDatabaseUtil,
+ organizationManagementUtil);
String apiId = createdAPIResource.getId();
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
.thenReturn(getConnection());
@@ -205,21 +266,32 @@ public void testIsAPIResourceExistById(Integer tenantId, boolean expected) throw
@DataProvider
public Object[][] getAPIResourceByIdData() {
return new Object[][]{
- {TENANT_ID, true},
- {INVALID_TENANT_ID, false}
+ {"testGetAPIResourceById", TENANT_ID, TENANT_ID, false, true},
+ {"testGetOrgAPIResourceById", TENANT_ID, ORGANIZATION_TENANT_ID, true, true},
+ {"testGetAPIResourceByIdInvalidTenant", TENANT_ID, INVALID_TENANT_ID, false, false}
};
}
@Test(dataProvider = "getAPIResourceByIdData", priority = 6)
- public void testGetAPIResourceById(Integer tenantId, boolean expected) throws Exception {
+ public void testGetAPIResourceById(String apiNamePostFix, Integer rootTenantId, Integer retrievingTenantId,
+ boolean isOrganization, boolean expected) throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class);
+ MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class)) {
+ if (isOrganization) {
+ mockRootOrganizationExtraction(rootTenantId, identityTenantUtil);
+ }
APIResource createdAPIResource =
- addAPIResourceToDB("testGetAPIResourceById", getConnection(), tenantId, identityDatabaseUtil);
+ addAPIResourceToDB(apiNamePostFix, getConnection(), rootTenantId, identityDatabaseUtil,
+ organizationManagementUtil);
String apiId = createdAPIResource.getId();
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
.thenReturn(getConnection());
- Assert.assertEquals(daoImpl.getAPIResourceById(apiId, TENANT_ID) != null, expected);
+ organizationManagementUtil.when(() -> OrganizationManagementUtil.isOrganization(anyInt()))
+ .thenReturn(isOrganization);
+ Assert.assertEquals(daoImpl.getAPIResourceById(apiId, retrievingTenantId) != null, expected);
}
}
@@ -234,9 +306,11 @@ public Object[][] isScopeExistByIdData() {
@Test(dataProvider = "isScopeExistByIdData", priority = 7)
public void testIsScopeExistById(Integer tenantId, boolean expected) throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
- APIResource createdAPIResource = addAPIResourceToDB("testIsScopeExistById", getConnection(),
- tenantId, identityDatabaseUtil);
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class)) {
+ APIResource createdAPIResource = addAPIResourceToDB("testIsScopeExistById", getConnection(), tenantId,
+ identityDatabaseUtil, organizationManagementUtil);
String scopeId = createdAPIResource.getScopes().get(0).getId();
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
.thenReturn(getConnection());
@@ -248,16 +322,24 @@ public void testIsScopeExistById(Integer tenantId, boolean expected) throws Exce
public Object[][] deleteAPIResourceByIdData() {
return new Object[][]{
- {TENANT_ID, false}
+ {TENANT_ID, false, false},
+ {TENANT_ID, true, false}
};
}
@Test(dataProvider = "deleteAPIResourceByIdData", priority = 8)
- public void testDeleteAPIResourceById(Integer tenantId, boolean expected) throws Exception {
+ public void testDeleteAPIResourceById(Integer tenantId, boolean isOrganization, boolean expected)
+ throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class);
+ MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class)) {
+ if (isOrganization) {
+ mockRootOrganizationExtraction(tenantId, identityTenantUtil);
+ }
String apiId = addAPIResourceToDB("testDeleteAPIResourceById", getConnection(), tenantId,
- identityDatabaseUtil).getId();
+ identityDatabaseUtil, organizationManagementUtil).getId();
Connection connection = getConnection();
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean())).thenReturn(connection);
@@ -266,10 +348,17 @@ public void testDeleteAPIResourceById(Integer tenantId, boolean expected) throws
connection.commit();
return null;
});
- daoImpl.deleteAPIResourceById(apiId, tenantId);
- identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
- .thenReturn(getConnection());
- Assert.assertEquals(daoImpl.isAPIResourceExistById(apiId, tenantId), expected);
+ organizationManagementUtil.when(() -> OrganizationManagementUtil.isOrganization(anyInt()))
+ .thenReturn(isOrganization);
+ if (!isOrganization) {
+ daoImpl.deleteAPIResourceById(apiId, tenantId);
+ identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
+ .thenReturn(getConnection());
+ Assert.assertEquals(daoImpl.isAPIResourceExistById(apiId, tenantId), expected);
+ } else {
+ Assert.expectThrows(APIResourceMgtClientException.class, () ->
+ daoImpl.deleteAPIResourceById(apiId, tenantId));
+ }
}
}
@@ -282,11 +371,14 @@ public Object[][] isScopeExistByNameData() {
}
@Test(dataProvider = "isScopeExistByNameData", priority = 9)
- public void testIsScopeExistByName(Integer tenantId, String scopeName, boolean expected) throws Exception {
-
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
+ public void testIsScopeExistByName(Integer tenantId, String scopeName, boolean expected)
+ throws Exception {
- addAPIResourceToDB(scopeName, getConnection(), tenantId, identityDatabaseUtil);
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class);
+ MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class)) {
+ addAPIResourceToDB(scopeName, getConnection(), tenantId, identityDatabaseUtil, organizationManagementUtil);
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
.thenReturn(getConnection());
@@ -296,9 +388,8 @@ public void testIsScopeExistByName(Integer tenantId, String scopeName, boolean e
@DataProvider
public Object[][] getScopeByNameAndTenantIdData() {
- String scopeName = "testGetScopeByNameAndTenantId";
return new Object[][]{
- {TENANT_ID, scopeName, scopeName}
+ {TENANT_ID, "testGetScopeByNameAndTenantId", "testGetScopeByNameAndTenantId"}
};
}
@@ -306,9 +397,10 @@ public Object[][] getScopeByNameAndTenantIdData() {
public void testGetScopeByNameAndTenantId(Integer tenantId, String scopeName, String expectedName)
throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
-
- addAPIResourceToDB(scopeName, getConnection(), tenantId, identityDatabaseUtil);
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class)) {
+ addAPIResourceToDB(scopeName, getConnection(), tenantId, identityDatabaseUtil, organizationManagementUtil);
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
.thenReturn(getConnection());
Scope scope = daoImpl.getScopeByNameAndTenantId(TEST_SCOPE_1 + scopeName, tenantId);
@@ -316,16 +408,27 @@ public void testGetScopeByNameAndTenantId(Integer tenantId, String scopeName, St
}
}
- @Test(priority = 11)
- public void testAddScopes() throws Exception {
+ @DataProvider
+ public Object[][] addScopes() {
+ return new Object[][]{
+ {TENANT_ID, TENANT_ID, false, "testAddScopes", "scope1", "scope2"},
+ {TENANT_ID, ORGANIZATION_TENANT_ID, true, "testAddScopesOrg", "scope1", "scope2"}
+ };
+ }
+
+ @Test(dataProvider = "addScopes", priority = 11)
+ public void testAddScopes(Integer rootTenantId, Integer addingTenantId, boolean isOrganization,
+ String apiNamePostFix, String scope1, String scope2) throws Exception {
try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
- MockedStatic identityTenantUtil = mockStatic(IdentityTenantUtil.class)) {
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class)) {
APIResource apiResource =
- addAPIResourceToDB("testAddScopes", getConnection(), TENANT_ID, identityDatabaseUtil);
+ addAPIResourceToDB(apiNamePostFix, getConnection(), rootTenantId, identityDatabaseUtil,
+ organizationManagementUtil);
String apiId = apiResource.getId();
- List scopes = Arrays.asList(createScope("scope1"), createScope("scope2"));
+ List scopes = Arrays.asList(createScope(scope1), createScope(scope2));
Connection connection = getConnection();
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean())).thenReturn(connection);
@@ -334,23 +437,41 @@ public void testAddScopes() throws Exception {
connection.commit();
return null;
});
- daoImpl.addScopes(scopes, apiId, TENANT_ID);
-
- for (Scope scope : scopes) {
- identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
- .thenReturn(getConnection());
- Assert.assertTrue(daoImpl.isScopeExistByName(scope.getName(), TENANT_ID));
+ organizationManagementUtil.when(() -> OrganizationManagementUtil.isOrganization(anyInt()))
+ .thenReturn(isOrganization);
+ if (!isOrganization) {
+ daoImpl.addScopes(scopes, apiId, addingTenantId);
+ for (Scope scope : scopes) {
+ identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
+ .thenReturn(getConnection());
+ Assert.assertTrue(daoImpl.isScopeExistByName(scope.getName(), rootTenantId));
+ }
+ } else {
+ Assert.expectThrows(APIResourceMgtClientException.class, () ->
+ daoImpl.addScopes(scopes, apiId, addingTenantId));
}
}
}
- @Test(priority = 12)
- public void testDeleteAllScopes() throws Exception {
+ @DataProvider
+ public Object[][] deleteAllScopes() {
+ return new Object[][]{
+ {TENANT_ID, TENANT_ID, false, "testDeleteAllScopes"},
+ {TENANT_ID, ORGANIZATION_TENANT_ID, true, "testDeleteAllOrgScopes"}
+ };
+ }
+
+ @Test(dataProvider = "deleteAllScopes", priority = 12)
+ public void testDeleteAllScopes(Integer rootTenantId, Integer deletingTenantId, boolean isOrganization,
+ String apiNamePostFix) throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class)) {
APIResource apiResource =
- addAPIResourceToDB("testDeleteAllScopes", getConnection(), TENANT_ID, identityDatabaseUtil);
+ addAPIResourceToDB(apiNamePostFix, getConnection(), rootTenantId, identityDatabaseUtil,
+ organizationManagementUtil);
String apiId = apiResource.getId();
Connection connection = getConnection();
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean())).thenReturn(connection);
@@ -359,23 +480,41 @@ public void testDeleteAllScopes() throws Exception {
connection.commit();
return null;
});
-
- daoImpl.deleteAllScopes(apiId, TENANT_ID);
- for (Scope scope : apiResource.getScopes()) {
- identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
- .thenReturn(getConnection());
- Assert.assertFalse(daoImpl.isScopeExistById(scope.getId(), TENANT_ID));
+ organizationManagementUtil.when(() -> OrganizationManagementUtil.isOrganization(anyInt()))
+ .thenReturn(isOrganization);
+ if (!isOrganization) {
+ daoImpl.deleteAllScopes(apiId, deletingTenantId);
+ for (Scope scope : apiResource.getScopes()) {
+ identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
+ .thenReturn(getConnection());
+ Assert.assertFalse(daoImpl.isScopeExistById(scope.getId(), TENANT_ID));
+ }
+ } else {
+ Assert.expectThrows(APIResourceMgtClientException.class, () ->
+ daoImpl.deleteAllScopes(apiId, deletingTenantId));
}
}
}
- @Test(priority = 13)
- public void testDeleteScope() throws Exception {
+ @DataProvider
+ public Object[][] deleteScope() {
+ return new Object[][]{
+ {TENANT_ID, TENANT_ID, false, "testDeleteScope"},
+ {TENANT_ID, ORGANIZATION_TENANT_ID, true, "testDeleteOrgScope"}
+ };
+ }
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
+ @Test(dataProvider = "deleteScope", priority = 13)
+ public void testDeleteScope(Integer rootTenantId, Integer deletingTenantId, boolean isOrganization,
+ String apiNamePostFix) throws Exception {
+
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class)) {
APIResource apiResource =
- addAPIResourceToDB("testDeleteScope", getConnection(), TENANT_ID, identityDatabaseUtil);
+ addAPIResourceToDB(apiNamePostFix, getConnection(), rootTenantId, identityDatabaseUtil,
+ organizationManagementUtil);
String apiId = apiResource.getId();
String scopeName = apiResource.getScopes().get(0).getName(); // Assuming there's at least one scope
@@ -387,13 +526,20 @@ public void testDeleteScope() throws Exception {
return null;
});
- // Testing the deleteScope method with the created API resource's ID and scope ID
- daoImpl.deleteScope(apiId, scopeName, TENANT_ID);
+ organizationManagementUtil.when(() -> OrganizationManagementUtil.isOrganization(anyInt()))
+ .thenReturn(isOrganization);
+ if (!isOrganization) {
+ // Testing the deleteScope method with the created API resource's ID and scope ID
+ daoImpl.deleteScope(apiId, scopeName, deletingTenantId);
- // Checking whether the scope is deleted
- identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
- .thenReturn(getConnection());
- Assert.assertFalse(daoImpl.isScopeExistByName(scopeName, TENANT_ID));
+ // Checking whether the scope is deleted
+ identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
+ .thenReturn(getConnection());
+ Assert.assertFalse(daoImpl.isScopeExistByName(scopeName, deletingTenantId));
+ } else {
+ Assert.expectThrows(APIResourceMgtClientException.class, () ->
+ daoImpl.deleteScope(apiId, scopeName, deletingTenantId));
+ }
}
}
@@ -402,45 +548,55 @@ public void testDeleteScope() throws Exception {
public Object[][] updateAPIResourceScopeAddition() {
return new Object[][]{
- {APIResourceManagementConstants.BUSINESS_TYPE},
- {APIResourceManagementConstants.SYSTEM_TYPE},
- {ORGANIZATION_TYPE},
- {TENANT_TYPE},
- {CONSOLE_ORG_LEVEL_TYPE}
+ {APIResourceManagementConstants.BUSINESS_TYPE, 2},
+ {APIResourceManagementConstants.SYSTEM_TYPE, 2},
+ {ORGANIZATION_TYPE, 2},
+ {TENANT_TYPE, 2},
+ {CONSOLE_ORG_LEVEL_TYPE, 2}
};
}
@Test(dataProvider = "updateAPIResourceScopeAddition", priority = 14)
- public void testUpdateAPIResourceScopeAddition(String type) throws Exception {
+ public void testUpdateAPIResourceScopeAddition(String type, int expectedValue)
+ throws Exception {
// Add API resource to database.
String apiNamePostFix = "update-scope-addition-test";
List scopes = new ArrayList<>();
scopes.add(createScope("test_scope_1_" + apiNamePostFix));
scopes.add(createScope("test_scope_2_" + apiNamePostFix));
- APIResource apiResource = addAPIResourceToDB(apiNamePostFix, scopes, type, getConnection(), TENANT_ID);
+ try (MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class)) {
+ // Following mocks are in action when the registered API resources are extracted from the database. This
+ // will not affect to the update operation since the update operation does not support in the organization
+ // level.
+ APIResource apiResource = addAPIResourceToDB(apiNamePostFix, scopes, type, getConnection(), TENANT_ID,
+ organizationManagementUtil);
+
+ // Validate scopes count before update.
+ validateScopesCount(apiResource.getId(), expectedValue);
+
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
+ identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
+ .thenReturn(getConnection());
- // Validate scopes count before update.
- validateScopesCount(apiResource.getId(), 2);
+ Scope newScope = createScope("test_scope_3_" + apiNamePostFix);
+ apiResource.getScopes().add(newScope);
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
- identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
- .thenReturn(getConnection());
- Scope newScope = createScope("test_scope_3_" + apiNamePostFix);
- apiResource.getScopes().add(newScope);
+ List addedScopes = new ArrayList<>();
+ addedScopes.add(newScope);
- List addedScopes = new ArrayList<>();
- addedScopes.add(newScope);
+ // Update API resource with a new scope.
+ daoImpl.updateAPIResource(apiResource, addedScopes, Collections.emptyList(), TENANT_ID);
+ }
- // Update API resource with a new scope.
- daoImpl.updateAPIResource(apiResource, addedScopes, Collections.emptyList(), TENANT_ID);
- }
+ // Validate updated scopes count.
+ validateScopesCount(apiResource.getId(), 3);
- // Validate updated scopes count.
- validateScopesCount(apiResource.getId(), 3);
+ // Delete API resource from database.
+ deleteAPIResourceFromDB(apiResource.getId(), TENANT_ID);
+ }
- // Delete API resource from database.
- deleteAPIResourceFromDB(apiResource.getId(), TENANT_ID);
}
/**
@@ -512,8 +668,11 @@ private static APIResource createAPIResource(String postFix, List scopes,
*/
private APIResource addAPIResourceToDB(String namePostFix, Connection connection, int tenantId) throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
- return addAPIResourceToDB(namePostFix, connection, tenantId, identityDatabaseUtil);
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class)) {
+ return addAPIResourceToDB(namePostFix, connection, tenantId, identityDatabaseUtil,
+ organizationManagementUtil);
}
}
@@ -528,7 +687,9 @@ private APIResource addAPIResourceToDB(String namePostFix, Connection connection
* @throws Exception Error when adding API resource.
*/
private APIResource addAPIResourceToDB(String namePostFix, Connection connection, int tenantId,
- MockedStatic identityDatabaseUtil) throws Exception {
+ MockedStatic identityDatabaseUtil,
+ MockedStatic organizationManagementUtil)
+ throws Exception {
APIResource apiResource = createAPIResource(namePostFix);
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean())).thenReturn(connection);
@@ -537,6 +698,8 @@ private APIResource addAPIResourceToDB(String namePostFix, Connection connection
connection.commit();
return null;
});
+ organizationManagementUtil.when(() -> OrganizationManagementUtil.isOrganization(anyInt()))
+ .thenReturn(false);
return daoImpl.addAPIResource(apiResource, tenantId);
}
@@ -552,7 +715,9 @@ private APIResource addAPIResourceToDB(String namePostFix, Connection connection
* @throws Exception Error when adding API resource.
*/
private APIResource addAPIResourceToDB(String namePostFix, List scopes, String type, Connection connection,
- int tenantId) throws Exception {
+ int tenantId,
+ MockedStatic organizationManagementUtil)
+ throws Exception {
try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
APIResource apiResource = createAPIResource(namePostFix, scopes, type);
@@ -562,6 +727,8 @@ private APIResource addAPIResourceToDB(String namePostFix, List scopes, S
connection.commit();
return null;
});
+ organizationManagementUtil.when(() -> OrganizationManagementUtil.isOrganization(anyInt()))
+ .thenReturn(false);
return daoImpl.addAPIResource(apiResource, tenantId);
}
@@ -663,4 +830,26 @@ private static String getFilePath() {
}
throw new IllegalArgumentException("DB Script file name cannot be empty.");
}
+
+ /**
+ * Mock the root organization extraction when the APIs need to be extracted from the organization level.
+ *
+ * @param rootTenantId Root tenant ID of the sub organization.
+ * @param identityTenantUtil Mocked IdentityTenantUtil to get the tenant domains.
+ * @throws OrganizationManagementException Error when extracting the root organization.
+ */
+ private static void mockRootOrganizationExtraction(Integer rootTenantId,
+ MockedStatic identityTenantUtil)
+ throws OrganizationManagementException {
+
+ identityTenantUtil.when(() -> IdentityTenantUtil.getTenantDomain(anyInt())).thenReturn("tenant1");
+ OrganizationManager organizationManager = mock(OrganizationManager.class);
+ APIResourceManagementServiceComponentHolder.getInstance().setOrganizationManager(organizationManager);
+ lenient().when(organizationManager.resolveOrganizationId(anyString())).thenReturn("org-id-1234");
+ lenient().when(organizationManager.getPrimaryOrganizationId("org-id-1234"))
+ .thenReturn("prim-org-id-1234");
+ lenient().when(organizationManager.resolveTenantDomain("prim-org-id-1234"))
+ .thenReturn("prim-tenant");
+ identityTenantUtil.when(() -> IdentityTenantUtil.getTenantId(anyString())).thenReturn(rootTenantId);
+ }
}
diff --git a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/test/java/org/wso2/carbon/identity/api/resource/mgt/dao/CacheBackedAPIResourceManagementDAOTest.java b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/test/java/org/wso2/carbon/identity/api/resource/mgt/dao/CacheBackedAPIResourceManagementDAOTest.java
index a6ea03d36fb8..e24909888807 100644
--- a/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/test/java/org/wso2/carbon/identity/api/resource/mgt/dao/CacheBackedAPIResourceManagementDAOTest.java
+++ b/components/api-resource-mgt/org.wso2.carbon.identity.api.resource.mgt/src/test/java/org/wso2/carbon/identity/api/resource/mgt/dao/CacheBackedAPIResourceManagementDAOTest.java
@@ -35,6 +35,7 @@
import org.wso2.carbon.identity.core.model.ExpressionNode;
import org.wso2.carbon.identity.core.util.IdentityDatabaseUtil;
import org.wso2.carbon.identity.core.util.IdentityTenantUtil;
+import org.wso2.carbon.identity.organization.management.service.util.OrganizationManagementUtil;
import java.nio.file.Paths;
import java.sql.Connection;
@@ -47,6 +48,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mockStatic;
public class CacheBackedAPIResourceManagementDAOTest {
@@ -101,9 +103,13 @@ public Object[][] getAPIResourcesCountData() {
public void testGetAPIResourcesCount(Integer tenantId, List expressionNodes, int expected)
throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class)) {
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
.thenReturn(getConnection());
+ organizationManagementUtil.when(() -> OrganizationManagementUtil.isOrganization(anyInt()))
+ .thenReturn(false);
Assert.assertEquals(daoImpl.getAPIResourcesCount(tenantId, expressionNodes).intValue(), expected);
}
}
@@ -121,9 +127,13 @@ public Object[][] getAPIResourcesData() {
public void testGetAPIResources(Integer limit, Integer tenantId, String sortOrder,
List expressionNodes, int count) throws Exception {
- try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class)) {
+ try (MockedStatic identityDatabaseUtil = mockStatic(IdentityDatabaseUtil.class);
+ MockedStatic organizationManagementUtil =
+ mockStatic(OrganizationManagementUtil.class)) {
identityDatabaseUtil.when(() -> IdentityDatabaseUtil.getDBConnection(anyBoolean()))
.thenReturn(getConnection());
+ organizationManagementUtil.when(() -> OrganizationManagementUtil.isOrganization(anyInt()))
+ .thenReturn(false);
Assert.assertEquals(daoImpl.getAPIResources(limit, tenantId, sortOrder, expressionNodes).size(), count);
}
}
@@ -139,9 +149,13 @@ public Object[][] addAPIResourceData() {
@Test(dataProvider = "addAPIResourceData", priority = 2)
public void testAddAPIResource(String postfix, int tenantId) throws Exception {
- try (MockedStatic