/* (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 static org.geoserver.security.xml.XMLConstants.A_GROUPNAME_RR; import static org.geoserver.security.xml.XMLConstants.A_PARENTID_RR; import static org.geoserver.security.xml.XMLConstants.A_PROPERTY_NAME_RR; import static org.geoserver.security.xml.XMLConstants.A_ROLEID_RR; import static org.geoserver.security.xml.XMLConstants.A_ROLEREFID_RR; import static org.geoserver.security.xml.XMLConstants.A_USERNAME_RR; import static org.geoserver.security.xml.XMLConstants.A_VERSION_RR; import static org.geoserver.security.xml.XMLConstants.E_GROUPLIST_RR; import static org.geoserver.security.xml.XMLConstants.E_GROUPROLES_RR; import static org.geoserver.security.xml.XMLConstants.E_PROPERTY_RR; import static org.geoserver.security.xml.XMLConstants.E_ROLELIST_RR; import static org.geoserver.security.xml.XMLConstants.E_ROLEREF_RR; import static org.geoserver.security.xml.XMLConstants.E_ROLEREGISTRY_RR; import static org.geoserver.security.xml.XMLConstants.E_ROLE_RR; import static org.geoserver.security.xml.XMLConstants.E_USERLIST_RR; import static org.geoserver.security.xml.XMLConstants.E_USERROLES_RR; import static org.geoserver.security.xml.XMLConstants.NS_RR; import static org.geoserver.security.xml.XMLConstants.VERSION_RR_1_0; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.SortedSet; import java.util.logging.Logger; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.commons.io.IOUtils; import org.geoserver.platform.resource.Resource; import org.geoserver.security.GeoServerRoleService; import org.geoserver.security.file.LockFile; import org.geoserver.security.impl.AbstractRoleStore; import org.geoserver.security.impl.GeoServerRole; import org.w3c.dom.Document; import org.w3c.dom.Element; public class XMLRoleStore extends AbstractRoleStore { static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.security.xml"); protected Resource roleResource; //TODO: use resource locking system protected LockFile lockFile = null; /** * Validate against schema on load/store, * default = true; */ private boolean validatingXMLSchema = true; public boolean isValidatingXMLSchema() { return validatingXMLSchema; } public void setValidatingXMLSchema(boolean validatingXMLSchema) { this.validatingXMLSchema = validatingXMLSchema; } /* (non-Javadoc) * @see org.geoserver.security.impl.AbstractRoleStore#initializeFromService(org.geoserver.security.GeoserverRoleService) */ public void initializeFromService(GeoServerRoleService service) throws IOException { this.roleResource=((XMLRoleService)service).roleResource; this.validatingXMLSchema=((XMLRoleService)service).isValidatingXMLSchema(); super.initializeFromService(service); } @Override protected void serialize() throws IOException { DocumentBuilder builder=null; try { builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); } catch (ParserConfigurationException e1) { throw new IOException(e1); } Document doc =builder.newDocument(); Element rolereg = doc.createElement(E_ROLEREGISTRY_RR); doc.appendChild(rolereg); rolereg.setAttribute(javax.xml.XMLConstants.XMLNS_ATTRIBUTE, NS_RR); rolereg.setAttribute(A_VERSION_RR, VERSION_RR_1_0); Element rolelist = doc.createElement(E_ROLELIST_RR); rolereg.appendChild(rolelist); for (GeoServerRole roleObject : helper.roleMap.values()) { Element role = doc.createElement(E_ROLE_RR); rolelist.appendChild(role); role.setAttribute(A_ROLEID_RR, roleObject.getAuthority()); GeoServerRole parentObject = helper.role_parentMap.get(roleObject); if (parentObject!=null) { role.setAttribute(A_PARENTID_RR, parentObject.getAuthority()); } for (Object key: roleObject.getProperties().keySet()) { Element property = doc.createElement(E_PROPERTY_RR); role.appendChild(property); property.setAttribute(A_PROPERTY_NAME_RR, key.toString()); property.setTextContent(roleObject.getProperties().getProperty(key.toString())); } } Element userList = doc.createElement(E_USERLIST_RR); rolereg.appendChild(userList); for (String userName: helper.user_roleMap.keySet()) { Element userroles = doc.createElement(E_USERROLES_RR); userList.appendChild(userroles); userroles.setAttribute(A_USERNAME_RR, userName); SortedSet<GeoServerRole> roleObjects = helper.user_roleMap.get(userName); for (GeoServerRole roleObject: roleObjects) { Element ref = doc.createElement(E_ROLEREF_RR); userroles.appendChild(ref); ref.setAttribute(A_ROLEREFID_RR,roleObject.getAuthority()); } } Element groupList = doc.createElement(E_GROUPLIST_RR); rolereg.appendChild(groupList); for (String groupName: helper.group_roleMap.keySet()) { Element grouproles = doc.createElement(E_GROUPROLES_RR); groupList.appendChild(grouproles); grouproles.setAttribute(A_GROUPNAME_RR, groupName); SortedSet<GeoServerRole> roleObjects = helper.group_roleMap.get(groupName); for (GeoServerRole roleObject: roleObjects) { Element ref = doc.createElement(E_ROLEREF_RR); grouproles.appendChild(ref); ref.setAttribute(A_ROLEREFID_RR,roleObject.getAuthority()); } } // serialize the dom try { // TODO, wait for JAVA 6 // if (isValidatingXMLSchema()) { // XMLValidator.Singleton.validateRoleRegistry(doc); // } Transformer tx = TransformerFactory.newInstance().newTransformer(); tx.setOutputProperty(OutputKeys.METHOD, "XML"); tx.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); tx.setOutputProperty(OutputKeys.INDENT, "yes"); OutputStream out = new BufferedOutputStream(roleResource.out()); try { tx.transform(new DOMSource(doc), new StreamResult(out)); out.flush(); } finally { IOUtils.closeQuietly(out); } /* standard java, but there is no possibility to set * the number of chars to indent, each line is starting at * column 0 Source source = new DOMSource(doc); // Prepare the output file Result result = new StreamResult( new OutputStreamWriter(new FileOutputStream(roleFile),"UTF-8")); TransformerFactory fac = TransformerFactory.newInstance(); Transformer xformer = fac.newTransformer(); xformer.setOutputProperty(OutputKeys.INDENT, "yes"); xformer.transform(source, result); */ } catch (Exception e) { throw new IOException(e); } } @Override protected void deserialize() throws IOException { super.deserialize(); releaseLock(); } @Override public String toString() { return getName(); } protected void ensureLock() throws IOException { if (lockFile != null) return; // we have one lockFile = new LockFile(roleResource); try { lockFile.writeLock(); } catch (IOException ex) { // cannot obtain lock lockFile = null; // assert lockFile == null throw ex; // throw again } } protected void releaseLock() { if (lockFile == null) return; // we have none lockFile.writeUnLock(); lockFile = null; } @Override public void addRole(GeoServerRole role) throws IOException { ensureLock(); super.addRole(role); } @Override public void updateRole(GeoServerRole role) throws IOException { ensureLock(); super.updateRole(role); } @Override public boolean removeRole(GeoServerRole role) throws IOException { ensureLock(); return super.removeRole(role); } @Override public void store() throws IOException { ensureLock(); super.store(); releaseLock(); } @Override public void disAssociateRoleFromGroup(GeoServerRole role, String groupname) throws IOException { ensureLock(); super.disAssociateRoleFromGroup(role, groupname); } @Override public void associateRoleToGroup(GeoServerRole role, String groupname) throws IOException { ensureLock(); super.associateRoleToGroup(role, groupname); } @Override public void associateRoleToUser(GeoServerRole role, String username) throws IOException { ensureLock(); super.associateRoleToUser(role, username); } @Override public void disAssociateRoleFromUser(GeoServerRole role, String username) throws IOException { ensureLock(); super.disAssociateRoleFromUser(role, username); } @Override public void setParentRole(GeoServerRole role, GeoServerRole parentRole) throws IOException { ensureLock(); super.setParentRole(role, parentRole); } @Override public void clear() throws IOException { ensureLock(); super.clear(); } }