diff --git a/pom.xml b/pom.xml index b384ead7..224a62bc 100644 --- a/pom.xml +++ b/pom.xml @@ -64,6 +64,12 @@ junit-platform-launcher ${junit-platform-version} + + org.mockito + mockito-inline + 5.2.0 + test + ch.qos.logback diff --git a/src/main/java/de/tum/cit/ase/ares/api/architecture/java/FileHandlerConstants.java b/src/main/java/de/tum/cit/ase/ares/api/architecture/java/FileHandlerConstants.java index ddc9776e..c33a667d 100644 --- a/src/main/java/de/tum/cit/ase/ares/api/architecture/java/FileHandlerConstants.java +++ b/src/main/java/de/tum/cit/ase/ares/api/architecture/java/FileHandlerConstants.java @@ -21,6 +21,7 @@ public class FileHandlerConstants { public static final Path ARCHUNIT_COMMAND_EXECUTION_METHODS = FileTools.resolveOnResources("templates", "architecture" , "java", "archunit", "methods", "command-execution-methods.txt"); public static final Path ARCHUNIT_THREAD_MANIPULATION_METHODS = FileTools.resolveOnResources("templates", "architecture" , "java", "archunit", "methods", "thread-manipulation-methods.txt"); public static final Path ARCHUNIT_SERIALIZATION_METHODS = FileTools.resolveOnResources("templates", "architecture" , "java", "archunit", "methods", "serializable-methods.txt"); + public static final Path ARCHUNIT_CLASSLOADER_METHODS = FileTools.resolveOnResources("templates", "architecture" , "java", "archunit", "methods", "classloader-methods.txt"); // // diff --git a/src/main/java/de/tum/cit/ase/ares/api/architecture/java/archunit/JavaArchUnitSecurityTestCase.java b/src/main/java/de/tum/cit/ase/ares/api/architecture/java/archunit/JavaArchUnitSecurityTestCase.java index 4950e19c..0895fb98 100644 --- a/src/main/java/de/tum/cit/ase/ares/api/architecture/java/archunit/JavaArchUnitSecurityTestCase.java +++ b/src/main/java/de/tum/cit/ase/ares/api/architecture/java/archunit/JavaArchUnitSecurityTestCase.java @@ -1,7 +1,6 @@ package de.tum.cit.ase.ares.api.architecture.java.archunit; // - import com.tngtech.archunit.core.domain.JavaClasses; import de.tum.cit.ase.ares.api.architecture.java.JavaArchitecturalTestCaseSupported; import de.tum.cit.ase.ares.api.policy.SecurityPolicy.PackagePermission; @@ -51,7 +50,6 @@ private JavaArchUnitSecurityTestCase(@Nonnull Builder builder) { this.javaArchitectureTestCaseSupported = builder.javaArchitectureTestCaseSupported; this.allowedPackages = builder.allowedPackages; } - // // diff --git a/src/main/java/de/tum/cit/ase/ares/api/architecture/java/archunit/JavaArchUnitTestCaseCollection.java b/src/main/java/de/tum/cit/ase/ares/api/architecture/java/archunit/JavaArchUnitTestCaseCollection.java index 7b681d9a..7d331ab1 100644 --- a/src/main/java/de/tum/cit/ase/ares/api/architecture/java/archunit/JavaArchUnitTestCaseCollection.java +++ b/src/main/java/de/tum/cit/ase/ares/api/architecture/java/archunit/JavaArchUnitTestCaseCollection.java @@ -158,4 +158,11 @@ public boolean test(JavaClass javaClass) { FileHandlerConstants.ARCHUNIT_SERIALIZATION_METHODS ); // + + // + public static final ArchRule NO_CLASSES_SHOULD_USE_CLASSLOADERS = createNoClassShouldHaveMethodRule( + "uses ClassLoaders", + FileHandlerConstants.ARCHUNIT_CLASSLOADER_METHODS + ); + // } \ No newline at end of file diff --git a/src/main/resources/de/tum/cit/ase/ares/api/templates/architecture/java/archunit/methods/classloader-methods.txt b/src/main/resources/de/tum/cit/ase/ares/api/templates/architecture/java/archunit/methods/classloader-methods.txt new file mode 100644 index 00000000..4407c211 --- /dev/null +++ b/src/main/resources/de/tum/cit/ase/ares/api/templates/architecture/java/archunit/methods/classloader-methods.txt @@ -0,0 +1 @@ +java.lang.ClassLoader \ No newline at end of file diff --git a/src/main/resources/de/tum/cit/ase/ares/api/templates/architecture/java/archunit/methods/reflection-methods.txt b/src/main/resources/de/tum/cit/ase/ares/api/templates/architecture/java/archunit/methods/reflection-methods.txt index 2cbb0495..1be946ce 100644 --- a/src/main/resources/de/tum/cit/ase/ares/api/templates/architecture/java/archunit/methods/reflection-methods.txt +++ b/src/main/resources/de/tum/cit/ase/ares/api/templates/architecture/java/archunit/methods/reflection-methods.txt @@ -74,6 +74,7 @@ java.lang.Class.getDeclaringClass() java.lang.ClassLoader.getParent() java.lang.ClassLoader.getSystemClassLoader() java.lang.ClassLoader.getPlatformClassLoader() +java.lang.ClassLoader java.lang.Module.addReads(java.lang.Module) java.lang.Module.getResourceAsStream(java.lang.String) java.lang.Module.addExports(java.lang.String, java.lang.Module) diff --git a/src/main/resources/de/tum/cit/ase/ares/api/templates/architecture/java/archunit/methods/thread-manipulation-methods.txt b/src/main/resources/de/tum/cit/ase/ares/api/templates/architecture/java/archunit/methods/thread-manipulation-methods.txt index f0d9c7a4..776cf9bc 100644 --- a/src/main/resources/de/tum/cit/ase/ares/api/templates/architecture/java/archunit/methods/thread-manipulation-methods.txt +++ b/src/main/resources/de/tum/cit/ase/ares/api/templates/architecture/java/archunit/methods/thread-manipulation-methods.txt @@ -149,6 +149,7 @@ java.util.concurrent.DelayQueue.take() java.util.concurrent.ExecutorService.close() java.util.concurrent.ForkJoinPool.managedBlock(java.util.concurrent.ForkJoinPool$ManagedBlocker) java.util.concurrent.ForkJoinPool.close() +java.util.concurrent.ForkJoinPool java.util.concurrent.ForkJoinTask.inForkJoinPool() java.util.concurrent.ForkJoinTask.fork() java.util.concurrent.ForkJoinTask.getPool() diff --git a/src/test/java/de/tum/cit/ase/ares/api/aop/JavaAOPModeTest.java b/src/test/java/de/tum/cit/ase/ares/api/aop/JavaAOPModeTest.java new file mode 100644 index 00000000..5a71d37d --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/aop/JavaAOPModeTest.java @@ -0,0 +1,124 @@ +package de.tum.cit.ase.ares.api.aop; + +import de.tum.cit.ase.ares.api.aop.java.JavaAOPMode; +import de.tum.cit.ase.ares.api.util.FileTools; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import java.lang.reflect.Method; +import java.nio.file.Path; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class JavaAOPModeTest { + + private static final int SETUP_OPTIONS_COUNT = 2; + /** + * Expected number of files to copy for instrumentation mode. + * This includes: + * - [List the specific files or types of files expected] + */ + private static final int INSTRUMENTATION_FILES_COUNT = 13; + private static final int INSTRUMENTATION_VALUES_COUNT = 12; + + /** + * Expected number of files to copy for AspectJ mode. + * This includes: + * - [List the specific files or types of files expected] + */ + private static final int ASPECTJ_FILES_COUNT = 2; + private static final int ASPECTJ_VALUES_COUNT = 2; + + private static String TEST_PACKAGE = "com.example"; + private static String TEST_MAIN_CLASS = "MainClass"; + private static String[] EXPECTED_ARRAY = {"mocked", "array"}; + + private JavaAOPMode instrumentationMode; + private JavaAOPMode aspectjMode; + + @BeforeEach + void setUp() { + instrumentationMode = JavaAOPMode.INSTRUMENTATION; + aspectjMode = JavaAOPMode.ASPECTJ; + } + + @Test + void testEnumValues() { + JavaAOPMode[] modes = JavaAOPMode.values(); + assertEquals(SETUP_OPTIONS_COUNT, modes.length); + assertTrue(Arrays.asList(modes).contains(JavaAOPMode.INSTRUMENTATION)); + assertTrue(Arrays.asList(modes).contains(JavaAOPMode.ASPECTJ)); + } + + @Test + void testFilesToCopy_InstrumentationMode() { + try (MockedStatic mockedFileTools = mockStatic(FileTools.class)) { + mockedFileTools + .when(() -> FileTools.resolveOnResources(any(String[].class))) + .thenReturn(mock(Path.class)); + instrumentationMode.filesToCopy(); + mockedFileTools + .verify(() -> FileTools.resolveOnResources(any(String[].class)), + times(INSTRUMENTATION_FILES_COUNT) + ); + } + } + + @Test + void testFilesToCopy_AspectJMode() { + try (MockedStatic mockedFileTools = mockStatic(FileTools.class)) { + mockedFileTools + .when(() -> FileTools.resolveOnResources(any(String[].class))) + .thenReturn(mock(Path.class)); + aspectjMode.filesToCopy(); + mockedFileTools + .verify(() -> FileTools.resolveOnResources(any(String[].class)), + times(ASPECTJ_FILES_COUNT) + ); + } + } + + @Test + void testFileValues_InstrumentationMode() { + try (MockedStatic mockedFileTools = mockStatic(FileTools.class)) { + mockedFileTools + .when(() -> FileTools.generatePackageNameArray(anyString(), anyInt())) + .thenReturn(EXPECTED_ARRAY); + instrumentationMode.fileValues(TEST_PACKAGE, TEST_MAIN_CLASS); + mockedFileTools + .verify(() -> FileTools.generatePackageNameArray(anyString(), anyInt()), + times(INSTRUMENTATION_VALUES_COUNT) + ); + } + } + + @Test + void testFileValues_AspectJMode() { + try (MockedStatic mockedFileTools = mockStatic(FileTools.class)) { + mockedFileTools + .when(() -> FileTools.generatePackageNameArray(anyString(), anyInt())) + .thenReturn(EXPECTED_ARRAY); + aspectjMode.fileValues(TEST_PACKAGE, TEST_MAIN_CLASS); + mockedFileTools + .verify(() -> FileTools.generatePackageNameArray(anyString(), anyInt()), + times(ASPECTJ_VALUES_COUNT) + ); + } + } + + @Test + void testReset() { + try { + ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + Class settingsClass = Class.forName("de.tum.cit.ase.ares.api.aop.java.JavaSecurityTestCaseSettings", true, classLoader); + Method resetMethod = settingsClass.getDeclaredMethod("reset"); + resetMethod.setAccessible(true); + resetMethod.invoke(null); + } catch (Exception e) { + fail("Exception should not have been thrown: " + e.getMessage()); + } + } +} \ No newline at end of file diff --git a/src/test/java/de/tum/cit/ase/ares/api/aop/JavaSecurityTestCaseSettingsTest.java b/src/test/java/de/tum/cit/ase/ares/api/aop/JavaSecurityTestCaseSettingsTest.java new file mode 100644 index 00000000..9a35c700 --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/aop/JavaSecurityTestCaseSettingsTest.java @@ -0,0 +1,65 @@ +package de.tum.cit.ase.ares.api.aop; + +import de.tum.cit.ase.ares.api.aop.java.JavaSecurityTestCaseSettings; +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import static org.junit.jupiter.api.Assertions.*; + +class JavaSecurityTestCaseSettingsTest { + + @Test + void testConstructorThrowsException() { + try { + Constructor constructor = JavaSecurityTestCaseSettings.class.getDeclaredConstructor(); + constructor.setAccessible(true); + constructor.newInstance(); + fail("Expected SecurityException to be thrown"); + } catch (InvocationTargetException e) { + assertInstanceOf(SecurityException.class, e.getCause()); + assertEquals("Ares Security Error (Reason: Ares-Code; Stage: Creation): JavaSecurityTestCaseSettings is a utility class and should not be instantiated.", e.getCause().getMessage()); + } catch (Exception e) { + fail("Unexpected exception: " + e); + } + } + + @Test + void testResetMethod() { + try { + Field aopModeField = JavaSecurityTestCaseSettings.class.getDeclaredField("aopMode"); + Field allowedListedClassesField = JavaSecurityTestCaseSettings.class.getDeclaredField("allowedListedClasses"); + Field portsAllowedToBeConnectedToField = JavaSecurityTestCaseSettings.class.getDeclaredField("portsAllowedToBeConnectedTo"); + + aopModeField.setAccessible(true); + allowedListedClassesField.setAccessible(true); + portsAllowedToBeConnectedToField.setAccessible(true); + + aopModeField.set(null, "test"); + allowedListedClassesField.set(null, new String[]{"testClass"}); + portsAllowedToBeConnectedToField.set(null, new int[]{8080}); + + Method resetMethod = JavaSecurityTestCaseSettings.class.getDeclaredMethod("reset"); + resetMethod.setAccessible(true); + resetMethod.invoke(null); + + assertNull(aopModeField.get(null)); + assertNull(allowedListedClassesField.get(null)); + assertNull(portsAllowedToBeConnectedToField.get(null)); + + Field pathsAllowedToBeReadField = JavaSecurityTestCaseSettings.class.getDeclaredField("pathsAllowedToBeRead"); + pathsAllowedToBeReadField.setAccessible(true); + assertNull(pathsAllowedToBeReadField.get(null)); + + Field pathsAllowedToBeOverwrittenField = JavaSecurityTestCaseSettings.class.getDeclaredField("pathsAllowedToBeOverwritten"); + pathsAllowedToBeOverwrittenField.setAccessible(true); + assertNull(pathsAllowedToBeOverwrittenField.get(null)); + + } catch (Exception e) { + fail("Unexpected exception: " + e); + } + } +} \ No newline at end of file diff --git a/src/test/java/de/tum/cit/ase/ares/api/aop/JavaSecurityTestCaseTest.java b/src/test/java/de/tum/cit/ase/ares/api/aop/JavaSecurityTestCaseTest.java new file mode 100644 index 00000000..9474cbda --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/aop/JavaSecurityTestCaseTest.java @@ -0,0 +1,80 @@ +package de.tum.cit.ase.ares.api.aop; + +import de.tum.cit.ase.ares.api.aop.java.JavaSecurityTestCase; +import de.tum.cit.ase.ares.api.aop.java.JavaSecurityTestCaseSupported; +import de.tum.cit.ase.ares.api.policy.SecurityPolicy.ResourceAccesses; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class JavaSecurityTestCaseTest { + + private JavaSecurityTestCase javaSecurityTestCase; + private ResourceAccesses resourceAccesses; + + @BeforeEach + void setUp() { + JavaSecurityTestCaseSupported supported = JavaSecurityTestCaseSupported.FILESYSTEM_INTERACTION; + resourceAccesses = mock(ResourceAccesses.class); + javaSecurityTestCase = new JavaSecurityTestCase(supported, resourceAccesses); + } + + @Test + void testWriteAOPSecurityTestCase() { + String result = javaSecurityTestCase.writeAOPSecurityTestCase("INSTRUMENTATION"); + assertEquals("", result); + } + + @Test + void testWriteAOPSecurityTestCaseFile() { + List allowedListedClasses = List.of("TestClass"); + List javaSecurityTestCases = List.of(javaSecurityTestCase); + + String result = JavaSecurityTestCase.writeAOPSecurityTestCaseFile( + "INSTRUMENTATION", + "de.tum.cit", + allowedListedClasses, + javaSecurityTestCases + ); + + assertTrue(result.contains("private static String aopMode")); + assertTrue(result.contains("private static String restrictedPackage")); + assertTrue(result.contains("private static String[] allowedListedClasses")); + } + + @Test + void testExecuteAOPSecurityTestCase() { + try (MockedStatic mockedStatic = mockStatic(JavaSecurityTestCase.class)) { + javaSecurityTestCase.executeAOPSecurityTestCase("INSTRUMENTATION"); + mockedStatic.verify(() -> JavaSecurityTestCase.setJavaAdviceSettingValue(anyString(), any(), eq("INSTRUMENTATION")), atLeastOnce()); + } + } + + @Test + void testGetPermittedFilePaths() throws Exception { + Method method = JavaSecurityTestCase.class.getDeclaredMethod("getPermittedFilePaths", String.class); + method.setAccessible(true); + List filePaths = (List) method.invoke(javaSecurityTestCase, "read"); + assertEquals(filePaths.size(), 0); + } + + @Test + void testGenerateAdviceSettingValue() throws Exception { + Method method = JavaSecurityTestCase.class.getDeclaredMethod("generateAdviceSettingValue", String.class, String.class, Object.class); + method.setAccessible(true); + String result = (String) method.invoke(null, "String", "testAdvice", "testValue"); + assertEquals("private static String testAdvice = \"testValue\";\n", result); + result = (String) method.invoke(null, "String[]", "testAdviceArray", List.of("value1", "value2")); + assertEquals("private static String[] testAdviceArray = new String[] {\"value1\", \"value2\"};\n", result); + InvocationTargetException thrown = assertThrows(InvocationTargetException.class, () -> { + method.invoke(null, "UnknownType", "testAdvice", "value"); + }); + assertEquals(SecurityException.class, thrown.getCause().getClass()); + } +} \ No newline at end of file diff --git a/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationAdviceToolboxTest.java b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationAdviceToolboxTest.java new file mode 100644 index 00000000..2cd54466 --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationAdviceToolboxTest.java @@ -0,0 +1,46 @@ +package de.tum.cit.ase.ares.api.aop.instrumentation.advice; + +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceToolbox; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import java.lang.reflect.Method; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +class JavaInstrumentationAdviceToolboxTest { + + + @Test + void testCheckFileSystemInteraction_AllowedInteraction() { + try (MockedStatic mockedToolbox = mockStatic(JavaInstrumentationAdviceToolbox.class)) { + Method getValueFromSettings = JavaInstrumentationAdviceToolbox.class.getDeclaredMethod("getValueFromSettings", String.class); + getValueFromSettings.setAccessible(true); + + mockedToolbox.when(() -> getValueFromSettings.invoke(null, "aopMode")).thenReturn("INSTRUMENTATION"); + mockedToolbox.when(() -> getValueFromSettings.invoke(null, "restrictedPackage")).thenReturn("de.tum.cit.ase"); + mockedToolbox.when(() -> getValueFromSettings.invoke(null, "allowedListedClasses")).thenReturn(new String[]{"de.tum.cit.ase.safe"}); + mockedToolbox.when(() -> getValueFromSettings.invoke(null, "pathsAllowedToBeRead")).thenReturn(new String[]{"/allowed/path"}); + + assertDoesNotThrow(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + "read", + "de.tum.cit.ase.safe.FileReader", + "readFile", + "(Ljava/lang/String;)V", + null, + new Object[]{"/allowed/path"} + )); + } catch (Exception e) { + fail("Exception should not have been thrown: " + e.getMessage()); + } + } + + @Test + void testLocalizeFallback() { + String key = "security.advice.test.key"; + String result = JavaInstrumentationAdviceToolbox.localize(key, "arg1", "arg2"); + key = "!security.advice.test.key!"; + assertEquals(key, result); + } +} \ No newline at end of file diff --git a/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationDeletePathConstructorAdviceTest.java b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationDeletePathConstructorAdviceTest.java new file mode 100644 index 00000000..c32d3520 --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationDeletePathConstructorAdviceTest.java @@ -0,0 +1,49 @@ +package de.tum.cit.ase.ares.api.aop.instrumentation.advice; + +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceToolbox; +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationDeletePathConstructorAdvice; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import static org.mockito.Mockito.*; + +class JavaInstrumentationDeletePathConstructorAdviceTest { + + private static final String OPERATION = "delete"; + private static final String CLASS_NAME = "de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationDeletePathConstructorAdvice"; + private static final String METHOD_NAME = ""; + private static final String METHOD_SIGNATURE = ""; + private static final Object[] ATTRIBUTES = new Object[0]; + private static final Object[] PARAMETERS = new Object[]{"param1", "param2"}; + + @Test + void testOnEnterVerifiesFileSystemInteractionForDelete() { + try (MockedStatic mockedToolbox = mockStatic(JavaInstrumentationAdviceToolbox.class)) { + // Arrange + mockedToolbox.when(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )).thenAnswer(invocation -> null); + + // Act + JavaInstrumentationDeletePathConstructorAdvice.onEnter( + CLASS_NAME, + PARAMETERS + ); + + // Assert + mockedToolbox.verify(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )); + } + } +} \ No newline at end of file diff --git a/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationDeletePathMethodAdviceTest.java b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationDeletePathMethodAdviceTest.java new file mode 100644 index 00000000..f67a3feb --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationDeletePathMethodAdviceTest.java @@ -0,0 +1,56 @@ +package de.tum.cit.ase.ares.api.aop.instrumentation.advice; + +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceToolbox; +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationDeletePathMethodAdvice; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import static org.mockito.Mockito.*; + +class JavaInstrumentationDeletePathMethodAdviceTest { + + private static final String OPERATION = "delete"; + private static final String CLASS_NAME = "de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationDeletePathMethodAdvice"; + private static final String METHOD_NAME = "methodName"; + private static final String METHOD_SIGNATURE = "methodSignature"; + private static final Object[] ATTRIBUTES = new Object[]{"attrib1", "attrib2"}; + private static final Object[] PARAMETERS = new Object[]{"param1", "param2"}; + private static final Object INSTANCE = new Object() { + public final String attrib1 = "attrib1"; + public final String attrib2 = "attrib2"; + }; + + @Test + void shouldCheckFileSystemInteraction_whenDeletingPath() { + try (MockedStatic mockedToolbox = mockStatic(JavaInstrumentationAdviceToolbox.class)) { + // Arrange + mockedToolbox.when(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )).thenAnswer(invocation -> null); + + // Act + JavaInstrumentationDeletePathMethodAdvice.onEnter( + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + INSTANCE, + PARAMETERS + ); + + // Assert + mockedToolbox.verify(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )); + } + } +} \ No newline at end of file diff --git a/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationExecutePathConstructorAdviceTest.java b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationExecutePathConstructorAdviceTest.java new file mode 100644 index 00000000..5e3bd230 --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationExecutePathConstructorAdviceTest.java @@ -0,0 +1,49 @@ +package de.tum.cit.ase.ares.api.aop.instrumentation.advice; + +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceToolbox; +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationExecutePathConstructorAdvice; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import static org.mockito.Mockito.*; + +class JavaInstrumentationExecutePathConstructorAdviceTest { + + private static final String OPERATION = "execute"; + private static final String CLASS_NAME = "de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationExecutePathConstructorAdvice"; + private static final String METHOD_NAME = ""; + private static final String METHOD_SIGNATURE = ""; + private static final Object[] ATTRIBUTES = new Object[0]; + private static final Object[] PARAMETERS = new Object[]{"param1", "param2"}; + + @Test + void testOnEnter() { + try (MockedStatic mockedToolbox = mockStatic(JavaInstrumentationAdviceToolbox.class)) { + // Arrange + mockedToolbox.when(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )).thenAnswer(invocation -> null); + + // Act + JavaInstrumentationExecutePathConstructorAdvice.onEnter( + CLASS_NAME, + PARAMETERS + ); + + // Assert + mockedToolbox.verify(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )); + } + } +} \ No newline at end of file diff --git a/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationExecutePathMethodAdviceTest.java b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationExecutePathMethodAdviceTest.java new file mode 100644 index 00000000..c2f321ca --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationExecutePathMethodAdviceTest.java @@ -0,0 +1,59 @@ +package de.tum.cit.ase.ares.api.aop.instrumentation.advice; + +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceToolbox; +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationExecutePathMethodAdvice; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import java.lang.reflect.Field; + +import static org.mockito.Mockito.*; + +class JavaInstrumentationExecutePathMethodAdviceTest { + + private static final String OPERATION = "execute"; + private static final String CLASS_NAME = "de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationExecutePathMethodAdvice"; + private static final String METHOD_NAME = "methodName"; + private static final String METHOD_SIGNATURE = "methodSignature"; + private static final Object[] ATTRIBUTES = new Object[]{"attrib1", "attrib2"}; + private static final Object[] PARAMETERS = new Object[]{"param1", "param2"}; + private static final Object INSTANCE = new Object() { + public final String attrib1 = "attrib1"; + public final String attrib2 = "attrib2"; + }; + + @Test + void testOnEnter() throws IllegalAccessException { + + try (MockedStatic mockedToolbox = mockStatic(JavaInstrumentationAdviceToolbox.class)) { + // Arrange + mockedToolbox.when(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )).thenAnswer(invocation -> null); + + // Act + JavaInstrumentationExecutePathMethodAdvice.onEnter( + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + INSTANCE, + PARAMETERS + ); + + // Assert + mockedToolbox.verify(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )); + } + } +} \ No newline at end of file diff --git a/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationOverwritePathConstructorAdviceTest.java b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationOverwritePathConstructorAdviceTest.java new file mode 100644 index 00000000..55028c18 --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationOverwritePathConstructorAdviceTest.java @@ -0,0 +1,49 @@ +package de.tum.cit.ase.ares.api.aop.instrumentation.advice; + +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceToolbox; +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationOverwritePathConstructorAdvice; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import static org.mockito.Mockito.*; + +class JavaInstrumentationOverwritePathConstructorAdviceTest { + + private static final String OPERATION = "overwrite"; + private static final String CLASS_NAME = "de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationOverwritePathConstructorAdvice"; + private static final String METHOD_NAME = ""; + private static final String METHOD_SIGNATURE = ""; + private static final Object[] ATTRIBUTES = new Object[0]; + private static final Object[] PARAMETERS = new Object[]{"param1", "param2"}; + + @Test + void testOnEnter() { + try (MockedStatic mockedToolbox = mockStatic(JavaInstrumentationAdviceToolbox.class)) { + // Arrange + mockedToolbox.when(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )).thenAnswer(invocation -> null); + + // Act + JavaInstrumentationOverwritePathConstructorAdvice.onEnter( + CLASS_NAME, + PARAMETERS + ); + + // Assert + mockedToolbox.verify(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )); + } + } +} \ No newline at end of file diff --git a/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationOverwritePathMethodAdviceTest.java b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationOverwritePathMethodAdviceTest.java new file mode 100644 index 00000000..e4834e10 --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationOverwritePathMethodAdviceTest.java @@ -0,0 +1,60 @@ +package de.tum.cit.ase.ares.api.aop.instrumentation.advice; + +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceToolbox; +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationOverwritePathMethodAdvice; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import java.lang.reflect.Field; + +import static org.mockito.AdditionalMatchers.aryEq; +import static org.mockito.Mockito.*; + +class JavaInstrumentationOverwritePathMethodAdviceTest { + + private static final String OPERATION = "overwrite"; + private static final String CLASS_NAME = "de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationOverwritePathMethodAdvice"; + private static final String METHOD_NAME = "methodName"; + private static final String METHOD_SIGNATURE = "methodSignature"; + private static final Object[] ATTRIBUTES = new Object[]{"attrib1", "attrib2"}; + private static final Object[] PARAMETERS = new Object[]{"param1", "param2"}; + private static final Object INSTANCE = new Object() { + public final String attrib1 = "attrib1"; + public final String attrib2 = "attrib2"; + }; + + @Test + void testOnEnter() throws Exception { + + try (MockedStatic mockedToolbox = mockStatic(JavaInstrumentationAdviceToolbox.class)) { + // Arrange + mockedToolbox.when(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )).thenAnswer(invocation -> null); + + // Act + JavaInstrumentationOverwritePathMethodAdvice.onEnter( + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + INSTANCE, + PARAMETERS + ); + + // Assert + mockedToolbox.verify(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )); + } + } +} \ No newline at end of file diff --git a/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationReadPathConstructorAdviceTest.java b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationReadPathConstructorAdviceTest.java new file mode 100644 index 00000000..dfb6f052 --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationReadPathConstructorAdviceTest.java @@ -0,0 +1,50 @@ +package de.tum.cit.ase.ares.api.aop.instrumentation.advice; + +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceToolbox; +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationReadPathConstructorAdvice; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import static org.mockito.AdditionalMatchers.aryEq; +import static org.mockito.Mockito.*; + +class JavaInstrumentationReadPathConstructorAdviceTest { + + private static final String OPERATION = "read"; + private static final String CLASS_NAME = "de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationReadPathConstructorAdvice"; + private static final String METHOD_NAME = ""; + private static final String METHOD_SIGNATURE = ""; + private static final Object[] ATTRIBUTES = new Object[0]; + private static final Object[] PARAMETERS = new Object[]{"param1", "param2"}; + + @Test + void testOnEnter() { + try (MockedStatic mockedToolbox = mockStatic(JavaInstrumentationAdviceToolbox.class)) { + // Arrange + mockedToolbox.when(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )).thenAnswer(invocation -> null); + + // Act + JavaInstrumentationReadPathConstructorAdvice.onEnter( + CLASS_NAME, + PARAMETERS + ); + + // Assert + mockedToolbox.verify(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )); + } + } +} diff --git a/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationReadPathMethodAdviceTest.java b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationReadPathMethodAdviceTest.java new file mode 100644 index 00000000..24cbaf68 --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/aop/instrumentation/advice/JavaInstrumentationReadPathMethodAdviceTest.java @@ -0,0 +1,60 @@ +package de.tum.cit.ase.ares.api.aop.instrumentation.advice; + +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationAdviceToolbox; +import de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationReadPathMethodAdvice; +import org.junit.jupiter.api.Test; +import org.mockito.MockedStatic; + +import java.lang.reflect.Field; + +import static org.mockito.AdditionalMatchers.aryEq; +import static org.mockito.Mockito.*; + +class JavaInstrumentationReadPathMethodAdviceTest { + + private static final String OPERATION = "read"; + private static final String CLASS_NAME = "de.tum.cit.ase.ares.api.aop.java.instrumentation.advice.JavaInstrumentationReadPathMethodAdvice"; + private static final String METHOD_NAME = "methodName"; + private static final String METHOD_SIGNATURE = "methodSignature"; + private static final Object[] ATTRIBUTES = new Object[]{"attrib1", "attrib2"}; + private static final Object[] PARAMETERS = new Object[]{"param1", "param2"}; + private static final Object INSTANCE = new Object() { + public final String attrib1 = "attrib1"; + public final String attrib2 = "attrib2"; + }; + + @Test + void testOnEnter() throws Exception { + + try (MockedStatic mockedToolbox = mockStatic(JavaInstrumentationAdviceToolbox.class)) { + // Arrange + mockedToolbox.when(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )).thenAnswer(invocation -> null); + + // Act + JavaInstrumentationReadPathMethodAdvice.onEnter( + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + INSTANCE, + PARAMETERS + ); + + // Assert + mockedToolbox.verify(() -> JavaInstrumentationAdviceToolbox.checkFileSystemInteraction( + OPERATION, + CLASS_NAME, + METHOD_NAME, + METHOD_SIGNATURE, + ATTRIBUTES, + PARAMETERS + )); + } + } +} \ No newline at end of file diff --git a/src/test/java/de/tum/cit/ase/ares/api/architecture/JavaArchUnitSecurityTestCaseTest.java b/src/test/java/de/tum/cit/ase/ares/api/architecture/JavaArchUnitSecurityTestCaseTest.java new file mode 100644 index 00000000..68e85e30 --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/architecture/JavaArchUnitSecurityTestCaseTest.java @@ -0,0 +1,101 @@ +package de.tum.cit.ase.ares.api.architecture; + +import com.tngtech.archunit.core.domain.JavaClasses; +import com.tngtech.archunit.core.importer.ClassFileImporter; +import de.tum.cit.ase.ares.api.architecture.java.archunit.JavaArchUnitSecurityTestCase; +import de.tum.cit.ase.ares.api.architecture.java.JavaArchitecturalTestCaseSupported; +import de.tum.cit.ase.ares.api.policy.SecurityPolicy.PackagePermission; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.*; + +class JavaArchUnitSecurityTestCaseTest { + + private JavaArchUnitSecurityTestCase testCase; + private JavaClasses classes; + + @BeforeEach + void setUp() { + classes = new ClassFileImporter().importPackages("com.example"); + } + + @Test + void testConstructorWithSingleParameter() { + testCase = JavaArchUnitSecurityTestCase + .builder() + .javaArchitecturalTestCaseSupported(JavaArchitecturalTestCaseSupported.FILESYSTEM_INTERACTION) + .build(); + assertNotNull(testCase); + } + + @Test + void testConstructorWithTwoParameters() { + Set packagePermissions = Set.of(new PackagePermission("com.example")); + testCase = JavaArchUnitSecurityTestCase + .builder() + .javaArchitecturalTestCaseSupported(JavaArchitecturalTestCaseSupported.PACKAGE_IMPORT) + .allowedPackages(packagePermissions) + .build(); + assertNotNull(testCase); + } + + @Test + void testWriteArchitectureTestCase() { + testCase = JavaArchUnitSecurityTestCase + .builder() + .javaArchitecturalTestCaseSupported(JavaArchitecturalTestCaseSupported.FILESYSTEM_INTERACTION) + .build(); + String content = testCase.writeArchitectureTestCase(); + assertNotNull(content); + } + + @Test + void testExecuteArchitectureTestCaseFilesystemInteraction() { + testCase = JavaArchUnitSecurityTestCase + .builder() + .javaArchitecturalTestCaseSupported(JavaArchitecturalTestCaseSupported.FILESYSTEM_INTERACTION) + .build(); + assertDoesNotThrow(() -> testCase.executeArchitectureTestCase(classes)); + } + + @Test + void testExecuteArchitectureTestCaseNetworkConnection() { + testCase = JavaArchUnitSecurityTestCase + .builder() + .javaArchitecturalTestCaseSupported(JavaArchitecturalTestCaseSupported.NETWORK_CONNECTION) + .build(); + assertDoesNotThrow(() -> testCase.executeArchitectureTestCase(classes)); + } + + @Test + void testExecuteArchitectureTestCaseThreadCreation() { + testCase = JavaArchUnitSecurityTestCase + .builder() + .javaArchitecturalTestCaseSupported(JavaArchitecturalTestCaseSupported.THREAD_CREATION) + .build(); + assertDoesNotThrow(() -> testCase.executeArchitectureTestCase(classes)); + } + + @Test + void testExecuteArchitectureTestCaseCommandExecution() { + testCase = JavaArchUnitSecurityTestCase + .builder() + .javaArchitecturalTestCaseSupported(JavaArchitecturalTestCaseSupported.COMMAND_EXECUTION) + .build(); + assertDoesNotThrow(() -> testCase.executeArchitectureTestCase(classes)); + } + + @Test + void testExecuteArchitectureTestCasePackageImport() { + Set packagePermissions = Set.of(new PackagePermission("com.example")); + testCase = JavaArchUnitSecurityTestCase + .builder() + .javaArchitecturalTestCaseSupported(JavaArchitecturalTestCaseSupported.PACKAGE_IMPORT) + .allowedPackages(packagePermissions) + .build(); + assertDoesNotThrow(() -> testCase.executeArchitectureTestCase(classes)); + } +} diff --git a/src/test/java/de/tum/cit/ase/ares/api/architecture/JavaArchUnitTestCaseSupportedTest.java b/src/test/java/de/tum/cit/ase/ares/api/architecture/JavaArchUnitTestCaseSupportedTest.java new file mode 100644 index 00000000..1e851b45 --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/architecture/JavaArchUnitTestCaseSupportedTest.java @@ -0,0 +1,42 @@ +package de.tum.cit.ase.ares.api.architecture; + +import de.tum.cit.ase.ares.api.architecture.java.JavaArchitecturalTestCaseSupported; +import org.junit.jupiter.api.Test; +import static org.junit.jupiter.api.Assertions.*; + +class JavaArchUnitTestCaseSupportedTest { + + @Test + void testEnumValues() { + JavaArchitecturalTestCaseSupported[] values = JavaArchitecturalTestCaseSupported.values(); + assertEquals(9, values.length); + assertEquals(JavaArchitecturalTestCaseSupported.FILESYSTEM_INTERACTION, values[0]); + assertEquals(JavaArchitecturalTestCaseSupported.NETWORK_CONNECTION, values[1]); + assertEquals(JavaArchitecturalTestCaseSupported.COMMAND_EXECUTION, values[2]); + assertEquals(JavaArchitecturalTestCaseSupported.THREAD_CREATION, values[3]); + assertEquals(JavaArchitecturalTestCaseSupported.PACKAGE_IMPORT, values[4]); + assertEquals(JavaArchitecturalTestCaseSupported.TERMINATE_JVM, values[5]); + assertEquals(JavaArchitecturalTestCaseSupported.REFLECTION, values[6]); + assertEquals(JavaArchitecturalTestCaseSupported.SERIALIZATION, values[7]); + assertEquals(JavaArchitecturalTestCaseSupported.CLASS_LOADING, values[8]); + } + + @Test + void testEnumValueOf() { + assertEquals(JavaArchitecturalTestCaseSupported.FILESYSTEM_INTERACTION, JavaArchitecturalTestCaseSupported.valueOf("FILESYSTEM_INTERACTION")); + assertEquals(JavaArchitecturalTestCaseSupported.NETWORK_CONNECTION, JavaArchitecturalTestCaseSupported.valueOf("NETWORK_CONNECTION")); + assertEquals(JavaArchitecturalTestCaseSupported.COMMAND_EXECUTION, JavaArchitecturalTestCaseSupported.valueOf("COMMAND_EXECUTION")); + assertEquals(JavaArchitecturalTestCaseSupported.THREAD_CREATION, JavaArchitecturalTestCaseSupported.valueOf("THREAD_CREATION")); + assertEquals(JavaArchitecturalTestCaseSupported.PACKAGE_IMPORT, JavaArchitecturalTestCaseSupported.valueOf("PACKAGE_IMPORT")); + assertEquals(JavaArchitecturalTestCaseSupported.TERMINATE_JVM, JavaArchitecturalTestCaseSupported.valueOf("TERMINATE_JVM")); + assertEquals(JavaArchitecturalTestCaseSupported.REFLECTION, JavaArchitecturalTestCaseSupported.valueOf("REFLECTION")); + assertEquals(JavaArchitecturalTestCaseSupported.SERIALIZATION, JavaArchitecturalTestCaseSupported.valueOf("SERIALIZATION")); + assertEquals(JavaArchitecturalTestCaseSupported.CLASS_LOADING, JavaArchitecturalTestCaseSupported.valueOf("CLASS_LOADING")); + } + + @Test + void testEnumValueOfInvalid() { + assertThrows(IllegalArgumentException.class, + () -> JavaArchitecturalTestCaseSupported.valueOf("INVALID_VALUE")); + } +} diff --git a/src/test/java/de/tum/cit/ase/ares/api/architecture/com/example/EmptyClass.java b/src/test/java/de/tum/cit/ase/ares/api/architecture/com/example/EmptyClass.java new file mode 100644 index 00000000..820822eb --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/architecture/com/example/EmptyClass.java @@ -0,0 +1,4 @@ +package de.tum.cit.ase.ares.api.architecture.com.example; + +public class EmptyClass { +} diff --git a/src/test/java/de/tum/cit/ase/ares/api/architecture/com/example/ExampleClass.java b/src/test/java/de/tum/cit/ase/ares/api/architecture/com/example/ExampleClass.java new file mode 100644 index 00000000..d8c2a15c --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/api/architecture/com/example/ExampleClass.java @@ -0,0 +1,10 @@ +package de.tum.cit.ase.ares.api.architecture.com.example; + +import de.tum.cit.ase.ares.integration.testuser.subject.SecurityPenguin; + +public class ExampleClass { + + void someMethod() { + SecurityPenguin.trySetSystemOut(); + } +} diff --git a/src/test/java/de/tum/cit/ase/ares/integration/ArchitectureSecurityTest.java b/src/test/java/de/tum/cit/ase/ares/integration/ArchitectureSecurityTest.java index 1ac45de8..e0af1b8c 100644 --- a/src/test/java/de/tum/cit/ase/ares/integration/ArchitectureSecurityTest.java +++ b/src/test/java/de/tum/cit/ase/ares/integration/ArchitectureSecurityTest.java @@ -62,12 +62,6 @@ void testArchUnitThreadCreation() { tests.assertThatEvents().haveExactly(1, testFailedWith("testArchUnitThreadCreation", SecurityException.class)); } - - @TestTest - void testWalaThreadCreation() { - tests.assertThatEvents().haveExactly(1, - testFailedWith("testWaLaThreadCreation", SecurityException.class)); - } // // diff --git a/src/test/java/de/tum/cit/ase/ares/integration/FileSystemAccessTest.java b/src/test/java/de/tum/cit/ase/ares/integration/FileSystemAccessTest.java index add760f0..442426c6 100644 --- a/src/test/java/de/tum/cit/ase/ares/integration/FileSystemAccessTest.java +++ b/src/test/java/de/tum/cit/ase/ares/integration/FileSystemAccessTest.java @@ -116,11 +116,6 @@ void test_accessPathTest() { // void test_weAccessPath() { // tests.assertThatEvents().haveExactly(1, finishedSuccessfully(weAccessPath)); // } - - @TestTest - void test_accessFileSystem() { - tests.assertThatEvents().haveExactly(1, testFailedWith("accessFileSystem", SecurityException.class)); - } // //TODO Markus: Look into why we are catching Runtime Exceptions and not Security Exceptions diff --git a/src/test/java/de/tum/cit/ase/ares/integration/testuser/ThreadUser.java b/src/test/java/de/tum/cit/ase/ares/integration/testuser/ThreadUser.java index 8d3d940a..1d11952c 100644 --- a/src/test/java/de/tum/cit/ase/ares/integration/testuser/ThreadUser.java +++ b/src/test/java/de/tum/cit/ase/ares/integration/testuser/ThreadUser.java @@ -1,7 +1,6 @@ package de.tum.cit.ase.ares.integration.testuser; import static org.junit.Assert.assertEquals; -import static org.junit.jupiter.api.Assertions.*; import java.nio.file.Path; import java.util.concurrent.*; @@ -15,7 +14,10 @@ import de.tum.cit.ase.ares.api.jupiter.PublicTest; import de.tum.cit.ase.ares.api.localization.UseLocale; //REMOVED: Import of ArtemisSecurityManager -import de.tum.cit.ase.ares.integration.testuser.subject.ThreadPenguin; +import de.tum.cit.ase.ares.integration.testuser.subject.threads.ThreadPenguin; + +import static org.assertj.core.api.Fail.fail; +import static org.junit.jupiter.api.Assertions.assertFalse; @UseLocale("en") @AllowThreads(maxActiveCount = 100) @@ -27,6 +29,10 @@ @SuppressWarnings("static-method") public class ThreadUser { + @PublicTest + @Policy(value = "src/test/resources/de/tum/cit/ase/ares/integration/testuser/securitypolicies/EverythingForbiddenPolicy.yaml", withinPath = "test-classes/de/tum/cit/ase/ares/integration/testuser/subject/threads") + void threadAccessTest() {} + @PublicTest void commonPoolInterruptable() throws InterruptedException, ExecutionException { // check functionality diff --git a/src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/ThreadPenguin.java b/src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/threads/ThreadPenguin.java similarity index 54% rename from src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/ThreadPenguin.java rename to src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/threads/ThreadPenguin.java index 9c3ad579..9f8553c9 100644 --- a/src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/ThreadPenguin.java +++ b/src/test/java/de/tum/cit/ase/ares/integration/testuser/subject/threads/ThreadPenguin.java @@ -1,8 +1,9 @@ -package de.tum.cit.ase.ares.integration.testuser.subject; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +package de.tum.cit.ase.ares.integration.testuser.subject.threads; import java.nio.file.Path; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; //REMOVED: Import of ArtemisSecurityManager @@ -29,9 +30,7 @@ public static void tryStartTwoThreads() { // ignore } }); - assertDoesNotThrow(() -> { - t1.start(); - }); + t1.start(); new Thread().start(); } @@ -61,14 +60,47 @@ public static void spawnEndlessThreads() { } } - public static void tryThreadWhitelisting() throws Throwable { + private static void verifyThreadWhitelisting(String message) throws Throwable { AtomicReference failure = new AtomicReference<>(); - Thread t = new Thread(() -> Path.of("pom.xml").toFile().canWrite()); - //REMOVED: Thread-whitelisting-request to ArtemisSecurityManager + Thread t = new Thread(() -> failure.set(new SecurityException(message))); t.setUncaughtExceptionHandler((t1, e) -> failure.set(e)); t.start(); t.join(); if (failure.get() != null) throw failure.get(); } + + public static void tryThreadWhitelisting() throws Throwable { + verifyThreadWhitelisting("Thread not whitelisted"); + } + + void threadWhitelistingWithPathFail() throws Throwable { + verifyThreadWhitelisting("Thread not whitelisted"); + } + + void commonPoolInterruptable() throws InterruptedException, ExecutionException { + // check functionality + var res = ForkJoinPool.commonPool().submit(() -> "A").get(); + // submit long-running task + var task = ForkJoinPool.commonPool().submit(() -> { + ThreadPenguin.sleepInCurrentThread(5_000); + }); + // check that the task is still running after 100 ms + try { + Thread.sleep(100); + } catch (@SuppressWarnings("unused") InterruptedException e) { + Thread.currentThread().interrupt(); + } + // wait for task end + ForkJoinPool.commonPool().awaitQuiescence(5, TimeUnit.SECONDS); + } + + public static void something() { + new ThreadPenguin().start(); + } + + @Override + public void start() { + super.start(); + } } diff --git a/src/test/java/de/tum/cit/ase/ares/testutilities/CustomConditionEvents.java b/src/test/java/de/tum/cit/ase/ares/testutilities/CustomConditionEvents.java new file mode 100644 index 00000000..fcd813f8 --- /dev/null +++ b/src/test/java/de/tum/cit/ase/ares/testutilities/CustomConditionEvents.java @@ -0,0 +1,50 @@ +package de.tum.cit.ase.ares.testutilities; + +import com.google.common.collect.ImmutableList; +import com.tngtech.archunit.lang.ConditionEvent; +import com.tngtech.archunit.lang.ConditionEvents; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Optional; + +/** + * Custom condition events used in ArchUnit tests + */ +public class CustomConditionEvents implements ConditionEvents { + private final List violations = new ArrayList<>(); + private Optional informationAboutNumberOfViolations = Optional.empty(); + + @Override + public void add(ConditionEvent event) { + if (!event.isViolation()) { + violations.add(event); + } + } + + @Override + public Optional getInformationAboutNumberOfViolations() { + return informationAboutNumberOfViolations; + } + + @Override + public void setInformationAboutNumberOfViolations(String informationAboutNumberOfViolations) { + this.informationAboutNumberOfViolations = Optional.of(informationAboutNumberOfViolations); + } + + @Override + public Collection getViolating() { + return ImmutableList.copyOf(violations); + } + + @Override + public boolean containViolation() { + return !violations.isEmpty(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "{" + violations + '}'; + } +}