package org.jtalks.poulpe.security; import org.jtalks.common.model.entity.User; import org.jtalks.common.model.entity.ComponentType; import org.jtalks.poulpe.model.entity.PoulpeUser; import org.jtalks.poulpe.service.UserService; import org.mockito.Matchers; import org.springframework.security.access.AccessDecisionVoter; import org.springframework.security.access.ConfigAttribute; import org.springframework.security.core.Authentication; import org.springframework.web.context.request.RequestAttributes; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.util.Collection; import java.util.Collections; import java.util.List; import static org.mockito.Matchers.anyObject; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.*; import static org.springframework.security.access.AccessDecisionVoter.ACCESS_DENIED; import static org.springframework.security.access.AccessDecisionVoter.ACCESS_GRANTED; import static org.springframework.web.context.request.RequestAttributes.SCOPE_SESSION; import static org.testng.Assert.assertEquals; /** * @author dionis */ public class AclAwareDecisionVoterTest { private static final String USERNAME = "USERNAME"; private static final String AUTHORIZED = "authorizedPoulpeUser"; private static final List<ConfigAttribute> ATTRIBUTES = Collections.emptyList(); private AclAwareDecisionVoter voter; private AccessDecisionVoter baseVoter; private UserService userService; @BeforeMethod public void setUp() { baseVoter = mock(AccessDecisionVoter.class); userService = mock(UserService.class); voter = spy(new AclAwareDecisionVoter(baseVoter, userService)); } @Test public void notAuthorized() { Authentication authentication = mock(Authentication.class); authenticatedSuccessfully(authentication); when(authentication.getPrincipal()).thenReturn("anonymous"); assertEquals(voter.vote(authentication, new Object(), ATTRIBUTES), ACCESS_GRANTED); } @Test public void notPoulpeUserShouldFail() { Authentication authentication = mock(Authentication.class); RequestAttributes requestAttributes = mock(RequestAttributes.class); doReturn(requestAttributes).when(voter).getRequestAttributes(); authenticatedSuccessfully(authentication); when(authentication.getPrincipal()).thenReturn(new User("user", "user@mail.com", "pass", "salt")); assertEquals(voter.vote(authentication, new Object(), ATTRIBUTES), ACCESS_DENIED); } @Test public void firstUnsuccessfulAttempt() { Authentication authentication = mock(Authentication.class); RequestAttributes requestAttributes = mock(RequestAttributes.class); doReturn(requestAttributes).when(voter).getRequestAttributes(); authenticatedSuccessfully(authentication); userHaveNotBeenAuthorizedYet(requestAttributes); unsuccessfulAuthorizationFlow(authentication, createPoulpeUserWithPredefinedName()); assertEquals(voter.vote(authentication, new Object(), ATTRIBUTES), ACCESS_DENIED); verify(requestAttributes).setAttribute(eq(AUTHORIZED), eq(false), eq(SCOPE_SESSION)); } private PoulpeUser createPoulpeUserWithPredefinedName() { PoulpeUser user = new PoulpeUser(); user.setUsername(USERNAME); return user; } private void unsuccessfulAuthorizationFlow(Authentication authentication, PoulpeUser poulpeUser) { when(authentication.getPrincipal()).thenReturn(poulpeUser); when(userService.accessAllowedToComponentType(eq(USERNAME), eq(ComponentType.ADMIN_PANEL))).thenReturn(false); } private void successfulAuthorizationFlow(Authentication authentication, PoulpeUser poulpeUser) { when(authentication.getPrincipal()).thenReturn(poulpeUser); when(userService.accessAllowedToComponentType(eq(USERNAME), eq(ComponentType.ADMIN_PANEL))).thenReturn(true); } private void userHaveNotBeenAuthorizedYet(RequestAttributes requestAttributes) { when(requestAttributes.getAttribute(eq(AUTHORIZED), eq(SCOPE_SESSION))).thenReturn(null); } @Test public void negativeResultOfAuthorizationAfterNegativeAuthorizationResultRememberedInSession() { Authentication authentication = mock(Authentication.class); RequestAttributes requestAttributes = mock(RequestAttributes.class); doReturn(requestAttributes).when(voter).getRequestAttributes(); authenticatedSuccessfully(authentication); previousAttemptToAuthorizeFailed(requestAttributes); unsuccessfulAuthorizationFlow(authentication, createPoulpeUserWithPredefinedName()); assertEquals(voter.vote(authentication, new Object(), ATTRIBUTES), ACCESS_DENIED); verify(requestAttributes).setAttribute(eq(AUTHORIZED), eq(false), eq(SCOPE_SESSION)); } @Test public void positiveResultOfAuthorizationAfterNegativeAuthorizationResultRememberedInSession() { Authentication authentication = mock(Authentication.class); RequestAttributes requestAttributes = mock(RequestAttributes.class); doReturn(requestAttributes).when(voter).getRequestAttributes(); authenticatedSuccessfully(authentication); previousAttemptToAuthorizeFailed(requestAttributes); successfulAuthorizationFlow(authentication, createPoulpeUserWithPredefinedName()); assertEquals(voter.vote(authentication, new Object(), ATTRIBUTES), ACCESS_GRANTED); verify(requestAttributes).setAttribute(eq(AUTHORIZED), eq(true), eq(SCOPE_SESSION)); } private void previousAttemptToAuthorizeFailed(RequestAttributes requestAttributes) { when(requestAttributes.getAttribute(eq(AUTHORIZED), eq(SCOPE_SESSION))).thenReturn(false); } @Test public void successfulAuthorizationShouldBeRememberedInSession() { Authentication authentication = mock(Authentication.class); RequestAttributes requestAttributes = mock(RequestAttributes.class); doReturn(requestAttributes).when(voter).getRequestAttributes(); authenticatedSuccessfully(authentication); userHaveNotBeenAuthorizedYet(requestAttributes); successfulAuthorizationFlow(authentication, createPoulpeUserWithPredefinedName()); assertEquals(voter.vote(authentication, new Object(), ATTRIBUTES), ACCESS_GRANTED); verify(requestAttributes).setAttribute(eq(AUTHORIZED), eq(true), eq(SCOPE_SESSION)); } @Test public void successfulAuthorizationResultShouldBeRememberedInSession() { Authentication authentication = mock(Authentication.class); RequestAttributes requestAttributes = mock(RequestAttributes.class); doReturn(requestAttributes).when(voter).getRequestAttributes(); authenticatedSuccessfully(authentication); when(authentication.getPrincipal()).thenReturn(createPoulpeUserWithPredefinedName()); userWasAuthorizedSuccessfully(requestAttributes); assertEquals(voter.vote(authentication, new Object(), ATTRIBUTES), ACCESS_GRANTED); } @Test public void supportsAttributeShouldBeDelegatedToBaseVoter() { ConfigAttribute configAttribute = mock(ConfigAttribute.class); voter.supports(configAttribute); verify(baseVoter).supports(eq(configAttribute)); } @Test public void supportsClassShouldBeDelegatedToBaseVoter() { Class<?> clazz = Object.class; voter.supports(clazz); verify(baseVoter).supports(eq(clazz)); } private void userWasAuthorizedSuccessfully(RequestAttributes requestAttributes) { when(requestAttributes.getAttribute(eq(AUTHORIZED), eq(SCOPE_SESSION))).thenReturn(true); } private void authenticatedSuccessfully(Authentication authentication) { when(baseVoter.vote(eq(authentication), anyObject(), Matchers.<Collection<ConfigAttribute>>any())).thenReturn(ACCESS_GRANTED); when(authentication.isAuthenticated()).thenReturn(true); } }