/* (c) 2016 Open Source Geospatial Foundation - all rights reserved * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.security.impl; import static org.hamcrest.Matchers.contains; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import java.io.StringReader; import java.util.Arrays; import java.util.Properties; import java.util.stream.Collectors; import java.util.stream.Stream; import org.geoserver.catalog.LayerGroupInfo; import org.geoserver.catalog.LayerGroupInfo.Mode; import org.geoserver.ows.Dispatcher; import org.geoserver.platform.GeoServerExtensionsHelper; import org.geoserver.security.ResourceAccessManager; import org.geoserver.security.SecureCatalogImpl; import org.junit.Test; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; /** * A variant to {@link SecureCatalogImplTest} allowing a per test setup of group nesting and rules * * @author Andrea Aime - GeoSolutions */ public class SecureCatalogImplGroupsTest extends AbstractAuthorizationTest { private static final String NAMED_GROUP_NAME = "named"; private static final String OPAQUE_GROUP_NAME = "opaque"; private static final String SINGLE_GROUP_NAME = "single"; private static final String NESTED_GROUP_NAME = "nested"; private static final String[] DEFAULT_RULES = new String[] { "*.*.r=*", "*.*.w=*" }; @Override public void setUp() throws Exception { super.setUp(); SecurityContextHolder.getContext().setAuthentication(null); Dispatcher.REQUEST.remove(); } protected ResourceAccessManager buildManager(String... theRules) throws Exception { Properties props = new Properties(); props.load(new StringReader(Stream.of(theRules).collect(Collectors.joining("\n")))); DefaultResourceAccessManager manager = new DefaultResourceAccessManager( new MemoryDataAccessRuleDAO(catalog, props), catalog); sc = new SecureCatalogImpl(catalog, manager) { @Override protected boolean isAdmin(Authentication authentication) { return false; } }; GeoServerExtensionsHelper.singleton("secureCatalog", sc, SecureCatalogImpl.class); return manager; } private LayerGroupInfo prepareStandaloneOpaqueGroup() throws Exception { // setup group LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, statesLayer, roadsLayer); layerGroups = Arrays.asList(opaque); populateCatalog(); // setup security buildManager(DEFAULT_RULES); SecurityContextHolder.getContext().setAuthentication(roUser); return opaque; } @Test public void testWmsStandaloneOpaqueGroup() throws Exception { setupRequestThreadLocal("WMS"); LayerGroupInfo opaque = prepareStandaloneOpaqueGroup(); // direct access to layers not allowed assertNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // however we can access the group and the layers through it LayerGroupInfo securedGroup = sc.getLayerGroupByName(opaque.prefixedName()); assertNotNull(securedGroup); assertEquals(2, securedGroup.getLayers().size()); } @Test public void testWfsStandaloneOpaqueGroup() throws Exception { setupRequestThreadLocal("WFS"); LayerGroupInfo opaque = prepareStandaloneOpaqueGroup(); // direct access to layers is allowed in this case assertNotNull(sc.getLayerByName(statesLayer.prefixedName())); assertNotNull(sc.getLayerByName(roadsLayer.prefixedName())); // and we can access the group and the layers through it LayerGroupInfo securedGroup = sc.getLayerGroupByName(opaque.prefixedName()); assertNotNull(securedGroup); assertEquals(2, securedGroup.getLayers().size()); } private LayerGroupInfo prepareNamedAndOpaqueGroup() throws Exception { // setup group LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, statesLayer, roadsLayer); LayerGroupInfo named = buildLayerGroup(NAMED_GROUP_NAME, Mode.NAMED, null, statesLayer, roadsLayer); layerGroups = Arrays.asList(named, opaque); populateCatalog(); // setup security buildManager(DEFAULT_RULES); SecurityContextHolder.getContext().setAuthentication(roUser); return opaque; } @Test public void testWmsNamedOpaqueGroup() throws Exception { setupRequestThreadLocal("WMS"); LayerGroupInfo opaque = prepareNamedAndOpaqueGroup(); // direct access to layers allowed because of the named group assertNotNull(sc.getLayerByName(statesLayer.prefixedName())); assertNotNull(sc.getLayerByName(roadsLayer.prefixedName())); // we can access the group and the layers through it LayerGroupInfo securedGroup = sc.getLayerGroupByName(opaque.prefixedName()); assertNotNull(securedGroup); assertEquals(2, securedGroup.getLayers().size()); } @Test public void testWfsNamedOpaqueGroup() throws Exception { setupRequestThreadLocal("WFS"); LayerGroupInfo opaque = prepareNamedAndOpaqueGroup(); // direct access to layers allowed assertNotNull(sc.getLayerByName(statesLayer.prefixedName())); assertNotNull(sc.getLayerByName(roadsLayer.prefixedName())); // and we can access the group and the layers through it LayerGroupInfo securedGroup = sc.getLayerGroupByName(opaque.prefixedName()); assertNotNull(securedGroup); assertEquals(2, securedGroup.getLayers().size()); } @Test public void testWmsSingleAndOpaqueGroup() throws Exception { setupRequestThreadLocal("WMS"); // setup groups LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, statesLayer, roadsLayer); LayerGroupInfo single = buildLayerGroup(SINGLE_GROUP_NAME, Mode.SINGLE, null, statesLayer, roadsLayer); layerGroups = Arrays.asList(single, opaque); populateCatalog(); // setup security buildManager(DEFAULT_RULES); SecurityContextHolder.getContext().setAuthentication(roUser); // direct access to layers not allowed because the only container is in opaque mode assertNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // we can access the group and the layers through it LayerGroupInfo opaqueSecuredGroup = sc.getLayerGroupByName(opaque.prefixedName()); assertNotNull(opaqueSecuredGroup); assertEquals(2, opaqueSecuredGroup.getLayers().size()); LayerGroupInfo securedSingleGroup = sc.getLayerGroupByName(single.prefixedName()); assertNotNull(securedSingleGroup); assertEquals(2, securedSingleGroup.getLayers().size()); } @Test public void testWmsMilitaryNamedAndPublicOpaqueGroup() throws Exception { setupRequestThreadLocal("WMS"); // setup groups LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, statesLayer, roadsLayer); LayerGroupInfo named = buildLayerGroup(NAMED_GROUP_NAME, Mode.NAMED, null, statesLayer, roadsLayer); layerGroups = Arrays.asList(named, opaque); populateCatalog(); // setup security buildManager(new String[] { "named.r=MILITARY" }); // try the ro user SecurityContextHolder.getContext().setAuthentication(roUser); // ... direct access to layers not allowed because the named group is not visible assertNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // ... but we can access the opaque group and the layers through it LayerGroupInfo securedGroup = sc.getLayerGroupByName(OPAQUE_GROUP_NAME); assertNotNull(securedGroup); assertEquals(2, securedGroup.getLayers().size()); // now try with the military one SecurityContextHolder.getContext().setAuthentication(milUser); // ... direct access to layers allowed because the named group is visible to the mil user assertNotNull(sc.getLayerByName(statesLayer.prefixedName())); assertNotNull(sc.getLayerByName(roadsLayer.prefixedName())); } @Test public void testWmsPublicSingleAndSecuredOpaqueGroup() throws Exception { setupRequestThreadLocal("WMS"); // setup groups LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, forestsLayer, roadsLayer); LayerGroupInfo single = buildLayerGroup(SINGLE_GROUP_NAME, Mode.SINGLE, null, statesLayer, roadsLayer); layerGroups = Arrays.asList(single, opaque); populateCatalog(); // setup security, single allowed to everybody, opaque to military only buildManager(SINGLE_GROUP_NAME + ".r=*", OPAQUE_GROUP_NAME + ".r=MILITARY"); SecurityContextHolder.getContext().setAuthentication(roUser); // try the ro user SecurityContextHolder.getContext().setAuthentication(roUser); // ... the only directly available layer should be states, contained in single assertNotNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(forestsLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // ... and even via groups it's the same assertNull(sc.getLayerGroupByName(opaque.prefixedName())); LayerGroupInfo securedSingleGroup = sc.getLayerGroupByName(single.prefixedName()); assertNotNull(securedSingleGroup); assertEquals(1, securedSingleGroup.getLayers().size()); // however switching to mil user SecurityContextHolder.getContext().setAuthentication(milUser); // ... same as above for direct access assertNotNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(forestsLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // but the opaque group is now visible along with its layers securedSingleGroup = sc.getLayerGroupByName(single.prefixedName()); assertNotNull(securedSingleGroup); assertEquals(2, securedSingleGroup.getLayers().size()); LayerGroupInfo securedOpaqueGroup = sc.getLayerGroupByName(opaque.prefixedName()); assertNotNull(securedOpaqueGroup); assertEquals(2, securedOpaqueGroup.getLayers().size()); } @Test public void testWmsSecuredSingleAndPublicOpaqueGroup() throws Exception { setupRequestThreadLocal("WMS"); // setup groups LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, forestsLayer, roadsLayer); LayerGroupInfo single = buildLayerGroup(SINGLE_GROUP_NAME, Mode.SINGLE, null, statesLayer, roadsLayer); layerGroups = Arrays.asList(single, opaque); populateCatalog(); // setup security, single allowed to everybody, opaque to military only buildManager(SINGLE_GROUP_NAME + ".r=MILITARY", OPAQUE_GROUP_NAME + ".r=*"); SecurityContextHolder.getContext().setAuthentication(roUser); // try the ro user SecurityContextHolder.getContext().setAuthentication(roUser); // ... states should be visible since "single" auth does not cascade to contained layers assertNotNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(forestsLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // ... the single group is not available, the opaque allows access to all its layers, even // the ones shared with the single assertNull(sc.getLayerGroupByName(single.prefixedName())); LayerGroupInfo securedOpaqueGroup = sc.getLayerGroupByName(opaque.prefixedName()); assertNotNull(securedOpaqueGroup); assertEquals(2, securedOpaqueGroup.getLayers().size()); // however switching to mil user SecurityContextHolder.getContext().setAuthentication(milUser); // ... now states becomes visible assertNotNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(forestsLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // but the opaque group is now visible along with its layers LayerGroupInfo securedSingleGroup = sc.getLayerGroupByName(single.prefixedName()); assertNotNull(securedSingleGroup); assertEquals(2, securedSingleGroup.getLayers().size()); securedOpaqueGroup = sc.getLayerGroupByName(opaque.prefixedName()); assertNotNull(securedOpaqueGroup); assertEquals(2, securedOpaqueGroup.getLayers().size()); } @Test public void testNestedOpaqueGroup() throws Exception { setupRequestThreadLocal("WMS"); // setup groups LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, statesLayer, roadsLayer); LayerGroupInfo named = buildLayerGroup(NAMED_GROUP_NAME, Mode.NAMED, null, forestsLayer, opaque); layerGroups = Arrays.asList(named, opaque); populateCatalog(); // setup security buildManager(DEFAULT_RULES); // direct access forests allowed but not states and roads assertNotNull(sc.getLayerByName(forestsLayer.prefixedName())); assertNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // however via group access we can see all layers LayerGroupInfo securedNamedGroup = sc.getLayerGroupByName(NAMED_GROUP_NAME); assertEquals(3, securedNamedGroup.layers().size()); LayerGroupInfo securedOpaqueGroup = sc.getLayerGroupByName(OPAQUE_GROUP_NAME); assertEquals(2, securedOpaqueGroup.layers().size()); } @Test public void testNestedOpaqueDenyNestedGroup() throws Exception { setupRequestThreadLocal("WMS"); // setup groups LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, statesLayer, roadsLayer); LayerGroupInfo named = buildLayerGroup(NAMED_GROUP_NAME, Mode.NAMED, null, forestsLayer, opaque); layerGroups = Arrays.asList(named, opaque); populateCatalog(); // setup security, disallow nested group buildManager(new String[] { OPAQUE_GROUP_NAME + ".r=MILITARY" }); // try the ro user SecurityContextHolder.getContext().setAuthentication(roUser); // direct access forests allowed but not states and roads assertNotNull(sc.getLayerByName(forestsLayer.prefixedName())); assertNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // and via group access we cannot reach the nested one either LayerGroupInfo securedNamedGroup = sc.getLayerGroupByName(NAMED_GROUP_NAME); assertEquals(1, securedNamedGroup.layers().size()); assertEquals(forestsLayer.getName(), securedNamedGroup.getLayers().get(0).getName()); // nested nor accessible directly either assertNull(sc.getLayerGroupByName(OPAQUE_GROUP_NAME)); } @Test public void testNestedOpaqueDenyContainerGroup() throws Exception { setupRequestThreadLocal("WMS"); // setup groups LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, statesLayer, roadsLayer); LayerGroupInfo named = buildLayerGroup(NAMED_GROUP_NAME, Mode.NAMED, null, forestsLayer, opaque); layerGroups = Arrays.asList(named, opaque); populateCatalog(); // setup security, disallow nested group buildManager(new String[] { NAMED_GROUP_NAME + ".r=MILITARY" }); // try the ro user SecurityContextHolder.getContext().setAuthentication(roUser); // ... direct access not available for any assertNull(sc.getLayerByName(forestsLayer.prefixedName())); assertNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // ... and via group access we cannot reach the nested one either assertNull(sc.getLayerGroupByName(NAMED_GROUP_NAME)); // ... nested nor accessible directly either assertNull(sc.getLayerGroupByName(OPAQUE_GROUP_NAME)); // switch to the mil user SecurityContextHolder.getContext().setAuthentication(milUser); // ... direct access available for forests assertNotNull(sc.getLayerByName(forestsLayer.prefixedName())); assertNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // ... however as mil via group access we can see all layers LayerGroupInfo securedNamedGroup = sc.getLayerGroupByName(NAMED_GROUP_NAME); assertEquals(3, securedNamedGroup.layers().size()); LayerGroupInfo securedOpaqueGroup = sc.getLayerGroupByName(OPAQUE_GROUP_NAME); assertEquals(2, securedOpaqueGroup.layers().size()); } /** * Same as {@link #testWmsStandaloneOpaqueGroup()} but with a nested group as the testing target */ @Test public void testWmsNestedInStandaloneOpaqueGroup() throws Exception { setupRequestThreadLocal("WMS"); // setup group LayerGroupInfo nested = buildLayerGroup(NESTED_GROUP_NAME, Mode.NAMED, null, statesLayer); LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, nested, roadsLayer); layerGroups = Arrays.asList(nested, opaque); populateCatalog(); // setup security buildManager(DEFAULT_RULES); SecurityContextHolder.getContext().setAuthentication(roUser); // direct access to nested group not allowed, nor to its layers assertNull(sc.getLayerGroupByName(NESTED_GROUP_NAME)); assertNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // however we can access the group as part of the opaque one LayerGroupInfo securedGroup = sc.getLayerGroupByName(opaque.prefixedName()); assertNotNull(securedGroup); assertEquals(2, securedGroup.getLayers().size()); assertThat(securedGroup.getLayers(), contains(nested, roadsLayer)); assertThat(securedGroup.layers(), contains(statesLayer, roadsLayer)); } /** * Same as {@link #testWmsNamedOpaqueGroup()} but with a nested group as the testing target */ @Test public void testWmsNestedInNamedOpaqueGroup() throws Exception { setupRequestThreadLocal("WMS"); // setup group LayerGroupInfo nested = buildLayerGroup(NESTED_GROUP_NAME, Mode.NAMED, null, statesLayer); LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, nested, roadsLayer); LayerGroupInfo named = buildLayerGroup(NAMED_GROUP_NAME, Mode.NAMED, null, nested, roadsLayer); layerGroups = Arrays.asList(nested, named, opaque); populateCatalog(); // setup security buildManager(DEFAULT_RULES); SecurityContextHolder.getContext().setAuthentication(roUser); // direct access to layers and nested group allowed because of the named group assertNotNull(sc.getLayerGroupByName(nested.prefixedName())); assertNotNull(sc.getLayerByName(statesLayer.prefixedName())); assertNotNull(sc.getLayerByName(roadsLayer.prefixedName())); // we can access the group and the layers through it LayerGroupInfo securedOpaqueGroup = sc.getLayerGroupByName(opaque.prefixedName()); assertNotNull(securedOpaqueGroup); assertEquals(2, securedOpaqueGroup.getLayers().size()); assertThat(securedOpaqueGroup.getLayers(), contains(nested, roadsLayer)); // and same for named LayerGroupInfo securedNamedGroup = sc.getLayerGroupByName(named.prefixedName()); assertNotNull(securedNamedGroup); assertEquals(2, securedNamedGroup.getLayers().size()); assertThat(securedNamedGroup.getLayers(), contains(nested, roadsLayer)); } /** * Same as {@link #testWmsSingleAndOpaqueGroup()} but with a nested group as the testing target */ @Test public void testWmsNestedInSingleAndOpaqueGroup() throws Exception { setupRequestThreadLocal("WMS"); // setup groups LayerGroupInfo nested = buildLayerGroup(NESTED_GROUP_NAME, Mode.NAMED, null, statesLayer); LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, nested, roadsLayer); LayerGroupInfo single = buildLayerGroup(SINGLE_GROUP_NAME, Mode.SINGLE, null, nested, roadsLayer); layerGroups = Arrays.asList(nested, single, opaque); populateCatalog(); // setup security buildManager(DEFAULT_RULES); SecurityContextHolder.getContext().setAuthentication(roUser); // direct access to layers and nested group not allowed because the only container is in opaque mode assertNull(sc.getLayerGroupByName(nested.prefixedName())); assertNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // we can access the group and the layers through it LayerGroupInfo opaqueSecuredGroup = sc.getLayerGroupByName(opaque.prefixedName()); assertNotNull(opaqueSecuredGroup); assertEquals(2, opaqueSecuredGroup.getLayers().size()); assertThat(opaqueSecuredGroup.getLayers(), contains(nested, roadsLayer)); LayerGroupInfo securedSingleGroup = sc.getLayerGroupByName(single.prefixedName()); assertNotNull(securedSingleGroup); assertEquals(2, securedSingleGroup.getLayers().size()); assertThat(securedSingleGroup.getLayers(), contains(nested, roadsLayer)); } /** * Same as {@link #testWmsMilitaryNamedAndPublicOpaqueGroup()} but with a nested group as the testing target */ @Test public void testWmsNestedInMilitaryNamedAndPublicOpaqueGroup() throws Exception { setupRequestThreadLocal("WMS"); // setup groups LayerGroupInfo nested = buildLayerGroup(NESTED_GROUP_NAME, Mode.NAMED, null, statesLayer); LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, nested, roadsLayer); LayerGroupInfo named = buildLayerGroup(NAMED_GROUP_NAME, Mode.NAMED, null, nested, roadsLayer); layerGroups = Arrays.asList(nested, opaque, named); populateCatalog(); // setup security buildManager(new String[] { "named.r=MILITARY" }); // try the ro user SecurityContextHolder.getContext().setAuthentication(roUser); // ... direct access to layers not allowed because the named group is not visible assertNull(sc.getLayerGroupByName(nested.prefixedName())); assertNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerByName(roadsLayer.prefixedName())); // ... but we can access the opaque group and the layers through it LayerGroupInfo securedGroup = sc.getLayerGroupByName(OPAQUE_GROUP_NAME); assertNotNull(securedGroup); assertEquals(2, securedGroup.getLayers().size()); assertThat(securedGroup.getLayers(), contains(nested, roadsLayer)); // now try with the military one SecurityContextHolder.getContext().setAuthentication(milUser); // ... direct access to layers allowed because the named group is visible to the mil user assertNotNull(sc.getLayerGroupByName(nested.prefixedName())); assertNotNull(sc.getLayerByName(statesLayer.prefixedName())); assertNotNull(sc.getLayerByName(roadsLayer.prefixedName())); } /** * Same as {@link #testWmsPublicSingleAndSecuredOpaqueGroup} but with a nested group as the testing target * @throws Exception */ @Test public void testWmsNestedInPublicSingleAndSecuredOpaqueGroup() throws Exception { setupRequestThreadLocal("WMS"); // setup groups LayerGroupInfo nested = buildLayerGroup(NESTED_GROUP_NAME, Mode.NAMED, null, statesLayer); LayerGroupInfo opaque = buildLayerGroup(OPAQUE_GROUP_NAME, Mode.OPAQUE_CONTAINER, null, forestsLayer, nested); LayerGroupInfo single = buildLayerGroup(SINGLE_GROUP_NAME, Mode.SINGLE, null, roadsLayer, nested); layerGroups = Arrays.asList(nested, single, opaque); populateCatalog(); // setup security, single allowed to everybody, opaque to military only buildManager(SINGLE_GROUP_NAME + ".r=*", OPAQUE_GROUP_NAME + ".r=MILITARY"); SecurityContextHolder.getContext().setAuthentication(roUser); // try the ro user SecurityContextHolder.getContext().setAuthentication(roUser); // ... the only directly available layer should be roads, contained in single assertNotNull(sc.getLayerByName(roadsLayer.prefixedName())); assertNull(sc.getLayerByName(forestsLayer.prefixedName())); assertNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerGroupByName(nested.prefixedName())); // ... and even via groups it's the same assertNull(sc.getLayerGroupByName(opaque.prefixedName())); LayerGroupInfo securedSingleGroup = sc.getLayerGroupByName(single.prefixedName()); assertNotNull(securedSingleGroup); assertEquals(1, securedSingleGroup.getLayers().size()); // however switching to mil user SecurityContextHolder.getContext().setAuthentication(milUser); // ... same as above for direct access assertNotNull(sc.getLayerByName(roadsLayer.prefixedName())); assertNull(sc.getLayerByName(forestsLayer.prefixedName())); assertNull(sc.getLayerByName(statesLayer.prefixedName())); assertNull(sc.getLayerGroupByName(nested.prefixedName())); // but the opaque group is now visible along with its layers securedSingleGroup = sc.getLayerGroupByName(single.prefixedName()); assertNotNull(securedSingleGroup); assertEquals(2, securedSingleGroup.getLayers().size()); assertThat(securedSingleGroup.getLayers(), contains(roadsLayer, nested)); LayerGroupInfo nestedInSingle = (LayerGroupInfo) securedSingleGroup.getLayers().get(1); assertEquals(1, nestedInSingle.getLayers().size()); assertThat(nestedInSingle.getLayers(), contains(statesLayer)); LayerGroupInfo securedOpaqueGroup = sc.getLayerGroupByName(opaque.prefixedName()); assertNotNull(securedOpaqueGroup); assertEquals(2, securedOpaqueGroup.getLayers().size()); assertThat(securedOpaqueGroup.getLayers(), contains(forestsLayer, nested)); LayerGroupInfo nestedInOpaque = (LayerGroupInfo) securedSingleGroup.getLayers().get(1); assertEquals(1, nestedInOpaque.getLayers().size()); assertThat(nestedInOpaque.getLayers(), contains(statesLayer)); } }