/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.security.impl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.geoserver.catalog.LayerGroupInfo; import org.geoserver.catalog.LayerInfo; import org.geoserver.catalog.ResourceInfo; import org.geoserver.catalog.WorkspaceInfo; import org.geoserver.security.AccessMode; import org.geoserver.security.CatalogMode; import org.geoserver.security.DataAccessLimits; import org.geoserver.security.LayerGroupAccessLimits; import org.geoserver.security.ResourceAccessManager; import org.geoserver.security.VectorAccessLimits; import org.geoserver.security.WorkspaceAccessLimits; import org.junit.Before; import org.junit.Test; import org.opengis.filter.Filter; import org.springframework.security.core.Authentication; public class DefaultResourceAccessManagerAuthTest extends AbstractAuthorizationTest { @Before public void setupCatalog() { populateCatalog(); } @Test public void testWideOpen() throws Exception { ResourceAccessManager manager = buildAccessManager("wideOpen.properties"); checkUserAccessFlat(manager, anonymous, true, true); } @Test public void testLockedDown() throws Exception { ResourceAccessManager manager = buildAccessManager("lockedDown.properties"); checkUserAccessFlat(manager, anonymous, false, false); checkUserAccessFlat(manager, roUser, false, false); checkUserAccessFlat(manager, rwUser, true, true); checkUserAccessFlat(manager, root, true, true); } @Test public void testPublicRead() throws Exception { ResourceAccessManager manager = buildAccessManager("publicRead.properties"); checkUserAccessFlat(manager, anonymous, true, false); checkUserAccessFlat(manager, roUser, true, false); checkUserAccessFlat(manager, rwUser, true, true); checkUserAccessFlat(manager, root, true, true); } private void checkUserAccessFlat(ResourceAccessManager manager, Authentication user, boolean expectedRead, boolean expectedWrite) { // states as a layer assertEquals(expectedRead, canAccess(manager, user, statesLayer, AccessMode.READ)); assertEquals(expectedWrite, canAccess(manager, user, statesLayer, AccessMode.WRITE)); // states as a resource final ResourceInfo resource = statesLayer.getResource(); assertEquals(expectedRead, canAccess(manager, user, resource, AccessMode.READ)); assertEquals(expectedWrite, canAccess(manager, user, resource, AccessMode.WRITE)); // the topp ws assertEquals(expectedRead, canAccess(manager, user, toppWs, AccessMode.READ)); assertEquals(expectedWrite, canAccess(manager, user, toppWs, AccessMode.WRITE)); } @Test public void testComplex() throws Exception { ResourceAccessManager wo = buildAccessManager("complex.properties"); // check non configured ws inherits root configuration, auth read, nobody write assertFalse(canAccess(wo, anonymous, nurcWs, AccessMode.READ)); assertFalse(canAccess(wo, anonymous, nurcWs, AccessMode.WRITE)); assertTrue(canAccess(wo, roUser, nurcWs, AccessMode.READ)); assertFalse(canAccess(wo, rwUser, nurcWs, AccessMode.WRITE)); assertTrue(canAccess(wo, root, nurcWs, AccessMode.WRITE)); // check access to the topp workspace (everybody read, nobody for write) assertTrue(canAccess(wo, anonymous, toppWs, AccessMode.READ)); assertFalse(canAccess(wo, anonymous, toppWs, AccessMode.WRITE)); assertTrue(canAccess(wo, roUser, toppWs, AccessMode.READ)); assertFalse(canAccess(wo, rwUser, toppWs, AccessMode.WRITE)); // check non configured layer in topp ws inherits topp security attributes assertTrue(canAccess(wo, anonymous, roadsLayer, AccessMode.READ)); assertFalse(canAccess(wo, anonymous, roadsLayer, AccessMode.WRITE)); assertTrue(canAccess(wo, roUser, roadsLayer, AccessMode.READ)); assertFalse(canAccess(wo, rwUser, roadsLayer, AccessMode.WRITE)); // check states uses its own config (auth for read, auth for write) assertFalse(canAccess(wo, anonymous, statesLayer, AccessMode.READ)); assertFalse(canAccess(wo, anonymous, statesLayer, AccessMode.WRITE)); assertTrue(canAccess(wo, roUser, statesLayer, AccessMode.READ)); assertFalse(canAccess(wo, roUser, statesLayer, AccessMode.WRITE)); assertTrue(canAccess(wo, rwUser, statesLayer, AccessMode.WRITE)); assertTrue(canAccess(wo, rwUser, statesLayer, AccessMode.WRITE)); // check landmarks uses its own config (all can for read, auth for write) assertTrue(canAccess(wo, anonymous, landmarksLayer, AccessMode.READ)); assertFalse(canAccess(wo, anonymous, landmarksLayer, AccessMode.WRITE)); assertTrue(canAccess(wo, roUser, landmarksLayer, AccessMode.READ)); assertFalse(canAccess(wo, roUser, landmarksLayer, AccessMode.WRITE)); assertTrue(canAccess(wo, rwUser, landmarksLayer, AccessMode.READ)); assertTrue(canAccess(wo, rwUser, statesLayer, AccessMode.WRITE)); // check military is off limits for anyone but the military users assertFalse(canAccess(wo, anonymous, basesLayer, AccessMode.READ)); assertFalse(canAccess(wo, anonymous, basesLayer, AccessMode.WRITE)); assertFalse(canAccess(wo, roUser, basesLayer, AccessMode.READ)); assertFalse(canAccess(wo, roUser, basesLayer, AccessMode.WRITE)); assertFalse(canAccess(wo, rwUser, basesLayer, AccessMode.READ)); assertFalse(canAccess(wo, rwUser, basesLayer, AccessMode.WRITE)); assertTrue(canAccess(wo, milUser, basesLayer, AccessMode.READ)); assertTrue(canAccess(wo, milUser, basesLayer, AccessMode.WRITE)); // check the layer with dots assertFalse(canAccess(wo, anonymous, arcGridLayer, AccessMode.READ)); assertFalse(canAccess(wo, anonymous, arcGridLayer, AccessMode.WRITE)); assertFalse(canAccess(wo, roUser, arcGridLayer, AccessMode.READ)); assertFalse(canAccess(wo, roUser, arcGridLayer, AccessMode.WRITE)); assertFalse(canAccess(wo, rwUser, arcGridLayer, AccessMode.READ)); assertFalse(canAccess(wo, rwUser, arcGridLayer, AccessMode.WRITE)); assertTrue(canAccess(wo, milUser, arcGridLayer, AccessMode.READ)); assertTrue(canAccess(wo, milUser, arcGridLayer, AccessMode.WRITE)); } @Test public void testDefaultMode() throws Exception { DefaultResourceAccessManager wo = buildAccessManager("lockedDown.properties"); assertEquals(CatalogMode.HIDE, wo.getMode()); } @Test public void testHideMode() throws Exception { DefaultResourceAccessManager wo = buildAccessManager("lockedDownHide.properties"); assertEquals(CatalogMode.HIDE, wo.getMode()); } @Test public void testChallengeMode() throws Exception { DefaultResourceAccessManager wo = buildAccessManager("lockedDownChallenge.properties"); assertEquals(CatalogMode.CHALLENGE, wo.getMode()); } @Test public void testMixedMode() throws Exception { DefaultResourceAccessManager wo = buildAccessManager("lockedDownMixed.properties"); assertEquals(CatalogMode.MIXED, wo.getMode()); } @Test public void testUnknownMode() throws Exception { DefaultResourceAccessManager wo = buildAccessManager("lockedDownUnknown.properties"); // should fall back on the default and complain in the logger assertEquals(CatalogMode.HIDE, wo.getMode()); } @Test public void testOverride() throws Exception { DefaultResourceAccessManager manager = buildAccessManager("override-ws.properties"); // since the use can read states, it can read its container ws oo assertTrue(canAccess(manager, roUser, statesLayer, AccessMode.READ)); assertTrue(canAccess(manager, roUser, toppWs, AccessMode.READ)); // no access for this one assertFalse(canAccess(manager, milUser, statesLayer, AccessMode.READ)); assertFalse(canAccess(manager, milUser, toppWs, AccessMode.READ)); } @Test public void testWmsNamedTreeAMilitaryOnly() throws Exception { setupRequestThreadLocal("WMS"); DefaultResourceAccessManager manager = buildAccessManager("namedTreeAMilitaryOnly.properties"); assertFalse(canAccess(manager, roUser, namedTreeA, AccessMode.READ)); // only contained in the hidden group and in a "single mode" one assertFalse(canAccess(manager, roUser, statesLayer, AccessMode.READ)); // contained also in containerTreeB assertTrue(canAccess(manager, roUser, roadsLayer, AccessMode.READ)); // the other layers in groups are also available assertTrue(canAccess(manager, roUser, containerTreeB, AccessMode.READ)); assertTrue(canAccess(manager, roUser, nestedContainerE, AccessMode.READ)); assertTrue(canAccess(manager, roUser, forestsLayer, AccessMode.READ)); assertTrue(canAccess(manager, roUser, singleGroupC, AccessMode.READ)); // check the mil user sees everything instead assertTrue(canAccess(manager, milUser, namedTreeA, AccessMode.READ)); assertTrue(canAccess(manager, milUser, statesLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, roadsLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, containerTreeB, AccessMode.READ)); assertTrue(canAccess(manager, milUser, nestedContainerE, AccessMode.READ)); assertTrue(canAccess(manager, milUser, forestsLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, singleGroupC, AccessMode.READ)); } @Test public void testContainerGroupBMilitaryOnly() throws Exception { setupRequestThreadLocal("WMS"); DefaultResourceAccessManager manager = buildAccessManager("containerTreeGroupBMilitaryOnly.properties"); // layer group A and its contents should be visible assertTrue(canAccess(manager, roUser, namedTreeA, AccessMode.READ)); assertTrue(canAccess(manager, roUser, statesLayer, AccessMode.READ)); assertTrue(canAccess(manager, roUser, roadsLayer, AccessMode.READ)); // layer group B and landmarks should not assertFalse(canAccess(manager, roUser, containerTreeB, AccessMode.READ)); assertFalse(canAccess(manager, roUser, landmarksLayer, AccessMode.READ)); // nor the nested group assertFalse(canAccess(manager, roUser, nestedContainerE, AccessMode.READ)); assertFalse(canAccess(manager, roUser, forestsLayer, AccessMode.READ)); // layer group C should be available assertTrue(canAccess(manager, roUser, singleGroupC, AccessMode.READ)); // now switch to the military user, that should see everything instead assertTrue(canAccess(manager, milUser, namedTreeA, AccessMode.READ)); assertTrue(canAccess(manager, milUser, statesLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, roadsLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, containerTreeB, AccessMode.READ)); assertTrue(canAccess(manager, milUser, nestedContainerE, AccessMode.READ)); assertTrue(canAccess(manager, milUser, forestsLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, singleGroupC, AccessMode.READ)); } @Test public void testWmsbothGroupABMilitaryOnly() throws Exception { setupRequestThreadLocal("WMS"); DefaultResourceAccessManager manager = buildAccessManager("bothGroupABMilitaryOnly.properties"); assertFalse(canAccess(manager, roUser, namedTreeA, AccessMode.READ)); // only contained in the hidden group and in a "single mode" one assertFalse(canAccess(manager, roUser, statesLayer, AccessMode.READ)); // contained also in containerTreeB, which is also denied assertFalse(canAccess(manager, roUser, roadsLayer, AccessMode.READ)); // the other layers in groups are also available assertFalse(canAccess(manager, roUser, containerTreeB, AccessMode.READ)); assertFalse(canAccess(manager, roUser, landmarksLayer, AccessMode.READ)); assertFalse(canAccess(manager, roUser, nestedContainerE, AccessMode.READ)); assertFalse(canAccess(manager, roUser, forestsLayer, AccessMode.READ)); assertTrue(canAccess(manager, roUser, singleGroupC, AccessMode.READ)); // check the mil user sees everything instead assertTrue(canAccess(manager, milUser, namedTreeA, AccessMode.READ)); assertTrue(canAccess(manager, milUser, statesLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, roadsLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, landmarksLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, containerTreeB, AccessMode.READ)); assertTrue(canAccess(manager, milUser, nestedContainerE, AccessMode.READ)); assertTrue(canAccess(manager, milUser, forestsLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, singleGroupC, AccessMode.READ)); } @Test public void testSingleGroupCMilitaryOnly() throws Exception { setupRequestThreadLocal("WMS"); DefaultResourceAccessManager manager = buildAccessManager("singleGroupCMilitaryOnly.properties"); // layer group A and its contents should be visible assertTrue(canAccess(manager, roUser, namedTreeA, AccessMode.READ)); assertTrue(canAccess(manager, roUser, statesLayer, AccessMode.READ)); assertTrue(canAccess(manager, roUser, roadsLayer, AccessMode.READ)); // layer group B and landmarks should also be visible assertTrue(canAccess(manager, roUser, containerTreeB, AccessMode.READ)); assertTrue(canAccess(manager, roUser, landmarksLayer, AccessMode.READ)); // layer group C should not be available, but the layers in it, states and bases, should assertFalse(canAccess(manager, roUser, singleGroupC, AccessMode.READ)); assertTrue(canAccess(manager, roUser, basesLayer, AccessMode.READ)); // now switch to the military user, that should see everything instead assertTrue(canAccess(manager, milUser, namedTreeA, AccessMode.READ)); assertTrue(canAccess(manager, milUser, statesLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, roadsLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, containerTreeB, AccessMode.READ)); assertTrue(canAccess(manager, milUser, singleGroupC, AccessMode.READ)); } @Test public void testWsContainerGroupDMilitaryOnly() throws Exception { setupRequestThreadLocal("WMS"); DefaultResourceAccessManager manager = buildAccessManager("wsContainerGroupDMilitaryOnly.properties"); // layer group A and its contents should be visible assertTrue(canAccess(manager, roUser, namedTreeA, AccessMode.READ)); assertTrue(canAccess(manager, roUser, statesLayer, AccessMode.READ)); assertTrue(canAccess(manager, roUser, roadsLayer, AccessMode.READ)); // layer group B and landmarks should also be visible assertTrue(canAccess(manager, roUser, containerTreeB, AccessMode.READ)); assertTrue(canAccess(manager, roUser, landmarksLayer, AccessMode.READ)); // layer group C should available, but the layers in it, states and bases, should assertTrue(canAccess(manager, roUser, singleGroupC, AccessMode.READ)); assertTrue(canAccess(manager, roUser, basesLayer, AccessMode.READ)); // layer group D and its exclusive contents are not visible assertFalse(canAccess(manager, roUser, wsContainerD, AccessMode.READ)); assertFalse(canAccess(manager, roUser, arcGridLayer, AccessMode.READ)); // now switch to the military user, that should see everything instead assertTrue(canAccess(manager, milUser, namedTreeA, AccessMode.READ)); assertTrue(canAccess(manager, milUser, statesLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, roadsLayer, AccessMode.READ)); assertTrue(canAccess(manager, milUser, containerTreeB, AccessMode.READ)); assertTrue(canAccess(manager, milUser, singleGroupC, AccessMode.READ)); assertTrue(canAccess(manager, milUser, wsContainerD, AccessMode.READ)); assertTrue(canAccess(manager, milUser, arcGridLayer, AccessMode.READ)); } private boolean canAccess(ResourceAccessManager manager, Authentication user, LayerInfo catalogInfo, AccessMode mode) { DataAccessLimits limits = manager.getAccessLimits(user, catalogInfo); return canAccess(mode, limits); } private boolean canAccess(ResourceAccessManager manager, Authentication user, LayerGroupInfo catalogInfo, AccessMode mode) { LayerGroupAccessLimits limits = manager.getAccessLimits(user, catalogInfo); return limits == null; } private boolean canAccess(AccessMode mode, DataAccessLimits limits) { if(limits == null) { return true; } else if(mode == AccessMode.READ) { return limits.getReadFilter() != Filter.EXCLUDE; } else if(mode == AccessMode.WRITE) { if(limits instanceof VectorAccessLimits) { return ((VectorAccessLimits) limits).getWriteFilter() != Filter.EXCLUDE; } else { return false; } } else { throw new RuntimeException("Unknown access mode " + mode); } } private boolean canAccess(ResourceAccessManager manager, Authentication user, ResourceInfo catalogInfo, AccessMode mode) { DataAccessLimits limits = manager.getAccessLimits(user, catalogInfo); return canAccess(mode, limits); } private boolean canAccess(ResourceAccessManager manager, Authentication user, WorkspaceInfo catalogInfo, AccessMode mode) { WorkspaceAccessLimits limits = manager.getAccessLimits(user, catalogInfo); if(limits == null) { return true; } else if(mode == AccessMode.READ) { return limits.isReadable(); } else if(mode == AccessMode.WRITE) { return limits.isWritable(); } else if(mode == AccessMode.ADMIN) { return limits.isAdminable(); } else { throw new RuntimeException("Unknown access mode " + mode); } } }