This is an automated email from the ASF dual-hosted git repository.
apelluru pushed a commit to branch feature/improve-test-coverage
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-core.git
The following commit(s) were added to refs/heads/feature/improve-test-coverage
by this push:
new 290c8a8 SLING-13257: Improve Test Coverage
290c8a8 is described below
commit 290c8a8f72fc94a8f59c9a35f5fc68670b8165f7
Author: Ashok Pelluru <[email protected]>
AuthorDate: Mon Jul 6 17:24:27 2026 +0200
SLING-13257: Improve Test Coverage
---
.../org/apache/sling/auth/core/AuthUtilTest.java | 535 +++++++++++++++++++++
.../core/impl/AuthenticationHandlerHolderTest.java | 242 ++++++++++
.../impl/AuthenticationHandlerWrapperTest.java | 113 +++++
.../impl/AuthenticationRequirementHolderTest.java | 71 +++
.../impl/AuthenticatorWebConsolePluginTest.java | 155 ++++++
.../impl/HttpBasicAuthenticationHandlerTest.java | 177 +++++++
.../sling/auth/core/impl/LoginServletTest.java | 107 +++++
.../sling/auth/core/impl/LogoutServletTest.java | 68 +++
.../sling/auth/core/impl/PathBasedHolderTest.java | 101 ++++
.../auth/core/impl/SlingAuthenticatorTest.java | 367 ++++++++++++++
.../EngineAuthenticationHandlerHolderTest.java | 211 ++++++++
.../impl/engine/EngineSlingAuthenticatorTest.java | 78 +++
.../spi/AbstractAuthenticationFormServletTest.java | 147 ++++++
.../spi/AbstractAuthenticationHandlerTest.java | 92 ++++
...stractJakartaAuthenticationFormServletTest.java | 153 ++++++
.../DefaultAuthenticationFeedbackHandlerTest.java | 100 ++++
...ltJakartaAuthenticationFeedbackHandlerTest.java | 121 +++++
.../sling/auth/core/spi/test-login-form.html | 1 +
18 files changed, 2839 insertions(+)
diff --git a/src/test/java/org/apache/sling/auth/core/AuthUtilTest.java
b/src/test/java/org/apache/sling/auth/core/AuthUtilTest.java
index 6d9de6a..9eadf81 100644
--- a/src/test/java/org/apache/sling/auth/core/AuthUtilTest.java
+++ b/src/test/java/org/apache/sling/auth/core/AuthUtilTest.java
@@ -18,14 +18,24 @@
*/
package org.apache.sling.auth.core;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.HashMap;
+import java.util.Map;
+
import jakarta.servlet.http.HttpServletRequest;
+import org.apache.sling.api.auth.Authenticator;
import org.apache.sling.api.resource.NonExistingResource;
+import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.SyntheticResource;
+import org.apache.sling.auth.core.spi.JakartaAuthenticationHandler;
import org.junit.Assert;
import org.junit.Test;
import org.mockito.Mockito;
+@SuppressWarnings("deprecation")
public class AuthUtilTest {
final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
@@ -162,4 +172,529 @@ public class AuthUtilTest {
Mockito.when(request.getHeader("User-Agent")).thenReturn("WebDAV
Client");
Assert.assertFalse(AuthUtil.isBrowserRequest(request));
}
+
+ // ---- Jakarta variants ----
+
+ @Test
+ public void test_getAttributeOrParameter_jakarta() {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getAttribute("a")).thenReturn("attrValue");
+ Assert.assertEquals("attrValue",
AuthUtil.getAttributeOrParameter(request, "a", "def"));
+
+ Mockito.when(request.getAttribute("b")).thenReturn(null);
+ Mockito.when(request.getParameter("b")).thenReturn("paramValue");
+ Assert.assertEquals("paramValue",
AuthUtil.getAttributeOrParameter(request, "b", "def"));
+
+ Mockito.when(request.getAttribute("c")).thenReturn("");
+ Mockito.when(request.getParameter("c")).thenReturn("");
+ Assert.assertEquals("def", AuthUtil.getAttributeOrParameter(request,
"c", "def"));
+
+ // non-string attribute is ignored
+ Mockito.when(request.getAttribute("d")).thenReturn(Integer.valueOf(1));
+ Mockito.when(request.getParameter("d")).thenReturn(null);
+ Assert.assertEquals("def", AuthUtil.getAttributeOrParameter(request,
"d", "def"));
+ }
+
+ @Test
+ public void test_getLoginResource_jakarta() {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+
Mockito.when(request.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/res");
+ Assert.assertEquals("/res", AuthUtil.getLoginResource(request,
"/def"));
+
+ jakarta.servlet.http.HttpServletRequest request2 =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ Assert.assertEquals("/def", AuthUtil.getLoginResource(request2,
"/def"));
+ }
+
+ @Test
+ public void test_getMappedLoginResourcePath_jakarta() {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+
Mockito.when(request.getAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER))
+ .thenReturn(resolver);
+
Mockito.when(request.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/res");
+ Mockito.when(resolver.map(request, "/res")).thenReturn("/mapped/res");
+ Assert.assertEquals("/mapped/res",
AuthUtil.getMappedLoginResourcePath(request, "/def"));
+ }
+
+ @Test
+ public void test_getMappedLoginResourcePath_null_jakarta() {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ // no resolver -> getResourceResolver returns null -> NPE guarded by
null path only
+ // here defaultLoginResource is null and no param -> resourcePath null
-> returns null
+ Assert.assertNull(AuthUtil.getMappedLoginResourcePath(request, null));
+ }
+
+ @Test
+ public void test_setLoginResourceAttribute_jakarta() {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ // attribute already set
+
Mockito.when(request.getAttribute(Authenticator.LOGIN_RESOURCE)).thenReturn("/existing");
+ Assert.assertEquals("/existing",
AuthUtil.setLoginResourceAttribute(request, "/def"));
+
+ // parameter set
+ jakarta.servlet.http.HttpServletRequest request2 =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+
Mockito.when(request2.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/param");
+ Assert.assertEquals("/param",
AuthUtil.setLoginResourceAttribute(request2, "/def"));
+
+ // default used
+ jakarta.servlet.http.HttpServletRequest request3 =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ Assert.assertEquals("/def",
AuthUtil.setLoginResourceAttribute(request3, "/def"));
+
+ // fallback to "/"
+ jakarta.servlet.http.HttpServletRequest request4 =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ Assert.assertEquals("/", AuthUtil.setLoginResourceAttribute(request4,
null));
+ }
+
+ @Test
+ public void test_sendRedirect_jakarta() throws Exception {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ jakarta.servlet.http.HttpServletResponse response =
+ Mockito.mock(jakarta.servlet.http.HttpServletResponse.class);
+ Mockito.when(request.getContextPath()).thenReturn("");
+ Mockito.when(request.getRequestURI()).thenReturn("/current");
+ Mockito.when(request.getQueryString()).thenReturn("x=1");
+
+ Map<String, String> params = new HashMap<>();
+ params.put("k", "v v");
+ AuthUtil.sendRedirect(request, response, "/valid/target", params);
+
+
Mockito.verify(response).sendRedirect(Mockito.contains("/valid/target?"));
+ }
+
+ @Test
+ public void test_sendRedirect_invalidTarget_jakarta() throws Exception {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ jakarta.servlet.http.HttpServletResponse response =
+ Mockito.mock(jakarta.servlet.http.HttpServletResponse.class);
+ Mockito.when(request.getContextPath()).thenReturn("/ctx");
+ Mockito.when(request.getRequestURI()).thenReturn("/current");
+
+ AuthUtil.sendRedirect(request, response, "relative", null);
+ Mockito.verify(response).sendRedirect(Mockito.startsWith("/ctx?"));
+ }
+
+ @Test
+ public void test_sendRedirect_invalidTarget_rootContext_jakarta() throws
Exception {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ jakarta.servlet.http.HttpServletResponse response =
+ Mockito.mock(jakarta.servlet.http.HttpServletResponse.class);
+ Mockito.when(request.getContextPath()).thenReturn("");
+ Mockito.when(request.getRequestURI()).thenReturn("/current");
+
+ AuthUtil.sendRedirect(request, response, "relative", null);
+ Mockito.verify(response).sendRedirect(Mockito.startsWith("/?"));
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void test_sendRedirect_committed_jakarta() throws Exception {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ jakarta.servlet.http.HttpServletResponse response =
+ Mockito.mock(jakarta.servlet.http.HttpServletResponse.class);
+ Mockito.when(response.isCommitted()).thenReturn(true);
+ AuthUtil.sendRedirect(request, response, "/target", null);
+ }
+
+ @Test
+ public void test_isValidateRequest_jakarta() {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+
Mockito.when(request.getParameter(AuthConstants.PAR_J_VALIDATE)).thenReturn("TRUE");
+ Assert.assertTrue(AuthUtil.isValidateRequest(request));
+
Mockito.when(request.getParameter(AuthConstants.PAR_J_VALIDATE)).thenReturn("no");
+ Assert.assertFalse(AuthUtil.isValidateRequest(request));
+ }
+
+ @Test
+ public void test_sendValid_jakarta() {
+ jakarta.servlet.http.HttpServletResponse response =
+ Mockito.mock(jakarta.servlet.http.HttpServletResponse.class);
+ AuthUtil.sendValid(response);
+
Mockito.verify(response).setStatus(jakarta.servlet.http.HttpServletResponse.SC_OK);
+ Mockito.verify(response).setContentLength(0);
+ }
+
+ @Test
+ public void test_sendInvalid_withReason_jakarta() throws Exception {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ jakarta.servlet.http.HttpServletResponse response =
+ Mockito.mock(jakarta.servlet.http.HttpServletResponse.class);
+
Mockito.when(request.getAttribute(JakartaAuthenticationHandler.FAILURE_REASON))
+ .thenReturn("bad");
+
Mockito.when(request.getAttribute(JakartaAuthenticationHandler.FAILURE_REASON_CODE))
+ .thenReturn("code1");
+ StringWriter sw = new StringWriter();
+ Mockito.when(response.getWriter()).thenReturn(new PrintWriter(sw));
+
+ AuthUtil.sendInvalid(request, response);
+
Mockito.verify(response).setStatus(jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN);
+ Mockito.verify(response).setHeader(AuthConstants.X_REASON, "bad");
+ Mockito.verify(response).setHeader(AuthConstants.X_REASON_CODE,
"code1");
+ Assert.assertTrue(sw.toString().contains("bad"));
+ }
+
+ @Test
+ public void test_sendInvalid_noReason_jakarta() {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ jakarta.servlet.http.HttpServletResponse response =
+ Mockito.mock(jakarta.servlet.http.HttpServletResponse.class);
+ AuthUtil.sendInvalid(request, response);
+
Mockito.verify(response).setStatus(jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN);
+ }
+
+ @Test
+ public void test_checkReferer_jakarta() {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ // not a POST -> true
+ Mockito.when(request.getMethod()).thenReturn("GET");
+ Assert.assertTrue(AuthUtil.checkReferer(request, "/login"));
+
+ // POST with no referer -> true
+ Mockito.when(request.getMethod()).thenReturn("POST");
+ Assert.assertTrue(AuthUtil.checkReferer(request, "/login"));
+
+ // POST with matching referer -> true
+ Mockito.when(request.getContextPath()).thenReturn("");
+
Mockito.when(request.getHeader("Referer")).thenReturn("http://host/login");
+ Assert.assertTrue(AuthUtil.checkReferer(request, "/login"));
+
+ // POST with non-matching referer -> false
+
Mockito.when(request.getHeader("Referer")).thenReturn("http://host/other");
+ Assert.assertFalse(AuthUtil.checkReferer(request, "/login"));
+
+ // POST with malformed referer -> true (parse fails, falls through)
+ Mockito.when(request.getHeader("Referer")).thenReturn("::not a url::");
+ Assert.assertTrue(AuthUtil.checkReferer(request, "/login"));
+ }
+
+ @Test
+ public void test_isAjaxRequest_jakarta() {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+
Mockito.when(request.getHeader("X-Requested-With")).thenReturn("XMLHttpRequest");
+ Assert.assertTrue(AuthUtil.isAjaxRequest(request));
+
Mockito.when(request.getHeader("X-Requested-With")).thenReturn("other");
+ Assert.assertFalse(AuthUtil.isAjaxRequest(request));
+ }
+
+ @Test
+ public void test_isRedirectValid_url_jakarta() {
+ Assert.assertFalse(
+
AuthUtil.isRedirectValid((jakarta.servlet.http.HttpServletRequest) null,
"http://www.google.com"));
+ }
+
+ @Test
+ public void test_isBrowserRequest_jakarta() {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+
Mockito.when(request.getHeader("User-Agent")).thenReturn("Mozilla/5.0");
+ Assert.assertTrue(AuthUtil.isBrowserRequest(request));
+ Mockito.when(request.getHeader("User-Agent")).thenReturn("curl");
+ Assert.assertFalse(AuthUtil.isBrowserRequest(request));
+ }
+
+ // ---- Deprecated javax variants ----
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void test_getAttributeOrParameter_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getAttribute("a")).thenReturn("attrValue");
+ Assert.assertEquals("attrValue",
AuthUtil.getAttributeOrParameter(request, "a", "def"));
+
+ Mockito.when(request.getAttribute("b")).thenReturn(null);
+ Mockito.when(request.getParameter("b")).thenReturn("paramValue");
+ Assert.assertEquals("paramValue",
AuthUtil.getAttributeOrParameter(request, "b", "def"));
+
+ Mockito.when(request.getAttribute("c")).thenReturn(null);
+ Mockito.when(request.getParameter("c")).thenReturn(null);
+ Assert.assertEquals("def", AuthUtil.getAttributeOrParameter(request,
"c", "def"));
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void test_getLoginResource_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+
Mockito.when(request.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/res");
+ Assert.assertEquals("/res", AuthUtil.getLoginResource(request,
"/def"));
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void test_getMappedLoginResourcePath_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+
Mockito.when(request.getAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER))
+ .thenReturn(resolver);
+
Mockito.when(request.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/res");
+ Mockito.when(resolver.map(request, "/res")).thenReturn("/mapped/res");
+ Assert.assertEquals("/mapped/res",
AuthUtil.getMappedLoginResourcePath(request, "/def"));
+
+ javax.servlet.http.HttpServletRequest request2 =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Assert.assertNull(AuthUtil.getMappedLoginResourcePath(request2, null));
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void test_setLoginResourceAttribute_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+
Mockito.when(request.getAttribute(Authenticator.LOGIN_RESOURCE)).thenReturn("/existing");
+ Assert.assertEquals("/existing",
AuthUtil.setLoginResourceAttribute(request, "/def"));
+
+ javax.servlet.http.HttpServletRequest request2 =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+
Mockito.when(request2.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/param");
+ Assert.assertEquals("/param",
AuthUtil.setLoginResourceAttribute(request2, "/def"));
+
+ javax.servlet.http.HttpServletRequest request3 =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Assert.assertEquals("/def",
AuthUtil.setLoginResourceAttribute(request3, "/def"));
+
+ javax.servlet.http.HttpServletRequest request4 =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Assert.assertEquals("/", AuthUtil.setLoginResourceAttribute(request4,
null));
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void test_sendRedirect_javax() throws Exception {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ javax.servlet.http.HttpServletResponse response =
Mockito.mock(javax.servlet.http.HttpServletResponse.class);
+ Mockito.when(request.getContextPath()).thenReturn("");
+ Mockito.when(request.getRequestURI()).thenReturn("/current");
+ Mockito.when(request.getQueryString()).thenReturn(null);
+
+ Map<String, String> params = new HashMap<>();
+ params.put("k", "v");
+ AuthUtil.sendRedirect(request, response, "/valid/target", params);
+
Mockito.verify(response).sendRedirect(Mockito.contains("/valid/target?"));
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void test_isValidateRequest_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+
Mockito.when(request.getParameter(AuthConstants.PAR_J_VALIDATE)).thenReturn("true");
+ Assert.assertTrue(AuthUtil.isValidateRequest(request));
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void test_sendValid_javax() {
+ javax.servlet.http.HttpServletResponse response =
Mockito.mock(javax.servlet.http.HttpServletResponse.class);
+ AuthUtil.sendValid(response);
+
Mockito.verify(response).setStatus(javax.servlet.http.HttpServletResponse.SC_OK);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void test_sendInvalid_javax() throws Exception {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ javax.servlet.http.HttpServletResponse response =
Mockito.mock(javax.servlet.http.HttpServletResponse.class);
+
Mockito.when(request.getAttribute(JakartaAuthenticationHandler.FAILURE_REASON))
+ .thenReturn("bad");
+ StringWriter sw = new StringWriter();
+ Mockito.when(response.getWriter()).thenReturn(new PrintWriter(sw));
+ AuthUtil.sendInvalid(request, response);
+
Mockito.verify(response).setStatus(javax.servlet.http.HttpServletResponse.SC_FORBIDDEN);
+ Assert.assertTrue(sw.toString().contains("bad"));
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void test_checkReferer_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getMethod()).thenReturn("POST");
+ Mockito.when(request.getContextPath()).thenReturn("");
+
Mockito.when(request.getHeader("Referer")).thenReturn("http://host/login");
+ Assert.assertTrue(AuthUtil.checkReferer(request, "/login"));
+
Mockito.when(request.getHeader("Referer")).thenReturn("http://host/other");
+ Assert.assertFalse(AuthUtil.checkReferer(request, "/login"));
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void test_isAjaxRequest_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+
Mockito.when(request.getHeader("X-Requested-With")).thenReturn("XMLHttpRequest");
+ Assert.assertTrue(AuthUtil.isAjaxRequest(request));
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void test_isBrowserRequest_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getHeader("User-Agent")).thenReturn("Opera/9");
+ Assert.assertTrue(AuthUtil.isBrowserRequest(request));
+ Mockito.when(request.getHeader("User-Agent")).thenReturn(null);
+ Assert.assertFalse(AuthUtil.isBrowserRequest(request));
+ }
+
+ @SuppressWarnings("deprecation")
+ @Test
+ public void test_isRedirectValid_javax() {
+
Assert.assertFalse(AuthUtil.isRedirectValid((javax.servlet.http.HttpServletRequest)
null, "http://host"));
+
Assert.assertTrue(AuthUtil.isRedirectValid((javax.servlet.http.HttpServletRequest)
null, "/absolute/path"));
+
Assert.assertFalse(AuthUtil.isRedirectValid((javax.servlet.http.HttpServletRequest)
null, "/unnormalized//x"));
+ }
+
+ // ---- jakarta isRedirectValid, resolver resolves the target ----
+
+ @Test
+ public void test_isRedirectValid_resolvesToResource_jakarta() {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getContextPath()).thenReturn("");
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+ final Resource resource = Mockito.mock(Resource.class);
+ Mockito.when(resource.getResourceType()).thenReturn("some/type");
+ Mockito.when(resolver.resolve(Mockito.eq(request),
Mockito.anyString())).thenReturn(resource);
+
Mockito.when(request.getAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER))
+ .thenReturn(resolver);
+
+ Assert.assertTrue(AuthUtil.isRedirectValid(request, "/valid/path"));
+ }
+
+ // ---- javax isRedirectValid full branch coverage ----
+
+ @Test
+ public void test_isRedirectValid_empty_javax() {
+
Assert.assertFalse(AuthUtil.isRedirectValid((javax.servlet.http.HttpServletRequest)
null, ""));
+
Assert.assertFalse(AuthUtil.isRedirectValid((javax.servlet.http.HttpServletRequest)
null, null));
+ }
+
+ @Test
+ public void test_isRedirectValid_illegalCharacters_javax() {
+ // a space triggers a URISyntaxException
+
Assert.assertFalse(AuthUtil.isRedirectValid((javax.servlet.http.HttpServletRequest)
null, "/a b"));
+ }
+
+ @Test
+ public void test_isRedirectValid_url_javax() {
+
Assert.assertFalse(AuthUtil.isRedirectValid((javax.servlet.http.HttpServletRequest)
null, "http://host/x"));
+ }
+
+ @Test
+ public void test_isRedirectValid_notNormalized_javax() {
+
Assert.assertFalse(AuthUtil.isRedirectValid((javax.servlet.http.HttpServletRequest)
null, "/a//b"));
+ }
+
+ @Test
+ public void test_isRedirectValid_contextPathMismatch_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getContextPath()).thenReturn("/ctx");
+ Assert.assertFalse(AuthUtil.isRedirectValid(request, "/other/path"));
+ }
+
+ @Test
+ public void test_isRedirectValid_contextRoot_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getContextPath()).thenReturn("/ctx");
+ Assert.assertTrue(AuthUtil.isRedirectValid(request, "/ctx"));
+ }
+
+ @Test
+ public void test_isRedirectValid_notAbsoluteAfterContext_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getContextPath()).thenReturn("/ctx");
+ Assert.assertFalse(AuthUtil.isRedirectValid(request, "/ctxrelative"));
+ }
+
+ @Test
+ public void test_isRedirectValid_illegalChars_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getContextPath()).thenReturn("");
+ Assert.assertFalse(AuthUtil.isRedirectValid(request, "/path'quote"));
+ }
+
+ @Test
+ public void test_isRedirectValid_resolvesToResource_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getContextPath()).thenReturn("");
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+ final Resource resource = Mockito.mock(Resource.class);
+ Mockito.when(resource.getResourceType()).thenReturn("some/type");
+ Mockito.when(resolver.resolve(Mockito.eq(request),
Mockito.anyString())).thenReturn(resource);
+
Mockito.when(request.getAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER))
+ .thenReturn(resolver);
+
+ Assert.assertTrue(AuthUtil.isRedirectValid(request, "/valid/path"));
+ }
+
+ // ---- javax sendRedirect branch coverage ----
+
+ @Test
+ public void test_sendRedirect_invalidTarget_rootContext_javax() throws
Exception {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ javax.servlet.http.HttpServletResponse response =
Mockito.mock(javax.servlet.http.HttpServletResponse.class);
+ Mockito.when(request.getContextPath()).thenReturn("");
+ Mockito.when(request.getRequestURI()).thenReturn("/current");
+ AuthUtil.sendRedirect(request, response, "relative", null);
+ Mockito.verify(response).sendRedirect(Mockito.startsWith("/?"));
+ }
+
+ @Test
+ public void test_sendRedirect_invalidTarget_withContext_javax() throws
Exception {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ javax.servlet.http.HttpServletResponse response =
Mockito.mock(javax.servlet.http.HttpServletResponse.class);
+ Mockito.when(request.getContextPath()).thenReturn("/ctx");
+ Mockito.when(request.getRequestURI()).thenReturn("/ctx/current");
+ Mockito.when(request.getQueryString()).thenReturn("a=b");
+ final Map<String, String> params = new HashMap<>();
+ AuthUtil.sendRedirect(request, response, "relative", params);
+ Mockito.verify(response).sendRedirect(Mockito.startsWith("/ctx?"));
+ }
+
+ // ---- jakarta sendInvalid with reason code ----
+
+ @Test
+ public void test_sendInvalid_withReasonCode_jakarta() throws Exception {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ jakarta.servlet.http.HttpServletResponse response =
+ Mockito.mock(jakarta.servlet.http.HttpServletResponse.class);
+
Mockito.when(request.getAttribute(JakartaAuthenticationHandler.FAILURE_REASON))
+ .thenReturn("bad");
+
Mockito.when(request.getAttribute(JakartaAuthenticationHandler.FAILURE_REASON_CODE))
+ .thenReturn("code42");
+ Mockito.when(response.getWriter()).thenReturn(new
java.io.PrintWriter(new java.io.StringWriter()));
+ AuthUtil.sendInvalid(request, response);
+ Mockito.verify(response).setHeader(AuthConstants.X_REASON_CODE,
"code42");
+ }
+
+ // ---- IOException error paths ----
+
+ @Test
+ public void test_sendValid_ioexception_jakarta() throws Exception {
+ jakarta.servlet.http.HttpServletResponse response =
+ Mockito.mock(jakarta.servlet.http.HttpServletResponse.class);
+ Mockito.doThrow(new IOException("boom")).when(response).flushBuffer();
+ AuthUtil.sendValid(response);
+ }
+
+ @Test
+ public void test_sendValid_ioexception_javax() throws Exception {
+ javax.servlet.http.HttpServletResponse response =
Mockito.mock(javax.servlet.http.HttpServletResponse.class);
+ Mockito.doThrow(new IOException("boom")).when(response).flushBuffer();
+ AuthUtil.sendValid(response);
+ }
+
+ @Test
+ public void test_sendInvalid_ioexception_jakarta() throws Exception {
+ jakarta.servlet.http.HttpServletRequest request =
Mockito.mock(jakarta.servlet.http.HttpServletRequest.class);
+ jakarta.servlet.http.HttpServletResponse response =
+ Mockito.mock(jakarta.servlet.http.HttpServletResponse.class);
+ Mockito.doThrow(new IOException("boom")).when(response).flushBuffer();
+ AuthUtil.sendInvalid(request, response);
+ }
+
+ @Test
+ public void test_sendInvalid_ioexception_javax() throws Exception {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ javax.servlet.http.HttpServletResponse response =
Mockito.mock(javax.servlet.http.HttpServletResponse.class);
+ Mockito.doThrow(new IOException("boom")).when(response).flushBuffer();
+ AuthUtil.sendInvalid(request, response);
+ }
+
+ // ---- javax checkReferer malformed URL ----
+
+ @Test
+ public void test_checkReferer_malformedUrl_javax() {
+ javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getMethod()).thenReturn("POST");
+ Mockito.when(request.getContextPath()).thenReturn("");
+ Mockito.when(request.getHeader("Referer")).thenReturn("::: not a url
:::");
+ Assert.assertTrue(AuthUtil.checkReferer(request, "/login"));
+ }
}
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/AuthenticationHandlerHolderTest.java
b/src/test/java/org/apache/sling/auth/core/impl/AuthenticationHandlerHolderTest.java
new file mode 100644
index 0000000..31bd0aa
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/impl/AuthenticationHandlerHolderTest.java
@@ -0,0 +1,242 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.impl;
+
+import java.io.IOException;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.sling.auth.core.AuthConstants;
+import org.apache.sling.auth.core.spi.AuthenticationInfo;
+import org.apache.sling.auth.core.spi.JakartaAuthenticationFeedbackHandler;
+import org.apache.sling.auth.core.spi.JakartaAuthenticationHandler;
+import org.junit.Test;
+import org.mockito.InOrder;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+public class AuthenticationHandlerHolderTest {
+
+ private static final String PATH = "/content";
+
+ private interface FeedbackHandler extends JakartaAuthenticationHandler,
JakartaAuthenticationFeedbackHandler {}
+
+ @SuppressWarnings("deprecation")
+ private interface LegacyFeedbackHandler
+ extends org.apache.sling.auth.core.spi.AuthenticationHandler,
+
org.apache.sling.auth.core.spi.AuthenticationFeedbackHandler {}
+
+ @Test
+ public void extractCredentialsSetsAndRestoresExistingPath() {
+ final JakartaAuthenticationHandler handler =
mock(JakartaAuthenticationHandler.class);
+ final AuthenticationHandlerHolder holder = holder(handler, "form",
null);
+ final HttpServletRequest request = mock(HttpServletRequest.class);
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+ final AuthenticationInfo authInfo = new AuthenticationInfo("form");
+
when(request.getAttribute(JakartaAuthenticationHandler.PATH_PROPERTY)).thenReturn("oldPath");
+ when(handler.extractCredentials(request,
response)).thenReturn(authInfo);
+
+ assertSame(authInfo, holder.extractCredentials(request, response));
+
+ final InOrder order = inOrder(request, handler);
+
order.verify(request).getAttribute(JakartaAuthenticationHandler.PATH_PROPERTY);
+
order.verify(request).setAttribute(JakartaAuthenticationHandler.PATH_PROPERTY,
PATH);
+ order.verify(handler).extractCredentials(request, response);
+
order.verify(request).setAttribute(JakartaAuthenticationHandler.PATH_PROPERTY,
"oldPath");
+ }
+
+ @Test
+ public void dropCredentialsRemovesPathWhenNoPreviousPathExists() throws
IOException {
+ final JakartaAuthenticationHandler handler =
mock(JakartaAuthenticationHandler.class);
+ final AuthenticationHandlerHolder holder = holder(handler, "form",
null);
+ final HttpServletRequest request = mock(HttpServletRequest.class);
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+
+ holder.dropCredentials(request, response);
+
+ final InOrder order = inOrder(request, handler);
+
order.verify(request).setAttribute(JakartaAuthenticationHandler.PATH_PROPERTY,
PATH);
+ order.verify(handler).dropCredentials(request, response);
+
order.verify(request).removeAttribute(JakartaAuthenticationHandler.PATH_PROPERTY);
+ }
+
+ @Test
+ public void requestCredentialsDelegatesWhenRequestedLoginMatchesAuthType()
throws IOException {
+ final JakartaAuthenticationHandler handler =
mock(JakartaAuthenticationHandler.class);
+ final AuthenticationHandlerHolder holder = holder(handler, "form",
null);
+ final HttpServletRequest request = requestWithLogin(null, "form");
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+ when(handler.requestCredentials(request, response)).thenReturn(true);
+
+ assertTrue(holder.requestCredentials(request, response));
+
+ verify(handler).requestCredentials(request, response);
+
verify(request).removeAttribute(JakartaAuthenticationHandler.PATH_PROPERTY);
+ }
+
+ @Test
+ public void
requestCredentialsSkipsWhenRequestedLoginDoesNotMatchAuthType() throws
IOException {
+ final JakartaAuthenticationHandler handler =
mock(JakartaAuthenticationHandler.class);
+ final AuthenticationHandlerHolder holder = holder(handler, "form",
null);
+ final HttpServletRequest request = requestWithLogin(null, "basic");
+
+ assertFalse(holder.requestCredentials(request,
mock(HttpServletResponse.class)));
+
+ verify(handler,
never()).requestCredentials(any(HttpServletRequest.class),
any(HttpServletResponse.class));
+
verify(request).removeAttribute(JakartaAuthenticationHandler.PATH_PROPERTY);
+ }
+
+ @Test
+ public void requestCredentialsUsesLoginAttributeBeforeParameter() throws
IOException {
+ final JakartaAuthenticationHandler handler =
mock(JakartaAuthenticationHandler.class);
+ final AuthenticationHandlerHolder holder = holder(handler, "form",
null);
+ final HttpServletRequest request = requestWithLogin("form", "basic");
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+ when(handler.requestCredentials(request, response)).thenReturn(true);
+
+ assertTrue(holder.requestCredentials(request, response));
+
+ verify(handler).requestCredentials(request, response);
+ }
+
+ @Test
+ public void requestCredentialsWithoutAuthTypeIgnoresRequestedLogin()
throws IOException {
+ final JakartaAuthenticationHandler handler =
mock(JakartaAuthenticationHandler.class);
+ final AuthenticationHandlerHolder holder = holder(handler, null, null);
+ final HttpServletRequest request = requestWithLogin(null, "basic");
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+ when(handler.requestCredentials(request, response)).thenReturn(true);
+
+ assertTrue(holder.requestCredentials(request, response));
+
+ verify(handler).requestCredentials(request, response);
+ }
+
+ @Test
+ public void browserOnlyRequestCredentialsSkipsNonBrowserRequests() throws
IOException {
+ final JakartaAuthenticationHandler handler =
mock(JakartaAuthenticationHandler.class);
+ final AuthenticationHandlerHolder holder = holder(handler, "form",
"true");
+ final HttpServletRequest request = requestWithLogin(null, null);
+ when(request.getHeader("User-Agent")).thenReturn("curl/8.0");
+
+ assertFalse(holder.requestCredentials(request,
mock(HttpServletResponse.class)));
+
+ verify(handler,
never()).requestCredentials(any(HttpServletRequest.class),
any(HttpServletResponse.class));
+ }
+
+ @Test
+ public void
browserOnlyRequestCredentialsAllowsBrowserRequestsForYesValue() throws
IOException {
+ final JakartaAuthenticationHandler handler =
mock(JakartaAuthenticationHandler.class);
+ final AuthenticationHandlerHolder holder = holder(handler, "form",
"yes");
+ final HttpServletRequest request = requestWithLogin(null, null);
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+ when(request.getHeader("User-Agent")).thenReturn("Mozilla/5.0");
+ when(handler.requestCredentials(request, response)).thenReturn(true);
+
+ assertTrue(holder.requestCredentials(request, response));
+
+ verify(handler).requestCredentials(request, response);
+ }
+
+ @Test
+ public void
getFeedbackHandlerReturnsJakartaFeedbackHandlerOnlyWhenImplemented() {
+ final FeedbackHandler feedbackHandler = mock(FeedbackHandler.class);
+ assertSame(feedbackHandler, holder(feedbackHandler, "form",
null).getFeedbackHandler());
+ assertNull(
+ holder(mock(JakartaAuthenticationHandler.class), "form",
null).getFeedbackHandler());
+ }
+
+ @Test
+ @SuppressWarnings("deprecation")
+ public void legacyConstructorWrapsDeprecatedAuthenticationHandler() {
+ final org.apache.sling.auth.core.spi.AuthenticationHandler handler =
mock(LegacyFeedbackHandler.class);
+ final AuthenticationHandlerHolder holder =
+ new AuthenticationHandlerHolder(PATH, handler,
serviceReference("legacy", null));
+ final HttpServletRequest request = mock(HttpServletRequest.class);
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+ final AuthenticationInfo authInfo = new AuthenticationInfo("legacy");
+ when(handler.extractCredentials(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class)))
+ .thenReturn(authInfo);
+
+ assertSame(authInfo, holder.extractCredentials(request, response));
+ }
+
+ @Test
+ public void equalsHashCodeCompareToAndToStringIncludeHolderState() {
+ final JakartaAuthenticationHandler handler =
mock(JakartaAuthenticationHandler.class);
+ when(handler.toString()).thenReturn("handlerString");
+ final ServiceReference<?> serviceReference = serviceReference("form",
null);
+ final AuthenticationHandlerHolder holder = new
AuthenticationHandlerHolder(PATH, handler, serviceReference);
+ final AuthenticationHandlerHolder same = new
AuthenticationHandlerHolder(PATH, handler, serviceReference);
+ final AuthenticationHandlerHolder differentHandler =
+ new AuthenticationHandlerHolder(PATH,
mock(JakartaAuthenticationHandler.class), serviceReference);
+ final AuthenticationHandlerHolder differentType =
+ new AuthenticationHandlerHolder(PATH, handler,
serviceReference("basic", null));
+ final AuthenticationHandlerHolder differentBrowserOnly =
+ new AuthenticationHandlerHolder(PATH, handler,
serviceReference("form", "true"));
+
+ assertEquals(holder, holder);
+ assertEquals(holder, same);
+ assertEquals(holder.hashCode(), same.hashCode());
+ assertEquals(0, holder.compareTo(same));
+ assertNotEquals(holder, null);
+ assertNotEquals(holder, differentHandler);
+ assertNotEquals(holder, differentType);
+ assertNotEquals(holder, differentBrowserOnly);
+ assertEquals("handlerString", holder.toString());
+ assertTrue(holder.isPathRequiresHandler("/content/page"));
+ }
+
+ private AuthenticationHandlerHolder holder(
+ final JakartaAuthenticationHandler handler, final String authType,
final String browserOnly) {
+ return new AuthenticationHandlerHolder(PATH, handler,
serviceReference(authType, browserOnly));
+ }
+
+ private HttpServletRequest requestWithLogin(final String attributeValue,
final String parameterValue) {
+ final HttpServletRequest request = mock(HttpServletRequest.class);
+
when(request.getAttribute(JakartaAuthenticationHandler.REQUEST_LOGIN_PARAMETER))
+ .thenReturn(attributeValue);
+
when(request.getParameter(JakartaAuthenticationHandler.REQUEST_LOGIN_PARAMETER))
+ .thenReturn(parameterValue);
+ return request;
+ }
+
+ private ServiceReference<?> serviceReference(final String authType, final
String browserOnly) {
+ final ServiceReference<?> serviceReference =
mock(ServiceReference.class);
+
when(serviceReference.getProperty(JakartaAuthenticationHandler.TYPE_PROPERTY))
+ .thenReturn(authType);
+
when(serviceReference.getProperty(AuthConstants.AUTH_HANDLER_BROWSER_ONLY))
+ .thenReturn(browserOnly);
+ return serviceReference;
+ }
+}
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/AuthenticationHandlerWrapperTest.java
b/src/test/java/org/apache/sling/auth/core/impl/AuthenticationHandlerWrapperTest.java
new file mode 100644
index 0000000..6fc93ae
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/impl/AuthenticationHandlerWrapperTest.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.impl;
+
+import java.io.IOException;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.sling.auth.core.spi.AuthenticationFeedbackHandler;
+import org.apache.sling.auth.core.spi.AuthenticationHandler;
+import org.apache.sling.auth.core.spi.AuthenticationInfo;
+import org.apache.sling.auth.core.spi.JakartaAuthenticationFeedbackHandler;
+import org.apache.sling.auth.core.spi.JakartaAuthenticationHandler;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@SuppressWarnings("deprecation")
+public class AuthenticationHandlerWrapperTest {
+
+ private interface FeedbackHandler extends AuthenticationHandler,
AuthenticationFeedbackHandler {}
+
+ @Test
+ public void plainWrapperDelegatesAuthenticationHandlerMethods() throws
IOException {
+ final AuthenticationHandler handler =
mock(AuthenticationHandler.class);
+ final JakartaAuthenticationHandler wrapper =
AuthenticationHandlerWrapper.wrap(handler);
+ final HttpServletRequest request = mock(HttpServletRequest.class);
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+ final AuthenticationInfo authInfo = new AuthenticationInfo("legacy");
+ when(handler.extractCredentials(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class)))
+ .thenReturn(authInfo);
+ when(handler.requestCredentials(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class)))
+ .thenReturn(true);
+
+ assertFalse(wrapper instanceof JakartaAuthenticationFeedbackHandler);
+ assertSame(authInfo, wrapper.extractCredentials(request, response));
+ assertTrue(wrapper.requestCredentials(request, response));
+ wrapper.dropCredentials(request, response);
+
+ final ArgumentCaptor<javax.servlet.http.HttpServletRequest>
requestCaptor =
+
ArgumentCaptor.forClass(javax.servlet.http.HttpServletRequest.class);
+ final ArgumentCaptor<javax.servlet.http.HttpServletResponse>
responseCaptor =
+
ArgumentCaptor.forClass(javax.servlet.http.HttpServletResponse.class);
+ verify(handler).extractCredentials(requestCaptor.capture(),
responseCaptor.capture());
+ verify(handler)
+ .requestCredentials(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class));
+ verify(handler)
+ .dropCredentials(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class));
+ assertNotNull(requestCaptor.getValue());
+ assertNotNull(responseCaptor.getValue());
+ }
+
+ @Test
+ public void feedbackWrapperDelegatesFeedbackMethods() {
+ final FeedbackHandler handler = mock(FeedbackHandler.class);
+ final JakartaAuthenticationHandler wrapper =
AuthenticationHandlerWrapper.wrap(handler);
+ final JakartaAuthenticationFeedbackHandler feedbackWrapper =
(JakartaAuthenticationFeedbackHandler) wrapper;
+ final HttpServletRequest request = mock(HttpServletRequest.class);
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+ final AuthenticationInfo authInfo = new AuthenticationInfo("legacy");
+ when(handler.authenticationSucceeded(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class),
+ any(AuthenticationInfo.class)))
+ .thenReturn(true);
+
+ feedbackWrapper.authenticationFailed(request, response, authInfo);
+ assertTrue(feedbackWrapper.authenticationSucceeded(request, response,
authInfo));
+
+ verify(handler)
+ .authenticationFailed(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class),
+ org.mockito.ArgumentMatchers.same(authInfo));
+ verify(handler)
+ .authenticationSucceeded(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class),
+ org.mockito.ArgumentMatchers.same(authInfo));
+ }
+}
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/AuthenticationRequirementHolderTest.java
b/src/test/java/org/apache/sling/auth/core/impl/AuthenticationRequirementHolderTest.java
new file mode 100644
index 0000000..c51ca32
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/impl/AuthenticationRequirementHolderTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.impl;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class AuthenticationRequirementHolderTest {
+
+ @Test
+ public void test_fromConfig_plus() {
+ AuthenticationRequirementHolder h =
AuthenticationRequirementHolder.fromConfig("+/secure", null);
+ Assert.assertTrue(h.requiresAuthentication());
+ Assert.assertEquals("/secure", h.fullPath);
+ }
+
+ @Test
+ public void test_fromConfig_minus() {
+ AuthenticationRequirementHolder h =
AuthenticationRequirementHolder.fromConfig("-/open", null);
+ Assert.assertFalse(h.requiresAuthentication());
+ Assert.assertEquals("/open", h.fullPath);
+ }
+
+ @Test
+ public void test_fromConfig_plain() {
+ AuthenticationRequirementHolder h =
AuthenticationRequirementHolder.fromConfig("/plain", null);
+ Assert.assertTrue(h.requiresAuthentication());
+ Assert.assertEquals("/plain", h.fullPath);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void test_fromConfig_null() {
+ AuthenticationRequirementHolder.fromConfig(null, null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void test_fromConfig_empty() {
+ AuthenticationRequirementHolder.fromConfig("", null);
+ }
+
+ @Test
+ public void test_hashCode_equals() {
+ AuthenticationRequirementHolder a = new
AuthenticationRequirementHolder("/p", true, null);
+ AuthenticationRequirementHolder b = new
AuthenticationRequirementHolder("/p", true, null);
+ AuthenticationRequirementHolder c = new
AuthenticationRequirementHolder("/p", false, null);
+
+ Assert.assertEquals(a, b);
+ Assert.assertEquals(a.hashCode(), b.hashCode());
+ Assert.assertNotEquals(a, c);
+ Assert.assertNotEquals(a.hashCode(), c.hashCode());
+ Assert.assertEquals(a, a);
+ Assert.assertNotEquals(a, null);
+ Assert.assertNotEquals(a, "not a holder");
+ }
+}
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/AuthenticatorWebConsolePluginTest.java
b/src/test/java/org/apache/sling/auth/core/impl/AuthenticatorWebConsolePluginTest.java
new file mode 100644
index 0000000..c03e1b2
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/impl/AuthenticatorWebConsolePluginTest.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.impl;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.sling.auth.core.impl.hc.SetField;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class AuthenticatorWebConsolePluginTest {
+
+ private SlingAuthenticator.Config config;
+ private AuthenticationHandlersManager handlersManager;
+
+ @SuppressWarnings("unchecked")
+ private PathBasedHolderCache<AuthenticationRequirementHolder>
requirementsManager =
+ Mockito.mock(PathBasedHolderCache.class);
+
+ private HttpServletRequest request =
Mockito.mock(HttpServletRequest.class);
+ private HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+
+ @Before
+ public void setup() throws Exception {
+ config = Mockito.mock(SlingAuthenticator.Config.class);
+ Mockito.when(config.sling_auth_anonymous_user()).thenReturn("");
+ Mockito.when(config.auth_sudo_cookie()).thenReturn("sling.sudo");
+ Mockito.when(config.auth_sudo_parameter()).thenReturn("sudo");
+
+ handlersManager = Mockito.mock(AuthenticationHandlersManager.class);
+ Map<String, List<String>> handlerMap = new LinkedHashMap<>();
+ handlerMap.put("/path/a", Arrays.asList("HandlerA", "HandlerB"));
+
Mockito.when(handlersManager.getAuthenticationHandlerMap()).thenReturn(handlerMap);
+
+ Mockito.when(requirementsManager.getHolders())
+ .thenReturn(Arrays.asList(
+ new AuthenticationRequirementHolder("/secure", true,
null),
+ new AuthenticationRequirementHolder("/public", false,
null)));
+ }
+
+ private AuthenticatorWebConsolePlugin newPlugin() throws Exception {
+ AuthenticatorWebConsolePlugin plugin = new
AuthenticatorWebConsolePlugin(config);
+ SetField.set(plugin, "authenticationHoldersManager", handlersManager);
+ SetField.set(plugin, "authenticationRequirementsManager",
requirementsManager);
+ return plugin;
+ }
+
+ @Test
+ public void test_doGet_rendersAllSections() throws Exception {
+ AuthenticatorWebConsolePlugin plugin = newPlugin();
+ StringWriter sw = new StringWriter();
+ Mockito.when(response.getWriter()).thenReturn(new PrintWriter(sw));
+
+ plugin.doGet(request, response);
+
+ String out = sw.toString();
+ Assert.assertTrue(out.contains("Registered Authentication Handler"));
+ Assert.assertTrue(out.contains("/path/a"));
+ Assert.assertTrue(out.contains("HandlerA"));
+ Assert.assertTrue(out.contains("Authentication Requirement
Configuration"));
+ Assert.assertTrue(out.contains("/secure"));
+ Assert.assertTrue(out.contains("Yes"));
+ Assert.assertTrue(out.contains("/public"));
+ Assert.assertTrue(out.contains("No"));
+ Assert.assertTrue(out.contains("Miscellaneous Configuration"));
+ Assert.assertTrue(out.contains("sling.sudo"));
+ Assert.assertTrue(out.contains("sudo"));
+ }
+
+ @Test
+ public void test_config_default_anonymous_user() throws Exception {
+ Mockito.when(config.sling_auth_anonymous_user()).thenReturn(null);
+ AuthenticatorWebConsolePlugin plugin = newPlugin();
+ StringWriter sw = new StringWriter();
+ Mockito.when(response.getWriter()).thenReturn(new PrintWriter(sw));
+
+ plugin.doGet(request, response);
+ Assert.assertTrue(sw.toString().contains("(default)"));
+ }
+
+ @Test
+ public void test_service_get_dispatches() throws Exception {
+ AuthenticatorWebConsolePlugin plugin = newPlugin();
+ StringWriter sw = new StringWriter();
+ Mockito.when(response.getWriter()).thenReturn(new PrintWriter(sw));
+ Mockito.when(request.getMethod()).thenReturn("GET");
+ Mockito.when(request.getProtocol()).thenReturn("HTTP/1.1");
+
+ plugin.service(request, response);
+ Assert.assertTrue(sw.toString().contains("Registered Authentication
Handler"));
+ }
+
+ @Test
+ public void test_service_post_ignored() throws Exception {
+ AuthenticatorWebConsolePlugin plugin = newPlugin();
+ Mockito.when(request.getMethod()).thenReturn("POST");
+
+ plugin.service(request, response);
+ Mockito.verify(response, Mockito.never()).getWriter();
+ }
+
+ @Test
+ public void test_doGet_ioexception_sends_error() throws Exception {
+ AuthenticatorWebConsolePlugin plugin = newPlugin();
+ jakarta.servlet.ServletConfig scfg =
Mockito.mock(jakarta.servlet.ServletConfig.class);
+
Mockito.when(scfg.getServletContext()).thenReturn(Mockito.mock(jakarta.servlet.ServletContext.class));
+ plugin.init(scfg);
+ Mockito.when(response.getWriter()).thenThrow(new IOException("no
writer"));
+
+ plugin.doGet(request, response);
+
Mockito.verify(response).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+
+ @Test
+ public void test_modified_updates_config() throws Exception {
+ AuthenticatorWebConsolePlugin plugin = newPlugin();
+ SlingAuthenticator.Config newConfig =
Mockito.mock(SlingAuthenticator.Config.class);
+ Mockito.when(newConfig.sling_auth_anonymous_user()).thenReturn(null);
+ Mockito.when(newConfig.auth_sudo_cookie()).thenReturn("c2");
+ Mockito.when(newConfig.auth_sudo_parameter()).thenReturn("p2");
+ plugin.modified(newConfig);
+
+ StringWriter sw = new StringWriter();
+ Mockito.when(response.getWriter()).thenReturn(new PrintWriter(sw));
+ plugin.doGet(request, response);
+ Assert.assertTrue(sw.toString().contains("c2"));
+ Assert.assertTrue(sw.toString().contains("p2"));
+ }
+}
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/HttpBasicAuthenticationHandlerTest.java
b/src/test/java/org/apache/sling/auth/core/impl/HttpBasicAuthenticationHandlerTest.java
new file mode 100644
index 0000000..97db2d9
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/impl/HttpBasicAuthenticationHandlerTest.java
@@ -0,0 +1,177 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.impl;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.sling.auth.core.spi.AuthenticationInfo;
+import org.apache.sling.auth.core.spi.JakartaAuthenticationHandler;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class HttpBasicAuthenticationHandlerTest {
+
+ private HttpServletRequest request =
Mockito.mock(HttpServletRequest.class);
+ private HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+
+ private static String basic(String user, String pass) {
+ String raw = user + ":" + pass;
+ return "Basic " +
Base64.getEncoder().encodeToString(raw.getBytes(StandardCharsets.ISO_8859_1));
+ }
+
+ @Test
+ public void test_extractCredentials_valid() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+
Mockito.when(request.getHeader("Authorization")).thenReturn(basic("admin",
"secret"));
+ AuthenticationInfo info = handler.extractCredentials(request,
response);
+ Assert.assertNotNull(info);
+ Assert.assertEquals("admin", info.getUser());
+ Assert.assertArrayEquals("secret".toCharArray(), info.getPassword());
+ }
+
+ @Test
+ public void test_extractCredentials_no_colon() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ String header = "Basic " +
Base64.getEncoder().encodeToString("justuser".getBytes(StandardCharsets.ISO_8859_1));
+ Mockito.when(request.getHeader("Authorization")).thenReturn(header);
+ AuthenticationInfo info = handler.extractCredentials(request);
+ Assert.assertNotNull(info);
+ Assert.assertEquals("justuser", info.getUser());
+ Assert.assertEquals(0, info.getPassword().length);
+ }
+
+ @Test
+ public void test_extractCredentials_no_header() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ Assert.assertNull(handler.extractCredentials(request));
+ Mockito.when(request.getHeader("Authorization")).thenReturn("");
+ Assert.assertNull(handler.extractCredentials(request));
+ }
+
+ @Test
+ public void test_extractCredentials_no_blank() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ Mockito.when(request.getHeader("Authorization")).thenReturn("Basic");
+ Assert.assertNull(handler.extractCredentials(request));
+ }
+
+ @Test
+ public void test_extractCredentials_wrong_scheme() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ Mockito.when(request.getHeader("Authorization")).thenReturn("Digest
abc");
+ Assert.assertNull(handler.extractCredentials(request));
+ }
+
+ @Test
+ public void test_extractCredentials_login_requested() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ Mockito.when(request.getHeader("Authorization")).thenReturn(null);
+
Mockito.when(request.getParameter(JakartaAuthenticationHandler.REQUEST_LOGIN_PARAMETER))
+ .thenReturn("BASIC");
+ AuthenticationInfo info = handler.extractCredentials(request,
response);
+ Assert.assertSame(AuthenticationInfo.DOING_AUTH, info);
+
Mockito.verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+
+ @Test
+ public void test_extractCredentials_no_login_requested() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ Mockito.when(request.getHeader("Authorization")).thenReturn(null);
+ Assert.assertNull(handler.extractCredentials(request, response));
+ }
+
+ @Test
+ public void test_requestCredentials_fullSupport() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ Assert.assertTrue(handler.requestCredentials(request, response));
+
Mockito.verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+
+ @Test
+ public void test_requestCredentials_preemptive() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", false);
+ Assert.assertFalse(handler.requestCredentials(request, response));
+ Mockito.verify(response, Mockito.never()).setStatus(Mockito.anyInt());
+ }
+
+ @Test
+ public void test_dropCredentials_fullSupport_withHeader() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ Mockito.when(request.getHeader("Authorization")).thenReturn("Basic
xyz");
+ handler.dropCredentials(request, response);
+
Mockito.verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+
+ @Test
+ public void test_dropCredentials_noHeader() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ Mockito.when(request.getHeader("Authorization")).thenReturn(null);
+ handler.dropCredentials(request, response);
+ Mockito.verify(response, Mockito.never()).setStatus(Mockito.anyInt());
+ }
+
+ @Test
+ public void test_authenticationFailed_notValidate() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ handler.authenticationFailed(request, response, new
AuthenticationInfo("BASIC"));
+
Mockito.verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+ }
+
+ @Test
+ public void test_authenticationFailed_validate() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ Mockito.when(request.getParameter("j_validate")).thenReturn("true");
+ handler.authenticationFailed(request, response, new
AuthenticationInfo("BASIC"));
+ Mockito.verify(response, Mockito.never()).setStatus(Mockito.anyInt());
+ }
+
+ @Test
+ public void test_sendUnauthorized_committed() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ Mockito.when(response.isCommitted()).thenReturn(true);
+ Assert.assertFalse(handler.sendUnauthorized(response));
+ }
+
+ @Test
+ public void test_sendUnauthorized_ok() {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ Assert.assertTrue(handler.sendUnauthorized(response));
+ Mockito.verify(response).setHeader("WWW-Authenticate", "Basic
realm=\"realm\"");
+ }
+
+ @Test
+ public void test_sendUnauthorized_ioexception() throws IOException {
+ HttpBasicAuthenticationHandler handler = new
HttpBasicAuthenticationHandler("realm", true);
+ Mockito.doThrow(new IOException("boom")).when(response).flushBuffer();
+ Assert.assertFalse(handler.sendUnauthorized(response));
+ }
+
+ @Test
+ public void test_toString() {
+ Assert.assertTrue(
+ new HttpBasicAuthenticationHandler("r",
true).toString().contains("enabled"));
+ Assert.assertTrue(
+ new HttpBasicAuthenticationHandler("r",
false).toString().contains("preemptive"));
+ }
+}
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/LoginServletTest.java
b/src/test/java/org/apache/sling/auth/core/impl/LoginServletTest.java
new file mode 100644
index 0000000..43773b0
--- /dev/null
+++ b/src/test/java/org/apache/sling/auth/core/impl/LoginServletTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.impl;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.auth.Authenticator;
+import org.apache.sling.api.auth.NoAuthenticationHandlerException;
+import org.apache.sling.auth.core.impl.hc.SetField;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class LoginServletTest {
+
+ private SlingHttpServletRequest request =
Mockito.mock(SlingHttpServletRequest.class);
+ private SlingHttpServletResponse response =
Mockito.mock(SlingHttpServletResponse.class);
+
+ @Test
+ public void test_login_success() throws Exception {
+ LoginServlet servlet = new LoginServlet();
+ Authenticator authenticator = Mockito.mock(Authenticator.class);
+ SetField.set(servlet, "authenticator", authenticator);
+
+ Mockito.when(request.getAuthType()).thenReturn(null);
+ servlet.service(request, response);
+
+ Mockito.verify(authenticator)
+ .login((javax.servlet.http.HttpServletRequest) request,
(javax.servlet.http.HttpServletResponse)
+ response);
+ }
+
+ @Test
+ public void test_login_redirect_when_authenticated_and_self() throws
Exception {
+ LoginServlet servlet = new LoginServlet();
+ Authenticator authenticator = Mockito.mock(Authenticator.class);
+ SetField.set(servlet, "authenticator", authenticator);
+
+ Mockito.when(request.getAuthType()).thenReturn("BASIC");
+ Mockito.when(request.getContextPath()).thenReturn("/ctx");
+ // no login resource -> resourcePath null -> isSelf true
+ servlet.service(request, response);
+
+ Mockito.verify(response).sendRedirect("/ctx/");
+ Mockito.verify(authenticator, Mockito.never())
+ .login(
+
Mockito.any(javax.servlet.http.HttpServletRequest.class),
+
Mockito.any(javax.servlet.http.HttpServletResponse.class));
+ }
+
+ @Test
+ public void test_login_no_authenticator() throws Exception {
+ LoginServlet servlet = new LoginServlet();
+ Mockito.when(request.getAuthType()).thenReturn(null);
+ servlet.service(request, response);
+
Mockito.verify(response).sendError(Mockito.eq(HttpServletResponse.SC_FORBIDDEN),
Mockito.anyString());
+ }
+
+ @Test
+ public void test_login_no_handler() throws Exception {
+ LoginServlet servlet = new LoginServlet();
+ Authenticator authenticator = Mockito.mock(Authenticator.class);
+ SetField.set(servlet, "authenticator", authenticator);
+ Mockito.when(request.getAuthType()).thenReturn(null);
+ Mockito.doThrow(new NoAuthenticationHandlerException())
+ .when(authenticator)
+ .login(
+
Mockito.any(javax.servlet.http.HttpServletRequest.class),
+
Mockito.any(javax.servlet.http.HttpServletResponse.class));
+
+ servlet.service(request, response);
+
Mockito.verify(response).sendError(Mockito.eq(HttpServletResponse.SC_FORBIDDEN),
Mockito.anyString());
+ }
+
+ @Test
+ public void test_login_response_committed() throws Exception {
+ LoginServlet servlet = new LoginServlet();
+ Authenticator authenticator = Mockito.mock(Authenticator.class);
+ SetField.set(servlet, "authenticator", authenticator);
+ Mockito.when(request.getAuthType()).thenReturn(null);
+ Mockito.doThrow(new IllegalStateException("committed"))
+ .when(authenticator)
+ .login(
+
Mockito.any(javax.servlet.http.HttpServletRequest.class),
+
Mockito.any(javax.servlet.http.HttpServletResponse.class));
+
+ servlet.service(request, response);
+ Mockito.verify(response, Mockito.never()).sendError(Mockito.anyInt(),
Mockito.anyString());
+ }
+}
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/LogoutServletTest.java
b/src/test/java/org/apache/sling/auth/core/impl/LogoutServletTest.java
new file mode 100644
index 0000000..2b98fa8
--- /dev/null
+++ b/src/test/java/org/apache/sling/auth/core/impl/LogoutServletTest.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.impl;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.auth.Authenticator;
+import org.apache.sling.auth.core.impl.hc.SetField;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class LogoutServletTest {
+
+ private SlingHttpServletRequest request =
Mockito.mock(SlingHttpServletRequest.class);
+ private SlingHttpServletResponse response =
Mockito.mock(SlingHttpServletResponse.class);
+
+ @Test
+ public void test_logout_success() throws Exception {
+ LogoutServlet servlet = new LogoutServlet();
+ Authenticator authenticator = Mockito.mock(Authenticator.class);
+ SetField.set(servlet, "authenticator", authenticator);
+
+ servlet.service(request, response);
+ Mockito.verify(authenticator)
+ .logout((javax.servlet.http.HttpServletRequest) request,
(javax.servlet.http.HttpServletResponse)
+ response);
+ }
+
+ @Test
+ public void test_logout_no_authenticator() throws Exception {
+ LogoutServlet servlet = new LogoutServlet();
+ servlet.service(request, response);
+ Mockito.verify(response).setStatus(HttpServletResponse.SC_NO_CONTENT);
+ }
+
+ @Test
+ public void test_logout_response_committed() throws Exception {
+ LogoutServlet servlet = new LogoutServlet();
+ Authenticator authenticator = Mockito.mock(Authenticator.class);
+ SetField.set(servlet, "authenticator", authenticator);
+ Mockito.doThrow(new IllegalStateException("committed"))
+ .when(authenticator)
+ .logout(
+
Mockito.any(javax.servlet.http.HttpServletRequest.class),
+
Mockito.any(javax.servlet.http.HttpServletResponse.class));
+
+ servlet.service(request, response);
+ Mockito.verify(response, Mockito.never()).setStatus(Mockito.anyInt());
+ }
+}
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/PathBasedHolderTest.java
b/src/test/java/org/apache/sling/auth/core/impl/PathBasedHolderTest.java
index a128efa..2548909 100644
--- a/src/test/java/org/apache/sling/auth/core/impl/PathBasedHolderTest.java
+++ b/src/test/java/org/apache/sling/auth/core/impl/PathBasedHolderTest.java
@@ -18,7 +18,11 @@
*/
package org.apache.sling.auth.core.impl;
+import org.junit.Assert;
import org.junit.Test;
+import org.mockito.Mockito;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -26,6 +30,10 @@ import static org.junit.Assert.assertTrue;
public class PathBasedHolderTest {
+ private static PathBasedHolder holder(String url, ServiceReference<?> ref)
{
+ return new PathBasedHolder(url, ref) {};
+ }
+
@Test
public void TestIsPathRequiresHandlerRoot() {
final PathBasedHolder holder = new PathBasedHolder("/", null) {};
@@ -116,4 +124,97 @@ public class PathBasedHolderTest {
final String handlerPath = "";
assertPathRequiresHandler(true, requestPath, handlerPath);
}
+
+ @Test
+ public void test_getProvider_noReference() {
+ assertEquals("Apache Sling Request Authenticator", holder("/x",
null).getProvider());
+ }
+
+ @Test
+ public void test_getProvider_description() {
+ ServiceReference<?> ref = Mockito.mock(ServiceReference.class);
+
Mockito.when(ref.getProperty(Constants.SERVICE_DESCRIPTION)).thenReturn("My
Service");
+ assertEquals("My Service", holder("/x", ref).getProvider());
+ }
+
+ @Test
+ public void test_getProvider_serviceId() {
+ ServiceReference<?> ref = Mockito.mock(ServiceReference.class);
+
Mockito.when(ref.getProperty(Constants.SERVICE_DESCRIPTION)).thenReturn(null);
+ Mockito.when(ref.getProperty(Constants.SERVICE_ID)).thenReturn(42L);
+ assertEquals("Service 42", holder("/x", ref).getProvider());
+ }
+
+ @Test
+ public void test_protocol_and_host_parsing() {
+ PathBasedHolder h = holder("http://example.com/some/path", null);
+ assertTrue(h.isPathRequiresHandler("/some/path"));
+
+ // host only with trailing content
+ PathBasedHolder h2 = holder("//example.com/foo", null);
+ assertTrue(h2.isPathRequiresHandler("/foo"));
+
+ // host only, no path
+ PathBasedHolder h3 = holder("//example.com", null);
+ assertTrue(h3.isPathRequiresHandler("/anything"));
+
+ // just double slash
+ PathBasedHolder h4 = holder("//", null);
+ assertTrue(h4.isPathRequiresHandler("/anything"));
+ }
+
+ @Test
+ public void test_hashCode_and_equals() {
+ PathBasedHolder a = holder("/x", null);
+ PathBasedHolder b = holder("/x", null);
+ assertEquals(a.hashCode(), b.hashCode());
+ assertEquals(a, b);
+ Assert.assertNotEquals(a, holder("/y", null));
+ Assert.assertNotEquals(a, null);
+ Assert.assertNotEquals(a, "not a holder");
+ assertEquals(a, a);
+ }
+
+ @Test
+ public void test_equals_differentServiceReference() {
+ ServiceReference<?> ref = Mockito.mock(ServiceReference.class);
+ Assert.assertNotEquals(holder("/x", ref), holder("/x", null));
+ assertEquals(holder("/x", ref), holder("/x", ref));
+ }
+
+ @Test
+ public void test_compareTo_byPath() {
+ PathBasedHolder a = holder("/a", null);
+ PathBasedHolder b = holder("/b", null);
+ assertTrue(a.compareTo(b) > 0);
+ assertTrue(b.compareTo(a) < 0);
+ }
+
+ @Test
+ public void test_compareTo_nullServiceReferences() {
+ PathBasedHolder a = holder("/same", null);
+ PathBasedHolder b = holder("/same", null);
+ // both null service references -> compared by class name (same class)
-> 0
+ assertEquals(0, a.compareTo(b));
+ }
+
+ @Test
+ public void test_compareTo_oneNullServiceReference() {
+ ServiceReference<?> ref = Mockito.mock(ServiceReference.class);
+ PathBasedHolder withRef = holder("/same", ref);
+ PathBasedHolder withoutRef = holder("/same", null);
+ assertEquals(-1, withoutRef.compareTo(withRef));
+ assertEquals(1, withRef.compareTo(withoutRef));
+ }
+
+ @Test
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ public void test_compareTo_byServiceReference() {
+ ServiceReference refA = Mockito.mock(ServiceReference.class);
+ ServiceReference refB = Mockito.mock(ServiceReference.class);
+ Mockito.when(refB.compareTo(refA)).thenReturn(5);
+ PathBasedHolder a = holder("/same", refA);
+ PathBasedHolder b = holder("/same", refB);
+ assertEquals(5, a.compareTo(b));
+ }
}
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticatorTest.java
b/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticatorTest.java
index 053a6b9..85cebce 100644
--- a/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticatorTest.java
+++ b/src/test/java/org/apache/sling/auth/core/impl/SlingAuthenticatorTest.java
@@ -29,6 +29,7 @@ import jakarta.servlet.http.HttpServletResponse;
import junitx.util.PrivateAccessor;
import org.apache.sling.api.SlingJakartaHttpServletRequest;
import org.apache.sling.api.SlingJakartaHttpServletResponse;
+import org.apache.sling.api.auth.NoAuthenticationHandlerException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.auth.core.AuthenticationSupport;
@@ -493,4 +494,370 @@ public class SlingAuthenticatorTest {
throw new UnsupportedOperationException("Unimplemented method
'dropCredentials'");
}
}
+
+ private SlingAuthenticator
createAuthenticator(AbstractAuthenticationHandlerHolder... holders) {
+ final SlingAuthenticator.Config config =
SlingAuthenticatorTest.createDefaultConfig();
+ final AuthenticationRequirementsManager requirements =
+ new AuthenticationRequirementsManager(createBundleContext(),
null, config, callable -> callable.run());
+ final AuthenticationHandlersManager handlers = new
AuthenticationHandlersManager(config);
+ for (AbstractAuthenticationHandlerHolder h : holders) {
+ handlers.addHolder(h);
+ }
+ return new SlingAuthenticator(requirements, handlers, null,
Mockito.mock(BundleContext.class), config);
+ }
+
+ private SlingAuthenticator createAuthenticator(
+ final ResourceResolverFactory rrf, final
AbstractAuthenticationHandlerHolder... holders) {
+ final SlingAuthenticator.Config config =
SlingAuthenticatorTest.createDefaultConfig();
+ final AuthenticationRequirementsManager requirements =
+ new AuthenticationRequirementsManager(createBundleContext(),
null, config, callable -> callable.run());
+ final AuthenticationHandlersManager handlers = new
AuthenticationHandlersManager(config);
+ for (AbstractAuthenticationHandlerHolder h : holders) {
+ handlers.addHolder(h);
+ }
+ return new SlingAuthenticator(requirements, handlers, rrf,
Mockito.mock(BundleContext.class), config);
+ }
+
+ private AbstractAuthenticationHandlerHolder infoHolder(final String path,
final AuthenticationInfo info) {
+ return new AbstractAuthenticationHandlerHolder(path, null) {
+ @Override
+ protected JakartaAuthenticationFeedbackHandler
getFeedbackHandler() {
+ return null;
+ }
+
+ @Override
+ protected AuthenticationInfo doExtractCredentials(
+ HttpServletRequest request, HttpServletResponse response) {
+ return info;
+ }
+
+ @Override
+ protected boolean doRequestCredentials(HttpServletRequest request,
HttpServletResponse response)
+ throws IOException {
+ return true;
+ }
+
+ @Override
+ protected void doDropCredentials(HttpServletRequest request,
HttpServletResponse response)
+ throws IOException {}
+ };
+ }
+
+ private AbstractAuthenticationHandlerHolder holder(
+ final String path, final boolean requestResult, final boolean
throwOnRequest) {
+ return new AbstractAuthenticationHandlerHolder(path, null) {
+ @Override
+ protected JakartaAuthenticationFeedbackHandler
getFeedbackHandler() {
+ return null;
+ }
+
+ @Override
+ protected AuthenticationInfo doExtractCredentials(
+ HttpServletRequest request, HttpServletResponse response) {
+ return null;
+ }
+
+ @Override
+ protected boolean doRequestCredentials(HttpServletRequest request,
HttpServletResponse response)
+ throws IOException {
+ if (throwOnRequest) {
+ throw new IOException("boom");
+ }
+ return requestResult;
+ }
+
+ @Override
+ protected void doDropCredentials(HttpServletRequest request,
HttpServletResponse response)
+ throws IOException {}
+ };
+ }
+
+ private HttpServletRequest requestFor(String path) {
+ final HttpServletRequest request =
Mockito.mock(HttpServletRequest.class);
+ Mockito.when(request.getServletPath()).thenReturn(path);
+ Mockito.when(request.getServerName()).thenReturn("localhost");
+ Mockito.when(request.getServerPort()).thenReturn(80);
+ Mockito.when(request.getScheme()).thenReturn("http");
+ Mockito.when(request.getContextPath()).thenReturn("");
+ Mockito.when(request.getRequestURI()).thenReturn(path);
+ return request;
+ }
+
+ @Test
+ public void test_login_success() {
+ final SlingAuthenticator auth = createAuthenticator(holder("/", true,
false));
+ final HttpServletRequest request = requestFor("/content");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ auth.login(request, response);
+ }
+
+ @Test
+ public void test_login_handler_throws_is_treated_as_done() {
+ final SlingAuthenticator auth = createAuthenticator(holder("/", false,
true));
+ final HttpServletRequest request = requestFor("/content");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ auth.login(request, response);
+ }
+
+ @Test(expected = NoAuthenticationHandlerException.class)
+ public void test_login_no_handler() {
+ final SlingAuthenticator auth = createAuthenticator(holder("/", false,
false));
+ final HttpServletRequest request = requestFor("/content");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ auth.login(request, response);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void test_login_response_committed() {
+ final SlingAuthenticator auth = createAuthenticator(holder("/", true,
false));
+ final HttpServletRequest request = requestFor("/content");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ Mockito.when(response.isCommitted()).thenReturn(true);
+ auth.login(request, response);
+ }
+
+ @Test
+ public void test_logout_success() {
+ final SlingAuthenticator auth = createAuthenticator(holder("/", true,
false));
+ final HttpServletRequest request = requestFor("/content");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ auth.logout(request, response);
+ }
+
+ @Test(expected = IllegalStateException.class)
+ public void test_logout_response_committed() {
+ final SlingAuthenticator auth = createAuthenticator(holder("/", true,
false));
+ final HttpServletRequest request = requestFor("/content");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ Mockito.when(response.isCommitted()).thenReturn(true);
+ auth.logout(request, response);
+ }
+
+ @Test
+ public void test_javax_login_wrapper() {
+ final SlingAuthenticator auth = createAuthenticator(holder("/", true,
false));
+ final javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getServletPath()).thenReturn("/content");
+ Mockito.when(request.getServerName()).thenReturn("localhost");
+ Mockito.when(request.getServerPort()).thenReturn(80);
+ Mockito.when(request.getScheme()).thenReturn("http");
+ Mockito.when(request.getContextPath()).thenReturn("");
+ final javax.servlet.http.HttpServletResponse response =
+ Mockito.mock(javax.servlet.http.HttpServletResponse.class);
+ auth.login(request, response);
+ }
+
+ @Test
+ public void test_javax_logout_wrapper() {
+ final SlingAuthenticator auth = createAuthenticator(holder("/", true,
false));
+ final javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getServletPath()).thenReturn("/content");
+ Mockito.when(request.getServerName()).thenReturn("localhost");
+ Mockito.when(request.getServerPort()).thenReturn(80);
+ Mockito.when(request.getScheme()).thenReturn("http");
+ Mockito.when(request.getContextPath()).thenReturn("");
+ final javax.servlet.http.HttpServletResponse response =
+ Mockito.mock(javax.servlet.http.HttpServletResponse.class);
+ auth.logout(request, response);
+ }
+
+ @Test
+ public void test_handleSecurity_already_authenticated() {
+ final SlingAuthenticator auth = createAuthenticator();
+ final HttpServletRequest request = requestFor("/content");
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+
Mockito.when(request.getAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER))
+ .thenReturn(resolver);
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ Assert.assertTrue(auth.handleSecurity(request, response));
+ }
+
+ @Test
+ public void test_handleSecurity_valid_credentials() throws Exception {
+ final ResourceResolverFactory rrf =
Mockito.mock(ResourceResolverFactory.class);
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+
Mockito.when(rrf.getResourceResolver(Mockito.any(java.util.Map.class))).thenReturn(resolver);
+
+ final AuthenticationInfo info = new AuthenticationInfo("basic",
"user", "pwd".toCharArray());
+ final SlingAuthenticator auth = createAuthenticator(rrf,
infoHolder("/", info));
+
+ final HttpServletRequest request = requestFor("/content");
+ // a non-resolver attribute should be overwritten
+
Mockito.when(request.getAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER))
+ .thenReturn("not-a-resolver");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+
+ auth.handleSecurity(request, response);
+ Mockito.verify(request, Mockito.atLeastOnce())
+
.setAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER, resolver);
+ }
+
+ @Test
+ public void test_handleSecurity_valid_credentials_with_redirect() throws
Exception {
+ final ResourceResolverFactory rrf =
Mockito.mock(ResourceResolverFactory.class);
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+
Mockito.when(rrf.getResourceResolver(Mockito.any(java.util.Map.class))).thenReturn(resolver);
+
+ final AuthenticationInfo info = new AuthenticationInfo("basic",
"user", "pwd".toCharArray());
+ final SlingAuthenticator auth = createAuthenticator(rrf,
infoHolder("/", info));
+
+ final HttpServletRequest request = requestFor("/content");
+
Mockito.when(request.getParameter(AuthenticationSupport.REDIRECT_PARAMETER))
+ .thenReturn("/content/redirect");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+
+ // redirect requested -> request considered done, resolver closed
+ Assert.assertFalse(auth.handleSecurity(request, response));
+ Mockito.verify(resolver).close();
+ }
+
+ @Test
+ public void test_handleSecurity_doing_auth() {
+ final SlingAuthenticator auth = createAuthenticator(infoHolder("/",
AuthenticationInfo.DOING_AUTH));
+ final HttpServletRequest request = requestFor("/content");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ Assert.assertFalse(auth.handleSecurity(request, response));
+ }
+
+ @Test
+ public void test_handleSecurity_fail_auth_triggers_login() {
+ final SlingAuthenticator auth = createAuthenticator(infoHolder("/",
AuthenticationInfo.FAIL_AUTH));
+ final HttpServletRequest request = requestFor("/content");
+ Mockito.when(request.getRequestURI()).thenReturn("/content");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ Assert.assertFalse(auth.handleSecurity(request, response));
+ }
+
+ @Test
+ public void test_finishSecurity_closes_resolver() {
+ final SlingAuthenticator auth = createAuthenticator();
+ final HttpServletRequest request = requestFor("/content");
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+
Mockito.when(request.getAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER))
+ .thenReturn(resolver);
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ auth.finishSecurity(request, response);
+ Mockito.verify(resolver).close();
+
Mockito.verify(request).removeAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER);
+ }
+
+ @Test
+ public void test_finishSecurity_no_resolver() {
+ final SlingAuthenticator auth = createAuthenticator();
+ final HttpServletRequest request = requestFor("/content");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ auth.finishSecurity(request, response);
+ }
+
+ @Test
+ public void test_javax_handleSecurity_wrapper() {
+ final ResourceResolverFactory rrf =
Mockito.mock(ResourceResolverFactory.class);
+ final ResourceResolver resolver = Mockito.mock(ResourceResolver.class);
+ try {
+
Mockito.when(rrf.getResourceResolver(Mockito.any(java.util.Map.class)))
+ .thenReturn(resolver);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ final AuthenticationInfo info = new AuthenticationInfo("basic",
"user", "pwd".toCharArray());
+ final SlingAuthenticator auth = createAuthenticator(rrf,
infoHolder("/", info));
+
+ final javax.servlet.http.HttpServletRequest request =
Mockito.mock(javax.servlet.http.HttpServletRequest.class);
+ Mockito.when(request.getServletPath()).thenReturn("/content");
+ Mockito.when(request.getServerName()).thenReturn("localhost");
+ Mockito.when(request.getServerPort()).thenReturn(80);
+ Mockito.when(request.getScheme()).thenReturn("http");
+ Mockito.when(request.getContextPath()).thenReturn("");
+ Mockito.when(request.getRequestURI()).thenReturn("/content");
+ final javax.servlet.http.HttpServletResponse response =
+ Mockito.mock(javax.servlet.http.HttpServletResponse.class);
+ auth.handleSecurity(request, response);
+ }
+
+ @Test
+ public void test_logout_dropCredentials_ioexception() {
+ final AbstractAuthenticationHandlerHolder dropThrows = new
AbstractAuthenticationHandlerHolder("/", null) {
+ @Override
+ protected JakartaAuthenticationFeedbackHandler
getFeedbackHandler() {
+ return null;
+ }
+
+ @Override
+ protected AuthenticationInfo doExtractCredentials(
+ HttpServletRequest request, HttpServletResponse response) {
+ return null;
+ }
+
+ @Override
+ protected boolean doRequestCredentials(HttpServletRequest request,
HttpServletResponse response)
+ throws IOException {
+ return false;
+ }
+
+ @Override
+ protected void doDropCredentials(HttpServletRequest request,
HttpServletResponse response)
+ throws IOException {
+ throw new IOException("boom");
+ }
+ };
+ final SlingAuthenticator auth = createAuthenticator(dropThrows);
+ final HttpServletRequest request = requestFor("/content");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ auth.logout(request, response);
+ }
+
+ private Object invokeHandleLoginFailure(
+ SlingAuthenticator auth,
+ HttpServletRequest request,
+ HttpServletResponse response,
+ AuthenticationInfo info,
+ Exception reason)
+ throws Throwable {
+ return junitx.util.PrivateAccessor.invoke(
+ auth,
+ "handleLoginFailure",
+ new Class[] {
+ HttpServletRequest.class, HttpServletResponse.class,
AuthenticationInfo.class, Exception.class
+ },
+ new Object[] {request, response, info, reason});
+ }
+
+ @Test
+ public void test_handleLoginFailure_loginException_doLogin() throws
Throwable {
+ final SlingAuthenticator auth = createAuthenticator(holder("/", true,
false));
+ final HttpServletRequest request = requestFor("/content");
+
Mockito.when(request.getParameter(org.apache.sling.auth.core.AuthConstants.PAR_J_VALIDATE))
+ .thenReturn("true");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ final AuthenticationInfo info = new AuthenticationInfo("basic",
"user");
+ final Object result = invokeHandleLoginFailure(
+ auth, request, response, info, new
org.apache.sling.api.resource.LoginException("bad"));
+ Assert.assertEquals(Boolean.FALSE, result);
+ }
+
+ @Test
+ public void test_handleLoginFailure_tooManySessions() throws Throwable {
+ final SlingAuthenticator auth = createAuthenticator();
+ final HttpServletRequest request = requestFor("/content");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ final AuthenticationInfo info = new AuthenticationInfo("basic",
"user");
+ invokeHandleLoginFailure(auth, request, response, info, new
TooManySessionsException("too many"));
+ Mockito.verify(response).sendError(Mockito.eq(503),
Mockito.anyString());
+ }
+
+ @Test
+ public void test_handleLoginFailure_genericError() throws Throwable {
+ final SlingAuthenticator auth = createAuthenticator();
+ final HttpServletRequest request = requestFor("/content");
+ final HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+ final AuthenticationInfo info = new AuthenticationInfo("basic",
"user");
+ invokeHandleLoginFailure(auth, request, response, info, new
RuntimeException("kaboom"));
+ Mockito.verify(response).sendError(Mockito.eq(500),
Mockito.anyString());
+ }
+
+ static class TooManySessionsException extends RuntimeException {
+ TooManySessionsException(String msg) {
+ super(msg);
+ }
+ }
}
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/engine/EngineAuthenticationHandlerHolderTest.java
b/src/test/java/org/apache/sling/auth/core/impl/engine/EngineAuthenticationHandlerHolderTest.java
new file mode 100644
index 0000000..a3fc99b
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/impl/engine/EngineAuthenticationHandlerHolderTest.java
@@ -0,0 +1,211 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.impl.engine;
+
+import javax.jcr.Credentials;
+
+import java.io.IOException;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import junitx.util.PrivateAccessor;
+import org.apache.sling.auth.core.spi.AuthenticationFeedbackHandler;
+import org.apache.sling.auth.core.spi.AuthenticationInfo;
+import org.apache.sling.auth.core.spi.JakartaAuthenticationFeedbackHandler;
+import org.apache.sling.engine.auth.AuthenticationHandler;
+import org.junit.Test;
+import org.osgi.framework.ServiceReference;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@SuppressWarnings("deprecation")
+public class EngineAuthenticationHandlerHolderTest {
+
+ private static final String PATH = "/content";
+
+ private interface FeedbackEngineHandler extends AuthenticationHandler,
AuthenticationFeedbackHandler {}
+
+ @Test
+ public void extractCredentialsReturnsNullWhenEngineHandlerReturnsNull() {
+ final AuthenticationHandler handler =
mock(AuthenticationHandler.class);
+ final EngineAuthenticationHandlerHolder holder = holder(handler);
+
+ assertNull(holder.doExtractCredentials(mock(HttpServletRequest.class),
mock(HttpServletResponse.class)));
+ }
+
+ @Test
+ public void extractCredentialsConvertsDoingAuthSingleton() {
+ final AuthenticationHandler handler =
mock(AuthenticationHandler.class);
+ final EngineAuthenticationHandlerHolder holder = holder(handler);
+ when(handler.authenticate(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class)))
+
.thenReturn(org.apache.sling.engine.auth.AuthenticationInfo.DOING_AUTH);
+
+ assertSame(
+ AuthenticationInfo.DOING_AUTH,
+ holder.doExtractCredentials(mock(HttpServletRequest.class),
mock(HttpServletResponse.class)));
+ }
+
+ @Test
+ public void extractCredentialsConvertsLegacyAuthenticationInfo() {
+ final AuthenticationHandler handler =
mock(AuthenticationHandler.class);
+ final EngineAuthenticationHandlerHolder holder = holder(handler);
+ final Credentials credentials = mock(Credentials.class);
+ final org.apache.sling.engine.auth.AuthenticationInfo engineInfo =
+ new org.apache.sling.engine.auth.AuthenticationInfo("engine",
credentials, "workspace");
+ when(handler.authenticate(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class)))
+ .thenReturn(engineInfo);
+
+ final AuthenticationInfo info =
+ holder.doExtractCredentials(mock(HttpServletRequest.class),
mock(HttpServletResponse.class));
+
+ assertEquals("engine", info.getAuthType());
+ assertSame(credentials, info.get("user.jcr.credentials"));
+ assertEquals("workspace", info.get("user.jcr.workspace"));
+ }
+
+ @Test
+ public void requestCredentialsDelegatesToLegacyHandler() throws
IOException {
+ final AuthenticationHandler handler =
mock(AuthenticationHandler.class);
+ final EngineAuthenticationHandlerHolder holder = holder(handler);
+ when(handler.requestAuthentication(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class)))
+ .thenReturn(true);
+
+ assertTrue(holder.doRequestCredentials(mock(HttpServletRequest.class),
mock(HttpServletResponse.class)));
+
+ verify(handler)
+ .requestAuthentication(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class));
+ }
+
+ @Test
+ public void dropCredentialsDoesNotCallLegacyHandler() throws Throwable {
+ final AuthenticationHandler handler =
mock(AuthenticationHandler.class);
+
+ holder(handler).doDropCredentials(mock(HttpServletRequest.class),
mock(HttpServletResponse.class));
+
+ verify(handler, never())
+ .authenticate(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class));
+ verify(handler, never())
+ .requestAuthentication(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class));
+ }
+
+ @Test
+ public void getFeedbackHandlerReturnsNullForPlainEngineHandler() throws
Throwable {
+
assertNull(getFeedbackHandler(holder(mock(AuthenticationHandler.class))));
+ }
+
+ @Test
+ public void feedbackHandlerAdaptsJakartaCallsToLegacyFeedbackHandler()
throws Throwable {
+ final FeedbackEngineHandler handler =
mock(FeedbackEngineHandler.class);
+ final JakartaAuthenticationFeedbackHandler feedbackHandler =
getFeedbackHandler(holder(handler));
+ final HttpServletRequest request = mock(HttpServletRequest.class);
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+ final AuthenticationInfo authInfo = new AuthenticationInfo("engine");
+ when(handler.authenticationSucceeded(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class),
+ same(authInfo)))
+ .thenReturn(true);
+
+ assertNotNull(feedbackHandler);
+ feedbackHandler.authenticationFailed(request, response, authInfo);
+ assertTrue(feedbackHandler.authenticationSucceeded(request, response,
authInfo));
+
+ verify(handler)
+ .authenticationFailed(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class),
+ same(authInfo));
+ verify(handler)
+ .authenticationSucceeded(
+ any(javax.servlet.http.HttpServletRequest.class),
+ any(javax.servlet.http.HttpServletResponse.class),
+ same(authInfo));
+ }
+
+ @Test
+ public void finalMethodsSetAndResetPathAroundEngineDelegation() {
+ final AuthenticationHandler handler =
mock(AuthenticationHandler.class);
+ final EngineAuthenticationHandlerHolder holder = holder(handler);
+ final HttpServletRequest request = mock(HttpServletRequest.class);
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+
when(request.getAttribute(org.apache.sling.auth.core.spi.JakartaAuthenticationHandler.PATH_PROPERTY))
+ .thenReturn("oldPath");
+
+ holder.extractCredentials(request, response);
+
+
verify(request).setAttribute(org.apache.sling.auth.core.spi.JakartaAuthenticationHandler.PATH_PROPERTY,
PATH);
+ verify(request)
+
.setAttribute(org.apache.sling.auth.core.spi.JakartaAuthenticationHandler.PATH_PROPERTY,
"oldPath");
+ }
+
+ @Test
+ public void equalsHashCodeCompareToAndToStringIncludeEngineHandler() {
+ final AuthenticationHandler handler =
mock(AuthenticationHandler.class);
+ when(handler.toString()).thenReturn("engineHandler");
+ final ServiceReference<?> reference = mock(ServiceReference.class);
+ final EngineAuthenticationHandlerHolder holder =
+ new EngineAuthenticationHandlerHolder(PATH, handler,
reference);
+ final EngineAuthenticationHandlerHolder same = new
EngineAuthenticationHandlerHolder(PATH, handler, reference);
+ final EngineAuthenticationHandlerHolder differentHandler =
+ new EngineAuthenticationHandlerHolder(PATH,
mock(AuthenticationHandler.class), reference);
+
+ assertEquals(holder, holder);
+ assertEquals(holder, same);
+ assertEquals(holder.hashCode(), same.hashCode());
+ assertEquals(0, holder.compareTo(same));
+ assertNotEquals(holder, null);
+ assertNotEquals(holder, differentHandler);
+ assertFalse(holder.equals(new Object()));
+ assertEquals("engineHandler (Legacy API Handler)", holder.toString());
+ }
+
+ private EngineAuthenticationHandlerHolder holder(final
AuthenticationHandler handler) {
+ return new EngineAuthenticationHandlerHolder(PATH, handler,
mock(ServiceReference.class));
+ }
+
+ private JakartaAuthenticationFeedbackHandler getFeedbackHandler(final
EngineAuthenticationHandlerHolder holder)
+ throws Throwable {
+ return (JakartaAuthenticationFeedbackHandler)
+ PrivateAccessor.invoke(holder, "getFeedbackHandler", new
Class[0], new Object[0]);
+ }
+}
diff --git
a/src/test/java/org/apache/sling/auth/core/impl/engine/EngineSlingAuthenticatorTest.java
b/src/test/java/org/apache/sling/auth/core/impl/engine/EngineSlingAuthenticatorTest.java
new file mode 100644
index 0000000..a56241d
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/impl/engine/EngineSlingAuthenticatorTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.impl.engine;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.auth.core.impl.hc.SetField;
+import org.apache.sling.engine.auth.NoAuthenticationHandlerException;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+@SuppressWarnings("deprecation")
+public class EngineSlingAuthenticatorTest {
+
+ private HttpServletRequest request =
Mockito.mock(HttpServletRequest.class);
+ private HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+
+ @Test
+ public void test_login_delegates() throws Exception {
+ EngineSlingAuthenticator bridge = new EngineSlingAuthenticator();
+ org.apache.sling.api.auth.Authenticator delegate =
Mockito.mock(org.apache.sling.api.auth.Authenticator.class);
+ SetField.set(bridge, "slingAuthenticator", delegate);
+
+ bridge.login(request, response);
+ Mockito.verify(delegate)
+ .login((javax.servlet.http.HttpServletRequest) request,
(javax.servlet.http.HttpServletResponse)
+ response);
+ }
+
+ @Test
+ public void test_login_wraps_exception() throws Exception {
+ EngineSlingAuthenticator bridge = new EngineSlingAuthenticator();
+ org.apache.sling.api.auth.Authenticator delegate =
Mockito.mock(org.apache.sling.api.auth.Authenticator.class);
+ SetField.set(bridge, "slingAuthenticator", delegate);
+ Mockito.doThrow(new
org.apache.sling.api.auth.NoAuthenticationHandlerException())
+ .when(delegate)
+ .login(
+
Mockito.any(javax.servlet.http.HttpServletRequest.class),
+
Mockito.any(javax.servlet.http.HttpServletResponse.class));
+
+ try {
+ bridge.login(request, response);
+ Assert.fail("Expected NoAuthenticationHandlerException");
+ } catch (NoAuthenticationHandlerException expected) {
+ Assert.assertNotNull(expected.getCause());
+ }
+ }
+
+ @Test
+ public void test_logout_delegates() throws Exception {
+ EngineSlingAuthenticator bridge = new EngineSlingAuthenticator();
+ org.apache.sling.api.auth.Authenticator delegate =
Mockito.mock(org.apache.sling.api.auth.Authenticator.class);
+ SetField.set(bridge, "slingAuthenticator", delegate);
+
+ bridge.logout(request, response);
+ Mockito.verify(delegate)
+ .logout((javax.servlet.http.HttpServletRequest) request,
(javax.servlet.http.HttpServletResponse)
+ response);
+ }
+}
diff --git
a/src/test/java/org/apache/sling/auth/core/spi/AbstractAuthenticationFormServletTest.java
b/src/test/java/org/apache/sling/auth/core/spi/AbstractAuthenticationFormServletTest.java
new file mode 100644
index 0000000..d778d18
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/spi/AbstractAuthenticationFormServletTest.java
@@ -0,0 +1,147 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.spi;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import org.apache.sling.api.auth.Authenticator;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+@SuppressWarnings("deprecation")
+public class AbstractAuthenticationFormServletTest {
+
+ private static class TestFormServlet extends
AbstractAuthenticationFormServlet {
+ private final String reason;
+
+ TestFormServlet(String reason) {
+ this.reason = reason;
+ }
+
+ @Override
+ protected String getReason(HttpServletRequest request) {
+ return reason;
+ }
+
+ @Override
+ protected String getDefaultFormPath() {
+ return "test-login-form.html";
+ }
+
+ @Override
+ protected String getCustomFormPath() {
+ return "does-not-exist.html";
+ }
+ }
+
+ private HttpServletRequest request =
Mockito.mock(HttpServletRequest.class);
+ private HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+
+ @Test
+ public void test_doGet_rendersForm() throws Exception {
+ TestFormServlet servlet = new TestFormServlet("Reason!");
+ Mockito.when(request.getContextPath()).thenReturn("");
+ StringWriter sw = new StringWriter();
+ Mockito.when(response.getWriter()).thenReturn(new PrintWriter(sw));
+
+ servlet.doGet(request, response);
+
+ String out = sw.toString();
+ Assert.assertTrue(out.contains("reason=[Reason!]"));
+ Mockito.verify(response).setContentType("text/html");
+ Mockito.verify(response).flushBuffer();
+ }
+
+ @Test
+ public void test_doPost_rendersForm() throws Exception {
+ TestFormServlet servlet = new TestFormServlet("");
+ Mockito.when(request.getContextPath()).thenReturn("");
+ StringWriter sw = new StringWriter();
+ Mockito.when(response.getWriter()).thenReturn(new PrintWriter(sw));
+
+ servlet.doPost(request, response);
+ Assert.assertTrue(sw.toString().contains("<html>"));
+ }
+
+ @Test
+ public void test_getForm_substitutes_and_escapes() throws Exception {
+ TestFormServlet servlet = new TestFormServlet("<b>&\"'");
+ Mockito.when(request.getContextPath()).thenReturn("");
+
Mockito.when(request.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/valid/path");
+
+ String form = servlet.getForm(request);
+ Assert.assertTrue(form.contains("resource=[/valid/path]"));
+ Assert.assertTrue(form.contains("<b>&%22%27"));
+ }
+
+ @Test
+ public void test_getForm_invalid_resource_cleansed() throws Exception {
+ TestFormServlet servlet = new TestFormServlet("");
+ Mockito.when(request.getContextPath()).thenReturn("");
+
Mockito.when(request.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/invalid//path");
+
+ String form = servlet.getForm(request);
+ Assert.assertTrue(form.contains("resource=[]"));
+ }
+
+ @Test
+ public void test_getContextPath_from_resource() {
+ TestFormServlet servlet = new TestFormServlet("");
+
Mockito.when(request.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/foo/bar/?x=1");
+ Assert.assertEquals("/foo/bar", servlet.getContextPath(request));
+ }
+
+ @Test
+ public void test_getContextPath_fallback_to_servlet_context() {
+ TestFormServlet servlet = new TestFormServlet("");
+ Mockito.when(request.getContextPath()).thenReturn("/ctx");
+ Assert.assertEquals("/ctx", servlet.getContextPath(request));
+ }
+
+ @Test
+ public void test_handle_ioexception_sends_error() throws Exception {
+ TestFormServlet servlet = new TestFormServlet("");
+ javax.servlet.ServletConfig config =
Mockito.mock(javax.servlet.ServletConfig.class);
+
Mockito.when(config.getServletContext()).thenReturn(Mockito.mock(javax.servlet.ServletContext.class));
+ servlet.init(config);
+ Mockito.when(request.getContextPath()).thenReturn("");
+ Mockito.when(response.getWriter()).thenThrow(new IOException("no
writer"));
+
+ servlet.doGet(request, response);
+
Mockito.verify(response).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+
+ @Test
+ public void test_default_paths() {
+ AbstractAuthenticationFormServlet servlet = new
AbstractAuthenticationFormServlet() {
+ @Override
+ protected String getReason(HttpServletRequest request) {
+ return "";
+ }
+ };
+ Assert.assertEquals("login.html", servlet.getDefaultFormPath());
+ Assert.assertEquals("custom_login.html", servlet.getCustomFormPath());
+ }
+}
diff --git
a/src/test/java/org/apache/sling/auth/core/spi/AbstractAuthenticationHandlerTest.java
b/src/test/java/org/apache/sling/auth/core/spi/AbstractAuthenticationHandlerTest.java
new file mode 100644
index 0000000..272ac45
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/spi/AbstractAuthenticationHandlerTest.java
@@ -0,0 +1,92 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.spi;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.api.auth.Authenticator;
+import org.apache.sling.auth.core.AuthConstants;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+/**
+ * Verifies that the deprecated {@link AbstractAuthenticationHandler} helper
+ * methods delegate to {@link org.apache.sling.auth.core.AuthUtil}.
+ */
+@SuppressWarnings("deprecation")
+public class AbstractAuthenticationHandlerTest {
+
+ private HttpServletRequest request =
Mockito.mock(HttpServletRequest.class);
+ private HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+
+ @Test
+ public void test_getAttributeOrParameter() {
+ Mockito.when(request.getParameter("p")).thenReturn("v");
+ Assert.assertEquals("v",
AbstractAuthenticationHandler.getAttributeOrParameter(request, "p", "def"));
+ }
+
+ @Test
+ public void test_getLoginResource() {
+
Mockito.when(request.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/res");
+ Assert.assertEquals("/res",
AbstractAuthenticationHandler.getLoginResource(request, "/def"));
+ }
+
+ @Test
+ public void test_setLoginResourceAttribute() {
+ Assert.assertEquals("/def",
AbstractAuthenticationHandler.setLoginResourceAttribute(request, "/def"));
+ }
+
+ @Test
+ public void test_sendRedirect() throws Exception {
+ Mockito.when(request.getContextPath()).thenReturn("");
+ Mockito.when(request.getRequestURI()).thenReturn("/current");
+ Map<String, String> params = new HashMap<>();
+ AbstractAuthenticationHandler.sendRedirect(request, response,
"/target", params);
+ Mockito.verify(response).sendRedirect(Mockito.contains("/target?"));
+ }
+
+ @Test
+ public void test_isRedirectValid() {
+ Assert.assertTrue(AbstractAuthenticationHandler.isRedirectValid(null,
"/absolute/path"));
+ Assert.assertFalse(AbstractAuthenticationHandler.isRedirectValid(null,
"http://host"));
+ }
+
+ @Test
+ public void test_isValidateRequest() {
+
Mockito.when(request.getParameter(AuthConstants.PAR_J_VALIDATE)).thenReturn("true");
+
Assert.assertTrue(AbstractAuthenticationHandler.isValidateRequest(request));
+ }
+
+ @Test
+ public void test_sendValid() {
+ AbstractAuthenticationHandler.sendValid(response);
+ Mockito.verify(response).setStatus(HttpServletResponse.SC_OK);
+ }
+
+ @Test
+ public void test_sendInvalid() {
+ AbstractAuthenticationHandler.sendInvalid(request, response);
+ Mockito.verify(response).setStatus(HttpServletResponse.SC_FORBIDDEN);
+ }
+}
diff --git
a/src/test/java/org/apache/sling/auth/core/spi/AbstractJakartaAuthenticationFormServletTest.java
b/src/test/java/org/apache/sling/auth/core/spi/AbstractJakartaAuthenticationFormServletTest.java
new file mode 100644
index 0000000..0d88a06
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/spi/AbstractJakartaAuthenticationFormServletTest.java
@@ -0,0 +1,153 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.spi;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.sling.api.auth.Authenticator;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class AbstractJakartaAuthenticationFormServletTest {
+
+ private static class TestFormServlet extends
AbstractJakartaAuthenticationFormServlet {
+ private final String reason;
+
+ TestFormServlet(String reason) {
+ this.reason = reason;
+ }
+
+ @Override
+ protected String getReason(HttpServletRequest request) {
+ return reason;
+ }
+
+ @Override
+ protected String getDefaultFormPath() {
+ return "test-login-form.html";
+ }
+
+ @Override
+ protected String getCustomFormPath() {
+ return "does-not-exist.html";
+ }
+ }
+
+ private HttpServletRequest request =
Mockito.mock(HttpServletRequest.class);
+ private HttpServletResponse response =
Mockito.mock(HttpServletResponse.class);
+
+ @Test
+ public void test_doGet_rendersForm() throws Exception {
+ TestFormServlet servlet = new TestFormServlet("Reason!");
+ Mockito.when(request.getContextPath()).thenReturn("");
+ StringWriter sw = new StringWriter();
+ Mockito.when(response.getWriter()).thenReturn(new PrintWriter(sw));
+
+ servlet.doGet(request, response);
+
+ String out = sw.toString();
+ Assert.assertTrue(out.contains("reason=[Reason!]"));
+ Mockito.verify(response).setContentType("text/html");
+ Mockito.verify(response).flushBuffer();
+ }
+
+ @Test
+ public void test_doPost_rendersForm() throws Exception {
+ TestFormServlet servlet = new TestFormServlet("");
+ Mockito.when(request.getContextPath()).thenReturn("");
+ StringWriter sw = new StringWriter();
+ Mockito.when(response.getWriter()).thenReturn(new PrintWriter(sw));
+
+ servlet.doPost(request, response);
+ Assert.assertTrue(sw.toString().contains("<html>"));
+ }
+
+ @Test
+ public void test_getForm_substitutes_and_escapes() throws Exception {
+ TestFormServlet servlet = new TestFormServlet("<b>&\"'");
+ Mockito.when(request.getContextPath()).thenReturn("");
+
Mockito.when(request.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/valid/path");
+
+ String form = servlet.getForm(request);
+ Assert.assertTrue(form.contains("resource=[/valid/path]"));
+ // reason escaped
+ Assert.assertTrue(form.contains("<b>&%22%27"));
+ }
+
+ @Test
+ public void test_getForm_invalid_resource_cleansed() throws Exception {
+ TestFormServlet servlet = new TestFormServlet("");
+ Mockito.when(request.getContextPath()).thenReturn("");
+ // an invalid (non-normalized) redirect target must be cleansed to
empty
+
Mockito.when(request.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/invalid//path");
+
+ String form = servlet.getForm(request);
+ Assert.assertTrue(form.contains("resource=[]"));
+ }
+
+ @Test
+ public void test_getResource_default_empty() {
+ TestFormServlet servlet = new TestFormServlet("");
+ Assert.assertEquals("", servlet.getResource(request));
+ }
+
+ @Test
+ public void test_getContextPath_from_resource() {
+ TestFormServlet servlet = new TestFormServlet("");
+
Mockito.when(request.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/foo/bar/?x=1");
+ Assert.assertEquals("/foo/bar", servlet.getContextPath(request));
+ }
+
+ @Test
+ public void test_getContextPath_fallback_to_servlet_context() {
+ TestFormServlet servlet = new TestFormServlet("");
+ Mockito.when(request.getContextPath()).thenReturn("/ctx");
+ Assert.assertEquals("/ctx", servlet.getContextPath(request));
+ }
+
+ @Test
+ public void test_handle_ioexception_sends_error() throws Exception {
+ TestFormServlet servlet = new TestFormServlet("");
+ jakarta.servlet.ServletConfig config =
Mockito.mock(jakarta.servlet.ServletConfig.class);
+
Mockito.when(config.getServletContext()).thenReturn(Mockito.mock(jakarta.servlet.ServletContext.class));
+ servlet.init(config);
+ Mockito.when(request.getContextPath()).thenReturn("");
+ Mockito.when(response.getWriter()).thenThrow(new IOException("no
writer"));
+
+ servlet.doGet(request, response);
+
Mockito.verify(response).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ }
+
+ @Test
+ public void test_default_paths() {
+ AbstractJakartaAuthenticationFormServlet servlet = new
AbstractJakartaAuthenticationFormServlet() {
+ @Override
+ protected String getReason(HttpServletRequest request) {
+ return "";
+ }
+ };
+ Assert.assertEquals("login.html", servlet.getDefaultFormPath());
+ Assert.assertEquals("custom_login.html", servlet.getCustomFormPath());
+ }
+}
diff --git
a/src/test/java/org/apache/sling/auth/core/spi/DefaultAuthenticationFeedbackHandlerTest.java
b/src/test/java/org/apache/sling/auth/core/spi/DefaultAuthenticationFeedbackHandlerTest.java
new file mode 100644
index 0000000..bd5d905
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/spi/DefaultAuthenticationFeedbackHandlerTest.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.spi;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.auth.core.AuthenticationSupport;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+@SuppressWarnings("deprecation")
+public class DefaultAuthenticationFeedbackHandlerTest {
+
+ @Test
+ public void test_no_redirect() {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
Assert.assertFalse(DefaultAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ }
+
+ @Test
+ public void test_redirect_true_uses_requestUri() throws Exception {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
Mockito.when(request.getParameter(AuthenticationSupport.REDIRECT_PARAMETER))
+ .thenReturn("true");
+ Mockito.when(request.getRequestURI()).thenReturn("/same/uri");
+
Assert.assertTrue(DefaultAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ Mockito.verify(response).sendRedirect("/same/uri");
+ }
+
+ @Test
+ public void test_redirect_absolute_valid() throws Exception {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
Mockito.when(request.getParameter(AuthenticationSupport.REDIRECT_PARAMETER))
+ .thenReturn("/valid/path");
+ Mockito.when(request.getContextPath()).thenReturn("");
+
Assert.assertTrue(DefaultAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ Mockito.verify(response).sendRedirect("/valid/path");
+ }
+
+ @Test
+ public void test_redirect_relative_made_absolute() throws Exception {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
Mockito.when(request.getParameter(AuthenticationSupport.REDIRECT_PARAMETER))
+ .thenReturn("rel");
+ Mockito.when(request.getRequestURI()).thenReturn("/base/page");
+ Mockito.when(request.getContextPath()).thenReturn("");
+
Assert.assertTrue(DefaultAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ Mockito.verify(response).sendRedirect("/base/rel");
+ }
+
+ @Test
+ public void test_redirect_invalid_falls_back_to_root() throws Exception {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
Mockito.when(request.getParameter(AuthenticationSupport.REDIRECT_PARAMETER))
+ .thenReturn("/invalid//path");
+ Mockito.when(request.getContextPath()).thenReturn("");
+
Assert.assertTrue(DefaultAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ Mockito.verify(response).sendRedirect("/");
+ }
+
+ @Test
+ public void test_authenticationFailed_noop() {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+ DefaultAuthenticationFeedbackHandler handler = new
DefaultAuthenticationFeedbackHandler();
+ handler.authenticationFailed(request, response, new
AuthenticationInfo("test"));
+ Mockito.verifyNoInteractions(response);
+ }
+
+ @Test
+ public void test_authenticationSucceeded_delegates() {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+ DefaultAuthenticationFeedbackHandler handler = new
DefaultAuthenticationFeedbackHandler();
+ Assert.assertFalse(handler.authenticationSucceeded(request, response,
new AuthenticationInfo("test")));
+ }
+}
diff --git
a/src/test/java/org/apache/sling/auth/core/spi/DefaultJakartaAuthenticationFeedbackHandlerTest.java
b/src/test/java/org/apache/sling/auth/core/spi/DefaultJakartaAuthenticationFeedbackHandlerTest.java
new file mode 100644
index 0000000..1480070
--- /dev/null
+++
b/src/test/java/org/apache/sling/auth/core/spi/DefaultJakartaAuthenticationFeedbackHandlerTest.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF 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.apache.sling.auth.core.spi;
+
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.sling.auth.core.AuthenticationSupport;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class DefaultJakartaAuthenticationFeedbackHandlerTest {
+
+ @Test
+ public void test_no_redirect() {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+ // no redirect parameter and no login resource -> false
+
Assert.assertFalse(DefaultJakartaAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ }
+
+ @Test
+ public void test_redirect_true_uses_requestUri() throws Exception {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
Mockito.when(request.getParameter(AuthenticationSupport.REDIRECT_PARAMETER))
+ .thenReturn("true");
+ Mockito.when(request.getRequestURI()).thenReturn("/same/uri");
+
Assert.assertTrue(DefaultJakartaAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ Mockito.verify(response).sendRedirect("/same/uri");
+ }
+
+ @Test
+ public void test_redirect_empty_uses_requestUri() throws Exception {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
Mockito.when(request.getParameter(AuthenticationSupport.REDIRECT_PARAMETER))
+ .thenReturn("");
+ Mockito.when(request.getRequestURI()).thenReturn("/same/uri");
+
Assert.assertTrue(DefaultJakartaAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ Mockito.verify(response).sendRedirect("/same/uri");
+ }
+
+ @Test
+ public void test_redirect_absolute_valid() throws Exception {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
Mockito.when(request.getParameter(AuthenticationSupport.REDIRECT_PARAMETER))
+ .thenReturn("/valid/path");
+ Mockito.when(request.getContextPath()).thenReturn("");
+
Assert.assertTrue(DefaultJakartaAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ Mockito.verify(response).sendRedirect("/valid/path");
+ }
+
+ @Test
+ public void test_redirect_relative_made_absolute() throws Exception {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
Mockito.when(request.getParameter(AuthenticationSupport.REDIRECT_PARAMETER))
+ .thenReturn("rel");
+ Mockito.when(request.getRequestURI()).thenReturn("/base/page");
+ Mockito.when(request.getContextPath()).thenReturn("");
+
Assert.assertTrue(DefaultJakartaAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ Mockito.verify(response).sendRedirect("/base/rel");
+ }
+
+ @Test
+ public void test_redirect_invalid_falls_back_to_root() throws Exception {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
Mockito.when(request.getParameter(AuthenticationSupport.REDIRECT_PARAMETER))
+ .thenReturn("/invalid//path");
+ Mockito.when(request.getContextPath()).thenReturn("");
+
Assert.assertTrue(DefaultJakartaAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ Mockito.verify(response).sendRedirect("/");
+ }
+
+ @Test
+ public void test_redirect_send_failure_is_swallowed() throws Exception {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+
Mockito.when(request.getParameter(AuthenticationSupport.REDIRECT_PARAMETER))
+ .thenReturn("/valid");
+ Mockito.when(request.getContextPath()).thenReturn("");
+ Mockito.doThrow(new
java.io.IOException("boom")).when(response).sendRedirect(Mockito.anyString());
+
Assert.assertTrue(DefaultJakartaAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ }
+
+ @Test
+ public void test_authenticationFailed_noop() {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+ DefaultJakartaAuthenticationFeedbackHandler handler = new
DefaultJakartaAuthenticationFeedbackHandler();
+ handler.authenticationFailed(request, response, new
AuthenticationInfo("test"));
+ Mockito.verifyNoInteractions(response);
+ }
+
+ @Test
+ public void test_authenticationSucceeded_delegates() {
+ HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
+ HttpServletResponse response = Mockito.mock(HttpServletResponse.class);
+ DefaultJakartaAuthenticationFeedbackHandler handler = new
DefaultJakartaAuthenticationFeedbackHandler();
+ Assert.assertFalse(handler.authenticationSucceeded(request, response,
new AuthenticationInfo("test")));
+ }
+}
diff --git
a/src/test/resources/org/apache/sling/auth/core/spi/test-login-form.html
b/src/test/resources/org/apache/sling/auth/core/spi/test-login-form.html
new file mode 100644
index 0000000..cdea831
--- /dev/null
+++ b/src/test/resources/org/apache/sling/auth/core/spi/test-login-form.html
@@ -0,0 +1 @@
+<html>resource=[${resource}] reason=[${j_reason}] rcp=[${requestContextPath}]
cp=[${contextPath}]</html>
\ No newline at end of file