package org.geoserver.wcs; import static org.geoserver.data.test.MockData.*; import java.io.File; import java.io.FileOutputStream; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Properties; import org.geoserver.catalog.Catalog; import org.geoserver.catalog.CoverageInfo; import org.geoserver.data.test.MockData; import org.geoserver.platform.GeoServerExtensions; import org.geoserver.security.CatalogMode; import org.geoserver.security.CoverageAccessLimits; import org.geoserver.security.ResourceAccessManager; import org.geoserver.security.TestResourceAccessManager; import org.geoserver.util.SecurityUtils; import org.geotools.coverage.grid.GridCoverage2D; import org.geotools.geometry.DirectPosition2D; import org.geotools.referencing.CRS; import org.opengis.coverage.grid.GridCoverage; import org.opengis.filter.Filter; import org.opengis.geometry.DirectPosition; import org.opengis.referencing.crs.CoordinateReferenceSystem; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.GrantedAuthorityImpl; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.vfny.geoserver.wcs.WcsException; import com.vividsolutions.jts.geom.MultiPolygon; import com.vividsolutions.jts.io.WKTReader; /** * Performs integration tests using a mock {@link ResourceAccessManager} * * @author Andrea Aime - GeoSolutions * */ public class ResourceAccessManagerWCSTest extends AbstractGetCoverageTest { /** * Add the test resource access manager in the spring context */ protected String[] getSpringContextLocations() { String[] base = super.getSpringContextLocations(); String[] extended = new String[base.length + 1]; System.arraycopy(base, 0, extended, 0, base.length); extended[base.length] = "classpath:/org/geoserver/wcs/ResourceAccessManagerContext.xml"; return extended; } /** * Enable the Spring Security auth filters */ @Override protected List<javax.servlet.Filter> getFilters() { return Collections.singletonList((javax.servlet.Filter) GeoServerExtensions .bean("filterChainProxy")); } /** * Add the users */ @Override protected void populateDataDirectory(MockData dataDirectory) throws Exception { super.populateDataDirectory(dataDirectory); File security = new File(dataDirectory.getDataDirectoryRoot(), "security"); security.mkdir(); File users = new File(security, "users.properties"); Properties props = new Properties(); props.put("admin", "geoserver,ROLE_ADMINISTRATOR"); props.put("cite", "cite,ROLE_DUMMY"); props.put("cite_noworld", "cite,ROLE_DUMMY"); props.put("cite_noworld_challenge", "cite,ROLE_DUMMY"); props.put("cite_usa", "cite,ROLE_DUMMY"); props.store(new FileOutputStream(users), ""); } @Override protected void setUpInternal() throws Exception { super.setUpInternal(); // populate the access manager TestResourceAccessManager tam = (TestResourceAccessManager) applicationContext .getBean("testResourceAccessManager"); Catalog catalog = getCatalog(); CoverageInfo world = catalog.getCoverageByName(getLayerId(MockData.WORLD)); // limits for mr cite_noworld: can't access the world layer tam.putLimits("cite_noworld", world, new CoverageAccessLimits(CatalogMode.HIDE, Filter.EXCLUDE, null, null)); // limits for mr cite_noworld: can't access the world layer tam.putLimits("cite_noworld_challenge", world, new CoverageAccessLimits( CatalogMode.CHALLENGE, Filter.EXCLUDE, null, null)); // limits the area to north america MultiPolygon rasterFilter = (MultiPolygon) new WKTReader().read("MULTIPOLYGON(((-120 30, -120 60, -60 60, -60 30, -120 30)))"); tam.putLimits("cite_usa", world, new CoverageAccessLimits(CatalogMode.HIDE, null, rasterFilter, null)); } Map<String, Object> getWorld() { Map<String, Object> raw = baseMap(); final String getLayerId = getLayerId(WORLD); raw.put("identifier", getLayerId); raw.put("format", "image/tiff"); raw.put("BoundingBox", "-90,-180,90,180,urn:ogc:def:crs:EPSG:6.6:4326"); raw.put("store", "false"); raw.put("GridBaseCRS", "urn:ogc:def:crs:EPSG:6.6:4326"); return raw; } public void testNoLimits() throws Exception { Map<String, Object> raw = getWorld(); authenticate("cite", "cite"); GridCoverage[] coverages = executeGetCoverageKvp(raw); // basic checks assertEquals(1, coverages.length); GridCoverage2D coverage = (GridCoverage2D) coverages[0]; final CoordinateReferenceSystem wgs84Flipped = CRS.decode("urn:ogc:def:crs:EPSG:6.6:4326"); assertEquals(wgs84Flipped, coverage.getEnvelope().getCoordinateReferenceSystem()); assertEquals(-90.0, coverage.getEnvelope().getMinimum(0)); assertEquals(-180.0, coverage.getEnvelope().getMinimum(1)); assertEquals(90.0, coverage.getEnvelope().getMaximum(0)); assertEquals(180.0, coverage.getEnvelope().getMaximum(1)); // make sure it has not been cropped int[] value = new int[3]; // some point in USA coverage.evaluate((DirectPosition) new DirectPosition2D(wgs84Flipped, 40, -90), value); assertTrue(value[0] > 0); assertTrue(value[1] > 0); assertTrue(value[2] > 0); // some point in Europe coverage.evaluate((DirectPosition) new DirectPosition2D(wgs84Flipped, 45, 12), value); assertTrue(value[0] > 0); assertTrue(value[1] > 0); assertTrue(value[2] > 0); } public void testNoAccess() throws Exception { Map<String, Object> raw = getWorld(); authenticate("cite_noworld", "cite"); try { executeGetCoverageKvp(raw); fail("This should have failed with an exception"); } catch (WcsException e) { // we should have got some complaint about the layer not being there assertTrue(e.getMessage().matches(".*wcs:World.*")); } } public void testChallenge() throws Exception { Map<String, Object> raw = getWorld(); authenticate("cite_noworld_challenge", "cite"); try { executeGetCoverageKvp(raw); fail("This should have failed with a security exception"); } catch (Throwable e) { // make sure we are dealing with some security exception Throwable se = null; while(e.getCause() != null && e.getCause() != e) { e = e.getCause(); if (SecurityUtils.isSecurityException(e)) { se = e; } } if(e == null) { fail("We should have got some sort of SpringSecurityException"); } else { // some mumbling about not having enough privileges assertTrue(se.getMessage().contains("World")); assertTrue(se.getMessage().contains("privileges")); } } } public void testRasterFilterUSA() throws Exception { Map<String, Object> raw = getWorld(); authenticate("cite_usa", "cite"); GridCoverage[] coverages = executeGetCoverageKvp(raw); // basic checks assertEquals(1, coverages.length); GridCoverage2D coverage = (GridCoverage2D) coverages[0]; final CoordinateReferenceSystem wgs84Flipped = CRS.decode("urn:ogc:def:crs:EPSG:6.6:4326"); assertEquals(wgs84Flipped, coverage.getEnvelope().getCoordinateReferenceSystem()); assertEquals(-90.0, coverage.getEnvelope().getMinimum(0)); assertEquals(-180.0, coverage.getEnvelope().getMinimum(1)); assertEquals(90.0, coverage.getEnvelope().getMaximum(0)); assertEquals(180.0, coverage.getEnvelope().getMaximum(1)); // make sure it has been cropped int[] value = new int[3]; // some point in USA coverage.evaluate((DirectPosition) new DirectPosition2D(wgs84Flipped, 40, -90), value); assertTrue(value[0] > 0); assertTrue(value[1] > 0); assertTrue(value[2] > 0); // some point in Europe (should have been cropped, we should get the bkg value) coverage.evaluate((DirectPosition) new DirectPosition2D(wgs84Flipped, 45, 12), value); assertEquals(0, value[0]); assertEquals(0, value[1]); assertEquals(0, value[2]); } @Override protected void authenticate(String username, String password) { // override as this is not a test going through the servlet filters GrantedAuthority ga = new GrantedAuthorityImpl("MOCKROLE"); UsernamePasswordAuthenticationToken user = new UsernamePasswordAuthenticationToken( username, null, new GrantedAuthority[] { ga }); SecurityContextHolder.getContext().setAuthentication(user); } }