/* (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; import static org.custommonkey.xmlunit.XMLAssert.assertXpathEvaluatesTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import javax.servlet.Filter; import org.custommonkey.xmlunit.SimpleNamespaceContext; import org.custommonkey.xmlunit.XMLUnit; import org.custommonkey.xmlunit.XpathEngine; import org.geoserver.config.GeoServer; import org.geoserver.data.test.CiteTestData; import org.geoserver.data.test.MockData; import org.geoserver.data.test.SystemTestData; import org.geoserver.security.config.SecurityManagerConfig; import org.geoserver.security.impl.GeoServerRole; import org.geoserver.test.GeoServerSystemTestSupport; import org.geoserver.wms.WMSInfo; import org.junit.Test; import org.w3c.dom.Document; import org.springframework.mock.web.MockHttpServletResponse; public class AuthencationKeyOWSTest extends GeoServerSystemTestSupport { private static String adminKey; private static String citeKey; @Override protected void setUpTestData(SystemTestData testData) throws Exception { super.setUpTestData(testData); // setup their data access rights // namespace.layer.permission=role[,role2,...] File security = new File(testData.getDataDirectoryRoot(), "security"); Properties props = new Properties(); File layers = new File(security, "layers.properties"); props = new Properties(); props.put("mode", "hidden"); props.put("*.*.r", "NO_ONE"); props.put("*.*.w", "NO_ONE"); props.put("sf.*.r", "*"); props.put("cite.*.r", "cite"); props.put("cite.*.w", "cite"); FileOutputStream outputFile = new FileOutputStream(layers); try { props.store(outputFile, ""); } finally { outputFile.close(); } } @Override protected void onSetUp(SystemTestData testData) throws Exception { super.onSetUp(testData); Map<String, String> namespaces = new HashMap<String, String>(); namespaces.put("wms", "http://www.opengis.net/wms"); namespaces.put("ows", "http://www.opengis.net/ows"); namespaces.put("xlink", "http://www.w3.org/1999/xlink"); namespaces.put("ogc", "http://www.opengis.net/ogc"); namespaces.put("", "http://www.opengis.net/ogc"); namespaces.put("wfs", "http://www.opengis.net/wfs"); namespaces.put("xsi", "http://www.w3.org/2001/XMLSchema-instance"); CiteTestData.registerNamespaces(namespaces); XMLUnit.setXpathNamespaceContext(new SimpleNamespaceContext(namespaces)); // setup limited srs GeoServer gs = getGeoServer(); WMSInfo wms = gs.getService(WMSInfo.class); wms.getSRS().add("EPSG:4326"); gs.save(wms); GeoServerUserGroupService service = getSecurityManager().loadUserGroupService("default"); GeoServerUserGroupStore store = service.createStore(); store.load(); store.addUser(store.createUserObject("cite","cite",true)); store.store(); GeoServerRoleService rservice = getSecurityManager().loadRoleService("default"); GeoServerRoleStore rstore = rservice.createStore(); rstore.load(); GeoServerRole no_one=rstore.createRoleObject("NO_ONE"); rstore.addRole(no_one); GeoServerRole rcite=rstore.createRoleObject("cite"); rstore.addRole(rcite); rstore.associateRoleToUser(rstore.createRoleObject("cite"), "cite"); rstore.store(); String authKeyUrlParam = "authkey"; String filterName = "testAuthKeyFilter1"; AuthenticationKeyFilterConfig config = new AuthenticationKeyFilterConfig(); config.setClassName(GeoServerAuthenticationKeyFilter.class.getName()); config.setName(filterName); config.setUserGroupServiceName("default"); config.setAuthKeyParamName(authKeyUrlParam); config.setAuthKeyMapperName("propertyMapper"); getSecurityManager().saveFilter(config); SecurityManagerConfig mconfig = getSecurityManager().getSecurityConfig(); GeoServerSecurityFilterChain filterChain = mconfig.getFilterChain(); VariableFilterChain chain = (VariableFilterChain)filterChain.getRequestChainByName("default"); chain.getFilterNames().add(0,filterName); getSecurityManager().saveSecurityConfig(mconfig); GeoServerAuthenticationKeyFilter authKeyFilter = (GeoServerAuthenticationKeyFilter) getSecurityManager().loadFilter(filterName); PropertyAuthenticationKeyMapper mapper = (PropertyAuthenticationKeyMapper) authKeyFilter.getMapper(); mapper.synchronize(); for (Entry<Object,Object> entry: mapper.authKeyProps.entrySet()) { if ("admin".equals(entry.getValue())) adminKey=(String)entry.getKey(); if ("cite".equals(entry.getValue())) citeKey=(String)entry.getKey(); } if (adminKey==null) throw new RuntimeException ("Missing admin key"); if (citeKey==null) throw new RuntimeException ("Missing cite key"); } /** * Enable the Spring Security authentication filters, we want the test to be complete and * realistic */ @Override protected List<javax.servlet.Filter> getFilters() { SecurityManagerConfig mconfig = getSecurityManager().getSecurityConfig(); GeoServerSecurityFilterChain filterChain = mconfig.getFilterChain(); VariableFilterChain chain = (VariableFilterChain)filterChain.getRequestChainByName("default"); List<Filter> result = new ArrayList<Filter>(); for (String filterName : chain.getCompiledFilterNames()) { try { result.add(getSecurityManager().loadFilter(filterName)); } catch (IOException e) { throw new RuntimeException(e); } } return result; } @Test public void testAnonymousCapabilities() throws Exception { Document doc = getAsDOM("wms?request=GetCapabilities&version=1.1.0"); //print(doc); // check we have the sf layers, but not the cite ones not the cdf ones XpathEngine engine = XMLUnit.newXpathEngine(); assertTrue(engine.getMatchingNodes("//Layer/Name[starts-with(text(), 'sf:')]", doc) .getLength() > 1); assertEquals(0, engine.getMatchingNodes("//Layer/Name[starts-with(text(), 'cite:')]", doc) .getLength()); assertEquals(0, engine.getMatchingNodes("//Layer/Name[starts-with(text(), 'cdf:')]", doc) .getLength()); } @Test public void testAdminCapabilities() throws Exception { Document doc = getAsDOM("wms?request=GetCapabilities&version=1.1.0&authkey=" + adminKey); //print(doc); // check we have all the layers XpathEngine engine = XMLUnit.newXpathEngine(); assertTrue(engine.getMatchingNodes("//Layer/Name[starts-with(text(), 'sf:')]", doc) .getLength() > 1); assertTrue(engine.getMatchingNodes("//Layer/Name[starts-with(text(), 'cdf:')]", doc) .getLength() > 1); assertTrue(engine.getMatchingNodes("//Layer/Name[starts-with(text(), 'cite:')]", doc) .getLength() > 1); // check the authentication key has been propagated String url = engine.evaluate("//GetMap/DCPType/HTTP/Get/OnlineResource/@xlink:href", doc); assertTrue(url.contains("&authkey=" + adminKey)); } @Test public void testCiteCapabilities() throws Exception { Document doc = getAsDOM("wms?request=GetCapabilities&version=1.1.0&authkey=" + citeKey); //print(doc); // check we have the sf and cite layers, but not cdf XpathEngine engine = XMLUnit.newXpathEngine(); assertTrue(engine.getMatchingNodes("//Layer/Name[starts-with(text(), 'sf:')]", doc) .getLength() > 1); assertTrue(engine.getMatchingNodes("//Layer/Name[starts-with(text(), 'cite:')]", doc) .getLength() > 1); assertEquals(0, engine.getMatchingNodes("//Layer/Name[starts-with(text(), 'cdf:')]", doc) .getLength()); // check the authentication key has been propagated String url = engine.evaluate("//GetMap/DCPType/HTTP/Get/OnlineResource/@xlink:href", doc); assertTrue(url.contains("&authkey=" + citeKey)); } @Test public void testAnonymousGetFeature() throws Exception { Document doc = getAsDOM("wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=" + getLayerId(MockData.PONDS)); assertEquals("ServiceExceptionReport", doc.getDocumentElement().getLocalName()); } @Test public void testAdminGetFeature() throws Exception { Document doc = getAsDOM("wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=" + getLayerId(MockData.PONDS) + "&authkey=" + adminKey); // print(doc); assertXpathEvaluatesTo("1", "count(//wfs:FeatureCollection)", doc); XpathEngine engine = XMLUnit.newXpathEngine(); String url = engine.evaluate("//wfs:FeatureCollection/@xsi:schemaLocation", doc); assertTrue(url.contains("&authkey=" + adminKey)); } @Test public void testCiteGetFeature() throws Exception { Document doc = getAsDOM("wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=" + getLayerId(MockData.PONDS) + "&authkey=" + citeKey); // print(doc); assertXpathEvaluatesTo("1", "count(//wfs:FeatureCollection)", doc); XpathEngine engine = XMLUnit.newXpathEngine(); String url = engine.evaluate("//wfs:FeatureCollection/@xsi:schemaLocation", doc); assertTrue(url.contains("&authkey=" + citeKey)); } @Test public void testCiteGetFeatureCaseInsensitive() throws Exception { Document doc = getAsDOM("wfs?service=WFS&version=1.0.0&request=GetFeature&typeName=" + getLayerId(MockData.PONDS) + "&AUTHKEY=" + citeKey); // print(doc); assertXpathEvaluatesTo("1", "count(//wfs:FeatureCollection)", doc); XpathEngine engine = XMLUnit.newXpathEngine(); String url = engine.evaluate("//wfs:FeatureCollection/@xsi:schemaLocation", doc); assertTrue(url.contains("&authkey=" + citeKey)); } /* * Tests that URLs in the OpenLayers Map are correctly generated (see: GEOS-7295) */ @Test public void testOpenLayersMapOutput() throws Exception { MockHttpServletResponse response = getAsServletResponse("cite/wms?service=WMS&" + "version=1.1.0&" + "request=GetMap&" + "bbox=-2.0,2.0,-1.0,6.0&" + "layers=" + MockData.BASIC_POLYGONS.getPrefix() + ":" + MockData.BASIC_POLYGONS.getLocalPart() + "&" + "width=300&" + "height=300&" + "srs=EPSG:4326&" + "format=application/openlayers" + "&authkey=" + citeKey); byte[] responseContent = getBinary(response); String htmlDoc = new String(responseContent, "UTF-8"); assertTrue(htmlDoc.indexOf("http://localhost:8080/geoserver/cite/wms?authkey=" + citeKey) > 0); } }