Ver código fonte

unit tests and SECURITY policy

Allan Barcelos 1 ano atrás
pai
commit
dfd8e0e2e1

+ 13 - 0
SECURITY.md

@@ -0,0 +1,13 @@
+# Security Policy
+
+## Reporting a Vulnerability
+
+To report security issues send an email to [email protected]
+
+The following keys may be used to communicate sensitive information to developer:
+
+| Name | Fingerprint |
+|------|-------------|
+| Allan Barcelos | 492F 6B41 B83C B0BF 5B64 5777 F437 AC65 26AB 7A49 |
+
+You can import a key by running the following command with that individual’s fingerprint: `gpg --keyserver hkps://keys.openpgp.org --recv-keys "<fingerprint>"` Ensure that you put quotes around fingerprints containing spaces.

+ 11 - 1
pom.xml

@@ -70,7 +70,17 @@
       <artifactId>googleauth</artifactId>
       <version>1.5.0</version>
     </dependency>
-
+    <!-- TEST -->
+    <dependency>
+      <groupId>org.junit.vintage</groupId>
+      <artifactId>junit-vintage-engine</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 
   <repositories>

+ 111 - 0
src/test/java/io/jenkins/plugins/MfaEnforceFilterTest.java

@@ -0,0 +1,111 @@
+package io.jenkins.plugins;
+
+import static org.mockito.Mockito.*;
+
+import hudson.model.User;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MfaEnforceFilterTest {
+
+    @Mock
+    private HttpServletRequest request;
+
+    @Mock
+    private HttpServletResponse response;
+
+    @Mock
+    private FilterChain chain;
+
+    @Mock
+    private HttpSession session;
+
+    @Mock
+    private User user;
+
+    @Mock
+    private MfaUserProperty mfaProperty;
+
+    @Mock
+    private FilterConfig filterConfig;
+
+    private MfaEnforceFilter filter;
+
+    @Before
+    public void setUp() {
+        filter = new MfaEnforceFilter();
+    }
+
+    @Test
+    public void testStaticResourcesBypass() throws Exception {
+        when(request.getRequestURI()).thenReturn("/jenkins/static/some-resource.css");
+        when(request.getContextPath()).thenReturn("/jenkins");
+
+        filter.doFilter(request, response, chain);
+
+        verify(chain).doFilter(request, response);
+        verifyNoInteractions(response);
+    }
+
+    @Test
+    public void testNoUserLoggedIn() throws Exception {
+        when(request.getRequestURI()).thenReturn("/jenkins/some-page");
+        when(request.getContextPath()).thenReturn("/jenkins");
+
+        try (MockedStatic<User> mockedUser = mockStatic(User.class)) {
+            mockedUser.when(User::current).thenReturn(null);
+
+            filter.doFilter(request, response, chain);
+
+            verify(chain).doFilter(request, response);
+            verifyNoInteractions(response);
+        }
+    }
+
+    @Test
+    public void testUserWithMfaDisabled() throws Exception {
+        when(request.getRequestURI()).thenReturn("/jenkins/some-page");
+        when(request.getContextPath()).thenReturn("/jenkins");
+
+        try (MockedStatic<User> mockedUser = mockStatic(User.class)) {
+            mockedUser.when(User::current).thenReturn(user);
+            when(user.getProperty(MfaUserProperty.class)).thenReturn(null);
+
+            filter.doFilter(request, response, chain);
+
+            verify(chain).doFilter(request, response);
+            verifyNoInteractions(response);
+        }
+    }
+
+    @Test
+    public void testUserWithMfaEnabledButNotVerified() throws Exception {
+        when(request.getRequestURI()).thenReturn("/jenkins/some-page");
+        when(request.getContextPath()).thenReturn("/jenkins");
+        when(request.getSession(false)).thenReturn(session);
+
+        try (MockedStatic<User> mockedUser = mockStatic(User.class)) {
+            mockedUser.when(User::current).thenReturn(user);
+            when(user.getProperty(MfaUserProperty.class)).thenReturn(mfaProperty);
+            when(mfaProperty.isMfaEnabled()).thenReturn(true);
+            when(session.getAttribute("mfa-verified")).thenReturn(null);
+
+            filter.doFilter(request, response, chain);
+
+            verify(response).sendRedirect("/jenkins/mfa-verify/");
+            verify(chain, never()).doFilter(request, response);
+        }
+    }
+
+    // maybe more tests ...
+}

+ 60 - 0
src/test/java/io/jenkins/plugins/MfaFilterRegisterTest.java

@@ -0,0 +1,60 @@
+package io.jenkins.plugins;
+
+import static org.junit.Assert.*;
+import static org.mockito.ArgumentMatchers.*;
+import static org.mockito.Mockito.*;
+
+import hudson.init.InitMilestone;
+import hudson.init.Initializer;
+import hudson.util.PluginServletFilter;
+import javax.servlet.Filter;
+import javax.servlet.ServletException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockedStatic;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MfaFilterRegisterTest {
+
+    @Test
+    public void testInitializationMilestone() throws Exception {
+        // Verifica se a anotação está correta
+        Initializer initializer =
+                MfaFilterRegister.class.getDeclaredMethod("init").getAnnotation(Initializer.class);
+
+        assertNotNull(initializer);
+        assertEquals(InitMilestone.PLUGINS_STARTED, initializer.after());
+    }
+
+    @Test
+    public void testFilterRegistration() throws Exception {
+        try (MockedStatic<PluginServletFilter> pluginServletFilter = mockStatic(PluginServletFilter.class)) {
+            // Configura o mock para resolver a ambiguidade
+            pluginServletFilter
+                    .when(() -> PluginServletFilter.addFilter(any(Filter.class)))
+                    .thenAnswer(invocation -> null);
+
+            // Executa o método de registro
+            MfaFilterRegister.init();
+
+            // Verifica se o filtro foi adicionado
+            pluginServletFilter.verify(() -> PluginServletFilter.addFilter(isA(MfaFilter.class)));
+        }
+    }
+
+    @Test
+    public void testServletExceptionHandling() {
+        try (MockedStatic<PluginServletFilter> pluginServletFilter = mockStatic(PluginServletFilter.class)) {
+            // Configura para lançar exceção
+            pluginServletFilter
+                    .when(() -> PluginServletFilter.addFilter(any(Filter.class)))
+                    .thenThrow(new ServletException("Test error"));
+
+            // Verifica se a exceção é propagada
+            ServletException exception = assertThrows(ServletException.class, MfaFilterRegister::init);
+
+            assertEquals("Test error", exception.getMessage());
+        }
+    }
+}

+ 134 - 0
src/test/java/io/jenkins/plugins/MfaFilterTest.java

@@ -0,0 +1,134 @@
+package io.jenkins.plugins;
+
+import static org.mockito.Mockito.*;
+
+import hudson.model.User;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import jenkins.model.Jenkins;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockedStatic;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class MfaFilterTest {
+
+    @Mock
+    private HttpServletRequest request;
+
+    @Mock
+    private HttpServletResponse response;
+
+    @Mock
+    private FilterChain chain;
+
+    @Mock
+    private HttpSession session;
+
+    @Mock
+    private FilterConfig filterConfig;
+
+    @Mock
+    private User user;
+
+    @Mock
+    private MfaUserProperty mfaProperty;
+
+    @Mock
+    private Jenkins jenkins;
+
+    private MfaFilter filter;
+
+    @Before
+    public void setUp() {
+        filter = new MfaFilter();
+        when(request.getSession()).thenReturn(session);
+    }
+
+    @Test
+    public void testInitAndDestroy() throws Exception {
+        filter.init(filterConfig);
+        filter.destroy();
+        // Apenas verifica que não lança exceções
+    }
+
+    @Test
+    public void testNonHttpRequestPassesThrough() throws Exception {
+        ServletRequest nonHttpRequest = mock(ServletRequest.class);
+        ServletResponse nonHttpResponse = mock(ServletResponse.class);
+
+        filter.doFilter(nonHttpRequest, nonHttpResponse, chain);
+
+        verify(chain).doFilter(nonHttpRequest, nonHttpResponse);
+    }
+
+    @Test
+    public void testJenkinsNotInitializedPassesThrough() throws Exception {
+        try (MockedStatic<Jenkins> mockedJenkins = mockStatic(Jenkins.class)) {
+            mockedJenkins.when(Jenkins::getInstanceOrNull).thenReturn(null);
+
+            filter.doFilter(request, response, chain);
+
+            verify(chain).doFilter(request, response);
+        }
+    }
+
+    @Test
+    public void testNoUserLoggedInPassesThrough() throws Exception {
+        try (MockedStatic<Jenkins> mockedJenkins = mockStatic(Jenkins.class);
+                MockedStatic<User> mockedUser = mockStatic(User.class)) {
+
+            mockedJenkins.when(Jenkins::getInstanceOrNull).thenReturn(jenkins);
+            mockedUser.when(User::current).thenReturn(null);
+
+            filter.doFilter(request, response, chain);
+
+            verify(chain).doFilter(request, response);
+        }
+    }
+
+    @Test
+    public void testUserWithoutMfaEnabledPassesThrough() throws Exception {
+        try (MockedStatic<Jenkins> mockedJenkins = mockStatic(Jenkins.class);
+                MockedStatic<User> mockedUser = mockStatic(User.class)) {
+
+            mockedJenkins.when(Jenkins::getInstanceOrNull).thenReturn(jenkins);
+            mockedUser.when(User::current).thenReturn(user);
+            when(user.getProperty(MfaUserProperty.class)).thenReturn(null);
+
+            filter.doFilter(request, response, chain);
+
+            verify(chain).doFilter(request, response);
+        }
+    }
+
+    @Test
+    public void testMfaEnabledButNotVerifiedRedirects() throws Exception {
+        try (MockedStatic<Jenkins> mockedJenkins = mockStatic(Jenkins.class);
+                MockedStatic<User> mockedUser = mockStatic(User.class)) {
+
+            mockedJenkins.when(Jenkins::getInstanceOrNull).thenReturn(jenkins);
+            mockedUser.when(User::current).thenReturn(user);
+            when(user.getProperty(MfaUserProperty.class)).thenReturn(mfaProperty);
+            when(mfaProperty.isMfaEnabled()).thenReturn(true);
+            when(request.getRequestURI()).thenReturn("/jenkins/restricted");
+            when(request.getContextPath()).thenReturn("/jenkins");
+
+            filter.doFilter(request, response, chain);
+
+            verify(response).sendRedirect("/jenkins/mfa-verify");
+            verify(chain, never()).doFilter(request, response);
+        }
+    }
+
+    // maybe more tests ...
+
+}