/* (c) 2014 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.xml;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.logging.Logger;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import org.geoserver.platform.resource.Files;
import org.geoserver.platform.resource.Resource;
import org.geoserver.platform.resource.Resource.Type;
import org.geoserver.security.GeoServerRoleStore;
import org.geoserver.security.config.FileBasedSecurityServiceConfig;
import org.geoserver.security.config.SecurityNamedServiceConfig;
import org.geoserver.security.impl.AbstractRoleService;
import org.geoserver.security.impl.GeoServerRole;
import org.geoserver.util.IOUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class XMLRoleService extends AbstractRoleService {
static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.security.xml");
protected DocumentBuilder builder;
protected Resource roleResource;
/**
* Validate against schema on load/store,
* default = true;
*/
private boolean validatingXMLSchema = true;
public XMLRoleService() throws IOException{
super();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setIgnoringComments(true);
try {
builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException e) {
throw new IOException(e);
}
}
@Override
public void initializeFromConfig(SecurityNamedServiceConfig config) throws IOException {
super.initializeFromConfig(config);
validatingXMLSchema=false;
if (config instanceof XMLSecurityServiceConfig) {
validatingXMLSchema =((XMLSecurityServiceConfig) config).isValidating();
// copy schema file
Resource xsdFile = getConfigRoot().get(XMLConstants.FILE_RR_SCHEMA);
if (xsdFile.getType() == Type.UNDEFINED) {
IOUtils.copy(getClass().getResourceAsStream(XMLConstants.FILE_RR_SCHEMA),
xsdFile.out());
}
}
if (config instanceof FileBasedSecurityServiceConfig) {
String fileName = ((FileBasedSecurityServiceConfig) config).getFileName();
File roleFile = new File(fileName);
if (roleFile.isAbsolute()) {
roleResource = Files.asResource(roleFile);
} else {
roleResource = getConfigRoot().get(fileName);
}
if (roleResource.getType() == Type.UNDEFINED) {
IOUtils.copy(getClass().getResourceAsStream("rolesTemplate.xml"), roleResource.out());
}
} else {
throw new IOException("Cannot initialize from " +config.getClass().getName());
}
// load the data
deserialize();
}
@Override
public boolean canCreateStore() {
return true;
}
@Override
public GeoServerRoleStore createStore() throws IOException {
XMLRoleStore store = new XMLRoleStore();
store.initializeFromService(this);
return store;
}
public boolean isValidatingXMLSchema() {
return validatingXMLSchema;
}
public void setValidatingXMLSchema(boolean validatingXMLSchema) {
this.validatingXMLSchema = validatingXMLSchema;
}
@Override
protected void deserialize() throws IOException {
try {
Document doc=null;
InputStream is = null;
try {
is = roleResource.in();
doc = builder.parse(is);
} catch (SAXException e) {
throw new IOException(e);
} finally {
try {
is.close();
} catch (IOException e) {}
}
if (isValidatingXMLSchema()) {
XMLValidator.Singleton.validateRoleRegistry(doc);
}
XPathExpression expr = XMLXpathFactory.Singleton.getVersionExpressionRR();
String versioNummer = expr.evaluate(doc);
RoleXMLXpath xmlXPath = XMLXpathFactory.Singleton.getRoleXMLXpath(versioNummer);
clearMaps();
NodeList roleNodes = (NodeList) xmlXPath.getRoleListExpression().evaluate(doc,XPathConstants.NODESET);
for ( int i=0 ; i <roleNodes.getLength();i++) {
Node roleNode = roleNodes.item(i);
String roleName = xmlXPath.getRoleNameExpression().evaluate(roleNode);
NodeList propertyNodes = (NodeList) xmlXPath.getRolePropertiesExpression().evaluate(roleNode,XPathConstants.NODESET);
Properties roleProps = new Properties();
for ( int j=0 ; j <propertyNodes.getLength();j++) {
Node propertyNode = propertyNodes.item(j);
String propertyName = xmlXPath.getPropertyNameExpression().evaluate(propertyNode);
String propertyValue = xmlXPath.getPropertyValueExpression().evaluate(propertyNode);
roleProps.put(propertyName, propertyValue);
}
GeoServerRole role =createRoleObject(roleName);
role.getProperties().clear(); // set properties
for (Object key: roleProps.keySet()) {
role.getProperties().put(key, roleProps.get(key));
}
helper.roleMap.put(roleName,role);
}
// second pass for hierarchy
for ( int i=0 ; i <roleNodes.getLength();i++) {
Node roleNode = roleNodes.item(i);
String roleName = xmlXPath.getRoleNameExpression().evaluate(roleNode);
String parentName = xmlXPath.getParentExpression().evaluate(roleNode);
if (parentName!=null && parentName.length()>0) {
helper.role_parentMap.put(helper.roleMap.get(roleName),helper.roleMap.get(parentName));
}
}
// user roles
NodeList userRolesNodes = (NodeList) xmlXPath.getUserRolesExpression().evaluate(doc,XPathConstants.NODESET);
for ( int i=0 ; i <userRolesNodes.getLength();i++) {
Node userRolesNode = userRolesNodes.item(i);
String userName = xmlXPath.getUserNameExpression().evaluate(userRolesNode);
SortedSet<GeoServerRole> roleSet = new TreeSet<GeoServerRole>();
helper.user_roleMap.put(userName,roleSet);
NodeList userRolesRefNodes = (NodeList) xmlXPath.getUserRolRefsExpression().evaluate(userRolesNode,XPathConstants.NODESET);
for ( int j=0 ; j <userRolesRefNodes.getLength();j++) {
Node userRolesRefNode = userRolesRefNodes.item(j);
String roleRef = xmlXPath.getUserRolRefNameExpression().evaluate(userRolesRefNode);
roleSet.add(helper.roleMap.get(roleRef));
}
}
// group roles
NodeList groupRolesNodes = (NodeList) xmlXPath.getGroupRolesExpression().evaluate(doc,XPathConstants.NODESET);
for ( int i=0 ; i <groupRolesNodes.getLength();i++) {
Node groupRolesNode = groupRolesNodes.item(i);
String groupName = xmlXPath.getGroupNameExpression().evaluate(groupRolesNode);
SortedSet<GeoServerRole> roleSet = new TreeSet<GeoServerRole>();
helper.group_roleMap.put(groupName,roleSet);
NodeList groupRolesRefNodes = (NodeList) xmlXPath.getGroupRolRefsExpression().evaluate(groupRolesNode,XPathConstants.NODESET);
for ( int j=0 ; j <groupRolesRefNodes.getLength();j++) {
Node groupRolesRefNode = groupRolesRefNodes.item(j);
String roleRef = xmlXPath.getGroupRolRefNameExpression().evaluate(groupRolesRefNode);
roleSet.add(helper.roleMap.get(roleRef));
}
}
} catch (XPathExpressionException ex) {
throw new IOException(ex);
}
}
}