Skip to content

Commit

Permalink
Merge branch 'wso2:master' into add-cutsom-local-auth-mgt-support-dao…
Browse files Browse the repository at this point in the history
…-new
  • Loading branch information
Thisara-Welmilla authored Nov 29, 2024
2 parents 50d68e1 + ae33baf commit 9098395
Show file tree
Hide file tree
Showing 807 changed files with 2,782 additions and 94,720 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>action-mgt</artifactId>
<version>7.6.5-SNAPSHOT</version>
<version>7.7.8-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,8 @@ public ActionExecutionStatus<?> execute(ActionType actionType, Map<String, Objec
DIAGNOSTIC_LOGGER.logActionInitiation(action);
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();
}
}
Expand All @@ -144,10 +142,8 @@ public ActionExecutionStatus<?> execute(ActionType actionType, String[] actionId
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();
}
}
Expand Down Expand Up @@ -191,13 +187,13 @@ private Action getActionByActionId(ActionType actionType, String actionId, Strin
}

private List<Action> 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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>action-mgt</artifactId>
<version>7.6.5-SNAPSHOT</version>
<version>7.7.8-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
/*
* 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.Test;
import org.wso2.carbon.context.CarbonContext;
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.central.log.mgt.utils.LoggerUtils;
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;

/**
* Unit test class for ActionManagementAuditLogger class.
*/
@WithCarbonHome
public class ActionManagementAuditLoggerTest {

private ActionManagementAuditLogger auditLogger;
private Action action;
private CarbonContext carbonContext;
private MockedStatic<CarbonContext> carbonContextMockedStatic;
private MockedStatic<IdentityUtil> identityUtil;
private MockedStatic<IdentityTenantUtil> identityTenantUtil;
private MockedStatic<LoggerUtils> 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();

// Mock Action
action = mock(Action.class);
when(action.getId()).thenReturn("action-test-id");
when(action.getName()).thenReturn("Test Action");
when(action.getDescription()).thenReturn("This is a test action.");
when(action.getType()).thenReturn(Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN);
Map<String, String> authProperties = new HashMap<>();
authProperties.put("accessToken", "W*********t");
Authentication auth = new Authentication.AuthenticationBuilder().type(
Authentication.Type.BEARER).properties(authProperties).build();
when(action.getEndpoint()).thenReturn(new EndpointConfig.EndpointConfigBuilder().
uri("https://test.com").
authentication(auth).build());
when(action.getStatus()).thenReturn(Action.Status.ACTIVE);
}

@AfterMethod
public void tearDown() {

auditLogger = null;
action = null;
carbonContextMockedStatic.close();
identityUtil.close();
identityTenantUtil.close();
loggerUtilsMockedStatic.close();
}

@Test
public void testPrintAuditLogWithAction() throws NoSuchFieldException, IllegalAccessException {

ActionManagementAuditLogger.Operation operation = ActionManagementAuditLogger.Operation.ADD;
auditLogger.printAuditLog(operation, action);
AuditLog.AuditLogBuilder capturedArg = captureTriggerAuditLogEventArgs();

Assert.assertNotNull(capturedArg);
assertActionData(capturedArg);
assertAuditLoggerData(capturedArg, ADD_ACTION);
}

@Test
public void testPrintAuditLogWithActionId() throws NoSuchFieldException, IllegalAccessException {

ActionManagementAuditLogger.Operation operation = ActionManagementAuditLogger.Operation.UPDATE;
auditLogger.printAuditLog(operation, action.getId(), action);
AuditLog.AuditLogBuilder capturedArg = captureTriggerAuditLogEventArgs();

Assert.assertNotNull(capturedArg);
assertActionData(capturedArg);
assertAuditLoggerData(capturedArg, UPDATE_ACTION);
}

@Test
public void testPrintAuditLogWithActionTypeAndId() throws NoSuchFieldException, IllegalAccessException {

ActionManagementAuditLogger.Operation operation = ActionManagementAuditLogger.Operation.DELETE;
auditLogger.printAuditLog(operation, action.getType().name(), action.getId());
AuditLog.AuditLogBuilder capturedArg = captureTriggerAuditLogEventArgs();

Assert.assertNotNull(capturedArg);
Assert.assertEquals(extractMapByField("ActionId", capturedArg), "action-test-id");
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<AuditLog.AuditLogBuilder> 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<String, Object> dataMap = (Map<String, Object>) dataField.get(auditLogBuilder);
return (String) dataMap.get(fieldName);
}

/**
* Extract the specific field name from the provided map.
*
* @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 extractEndpointMapByField(String fieldName, AuditLog.AuditLogBuilder auditLogBuilder)
throws NoSuchFieldException, IllegalAccessException {

Field dataField = AuditLog.AuditLogBuilder.class.getDeclaredField("data");
dataField.setAccessible(true);
Map<String, Object> dataMap = (Map<String, Object>) dataField.get(auditLogBuilder);
Map<String, Object> endpointConfigMap = (Map<String, Object>) dataMap.get("EndpointConfiguration");
return (String) endpointConfigMap.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.
* @throws NoSuchFieldException if the provided field does not exist.
* @throws IllegalAccessException if the provided field is not accessible.
*/
private void assertActionData(AuditLog.AuditLogBuilder auditLogBuilder)
throws NoSuchFieldException, IllegalAccessException {

Assert.assertEquals(extractMapByField("ActionId", auditLogBuilder), "action-test-id");
Assert.assertEquals(extractMapByField("ActionName", auditLogBuilder), "Test Action");
Assert.assertEquals(extractMapByField("ActionType", auditLogBuilder),
Action.ActionTypes.PRE_ISSUE_ACCESS_TOKEN.getActionType());
Assert.assertEquals(extractMapByField("ActionStatus", auditLogBuilder), Action.Status.ACTIVE.value());
Assert.assertEquals(extractMapByField("ActionDescription", auditLogBuilder),
"This is a test action.");
Assert.assertEquals(extractEndpointMapByField("AuthenticationScheme", auditLogBuilder),
Authentication.Type.BEARER.getName());
Assert.assertEquals(extractEndpointMapByField("EndpointUri", auditLogBuilder),
"https://test.com");
}

/**
* 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;
}
}
}

2 changes: 1 addition & 1 deletion components/action-mgt/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<parent>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>identity-framework</artifactId>
<version>7.6.5-SNAPSHOT</version>
<version>7.7.8-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<parent>
<groupId>org.wso2.carbon.identity.framework</groupId>
<artifactId>api-resource-mgt</artifactId>
<version>7.6.5-SNAPSHOT</version>
<version>7.7.8-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

Expand Down
Loading

0 comments on commit 9098395

Please sign in to comment.