This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-core.git
The following commit(s) were added to refs/heads/master by this push:
new 00dd9d2 SLING-13389 : no NPE when an anonymous request carries a
"resource" parameter
00dd9d2 is described below
commit 00dd9d2cc9f9a2561711624ec02b273e15e74913
Author: dulvac <[email protected]>
AuthorDate: Tue Oct 13 16:10:38 2026 +0200
SLING-13389 : no NPE when an anonymous request carries a "resource"
parameter
The "resource" fallback added for SLING-13025 also ran in
getAnonymousResolver, before a resource resolver is on the request,
so AuthUtil.getMappedLoginResourcePath threw a NullPointerException for
the login form (which carries resource=<protected page>).
- getMappedLoginResourcePath returns the unmapped path when the request
has no resolver attribute, for the jakarta and the javax variant
- getAnonymousResolver only redirects on an explicit sling.auth.redirect;
the "resource" fallback is for the redirect after a successful login,
on the anonymous path it would send the login form to the protected
page and loop
- tests for the anonymous login page request, the explicit redirect on
anonymous access, and the no-resolver case of AuthUtil and both
feedback handlers
---
.../java/org/apache/sling/auth/core/AuthUtil.java | 13 +++++---
.../sling/auth/core/impl/SlingAuthenticator.java | 11 +++++--
.../org/apache/sling/auth/core/AuthUtilTest.java | 20 ++++++++++--
.../auth/core/impl/SlingAuthenticatorTest.java | 37 ++++++++++++++++++++++
.../DefaultAuthenticationFeedbackHandlerTest.java | 15 +++++++++
...ltJakartaAuthenticationFeedbackHandlerTest.java | 15 +++++++++
6 files changed, 103 insertions(+), 8 deletions(-)
diff --git a/src/main/java/org/apache/sling/auth/core/AuthUtil.java
b/src/main/java/org/apache/sling/auth/core/AuthUtil.java
index e50a668..d8a71ef 100644
--- a/src/main/java/org/apache/sling/auth/core/AuthUtil.java
+++ b/src/main/java/org/apache/sling/auth/core/AuthUtil.java
@@ -215,8 +215,10 @@ public final class AuthUtil {
* Returns the mapped resource path (to redirect to after a successful
authentication).
* It still needs to be validated by the caller.
* Use this method to issue a redirect instead of {@link
#getLoginResource(HttpServletRequest, String)} to correctly consider resource
resolver mapping.
+ * If the request carries no resource resolver (see {@link
AuthenticationSupport#REQUEST_ATTRIBUTE_RESOLVER}),
+ * for example while anonymous access is being established, the path is
returned unmapped.
* @return the mapped path of the resource target or {@code null} if non
is given in the request
- * @since 1.7.0 (Bundle Version 2.1.0)
+ * @since 1.7.0 (Bundle Version 2.1.2)
*/
public static @Nullable String getMappedLoginResourcePath(
final HttpServletRequest request, String defaultLoginResource) {
@@ -224,17 +226,19 @@ public final class AuthUtil {
if (resourcePath == null) {
return null;
}
- return getResourceResolver(request).map(request, resourcePath);
+ final ResourceResolver resolver = getResourceResolver(request);
+ return resolver == null ? resourcePath : resolver.map(request,
resourcePath);
}
/**
* Returns the mapped resource path (to redirect to after a successful
authentication).
* It still needs to be validated by the caller.
* Use this method to issue a redirect instead of {@link
#getLoginResource(javax.servlet.http.HttpServletRequest, String)} to correctly
consider resource resolver mapping.
+ * If the request carries no resource resolver, the path is returned
unmapped.
* @return the mapped path of the resource target or {@code null} if non
is given in the request
*
* @deprecated Use {@link #getMappedLoginResourcePath(HttpServletRequest,
String)}
- * @since 1.7.0 (Bundle Version 2.1.0)
+ * @since 1.7.0 (Bundle Version 2.1.2)
*/
@Deprecated
public static @Nullable String getMappedLoginResourcePath(
@@ -243,7 +247,8 @@ public final class AuthUtil {
if (resourcePath == null) {
return null;
}
- return getResourceResolver(request).map(request, resourcePath);
+ final ResourceResolver resolver = getResourceResolver(request);
+ return resolver == null ? resourcePath : resolver.map(request,
resourcePath);
}
/**
diff --git
a/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
b/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
index 4d0a61a..340519f 100644
--- a/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
+++ b/src/main/java/org/apache/sling/auth/core/impl/SlingAuthenticator.java
@@ -916,8 +916,15 @@ public class SlingAuthenticator implements Authenticator,
AuthenticationSupport,
ResourceResolver resolver =
resourceResolverFactory.getResourceResolver(authInfo);
// check whether the client asked for redirect after
- // authentication and/or impersonation
- if
(DefaultJakartaAuthenticationFeedbackHandler.handleRedirect(request, response))
{
+ // authentication and/or impersonation. Only an explicit
+ // sling.auth.redirect counts here: the "resource" fallback of
+ // handleRedirect is meant for the redirect after a successful
+ // login. An anonymous request carrying "resource" is typically
+ // the login form itself, redirecting it to the protected
+ // resource would loop (and there is no resolver on the
+ // request yet to map the path with)
+ if
(request.getParameter(AuthenticationSupport.REDIRECT_PARAMETER) != null
+ &&
DefaultJakartaAuthenticationFeedbackHandler.handleRedirect(request, response)) {
// request will now be terminated, so close the resolver
// to release resources
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 60a83b1..c813323 100644
--- a/src/test/java/org/apache/sling/auth/core/AuthUtilTest.java
+++ b/src/test/java/org/apache/sling/auth/core/AuthUtilTest.java
@@ -228,11 +228,20 @@ public class AuthUtilTest {
@Test
public void test_getMappedLoginResourcePath_null_jakarta() {
HttpServletRequest req = mock(HttpServletRequest.class);
- // no resolver -> getResourceResolver returns null -> NPE guarded by
null path only
- // here defaultLoginResource is null and no param -> resourcePath null
-> returns null
+ // no resolver, no parameter, no default -> nothing to map, returns
null
Assert.assertNull(AuthUtil.getMappedLoginResourcePath(req, null));
}
+ @Test
+ public void test_getMappedLoginResourcePath_without_resolver_jakarta() {
+ // anonymous request (e.g. the login page) carrying resource=... but
no resolver attribute yet:
+ // the path cannot be mapped and must be returned as is instead of
failing
+ HttpServletRequest req = mock(HttpServletRequest.class);
+
when(req.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/content/protected");
+ Assert.assertEquals("/content/protected",
AuthUtil.getMappedLoginResourcePath(req, null));
+ Assert.assertEquals("/def",
AuthUtil.getMappedLoginResourcePath(mock(HttpServletRequest.class), "/def"));
+ }
+
@Test
public void test_setLoginResourceAttribute_jakarta() {
HttpServletRequest req = mock(HttpServletRequest.class);
@@ -428,6 +437,13 @@ public class AuthUtilTest {
Assert.assertNull(AuthUtil.getMappedLoginResourcePath(request2, null));
}
+ @Test
+ public void test_getMappedLoginResourcePath_without_resolver_javax() {
+ javax.servlet.http.HttpServletRequest req =
mock(javax.servlet.http.HttpServletRequest.class);
+
when(req.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/content/protected");
+ Assert.assertEquals("/content/protected",
AuthUtil.getMappedLoginResourcePath(req, null));
+ }
+
@SuppressWarnings("deprecation")
@Test
public void test_setLoginResourceAttribute_javax() {
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 7e67d49..e0f4af0 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.Authenticator;
import org.apache.sling.api.auth.NoAuthenticationHandlerException;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.api.resource.ResourceResolverFactory;
@@ -726,6 +727,42 @@ public class SlingAuthenticatorTest {
verify(resolver).close();
}
+ @Test
+ public void test_handleSecurity_anonymous_login_page_with_resource_param()
throws Exception {
+ // the login form is requested anonymously and carries
resource=<protected page>; the request
+ // must proceed to render the form (no redirect, no exception), see
the 2.1.0 vote
+ final ResourceResolverFactory rrf =
mock(ResourceResolverFactory.class);
+ final ResourceResolver resolver = mock(ResourceResolver.class);
+
when(rrf.getResourceResolver(any(java.util.Map.class))).thenReturn(resolver);
+ final SlingAuthenticator auth = createAuthenticator(rrf);
+
+ final HttpServletRequest request =
requestFor("/system/sling/form/login");
+
when(request.getParameter(Authenticator.LOGIN_RESOURCE)).thenReturn("/content/protected");
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+
+ Assert.assertTrue(auth.handleSecurity(request, response));
+ verify(response, never()).sendRedirect(anyString());
+ verify(resolver, never()).close();
+
verify(request).setAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_RESOLVER,
resolver);
+ }
+
+ @Test
+ public void test_handleSecurity_anonymous_with_explicit_redirect_param()
throws Exception {
+ // sling.auth.redirect on an anonymous request keeps redirecting, as
before 2.1.0
+ final ResourceResolverFactory rrf =
mock(ResourceResolverFactory.class);
+ final ResourceResolver resolver = mock(ResourceResolver.class);
+
when(rrf.getResourceResolver(any(java.util.Map.class))).thenReturn(resolver);
+ final SlingAuthenticator auth = createAuthenticator(rrf);
+
+ final HttpServletRequest request = requestFor("/content");
+
when(request.getParameter(AuthenticationSupport.REDIRECT_PARAMETER)).thenReturn("/content/target");
+ final HttpServletResponse response = mock(HttpServletResponse.class);
+
+ Assert.assertFalse(auth.handleSecurity(request, response));
+ verify(response).sendRedirect("/content/target");
+ verify(resolver).close();
+ }
+
@Test
public void test_handleSecurity_doing_auth() {
final SlingAuthenticator auth = createAuthenticator(infoHolder("/",
AuthenticationInfo.DOING_AUTH));
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
index 0ae6527..4f2f95a 100644
---
a/src/test/java/org/apache/sling/auth/core/spi/DefaultAuthenticationFeedbackHandlerTest.java
+++
b/src/test/java/org/apache/sling/auth/core/spi/DefaultAuthenticationFeedbackHandlerTest.java
@@ -97,4 +97,19 @@ public class DefaultAuthenticationFeedbackHandlerTest {
DefaultAuthenticationFeedbackHandler handler = new
DefaultAuthenticationFeedbackHandler();
Assert.assertFalse(handler.authenticationSucceeded(request, response,
new AuthenticationInfo("test")));
}
+
+ @Test
+ public void test_redirect_resource_fallback_without_resolver() throws
Exception {
+ // SLING-13025 fallback to the "resource" parameter, on a request that
has no resolver
+ // attribute yet (anonymous access): must redirect to the unmapped
path, not fail
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ HttpServletResponse response = mock(HttpServletResponse.class);
+
when(request.getParameter(org.apache.sling.api.auth.Authenticator.LOGIN_RESOURCE))
+ .thenReturn("/content/protected");
+ when(request.getContextPath()).thenReturn("");
+ when(request.getServletPath()).thenReturn("/content/protected");
+ when(request.getRequestURI()).thenReturn("/content/protected");
+
Assert.assertTrue(DefaultAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ verify(response).sendRedirect("/content/protected");
+ }
}
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
index be79b7a..2f2ac28 100644
---
a/src/test/java/org/apache/sling/auth/core/spi/DefaultJakartaAuthenticationFeedbackHandlerTest.java
+++
b/src/test/java/org/apache/sling/auth/core/spi/DefaultJakartaAuthenticationFeedbackHandlerTest.java
@@ -118,4 +118,19 @@ public class
DefaultJakartaAuthenticationFeedbackHandlerTest {
DefaultJakartaAuthenticationFeedbackHandler handler = new
DefaultJakartaAuthenticationFeedbackHandler();
Assert.assertFalse(handler.authenticationSucceeded(request, response,
new AuthenticationInfo("test")));
}
+
+ @Test
+ public void test_redirect_resource_fallback_without_resolver() throws
Exception {
+ // SLING-13025 fallback to the "resource" parameter, on a request that
has no resolver
+ // attribute yet (anonymous access): must redirect to the unmapped
path, not fail
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ HttpServletResponse response = mock(HttpServletResponse.class);
+
when(request.getParameter(org.apache.sling.api.auth.Authenticator.LOGIN_RESOURCE))
+ .thenReturn("/content/protected");
+ when(request.getContextPath()).thenReturn("");
+ when(request.getServletPath()).thenReturn("/content/protected");
+ when(request.getRequestURI()).thenReturn("/content/protected");
+
Assert.assertTrue(DefaultJakartaAuthenticationFeedbackHandler.handleRedirect(request,
response));
+ verify(response).sendRedirect("/content/protected");
+ }
}