/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.osgi.web.portlet.container.test; import com.liferay.arquillian.extension.junit.bridge.junit.Arquillian; import com.liferay.portal.kernel.portlet.LiferayPortletURL; import com.liferay.portal.kernel.security.auth.AuthToken; import com.liferay.portal.kernel.security.auth.AuthTokenWhitelist; import com.liferay.portal.kernel.test.rule.AggregateTestRule; import com.liferay.portal.kernel.util.HashMapDictionary; import com.liferay.portal.kernel.util.HttpUtil; import com.liferay.portal.kernel.util.MapUtil; import com.liferay.portal.kernel.util.PropsKeys; import com.liferay.portal.security.auth.AuthTokenWhitelistImpl; import com.liferay.portal.security.auth.SessionAuthToken; import com.liferay.portal.test.log.CaptureAppender; import com.liferay.portal.test.log.Log4JLoggerTestUtil; import com.liferay.portal.test.rule.LiferayIntegrationTestRule; import com.liferay.portal.util.test.PortletContainerTestUtil; import com.liferay.portal.util.test.PortletContainerTestUtil.Response; import com.liferay.portlet.PortletURLImpl; import com.liferay.portlet.SecurityPortletContainerWrapper; import java.io.IOException; import java.io.PrintWriter; import java.util.Collections; import java.util.Dictionary; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.portlet.PortletRequest; import javax.portlet.PortletURL; import javax.portlet.ResourceRequest; import javax.portlet.ResourceResponse; import javax.servlet.http.HttpServletRequest; import org.apache.log4j.Level; import org.apache.log4j.spi.LoggingEvent; import org.junit.Assert; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; /** * @author Raymond Augé */ @RunWith(Arquillian.class) public class ActionRequestPortletContainerTest extends BasePortletContainerTestCase { @ClassRule @Rule public static final AggregateTestRule aggregateTestRule = new LiferayIntegrationTestRule(); @Test public void testAuthTokenCheckEnabled() throws Exception { HashMapDictionary<String, Object> properties = new HashMapDictionary<>(); properties.put("service.ranking", Integer.MAX_VALUE); registerService( AuthToken.class, new DisabledSessionAuthToken(), properties); setUpPortlet( testPortlet, new HashMapDictionary<String, Object>(), TEST_PORTLET_ID); HttpServletRequest httpServletRequest = PortletContainerTestUtil.getHttpServletRequest(group, layout); PortletURL portletURL = new PortletURLImpl( httpServletRequest, TEST_PORTLET_ID, layout.getPlid(), PortletRequest.ACTION_PHASE); Response response = PortletContainerTestUtil.request( portletURL.toString()); Assert.assertEquals(200, response.getCode()); Assert.assertTrue(testPortlet.isCalledAction()); } @Test public void testAuthTokenIgnoreOrigins() throws Exception { Dictionary<String, Object> properties = new HashMapDictionary<>(); properties.put( PropsKeys.AUTH_TOKEN_IGNORE_ORIGINS, SecurityPortletContainerWrapper.class.getName()); registerService(Object.class, new Object(), properties); setUpPortlet( testPortlet, new HashMapDictionary<String, Object>(), TEST_PORTLET_ID); HttpServletRequest httpServletRequest = PortletContainerTestUtil.getHttpServletRequest(group, layout); PortletURL portletURL = new PortletURLImpl( httpServletRequest, TEST_PORTLET_ID, layout.getPlid(), PortletRequest.ACTION_PHASE); Response response = PortletContainerTestUtil.request( portletURL.toString()); Assert.assertEquals(200, response.getCode()); Assert.assertTrue(testPortlet.isCalledAction()); } @Test public void testAuthTokenIgnorePortlets() throws Exception { Dictionary<String, Object> properties = new HashMapDictionary<>(); properties.put(PropsKeys.AUTH_TOKEN_IGNORE_PORTLETS, TEST_PORTLET_ID); registerService(Object.class, new Object(), properties); setUpPortlet( testPortlet, new HashMapDictionary<String, Object>(), TEST_PORTLET_ID); HttpServletRequest httpServletRequest = PortletContainerTestUtil.getHttpServletRequest(group, layout); PortletURL portletURL = new PortletURLImpl( httpServletRequest, TEST_PORTLET_ID, layout.getPlid(), PortletRequest.ACTION_PHASE); Response response = PortletContainerTestUtil.request( portletURL.toString()); Assert.assertEquals(200, response.getCode()); Assert.assertTrue(testPortlet.isCalledAction()); } @Test public void testInitParam() throws Exception { Dictionary<String, Object> properties = new HashMapDictionary<>(); properties.put( "javax.portlet.init-param.check-auth-token", Boolean.FALSE.toString()); setUpPortlet(testPortlet, properties, TEST_PORTLET_ID); HttpServletRequest httpServletRequest = PortletContainerTestUtil.getHttpServletRequest(group, layout); PortletURL portletURL = new PortletURLImpl( httpServletRequest, TEST_PORTLET_ID, layout.getPlid(), PortletRequest.ACTION_PHASE); Response response = PortletContainerTestUtil.request( portletURL.toString()); Assert.assertEquals(200, response.getCode()); Assert.assertTrue(testPortlet.isCalledAction()); } @Test public void testNoPortalAuthenticationTokens() throws Exception { setUpPortlet( testPortlet, new HashMapDictionary<String, Object>(), TEST_PORTLET_ID); HttpServletRequest httpServletRequest = PortletContainerTestUtil.getHttpServletRequest(group, layout); PortletURL portletURL = new PortletURLImpl( httpServletRequest, TEST_PORTLET_ID, layout.getPlid(), PortletRequest.ACTION_PHASE); String url = portletURL.toString(); try (CaptureAppender captureAppender = Log4JLoggerTestUtil.configureLog4JLogger( SecurityPortletContainerWrapper.class.getName(), Level.WARN)) { Response response = PortletContainerTestUtil.request(url); List<LoggingEvent> loggingEvents = captureAppender.getLoggingEvents(); Assert.assertEquals( loggingEvents.toString(), 1, loggingEvents.size()); LoggingEvent loggingEvent = loggingEvents.get(0); Assert.assertEquals( "User 0 is not allowed to access URL " + url.substring(0, url.indexOf('?')) + " and portlet " + TEST_PORTLET_ID, loggingEvent.getMessage()); Assert.assertEquals(200, response.getCode()); Assert.assertFalse(testPortlet.isCalledAction()); } } @Test public void testPortalAuthenticationToken() throws Exception { testPortlet = new ActionRequestTestPortlet(); setUpPortlet( testPortlet, new HashMapDictionary<String, Object>(), TEST_PORTLET_ID); HttpServletRequest httpServletRequest = PortletContainerTestUtil.getHttpServletRequest(group, layout); Response response = PortletContainerTestUtil.getPortalAuthentication( httpServletRequest, layout, TEST_PORTLET_ID); testPortlet.reset(); // Make an action request using the portal authentication token PortletURL portletURL = new PortletURLImpl( httpServletRequest, TEST_PORTLET_ID, layout.getPlid(), PortletRequest.ACTION_PHASE); String url = portletURL.toString(); url = HttpUtil.setParameter(url, "p_auth", response.getBody()); response = PortletContainerTestUtil.request( url, Collections.singletonMap("Cookie", response.getCookies())); Assert.assertEquals(200, response.getCode()); Assert.assertTrue(testPortlet.isCalledAction()); } @Test public void testPortalAuthenticationTokenSecret() throws Exception { HashMapDictionary<String, Object> properties = new HashMapDictionary<>(); properties.put("service.ranking", Integer.MAX_VALUE); registerService( AuthTokenWhitelist.class, new TestSharedSecretTokenWhitelist(), properties); setUpPortlet( testPortlet, new HashMapDictionary<String, Object>(), TEST_PORTLET_ID); HttpServletRequest httpServletRequest = PortletContainerTestUtil.getHttpServletRequest(group, layout); PortletURL portletURL = new PortletURLImpl( httpServletRequest, TEST_PORTLET_ID, layout.getPlid(), PortletRequest.ACTION_PHASE); portletURL.setParameter("p_auth_secret", _SHARED_SECRET); Response response = PortletContainerTestUtil.request( portletURL.toString()); Assert.assertEquals(200, response.getCode()); Assert.assertTrue(testPortlet.isCalledAction()); } @Test public void testStrutsAction() throws Exception { Dictionary<String, Object> properties = new HashMapDictionary<>(); properties.put(PropsKeys.AUTH_TOKEN_IGNORE_ACTIONS, "/test/portlet/1"); properties.put("com.liferay.portlet.struts-path", "test/portlet"); setUpPortlet(testPortlet, properties, TEST_PORTLET_ID); HttpServletRequest httpServletRequest = PortletContainerTestUtil.getHttpServletRequest(group, layout); PortletURL portletURL = new PortletURLImpl( httpServletRequest, TEST_PORTLET_ID, layout.getPlid(), PortletRequest.ACTION_PHASE); portletURL.setParameter("struts_action", "/test/portlet/1"); Response response = PortletContainerTestUtil.request( portletURL.toString()); Assert.assertEquals(200, response.getCode()); Assert.assertTrue(testPortlet.isCalledAction()); } @Test public void testXCSRFToken() throws Exception { testPortlet = new ActionRequestTestPortlet(); setUpPortlet( testPortlet, new HashMapDictionary<String, Object>(), TEST_PORTLET_ID); HttpServletRequest httpServletRequest = PortletContainerTestUtil.getHttpServletRequest(group, layout); Response response = PortletContainerTestUtil.getPortalAuthentication( httpServletRequest, layout, TEST_PORTLET_ID); testPortlet.reset(); // Make an action request using the portal authentication token PortletURL portletURL = new PortletURLImpl( httpServletRequest, TEST_PORTLET_ID, layout.getPlid(), PortletRequest.ACTION_PHASE); String url = portletURL.toString(); url = HttpUtil.removeParameter(url, "p_auth"); Map<String, List<String>> headers = new HashMap<>(); headers.put("Cookie", response.getCookies()); headers.put( "X-CSRF-Token", Collections.singletonList(response.getBody())); response = PortletContainerTestUtil.request(url, headers); Assert.assertEquals(200, response.getCode()); Assert.assertTrue(testPortlet.isCalledAction()); } private static final String _SHARED_SECRET = "test"; private static class ActionRequestTestPortlet extends TestPortlet { @Override public void serveResource( ResourceRequest resourceRequest, ResourceResponse resourceResponse) throws IOException { PrintWriter printWriter = resourceResponse.getWriter(); PortletURL portletURL = resourceResponse.createActionURL(); String queryString = HttpUtil.getQueryString(portletURL.toString()); Map<String, String[]> parameterMap = HttpUtil.getParameterMap( queryString); String portalAuthenticationToken = MapUtil.getString( parameterMap, "p_auth"); printWriter.write(portalAuthenticationToken); } } private static class DisabledSessionAuthToken extends SessionAuthToken { @Override public void addCSRFToken( HttpServletRequest request, LiferayPortletURL liferayPortletURL) { } @Override public void checkCSRFToken(HttpServletRequest request, String origin) { } } private static class TestSharedSecretTokenWhitelist extends AuthTokenWhitelistImpl { @Override public boolean isValidSharedSecret(String sharedSecret) { if (_SHARED_SECRET.equals(sharedSecret)) { return true; } return false; } } }