Skip to content

Commit

Permalink
Merge branch 'wso2:master' into add-cutsom-fed-auth-mgt-support
Browse files Browse the repository at this point in the history
  • Loading branch information
Thisara-Welmilla authored Nov 21, 2024
2 parents 7c89b80 + 307d331 commit a122919
Show file tree
Hide file tree
Showing 288 changed files with 5,039 additions and 640 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.10-SNAPSHOT</version>
<version>7.6.18-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>

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.10-SNAPSHOT</version>
<version>7.6.18-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.10-SNAPSHOT</version>
<version>7.6.18-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.10-SNAPSHOT</version>
<version>7.6.18-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.10-SNAPSHOT</version>
<version>7.6.18-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>org.wso2.carbon.identity.api.resource.mgt</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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," +
Expand Down Expand Up @@ -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," +
Expand All @@ -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" +
Expand Down Expand Up @@ -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 = ?";
Expand Down
Loading

0 comments on commit a122919

Please sign in to comment.