/* * 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.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 javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; 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 { @Test public void test_getTokenFile() { final File root = new File("bundle999").getAbsoluteFile(); final SlingHomeAction slingHome = new SlingHomeAction(); slingHome.setSlingHome(new File("sling").getAbsolutePath()); Mockery context = new Mockery(); final BundleContext bundleContext = context.mock(BundleContext.class); context.checking(new Expectations() { { // mock access to sling.home framework property allowing(bundleContext).getProperty("sling.home"); will(slingHome); // mock no data file support with file names starting with sl allowing(bundleContext).getDataFile( with(new StringStartsWith("sl"))); will(returnValue(null)); // mock data file support for any other name allowing(bundleContext).getDataFile(with(any(String.class))); will(new RVA(root)); } }); final FormAuthenticationHandler handler = new FormAuthenticationHandler(); // test files relative to bundle context File relFile0 = handler.getTokenFile("", bundleContext); assertEquals(root, relFile0); String relName1 = "rel/path"; File relFile1 = handler.getTokenFile(relName1, bundleContext); assertEquals(new File(root, relName1), relFile1); // test file relative to sling.home if no data file support String relName2 = "sl/rel_to_sling.home"; File relFile2 = handler.getTokenFile(relName2, bundleContext); assertEquals(new File(slingHome.getSlingHome(), relName2), relFile2); // test file relative to current working directory String relName3 = "sl/test"; slingHome.setSlingHome(null); File relFile3 = handler.getTokenFile(relName3, bundleContext); assertEquals(new File(relName3).getAbsoluteFile(), relFile3); // test absolute file return File absFile = new File("test").getAbsoluteFile(); File absFile0 = handler.getTokenFile(absFile.getPath(), bundleContext); assertEquals(absFile, absFile0); } @Test public void test_getUserid() { final FormAuthenticationHandler handler = new FormAuthenticationHandler(); assertEquals(null, handler.getUserId(null)); assertEquals(null, handler.getUserId("")); assertEquals(null, handler.getUserId("field0")); assertEquals(null, handler.getUserId("field0@field1")); assertEquals("field3", handler.getUserId("field0@field1@field3")); assertEquals("field3@field4", handler.getUserId("field0@field1@field3@field4")); } /** * 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. */ private static class RVA implements Action { private final File root; RVA(final File root) { this.root = root; } public Object invoke(Invocation invocation) throws Throwable { String data = (String) invocation.getParameter(0); if (data.startsWith("/")) { data = data.substring(1); } return new File(root, data); } public void describeTo(Description description) { description.appendText("returns new File(root, arg0)"); } } /** * The <code>SlingHomeAction</code> action returns the current value of the * <code>slingHome</code> field on all invocations */ private static class SlingHomeAction implements Action { private String slingHome; public void setSlingHome(String slingHome) { this.slingHome = slingHome; } public String getSlingHome() { return slingHome; } public Object invoke(Invocation invocation) throws Throwable { return slingHome; } public void describeTo(Description description) { description.appendText("returns " + slingHome); } } }