Index: ChangeLog =================================================================== --- ChangeLog (revision 1659548) +++ ChangeLog (working copy) @@ -1,5 +1,11 @@ -2015-02-12 David Vittor () +2015-02-16 David Vittor (dvittor@apache.org) + * 2.10.2-svn-14 + + * Fixed JSPWIKI-877 - Centralised ClassUtil.getResource() + +2015-02-12 David Vittor (dvittor@apache.org) + * 2.10.2-svn-13 * Fixed JSPWIKI-867 - Deleting attachments should retain focus on the Attach tab @@ -8,7 +14,7 @@ * Fixed search icon in Smart Template "search.gif" instead of "search.png" -2015-01-30 David Vittor (dvittor@apache.org) +2015-01-30 David Vittor (dvittor@apache.org) * 2.10.2-svn-12 Index: jspwiki-war/src/main/java/org/apache/wiki/api/engine/FilterManager.java =================================================================== --- jspwiki-war/src/main/java/org/apache/wiki/api/engine/FilterManager.java (revision 1659579) +++ jspwiki-war/src/main/java/org/apache/wiki/api/engine/FilterManager.java (working copy) @@ -32,7 +32,7 @@ String PROP_FILTERXML = "jspwiki.filterConfig"; /** Default location for the filter XML property file. Value is {@value}. */ - String DEFAULT_XMLFILE = "/WEB-INF/filters.xml"; + String DEFAULT_XMLFILE = "filters.xml"; /** JSPWiki system filters are all below this value. */ int SYSTEM_FILTER_PRIORITY = -1000; Index: jspwiki-war/src/main/java/org/apache/wiki/auth/AuthenticationManager.java =================================================================== --- jspwiki-war/src/main/java/org/apache/wiki/auth/AuthenticationManager.java (revision 1659579) +++ jspwiki-war/src/main/java/org/apache/wiki/auth/AuthenticationManager.java (working copy) @@ -18,14 +18,6 @@ */ package org.apache.wiki.auth; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.MalformedURLException; -import java.net.URL; import java.security.Principal; import java.util.Collections; import java.util.HashMap; @@ -41,7 +33,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; -import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.apache.wiki.WikiEngine; import org.apache.wiki.WikiSession; @@ -599,84 +590,6 @@ } /** - * Looks up and obtains a configuration file inside the WEB-INF folder of a - * wiki webapp. - * @param engine the wiki engine - * @param name the file to obtain, e.g., jspwiki.policy - * @return the URL to the file - */ - protected static URL findConfigFile( WikiEngine engine, String name ) - { - log.info( "looking for " + name + " inside WEB-INF " ); - // Try creating an absolute path first - File defaultFile = null; - if( engine.getRootPath() != null ) - { - defaultFile = new File( engine.getRootPath() + "/WEB-INF/" + name ); - } - if ( defaultFile != null && defaultFile.exists() ) - { - try - { - return defaultFile.toURI().toURL(); - } - catch ( MalformedURLException e) - { - // Shouldn't happen, but log it if it does - log.warn( "Malformed URL: " + e.getMessage() ); - } - - } - - // Ok, the absolute path didn't work; try other methods - - URL path = null; - - if( engine.getServletContext() != null ) - { - OutputStream os = null; - InputStream is = null; - try - { - log.info( "looking for /" + name + " on classpath" ); - // create a tmp file of the policy loaded as an InputStream and return the URL to it - // - is = AuthenticationManager.class.getResourceAsStream( "/" + name ); - if( is == null ) { - throw new FileNotFoundException( name + " not found" ); - } - File tmpFile = File.createTempFile( "temp." + name, "" ); - tmpFile.deleteOnExit(); - - os = new FileOutputStream(tmpFile); - - byte[] buff = new byte[1024]; - int bytes = 0; - while ((bytes = is.read(buff)) != -1) { - os.write(buff, 0, bytes); - } - - path = tmpFile.toURI().toURL(); - } - catch( MalformedURLException e ) - { - // This should never happen unless I screw up - log.fatal( "Your code is b0rked. You are a bad person.", e ); - } - catch (IOException e) - { - log.error( "failed to load security policy from file " + name + ",stacktrace follows", e ); - } - finally - { - IOUtils.closeQuietly( is ); - IOUtils.closeQuietly( os ); - } - } - return path; - } - - /** * Returns the first Principal in a set that isn't a {@link org.apache.wiki.auth.authorize.Role} or * {@link org.apache.wiki.auth.GroupPrincipal}. * @param principals the principal set Index: jspwiki-war/src/main/java/org/apache/wiki/auth/AuthorizationManager.java =================================================================== --- jspwiki-war/src/main/java/org/apache/wiki/auth/AuthorizationManager.java (revision 1659579) +++ jspwiki-war/src/main/java/org/apache/wiki/auth/AuthorizationManager.java (working copy) @@ -21,7 +21,6 @@ import java.io.File; import java.io.IOException; -import java.net.URL; import java.security.AccessControlException; import java.security.AccessController; import java.security.CodeSource; @@ -62,7 +61,6 @@ import org.apache.wiki.tags.WikiTagBase; import org.apache.wiki.util.ClassUtil; import org.freshcookies.security.policy.LocalPolicy; -import org.freshcookies.security.policy.PolicyException; /** *

Manages all access control and authorization; determines what authenticated @@ -472,13 +470,16 @@ // Initialize local security policy try { - String policyFileName = properties.getProperty( POLICY, DEFAULT_POLICY ); - URL policyURL = AuthenticationManager.findConfigFile( engine, policyFileName ); - - if (policyURL != null) + File policyFile = null; + String resourceName = properties.getProperty( POLICY, DEFAULT_POLICY ); + try { + policyFile = ClassUtil.getResourceAsFile(engine, resourceName, false); + } catch(IOException e) { + log.error(e,e); // This should not happen, it's not required. Null value will be handled below + } + if (policyFile != null) { - File policyFile = new File( policyURL.toURI().getPath() ); - log.info("We found security policy URL: " + policyURL + " and transformed it to file " + policyFile.getAbsolutePath()); + log.info("We found security policy URL: " + resourceName + " and transformed it to file " + policyFile.getAbsolutePath()); m_localPolicy = new LocalPolicy( policyFile, engine.getContentEncoding() ); m_localPolicy.refresh(); log.info( "Initialized default security policy: " + policyFile.getAbsolutePath() ); @@ -486,8 +487,8 @@ else { StringBuffer sb = new StringBuffer( "JSPWiki was unable to initialize the " ); - sb.append( "default security policy (WEB-INF/jspwiki.policy) file. " ); - sb.append( "Please ensure that the jspwiki.policy file exists in the default location. " ); + sb.append( "security policy " + resourceName + " file. " ); + sb.append( "Please ensure that the jspwiki.policy file exists in the correct location. " ); sb.append( "This file should exist regardless of the existance of a global policy file. " ); sb.append( "The global policy file is identified by the java.security.policy variable. " ); WikiSecurityException wse = new WikiSecurityException( sb.toString() ); Index: jspwiki-war/src/main/java/org/apache/wiki/auth/authorize/XMLGroupDatabase.java =================================================================== --- jspwiki-war/src/main/java/org/apache/wiki/auth/authorize/XMLGroupDatabase.java (revision 1659579) +++ jspwiki-war/src/main/java/org/apache/wiki/auth/authorize/XMLGroupDatabase.java (working copy) @@ -39,15 +39,16 @@ import org.apache.commons.lang.StringEscapeUtils; import org.apache.log4j.Logger; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import org.xml.sax.SAXException; import org.apache.wiki.WikiEngine; import org.apache.wiki.api.exceptions.NoRequiredPropertyException; import org.apache.wiki.auth.NoSuchPrincipalException; import org.apache.wiki.auth.WikiPrincipal; import org.apache.wiki.auth.WikiSecurityException; +import org.apache.wiki.util.ClassUtil; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; /** *

@@ -179,30 +180,13 @@ public void initialize( WikiEngine engine, Properties props ) throws NoRequiredPropertyException, WikiSecurityException { m_engine = engine; - - File defaultFile = null; - if ( engine.getRootPath() == null ) - { - log.warn( "Cannot identify JSPWiki root path" ); - defaultFile = new File( "WEB-INF/" + DEFAULT_DATABASE ).getAbsoluteFile(); + try { + String resourceName = props.getProperty( PROP_DATABASE, DEFAULT_DATABASE ); + m_file = ClassUtil.getResourceAsFile(engine, resourceName, true); + } catch(IOException e) { + throw new NoRequiredPropertyException(e.getMessage(), PROP_DATABASE); } - else - { - defaultFile = new File( engine.getRootPath() + "/WEB-INF/" + DEFAULT_DATABASE ); - } - // Get database file location - String file = props.getProperty( PROP_DATABASE ); - if ( file == null ) - { - log.warn( "XML group database property " + PROP_DATABASE + " not found; trying " + defaultFile ); - m_file = defaultFile; - } - else - { - m_file = new File( file ); - } - log.info( "XML group database at " + m_file.getAbsolutePath() ); // Read DOM Index: jspwiki-war/src/main/java/org/apache/wiki/auth/SecurityVerifier.java =================================================================== --- jspwiki-war/src/main/java/org/apache/wiki/auth/SecurityVerifier.java (revision 1659579) +++ jspwiki-war/src/main/java/org/apache/wiki/auth/SecurityVerifier.java (working copy) @@ -53,6 +53,7 @@ import org.apache.wiki.auth.permissions.WikiPermission; import org.apache.wiki.auth.user.UserDatabase; import org.apache.wiki.auth.user.UserProfile; +import org.apache.wiki.util.ClassUtil; import org.freshcookies.security.policy.PolicyReader; import org.jdom2.JDOMException; @@ -707,18 +708,13 @@ @SuppressWarnings("unchecked") protected void verifyPolicy() { - // Look up the policy file and set the status text. - URL policyURL = AuthenticationManager.findConfigFile( m_engine, AuthorizationManager.DEFAULT_POLICY ); - String path = policyURL.getPath(); - if ( path.startsWith("file:") ) - { - path = path.substring( 5 ); - } - File policyFile = new File( path ); - - // Next, verify the policy + // Get the policyFileName from the properties + String policyFileName = m_engine.getWikiProperties().getProperty( AuthorizationManager.POLICY, AuthorizationManager.DEFAULT_POLICY ); try { + // Look up the policy file + File policyFile = ClassUtil.getResourceAsFile(m_engine, policyFileName, true); + // Get the file PolicyReader policy = new PolicyReader( policyFile ); m_session.addMessage( INFO_POLICY, "The security policy '" + policy.getFile() + "' exists." ); Index: jspwiki-war/src/main/java/org/apache/wiki/auth/user/XMLUserDatabase.java =================================================================== --- jspwiki-war/src/main/java/org/apache/wiki/auth/user/XMLUserDatabase.java (revision 1659579) +++ jspwiki-war/src/main/java/org/apache/wiki/auth/user/XMLUserDatabase.java (working copy) @@ -44,6 +44,7 @@ import org.apache.wiki.auth.NoSuchPrincipalException; import org.apache.wiki.auth.WikiPrincipal; import org.apache.wiki.auth.WikiSecurityException; +import org.apache.wiki.util.ClassUtil; import org.apache.wiki.util.Serializer; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -270,29 +271,12 @@ */ public void initialize( WikiEngine engine, Properties props ) throws NoRequiredPropertyException { - File defaultFile = null; - if( engine.getRootPath() == null ) - { - log.warn( "Cannot identify JSPWiki root path" ); - defaultFile = new File( "WEB-INF/" + DEFAULT_USERDATABASE ).getAbsoluteFile(); + try { + String resourceName = props.getProperty( PROP_USERDATABASE, DEFAULT_USERDATABASE ); + c_file = ClassUtil.getResourceAsFile(engine, resourceName, true); + } catch(IOException e) { + throw new NoRequiredPropertyException(e.getMessage(), PROP_USERDATABASE); } - else - { - defaultFile = new File( engine.getRootPath() + "/WEB-INF/" + DEFAULT_USERDATABASE ); - } - - // Get database file location - String file = props.getProperty( PROP_USERDATABASE ); - if( file == null ) - { - log.warn( "XML user database property " + PROP_USERDATABASE + " not found; trying " + defaultFile ); - c_file = defaultFile; - } - else - { - c_file = new File( file ); - } - log.info("XML user database at "+c_file.getAbsolutePath()); buildDOM(); Index: jspwiki-war/src/main/java/org/apache/wiki/filters/DefaultFilterManager.java =================================================================== --- jspwiki-war/src/main/java/org/apache/wiki/filters/DefaultFilterManager.java (revision 1659579) +++ jspwiki-war/src/main/java/org/apache/wiki/filters/DefaultFilterManager.java (working copy) @@ -18,8 +18,6 @@ */ package org.apache.wiki.filters; -import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -193,43 +191,11 @@ */ protected void initialize( Properties props ) throws WikiException { InputStream xmlStream = null; - String xmlFile = props.getProperty( PROP_FILTERXML ); - try { registerFilters(); - if( m_engine.getServletContext() != null ) { - log.debug( "Attempting to locate " + DEFAULT_XMLFILE + " from servlet context." ); - if( xmlFile == null ) { - xmlStream = m_engine.getServletContext().getResourceAsStream( DEFAULT_XMLFILE ); - } else { - xmlStream = m_engine.getServletContext().getResourceAsStream( xmlFile ); - } - } - - if( xmlStream == null ) { - // just a fallback element to the old behaviour prior to 2.5.8 - log.debug( "Attempting to locate filters.xml from class path." ); - - if( xmlFile == null ) { - xmlStream = getClass().getResourceAsStream( "/filters.xml" ); - } else { - xmlStream = getClass().getResourceAsStream( xmlFile ); - } - } - - if( (xmlStream == null) && (xmlFile != null) ) { - log.debug("Attempting to load property file "+xmlFile); - xmlStream = new FileInputStream( new File(xmlFile) ); - } - - if( xmlStream == null ) { - log.info( "Cannot find property file for filters (this is okay, expected to find it as: '" + - ( xmlFile == null ? DEFAULT_XMLFILE : xmlFile ) + - "')" ); - return; - } - + String resourceName = props.getProperty( PROP_FILTERXML, DEFAULT_XMLFILE ); + xmlStream = ClassUtil.getResourceAsStream(m_engine, resourceName, false); parseConfigFile( xmlStream ); } catch( IOException e ) { log.error("Unable to read property file", e); Index: jspwiki-war/src/main/java/org/apache/wiki/Release.java =================================================================== --- jspwiki-war/src/main/java/org/apache/wiki/Release.java (revision 1659579) +++ jspwiki-war/src/main/java/org/apache/wiki/Release.java (working copy) @@ -72,7 +72,7 @@ *

* If the build identifier is empty, it is not added. */ - public static final String BUILD = "13"; + public static final String BUILD = "14"; /** * This is the generic version string you should use when printing out the version. It is of Index: jspwiki-war/src/main/java/org/apache/wiki/util/ClassUtil.java =================================================================== --- jspwiki-war/src/main/java/org/apache/wiki/util/ClassUtil.java (revision 1659579) +++ jspwiki-war/src/main/java/org/apache/wiki/util/ClassUtil.java (working copy) @@ -19,7 +19,9 @@ package org.apache.wiki.util; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.net.JarURLConnection; @@ -35,9 +37,12 @@ import java.util.jar.JarEntry; import java.util.jar.JarFile; +import javax.servlet.ServletContext; + import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; +import org.apache.wiki.WikiEngine; import org.apache.wiki.api.engine.PluginManager; import org.apache.wiki.api.exceptions.WikiException; import org.jdom2.Element; @@ -427,4 +432,134 @@ throw new WikiException("Failed to instantiate class "+requestedClass, e ); } } + + /** + * Get a resourceName from the given engine, returning a file. + * See {@link ClassUtil.getResource} + */ + public static File getResourceAsFile(WikiEngine engine, String resourceName, boolean required) throws IOException { + return getResourceAsFile(engine.getServletContext(), resourceName, required); + } + /** + * Get a resourceName from the given engine, returning an InputStream. + * See {@link ClassUtil.getResource} + */ + public static InputStream getResourceAsStream(WikiEngine engine, String resourceName, boolean required) throws IOException { + return getResourceAsStream(engine.getServletContext(), resourceName, required); + } + /** + * Get a resourceName from the given engine, returning a URL. + * See {@link ClassUtil.getResource} + */ + public static URL getResource(WikiEngine engine, String resourceName, boolean required) throws IOException { + return getResource(engine.getServletContext(), resourceName, required); + } + + /** + * Get a resourceName from the given ServletContext, returning a file. + * See {@link ClassUtil.getResource} + */ + public static File getResourceAsFile(ServletContext context, String resourceName, boolean required) throws IOException { + URL resourceUrl = getResource(context, resourceName, required); + if (resourceUrl != null) { + return new File(resourceUrl.getFile()); + } + return null; + } + + /** + * Get a resourceName from the given ServletContext, returning an InputStream. + * See {@link ClassUtil.getResource} + */ + public static InputStream getResourceAsStream(ServletContext context, String resourceName, boolean required) throws IOException { + URL resourceUrl = getResource(context, resourceName, required); + if (resourceUrl != null) { + return new FileInputStream(resourceUrl.getFile()); + } + return null; + } + + /** + * Get a resourceName from the given ServletContext, returning a URL. + * The sequence of searching is: + *

+ * @param context The servlet context of the application + * @param resourceName The file or resource being searched for + * @param required if required, this will throw an IOException if it cannot be found, otherwise will return null + * @return The URL to the resource. + * @throws IOException if required, and cannot be found. + */ + public static URL getResource(ServletContext context, String resourceName, boolean required) throws IOException { + URL result = null; + File resourceFile = new File(resourceName); + if (resourceFile != null && resourceFile.exists()) { + return new URL("file:/"+resourceFile.getAbsolutePath()); + } + try { + result = locateResource(context, resourceName); + } catch (Exception e) { + log.error(e,e); + } + if (required && result == null) { + throw new IOException("Required resource "+resourceName+" could not be found!"); + } + return result; + } + + /** + * Use {@link ClassUtil.locateResourceByPath} to find the resourceName, /WEB-INF/resourceName, and /WEB-INF/classes/resourceName. + */ + private static URL locateResource(ServletContext context, String resourceName) throws MalformedURLException { + URL result = locateResourceByPath(context, resourceName); + if (result == null) { + result = locateResourceByPath(context, "/WEB-INF/"+resourceName); + if (result == null) { + result = locateResourceByPath(context, "/WEB-INF/classes/"+resourceName); + } + } + return result; + } + + /** + * Locate a resource in the given context. + * Process is: + * + * @return the URL to the resource or null + */ + private static URL locateResourceByPath(ServletContext context, String resourceName) throws MalformedURLException { + URL result = null; + String basePath = context.getRealPath("/"); + if (basePath!=null) { + if (!basePath.endsWith(File.separator)) { + basePath = basePath+File.separator; + } + String fileResourceName = resourceName; + if (resourceName.startsWith(File.separator)) { + fileResourceName = resourceName.substring(1); + } + File resourceFile = new File( basePath + fileResourceName ); + if (resourceFile != null && resourceFile.exists()) { + result = new URL("file:/"+resourceFile.getAbsolutePath()); + } + } + if (result == null) { + try { + result = context.getResource( resourceName ); + if (result == null) { + result = WikiEngine.class.getResource( resourceName ); + } + } catch (Exception e) { + // ignore. Will be handled later + } + } + return result; + } } Index: jspwiki-war/src/main/java/org/apache/wiki/util/PropertyReader.java =================================================================== --- jspwiki-war/src/main/java/org/apache/wiki/util/PropertyReader.java (revision 1659579) +++ jspwiki-war/src/main/java/org/apache/wiki/util/PropertyReader.java (working copy) @@ -117,20 +117,10 @@ InputStream propertyStream = null; try { - // - // Figure out where our properties lie. - // - if( propertyFile == null ) { - LOG.info( "No " + PARAM_CUSTOMCONFIG + " defined for this context, " + - "looking for custom properties file with default name of: " + CUSTOM_JSPWIKI_CONFIG ); - // Use the custom property file at the default location - propertyStream = locateClassPathResource(context, CUSTOM_JSPWIKI_CONFIG); - } else { - LOG.info(PARAM_CUSTOMCONFIG + " defined, using " + propertyFile + " as the custom properties file."); - propertyStream = new FileInputStream( new File(propertyFile) ); - } + Properties props = getCombinedProperties(propertyFile); + String resourceName = props.getProperty( PARAM_CUSTOMCONFIG, CUSTOM_JSPWIKI_CONFIG ); + propertyStream = ClassUtil.getResourceAsStream(context, resourceName, false); - Properties props = getDefaultProperties(); if( propertyStream == null ) { LOG.info("No custom property file found, relying on JSPWiki defaults."); } else {