package com.globant.katari.core.security; import junit.framework.TestCase; import org.acegisecurity.AccessDecisionManager; import org.acegisecurity.AccessDeniedException; import org.acegisecurity.Authentication; import org.acegisecurity.GrantedAuthority; import org.acegisecurity.ConfigAttribute; import org.acegisecurity.ConfigAttributeDefinition; import org.acegisecurity.InsufficientAuthenticationException; import org.acegisecurity.intercept.web.AbstractFilterInvocationDefinitionSource; import org.acegisecurity.context.SecurityContextHolder; import org.apache.commons.lang.Validate; import static org.easymock.EasyMock.*; /** * SecureUrlAccessHelper test case. * @author gerardo.bercovich */ public class SecureUrlAccessHelperTest extends TestCase { /** Helper instance under test. */ private SecureUrlAccessHelper helper; /** Valid edit report uri. */ private static final String SOURCE_URI = "/ctx/module/m/list.do"; /** Valid edit report target url. */ private static final String ABSOLUTE_GRANTED = "/module/m/edit.do"; /** Valid delete report target uri. */ private static final String ABSOLUTE_DENIED = "/module/m/delete.do"; /** Valid delete report target uri. */ private static final String MODULE_ROOT = "/module/m/"; /** * Constructs the instance 'helper' of SecureUrlAccessHelper type with: * * A mocked DefinitionSource that returns a GrantAccess or DenyAccess * instance. * A DummyDecisionManager that decides based on the given DefinitionSource * type. */ @Override protected void setUp() { AbstractFilterInvocationDefinitionSource sourceMock = createMock(AbstractFilterInvocationDefinitionSource.class); expect(sourceMock.lookupAttributes(ABSOLUTE_GRANTED)) .andReturn(new GrantAccess()).anyTimes(); expect(sourceMock.lookupAttributes(ABSOLUTE_DENIED)) .andReturn(new DenyAccess()).anyTimes(); expect(sourceMock.lookupAttributes(MODULE_ROOT)) .andThrow(new AccessDeniedException("msg")).anyTimes(); replay(sourceMock); GrantedAuthority editor = createMock(GrantedAuthority.class); expect(editor.getAuthority()).andReturn("IS_AUTHENTICATED_ANONYMOUSLY"); expectLastCall().anyTimes(); replay(editor); GrantedAuthority[] authorities = {editor}; Authentication authentication = createMock(Authentication.class); expect(authentication.getAuthorities()).andReturn(authorities); expectLastCall().anyTimes(); replay(authentication); SecurityContextHolder.getContext().setAuthentication(authentication); helper = new SecureUrlAccessHelper(sourceMock, new DummyDecisionManager()); } /** * Test grant access to relative edit url from valid uri location. */ public void testCanAccesUrl_grantRelative() { assertTrue(helper.canAccessUrl(SOURCE_URI, "edit.do")); } /** * Test deny access to relative delte url from valid uri location. */ public void testCanAccesUrl_denyRelative() { assertFalse(helper.canAccessUrl(SOURCE_URI, "delete.do")); } /** * Test grant access to absolute edit url from valid uri location. */ public void testCanAccesUrl_grantAbsolute() { assertTrue(helper.canAccessUrl(SOURCE_URI, "/ctx" + ABSOLUTE_GRANTED)); } /** * Test deny access to absolute delete url from valid uri location. */ public void testCanAccesUrl_denyAbsolute() { assertFalse(helper.canAccessUrl(SOURCE_URI, "/ctx" + ABSOLUTE_DENIED)); } /** * Test Exception trying to access to absolute edit url from invalid uri * location. */ public void testCanAccesUrl_grantFromNoModuleAbsolute() { assertTrue(helper.canAccessUrl("/ctx/index.html", "/ctx" + ABSOLUTE_GRANTED)); } /** * Test Exception trying to access to absolute edit url from invalid uri * location. */ public void testCanAccesUrl_exceptionOnNoModuleRelative() { try { helper.canAccessUrl("/ctx/index.html", "edit.do"); fail("cannot use outside a module"); } catch (IllegalArgumentException e) { } } /** * Test Exception trying to access to full absolute edit url with protocol * from valid uri location. */ public void testCanAccesUrl_exceptionOnUrlWithProtocol() { try { helper.canAccessUrl(SOURCE_URI, "http://localhost:8080/ctx/module/report/editReport.do"); fail("cannot use protocols in absolute paths"); } catch (IllegalArgumentException e) { } } public void testCanAccesUrl_rootModuleDenied() { assertFalse(helper.canAccessUrl(SOURCE_URI, "/ctx" + MODULE_ROOT)); } /** * AccessDecisionManager implementation thats depends on the given * ConfigAttributeDefinition subtype to grant or deny access. * It is suited for use with mock objects for testing purpose. * * @author gerardo.bercovich */ private static class DummyDecisionManager implements AccessDecisionManager { /** * decide upon the type of config passed. */ public void decide(final Authentication authentication, final Object object, final ConfigAttributeDefinition config) throws AccessDeniedException, InsufficientAuthenticationException { Validate.isTrue(config instanceof DenyAccess || config instanceof GrantAccess); if (config instanceof DenyAccess) { throw new AccessDeniedException("test access denied exception"); } } /** * not implemented. */ public boolean supports(final ConfigAttribute attribute) { throw new UnsupportedOperationException("Not implemented!"); } /** * not implemented. */ @SuppressWarnings("unchecked") public boolean supports(final Class clazz) { throw new UnsupportedOperationException("Not implemented!"); } } @SuppressWarnings("serial") private static class DenyAccess extends ConfigAttributeDefinition{} @SuppressWarnings("serial") private static class GrantAccess extends ConfigAttributeDefinition{} }