You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by gh...@apache.org on 2020/09/22 00:09:33 UTC

[sling-org-apache-sling-auth-core] 01/01: SLING-9662 Use PathToUriMappingService to pre-process path before authentication

This is an automated email from the ASF dual-hosted git repository.

ghenzler pushed a commit to branch feature/SLING-9662-Introduce-SlingUri-Mapping-SPI-v3
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-auth-core.git

commit 64326aee30a3b904ffa21c8e67162df69575e31a
Author: georg.henzler <ge...@netcentric.biz>
AuthorDate: Mon Sep 21 10:44:56 2020 +0200

    SLING-9662 Use PathToUriMappingService to pre-process path before
    authentication
---
 pom.xml                                            |  2 +-
 .../sling/auth/core/AuthenticationSupport.java     |  8 +++
 .../sling/auth/core/impl/SlingAuthenticator.java   | 33 +++++-----
 .../org/apache/sling/auth/core/package-info.java   |  4 +-
 .../auth/core/impl/SlingAuthenticatorTest.java     | 77 ++++++++++------------
 5 files changed, 64 insertions(+), 60 deletions(-)

diff --git a/pom.xml b/pom.xml
index fb78d39..4b03116 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,7 +71,7 @@
         <dependency>
             <groupId>org.apache.sling</groupId>
             <artifactId>org.apache.sling.api</artifactId>
-            <version>2.20.0</version>
+            <version>2.23.0-SNAPSHOT</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
diff --git a/src/main/java/org/apache/sling/auth/core/AuthenticationSupport.java b/src/main/java/org/apache/sling/auth/core/AuthenticationSupport.java
index 7257110..0f2dd4d 100644
--- a/src/main/java/org/apache/sling/auth/core/AuthenticationSupport.java
+++ b/src/main/java/org/apache/sling/auth/core/AuthenticationSupport.java
@@ -85,6 +85,14 @@ public interface AuthenticationSupport {
     static final String REQUEST_ATTRIBUTE_RESOLVER = "org.apache.sling.auth.core.ResourceResolver";
 
     /**
+     * The name of the request attribute set by the {@link #handleSecurity(HttpServletRequest, HttpServletResponse)} method for the request
+     * URI that was resolved already.
+     * <p>
+     * The request attribute is set to a Sling <code>SlingUri</code> as provided by PathToUriMappingService.resolve().
+     */
+    static final String REQUEST_ATTRIBUTE_URI = "org.apache.sling.auth.core.SlingUri";
+
+    /**
      * The name of the request parameter indicating where to redirect to after
      * successful authentication (and optional impersonation). This parameter is
      * respected if either anonymous authentication or regular authentication
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 6e203cc..0f2054a 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
@@ -50,6 +50,8 @@ import org.apache.sling.api.auth.NoAuthenticationHandlerException;
 import org.apache.sling.api.resource.LoginException;
 import org.apache.sling.api.resource.ResourceResolver;
 import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.api.resource.mapping.PathToUriMappingService;
+import org.apache.sling.api.uri.SlingUri;
 import org.apache.sling.auth.core.AuthConstants;
 import org.apache.sling.auth.core.AuthUtil;
 import org.apache.sling.auth.core.AuthenticationSupport;
@@ -260,6 +262,9 @@ public class SlingAuthenticator implements Authenticator,
     @Reference
     private ResourceResolverFactory resourceResolverFactory;
 
+    @Reference
+    private PathToUriMappingService pathToUriMappingService;
+
     private PathBasedHolderCache<AbstractAuthenticationHandlerHolder> authHandlerCache = new PathBasedHolderCache<AbstractAuthenticationHandlerHolder>();
 
     // package protected for access in inner class ...
@@ -506,7 +511,7 @@ public class SlingAuthenticator implements Authenticator,
 
     private boolean doHandleSecurity(HttpServletRequest request, HttpServletResponse response) {
 
-        // 0. Check for request attribute; set if not present
+        // 0 Check for request attribute; set if not present
         Object authUriSufficesAttr = request
                 .getAttribute(AuthConstants.ATTR_REQUEST_AUTH_URI_SUFFIX);
         if (authUriSufficesAttr == null && authUriSuffices != null) {
@@ -747,22 +752,18 @@ public class SlingAuthenticator implements Authenticator,
      * @return The path
      */
     private String getPath(final HttpServletRequest request) {
-        final StringBuilder sb = new StringBuilder();
-        if (request.getServletPath() != null) {
-            sb.append(request.getServletPath());
-        }
-        if (request.getPathInfo() != null) {
-            sb.append(request.getPathInfo());
-        }
-        String path = sb.toString();
-        // Get the path used to select the authenticator, if the SlingServlet
-        // itself has been requested without any more info, this will be empty
-        // and we assume the root (SLING-722)
-        if (path.length() == 0) {
-            path = "/";
-        }
 
-        return path;
+        // this method is safely called from all three public entry points (that is handleSecurity(), login(), logout())
+        // for all execution paths
+        // therefore Sling engine may rely on AuthenticationSupport.REQUEST_ATTRIBUTE_URI
+
+        SlingUri slingUri = (SlingUri) request.getAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_URI);
+        if (slingUri == null) {
+            slingUri = pathToUriMappingService.resolve(request, null).getUri();
+            request.setAttribute(AuthenticationSupport.REQUEST_ATTRIBUTE_URI, slingUri);
+        }
+        
+        return slingUri.getPath();
     }
 
     private AuthenticationInfo getAuthenticationInfo(HttpServletRequest request, HttpServletResponse response) {
diff --git a/src/main/java/org/apache/sling/auth/core/package-info.java b/src/main/java/org/apache/sling/auth/core/package-info.java
index 66dee4f..f8d608e 100755
--- a/src/main/java/org/apache/sling/auth/core/package-info.java
+++ b/src/main/java/org/apache/sling/auth/core/package-info.java
@@ -22,9 +22,9 @@
  * of utility functions in the {@link org.apache.sling.auth.core.AuthUtil}
  * class.
  *
- * @version 1.4.0
+ * @version 1.5.0
  */
-@org.osgi.annotation.versioning.Version("1.4.0")
+@org.osgi.annotation.versioning.Version("1.5.0")
 package org.apache.sling.auth.core;
 
 
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 d3654cf..97cfd51 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
@@ -18,22 +18,49 @@
  */
 package org.apache.sling.auth.core.impl;
 
+import static org.mockito.Mockito.when;
+
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.apache.sling.api.resource.mapping.PathToUriMappingService;
+import org.apache.sling.api.uri.SlingUriBuilder;
 import org.apache.sling.auth.core.spi.AuthenticationFeedbackHandler;
 import org.apache.sling.auth.core.spi.AuthenticationInfo;
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
 import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
 
 import junitx.util.PrivateAccessor;
 
+@RunWith(MockitoJUnitRunner.class)
 public class SlingAuthenticatorTest {
 
+    @InjectMocks
+    SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
+
+    @Mock
+    PathToUriMappingService pathToUriMappingService;
+
+    @Mock
+    HttpServletRequest request;
+
+    @Mock
+    PathToUriMappingService.Result resolveResult;
+
+    @Before
+    public void setup() {
+        when(pathToUriMappingService.resolve(request, null)).thenReturn(resolveResult);
+    }
+
     @Test
     public void test_quoteCookieValue() throws UnsupportedEncodingException {
 
@@ -82,14 +109,13 @@ public class SlingAuthenticatorTest {
     //SLING-4864
     @Test
     public void  test_isAnonAllowed() throws Throwable {
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
 
-        PathBasedHolderCache<AuthenticationRequirementHolder> authRequiredCache = new PathBasedHolderCache<AuthenticationRequirementHolder>();
+        when(resolveResult.getUri()).thenReturn(SlingUriBuilder.parse("/", null).build());
 
+        PathBasedHolderCache<AuthenticationRequirementHolder> authRequiredCache = new PathBasedHolderCache<AuthenticationRequirementHolder>();
         authRequiredCache.addHolder(new AuthenticationRequirementHolder("/", false, null));
 
         PrivateAccessor.setField(slingAuthenticator, "authRequiredCache", authRequiredCache);
-        final HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
         Mockito.when(request.getServerName()).thenReturn("localhost");
         Mockito.when(request.getServerPort()).thenReturn(80);
         Mockito.when(request.getScheme()).thenReturn("http");
@@ -109,13 +135,10 @@ public class SlingAuthenticatorTest {
         final String PROTECTED_PATH = "/content/en/test";
         final String REQUEST_CHILD_NODE = "/content/en/test/childnodetest";
 
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
-
         PathBasedHolderCache<AbstractAuthenticationHandlerHolder> authRequiredCache = new PathBasedHolderCache<AbstractAuthenticationHandlerHolder>();
         authRequiredCache.addHolder(buildAuthHolderForAuthTypeAndPath(AUTH_TYPE, PROTECTED_PATH));
 
         PrivateAccessor.setField(slingAuthenticator, "authHandlerCache", authRequiredCache);
-        final HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
         buildExpectationsForRequest(request, REQUEST_CHILD_NODE);
 
         AuthenticationInfo authInfo = (AuthenticationInfo) PrivateAccessor.invoke(slingAuthenticator, "getAuthenticationInfo",
@@ -136,13 +159,10 @@ public class SlingAuthenticatorTest {
         final String PROTECTED_PATH = "/content/en/test";
         final String REQUEST_CHILD_NODE = "/content/en/test";
 
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
-
         PathBasedHolderCache<AbstractAuthenticationHandlerHolder> authRequiredCache = new PathBasedHolderCache<AbstractAuthenticationHandlerHolder>();
         authRequiredCache.addHolder(buildAuthHolderForAuthTypeAndPath(AUTH_TYPE, PROTECTED_PATH));
 
         PrivateAccessor.setField(slingAuthenticator, "authHandlerCache", authRequiredCache);
-        final HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
         buildExpectationsForRequest(request, REQUEST_CHILD_NODE);
 
         AuthenticationInfo authInfo = (AuthenticationInfo) PrivateAccessor.invoke(slingAuthenticator, "getAuthenticationInfo",
@@ -163,13 +183,10 @@ public class SlingAuthenticatorTest {
         final String PROTECTED_PATH = "/content/en/test";
         final String REQUEST_CHILD_NODE = "/content/en/test/";
 
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
-
         PathBasedHolderCache<AbstractAuthenticationHandlerHolder> authRequiredCache = new PathBasedHolderCache<AbstractAuthenticationHandlerHolder>();
         authRequiredCache.addHolder(buildAuthHolderForAuthTypeAndPath(AUTH_TYPE, PROTECTED_PATH));
 
         PrivateAccessor.setField(slingAuthenticator, "authHandlerCache", authRequiredCache);
-        final HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
         buildExpectationsForRequest(request, REQUEST_CHILD_NODE);
 
         AuthenticationInfo authInfo = (AuthenticationInfo) PrivateAccessor.invoke(slingAuthenticator, "getAuthenticationInfo",
@@ -190,13 +207,10 @@ public class SlingAuthenticatorTest {
         final String PROTECTED_PATH = "/content/en/test";
         final String REQUEST_CHILD_NODE = "/content/en/test.html";
 
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
-
         PathBasedHolderCache<AbstractAuthenticationHandlerHolder> authRequiredCache = new PathBasedHolderCache<AbstractAuthenticationHandlerHolder>();
         authRequiredCache.addHolder(buildAuthHolderForAuthTypeAndPath(AUTH_TYPE, PROTECTED_PATH));
 
         PrivateAccessor.setField(slingAuthenticator, "authHandlerCache", authRequiredCache);
-        final HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
         buildExpectationsForRequest(request, REQUEST_CHILD_NODE);
 
         AuthenticationInfo authInfo = (AuthenticationInfo) PrivateAccessor.invoke(slingAuthenticator, "getAuthenticationInfo",
@@ -213,13 +227,10 @@ public class SlingAuthenticatorTest {
         final String PROTECTED_PATH = "/";
         final String REQUEST_CHILD_NODE = "/content/en/test";
 
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
-
         PathBasedHolderCache<AbstractAuthenticationHandlerHolder> authRequiredCache = new PathBasedHolderCache<AbstractAuthenticationHandlerHolder>();
         authRequiredCache.addHolder(buildAuthHolderForAuthTypeAndPath(AUTH_TYPE, PROTECTED_PATH));
 
         PrivateAccessor.setField(slingAuthenticator, "authHandlerCache", authRequiredCache);
-        final HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
         buildExpectationsForRequest(request, REQUEST_CHILD_NODE);
 
         AuthenticationInfo authInfo = (AuthenticationInfo) PrivateAccessor.invoke(slingAuthenticator, "getAuthenticationInfo",
@@ -238,14 +249,11 @@ public class SlingAuthenticatorTest {
         final String PROTECTED_PATH_LONGER = "/resource1.test2";
         final String REQUEST_CHILD_NODE = "/resource1.test2";
 
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
-
         PathBasedHolderCache<AbstractAuthenticationHandlerHolder> authRequiredCache = new PathBasedHolderCache<AbstractAuthenticationHandlerHolder>();
         authRequiredCache.addHolder(buildAuthHolderForAuthTypeAndPath(AUTH_TYPE, PROTECTED_PATH));
         authRequiredCache.addHolder(buildAuthHolderForAuthTypeAndPath(AUTH_TYPE_LONGER, PROTECTED_PATH_LONGER));
 
         PrivateAccessor.setField(slingAuthenticator, "authHandlerCache", authRequiredCache);
-        final HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
         buildExpectationsForRequest(request, REQUEST_CHILD_NODE);
 
         AuthenticationInfo authInfo = (AuthenticationInfo) PrivateAccessor.invoke(slingAuthenticator, "getAuthenticationInfo",
@@ -279,19 +287,16 @@ public class SlingAuthenticatorTest {
         final String PROTECTED_PATH = "/content/en/test";
         final String REQUEST_NOT_PROTECTED_PATH = "/content/en/test2";
 
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
-
         PathBasedHolderCache<AbstractAuthenticationHandlerHolder> authRequiredCache = new PathBasedHolderCache<AbstractAuthenticationHandlerHolder>();
         authRequiredCache.addHolder(buildAuthHolderForAuthTypeAndPath(AUTH_TYPE, PROTECTED_PATH));
 
         PrivateAccessor.setField(slingAuthenticator, "authHandlerCache", authRequiredCache);
-        final HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
         buildExpectationsForRequest(request, REQUEST_NOT_PROTECTED_PATH);
 
         AuthenticationInfo authInfo = (AuthenticationInfo) PrivateAccessor.invoke(slingAuthenticator, "getAuthenticationInfo",
                 new Class[]{HttpServletRequest.class, HttpServletResponse.class}, new Object[]{request, Mockito.mock(HttpServletResponse.class)});
         /**
-         * The AUTH TYPE defined aboved should not be used for the path /test2.
+         * The AUTH TYPE defined above should not be used for the path /test2.
          */
         Assert.assertFalse(AUTH_TYPE.equals(authInfo.getAuthType()));
     }
@@ -300,7 +305,6 @@ public class SlingAuthenticatorTest {
     public void test_childNodeAuthenticationHandlerPath() throws Throwable {
         final String requestPath = "/content/test/test2";
         final String handlerPath = "/content/test";
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
 
         Assert.assertTrue( (boolean)PrivateAccessor.invoke(slingAuthenticator, "isNodeRequiresAuthHandler", new Class[] {String.class, String.class}, new Object[] {requestPath, handlerPath}));
     }
@@ -309,7 +313,6 @@ public class SlingAuthenticatorTest {
     public void test_siblingNodeAuthenticationHandlerPath() throws Throwable {
         final String requestPath = "/content/test2.html/en/2016/09/19/test.html";
         final String handlerPath = "/content/test";
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
 
         Assert.assertFalse( (boolean)PrivateAccessor.invoke(slingAuthenticator, "isNodeRequiresAuthHandler", new Class[] {String.class, String.class}, new Object[] {requestPath, handlerPath}));
     }
@@ -318,7 +321,6 @@ public class SlingAuthenticatorTest {
     public void test_actualNodeAuthenticationHandlerPath() throws Throwable {
         final String requestPath = "/content/test";
         final String handlerPath = "/content/test";
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
 
         Assert.assertTrue( (boolean)PrivateAccessor.invoke(slingAuthenticator, "isNodeRequiresAuthHandler", new Class[] {String.class, String.class}, new Object[] {requestPath, handlerPath}));
     }
@@ -327,7 +329,6 @@ public class SlingAuthenticatorTest {
     public void test_rootNodeAuthenticationHandlerPath() throws Throwable {
         final String requestPath = "/content/test";
         final String handlerPath = "/";
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
 
         Assert.assertTrue( (boolean)PrivateAccessor.invoke(slingAuthenticator, "isNodeRequiresAuthHandler", new Class[] {String.class, String.class}, new Object[] {requestPath, handlerPath}));
     }
@@ -336,7 +337,6 @@ public class SlingAuthenticatorTest {
     public void test_requestPathSelectorsAreTakenInConsideration() throws Throwable {
         final String requestPath = "/content/test.selector1.selector2.html/en/2016/test.html";
         final String handlerPath = "/content/test";
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
 
         Assert.assertTrue( (boolean)PrivateAccessor.invoke(slingAuthenticator, "isNodeRequiresAuthHandler", new Class[] {String.class, String.class}, new Object[] {requestPath, handlerPath}));
     }
@@ -345,7 +345,6 @@ public class SlingAuthenticatorTest {
     public void test_requestPathSelectorsSiblingAreTakenInConsideration() throws Throwable {
         final String requestPath = "/content/test.selector1.selector2.html/en/2016/09/19/test.html";
         final String handlerPath = "/content/test2";
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
 
         Assert.assertFalse( (boolean)PrivateAccessor.invoke(slingAuthenticator, "isNodeRequiresAuthHandler", new Class[] {String.class, String.class}, new Object[] {requestPath, handlerPath}));
     }
@@ -354,7 +353,6 @@ public class SlingAuthenticatorTest {
     public void test_requestPathBackSlash() throws Throwable {
         final String requestPath = "/page1\\somesubepage";
         final String handlerPath = "/page";
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
 
         Assert.assertFalse( (boolean)PrivateAccessor.invoke(slingAuthenticator, "isNodeRequiresAuthHandler", new Class[] {String.class, String.class}, new Object[] {requestPath, handlerPath}));
     }
@@ -363,7 +361,6 @@ public class SlingAuthenticatorTest {
     public void test_emptyNodeAuthenticationHandlerPath() throws Throwable {
         final String requestPath = "/content/test";
         final String handlerPath = "";
-        SlingAuthenticator slingAuthenticator = new SlingAuthenticator();
 
         Assert.assertTrue( (boolean)PrivateAccessor.invoke(slingAuthenticator, "isNodeRequiresAuthHandler", new Class[] {String.class, String.class}, new Object[] {requestPath, handlerPath}));
     }
@@ -376,14 +373,12 @@ public class SlingAuthenticatorTest {
      * @param request http request
      * @param requestPath request path
      */
-    private void buildExpectationsForRequest(final HttpServletRequest request,
-            final String requestPath) {
-        {
-            Mockito.when(request.getServletPath()).thenReturn(requestPath);
-            Mockito.when(request.getServerName()).thenReturn("localhost");
-            Mockito.when(request.getServerPort()).thenReturn(80);
-            Mockito.when(request.getScheme()).thenReturn("http");
-        }
+    private void buildExpectationsForRequest(final HttpServletRequest request, final String requestPath) {
+        // path is not taken directly from request but from PathToUriMappingService
+        when(resolveResult.getUri()).thenReturn(SlingUriBuilder.parse(requestPath, null).build());
+        when(request.getServerName()).thenReturn("localhost");
+        when(request.getServerPort()).thenReturn(80);
+        when(request.getScheme()).thenReturn("http");
     }
 
     /**