/* * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xwiki.security.authorization.testwikibuilding; import java.io.File; import java.io.FileNotFoundException; import java.net.URL; import java.util.Formatter; import java.util.HashMap; import java.util.Map; import java.util.Stack; import javax.xml.XMLConstants; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import javax.xml.validation.Schema; import javax.xml.validation.SchemaFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.xpn.xwiki.XWikiContext; /** * This class is used for building a mocked test setup for testing the authorization component. * * Superclass for mocked test wikis built from xml sources. * * @since 4.2 * @version $Id: 880b66ac795af312a6aa7b56989c37594ce54e2a $ */ public abstract class AbstractTestWiki { /** The subdirectory in the classpath were the test wiki definitions will be found. */ private final static String TEST_WIKI_DEFINITIONS_DIRECTORY = "testwikis"; /** The wiki description that is currently being parsed and built. */ private HasWikiContents currentWiki; /** The space description that is currently being parsed and built. */ private HasDocuments currentSpace; /** * The object (wiki, space or document) that have access control objects that is currently being parsed and built is * at the top of this stack. */ private final Stack<HasAcl> currentRightsHolder = new Stack<HasAcl>(); /** * The object (wiki or group) that have users that is currently being parsed and built is at the top of this stack. */ private final Stack<HasUsers> currentUsersHolder = new Stack<HasUsers>(); /** * Add a wiki definition. * * @param name The name of the wiki. * @param owner The owner of the wiki. * @param isMainWiki {@code true} if the wiki should be considered the main wiki. It is an error unless exactly one * wiki in a test wiki setup is marked as the mainwiki. * @param isReadOnly Wether the wiki is in read only mode. */ protected abstract HasWikiContents addWiki(String name, String owner, boolean isMainWiki, boolean isReadOnly, String alt); /** * @return The mocked context for this test wiki setup. */ public abstract XWikiContext getXWikiContext(); /** * Interface for xml sax parsing. */ private interface ElementBuilder { /** * Indicate start of element. * @param attributes The xml attributes. */ void startElement(Attributes attributes); /** Indicate end of element. */ void endElement(); } /** * A SAX handler for building a test wiki. */ private class WikiBuilder extends DefaultHandler { /** * Abstract class for convenient inheritance. */ private abstract class AbstractElementBuilder implements ElementBuilder { @Override public void startElement(Attributes attributes) { } @Override public void endElement() { } } /** * Abstract class for building a right declaration. */ private abstract class AbstractRightElementBuilder extends AbstractElementBuilder { @Override public void startElement(Attributes attributes) { String name = attributes.getValue("name"); String type = attributes.getValue("type"); HasAcl rightsHolder = currentRightsHolder.peek(); addRight(rightsHolder, name, type); } /** * Add a right to the rights holder. * @param rightsHolder The object (wiki, space or page) that can hold rights objects. * @param name The name (user- or group name) that should be assigned the right. * @param type The type of right (view, edit, etc.) */ protected abstract void addRight(HasAcl rightsHolder, String name, String type); } /** * The map of all element builders. */ private final Map<String, ElementBuilder> elementBuilders = new HashMap<String, ElementBuilder>(); /** * Convenience class for declaring element builders. */ private class DeclareElementBuilders { /** * @param name The XML element name. * @param elementBuilder The builder instance. * @return this instance. */ public DeclareElementBuilders declare(String name, ElementBuilder elementBuilder) { elementBuilders.put(name, elementBuilder); return this; } } { new DeclareElementBuilders() .declare( "wikis", new AbstractElementBuilder() { }) .declare( "wiki", new ElementBuilder() { @Override public void startElement(Attributes attributes) { String name = attributes.getValue("name"); String owner = attributes.getValue("owner"); boolean isMainWiki = "true".equals(attributes.getValue("mainWiki")); boolean isReadOnly = "true".equals(attributes.getValue("readOnly")); String alt = attributes.getValue("alt"); HasWikiContents wiki = addWiki(name, owner, isMainWiki, isReadOnly, alt); currentWiki = wiki; currentRightsHolder.push(currentWiki); currentUsersHolder.push(currentWiki); } @Override public void endElement() { currentWiki = null; currentRightsHolder.pop(); currentUsersHolder.pop(); } }) .declare( "user", new AbstractElementBuilder() { @Override public void startElement(Attributes attributes) { String name = attributes.getValue("name"); HasUsers usersHolder = currentUsersHolder.peek(); usersHolder.addUser(name); } }) .declare( "group", new ElementBuilder() { @Override public void startElement(Attributes attributes) { String name = attributes.getValue("name"); HasUsers group = currentWiki.addGroup(name); currentUsersHolder.push(group); } @Override public void endElement() { currentUsersHolder.pop(); } }) .declare( "space", new ElementBuilder() { @Override public void startElement(Attributes attributes) { String name = attributes.getValue("name"); String alt = attributes.getValue("alt"); currentSpace = currentWiki.addSpace(name, alt); currentRightsHolder.push(currentSpace); } @Override public void endElement() { currentSpace = null; currentRightsHolder.pop(); } }) .declare( "document", new ElementBuilder() { @Override public void startElement(Attributes attributes) { String name = attributes.getValue("name"); String creator = attributes.getValue("creator"); String alt = attributes.getValue("alt"); if (creator == null) { creator = "XWiki.Admin"; } HasAcl document = currentSpace.addDocument(name, creator, alt); currentRightsHolder.push(document); } @Override public void endElement() { currentRightsHolder.pop(); } }) .declare( "allowUser", new AbstractRightElementBuilder() { @Override public void addRight(HasAcl rightsHolder, String name, String type) { rightsHolder.addAllowUser(name, type); } }) .declare( "denyUser", new AbstractRightElementBuilder() { @Override public void addRight(HasAcl rightsHolder, String name, String type) { rightsHolder.addDenyUser(name, type); } }) .declare( "allowGroup", new AbstractRightElementBuilder() { @Override public void addRight(HasAcl rightsHolder, String name, String type) { rightsHolder.addAllowGroup(name, type); } }) .declare( "denyGroup", new AbstractRightElementBuilder() { @Override public void addRight(HasAcl rightsHolder, String name, String type) { rightsHolder.addDenyGroup(name, type); } }); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { getElementBuilder(qName).startElement(attributes); } @Override public void endElement(String uri, String localName, String qName) throws SAXException { getElementBuilder(qName).endElement(); } /** * @param qName The XML element name. * @return The element builder for the element name. * @throws SAXException if no element builder can be found for the element name. */ private ElementBuilder getElementBuilder(String qName) throws SAXException { ElementBuilder elementBuilder = elementBuilders.get(qName); if (elementBuilder == null) { throw new SAXException(new Formatter().format("Invalid element name: '%s'", qName).toString()); } return elementBuilder; } } /** * Load a test wiki from an xml-file located in the appropriate subdirectory in the classpath ({@link * TEST_WIKI_DEFINITIONS_DIRECTORY}). * * @param name The file name relative the test wiki subdirectory. */ protected void loadTestWiki(String name) throws Exception { URL testwikiUrl = ClassLoader.getSystemResource(TEST_WIKI_DEFINITIONS_DIRECTORY + File.separatorChar + name); if (testwikiUrl == null) { throw new FileNotFoundException(name); } URL schemaUrl = ClassLoader.getSystemResource("schemas" + File.separatorChar + "wikitest.xsd"); Schema schema = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(schemaUrl); SAXParserFactory parserFactory = SAXParserFactory.newInstance(); parserFactory.setSchema(schema); SAXParser parser = parserFactory.newSAXParser(); String filename = testwikiUrl.toURI().toString(); parser.parse(filename, new WikiBuilder()); } }