Author: cziegeler
Date: Mon Mar 10 09:53:48 2014
New Revision: 1575881

URL: http://svn.apache.org/r1575881
Log:
SLING-3443 : Parameter based redirection in FormAuthenticationHandler should 
not handle absolute urls. Apply modified patch from Ravi Teja

Modified:
    sling/trunk/bundles/auth/form/pom.xml
    
sling/trunk/bundles/auth/form/src/main/java/org/apache/sling/auth/form/impl/FormAuthenticationHandler.java
    
sling/trunk/bundles/auth/form/src/test/java/org/apache/sling/auth/form/FormReasonTest.java
    
sling/trunk/bundles/auth/form/src/test/java/org/apache/sling/auth/form/impl/FormAuthenticationHandlerTest.java

Modified: sling/trunk/bundles/auth/form/pom.xml
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/auth/form/pom.xml?rev=1575881&r1=1575880&r2=1575881&view=diff
==============================================================================
--- sling/trunk/bundles/auth/form/pom.xml (original)
+++ sling/trunk/bundles/auth/form/pom.xml Mon Mar 10 09:53:48 2014
@@ -171,5 +171,23 @@
             <groupId>org.slf4j</groupId>
             <artifactId>slf4j-simple</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <version>3.2</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-module-junit4</artifactId>
+            <version>1.5.4</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.powermock</groupId>
+            <artifactId>powermock-api-easymock</artifactId>
+            <version>1.5.4</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>

Modified: 
sling/trunk/bundles/auth/form/src/main/java/org/apache/sling/auth/form/impl/FormAuthenticationHandler.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/auth/form/src/main/java/org/apache/sling/auth/form/impl/FormAuthenticationHandler.java?rev=1575881&r1=1575880&r2=1575881&view=diff
==============================================================================
--- 
sling/trunk/bundles/auth/form/src/main/java/org/apache/sling/auth/form/impl/FormAuthenticationHandler.java
 (original)
+++ 
sling/trunk/bundles/auth/form/src/main/java/org/apache/sling/auth/form/impl/FormAuthenticationHandler.java
 Mon Mar 10 09:53:48 2014
@@ -37,6 +37,7 @@ import javax.servlet.http.HttpSession;
 
 import org.apache.commons.codec.binary.Base64;
 import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
 import org.apache.felix.scr.annotations.Properties;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.PropertyOption;
@@ -51,7 +52,6 @@ import org.apache.sling.api.resource.Res
 import org.apache.sling.api.resource.ResourceResolverFactory;
 import org.apache.sling.auth.core.AuthConstants;
 import org.apache.sling.auth.core.AuthUtil;
-import org.apache.sling.auth.core.spi.AbstractAuthenticationHandler;
 import org.apache.sling.auth.core.spi.AuthenticationHandler;
 import org.apache.sling.auth.core.spi.AuthenticationInfo;
 import org.apache.sling.auth.core.spi.DefaultAuthenticationFeedbackHandler;
@@ -76,7 +76,7 @@ import org.slf4j.LoggerFactory;
     @Property(name = AuthenticationHandler.TYPE_PROPERTY, value = 
HttpServletRequest.FORM_AUTH, propertyPrivate = true),
     @Property(name = Constants.SERVICE_RANKING, intValue = 0, propertyPrivate 
= false) })
 @Service
-public class FormAuthenticationHandler extends AbstractAuthenticationHandler {
+public class FormAuthenticationHandler extends 
DefaultAuthenticationFeedbackHandler implements AuthenticationHandler {
 
     /**
      * The name of the parameter providing the login form URL.
@@ -322,7 +322,7 @@ public class FormAuthenticationHandler e
                     // so that the invalid cookie isn't present on the authN
                     // operation.
                     authStorage.clear(request, response);
-                    if (this.loginAfterExpire || isValidateRequest(request)) {
+                    if (this.loginAfterExpire || 
AuthUtil.isValidateRequest(request)) {
                         // signal the requestCredentials method a previous 
login
                         // failure
                         request.setAttribute(FAILURE_REASON, 
FormReason.TIMEOUT);
@@ -355,13 +355,13 @@ public class FormAuthenticationHandler e
             return false;
         }
 
-        //check the referer to see if the request is for this handler
+        //check the referrer to see if the request is for this handler
         if (!AuthUtil.checkReferer(request, loginForm)) {
                //not for this handler, so return
                return false;
         }
 
-        final String resource = setLoginResourceAttribute(request,
+        final String resource = AuthUtil.setLoginResourceAttribute(request,
             request.getRequestURI());
 
         if (includeLoginForm && (resourceResolverFactory != null)) {
@@ -401,7 +401,7 @@ public class FormAuthenticationHandler e
         }
 
         try {
-            sendRedirect(request, response, loginForm, params);
+            AuthUtil.sendRedirect(request, response, loginForm, params);
         } catch (IOException e) {
             log.error("Failed to redirect to the login form " + loginForm, e);
         }
@@ -477,12 +477,25 @@ public class FormAuthenticationHandler e
                result = false;
             } else {
                // check whether redirect is requested by the resource parameter
-               final String resource = getLoginResource(request, null);
-               if (resource != null) {
+               final String targetResource = 
AuthUtil.getLoginResource(request, null);
+               if (targetResource != null) {
                        try {
-                               response.sendRedirect(resource);
+                       if (response.isCommitted()) {
+                           throw new IllegalStateException("Response is 
already committed");
+                       }
+                       response.resetBuffer();
+
+                       StringBuilder b = new StringBuilder();
+                       if (AuthUtil.isRedirectValid(request, targetResource)) {
+                           b.append(targetResource);
+                       } else if (request.getContextPath().length() == 0) {
+                           b.append("/");
+                       } else {
+                           b.append(request.getContextPath());
+                       }
+                       response.sendRedirect(b.toString());
                        } catch (IOException ioe) {
-                               log.error("Failed to send redirect to: " + 
resource, ioe);
+                               log.error("Failed to send redirect to: " + 
targetResource, ioe);
                        }
 
                        // terminate request, all done
@@ -593,8 +606,8 @@ public class FormAuthenticationHandler e
                 // as a POST request to the j_security_check page (unless
                 // the j_validate parameter is set); but only if this is not
                 // a validation request
-                if (!isValidateRequest(request)) {
-                    setLoginResourceAttribute(request, 
request.getContextPath());
+                if (!AuthUtil.isValidateRequest(request)) {
+                    AuthUtil.setLoginResourceAttribute(request, 
request.getContextPath());
                 }
             }
         }
@@ -731,8 +744,8 @@ public class FormAuthenticationHandler e
         this.loginAfterExpire = 
OsgiUtil.toBoolean(properties.get(PAR_LOGIN_AFTER_EXPIRE), 
DEFAULT_LOGIN_AFTER_EXPIRE);
     }
 
-    protected void deactivate(
-            @SuppressWarnings("unused") ComponentContext componentContext) {
+    @Deactivate
+    protected void deactivate() {
         if (loginModule != null) {
             loginModule.unregister();
             loginModule = null;

Modified: 
sling/trunk/bundles/auth/form/src/test/java/org/apache/sling/auth/form/FormReasonTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/auth/form/src/test/java/org/apache/sling/auth/form/FormReasonTest.java?rev=1575881&r1=1575880&r2=1575881&view=diff
==============================================================================
--- 
sling/trunk/bundles/auth/form/src/test/java/org/apache/sling/auth/form/FormReasonTest.java
 (original)
+++ 
sling/trunk/bundles/auth/form/src/test/java/org/apache/sling/auth/form/FormReasonTest.java
 Mon Mar 10 09:53:48 2014
@@ -18,23 +18,24 @@
  */
 package org.apache.sling.auth.form;
 
-import org.apache.sling.auth.form.FormReason;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
 
-import junit.framework.TestCase;
+import org.junit.Test;
 
-public class FormReasonTest extends TestCase {
+public class FormReasonTest {
 
-    public void test_TIMEOUT() {
+    @Test public void test_TIMEOUT() {
         assertEquals(FormReason.TIMEOUT,
             FormReason.valueOf(FormReason.TIMEOUT.name()));
     }
 
-    public void test_INVALID_CREDENTIALS() {
+    @Test public void test_INVALID_CREDENTIALS() {
         assertEquals(FormReason.INVALID_CREDENTIALS,
             FormReason.valueOf(FormReason.INVALID_CREDENTIALS.name()));
     }
 
-    public void test_INVALID() {
+    @Test public void test_INVALID() {
         try {
             FormReason.valueOf("INVALID");
             fail("unexpected result getting value of an invalid constant");

Modified: 
sling/trunk/bundles/auth/form/src/test/java/org/apache/sling/auth/form/impl/FormAuthenticationHandlerTest.java
URL: 
http://svn.apache.org/viewvc/sling/trunk/bundles/auth/form/src/test/java/org/apache/sling/auth/form/impl/FormAuthenticationHandlerTest.java?rev=1575881&r1=1575880&r2=1575881&view=diff
==============================================================================
--- 
sling/trunk/bundles/auth/form/src/test/java/org/apache/sling/auth/form/impl/FormAuthenticationHandlerTest.java
 (original)
+++ 
sling/trunk/bundles/auth/form/src/test/java/org/apache/sling/auth/form/impl/FormAuthenticationHandlerTest.java
 Mon Mar 10 09:53:48 2014
@@ -18,22 +18,42 @@
  */
 package org.apache.sling.auth.form.impl;
 
+import static org.easymock.EasyMock.cmpEq;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+import static org.junit.Assert.assertEquals;
+
 import java.io.File;
+import java.lang.reflect.Method;
 
-import junit.framework.TestCase;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
-import org.apache.sling.auth.form.impl.FormAuthenticationHandler;
+import org.apache.sling.api.auth.Authenticator;
+import org.apache.sling.auth.core.spi.AuthenticationInfo;
+import org.apache.sling.auth.core.spi.DefaultAuthenticationFeedbackHandler;
 import org.hamcrest.Description;
 import org.hamcrest.text.StringStartsWith;
 import org.jmock.Expectations;
 import org.jmock.Mockery;
 import org.jmock.api.Action;
 import org.jmock.api.Invocation;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.osgi.framework.BundleContext;
+import org.powermock.api.easymock.PowerMock;
+import org.powermock.api.support.membermodification.MemberMatcher;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest(FormAuthenticationHandler.class)
+public class FormAuthenticationHandlerTest {
 
-public class FormAuthenticationHandlerTest extends TestCase {
-
-    public void test_getTokenFile() {
+    @Test public void test_getTokenFile() {
         final File root = new File("bundle999").getAbsoluteFile();
         final SlingHomeAction slingHome = new SlingHomeAction();
         slingHome.setSlingHome(new File("sling").getAbsolutePath());
@@ -85,7 +105,7 @@ public class FormAuthenticationHandlerTe
         assertEquals(absFile, absFile0);
     }
 
-    public void test_getUserid() {
+    @Test public void test_getUserid() {
         final FormAuthenticationHandler handler = new 
FormAuthenticationHandler();
         assertEquals(null, handler.getUserId(null));
         assertEquals(null, handler.getUserId(""));
@@ -96,6 +116,61 @@ public class FormAuthenticationHandlerTe
     }
 
     /**
+     * Test for SLING-3443 Parameter based redirection should only handle 
relative paths
+     * @throws Exception PowerMock.expectPrivate throws Exception and 
UrlEncoder.encode
+     *                          throws UnsupportedEncodingException
+     * @since 1.0.6
+     */
+    @Test public void testRedirectionAfterLogin() throws Exception {
+        // Create mocks
+        final HttpServletRequest request = 
createMock(HttpServletRequest.class);
+        final HttpServletResponse response = 
createMock(HttpServletResponse.class);
+        final AuthenticationInfo authenticationInfo = 
createMock(AuthenticationInfo.class);
+
+        // Use PowerMock to mock private method
+        final String methodName = "refreshAuthData";
+        final FormAuthenticationHandler authenticationHandler = 
PowerMock.createPartialMock(FormAuthenticationHandler.class,
+                methodName);
+        final Method[] methods = 
MemberMatcher.methods(FormAuthenticationHandler.class, methodName);
+        PowerMock.expectPrivate(authenticationHandler, methods[0], request, 
response, authenticationInfo);
+
+        // Mock the static method since we are just unit testing the 
authentication succeeded flow
+        PowerMock.mockStatic(DefaultAuthenticationFeedbackHandler.class);
+        expect(DefaultAuthenticationFeedbackHandler.handleRedirect(request, 
response)).andReturn(false);
+
+        // Mocks the Authenticator.LOGIN_RESOURCE attribute
+        final String url = "http://www.blah.com";;
+        
expect(request.getAttribute(Authenticator.LOGIN_RESOURCE)).andReturn(url);
+
+        // Mocks the HttpServletRequest and HttpServletResponse object
+        expect(request.getMethod()).andReturn("POST");
+        
expect(request.getRequestURI()).andReturn("http://blah/blah/j_security_check";);
+        String contextPath = "/blah";
+        expect(request.getContextPath()).andReturn(contextPath).anyTimes();
+        expect(response.isCommitted()).andReturn(false);
+
+        // Mocking method with void return type
+        response.resetBuffer();
+        expectLastCall().once();
+
+        // The request should be redirected to the context root rather than the
+        // passing the parameter directly
+        response.sendRedirect(cmpEq(contextPath));
+
+        // Replay the mocks
+        replay(request);
+        replay(response);
+        replay(authenticationInfo);
+        replay(authenticationHandler);
+
+        // Test the method
+        authenticationHandler.authenticationSucceeded(request, response, 
authenticationInfo);
+
+        // Verify mocks
+        verify(request, response, authenticationInfo, authenticationHandler);
+    }
+
+    /**
      * The <code>RVA</code> action returns a file relative to some root file as
      * requested by the first parameter of the invocation, expecting the first
      * parameter to be a string.


Reply via email to