/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * 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 the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>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.apereo.portal.spring.security.preauth; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; import javax.servlet.ServletException; import org.apereo.portal.layout.profile.ProfileSelectionEvent; import org.apereo.portal.security.ISecurityContext; import org.apereo.portal.security.mvc.LoginController; import org.apereo.portal.spring.security.PortalPersonUserDetails; import org.hibernate.PropertyAccessException; import org.junit.Test; import org.springframework.security.core.context.SecurityContextHolder; public class PortalPreAuthenticatedProcessingFilterTest extends PortalPreAuthenticatedProcessingFilterTestBase { public void additionalSetup() {} @Test public void testLoginWithClearingOfContext() throws IOException, ServletException { SecurityContextHolder.createEmptyContext(); SecurityContextHolder.getContext().setAuthentication(auth); when(request.getServletPath()).thenReturn("/Login"); filter.setClearSecurityContextPriorToPortalAuthentication(true); filter.doFilter(request, response, filterChain); assertNull(SecurityContextHolder.getContext().getAuthentication()); } @Test public void testLoginWithNoClearingOfContext() throws IOException, ServletException { SecurityContextHolder.createEmptyContext(); SecurityContextHolder.getContext().setAuthentication(auth); when(request.getServletPath()).thenReturn("/Login"); filter.setClearSecurityContextPriorToPortalAuthentication(false); filter.doFilter(request, response, filterChain); assertNotNull(SecurityContextHolder.getContext().getAuthentication()); assertEquals(auth, SecurityContextHolder.getContext().getAuthentication()); } @Test public void testLogout() throws IOException, ServletException { SecurityContextHolder.createEmptyContext(); SecurityContextHolder.getContext().setAuthentication(auth); when(request.getServletPath()).thenReturn("/Logout"); filter.doFilter(request, response, filterChain); assertNull(SecurityContextHolder.getContext().getAuthentication()); } @Test public void testGetAuthenticatedCredentials() { ISecurityContext creds = (ISecurityContext) filter.getPreAuthenticatedCredentials(request); assertEquals(context, creds); } @Test public void testAuth() throws IOException, ServletException { PortalPersonUserDetails details = (PortalPersonUserDetails) filter.getPreAuthenticatedPrincipal(request); assertEquals(this.username, details.getUsername()); } @Test public void testFiresProfileSelectionEvent() throws IOException, ServletException { SecurityContextHolder.createEmptyContext(); SecurityContextHolder.getContext().setAuthentication(auth); when(request.getServletPath()).thenReturn("/Login"); when(request.getParameter(LoginController.REQUESTED_PROFILE_KEY)) .thenReturn("someProfileKey"); filter.doFilter(request, response, filterChain); final ProfileSelectionEvent expectedEvent = new ProfileSelectionEvent(filter, "someProfileKey", person, request); verify(this.eventPublisher).publishEvent(expectedEvent); } /** * Test that when swapping to another identity while specifying a target profile, fires event * for that profile. */ @Test public void testFiresSwappedToProfileSelectionEvent() throws IOException, ServletException { SecurityContextHolder.createEmptyContext(); SecurityContextHolder.getContext().setAuthentication(auth); when(request.getServletPath()).thenReturn("/Login"); when(request.isRequestedSessionIdValid()).thenReturn(true); when(identitySwapperManager.getTargetProfile(session)).thenReturn("targetProfileKey"); when(identitySwapperManager.getOriginalUsername(session)).thenReturn(null); when(identitySwapperManager.getTargetUsername(session)).thenReturn("targetUsername"); filter.doFilter(request, response, filterChain); final ProfileSelectionEvent expectedEvent = new ProfileSelectionEvent(filter, "targetProfileKey", person, request); verify(this.eventPublisher).publishEvent(expectedEvent); } /** * Test that when firing a profile selection event arising from personal profile selection, an * exception thrown by the event handler is handled by the * PortalPreAuthenticatedProcessingFilter such that it does not propagate and thereby prevent * user login. That is, failure to register the user profile selection is better than failure to * log in at all. * * @throws IOException * @throws ServletException */ @Test public void testHandlesExceptionFromFiringProfileSelectionEvent() throws IOException, ServletException { SecurityContextHolder.createEmptyContext(); SecurityContextHolder.getContext().setAuthentication(auth); when(request.getServletPath()).thenReturn("/Login"); when(request.getParameter(LoginController.REQUESTED_PROFILE_KEY)) .thenReturn("someProfileKey"); final ProfileSelectionEvent expectedEvent = new ProfileSelectionEvent(filter, "someProfileKey", person, request); final RuntimeException rootCause = new RuntimeException(); final PropertyAccessException propertyAccessException = new PropertyAccessException( rootCause, "String message", false, PortalPreAuthenticatedProcessingFilterTest.class, "somePropertyName"); // test that the specific observed exception type is handled doThrow(propertyAccessException).when(this.eventPublisher).publishEvent(expectedEvent); filter.doFilter(request, response, filterChain); // test that exceptions generally are handled doThrow(rootCause).when(this.eventPublisher).publishEvent(expectedEvent); filter.doFilter(request, response, filterChain); } /** * Test that when firing a profile selection event arising from swapped profile selection, an * exception thrown by the event handler is handled by the * PortalPreAuthenticatedProcessingFilter such that it does not propagate and thereby prevent * (swapped) user login. That is, failure to register the user profile selection and therefore * swapping as potentially the wrong profile is better than failing to swap at all. * * @throws IOException * @throws ServletException */ @Test public void testHandlesExceptionFromFiringSwappedProfileSelectionEvent() throws IOException, ServletException { SecurityContextHolder.createEmptyContext(); SecurityContextHolder.getContext().setAuthentication(auth); when(request.getServletPath()).thenReturn("/Login"); when(request.isRequestedSessionIdValid()).thenReturn(true); when(identitySwapperManager.getTargetProfile(session)).thenReturn("targetProfileKey"); when(identitySwapperManager.getOriginalUsername(session)).thenReturn(null); when(identitySwapperManager.getTargetUsername(session)).thenReturn("targetUsername"); final ProfileSelectionEvent expectedEvent = new ProfileSelectionEvent(filter, "targetProfileKey", person, request); final RuntimeException rootCause = new RuntimeException(); final PropertyAccessException propertyAccessException = new PropertyAccessException( rootCause, "String message", false, PortalPreAuthenticatedProcessingFilterTest.class, "somePropertyName"); // test that the specific observed exception type is handled doThrow(propertyAccessException).when(this.eventPublisher).publishEvent(expectedEvent); filter.doFilter(request, response, filterChain); // test that exceptions generally are handled doThrow(rootCause).when(this.eventPublisher).publishEvent(expectedEvent); filter.doFilter(request, response, filterChain); } }