Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuard.java =================================================================== diff -u -r2ab1076d8852ca61f6e633ea31de878497c3023a -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuard.java (.../CsrfGuard.java) (revision 2ab1076d8852ca61f6e633ea31de878497c3023a) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuard.java (.../CsrfGuard.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,791 +26,395 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard; -import java.io.IOException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.SecureRandom; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.regex.Pattern; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - import org.owasp.csrfguard.action.IAction; import org.owasp.csrfguard.config.ConfigurationProvider; import org.owasp.csrfguard.config.ConfigurationProviderFactory; import org.owasp.csrfguard.config.NullConfigurationProvider; import org.owasp.csrfguard.config.PropertiesConfigurationProviderFactory; import org.owasp.csrfguard.config.overlay.ExpirableCache; -import org.owasp.csrfguard.exception.CSRFGuardTokenException; -import org.owasp.csrfguard.log.ILogger; -import org.owasp.csrfguard.log.LogLevel; -import org.owasp.csrfguard.servlet.JavaScriptServlet; -import org.owasp.csrfguard.util.*; +import org.owasp.csrfguard.config.properties.ConfigParameters; +import org.owasp.csrfguard.session.LogicalSession; +import org.owasp.csrfguard.token.service.TokenService; +import org.owasp.csrfguard.token.storage.LogicalSessionExtractor; +import org.owasp.csrfguard.token.storage.TokenHolder; +import org.owasp.csrfguard.util.CsrfGuardPropertiesToStringBuilder; +import org.owasp.csrfguard.util.CsrfGuardUtils; -public final class CsrfGuard { +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.security.SecureRandom; +import java.time.Duration; +import java.util.*; +import java.util.regex.Pattern; - public static final String PAGE_TOKENS_KEY = "Owasp_CsrfGuard_Pages_Tokens_Key"; +public class CsrfGuard { - private Properties properties = null; + /** + * cache the configuration for a minute + */ + private static final ExpirableCache configurationProviderExpirableCache = new ExpirableCache<>(1); - /** - * cache the configuration for a minute - */ - private static ExpirableCache configurationProviderExpirableCache = new ExpirableCache(1); - - private ConfigurationProvider config() { - if (this.properties == null) { - return new NullConfigurationProvider(); - } - - ConfigurationProvider configurationProvider = configurationProviderExpirableCache.get(Boolean.TRUE); - - if (configurationProvider == null) { + /** + * cache regex patterns here + */ + private final Map regexPatternCache = new HashMap<>(); - synchronized (CsrfGuard.class) { - configurationProvider = retrieveNewConfig(); - } - } else if ( !configurationProvider.isCacheable()) { - //dont synchronize if not cacheable - configurationProvider = retrieveNewConfig(); - } - - - return configurationProvider; - } + private Properties properties = null; - void generatePageTokensForSession(final HttpSession session) { - final Map pageTokens = SessionUtils.extractPageTokensFromSession(session); - final Set protectedPages = getProtectedPages(); + private boolean isJavaScriptConfigurationNeeded; - for (String protectedResource : protectedPages) { - pageTokens.put(protectedResource, TokenUtils.getRandomToken()); - } + public CsrfGuard() {} - SessionUtils.updatePageTokensOnSession(session, pageTokens); - } - - /** - * @return new provider - */ - private ConfigurationProvider retrieveNewConfig() { - ConfigurationProvider configurationProvider = null; - //lets see what provider we are using - String configurationProviderFactoryClassName = this.properties.getProperty( - "org.owasp.csrfguard.configuration.provider.factory", PropertiesConfigurationProviderFactory.class.getName()); + public static CsrfGuard getInstance() { + return SingletonHolder.instance; + } - Class configurationProviderFactoryClass = CsrfGuardUtils.forName(configurationProviderFactoryClassName); - - ConfigurationProviderFactory configurationProviderFactory = CsrfGuardUtils.newInstance(configurationProviderFactoryClass); - - configurationProvider = configurationProviderFactory.retrieveConfiguration(this.properties); - configurationProviderExpirableCache.put(Boolean.TRUE, configurationProvider); - return configurationProvider; - } - - private static class SingletonHolder { - public static final CsrfGuard instance = new CsrfGuard(); - } + public static void load(final Properties theProperties) { + getInstance().properties = theProperties; + configurationProviderExpirableCache.clear(); + } - public static CsrfGuard getInstance() { - return SingletonHolder.instance; - } + public Map getRegexPatternCache() { + return this.regexPatternCache; + } - public static void load(Properties theProperties) throws NoSuchAlgorithmException, InstantiationException, IllegalAccessException, ClassNotFoundException, IOException, NoSuchProviderException { + public String getTokenName() { + return config().getTokenName(); + } - getInstance().properties = theProperties; - configurationProviderExpirableCache.clear(); - } - - public CsrfGuard() { - //Empty Constructor - } + public int getTokenLength() { + return config().getTokenLength(); + } - public ILogger getLogger() { - return config().getLogger(); - } + public boolean isRotateEnabled() { + return config().isRotateEnabled(); + } - public String getTokenName() { - return config().getTokenName(); - } + public boolean isTokenPerPageEnabled() { + return config().isTokenPerPageEnabled(); + } - public int getTokenLength() { - return config().getTokenLength(); - } + public boolean isTokenPerPagePrecreate() { + return config().isTokenPerPagePrecreateEnabled(); + } - public boolean isRotateEnabled() { - return config().isRotateEnabled(); - } + /** + * If csrf guard filter should check even if there is no session for the user + * Note: this changed in 2014/04/20, the default behavior used to be to + * not check if there is no session. If you want the legacy behavior (if your app + * is not susceptible to CSRF if the user has no session), set this to false + * + * @return if true + */ + public boolean isValidateWhenNoSessionExists() { + return config().isValidateWhenNoSessionExists(); + } - public boolean isTokenPerPageEnabled() { - return config().isTokenPerPageEnabled(); - } - public boolean isTokenPerPagePrecreate() { - return config().isTokenPerPagePrecreateEnabled(); - } + public SecureRandom getPrng() { + return config().getPrng(); + } - /** - * If csrf guard filter should check even if there is no session for the user - * Note: this changed in 2014/04/20, the default behavior used to be to - * not check if there is no session. If you want the legacy behavior (if your app - * is not susceptible to CSRF if the user has no session), set this to false - * @return if true - */ - public boolean isValidateWhenNoSessionExists() { - return config().isValidateWhenNoSessionExists(); - } - - public SecureRandom getPrng() { - return config().getPrng(); - } + public String getNewTokenLandingPage() { + return config().getNewTokenLandingPage(); + } - public String getNewTokenLandingPage() { - return config().getNewTokenLandingPage(); - } + public boolean isUseNewTokenLandingPage() { + return config().isUseNewTokenLandingPage(); + } - public boolean isUseNewTokenLandingPage() { - return config().isUseNewTokenLandingPage(); - } + public boolean isAjaxEnabled() { + return config().isAjaxEnabled(); + } - public boolean isAjaxEnabled() { - return config().isAjaxEnabled(); - } + public boolean isForceSynchronousAjax() { + return config().isForceSynchronousAjax(); + } - public boolean isProtectEnabled() { - return config().isProtectEnabled(); - } + /** + * @return if protect is enabled + * @see ConfigurationProvider#isProtectEnabled() + */ + public boolean isProtectEnabled() { + return config().isProtectEnabled(); + } - /** - * @see ConfigurationProvider#isEnabled() - * @return if enabled - */ - public boolean isEnabled() { - return config().isEnabled(); - } - - public String getSessionKey() { - return config().getSessionKey(); - } + /** + * @return if enabled + * @see ConfigurationProvider#isEnabled() + */ + public boolean isEnabled() { + return config().isEnabled(); + } - public Set getProtectedPages() { - return config().getProtectedPages(); - } + public Set getProtectedPages() { + return config().getProtectedPages(); + } - public Set getUnprotectedPages() { - return config().getUnprotectedPages(); - } + public Set getUnprotectedPages() { + return config().getUnprotectedPages(); + } - /** - * cache regex patterns here - */ - private Map regexPatternCache = new HashMap(); - - public Set getProtectedMethods () { - return config().getProtectedMethods(); - } + public TokenHolder getTokenHolder() { + return config().getTokenHolder(); + } - public List getActions() { - return config().getActions(); - } + public LogicalSessionExtractor getLogicalSessionExtractor() { + return config().getLogicalSessionExtractor(); + } - public String getJavascriptSourceFile() { - return config().getJavascriptSourceFile(); - } + public Set getProtectedMethods() { + return config().getProtectedMethods(); + } - /** - * @see ConfigurationProvider#isJavascriptInjectFormAttributes() - * @return if inject - */ - public boolean isJavascriptInjectFormAttributes() { - return config().isJavascriptInjectFormAttributes(); - } + public List getActions() { + return config().getActions(); + } - /** - * @see ConfigurationProvider#isJavascriptInjectGetForms() - * @return if inject - */ - public boolean isJavascriptInjectGetForms() { - return config().isJavascriptInjectGetForms(); - } - - public boolean isJavascriptDomainStrict() { - return config().isJavascriptDomainStrict(); - } + /** + * @see ConfigurationProvider#initializeJavaScriptConfiguration() + */ + public void initializeJavaScriptConfiguration() { + config().initializeJavaScriptConfiguration(); + this.isJavaScriptConfigurationNeeded = true; + } - public boolean isJavascriptRefererMatchProtocol() { - return config().isJavascriptRefererMatchProtocol(); - } + /** + * @return if inject + * @see ConfigurationProvider#isJavascriptInjectFormAttributes() + */ + public boolean isJavascriptInjectFormAttributes() { + return config().isJavascriptInjectFormAttributes(); + } - public boolean isJavascriptRefererMatchDomain() { - return config().isJavascriptRefererMatchDomain(); - } + /** + * @return if inject + * @see ConfigurationProvider#isJavascriptInjectGetForms() + */ + public boolean isJavascriptInjectGetForms() { + return config().isJavascriptInjectGetForms(); + } - public String getJavascriptCacheControl() { - return config().getJavascriptCacheControl(); - } + public boolean isJavascriptDomainStrict() { + return config().isJavascriptDomainStrict(); + } - public Pattern getJavascriptRefererPattern() { - return config().getJavascriptRefererPattern(); - } + public boolean isJavascriptRefererMatchProtocol() { + return config().isJavascriptRefererMatchProtocol(); + } - public boolean isJavascriptInjectIntoForms() { - return config().isJavascriptInjectIntoForms(); - } + public boolean isJavascriptRefererMatchDomain() { + return config().isJavascriptRefererMatchDomain(); + } - public boolean isJavascriptInjectIntoAttributes() { - return config().isJavascriptInjectIntoAttributes(); - } + public String getJavascriptCacheControl() { + return config().getJavascriptCacheControl(); + } - public String getJavascriptXrequestedWith() { - return config().getJavascriptXrequestedWith(); - } + public Pattern getJavascriptRefererPattern() { + return config().getJavascriptRefererPattern(); + } - public String getJavascriptTemplateCode() { - return config().getJavascriptTemplateCode(); - } - - public String getJavascriptUnprotectedExtensions() { - return config().getJavascriptUnprotectedExtensions(); - } - - public String getTokenValue(HttpServletRequest request) { - return getTokenValue(request, request.getRequestURI()); - } + public boolean isJavascriptInjectIntoForms() { + return config().isJavascriptInjectIntoForms(); + } - public String getTokenValue(HttpServletRequest request, String uri) { - String tokenValue = null; - HttpSession session = request.getSession(false); + public boolean isJavascriptInjectIntoAttributes() { + return config().isJavascriptInjectIntoAttributes(); + } - if (session != null) { - if (isTokenPerPageEnabled()) { + public boolean isJavascriptInjectIntoDynamicallyCreatedNodes() { + return config().isJavascriptInjectIntoDynamicallyCreatedNodes(); + } - Map pageTokens = SessionUtils.extractPageTokensFromSession(session); + public String getJavascriptDynamicNodeCreationEventName() { + return config().getJavascriptDynamicNodeCreationEventName(); + } - if (pageTokens != null) { - if (isTokenPerPagePrecreate()) { - createPageToken(pageTokens,uri); - } - tokenValue = pageTokens.get(uri); - - } - } + public String getJavascriptXrequestedWith() { + return config().getJavascriptXrequestedWith(); + } - if (tokenValue == null) { - tokenValue = (String) session.getAttribute(getSessionKey()); - } - } + public String getJavascriptTemplateCode() { + return config().getJavascriptTemplateCode(); + } - return tokenValue; - } + public String getJavascriptUnprotectedExtensions() { + return config().getJavascriptUnprotectedExtensions(); + } - public boolean isValidRequest(HttpServletRequest request, HttpServletResponse response) { - boolean valid = !isProtectedPageAndMethod(request); - HttpSession session = request.getSession(true); - String tokenFromSession = (String) session.getAttribute(getSessionKey()); + public TokenService getTokenService() { + return new TokenService(this); + } - if (!valid){ - /** print log message - page and method are protected **/ - getLogger().log(String.format("CSRFGuard analyzing request %s", request.getRequestURI())); - } - - /** sending request to protected resource - verify token **/ - if (tokenFromSession != null && !valid) { - try { - verifyToken(request); - valid = true; - } catch (CsrfGuardException csrfe) { - callActionsOnError(request, response, csrfe); - } + public boolean isPrintConfig() { + return config().isPrintConfig(); + } - /** rotate session and page tokens **/ - if (!isAjaxRequest(request) && isRotateEnabled()) { - rotateTokens(request); - } - /** expected token in session - bad state and not valid **/ - } else if (tokenFromSession == null && !valid) { - try { - throw new CsrfGuardException(MessageConstants.SESSION_TOKEN_MSG); - } catch (CsrfGuardException csrfe) { - callActionsOnError(request, response, csrfe); - } - } else { - /** unprotected page - nothing to do **/ - } - return valid; - } + public String getDomainOrigin() { + return config().getDomainOrigin(); + } - /** - * Verify the token based on the type - ex: page, session or ajax - * - * @param request - HttpRequest - * @throws CsrfGuardException - Exception - */ - private void verifyToken(HttpServletRequest request) throws CsrfGuardException { - if (isAjaxEnabled() && isAjaxRequest(request)) { - verifyAjaxToken(request); - } else if (isTokenPerPageEnabled()) { - verifyPageToken(request); - } else { - verifySessionToken(request); - } - } + public Duration getPageTokenSynchronizationTolerance() { + return config().getPageTokenSynchronizationTolerance(); + } - /** - * Invoked when there was a CsrfGuardException such as a token mismatch error. - * Calls the configured actions. - * @param request The HttpServletRequest - * @param response The HttpServletResponse - * @param csrfe The exception that triggered the actions call. Passed to the action. - * @see IAction#execute(HttpServletRequest, HttpServletResponse, CsrfGuardException) - */ - private void callActionsOnError(HttpServletRequest request, - HttpServletResponse response, CsrfGuardException csrfe) { - for (IAction action : getActions()) { - try { - action.execute(request, response, csrfe, this); - } catch (CsrfGuardException exception) { - getLogger().log(LogLevel.Error, exception); - } - } - } + /** + * if there are methods specified, then they (e.g. GET) are unprotected, and all others are protected + * + * @return the unprotected HTTP methods + */ + public Set getUnprotectedMethods() { + return config().getUnprotectedMethods(); + } - public void updateToken(HttpSession session) { - String tokenValue = (String) session.getAttribute(getSessionKey()); + @Override + public String toString() { + return isEnabled() ? new CsrfGuardPropertiesToStringBuilder(config()).toString() + : "OWASP CSRFGuard is disabled."; + } - /** Generate a new token and store it in the session. **/ - if (tokenValue == null) { - try { - tokenValue = RandomGenerator.generateRandomId(getPrng(), getTokenLength()); - } catch (Exception e) { - String errorLiteral = MessageConstants.RANDOM_TOKEN_FAILURE_MSG + " - " + "%s"; - throw new CSRFGuardTokenException(String.format(errorLiteral, e.getLocalizedMessage()), e); - } + /** + * Rotation in case of AJAX requests is not supported currently because of possible race conditions. + *

+ * A Single Page Application can fire multiple simultaneous requests. + * If rotation is enabled for AJAX requests, the first request could trigger a token change before the validation of the second request with the same token, causing + * false-positive CSRF intrusion exceptions. + * + * @param request the current request + * @return True if rotation is enabled and possible + */ + public boolean isRotateEnabled(final HttpServletRequest request) { + return isRotateEnabled() && !CsrfGuardUtils.isAjaxRequest(request); + } - session.setAttribute(getSessionKey(), tokenValue); - } - } + /** + * Method to be called by a logical session implementation when a new session is created.
+ *

+ * Example: {@link javax.servlet.http.HttpSessionListener#sessionCreated(javax.servlet.http.HttpSessionEvent)} + * + * @param logicalSession a logical session implementation + */ + public void onSessionCreated(final LogicalSession logicalSession) { + if (isEnabled()) { + final String logicalSessionKey = logicalSession.getKey(); - public void updateTokens(HttpServletRequest request) { - /** cannot create sessions if response already committed **/ - HttpSession session = request.getSession(false); + final TokenService tokenService = getTokenService(); + tokenService.createMasterTokenIfAbsent(logicalSessionKey); - if (session != null) { - /** create master token if it does not exist **/ - updateToken(session); - - /** create page specific token **/ - if (isTokenPerPageEnabled()) { + if (isTokenPerPageEnabled() + && isTokenPerPagePrecreate() + && isProtectEnabled() + && !logicalSession.areTokensGenerated()) { - Map pageTokens = SessionUtils.extractPageTokensFromSession(session); + tokenService.generateProtectedPageTokens(logicalSessionKey); + logicalSession.setTokensGenerated(true); + } + } + } - /** first time initialization **/ - if (pageTokens == null) { - pageTokens = new HashMap(); - session.setAttribute(CsrfGuard.PAGE_TOKENS_KEY, pageTokens); - } + /** + * Method to be called by a logical session implementation when a session is destroyed.
+ *

+ * Example: {@link javax.servlet.http.HttpSessionListener#sessionDestroyed(javax.servlet.http.HttpSessionEvent)} + * + * @param logicalSession a logical session implementation + */ + public void onSessionDestroyed(final LogicalSession logicalSession) { + final TokenHolder tokenHolder = getTokenHolder(); + if (Objects.nonNull(tokenHolder)) { + tokenHolder.remove(logicalSession.getKey()); + } + } - /** create token if it does not exist **/ - if (isProtectedPageAndMethod(request)) { - createPageToken(pageTokens, request.getRequestURI()); - } - } - } - } + public void writeLandingPage(final HttpServletResponse response, final String logicalSessionKey) throws IOException { + final String landingPage = getNewTokenLandingPage(); - /** - * Create page token if it doesn't exist. - * @param pageTokens A map of tokens. If token doesn't exist it will be added. - * @param uri The key for the tokens. - */ - private void createPageToken(Map pageTokens, String uri) { - - if(pageTokens == null) - return; - - /** create token if it does not exist **/ - if (pageTokens.containsKey(uri)) - return; - try { - pageTokens.put(uri, RandomGenerator.generateRandomId(getPrng(), getTokenLength())); - } catch (Exception e) { - String errorLiteral = MessageConstants.RANDOM_TOKEN_FAILURE_MSG + " - " + "%s"; - throw new CSRFGuardTokenException(String.format(errorLiteral, e.getLocalizedMessage()), e); - } - } + /* create auto posting form */ + final StringBuilder stringBuilder = new StringBuilder(); - public void writeLandingPage(HttpServletRequest request, HttpServletResponse response) throws IOException { - String landingPage = getNewTokenLandingPage(); + // TODO this HTML template should rather be extracted to a separate file + stringBuilder.append("") + .append("") + .append("OWASP CSRFGuard Project - New Token Landing Page") + .append("") + .append("") + .append("") + .append("") + .append(""); - sb.append("\r\n"); - sb.append("\r\n"); - sb.append("OWASP CSRFGuard Project - New Token Landing Page\r\n"); - sb.append("\r\n"); - sb.append("\r\n"); - sb.append("\r\n"); - sb.append("\r\n"); - sb.append("\r\n"); + /* write auto posting form */ + response.getWriter().write(code); + } - String code = sb.toString(); - /** setup headers **/ - response.setContentType("text/html"); - response.setContentLength(code.length()); + private ConfigurationProvider config() { + if (this.properties == null) { + return new NullConfigurationProvider(); + } - /** write auto posting form **/ - response.getWriter().write(code); - } + ConfigurationProvider configurationProvider = configurationProviderExpirableCache.get(Boolean.TRUE); - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); + if (configurationProvider == null) { - sb.append("\r\n*****************************************************\r\n"); - sb.append("* Owasp.CsrfGuard Properties\r\n"); - sb.append("*\r\n"); - sb.append(String.format("* Logger: %s\r\n", getLogger().getClass().getName())); - sb.append(String.format("* NewTokenLandingPage: %s\r\n", getNewTokenLandingPage())); - sb.append(String.format("* PRNG: %s\r\n", getPrng().getAlgorithm())); - sb.append(String.format("* SessionKey: %s\r\n", getSessionKey())); - sb.append(String.format("* TokenLength: %s\r\n", getTokenLength())); - sb.append(String.format("* TokenName: %s\r\n", getTokenName())); - sb.append(String.format("* Ajax: %s\r\n", isAjaxEnabled())); - sb.append(String.format("* Rotate: %s\r\n", isRotateEnabled())); - sb.append(String.format("* Javascript cache control: %s\r\n", getJavascriptCacheControl())); - sb.append(String.format("* Javascript domain strict: %s\r\n", isJavascriptDomainStrict())); - sb.append(String.format("* Javascript inject attributes: %s\r\n", isJavascriptInjectIntoAttributes())); - sb.append(String.format("* Javascript inject forms: %s\r\n", isJavascriptInjectIntoForms())); - sb.append(String.format("* Javascript referer pattern: %s\r\n", getJavascriptRefererPattern())); - sb.append(String.format("* Javascript referer match protocol: %s\r\n", isJavascriptRefererMatchProtocol())); - sb.append(String.format("* Javascript referer match domain: %s\r\n", isJavascriptRefererMatchDomain())); - sb.append(String.format("* Javascript unprotected extensions: %s\r\n", getJavascriptUnprotectedExtensions())); - sb.append(String.format("* Javascript source file: %s\r\n", getJavascriptSourceFile())); - sb.append(String.format("* Javascript X requested with: %s\r\n", getJavascriptXrequestedWith())); - sb.append(String.format("* Protected methods: %s\r\n", CsrfGuardUtils.toStringForLog(getProtectedMethods()))); - sb.append(String.format("* Protected pages size: %s\r\n", CsrfGuardUtils.length(getProtectedPages()))); - sb.append(String.format("* Unprotected methods: %s\r\n", CsrfGuardUtils.toStringForLog(getUnprotectedMethods()))); - sb.append(String.format("* Unprotected pages size: %s\r\n", CsrfGuardUtils.length(getUnprotectedPages()))); - sb.append(String.format("* TokenPerPage: %s\r\n", isTokenPerPageEnabled())); - sb.append(String.format("* Enabled: %s\r\n", isEnabled())); - sb.append(String.format("* ValidateWhenNoSessionExists: %s\r\n", isValidateWhenNoSessionExists())); - - for (IAction action : getActions()) { - sb.append(String.format("* Action: %s\r\n", action.getClass().getName())); + synchronized (CsrfGuard.class) { + configurationProvider = retrieveNewConfig(); + } + } else if (!configurationProvider.isCacheable()) { + /* don't synchronize if not cacheable */ + configurationProvider = retrieveNewConfig(); + } - for (String name : action.getParameterMap().keySet()) { - String value = action.getParameter(name); + return configurationProvider; + } - sb.append(String.format("*\tParameter: %s = %s\r\n", name, value)); - } - } - sb.append("*****************************************************\r\n"); + /** + * @return new provider + */ + private ConfigurationProvider retrieveNewConfig() { + final ConfigurationProvider configurationProvider; + /* let's see what provider we are using */ + final String configurationProviderFactoryClassName = this.properties.getProperty(ConfigParameters.CONFIG_PROVIDER_FACTORY_PROPERTY_NAME, PropertiesConfigurationProviderFactory.class.getName()); - return sb.toString(); - } + final Class configurationProviderFactoryClass = CsrfGuardUtils.forName(configurationProviderFactoryClassName); - private boolean isAjaxRequest(final HttpServletRequest request) { - final String header = request.getHeader("X-Requested-With"); - if (header == null) { - return false; - } - final String[] headers = header.split(","); - for (final String requestedWithHeader: headers) { - if ("XMLHttpRequest".equals(requestedWithHeader.trim())) { - return true; - } - } - return false; - } + final ConfigurationProviderFactory configurationProviderFactory = CsrfGuardUtils.newInstance(configurationProviderFactoryClass); - private void verifyAjaxToken(HttpServletRequest request) throws CsrfGuardException { - HttpSession session = request.getSession(true); - String tokenFromSession = (String) session.getAttribute(getSessionKey()); - String tokenFromRequest = request.getHeader(getTokenName()); + configurationProvider = configurationProviderFactory.retrieveConfiguration(this.properties); + if (this.isJavaScriptConfigurationNeeded) { + configurationProvider.initializeJavaScriptConfiguration(); + } - if (tokenFromRequest == null) { - /** FAIL: token is missing from the request **/ - throw new CsrfGuardException(MessageConstants.MISSING_TOKEN_MSG); - } else { - //if there are two headers, then the result is comma separated - if (!tokenFromSession.equals(tokenFromRequest)) { - if (tokenFromRequest.contains(",")) { - tokenFromRequest = tokenFromRequest.substring(0, tokenFromRequest.indexOf(',')).trim(); - } - if (!tokenFromSession.equals(tokenFromRequest)) { - /** FAIL: the request token does not match the session token **/ - throw new CsrfGuardException(MessageConstants.MISSING_TOKEN_MSG); - } - } - } - } + configurationProviderExpirableCache.put(Boolean.TRUE, configurationProvider); + return configurationProvider; + } - private void verifyPageToken(HttpServletRequest request) throws CsrfGuardException { - - HttpSession session = request.getSession(true); - Map pageTokens = SessionUtils.extractPageTokensFromSession(session); - - String tokenFromPages = (pageTokens != null ? pageTokens.get(request.getRequestURI()) : null); - String tokenFromSession = (String) session.getAttribute(getSessionKey()); - String tokenFromRequest = request.getParameter(getTokenName()); - - if (tokenFromRequest == null) { - /** FAIL: token is missing from the request **/ - throw new CsrfGuardException(MessageConstants.MISSING_TOKEN_MSG); - } else if (tokenFromPages != null) { - if (!tokenFromPages.equals(tokenFromRequest)) { - /** FAIL: request does not match page token **/ - SessionUtils.invalidateTokenForResource(session, tokenFromPages, tokenFromRequest); - throw new CsrfGuardException(MessageConstants.MISMATCH_PAGE_TOKEN_MSG); - } - } else if (!tokenFromSession.equals(tokenFromRequest)) { - /** FAIL: the request token does not match the session token **/ - SessionUtils.invalidateSessionToken(session); - throw new CsrfGuardException(MessageConstants.MISMATCH_SESSION_TOKEN_MSG); - } - } - - private void verifySessionToken(HttpServletRequest request) throws CsrfGuardException { - HttpSession session = request.getSession(true); - String tokenFromSession = (String) session.getAttribute(getSessionKey()); - String tokenFromRequest = request.getParameter(getTokenName()); - - if (tokenFromRequest == null) { - /** FAIL: token is missing from the request **/ - throw new CsrfGuardException(MessageConstants.MISSING_TOKEN_MSG); - } else if (!tokenFromSession.equals(tokenFromRequest)) { - /** FAIL: the request token does not match the session token **/ - SessionUtils.invalidateSessionToken(session); - throw new CsrfGuardException(MessageConstants.MISMATCH_SESSION_TOKEN_MSG); - } - } - - private void rotateTokens(HttpServletRequest request) { - HttpSession session = request.getSession(true); - - /** rotate master token **/ - String tokenFromSession; - - try { - tokenFromSession = RandomGenerator.generateRandomId(getPrng(), getTokenLength()); - } catch (Exception e) { - String errorLiteral = MessageConstants.RANDOM_TOKEN_FAILURE_MSG + " - " + "%s"; - throw new CSRFGuardTokenException(String.format(errorLiteral, e.getLocalizedMessage()), e); - } - - session.setAttribute(getSessionKey(), tokenFromSession); - - /** rotate page token **/ - if (isTokenPerPageEnabled()) { - - Map pageTokens = SessionUtils.extractPageTokensFromSession(session); - - try { - pageTokens.put(request.getRequestURI(), RandomGenerator.generateRandomId(getPrng(), getTokenLength())); - } catch (Exception e) { - String errorLiteral = MessageConstants.RANDOM_TOKEN_FAILURE_MSG + " - " + "%s"; - throw new CSRFGuardTokenException(String.format(errorLiteral, e.getLocalizedMessage()), e); - } - } - } - - public boolean isProtectedPage(String uri) { - - //if this is a javascript page, let it go through - if (JavaScriptServlet.getJavascriptUris().contains(uri)) { - return false; - } - - // LAMS LDEV-4932 Replace multiple slashes with a single one, so it works the same as Spring MVC - uri = uri.replaceAll("/{2,}", "/"); - - boolean retval = !isProtectEnabled(); - - for (String protectedPage : getProtectedPages()) { - if (isUriExactMatch(protectedPage, uri)) { - return true; - } else if (isUriMatch(protectedPage, uri)) { - retval = true; - } - } - - for (String unprotectedPage : getUnprotectedPages()) { - if (isUriExactMatch(unprotectedPage, uri)) { - return false; - } else if (isUriMatch(unprotectedPage, uri)) { - retval = false; - } - } - - return retval; - } - - /** - * Whether or not the HTTP method is protected, i.e. should be checked for token. - * @param method The method to check for protection status - * @return true when the given method name is in the protected methods set and not in the unprotected methods set - */ - public boolean isProtectedMethod(String method) { - boolean isProtected = true; - - { - Set theProtectedMethods = getProtectedMethods(); - if (!theProtectedMethods.isEmpty() && !theProtectedMethods.contains(method)) { - isProtected = false; - } - } - - { - Set theUnprotectedMethods = getUnprotectedMethods(); - if (!theUnprotectedMethods.isEmpty() && theUnprotectedMethods.contains(method)) { - isProtected = false; - } - } - - return isProtected; - } - - public boolean isProtectedPageAndMethod(String page, String method) { - return (isProtectedPage(page) && isProtectedMethod(method)); - } - - public boolean isProtectedPageAndMethod(HttpServletRequest request) { - return isProtectedPageAndMethod(request.getRequestURI(), request.getMethod()); - } - - public boolean isPrintConfig() { - return config().isPrintConfig(); - } - - public String getDomainOrigin() { - return config().getDomainOrigin(); - } - - /** - * FIXME: taken from Tomcat - ApplicationFilterFactory - * - * @param testPath the pattern to match. - * @param requestPath the current request path. - * @return {@code true} if {@code requestPath} matches {@code testPath}. - */ - private boolean isUriMatch(String testPath, String requestPath) { - - //case 4, if it is a regex - if (RegexValidationUtil.isTestPathRegex(testPath)) { - - Pattern pattern = this.regexPatternCache.get(testPath); - if (pattern == null) { - pattern = Pattern.compile(testPath); - this.regexPatternCache.put(testPath, pattern); - } - - return pattern.matcher(requestPath).matches(); - } - - boolean retval = false; - - /** Case 1: Exact Match - * MCH 140419: ??? isnt this checks in isUriExactMatch() ??? **/ - if (testPath.equals(requestPath)) { - retval = true; - } - - /** Case 2 - Path Match ("/.../*") **/ - if (testPath.equals("/*")) { - retval = true; - } - - if (testPath.endsWith("/*") && - (testPath.regionMatches(0, requestPath, 0, testPath.length() - 2) - && (requestPath.length() == (testPath.length() - 2) - || '/' == requestPath.charAt(testPath.length() - 2)))) { - retval = true; - } - - /** Case 3 - Extension Match **/ - retval = validateExtensionMatch(testPath, requestPath, retval); - - return retval; - } - - private boolean validateExtensionMatch(String testPath, String requestPath, boolean retval) { - if (testPath != null && testPath.startsWith("*.")) { - int slash = requestPath.lastIndexOf('/'); - int period = requestPath.lastIndexOf('.'); - - if ((slash >= 0) && (period > slash) && (period != requestPath.length() - 1) - && ((requestPath.length() - period) == (testPath.length() - 1))) { - retval = testPath.regionMatches(2, requestPath, period + 1, - testPath.length() - 2); - } - } - return retval; - } - - private boolean isUriExactMatch(String testPath, String requestPath) { - - //cant be an exact match if this is a regex - if (RegexValidationUtil.isTestPathRegex(testPath)) { - return false; - } - - boolean retval = false; - - /** Case 1: Exact Match **/ - if (testPath.equals(requestPath)) { - retval = true; - } - - return retval; - } - - /** - * if there are methods specified, then they (e.g. GET) are unprotected, and all others are protected - * @return the unprotected HTTP methods - */ - public Set getUnprotectedMethods () { - return config().getUnprotectedMethods(); - } - + private static final class SingletonHolder { + public static final CsrfGuard instance = new CsrfGuard(); + } } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuardException.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuardException.java (.../CsrfGuardException.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuardException.java (.../CsrfGuardException.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,22 +26,22 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard; public class CsrfGuardException extends Exception { private static final long serialVersionUID = -4468336915273168914L; - public CsrfGuardException(String msg) { + public CsrfGuardException(final String msg) { super(msg); } - public CsrfGuardException(Exception e) { + public CsrfGuardException(final Exception e) { super(e); } - public CsrfGuardException(String msg, Exception e) { + public CsrfGuardException(final String msg, final Exception e) { super(msg, e); } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuardFilter.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuardFilter.java (.../CsrfGuardFilter.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuardFilter.java (.../CsrfGuardFilter.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,20 +1,20 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - *

+ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - *

- * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. - *

+ * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -26,75 +26,114 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard; import org.owasp.csrfguard.http.InterceptRedirectResponse; +import org.owasp.csrfguard.session.LogicalSession; +import org.owasp.csrfguard.token.storage.LogicalSessionExtractor; +import org.owasp.csrfguard.token.transferobject.TokenTO; +import org.owasp.csrfguard.util.CsrfGuardUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; import java.io.IOException; +import java.util.Collections; -public final class CsrfGuardFilter implements Filter { +public class CsrfGuardFilter implements Filter { private FilterConfig filterConfig = null; + private static final Logger LOGGER = LoggerFactory.getLogger(CsrfGuardFilter.class); + @Override - public void destroy() { - filterConfig = null; + public void init(final FilterConfig filterConfig) { + this.filterConfig = filterConfig; } @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { + public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain filterChain) throws IOException, ServletException { + final CsrfGuard csrfGuard = CsrfGuard.getInstance(); - //maybe the short circuit to disable is set - if (!CsrfGuard.getInstance().isEnabled()) { + if (csrfGuard.isEnabled()) { + if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { + doFilter((HttpServletRequest) request, (HttpServletResponse) response, filterChain, csrfGuard); + } else { + handleNonHttpServletMessages(request, response, filterChain); + } + } else { filterChain.doFilter(request, response); - return; } + } - /** only work with HttpServletRequest objects **/ - if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) { + @Override + public void destroy() { + this.filterConfig = null; + } - HttpServletRequest httpRequest = (HttpServletRequest) request; - HttpSession session = httpRequest.getSession(false); + private void doFilter(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse, final FilterChain filterChain, final CsrfGuard csrfGuard) throws IOException, ServletException { + final InterceptRedirectResponse interceptRedirectResponse = new InterceptRedirectResponse(httpServletResponse, httpServletRequest, csrfGuard); - //if there is no session and we arent validating when no session exists - if (session == null && !CsrfGuard.getInstance().isValidateWhenNoSessionExists()) { - // If there is no session, no harm can be done - filterChain.doFilter(httpRequest, (HttpServletResponse) response); - return; - } + final LogicalSessionExtractor sessionKeyExtractor = csrfGuard.getLogicalSessionExtractor(); + final LogicalSession logicalSession = sessionKeyExtractor.extract(httpServletRequest); - CsrfGuard csrfGuard = CsrfGuard.getInstance(); - InterceptRedirectResponse httpResponse = new InterceptRedirectResponse((HttpServletResponse) response, httpRequest, csrfGuard); - -// if(MultipartHttpServletRequest.isMultipartRequest(httpRequest)) { -// httpRequest = new MultipartHttpServletRequest(httpRequest); -// } - - if ((session != null && session.isNew()) && csrfGuard.isUseNewTokenLandingPage()) { - csrfGuard.writeLandingPage(httpRequest, httpResponse); - } else if (csrfGuard.isValidRequest(httpRequest, httpResponse)) { - filterChain.doFilter(httpRequest, httpResponse); + if (logicalSession == null) { + if (csrfGuard.isUseNewTokenLandingPage()) { + final LogicalSession createdLogicalSession = sessionKeyExtractor.extractOrCreate(httpServletRequest); + csrfGuard.writeLandingPage(interceptRedirectResponse, createdLogicalSession.getKey()); } else { - /** invalid request - nothing to do - actions already executed **/ + handleNoSession(httpServletRequest, httpServletResponse, interceptRedirectResponse, filterChain, csrfGuard); } + } else { + handleSession(httpServletRequest, interceptRedirectResponse, filterChain, logicalSession, csrfGuard); + } + } - /** update tokens **/ - csrfGuard.updateTokens(httpRequest); + private void handleSession(final HttpServletRequest httpServletRequest, final InterceptRedirectResponse interceptRedirectResponse, final FilterChain filterChain, + final LogicalSession logicalSession, final CsrfGuard csrfGuard) throws IOException, ServletException { + final String logicalSessionKey = logicalSession.getKey(); + + if (new CsrfValidator().isValid(httpServletRequest, interceptRedirectResponse)) { + filterChain.doFilter(httpServletRequest, interceptRedirectResponse); } else { - filterConfig.getServletContext().log(String.format("[WARNING] CsrfGuard does not know how to work with requests of class %s ", request.getClass().getName())); + logInvalidRequest(httpServletRequest); + } - filterChain.doFilter(request, response); + final String requestURI = httpServletRequest.getRequestURI(); + final String generatedToken = csrfGuard.getTokenService().generateTokensIfAbsent(logicalSessionKey, httpServletRequest.getMethod(), requestURI); + + CsrfGuardUtils.addResponseTokenHeader(csrfGuard, httpServletRequest, interceptRedirectResponse, new TokenTO(Collections.singletonMap(requestURI, generatedToken))); + } + + private void handleNoSession(final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse, final InterceptRedirectResponse interceptRedirectResponse, final FilterChain filterChain, + final CsrfGuard csrfGuard) throws IOException, ServletException { + if (csrfGuard.isValidateWhenNoSessionExists()) { + if (new CsrfValidator().isValid(httpServletRequest, interceptRedirectResponse)) { + filterChain.doFilter(httpServletRequest, interceptRedirectResponse); + } else { + logInvalidRequest(httpServletRequest); + } + } else { + filterChain.doFilter(httpServletRequest, httpServletResponse); } } - @Override - public void init(@SuppressWarnings("hiding") FilterConfig filterConfig) throws ServletException { - this.filterConfig = filterConfig; + private void handleNonHttpServletMessages(final ServletRequest request, final ServletResponse response, final FilterChain filterChain) throws IOException, ServletException { + final String message = String.format("CSRFGuard does not know how to work with requests of class %s ", request.getClass().getName()); + LOGGER.warn(message); + this.filterConfig.getServletContext().log("[WARNING]" + message); + + filterChain.doFilter(request, response); } + private void logInvalidRequest(final HttpServletRequest httpRequest) { + final String requestURI = httpRequest.getRequestURI(); + final String remoteAddress = httpRequest.getRemoteAddr(); + + LOGGER.warn("Invalid request: URI: '{}' | Remote Address: '{}'", requestURI, remoteAddress); + } } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuardHttpSessionListener.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuardHttpSessionListener.java (.../CsrfGuardHttpSessionListener.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuardHttpSessionListener.java (.../CsrfGuardHttpSessionListener.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,6 +1,36 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package org.owasp.csrfguard; -import org.owasp.csrfguard.util.SessionUtils; +import org.owasp.csrfguard.session.ContainerSession; +import org.owasp.csrfguard.session.LogicalSession; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionEvent; @@ -9,21 +39,16 @@ public class CsrfGuardHttpSessionListener implements HttpSessionListener { @Override - public void sessionCreated(HttpSessionEvent event) { - HttpSession session = event.getSession(); - CsrfGuard csrfGuard = CsrfGuard.getInstance(); - csrfGuard.updateToken(session); - // Check if should generate tokens for protected resources on current session - if (csrfGuard.isTokenPerPageEnabled() && csrfGuard.isTokenPerPagePrecreate() - && !SessionUtils.tokensGenerated(session)) { - csrfGuard.generatePageTokensForSession(session); - } - + public void sessionCreated(final HttpSessionEvent event) { + final HttpSession session = event.getSession(); + final LogicalSession logicalSession = new ContainerSession(session); + CsrfGuard.getInstance().onSessionCreated(logicalSession); } @Override - public void sessionDestroyed(HttpSessionEvent event) { - /** nothing to do **/ + public void sessionDestroyed(final HttpSessionEvent event) { + final HttpSession session = event.getSession(); + final LogicalSession logicalSession = new ContainerSession(session); + CsrfGuard.getInstance().onSessionDestroyed(logicalSession); } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuardServletContextListener.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuardServletContextListener.java (.../CsrfGuardServletContextListener.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfGuardServletContextListener.java (.../CsrfGuardServletContextListener.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,18 +1,47 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package org.owasp.csrfguard; +import org.apache.commons.lang3.StringUtils; +import org.owasp.csrfguard.config.overlay.ConfigurationOverlayProvider; + +import javax.servlet.ServletContext; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.util.Objects; import java.util.Properties; -import javax.servlet.ServletContext; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; - -import org.owasp.csrfguard.config.overlay.ConfigurationOverlayProvider; -import org.owasp.csrfguard.util.Streams; - public class CsrfGuardServletContextListener implements ServletContextListener { private static final String CONFIG_PARAM = "Owasp.CsrfGuard.Config"; @@ -22,7 +51,7 @@ * servlet context (will be the empty string if it is / ) */ private static String servletContext = null; - + /** * servlet context (will be the empty string if it is / ) * @return the servletContext @@ -35,54 +64,53 @@ * config file name if specified in the web.xml */ private static String configFileName = null; - + /** * config file name if specified in the web.xml * @return config file name */ public static String getConfigFileName() { return configFileName; } - + @Override - public void contextInitialized(ServletContextEvent event) { - ServletContext context = event.getServletContext(); + public void contextInitialized(final ServletContextEvent event) { + final ServletContext context = event.getServletContext(); servletContext = context.getContextPath(); - //since this is just a prefix of a path, then if there is no servlet context, it is the empty string - if (servletContext == null || "/".equals(servletContext)) { + // since this is just a prefix of a path, then if there is no servlet context, it is the empty string + if (StringUtils.equals(servletContext, "/")) { servletContext = ""; } - + configFileName = context.getInitParameter(CONFIG_PARAM); if (configFileName == null) { configFileName = ConfigurationOverlayProvider.OWASP_CSRF_GUARD_PROPERTIES; } - InputStream is = null; - Properties properties = new Properties(); + try (final InputStream configFileInputStream = getResourceStream(configFileName, context, false)) { + if (Objects.isNull(configFileInputStream)) { + try (final InputStream metaInfInputStream = getResourceStream(ConfigurationOverlayProvider.META_INF_CSRFGUARD_PROPERTIES, context, false)) { + if (Objects.isNull(metaInfInputStream)) { + throw new RuntimeException("Can't find default OWASP CSRFGuard properties file: " + configFileName); + } - try { - is = getResourceStream(configFileName, context, false); - - if (is == null) { - is = getResourceStream(ConfigurationOverlayProvider.META_INF_CSRFGUARD_PROPERTIES, context, false); + loadProperties(metaInfInputStream); + } } - if (is == null) { - throw new RuntimeException("Cant find default owasp csrfguard properties file: " + configFileName); - } - - properties.load(is); - CsrfGuard.load(properties); - } catch (Exception e) { + loadProperties(configFileInputStream); + } catch (final Exception e) { throw new RuntimeException(e); - } finally { - Streams.close(is); } + printConfigIfConfigured(context, "Printing properties before JavaScript servlet, note, the JavaScript properties might not be initialized yet: "); + } - printConfigIfConfigured(context, "Printing properties before Javascript servlet, note, the javascript properties might not be initialized yet: "); + private void loadProperties(final InputStream resourceStream) throws IOException { + final Properties properties = new Properties(); + properties.load(resourceStream); + CsrfGuard.load(properties); } /** @@ -92,57 +120,58 @@ * @param prefix The string used as a prefix when printing the configuration to the log * @see javax.servlet.ServletContext#log(String) */ - public static void printConfigIfConfigured(ServletContext context, String prefix) { - String printConfig = context.getInitParameter(CONFIG_PRINT_PARAM); + public static void printConfigIfConfigured(final ServletContext context, final String prefix) { + final CsrfGuard csrfGuard = CsrfGuard.getInstance(); - if (printConfig == null || "".equals(printConfig.trim())) { - printConfig = CsrfGuard.getInstance().isPrintConfig() ? "true" : null; + if (csrfGuard.isEnabled()) { + final String contextPrintConfig = context.getInitParameter(CONFIG_PRINT_PARAM); + final boolean shouldPrintConfig = StringUtils.isBlank(contextPrintConfig) ? csrfGuard.isPrintConfig() + : Boolean.parseBoolean(contextPrintConfig); + if (shouldPrintConfig) { + context.log(prefix + csrfGuard); + } + } else { + context.log("OWASP CSRFGuard is disabled."); } - - if (printConfig != null && Boolean.parseBoolean(printConfig)) { - context.log(prefix - + CsrfGuard.getInstance().toString()); - } } @Override - public void contextDestroyed(ServletContextEvent event) { - /** nothing to do **/ + public void contextDestroyed(final ServletContextEvent event) { + /* nothing to do */ } - private InputStream getResourceStream(String resourceName, ServletContext context, boolean failIfNotFound) throws IOException { - InputStream is = null; + private InputStream getResourceStream(final String resourceName, final ServletContext context, final boolean failIfNotFound) throws IOException { + InputStream inputStream; - /** try classpath **/ - is = getClass().getClassLoader().getResourceAsStream(resourceName); + /* try classpath */ + inputStream = getClass().getClassLoader().getResourceAsStream(resourceName); - /** try web context **/ - if (is == null) { - String fileName = context.getRealPath(resourceName); + /* try web context */ + if (inputStream == null) { + final String fileName = context.getRealPath(resourceName); if (fileName != null) { - File file = new File(fileName); + final File file = new File(fileName); if (file.exists()) { - is = new FileInputStream(fileName); + inputStream = new FileInputStream(fileName); } } } - /** try current directory **/ - if (is == null) { - File file = new File(resourceName); + /* try current directory */ + if (inputStream == null) { + final File file = new File(resourceName); if (file.exists()) { - is = new FileInputStream(resourceName); + inputStream = new FileInputStream(resourceName); } } - /** fail if still empty **/ - if (is == null && failIfNotFound) { + /* fail if still empty */ + if (inputStream == null && failIfNotFound) { throw new IOException(String.format("unable to locate resource - %s", resourceName)); } - return is; + return inputStream; } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfValidator.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfValidator.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/CsrfValidator.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,248 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard; + +import org.apache.commons.lang3.StringUtils; +import org.owasp.csrfguard.action.IAction; +import org.owasp.csrfguard.servlet.JavaScriptServlet; +import org.owasp.csrfguard.session.LogicalSession; +import org.owasp.csrfguard.token.businessobject.TokenBO; +import org.owasp.csrfguard.token.mapper.TokenMapper; +import org.owasp.csrfguard.token.service.TokenService; +import org.owasp.csrfguard.token.transferobject.TokenTO; +import org.owasp.csrfguard.util.CsrfGuardUtils; +import org.owasp.csrfguard.util.MessageConstants; +import org.owasp.csrfguard.util.RegexValidationUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Objects; +import java.util.Set; +import java.util.function.UnaryOperator; +import java.util.regex.Pattern; + +public final class CsrfValidator { + + private final CsrfGuard csrfGuard; + + private static final Logger LOGGER = LoggerFactory.getLogger(CsrfValidator.class); + + public CsrfValidator() { + this.csrfGuard = CsrfGuard.getInstance(); + } + + public boolean isValid(final HttpServletRequest request, final HttpServletResponse response) { + final boolean isValid; + + final String normalizedResourceURI = CsrfGuardUtils.normalizeResourceURI(request); + final ProtectionResult protectionResult = isProtectedPageAndMethod(request); + if (protectionResult.isProtected()) { + LOGGER.debug("CSRFGuard analyzing protected resource: '{}'", normalizedResourceURI); + isValid = isTokenValidInRequest(request, response, protectionResult.getResourceIdentifier()); + } else { + LOGGER.debug("Unprotected page: '{}'", normalizedResourceURI); + isValid = true; + } + + return isValid; + } + + public ProtectionResult isProtectedPageAndMethod(final String page, final String method) { + final String normalizedResourceUri = CsrfGuardUtils.normalizeResourceURI(page); + final ProtectionResult protectionResult = isProtectedPage(normalizedResourceUri); + + return (protectionResult.isProtected() && isProtectedMethod(method)) ? protectionResult + : new ProtectionResult(false, normalizedResourceUri); + } + + public ProtectionResult isProtectedPage(final String normalizedResourceUri) { + final ProtectionResult protectionResult; + + if (JavaScriptServlet.getJavascriptUris().contains(normalizedResourceUri)) { + /* if this is a javascript page, let it go through */ + protectionResult = new ProtectionResult(false, normalizedResourceUri); + } else if (this.csrfGuard.isProtectEnabled()) { + /* all links are unprotected, except the ones that were explicitly specified */ + protectionResult = isUriMatch(normalizedResourceUri, this.csrfGuard.getProtectedPages(), v -> v, false); + } else { + /* all links are protected, except the ones were explicitly excluded */ + protectionResult = isUriMatch(normalizedResourceUri, this.csrfGuard.getUnprotectedPages(), v -> new ProtectionResult(false, v.getResourceIdentifier()), true); + } + return protectionResult; + } + + private static boolean isUriPathMatch(final String configuredPageUri, final String requestUri) { + return configuredPageUri.equals("/*") || (configuredPageUri.endsWith("/*") && (configuredPageUri.regionMatches(0, requestUri, 0, configuredPageUri.length() - 2) + && ((requestUri.length() == (configuredPageUri.length() - 2)) || ('/' == requestUri.charAt(configuredPageUri.length() - 2))))); + } + + /** + * FIXME: taken from Tomcat - ApplicationFilterFactory#matchFiltersURL + */ + private static boolean isExtensionMatch(final String testPath, final String requestPath) { + final boolean result; + if (StringUtils.startsWith(testPath, "*.")) { + final int slash = requestPath.lastIndexOf('/'); + final int period = requestPath.lastIndexOf('.'); + + if ((slash >= 0) + && (period > slash) + && (period != requestPath.length() - 1) + && ((requestPath.length() - period) == (testPath.length() - 1))) { + result = testPath.regionMatches(2, requestPath, period + 1, testPath.length() - 2); + } else { + result = false; + } + } else { + result = false; + } + + return result; + } + + private ProtectionResult isUriMatch(final String normalizedResourceUri, final Set pages, final UnaryOperator operator, final boolean isProtected) { + for (final String page : pages) { + final ProtectionResult protectionResult = isUriMatch(page, normalizedResourceUri); + if (protectionResult.isProtected()) { + return operator.apply(protectionResult); + } + } + return new ProtectionResult(isProtected, normalizedResourceUri); + } + + private TokenService getTokenService() { + return new TokenService(this.csrfGuard); + } + + private ProtectionResult isProtectedPageAndMethod(final HttpServletRequest request) { + return isProtectedPageAndMethod(request.getRequestURI(), request.getMethod()); + } + + /** + * Whether or not the HTTP method is protected, i.e. should be checked for token. + * + * @param method The method to check for protection status + * @return true when the given method name is in the protected methods set and not in the unprotected methods set + */ + private boolean isProtectedMethod(final String method) { + boolean isProtected = true; + + final Set protectedMethods = this.csrfGuard.getProtectedMethods(); + if (!protectedMethods.isEmpty() && !protectedMethods.contains(method)) { + isProtected = false; + } + + final Set unprotectedMethods = this.csrfGuard.getUnprotectedMethods(); + if (!unprotectedMethods.isEmpty() && unprotectedMethods.contains(method)) { + isProtected = false; + } + + return isProtected; + } + + /** + * @param configuredPageUri the pattern to match. + * @param requestUri the current request path. + * @return {@code true} if {@code requestUri} matches {@code configuredPageUri}. + */ + private ProtectionResult isUriMatch(final String configuredPageUri, final String requestUri) { + if (Objects.nonNull(configuredPageUri)) { + if (configuredPageUri.equals(requestUri) || isUriPathMatch(configuredPageUri, requestUri) || isExtensionMatch(configuredPageUri, requestUri)) { + return new ProtectionResult(true, requestUri); + } else if (isUriRegexMatch(configuredPageUri, requestUri)) { + return new ProtectionResult(true, configuredPageUri); + } else { + return new ProtectionResult(false, requestUri); + } + } else { + return new ProtectionResult(false, requestUri); + } + } + + private boolean isUriRegexMatch(final String configuredPageUri, final String requestUri) { + return RegexValidationUtil.isTestPathRegex(configuredPageUri) && this.csrfGuard.getRegexPatternCache().computeIfAbsent(configuredPageUri, k -> Pattern.compile(configuredPageUri)) + .matcher(requestUri) + .matches(); + } + + private boolean isTokenValidInRequest(final HttpServletRequest request, final HttpServletResponse response, final String resourceIdentifier) { + boolean isValid = false; + + final CsrfGuard csrfGuard = CsrfGuard.getInstance(); + final LogicalSession logicalSession = csrfGuard.getLogicalSessionExtractor().extract(request); + + if (Objects.nonNull(logicalSession)) { + final TokenService tokenService = getTokenService(); + final String logicalSessionKey = logicalSession.getKey(); + final String masterToken = tokenService.getMasterToken(logicalSessionKey); + + if (Objects.nonNull(masterToken)) { + try { + final TokenBO tokenBO = tokenService.verifyToken(request, resourceIdentifier, logicalSessionKey, masterToken); + + final TokenTO tokenTO = csrfGuard.isRotateEnabled(request) ? tokenService.rotateUsedToken(logicalSessionKey, resourceIdentifier, tokenBO) + : TokenMapper.toTransferObject(tokenBO); + + CsrfGuardUtils.addResponseTokenHeader(csrfGuard, request, response, tokenTO); + + isValid = true; + } catch (final CsrfGuardException e) { + callActionsOnError(request, response, e); + } + } else { + callActionsOnError(request, response, new CsrfGuardException(MessageConstants.TOKEN_MISSING_FROM_STORAGE_MSG)); + } + } else { + callActionsOnError(request, response, new CsrfGuardException(MessageConstants.TOKEN_MISSING_FROM_STORAGE_MSG)); + } + + return isValid; + } + + /** + * Invoked when there was a CsrfGuardException such as a token mismatch error. + * Calls the configured actions. + * + * @param request The HttpServletRequest + * @param response The HttpServletResponse + * @param csrfGuardException The exception that triggered the actions call. Passed to the action. + * @see IAction#execute(HttpServletRequest, HttpServletResponse, CsrfGuardException, CsrfGuard) + */ + private void callActionsOnError(final HttpServletRequest request, final HttpServletResponse response, final CsrfGuardException csrfGuardException) { + for (final IAction action : this.csrfGuard.getActions()) { + try { + action.execute(request, response, csrfGuardException, this.csrfGuard); + } catch (final CsrfGuardException exception) { + LOGGER.error(String.format("Error while executing action '%s'", action.getName()), exception); + } + } + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/ProtectionResult.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/ProtectionResult.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/ProtectionResult.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,48 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard; + +public class ProtectionResult { + + private final boolean isProtected; + private final String resourceIdentifier; + + public ProtectionResult(final boolean isProtected, final String resourceIdentifier) { + this.isProtected = isProtected; + this.resourceIdentifier = resourceIdentifier; + } + + public boolean isProtected() { + return this.isProtected; + } + + public String getResourceIdentifier() { + return this.resourceIdentifier; + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/AbstractAction.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/AbstractAction.java (.../AbstractAction.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/AbstractAction.java (.../AbstractAction.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,36 +26,38 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.action; -import java.util.*; +import java.util.HashMap; +import java.util.Map; public abstract class AbstractAction implements IAction { private static final long serialVersionUID = -1654117674049587348L; private String name = null; - private Map parameters = new HashMap(); + private final Map parameters = new HashMap<>(); @Override - public void setName(String name) { + public void setName(final String name) { this.name = name; } @Override public String getName() { - return name; + return this.name; } @Override - public void setParameter(String name, String value) { - parameters.put(name, value); + public void setParameter(final String name, final String value) { + this.parameters.put(name, value); } @Override - public String getParameter(String parameterName) { - String value = parameters.get(parameterName); + public String getParameter(final String parameterName) { + final String value = this.parameters.get(parameterName); if (value == null) { throw new RuntimeException(String.format("unable to locate expected parameter %s", parameterName)); @@ -66,7 +68,6 @@ @Override public Map getParameterMap() { - return parameters; + return this.parameters; } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Empty.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Empty.java (.../Empty.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Empty.java (.../Empty.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,21 +26,24 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.action; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.owasp.csrfguard.CsrfGuard; import org.owasp.csrfguard.CsrfGuardException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * TODO document or why it is needed or remove this Action + */ public final class Empty extends AbstractAction { private static final long serialVersionUID = 3530383602177340966L; @Override - public void execute(HttpServletRequest request, HttpServletResponse response, CsrfGuardException csrfe, CsrfGuard csrfGuard) throws CsrfGuardException { + public void execute(final HttpServletRequest request, final HttpServletResponse response, final CsrfGuardException csrfGuardException, final CsrfGuard csrfGuard) throws CsrfGuardException { // nothing to do } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Error.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Error.java (.../Error.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Error.java (.../Error.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,30 +26,29 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.action; -import java.io.IOException; +import org.owasp.csrfguard.CsrfGuard; +import org.owasp.csrfguard.CsrfGuardException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; -import org.owasp.csrfguard.CsrfGuard; -import org.owasp.csrfguard.CsrfGuardException; - public final class Error extends AbstractAction { private static final long serialVersionUID = 5479074081984904252L; @Override - public void execute(HttpServletRequest request, HttpServletResponse response, CsrfGuardException csrfe, CsrfGuard csrfGuard) throws CsrfGuardException { - int code = Integer.parseInt(getParameter("Code")); - String message = getParameter("Message"); - + public void execute(final HttpServletRequest request, final HttpServletResponse response, final CsrfGuardException csrfGuardException, final CsrfGuard csrfGuard) throws CsrfGuardException { try { + final int code = Integer.parseInt(getParameter("Code")); + final String message = getParameter("Message"); + response.sendError(code, message); - } catch (IOException ioe) { - throw new CsrfGuardException(ioe); + } catch (final NumberFormatException | IOException e) { + throw new CsrfGuardException(e); } } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Forward.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Forward.java (.../Forward.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Forward.java (.../Forward.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,32 +26,29 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.action; -import java.io.IOException; +import org.owasp.csrfguard.CsrfGuard; +import org.owasp.csrfguard.CsrfGuardException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; -import org.owasp.csrfguard.CsrfGuard; -import org.owasp.csrfguard.CsrfGuardException; - public final class Forward extends AbstractAction { private static final long serialVersionUID = -3727752206497452347L; @Override - public void execute(HttpServletRequest request, HttpServletResponse response, CsrfGuardException csrfe, CsrfGuard csrfGuard) throws CsrfGuardException { - String errorPage = getParameter("Page"); + public void execute(final HttpServletRequest request, final HttpServletResponse response, final CsrfGuardException csrfGuardException, final CsrfGuard csrfGuard) throws CsrfGuardException { + final String errorPage = getParameter("Page"); try { request.getRequestDispatcher(errorPage).forward(request, response); - } catch (IOException ioe) { - throw new CsrfGuardException(ioe); - } catch (ServletException se) { - throw new CsrfGuardException(se); + } catch (final IOException | ServletException e) { + throw new CsrfGuardException(e); } } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/IAction.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/IAction.java (.../IAction.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/IAction.java (.../IAction.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,27 +26,61 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.action; +import org.owasp.csrfguard.CsrfGuard; +import org.owasp.csrfguard.CsrfGuardException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.io.Serializable; -import java.util.*; +import java.util.Map; -import javax.servlet.http.*; - -import org.owasp.csrfguard.*; - +/** + * Interface enabling interaction with Actions, that are invoked in case of a potential CSRF attack + */ public interface IAction extends Serializable { + /** + * Sets the name of the action + * + * @param name the name of the action + */ void setName(String name); + /** + * @return the name of the action + */ String getName(); + /** + * Sets a parameter with a custom name and value + * + * @param name the name of the parameter + * @param value the value of the parameter + */ void setParameter(String name, String value); + /** + * @param name the name of the parameter + * @return the configured parameter based on its name + */ String getParameter(String name); + /** + * @return the whole parameter map + */ Map getParameterMap(); - void execute(HttpServletRequest request, HttpServletResponse response, CsrfGuardException csrfe, CsrfGuard csrfGuard) throws CsrfGuardException; - + /** + * Executes this action. + * @param request the HTTP request that triggered a potential CSRF attack + * @param response the HTTP response object associated with the potentially malicious HTTP request + * @param csrfGuardException the CSRF Guard exception object + * @param csrfGuard the main CSRF Guard object, with access to inner workings of the solution + * + * @throws CsrfGuardException the exception type thrown in case of a potential CSRF attack + */ + void execute(HttpServletRequest request, HttpServletResponse response, CsrfGuardException csrfGuardException, CsrfGuard csrfGuard) throws CsrfGuardException; } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Invalidate.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Invalidate.java (.../Invalidate.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Invalidate.java (.../Invalidate.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,23 +26,28 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.action; -import javax.servlet.http.*; +import org.owasp.csrfguard.CsrfGuard; +import org.owasp.csrfguard.CsrfGuardException; +import org.owasp.csrfguard.session.LogicalSession; -import org.owasp.csrfguard.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Objects; public final class Invalidate extends AbstractAction { private static final long serialVersionUID = -3060679616261531773L; @Override - public void execute(HttpServletRequest request, HttpServletResponse response, CsrfGuardException csrfe, CsrfGuard csrfGuard) throws CsrfGuardException { - HttpSession session = request.getSession(false); + public void execute(final HttpServletRequest request, final HttpServletResponse response, final CsrfGuardException csrfGuardException, final CsrfGuard csrfGuard) throws CsrfGuardException { - if (session != null) { - session.invalidate(); + final LogicalSession logicalSession = csrfGuard.getLogicalSessionExtractor().extract(request); + + if (Objects.nonNull(logicalSession)) { + csrfGuard.getTokenService().invalidate(logicalSession); } } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Log.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Log.java (.../Log.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Log.java (.../Log.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,60 +26,72 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.action; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - +import org.apache.commons.lang3.StringUtils; import org.owasp.csrfguard.CsrfGuard; import org.owasp.csrfguard.CsrfGuardException; -import org.owasp.csrfguard.log.LogLevel; -import org.owasp.csrfguard.util.CsrfGuardUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.security.Principal; + public final class Log extends AbstractAction { - private static final long serialVersionUID = 8238761463376338707L; + private static final long serialVersionUID = 8238761463376338707L; - @Override - public void execute(HttpServletRequest request, HttpServletResponse response, CsrfGuardException csrfe, CsrfGuard csrfGuard) throws CsrfGuardException { - String logMessage = getParameter("Message"); + private static final Logger LOGGER = LoggerFactory.getLogger(Log.class); - /** Exception Information **/ - logMessage = logMessage.replace("%exception%", String.valueOf(csrfe)); - logMessage = logMessage.replace("%exception_message%", csrfe.getLocalizedMessage()); + @Override + public void execute(final HttpServletRequest request, final HttpServletResponse response, final CsrfGuardException csrfGuardException, final CsrfGuard csrfGuard) throws CsrfGuardException { + String logMessage = getParameter("Message"); - /** Remote Network Information **/ - logMessage = logMessage.replace("%remote_ip%", CsrfGuardUtils.defaultString(request.getRemoteAddr())); - logMessage = logMessage.replace("%remote_host%", CsrfGuardUtils.defaultString(request.getRemoteHost())); - logMessage = logMessage.replace("%remote_port%", String.valueOf(request.getRemotePort())); + /* Exception Information */ + logMessage = logMessage.replace("%exception%", String.valueOf(csrfGuardException)) + .replace("%exception_message%", csrfGuardException.getLocalizedMessage()); - /** Local Network Information **/ - logMessage = logMessage.replace("%local_ip%", CsrfGuardUtils.defaultString(request.getLocalAddr())); - logMessage = logMessage.replace("%local_host%", CsrfGuardUtils.defaultString(request.getLocalName())); - logMessage = logMessage.replace("%local_port%", String.valueOf(request.getLocalPort())); + /* Remote Network Information */ + logMessage = logMessage.replace("%remote_ip%", StringUtils.defaultString(request.getRemoteAddr())) + .replace("%remote_host%", StringUtils.defaultString(request.getRemoteHost())) + .replace("%remote_port%", String.valueOf(request.getRemotePort())); - /** Requested Resource Information **/ - logMessage = logMessage.replace("%request_method%", CsrfGuardUtils.defaultString(request.getMethod())); - logMessage = logMessage.replace("%request_uri%", CsrfGuardUtils.defaultString(request.getRequestURI())); - logMessage = logMessage.replace("%request_url%", request.getRequestURL().toString()); + /* Local Network Information */ + logMessage = logMessage.replace("%local_ip%", StringUtils.defaultString(request.getLocalAddr())) + .replace("%local_host%", StringUtils.defaultString(request.getLocalName())) + .replace("%local_port%", String.valueOf(request.getLocalPort())); - // JavaEE Principal Information - String user = request.getRemoteUser(); - if (user == null || "".equals(user.trim())) { - user = (String)request.getAttribute("REMOTE_USER"); - } - if (user == null || "".equals(user.trim())) { - if (request.getUserPrincipal() != null) { - user = request.getUserPrincipal().getName(); - } - } - if (user != null && !"".equals(user.trim())) { - logMessage = logMessage.replace("%user%", user); - } else { - logMessage = logMessage.replace("%user%", ""); - } + /* Requested Resource Information */ + logMessage = logMessage.replace("%request_method%", StringUtils.defaultString(request.getMethod())) + .replace("%request_uri%", StringUtils.defaultString(request.getRequestURI())) + .replace("%request_url%", request.getRequestURL().toString()); - csrfGuard.getLogger().log(LogLevel.Error, logMessage); - } - + logMessage = logMessage.replace("%user%", getUserName(request)); + + LOGGER.error(logMessage); + } + + private String getUserName(final HttpServletRequest request) { + // JavaEE Principal Information + String user = request.getRemoteUser(); + + if (StringUtils.isBlank(user)) { + user = (String) request.getAttribute("REMOTE_USER"); + } + + if (StringUtils.isBlank(user)) { + final Principal userPrincipal = request.getUserPrincipal(); + if (userPrincipal != null) { + user = userPrincipal.getName(); + } + } + + if (StringUtils.isBlank(user)) { + user = ""; + } + + return user; + } } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Redirect.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Redirect.java (.../Redirect.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Redirect.java (.../Redirect.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,29 +26,28 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.action; -import java.io.IOException; +import org.owasp.csrfguard.CsrfGuard; +import org.owasp.csrfguard.CsrfGuardException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; -import org.owasp.csrfguard.CsrfGuard; -import org.owasp.csrfguard.CsrfGuardException; - public final class Redirect extends AbstractAction { private static final long serialVersionUID = -2265693822259717332L; @Override - public void execute(HttpServletRequest request, HttpServletResponse response, CsrfGuardException csrfe, CsrfGuard csrfGuard) throws CsrfGuardException { - String errorPage = getParameter("Page"); + public void execute(final HttpServletRequest request, final HttpServletResponse response, final CsrfGuardException csrfGuardException, final CsrfGuard csrfGuard) throws CsrfGuardException { + final String errorPage = getParameter("Page"); try { response.sendRedirect(errorPage); - } catch (IOException ioe) { + } catch (final IOException ioe) { throw new CsrfGuardException(ioe); } } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/RequestAttribute.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/RequestAttribute.java (.../RequestAttribute.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/RequestAttribute.java (.../RequestAttribute.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,23 +26,23 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.action; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - import org.owasp.csrfguard.CsrfGuard; import org.owasp.csrfguard.CsrfGuardException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + public final class RequestAttribute extends AbstractAction { private static final long serialVersionUID = 6714855990116387348L; @Override - public void execute(HttpServletRequest request, HttpServletResponse response, CsrfGuardException csrfe, CsrfGuard csrfGuard) throws CsrfGuardException { - String attributeName = getParameter("AttributeName"); + public void execute(final HttpServletRequest request, final HttpServletResponse response, final CsrfGuardException csrfGuardException, final CsrfGuard csrfGuard) throws CsrfGuardException { + final String attributeName = getParameter("AttributeName"); - request.setAttribute(attributeName, csrfe); + request.setAttribute(attributeName, csrfGuardException); } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Rotate.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Rotate.java (.../Rotate.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/Rotate.java (.../Rotate.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,70 +26,29 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.action; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import org.owasp.csrfguard.CsrfGuard; +import org.owasp.csrfguard.CsrfGuardException; +import org.owasp.csrfguard.session.LogicalSession; +import org.owasp.csrfguard.token.storage.LogicalSessionExtractor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; +import java.util.Objects; -import org.owasp.csrfguard.CsrfGuard; -import org.owasp.csrfguard.CsrfGuardException; -import org.owasp.csrfguard.util.RandomGenerator; - public class Rotate extends AbstractAction { - private static final long serialVersionUID = -3164557586544451406L; + private static final long serialVersionUID = -3164557586544451406L; - @Override - public void execute(HttpServletRequest request, HttpServletResponse response, CsrfGuardException csrfe, CsrfGuard csrfGuard) throws CsrfGuardException { - HttpSession session = request.getSession(false); + @Override + public void execute(final HttpServletRequest request, final HttpServletResponse response, final CsrfGuardException csrfGuardException, final CsrfGuard csrfGuard) throws CsrfGuardException { + final LogicalSessionExtractor logicalSessionExtractor = csrfGuard.getLogicalSessionExtractor(); + final LogicalSession logicalSession = logicalSessionExtractor.extract(request); - if (session != null) { - updateSessionToken(session, csrfGuard); - - if (csrfGuard.isTokenPerPageEnabled()) { - updatePageTokens(session, csrfGuard); - } - } - } - - private void updateSessionToken(HttpSession session, CsrfGuard csrfGuard) throws CsrfGuardException { - String token; - - try { - token = RandomGenerator.generateRandomId(csrfGuard.getPrng(), - csrfGuard.getTokenLength()); - } catch (Exception e) { - throw new CsrfGuardException(String.format("unable to generate the random token - %s", e.getLocalizedMessage()), e); - } - - session.setAttribute(csrfGuard.getSessionKey(), token); - } - - private void updatePageTokens(HttpSession session, CsrfGuard csrfGuard) throws CsrfGuardException { - @SuppressWarnings("unchecked") - Map pageTokens = (Map) session.getAttribute(CsrfGuard.PAGE_TOKENS_KEY); - List pages = new ArrayList(); - - if(pageTokens != null) { - pages.addAll(pageTokens.keySet()); - } - - for (String page : pages) { - String token; - - try { - token = RandomGenerator.generateRandomId(csrfGuard.getPrng(), csrfGuard.getTokenLength()); - } catch (Exception e) { - throw new CsrfGuardException(String.format("unable to generate the random token - %s", e.getLocalizedMessage()), e); - } - - pageTokens.put(page, token); - } - } - + if (Objects.nonNull(logicalSession)) { + csrfGuard.getTokenService().rotateAllTokens(logicalSession.getKey()); + } + } } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/SessionAttribute.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/SessionAttribute.java (.../SessionAttribute.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/action/SessionAttribute.java (.../SessionAttribute.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,24 +26,33 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.action; -import javax.servlet.http.*; +import org.owasp.csrfguard.CsrfGuard; +import org.owasp.csrfguard.CsrfGuardException; +import org.owasp.csrfguard.config.properties.ConfigParameters; +import org.owasp.csrfguard.session.LogicalSession; -import org.owasp.csrfguard.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Objects; +/** + * Saves the thrown CsrfGuardException object after a token validation to the session, bound to the attribute name extracted from the properties file. + */ public final class SessionAttribute extends AbstractAction { private static final long serialVersionUID = 1367492926060283228L; @Override - public void execute(HttpServletRequest request, HttpServletResponse response, CsrfGuardException csrfe, CsrfGuard csrfGuard) throws CsrfGuardException { - String attributeName = getParameter("AttributeName"); - HttpSession session = request.getSession(false); + public void execute(final HttpServletRequest request, final HttpServletResponse response, final CsrfGuardException csrfGuardException, final CsrfGuard csrfGuard) { + final String attributeName = getParameter(ConfigParameters.ACTION_ATTRIBUTE_NAME); - if (session != null) { - session.setAttribute(attributeName, csrfe); + final LogicalSession logicalSession = CsrfGuard.getInstance().getLogicalSessionExtractor().extract(request); + + if (Objects.nonNull(logicalSession)) { + logicalSession.setAttribute(attributeName, csrfGuardException); } } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/ConfigurationProvider.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/ConfigurationProvider.java (.../ConfigurationProvider.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/ConfigurationProvider.java (.../ConfigurationProvider.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,20 +1,20 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - *

+ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: - *

- * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. - *

+ * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE @@ -26,124 +26,255 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.config; +import org.owasp.csrfguard.action.IAction; +import org.owasp.csrfguard.token.storage.LogicalSessionExtractor; +import org.owasp.csrfguard.token.storage.TokenHolder; + import java.security.SecureRandom; +import java.time.Duration; import java.util.List; import java.util.Set; import java.util.regex.Pattern; -import org.owasp.csrfguard.action.IAction; -import org.owasp.csrfguard.log.ILogger; - +/** + * Interface that enables interaction with configuration providers + */ public interface ConfigurationProvider { - /** @return true when this configuration provider can be cached for a minute, i.e. it is all setup */ + /** + * @return true when this configuration provider can be cached for a minute, i.e. it is all setup + */ boolean isCacheable(); + /** + * @return true if the display of the CSRF configuration at start-up was requested, false otherwise + */ boolean isPrintConfig(); - ILogger getLogger(); - + /** + * @return the name of the CSRF token, used in the DOM + */ String getTokenName(); /** * If csrf guard filter should check even if there is no session for the user * Note: this changed around 2014/04, the default behavior used to be to * not check if there is no session. If you want the legacy behavior (if your app * is not susceptible to CSRF if the user has no session), set this to false + * * @return true when validation is performed even when no session exists */ boolean isValidateWhenNoSessionExists(); + /** + * This parameter controls how long a generated token should be. + * @return the configured length of the token + */ int getTokenLength(); + /** + * @return true if token rotation was configured, false otherwise + */ boolean isRotateEnabled(); + /** + * @return true if token-per-page was configured, false otherwise + */ boolean isTokenPerPageEnabled(); + /** + * @return true if pre-generation of page tokens has been configured, false otherwise + */ boolean isTokenPerPagePrecreateEnabled(); + /** + * @return the pseudo-random number generator instance, which is used to generate CSRF tokens + */ SecureRandom getPrng(); + /** + * @return the path of a page to which a new user (with no logical session) will be redirected + */ String getNewTokenLandingPage(); + /** + * @return true if new users (without a logical session) should be redirected to a pre-configured page + * @see ConfigurationProvider#getNewTokenLandingPage() + */ boolean isUseNewTokenLandingPage(); + /** + * @return true if Asynchronous JavaScript And XML (AJAX) support was configured, false otherwise + */ boolean isAjaxEnabled(); + /** + * The default behavior of CSRFGuard is to protect all pages. Pages marked as unprotected will not be protected.
+ * If the Protect property is enabled, this behavior is reversed. Pages must be marked as protected to be protected. + * All other pages will not be protected. This is useful when the CsrfGuardFilter is aggressively mapped (ex: /*), + * but you only want to protect a few pages. + * + * @return false if all pages are protected, true if pages are required to be explicit protected + */ boolean isProtectEnabled(); - String getSessionKey(); + /** + * @return whether the legacy Synchronous AJAX requests are enabled + */ + boolean isForceSynchronousAjax(); + /** + * @return the configured set of all protected pages + */ Set getProtectedPages(); + /** + * @return the configured set of all un-protected pages + */ Set getUnprotectedPages(); + /** + * @return the configured set of protected HTTP methods (verbs) + */ Set getProtectedMethods(); /** * if there are methods here, then all other HTTP methods are protected and these (e.g. GET) are unprotected + * * @return the unprotected methods */ Set getUnprotectedMethods(); /** * if the filter is enabled + * * @return is csrf guard filter is enabled */ boolean isEnabled(); + /** + * @return the configured list of actions to be executed in case of a potential CSRF attack + */ List getActions(); + /** + * @return the overridden path to the configured CSRFGuard JavaScript logic, or null if the default is used + */ String getJavascriptSourceFile(); + /** + * @return true if tokens should only be injected into links that have the same domain from which the HTML originates, + * false if subdomains are also permitted + */ boolean isJavascriptDomainStrict(); + /** + * TODO Currently not configurable through the properties! + * + * @return the configured domain, whose resources are intended be decorated with CSRF tokens + */ String getDomainOrigin(); + /** + * @return the configured JavaScript cache control + */ String getJavascriptCacheControl(); + /** + * @return the configured JavaScript "Referer" pattern to be used + */ Pattern getJavascriptRefererPattern(); /** + * JavaScript configuration parameters can be set/overwritten via the servlet configuration. + * This method is intended to trigger the initialization of the JavaScript parameters, if/after the JavaScript servlet is initialized. + */ + void initializeJavaScriptConfiguration(); + + /** * if the token should be injected in GET forms (which will be on the URL) * if the HTTP method GET is unprotected, then this should likely be false - * @return true if the token should be injected in GET forms via Javascript + * + * @return true if the token should be injected in GET forms via Javascript */ boolean isJavascriptInjectGetForms(); /** * if the token should be injected in the action in forms * note, if injectIntoForms is true, then this might not need to be true + * * @return if inject */ boolean isJavascriptInjectFormAttributes(); + /** + * @return true if injecting tokens into JavaScript forms was configured + */ boolean isJavascriptInjectIntoForms(); /** - * if the referer to the javascript must match match the protocol of the domain + * if the referer to the javascript must match the protocol of the domain + * * @return true if the javascript must match the protocol of the domain */ boolean isJavascriptRefererMatchProtocol(); /** * if the referer to the javascript must match domain - * @return true if the javascript must match domain + * + * @return true if the javascript must match domain */ boolean isJavascriptRefererMatchDomain(); + /** + * @return true if injecting tokens into HTML attributes was configured + */ boolean isJavascriptInjectIntoAttributes(); + /** + * @return true if injecting tokens into dynamically injected DOM nodes was configured + */ + boolean isJavascriptInjectIntoDynamicallyCreatedNodes(); + + /** + * @return the name of the JavaScript dynamic node creation event, if the functionality was configured + */ + String getJavascriptDynamicNodeCreationEventName(); + + /** + * TODO document + * + * @return the configured value of the "X-Requested-With" header + */ String getJavascriptXrequestedWith(); + /** + * @return the content of the template JavaScript code, on which the JavaScript configurations will be applied + */ String getJavascriptTemplateCode(); /** - * example:"js,css,gif,png,ico,jpg" - * @return + * example: "js,css,gif,png,ico,jpg" + * + * @return the configured list of un-protected, comma separated extensions */ String getJavascriptUnprotectedExtensions(); + /** + * @return the configured TokenHolder instance + */ + TokenHolder getTokenHolder(); + + /** + * @return the configured LogicalSessionExtractor + */ + LogicalSessionExtractor getLogicalSessionExtractor(); + + /** + * @return the configured page token synchronization tolerance + */ + Duration getPageTokenSynchronizationTolerance(); } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/ConfigurationProviderFactory.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/ConfigurationProviderFactory.java (.../ConfigurationProviderFactory.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/ConfigurationProviderFactory.java (.../ConfigurationProviderFactory.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,4 +1,33 @@ -/** +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* * @author mchyzer * $Id$ */ @@ -18,5 +47,4 @@ * @return the configuration */ ConfigurationProvider retrieveConfiguration(Properties properties); - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/NullConfigurationProvider.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/NullConfigurationProvider.java (.../NullConfigurationProvider.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/NullConfigurationProvider.java (.../NullConfigurationProvider.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,257 +26,230 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.config; +import org.owasp.csrfguard.action.IAction; +import org.owasp.csrfguard.config.properties.ConfigParameters; +import org.owasp.csrfguard.token.storage.LogicalSessionExtractor; +import org.owasp.csrfguard.token.storage.TokenHolder; + import java.security.SecureRandom; +import java.time.Duration; import java.util.Collections; import java.util.List; import java.util.Set; import java.util.regex.Pattern; -import org.owasp.csrfguard.action.IAction; -import org.owasp.csrfguard.log.ConsoleLogger; -import org.owasp.csrfguard.log.ILogger; - /** - * ConfigurationProvider which returns all null or empty values (except for the logger). + * {@link ConfigurationProvider} which returns all null or empty values (except for the logger). * Used before initialization has occurred. */ public final class NullConfigurationProvider implements ConfigurationProvider { - private static final ILogger logger = new ConsoleLogger(); - - public NullConfigurationProvider() { - } + public NullConfigurationProvider() {} - @Override - public ILogger getLogger() { - return logger; - } + @Override + public boolean isCacheable() { + return true; + } - @Override - public String getTokenName() { - return null; - } + @Override + public boolean isPrintConfig() { + return false; + } - @Override - public int getTokenLength() { - return 0; - } + @Override + public String getTokenName() { + return null; + } - @Override - public boolean isRotateEnabled() { - return false; - } + @Override + public boolean isValidateWhenNoSessionExists() { + return false; + } - @Override - public boolean isTokenPerPageEnabled() { - return false; - } + @Override + public int getTokenLength() { + return 0; + } - @Override - public boolean isTokenPerPagePrecreateEnabled() { - return false; - } + @Override + public boolean isRotateEnabled() { + return false; + } - @Override - public SecureRandom getPrng() { - try { - return SecureRandom.getInstance("SHA1PRNG", "SUN"); - } catch (Exception e) { - throw new RuntimeException(e); - } - } + @Override + public boolean isTokenPerPageEnabled() { + return false; + } - @Override - public String getNewTokenLandingPage() { - return null; - } + @Override + public boolean isTokenPerPagePrecreateEnabled() { + return false; + } - @Override - public boolean isUseNewTokenLandingPage() { - return false; - } + @Override + public SecureRandom getPrng() { + try { + return SecureRandom.getInstance(ConfigParameters.DEFAULT_PRNG.getValue(), ConfigParameters.DEFAULT_PRNG.getKey()); + } catch (final Exception e) { + throw new RuntimeException(e); + } + } - @Override - public boolean isAjaxEnabled() { - return false; - } + @Override + public String getNewTokenLandingPage() { + return null; + } - @Override - public boolean isProtectEnabled() { - return false; - } + @Override + public boolean isUseNewTokenLandingPage() { + return false; + } - @Override - public String getSessionKey() { - return null; - } + @Override + public boolean isAjaxEnabled() { + return false; + } - @Override - public Set getProtectedPages() { - return Collections.emptySet(); - } + @Override + public boolean isProtectEnabled() { + return false; + } - @Override - public Set getUnprotectedPages() { - return Collections.emptySet(); - } + @Override + public boolean isForceSynchronousAjax() { + return false; + } - @Override - public Set getProtectedMethods() { - return Collections.emptySet(); - } + @Override + public Set getProtectedPages() { + return Collections.emptySet(); + } - @Override - public List getActions() { - return Collections.emptyList(); - } + @Override + public Set getUnprotectedPages() { + return Collections.emptySet(); + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isPrintConfig() - */ - @Override - public boolean isPrintConfig() { - return false; - } + @Override + public Set getProtectedMethods() { + return Collections.emptySet(); + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getJavascriptSourceFile() - */ - @Override - public String getJavascriptSourceFile() { - return null; - } + @Override + public Set getUnprotectedMethods() { + return Collections.emptySet(); + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptDomainStrict() - */ - @Override - public boolean isJavascriptDomainStrict() { - return false; - } + @Override + public boolean isEnabled() { + return false; + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getJavascriptCacheControl() - */ - @Override - public String getJavascriptCacheControl() { - return null; - } + @Override + public List getActions() { + return Collections.emptyList(); + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getJavascriptRefererPattern() - */ - @Override - public Pattern getJavascriptRefererPattern() { - return null; - } + @Override + public String getJavascriptSourceFile() { + return null; + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptInjectIntoForms() - */ - @Override - public boolean isJavascriptInjectIntoForms() { - return false; - } + @Override + public boolean isJavascriptDomainStrict() { + return false; + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptInjectIntoAttributes() - */ - @Override - public boolean isJavascriptInjectIntoAttributes() { - return false; - } + @Override + public String getDomainOrigin() { + return null; + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getJavascriptXrequestedWith() - */ - @Override - public String getJavascriptXrequestedWith() { - return null; - } + @Override + public String getJavascriptCacheControl() { + return null; + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getJavascriptTemplateCode() - */ - @Override - public String getJavascriptTemplateCode() { - return null; - } + @Override + public Pattern getJavascriptRefererPattern() { + return null; + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isCacheable() - */ - public boolean isCacheable() { - return true; - } + @Override + public void initializeJavaScriptConfiguration() { + // do nothing + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getUnprotectedMethods() - */ - public Set getUnprotectedMethods() { - return Collections.emptySet(); - } + @Override + public boolean isJavascriptInjectGetForms() { + return false; + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptRefererMatchProtocol() - */ - @Override - public boolean isJavascriptRefererMatchProtocol() { - return false; - } + @Override + public boolean isJavascriptInjectFormAttributes() { + return false; + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptRefererMatchDomain() - */ - @Override - public boolean isJavascriptRefererMatchDomain() { - return false; - } + @Override + public boolean isJavascriptInjectIntoForms() { + return false; + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isEnabled() - */ - @Override - public boolean isEnabled() { - return false; - } + @Override + public boolean isJavascriptRefererMatchProtocol() { + return false; + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isValidateWhenNoSessionExists() - */ - @Override - public boolean isValidateWhenNoSessionExists() { - return false; - } + @Override + public boolean isJavascriptRefererMatchDomain() { + return false; + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptInjectGetForms() - */ - public boolean isJavascriptInjectGetForms() { - return false; - } + @Override + public boolean isJavascriptInjectIntoAttributes() { + return false; + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptInjectFormAttributes() - */ - public boolean isJavascriptInjectFormAttributes() { - return false; - } + @Override + public boolean isJavascriptInjectIntoDynamicallyCreatedNodes() { + return false; + } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getDomainOrigin() - */ - @Override - public String getDomainOrigin() { - return null; - } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getJavascriptUnprotectedExtensions() - */ - @Override - public String getJavascriptUnprotectedExtensions() { - return null; - } + @Override + public String getJavascriptDynamicNodeCreationEventName() { + return null; + } + + @Override + public String getJavascriptXrequestedWith() { + return null; + } + + @Override + public String getJavascriptTemplateCode() { + return null; + } + + @Override + public String getJavascriptUnprotectedExtensions() { + return null; + } + + @Override + public TokenHolder getTokenHolder() { + return null; + } + + @Override + public LogicalSessionExtractor getLogicalSessionExtractor() { + return null; + } + + @Override + public Duration getPageTokenSynchronizationTolerance() { + return null; + } } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/NullConfigurationProviderFactory.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/NullConfigurationProviderFactory.java (.../NullConfigurationProviderFactory.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/NullConfigurationProviderFactory.java (.../NullConfigurationProviderFactory.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,36 +1,53 @@ -/** - * @author mchyzer - * $Id$ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.config; import java.util.Properties; /** - * + * TODO document */ -public class NullConfigurationProviderFactory implements - ConfigurationProviderFactory { +public class NullConfigurationProviderFactory implements ConfigurationProviderFactory { - /** - * - */ - public NullConfigurationProviderFactory() { - } + public NullConfigurationProviderFactory() {} /** - * cache this it doesnt change + * cache this it doesn't change */ private static ConfigurationProvider configurationProvider = null; - /** - * @see org.owasp.csrfguard.config.ConfigurationProviderFactory#retrieveConfiguration(java.util.Properties) - */ - public ConfigurationProvider retrieveConfiguration(Properties properties) { + @Override + public ConfigurationProvider retrieveConfiguration(final Properties properties) { if (configurationProvider == null) { configurationProvider = new NullConfigurationProvider(); } return configurationProvider; } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/PropertiesConfigurationProvider.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/PropertiesConfigurationProvider.java (.../PropertiesConfigurationProvider.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/PropertiesConfigurationProvider.java (.../PropertiesConfigurationProvider.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,593 +26,624 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.config; -import java.io.IOException; -import java.security.SecureRandom; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.regex.Pattern; - -import javax.servlet.ServletConfig; - -import org.owasp.csrfguard.CsrfGuardServletContextListener; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; import org.owasp.csrfguard.action.IAction; -import org.owasp.csrfguard.log.ILogger; +import org.owasp.csrfguard.config.properties.ConfigParameters; +import org.owasp.csrfguard.config.properties.HttpMethod; +import org.owasp.csrfguard.config.properties.PropertyUtils; +import org.owasp.csrfguard.config.properties.javascript.JavaScriptConfigParameters; +import org.owasp.csrfguard.config.properties.javascript.JsConfigParameter; import org.owasp.csrfguard.servlet.JavaScriptServlet; +import org.owasp.csrfguard.token.storage.LogicalSessionExtractor; +import org.owasp.csrfguard.token.storage.TokenHolder; import org.owasp.csrfguard.util.CsrfGuardUtils; +import org.owasp.csrfguard.util.RegexValidationUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import javax.servlet.ServletConfig; +import java.io.IOException; +import java.security.*; +import java.time.Duration; +import java.util.*; +import java.util.function.IntPredicate; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + /** - * ConfifgurationProvider based on a java.util.Properties object. - * + * {@link ConfigurationProvider} based on a {@link java.util.Properties} object. */ public class PropertiesConfigurationProvider implements ConfigurationProvider { - private final static String ACTION_PREFIX = "org.owasp.csrfguard.action."; + private static final Logger LOGGER = LoggerFactory.getLogger(PropertiesConfigurationProvider.class); - private final static String PROTECTED_PAGE_PREFIX = "org.owasp.csrfguard.protected."; - - private final static String UNPROTECTED_PAGE_PREFIX = "org.owasp.csrfguard.unprotected."; + private final Set protectedPages; - private final ILogger logger; + private final Set unprotectedPages; - private final String tokenName; + private final Set protectedMethods; - private final int tokenLength; + private final Set unprotectedMethods; - private final boolean rotate; + private final List actions; + private final Properties propertiesCache; + private final boolean enabled; - - private final boolean tokenPerPage; - private final boolean tokenPerPagePrecreate; + private String tokenName; - private final boolean printConfig; - - private final SecureRandom prng; + private int tokenLength; - private final String newTokenLandingPage; + private boolean rotate; - private final boolean useNewTokenLandingPage; + private boolean tokenPerPage; - private final boolean ajax; - - private final boolean protect; - - private final String sessionKey; - - private final Set protectedPages; + private boolean tokenPerPagePrecreate; - private final Set unprotectedPages; + private boolean printConfig; - private final Set protectedMethods; + private SecureRandom prng; - private final Set unprotectedMethods; + private String newTokenLandingPage; - private final List actions; - - private Properties propertiesCache; - + private boolean useNewTokenLandingPage; + + private boolean ajax; + + private boolean protect; + + private boolean forceSynchronousAjax; + private String domainOrigin; - - public PropertiesConfigurationProvider(Properties properties) { + + private Duration pageTokenSynchronizationTolerance; + + private boolean validationWhenNoSessionExists; + + private boolean javascriptParamsInitialized = false; + + private String javascriptTemplateCode; + + private String javascriptSourceFile; + + private boolean javascriptDomainStrict; + + private String javascriptCacheControl; + + private Pattern javascriptRefererPattern; + + private boolean javascriptInjectIntoForms; + + private boolean javascriptRefererMatchProtocol; + + private boolean javascriptInjectIntoAttributes; + + private boolean isJavascriptInjectIntoDynamicallyCreatedNodes; + + private String javascriptDynamicNodeCreationEventName; + + private String javascriptXrequestedWith; + + private boolean javascriptInjectGetForms; + + private boolean javascriptRefererMatchDomain; + + private boolean javascriptInjectFormAttributes; + + private String javascriptUnprotectedExtensions; + + private LogicalSessionExtractor logicalSessionExtractor; + + private TokenHolder tokenHolder; + + public PropertiesConfigurationProvider(final Properties properties) { try { this.propertiesCache = properties; - actions = new ArrayList(); - protectedPages = new HashSet(); - unprotectedPages = new HashSet(); - protectedMethods = new HashSet(); - unprotectedMethods = new HashSet(); - /** load simple properties **/ - logger = (ILogger) Class.forName(propertyString(properties, "org.owasp.csrfguard.Logger", "org.owasp.csrfguard.log.ConsoleLogger")).newInstance(); - tokenName = propertyString(properties, "org.owasp.csrfguard.TokenName", "OWASP-CSRFGUARD"); - tokenLength = Integer.parseInt(propertyString(properties, "org.owasp.csrfguard.TokenLength", "32")); - rotate = Boolean.valueOf(propertyString(properties, "org.owasp.csrfguard.Rotate", "false")); - tokenPerPage = Boolean.valueOf(propertyString(properties, "org.owasp.csrfguard.TokenPerPage", "false")); + this.actions = new ArrayList<>(); + this.protectedPages = new HashSet<>(); + this.unprotectedPages = new HashSet<>(); + this.protectedMethods = new HashSet<>(); + this.unprotectedMethods = new HashSet<>(); - this.validationWhenNoSessionExists = Boolean.valueOf(propertyString(properties, "org.owasp.csrfguard.ValidateWhenNoSessionExists", "true")); - this.domainOrigin = propertyString(properties, "org.owasp.csrfguard.domainOrigin", null); - tokenPerPagePrecreate = Boolean.valueOf(propertyString(properties, "org.owasp.csrfguard.TokenPerPagePrecreate", "false")); - prng = SecureRandom.getInstance(propertyString(properties, "org.owasp.csrfguard.PRNG", "SHA1PRNG"), propertyString(properties, "org.owasp.csrfguard.PRNG.Provider", "SUN")); - newTokenLandingPage = propertyString(properties, "org.owasp.csrfguard.NewTokenLandingPage"); - - printConfig = Boolean.valueOf(propertyString(properties, "org.owasp.csrfguard.Config.Print", "false")); + this.enabled = PropertyUtils.getProperty(properties, ConfigParameters.CSRFGUARD_ENABLED); - this.enabled = Boolean.valueOf(propertyString(properties, "org.owasp.csrfguard.Enabled", "true")); - - //default to false if newTokenLandingPage is not set; default to true if set. - if (newTokenLandingPage == null) { - useNewTokenLandingPage = Boolean.valueOf(propertyString(properties, "org.owasp.csrfguard.UseNewTokenLandingPage", "false")); - } else { - useNewTokenLandingPage = Boolean.valueOf(propertyString(properties, "org.owasp.csrfguard.UseNewTokenLandingPage", "true")); - } - sessionKey = propertyString(properties, "org.owasp.csrfguard.SessionKey", "OWASP_CSRFGUARD_KEY"); - ajax = Boolean.valueOf(propertyString(properties, "org.owasp.csrfguard.Ajax", "false")); - protect = Boolean.valueOf(propertyString(properties, "org.owasp.csrfguard.Protect", "false")); - - /** first pass: instantiate actions **/ - Map actionsMap = new HashMap(); - - for (Object obj : properties.keySet()) { - String key = (String) obj; - - if (key.startsWith(ACTION_PREFIX)) { - String directive = key.substring(ACTION_PREFIX.length()); - int index = directive.indexOf('.'); - - /** action name/class **/ - if (index < 0) { - String actionClass = propertyString(properties, key); - IAction action = (IAction) Class.forName(actionClass).newInstance(); - - action.setName(directive); - actionsMap.put(action.getName(), action); - actions.add(action); - } - } - } - - /** second pass: initialize action parameters **/ - for (Object obj : properties.keySet()) { - String key = (String) obj; - - if (key.startsWith(ACTION_PREFIX)) { - String directive = key.substring(ACTION_PREFIX.length()); - int index = directive.indexOf('.'); - - /** action name/class **/ - if (index >= 0) { - String actionName = directive.substring(0, index); - IAction action = actionsMap.get(actionName); - - if (action == null) { - throw new IOException(String.format("action class %s has not yet been specified", actionName)); - } - - String parameterName = directive.substring(index + 1); - String parameterValue = propertyString(properties, key); - - action.setParameter(parameterName, parameterValue); - } - } - } - - /** ensure at least one action was defined **/ - if (actions.size() <= 0) { - throw new IOException("failure to define at least one action"); - } - - /** initialize protected, unprotected pages **/ - for (Object obj : properties.keySet()) { - String key = (String) obj; - - if (key.startsWith(PROTECTED_PAGE_PREFIX)) { - String directive = key.substring(PROTECTED_PAGE_PREFIX.length()); - int index = directive.indexOf('.'); - - /** page name/class **/ - if (index < 0) { - String pageUri = propertyString(properties, key); - - protectedPages.add(pageUri); - } - } - - if (key.startsWith(UNPROTECTED_PAGE_PREFIX)) { - String directive = key.substring(UNPROTECTED_PAGE_PREFIX.length()); - int index = directive.indexOf('.'); - - /** page name/class **/ - if (index < 0) { - String pageUri = propertyString(properties, key); - - unprotectedPages.add(pageUri); - } - } - } - - /** initialize protected methods **/ - String methodList = propertyString(properties, "org.owasp.csrfguard.ProtectedMethods"); - if (methodList != null && methodList.trim().length() != 0) { - for (String method : methodList.split(",")) { - protectedMethods.add(method.trim()); - } - } - /** initialize unprotected methods **/ - methodList = propertyString(properties, "org.owasp.csrfguard.UnprotectedMethods"); - if (methodList != null && methodList.trim().length() != 0) { - for (String method : methodList.split(",")) { - unprotectedMethods.add(method.trim()); - } - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - private boolean javascriptParamsInitted = false; - - private void javascriptInitParamsIfNeeded() { - if (!this.javascriptParamsInitted) { - ServletConfig servletConfig = JavaScriptServlet.getStaticServletConfig(); - - if (servletConfig != null) { - - this.javascriptCacheControl = CsrfGuardUtils.getInitParameter(servletConfig, "cache-control", - propertyString(this.propertiesCache, "org.owasp.csrfguard.JavascriptServlet.cacheControl"), "private, maxage=28800"); - this.javascriptDomainStrict = Boolean.valueOf(CsrfGuardUtils.getInitParameter(servletConfig, "domain-strict", - propertyString(this.propertiesCache, "org.owasp.csrfguard.JavascriptServlet.domainStrict"), "true")); - this.javascriptInjectIntoAttributes = Boolean.valueOf(CsrfGuardUtils.getInitParameter(servletConfig, "inject-into-attributes", - propertyString(this.propertiesCache, "org.owasp.csrfguard.JavascriptServlet.injectIntoAttributes"), "true")); + if (this.enabled) { + this.tokenName = PropertyUtils.getProperty(properties, ConfigParameters.TOKEN_NAME); + this.tokenLength = getTokenLength(properties); + this.rotate = PropertyUtils.getProperty(properties, ConfigParameters.ROTATE); + this.tokenPerPage = PropertyUtils.getProperty(properties, ConfigParameters.TOKEN_PER_PAGE); - this.javascriptInjectGetForms = Boolean.valueOf(CsrfGuardUtils.getInitParameter(servletConfig, "inject-get-forms", - propertyString(this.propertiesCache, "org.owasp.csrfguard.JavascriptServlet.injectGetForms"), "true")); + this.validationWhenNoSessionExists = PropertyUtils.getProperty(properties, ConfigParameters.VALIDATE_WHEN_NO_SESSION_EXISTS); + this.domainOrigin = PropertyUtils.getProperty(properties, ConfigParameters.DOMAIN_ORIGIN); + this.tokenPerPagePrecreate = PropertyUtils.getProperty(properties, ConfigParameters.TOKEN_PER_PAGE_PRECREATE); - this.javascriptInjectFormAttributes = Boolean.valueOf(CsrfGuardUtils.getInitParameter(servletConfig, "inject-form-attributes", - propertyString(this.propertiesCache, "org.owasp.csrfguard.JavascriptServlet.injectFormAttributes"), "true")); + this.prng = getSecureRandomInstance(properties); - this.javascriptInjectIntoForms = Boolean.valueOf(CsrfGuardUtils.getInitParameter(servletConfig, "inject-into-forms", - propertyString(this.propertiesCache, "org.owasp.csrfguard.JavascriptServlet.injectIntoForms"), "true")); - - this.javascriptRefererPattern = Pattern.compile(CsrfGuardUtils.getInitParameter(servletConfig, "referer-pattern", - propertyString(this.propertiesCache, "org.owasp.csrfguard.JavascriptServlet.refererPattern"), ".*")); + this.printConfig = PropertyUtils.getProperty(properties, ConfigParameters.PRINT_ENABLED); - this.javascriptRefererMatchProtocol = Boolean.valueOf(CsrfGuardUtils.getInitParameter(servletConfig, "referer-match-protocol", - propertyString(this.propertiesCache, "org.owasp.csrfguard.JavascriptServlet.refererMatchProtocol"), "true")); + this.protect = PropertyUtils.getProperty(properties, ConfigParameters.CSRFGUARD_PROTECT); + this.forceSynchronousAjax = PropertyUtils.getProperty(properties, ConfigParameters.FORCE_SYNCHRONOUS_AJAX); - this.javascriptRefererMatchDomain = Boolean.valueOf(CsrfGuardUtils.getInitParameter(servletConfig, "referer-match-domain", - propertyString(this.propertiesCache, "org.owasp.csrfguard.JavascriptServlet.refererMatchDomain"), "true")); - - /* unprotectedExtensions - default to none unless specified */ - this.javascriptUnprotectedExtensions = CsrfGuardUtils.getInitParameter(servletConfig, "unprotected-extensions", - propertyString(this.propertiesCache, "org.owasp.csrfguard.JavascriptServlet.UnprotectedExtensions"), ""); + this.newTokenLandingPage = PropertyUtils.getProperty(properties, ConfigParameters.NEW_TOKEN_LANDING_PAGE); + this.useNewTokenLandingPage = PropertyUtils.getProperty(properties, ConfigParameters.getUseNewTokenLandingPage(this.newTokenLandingPage)); - this.javascriptSourceFile = CsrfGuardUtils.getInitParameter(servletConfig, "source-file", - propertyString(this.propertiesCache, "org.owasp.csrfguard.JavascriptServlet.sourceFile"), null); - this.javascriptXrequestedWith = CsrfGuardUtils.getInitParameter(servletConfig, "x-requested-with", - propertyString(this.propertiesCache, "org.owasp.csrfguard.JavascriptServlet.xRequestedWith"), "OWASP CSRFGuard Project"); - if(this.javascriptSourceFile == null) { - this.javascriptTemplateCode = CsrfGuardUtils.readResourceFileContent("META-INF/csrfguard.js", true); - } else if (this.javascriptSourceFile.startsWith("META-INF/")) { - this.javascriptTemplateCode = CsrfGuardUtils.readResourceFileContent(this.javascriptSourceFile, true); - } else if (this.javascriptSourceFile.startsWith("classpath:")) { - final String location = this.javascriptSourceFile.substring("classpath:".length()).trim(); - this.javascriptTemplateCode = CsrfGuardUtils.readResourceFileContent(location, true); - } else if (this.javascriptSourceFile.startsWith("file:")) { - final String location = this.javascriptSourceFile.substring("file:".length()).trim(); - this.javascriptTemplateCode = CsrfGuardUtils.readFileContent(location); - } else if (servletConfig.getServletContext().getRealPath(this.javascriptSourceFile) != null) { - this.javascriptTemplateCode = CsrfGuardUtils.readFileContent( - servletConfig.getServletContext().getRealPath(this.javascriptSourceFile)); - } else { - throw new IllegalStateException("getRealPath failed for file " + this.javascriptSourceFile); - } - - this.javascriptParamsInitted = true; + this.ajax = PropertyUtils.getProperty(properties, ConfigParameters.AJAX_ENABLED); + + this.pageTokenSynchronizationTolerance = PropertyUtils.getProperty(properties, ConfigParameters.PAGE_TOKEN_SYNCHRONIZATION_TOLERANCE); + + initializeTokenPersistenceConfigurations(properties); + + initializeActionParameters(properties, instantiateActions(properties)); + + initializePageProtection(properties); + + initializeMethodProtection(properties); } + } catch (final Exception e) { + throw new RuntimeException(e); } } - /** - * property string and substitutions - * @param properties The properties from which to fetch a value - * @param propertyName The name of the desired property - * @return the value, with common substitutions performed - * @see #commonSubstitutions(String) - */ - public static String propertyString(Properties properties, String propertyName) { - String value = properties.getProperty(propertyName); - value = commonSubstitutions(value); - return value; - } - - /** - * property string and substitutions - * @param properties The properties from which to fetch a value - * @param propertyName The name of the desired property - * @param defaultValue The value to use when the propertyName does not exist - * @return the value, with common substitutions performed - * @see #commonSubstitutions(String) - */ - public static String propertyString(Properties properties, String propertyName, String defaultValue) { - String value = properties.getProperty(propertyName, defaultValue); - value = commonSubstitutions(value); - return value; - } - - public ILogger getLogger() { - return logger; - } - + @Override public String getTokenName() { - return tokenName; + return this.tokenName; } + @Override public int getTokenLength() { - return tokenLength; + return this.tokenLength; } + @Override public boolean isRotateEnabled() { - return rotate; + return this.rotate; } - /** - * @see ConfigurationProvider#isValidateWhenNoSessionExists() - */ @Override public boolean isValidateWhenNoSessionExists() { return this.validationWhenNoSessionExists; } - /** - * If csrf guard filter should check even if there is no session for the user - * Note: this changed in 2014/04, the default behavior used to be to - * not check if there is no session. If you want the legacy behavior (if your app - * is not susceptible to CSRF if the user has no session), set this to false - */ - private final boolean validationWhenNoSessionExists; - + @Override public boolean isTokenPerPageEnabled() { - return tokenPerPage; + return this.tokenPerPage; } + @Override public boolean isTokenPerPagePrecreateEnabled() { - return tokenPerPagePrecreate; + return this.tokenPerPagePrecreate; } + @Override public SecureRandom getPrng() { - return prng; + return this.prng; } + @Override public String getNewTokenLandingPage() { - return newTokenLandingPage; + return this.newTokenLandingPage; } + @Override public boolean isUseNewTokenLandingPage() { - return useNewTokenLandingPage; + return this.useNewTokenLandingPage; } + @Override public boolean isAjaxEnabled() { - return ajax; + return this.ajax; } + @Override public boolean isProtectEnabled() { - return protect; + return this.protect; } - public String getSessionKey() { - return sessionKey; + @Override + public boolean isForceSynchronousAjax() { + return this.forceSynchronousAjax; } + @Override public Set getProtectedPages() { - return protectedPages; + return this.protectedPages; } + @Override public Set getUnprotectedPages() { - return unprotectedPages; + return this.unprotectedPages; } + @Override public Set getProtectedMethods () { - return protectedMethods; + return this.protectedMethods; } - /** - * if there are methods here, they are unprotected (e.g. GET), and all others are protected - * @return the unprotected methods - */ @Override public Set getUnprotectedMethods () { return this.unprotectedMethods; } + @Override public List getActions() { - return actions; + return this.actions; } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isPrintConfig() - */ + @Override public boolean isPrintConfig() { return this.printConfig; } - private String javascriptTemplateCode; + @Override + public void initializeJavaScriptConfiguration() { + this.javascriptInitParamsIfNeeded(); + } - private String javascriptSourceFile; - - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getJavascriptSourceFile() - */ @Override public String getJavascriptSourceFile() { - this.javascriptInitParamsIfNeeded(); - return javascriptSourceFile; + return this.javascriptSourceFile; } - private boolean javascriptDomainStrict; - - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptDomainStrict() - */ @Override public boolean isJavascriptDomainStrict() { - this.javascriptInitParamsIfNeeded(); - return javascriptDomainStrict; + return this.javascriptDomainStrict; } - private String javascriptCacheControl; - - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getJavascriptCacheControl() - */ @Override public String getJavascriptCacheControl() { - this.javascriptInitParamsIfNeeded(); - return javascriptCacheControl; + return this.javascriptCacheControl; } - private Pattern javascriptRefererPattern; - - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getJavascriptRefererPattern() - */ @Override public Pattern getJavascriptRefererPattern() { - this.javascriptInitParamsIfNeeded(); - return javascriptRefererPattern; + return this.javascriptRefererPattern; } - private boolean javascriptInjectIntoForms; - - private boolean javascriptRefererMatchProtocol; - - /** - * if the referer must match domain - */ - private boolean javascriptRefererMatchDomain; - - /** - * if the referer protocol must match protocol on the domain - * @return the isJavascriptRefererMatchProtocol - */ @Override public boolean isJavascriptRefererMatchProtocol() { - this.javascriptInitParamsIfNeeded(); return this.javascriptRefererMatchProtocol; } - /** - * if the referer must match domain - * @return the javascriptRefererMatchDomain - */ @Override public boolean isJavascriptRefererMatchDomain() { - this.javascriptInitParamsIfNeeded(); return this.javascriptRefererMatchDomain; } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptInjectIntoForms() - */ @Override public boolean isJavascriptInjectIntoForms() { - this.javascriptInitParamsIfNeeded(); - return javascriptInjectIntoForms; + return this.javascriptInjectIntoForms; } - private boolean javascriptInjectIntoAttributes; - - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptInjectIntoAttributes() - */ @Override public boolean isJavascriptInjectIntoAttributes() { - this.javascriptInitParamsIfNeeded(); return this.javascriptInjectIntoAttributes; } - private String javascriptXrequestedWith; - - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getJavascriptXrequestedWith() - */ - @Override + @Override + public boolean isJavascriptInjectIntoDynamicallyCreatedNodes() { + return this.isJavascriptInjectIntoDynamicallyCreatedNodes; + } + + @Override + public String getJavascriptDynamicNodeCreationEventName() { + return this.javascriptDynamicNodeCreationEventName; + } + + @Override public String getJavascriptXrequestedWith() { - this.javascriptInitParamsIfNeeded(); - return javascriptXrequestedWith; + return this.javascriptXrequestedWith; } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getJavascriptTemplateCode() - */ @Override public String getJavascriptTemplateCode() { - this.javascriptInitParamsIfNeeded(); return this.javascriptTemplateCode; } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isCacheable() - */ + @Override public boolean isCacheable() { - //dont cache this until the javascript params are all set - //i.e. the javascript servlet is - return this.javascriptParamsInitted; + /* don't cache this until the javascript params are all set i.e. the javascript servlet is initialized */ + return this.javascriptParamsInitialized; } - - /** - * Replaces percent-bounded expressions such as "%servletContext%." - * common subsitutions in config values - * @param input A string with expressions that should be replaced - * @return new string with "common" expressions replaced by configuration values - */ - public static String commonSubstitutions(String input) { - if (input == null || !input.contains("%")) { - return input; - } - input = input.replace("%servletContext%", CsrfGuardUtils.defaultString(CsrfGuardServletContextListener.getServletContext())); - return input; - } - - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isEnabled() - */ @Override public boolean isEnabled() { return this.enabled; } - - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptInjectGetForms() - */ - private boolean javascriptInjectGetForms; - - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptInjectGetForms() - */ + + @Override public boolean isJavascriptInjectGetForms() { - this.javascriptInitParamsIfNeeded(); return this.javascriptInjectGetForms; } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptInjectFormAttributes() - */ - private boolean javascriptInjectFormAttributes; - - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#isJavascriptInjectFormAttributes() - */ + @Override public boolean isJavascriptInjectFormAttributes() { - this.javascriptInitParamsIfNeeded(); return this.javascriptInjectFormAttributes; } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getDomainOrigin() - */ @Override public String getDomainOrigin() { - return domainOrigin; + return this.domainOrigin; } - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getDomainOrigin() - */ - private String javascriptUnprotectedExtensions; - - /** - * @see org.owasp.csrfguard.config.ConfigurationProvider#getDomainOrigin() - */ + @Override public String getJavascriptUnprotectedExtensions() { - this.javascriptInitParamsIfNeeded(); return this.javascriptUnprotectedExtensions; } + + @Override + public TokenHolder getTokenHolder() { + return this.tokenHolder; + } + + @Override + public LogicalSessionExtractor getLogicalSessionExtractor() { + return this.logicalSessionExtractor; + } + + @Override + public Duration getPageTokenSynchronizationTolerance() { + return this.pageTokenSynchronizationTolerance; + } + + private Map instantiateActions(final Properties properties) throws InstantiationException, IllegalAccessException { + final Map actionsMap = new HashMap<>(); + + for (final Object obj : properties.keySet()) { + final String propertyKey = (String) obj; + + final String actionProperty = getPrimaryPropertyDirective(propertyKey, ConfigParameters.ACTION_PREFIX); + + if (Objects.nonNull(actionProperty)) { + final String actionClass = PropertyUtils.getProperty(properties, propertyKey); + final IAction action = CsrfGuardUtils.forName(actionClass).newInstance(); + + action.setName(actionProperty); + actionsMap.put(action.getName(), action); + this.actions.add(action); + } + } + return actionsMap; + } + + private void initializeMethodProtection(final Properties properties) { + this.protectedMethods.addAll(initializeMethodProtection(properties, ConfigParameters.PROTECTED_METHODS)); + this.unprotectedMethods.addAll(initializeMethodProtection(properties, ConfigParameters.UNPROTECTED_METHODS)); + + final HashSet intersection = new HashSet<>(this.protectedMethods); + intersection.retainAll(this.unprotectedMethods); + + if (!intersection.isEmpty()) { + throw new IllegalArgumentException(String.format("The %s HTTP method(s) cannot be both protected and unprotected.", intersection)); + } + } + + private static Set initializeMethodProtection(final Properties properties, final String configParameterName) { + final String methodProtectionValue = PropertyUtils.getProperty(properties, configParameterName); + if (StringUtils.isNotBlank(methodProtectionValue)) { + final Set httpMethods = Arrays.stream(methodProtectionValue.split(",")).map(String::trim).collect(Collectors.toSet()); + HttpMethod.validate(httpMethods); + return httpMethods; + } + return Collections.emptySet(); + } + + private void initializePageProtection(final Properties properties) { + for (final Object obj : properties.keySet()) { + final String propertyKey = (String) obj; + + final String protectedPage = getPageProperty(properties, propertyKey, ConfigParameters.PROTECTED_PAGE_PREFIX); + + if (Objects.nonNull(protectedPage)) { + this.protectedPages.add(protectedPage); + } else { + final String unProtectedPage = getPageProperty(properties, propertyKey, ConfigParameters.UNPROTECTED_PAGE_PREFIX); + if (Objects.nonNull(unProtectedPage)) { + this.unprotectedPages.add(unProtectedPage); + } + } + } + } + + private void initializeActionParameters(final Properties properties, final Map actionsMap) throws IOException { + for (final Object obj : properties.keySet()) { + final String propertyKey = (String) obj; + + final Pair actionParameterProperty = getParameterPropertyDirective(propertyKey, ConfigParameters.ACTION_PREFIX); + + if (Objects.nonNull(actionParameterProperty)) { + final String directive = actionParameterProperty.getKey(); + final int index = actionParameterProperty.getValue(); + + final String actionName = directive.substring(0, index); + final IAction action = actionsMap.get(actionName); + + final String parameterName = directive.substring(index + 1); + final String parameterValue = PropertyUtils.getProperty(properties, propertyKey); + + action.setParameter(parameterName, parameterValue); + } + } + + /* ensure at least one action was defined */ + if (this.actions.isEmpty()) { + throw new IOException("At least one action that will be called in case of CSRF attacks must be defined!"); + } + } + + private static Pair getParameterPropertyDirective(final String propertyKey, final String propertyKeyPrefix) { + return getPropertyDirective(propertyKey, propertyKeyPrefix, i -> i >= 0); + } + + private static String getPrimaryPropertyDirective(final String propertyKey, final String propertyKeyPrefix) { + final Pair propertyDirective = getPropertyDirective(propertyKey, propertyKeyPrefix, i -> i < 0); + + return Objects.isNull(propertyDirective) ? null : propertyDirective.getKey(); + } + + private static Pair getPropertyDirective(final String propertyKey, final String propertyKeyPrefix, final IntPredicate directivePredicate) { + Pair result = null; + if (propertyKey.startsWith(propertyKeyPrefix)) { + final String directive = propertyKey.substring(propertyKeyPrefix.length()); + final int index = directive.indexOf('.'); + + if (directivePredicate.test(index)) { + result = Pair.of(directive, index); + } + } + + return result; + } + + private String getPageProperty(final Properties properties, final String propertyKey, final String propertyKeyPrefix) { + String result = null; + final String pageProperty = getPrimaryPropertyDirective(propertyKey, propertyKeyPrefix); + + if (Objects.nonNull(pageProperty)) { + final String pageUri = PropertyUtils.getProperty(properties, propertyKey); + + result = isSpecialUriDescriptor(pageUri) ? pageUri + : CsrfGuardUtils.normalizeResourceURI(pageUri); + } + + return result; + } + + /** + * Decides whether the given resourceUri is a static descriptor or a matching rule + * Has to be in sync with org.owasp.csrfguard.CsrfValidator.isUriMatch(java.lang.String, java.lang.String) and calculatePageTokenForUri in the JS logic + */ + private boolean isSpecialUriDescriptor(final String resourceUri) { + if (this.tokenPerPage && (resourceUri.endsWith("/*") || resourceUri.startsWith("*."))) { + // FIXME implement in the JS logic (calculatePageTokenForUri) + LOGGER.warn("'Extension' and 'partial path wildcard' matching for page tokens is not supported properly yet! " + + "Every resource will be assigned a new unique token instead of using the defined resource matcher token. " + + "Although this is not a security issue, in case of a large REST application it can have an impact on performance. " + + "Consider using regular expressions instead."); + } + + return RegexValidationUtil.isTestPathRegex(resourceUri) || resourceUri.startsWith("/*") || resourceUri.endsWith("/*") || resourceUri.startsWith("*."); + } + + private void javascriptInitParamsIfNeeded() { + if (!this.javascriptParamsInitialized) { + final ServletConfig servletConfig = JavaScriptServlet.getStaticServletConfig(); + + if (servletConfig != null) { + this.javascriptCacheControl = getProperty(JavaScriptConfigParameters.CACHE_CONTROL, servletConfig); + this.javascriptDomainStrict = getProperty(JavaScriptConfigParameters.DOMAIN_STRICT, servletConfig); + this.javascriptInjectIntoAttributes = getProperty(JavaScriptConfigParameters.INJECT_INTO_ATTRIBUTES, servletConfig); + this.javascriptInjectGetForms = getProperty(JavaScriptConfigParameters.INJECT_GET_FORMS, servletConfig); + this.javascriptInjectFormAttributes = getProperty(JavaScriptConfigParameters.INJECT_FORM_ATTRIBUTES, servletConfig); + this.javascriptInjectIntoForms = getProperty(JavaScriptConfigParameters.INJECT_INTO_FORMS, servletConfig); + this.isJavascriptInjectIntoDynamicallyCreatedNodes = getProperty(JavaScriptConfigParameters.INJECT_INTO_DYNAMICALLY_CREATED_NODES, servletConfig); + this.javascriptDynamicNodeCreationEventName = getProperty(JavaScriptConfigParameters.DYNAMIC_NODE_CREATION_EVENT_NAME, servletConfig); + this.javascriptRefererPattern = Pattern.compile(getProperty(JavaScriptConfigParameters.REFERER_PATTERN, servletConfig)); + this.javascriptRefererMatchProtocol = getProperty(JavaScriptConfigParameters.REFERER_MATCH_PROTOCOL, servletConfig); + this.javascriptRefererMatchDomain = getProperty(JavaScriptConfigParameters.REFERER_MATCH_DOMAIN, servletConfig); + this.javascriptUnprotectedExtensions = getProperty(JavaScriptConfigParameters.UNPROTECTED_EXTENSIONS, servletConfig); + this.javascriptSourceFile = getProperty(JavaScriptConfigParameters.SOURCE_FILE, servletConfig); + this.javascriptXrequestedWith = getProperty(JavaScriptConfigParameters.X_REQUESTED_WITH, servletConfig); + + if (StringUtils.isBlank(this.javascriptSourceFile)) { + this.javascriptTemplateCode = CsrfGuardUtils.readResourceFileContent("META-INF/csrfguard.js"); + } else if (this.javascriptSourceFile.startsWith("META-INF/")) { + this.javascriptTemplateCode = CsrfGuardUtils.readResourceFileContent(this.javascriptSourceFile); + } else if (this.javascriptSourceFile.startsWith("classpath:")) { + final String location = this.javascriptSourceFile.substring("classpath:".length()).trim(); + this.javascriptTemplateCode = CsrfGuardUtils.readResourceFileContent(location); + } else if (this.javascriptSourceFile.startsWith("file:")) { + final String location = this.javascriptSourceFile.substring("file:".length()).trim(); + this.javascriptTemplateCode = CsrfGuardUtils.readFileContent(location); + } else if (servletConfig.getServletContext().getRealPath(this.javascriptSourceFile) != null) { + this.javascriptTemplateCode = CsrfGuardUtils.readFileContent(servletConfig.getServletContext().getRealPath(this.javascriptSourceFile)); + } else { + throw new IllegalStateException("getRealPath failed for file " + this.javascriptSourceFile); + } + + this.javascriptParamsInitialized = true; + } + } + } + + private T getProperty(final JsConfigParameter jsConfigParameter, final ServletConfig servletConfig) { + return jsConfigParameter.getProperty(servletConfig, this.propertiesCache); + } + + private void initializeTokenPersistenceConfigurations(final Properties properties) throws InstantiationException, IllegalAccessException { + final String logicalSessionExtractorName = PropertyUtils.getProperty(properties, ConfigParameters.LOGICAL_SESSION_EXTRACTOR_NAME); + if (StringUtils.isNoneBlank(logicalSessionExtractorName)) { + this.logicalSessionExtractor = CsrfGuardUtils.forName(logicalSessionExtractorName).newInstance(); + + final String tokenHolderClassName = StringUtils.defaultIfBlank(PropertyUtils.getProperty(properties, ConfigParameters.TOKEN_HOLDER), ConfigParameters.TOKEN_HOLDER.getValue()); + this.tokenHolder = CsrfGuardUtils.forName(tokenHolderClassName).newInstance(); + } else { + throw new IllegalArgumentException(String.format("Mandatory parameter [%s] is missing from the configuration!", ConfigParameters.LOGICAL_SESSION_EXTRACTOR_NAME)); + } + } + + private int getTokenLength(final Properties properties) { + final int tokenLength = PropertyUtils.getProperty(properties, ConfigParameters.TOKEN_LENGTH); + + if (tokenLength < 4) { + throw new IllegalArgumentException("The token length cannot be less than 4 characters. The recommended default value is: " + ConfigParameters.TOKEN_LENGTH.getDefaultValue()); + } + + return tokenLength; + } + + private SecureRandom getSecureRandomInstance(final Properties properties) { + final String algorithm = PropertyUtils.getProperty(properties, ConfigParameters.PRNG); + final String provider = PropertyUtils.getProperty(properties, ConfigParameters.PRNG_PROVIDER); + + return getSecureRandomInstance(algorithm, provider); + } + + private SecureRandom getSecureRandomInstance(final String algorithm, final String provider) { + SecureRandom secureRandom; + try { + if (Objects.nonNull(provider)) { + secureRandom = Objects.nonNull(algorithm) ? SecureRandom.getInstance(algorithm, provider) : getDefaultSecureRandom(); + } else { + secureRandom = Objects.nonNull(algorithm) ? SecureRandom.getInstance(algorithm) : getDefaultSecureRandom(); + } + } catch (final NoSuchProviderException e) { + LOGGER.warn("The configured Secure Random Provider '{}' was not found, trying default providers.", provider); + LOGGER.info(getAvailableSecureRandomProvidersAndAlgorithms()); + + secureRandom = getSecureRandomInstance(algorithm, null); + logDefaultPrngProviderAndAlgorithm(secureRandom); + } catch (final NoSuchAlgorithmException nse) { + LOGGER.warn("The configured Secure Random Algorithm '{}' was not found, reverting to system defaults.", algorithm); + LOGGER.info(getAvailableSecureRandomProvidersAndAlgorithms()); + + secureRandom = getSecureRandomInstance(null, null); + } + return secureRandom; + } + + private SecureRandom getDefaultSecureRandom() { + final SecureRandom defaultSecureRandom = new SecureRandom(); + logDefaultPrngProviderAndAlgorithm(defaultSecureRandom); + return defaultSecureRandom; + } + + private void logDefaultPrngProviderAndAlgorithm(final SecureRandom defaultSecureRandom) { + LOGGER.info("Using default Secure Random Provider '{}' and '{}' Algorithm.", defaultSecureRandom.getProvider().getName(), defaultSecureRandom.getAlgorithm()); + } + + private static String getAvailableSecureRandomProvidersAndAlgorithms() { + final String prefix = "Available Secure Random providers and algorithms:" + System.lineSeparator(); + return Stream.of(Security.getProviders()) + .map(Provider::getServices) + .flatMap(Collection::stream) + .filter(service -> SecureRandom.class.getSimpleName().equals(service.getType())) + .map(service -> String.format("\tProvider: %s | Algorithm: %s", service.getProvider().getName(), service.getAlgorithm())) + .collect(Collectors.joining(System.lineSeparator(), prefix, StringUtils.EMPTY)); + } } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/PropertiesConfigurationProviderFactory.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/PropertiesConfigurationProviderFactory.java (.../PropertiesConfigurationProviderFactory.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/PropertiesConfigurationProviderFactory.java (.../PropertiesConfigurationProviderFactory.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,40 +1,60 @@ -/** - * @author mchyzer - * $Id$ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.config; import java.util.Properties; /** - * + * TODO document */ -public class PropertiesConfigurationProviderFactory implements - ConfigurationProviderFactory { +public class PropertiesConfigurationProviderFactory implements ConfigurationProviderFactory { /** - * + * TODO document */ - public PropertiesConfigurationProviderFactory() { - } + public PropertiesConfigurationProviderFactory() {} /** - * cache this since it doesnt change + * cache this since it doesn't change */ private static ConfigurationProvider configurationProvider = null; - /** - * @see org.owasp.csrfguard.config.ConfigurationProviderFactory#retrieveConfiguration(java.util.Properties) - */ - public ConfigurationProvider retrieveConfiguration(Properties properties) { + @Override + public ConfigurationProvider retrieveConfiguration(final Properties properties) { if (configurationProvider == null) { try { configurationProvider = new PropertiesConfigurationProvider(properties); - } catch (Exception e) { + } catch (final Exception e) { throw new RuntimeException(e); } } return configurationProvider; } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigPropertiesCascadeBase.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigPropertiesCascadeBase.java (.../ConfigPropertiesCascadeBase.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigPropertiesCascadeBase.java (.../ConfigPropertiesCascadeBase.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,48 +26,36 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.config.overlay; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.StringReader; import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.regex.Pattern; +import java.util.*; -import org.owasp.csrfguard.log.ILogger; -import org.owasp.csrfguard.log.LogLevel; -import org.owasp.csrfguard.util.CsrfGuardUtils; - - /** * Base class for a cascaded config. Extend this class to have a config * based on a certain file. - * + * + * This code is copied from the Grouper project + * + * see https://github.com/Internet2/grouper/blob/master/grouper-misc/grouperActivemq/dist/bin/edu/internet2/middleware/grouperActivemq/config/ConfigPropertiesCascadeBase.java * @author mchyzer * */ public abstract class ConfigPropertiesCascadeBase { - /** - * help subclasses manipulate properties. note, this is only for subclasses... - * @return properties - */ - protected Properties internalProperties() { - return this.properties; - } - /** if a key ends with this, then it is an EL property */ private static final String EL_CONFIG_SUFFIX = ".elConfig"; + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigPropertiesCascadeBase.class); + /** * this is used to tell engine where the default and example config is... */ @@ -97,7 +85,6 @@ return (T)configPropertiesCascadeBase.retrieveFromConfigFileOrCache(); } - /** * if it's ok to put the config file in the same directory as a jar, * then return a class in the jar here @@ -113,14 +100,8 @@ */ protected abstract String getSecondsToCheckConfigKey(); - /** - * if there are things that are calculated, clear them out (e.g. if an override is set) - */ - public abstract void clearCachedCalculatedValues(); - /** override map for properties in thread local to be used in a web server or the like */ - private static ThreadLocal, Map>> propertiesThreadLocalOverrideMap - = null; + private static ThreadLocal, Map>> propertiesThreadLocalOverrideMap = null; /** * override map for properties in thread local to be used in a web server or the like, based on property class @@ -148,22 +129,9 @@ /** override map for properties, for testing, put properties in here, based on config class * this is static since the properties class can get reloaded, but these shouldn't */ - private static Map, Map> propertiesOverrideMap - = null; + private static Map, Map> propertiesOverrideMap = null; /** - * @return the set of property names - * @see java.util.Hashtable#keySet() - */ - @SuppressWarnings("unchecked") - public Set propertyNames() { - - Set result = new LinkedHashSet(); - result.addAll((Set)(Object)this.propertiesHelper(false).keySet()); - return result; - } - - /** * override map for properties for testing * @return the override map */ @@ -242,205 +210,6 @@ private Properties properties = new Properties(); /** - * get the property value as a string - * @param key The property name - * @return the property value, or null if not found - */ - public String propertyValueStringRequired(String key) { - return propertyValueString(key, null, true).getTheValue(); - } - - /** - * get the property value as a string - * @param key The property name - * @param defaultValue The value used when such property value is found (in place of null) - * @return the property value - */ - public String propertyValueString(String key, String defaultValue) { - return propertyValueString(key, defaultValue, false).getTheValue(); - } - - /** - * get the property value as a string or null if not there - * @param key The property name - * @return the property value - */ - public String propertyValueString(String key) { - return propertyValueString(key, null, false).getTheValue(); - } - - /** - * result of a property value - */ - static class PropertyValueResult { - - - /** - * - * @param theValue1 property value - * @param hasKey1 whether or not the key exists - */ - public PropertyValueResult(String theValue1, boolean hasKey1) { - super(); - this.theValue = theValue1; - this.hasKey = hasKey1; - } - - - /** value from lookup */ - private String theValue; - - /** if there is a key in the properties file */ - private boolean hasKey; - - - /** - * value from lookup - * @return the theValue - */ - public String getTheValue() { - return this.theValue; - } - - - /** - * value from lookup - * @param theValue1 the theValue to set - */ - public void setTheValue(String theValue1) { - this.theValue = theValue1; - } - - - /** - * if there is a key in the properties file - * @return the hasKey - */ - public boolean isHasKey() { - return this.hasKey; - } - - - /** - * if there is a key in the properties file - * @param hasKey1 the hasKey to set - */ - public void setHasKey(boolean hasKey1) { - this.hasKey = hasKey1; - } - - } - - /** - * get the property value as a string - * @param key property key - * @param defaultValue value to use when key is not found - * @param required When true, throw an exception if the key does not exist - * @return the property value - */ - protected PropertyValueResult propertyValueString(String key, String defaultValue, boolean required) { - if (key.endsWith(EL_CONFIG_SUFFIX)) { - throw new RuntimeException("Why does key end in suffix??? " + EL_CONFIG_SUFFIX + ", " + key); - } - return propertyValueStringHelper(key, defaultValue, required); - } - - /** - * get the property value as a string - * @param key property key - * @param defaultValue value to use when key is not found - * @param required When true, throw an exception if the key does not exist - * @return the property value - */ - protected PropertyValueResult propertyValueStringHelper(String key, String defaultValue, boolean required) { - - //lets look for EL - if (!key.endsWith(EL_CONFIG_SUFFIX)) { - - PropertyValueResult elPropertyValueResult = propertyValueStringHelper(key + EL_CONFIG_SUFFIX, null, false); - - if (elPropertyValueResult.isHasKey()) { - - //process the EL - String result = ConfigPropertiesCascadeUtils.substituteExpressionLanguage(elPropertyValueResult.getTheValue(), null, true, true, true, false); - PropertyValueResult propertyValueResult = new PropertyValueResult(result, true); - return propertyValueResult; - } - - } - - //first check threadlocal map - boolean hasKey = false; - Map overrideMap = propertiesThreadLocalOverrideMap(); - - hasKey = overrideMap == null ? false : overrideMap.containsKey(key); - String value = hasKey ? overrideMap.get(key) : null; - if (!hasKey) { - - overrideMap = propertiesOverrideMap(); - - hasKey = overrideMap == null ? null : overrideMap.containsKey(key); - value = hasKey ? overrideMap.get(key) : null; - } - if (!hasKey) { - hasKey = this.properties.containsKey(key); - value = hasKey ? this.properties.getProperty(key) : null; - } - if (!required && !hasKey) { - return new PropertyValueResult(defaultValue, false); - } - if (required && !hasKey) { - String error = "Cant find property: " + key + " in properties file: " + this.getMainConfigClasspath() + ", it is required"; - - throw new RuntimeException(error); - } - value = ConfigPropertiesCascadeUtils.trim(value); - value = substituteCommonVars(value); - - if (!required && ConfigPropertiesCascadeUtils.isBlank(value)) { - return new PropertyValueResult(null, true); - } - - //do the validation if this is required - if (required && ConfigPropertiesCascadeUtils.isBlank(value)) { - String error = "Property " + key + " in properties file: " + this.getMainConfigClasspath() + ", has a blank value, it is required"; - - throw new RuntimeException(error); - } - - return new PropertyValueResult(value, true); - } - - /** - * substitute common vars like $space$ and $newline$ - * @param string input string - * @return new string with some dollar-delimited tokens replaced - */ - protected static String substituteCommonVars(String string) { - if (string != null && string.indexOf('$') < 0 ) { - //might have $space$ - string = ConfigPropertiesCascadeUtils.replace(string, "$space$", " "); - - //note, at some point we could be OS specific - string = ConfigPropertiesCascadeUtils.replace(string, "$newline$", "\n"); - } - return string; - } - - /** - * when this config object was created - */ - private long createdTime = System.currentTimeMillis(); - - /** - * when this config object was created - * @return the createdTime - */ - long getCreatedTime() { - return this.createdTime; - } - - /** * when this config object was created or last checked for changes */ private long lastCheckedTime = System.currentTimeMillis(); @@ -532,7 +301,7 @@ try { return new FileInputStream(configFile); } catch (Exception e) { - logError("Cant read config file: " + configFile.getAbsolutePath(), e); + LOGGER.error("Cant read config file: " + configFile.getAbsolutePath(), e); } } } @@ -573,14 +342,6 @@ /** - * keep the original config string for logging purposes, e.g. file:/a/b/c.properties - * @return the originalConfig - */ - public String getOriginalConfig() { - return this.originalConfig; - } - - /** * the contents when the config file was read */ private String contents = null; @@ -613,12 +374,12 @@ } catch (Exception e) { throw new RuntimeException("Problem reading config: '" + this.originalConfig + "'", e); } finally { - CsrfGuardUtils.closeQuietly(inputStream); + ConfigPropertiesCascadeCommonUtils.closeQuietly(inputStream); } } /** - * + * * @param configFileFullConfig The config file location reference such as file:/some/path/config.properties */ public ConfigFile(String configFileFullConfig) { @@ -659,25 +420,6 @@ private String configFileTypeConfig; - /** - * the type of config file (file path, classpath, etc) - * @return the configFileType - */ - public ConfigFileType getConfigFileType() { - return this.configFileType; - } - - - /** - * the config part which says which file or classpath etc - * @return the configFileTypeConfig - */ - public String getConfigFileTypeConfig() { - return this.configFileTypeConfig; - } - - - } /** @@ -717,21 +459,19 @@ if (ConfigPropertiesCascadeUtils.isBlank(secondsToCheckConfigString)) { secondsToCheckConfigString = mainExampleConfigFile.getProperty(this.getSecondsToCheckConfigKey()); } - } - } //if hasnt found yet, there is a problem if (ConfigPropertiesCascadeUtils.isBlank(overrideFullConfig)) { - throw new RuntimeException("Cant find the hierarchy config key: " + this.getHierarchyConfigKey() + throw new RuntimeException("Cant find the hierarchy config key: " + this.getHierarchyConfigKey() + " in config files: " + this.getMainConfigClasspath() + " or " + this.getMainExampleConfigClasspath()); } //if hasnt found yet, there is a problem if (ConfigPropertiesCascadeUtils.isBlank(secondsToCheckConfigString)) { - throw new RuntimeException("Cant find the seconds to check config key: " + this.getSecondsToCheckConfigKey() + throw new RuntimeException("Cant find the seconds to check config key: " + this.getSecondsToCheckConfigKey() + " in config files: " + this.getMainConfigClasspath() + " or " + this.getMainExampleConfigClasspath()); } @@ -743,7 +483,7 @@ result.timeToCheckConfigSeconds = ConfigPropertiesCascadeUtils.intValue(secondsToCheckConfigString); } catch (Exception e) { throw new RuntimeException("Invalid integer seconds to check config config value: " + secondsToCheckConfigString - + ", key: " + this.getSecondsToCheckConfigKey() + + ", key: " + this.getSecondsToCheckConfigKey() + " in config files: " + this.getMainConfigClasspath() + " or " + this.getMainExampleConfigClasspath()); @@ -779,56 +519,6 @@ } /** - * get the logger instance - * @return the ilogger - */ - private static ILogger iLogger() { - //endless loop - //CsrfGuard csrfGuard = CsrfGuard.getInstance(); - //ILogger iLogger = csrfGuard == null ? null : csrfGuard.getLogger(); - //return iLogger; - return null; - - } - - /** - * make sure LOG is there, after things are initialized - * @param logMessage Message to log - * @param t Exception to log, or null - */ - protected static void logInfo(String logMessage, Exception t) { - ILogger iLogger = iLogger(); - if (iLogger != null) { - if (!ConfigPropertiesCascadeUtils.isBlank(logMessage)) { - iLogger.log(LogLevel.Info, logMessage); - } - if (t != null) { - iLogger.log(LogLevel.Info, t); - } - } - } - - /** - * make sure LOG is there, after things are initialized - * @param logMessage Message to log - * @param t Exception to log, or null - */ - protected static void logError(String logMessage, Exception t) { - ILogger iLogger = iLogger(); - if (iLogger != null) { - if (!ConfigPropertiesCascadeUtils.isBlank(logMessage)) { - iLogger.log(LogLevel.Info, logMessage); - } - if (t != null) { - iLogger.log(LogLevel.Info, t); - } - } else { - System.err.println("ERROR: " + logMessage); - t.printStackTrace(); - } - } - - /** * see if there is one in cache, if so, use it, if not, get from config files * @return the config from file or cache */ @@ -894,10 +584,7 @@ return configObject; } finally { - ILogger iLogger = iLogger(); - if (iLogger != null) { - iLogger.log(LogLevel.Debug, ConfigPropertiesCascadeUtils.mapToString(debugMap)); - } + LOGGER.debug(ConfigPropertiesCascadeUtils.mapToString(debugMap)); } } @@ -940,16 +627,14 @@ } } catch (Exception e) { //lets log and return the old one - logError("Error checking for changes in configs (will use previous version): " + this.getMainConfigClasspath(), e); + LOGGER.error("Error checking for changes in configs (will use previous version): " + this.getMainConfigClasspath(), e); } finally { //reset the time so we dont have to check again for a while this.lastCheckedTime = System.currentTimeMillis(); } return false; } - - /** * get the main config classpath, e.g. csrf guard properties * @return the classpath of the main config file @@ -969,172 +654,20 @@ protected abstract String getMainExampleConfigClasspath(); /** - * get a boolean and validate from csrf guard properties - * @param key property key - * @param defaultValue valud to use when key is missing - * @return true when the property value represents an affirmative string such as {true, t, yes, y} - */ - public boolean propertyValueBoolean(String key, boolean defaultValue) { - return propertyValueBoolean(key, defaultValue, false); - } - - /** - * if the key is there, whether or not the value is blank - * @param key property key - * @return true or false - */ - public boolean containsKey(String key) { - - return propertyValueString(key, null, false).isHasKey(); - - } - - /** - * get a boolean and validate from csrf guard properties or null if not there - * @param key property key - * @return the boolean or null - */ - public Boolean propertyValueBoolean(String key) { - return propertyValueBoolean(key, null, false); - } - - - /** - * get a boolean pop and validate from the config file - * @param key property key - * @param defaultValue Used when no property value is found for the given key, when the 'required' option is not set - * @param required Whether or not a value is required to be present - * @return true when property value is string is one of {true, t, yes, y} and false when one of {false, f, no, n} - */ - protected Boolean propertyValueBoolean(String key, Boolean defaultValue, boolean required) { - String value = propertyValueString(key, null, false).getTheValue(); - if (ConfigPropertiesCascadeUtils.isBlank(value) && !required) { - return defaultValue; - } - if (ConfigPropertiesCascadeUtils.isBlank(value) && required) { - throw new RuntimeException("Cant find boolean property " + key + " in properties file: " + this.getMainConfigClasspath() + ", it is required, expecting true or false"); - } - if ("true".equalsIgnoreCase(value)) { - return true; - } - if ("false".equalsIgnoreCase(value)) { - return false; - } - if ("t".equalsIgnoreCase(value)) { - return true; - } - if ("f".equalsIgnoreCase(value)) { - return false; - } - if ("yes".equalsIgnoreCase(value)) { - return true; - } - if ("no".equalsIgnoreCase(value)) { - return false; - } - if ("y".equalsIgnoreCase(value)) { - return true; - } - if ("n".equalsIgnoreCase(value)) { - return false; - } - throw new RuntimeException("Invalid boolean value: '" + value + "' for property: " + key - + " in properties file: " + this.getMainConfigClasspath() + ", expecting true or false"); - - } - - /** - * get an int and validate from the config file - * @param key property key - * @param defaultValue Used when no property value is found for the given key, when the 'required' option is not set - * @param required Whether or not a value is required to be present - * @return the property value - */ - protected Integer propertyValueInt(String key, Integer defaultValue, boolean required) { - String value = propertyValueString(key, null, false).getTheValue(); - if (ConfigPropertiesCascadeUtils.isBlank(value) && !required) { - return defaultValue; - } - if (ConfigPropertiesCascadeUtils.isBlank(value) && required) { - throw new RuntimeException("Cant find integer property " + key + " in config file: " + this.getMainConfigClasspath() + ", it is required"); - } - try { - return ConfigPropertiesCascadeUtils.intValue(value); - } catch (Exception e) { - - } - throw new RuntimeException("Invalid integer value: '" + value + "' for property: " - + key + " in config file: " + this.getMainConfigClasspath() + " in properties file"); - - } - - /** - * get a boolean and validate from csrf guard properties - * @param key property key - * @return the boolean property value - */ - public boolean propertyValueBooleanRequired(String key) { - - return propertyValueBoolean(key, false, true); - - } - - /** - * get a boolean and validate from csrf guard properties - * @param key property key - * @return the integer property value - */ - public int propertyValueIntRequired(String key) { - - return propertyValueInt(key, -1, true); - - } - - /** - * get a boolean and validate from csrf guard properties - * @param key property key - * @param defaultValue Used when key not found - * @return the property value - */ - public int propertyValueInt(String key, int defaultValue ) { - - return propertyValueInt(key, defaultValue, false); - - } - - /** - * get a boolean and validate from csrf guard properties - * @param key property key - * @return the int or null if there - */ - public Integer propertyValueInt(String key ) { - - return propertyValueInt(key, null, false); - - } - - /** * read properties from a resource, don't modify the properties returned since they are cached * @param resourceName Name of properties resource * @param exceptionIfNotExist When true, throw an exception if an URL for the resource name cannot be constructued * @return the properties or null if not exist */ - protected static Properties propertiesFromResourceName(String resourceName, - boolean exceptionIfNotExist) { - + protected static Properties propertiesFromResourceName(String resourceName, boolean exceptionIfNotExist) { Properties properties = new Properties(); - URL url = null; try { - url = ConfigPropertiesCascadeUtils.computeUrl(resourceName, true); - } catch (Exception e) { - //I guess this ok - logInfo("Problem loading config file: " + resourceName, e); - + LOGGER.info("Problem loading config file: " + resourceName, e); } if (url == null && exceptionIfNotExist) { @@ -1159,117 +692,4 @@ return properties; } - /** - * make sure a value exists in properties - * @param key property key - * @return true if property exists with non-blank value, false otherwise - */ - public boolean assertPropertyValueRequired(String key) { - String value = propertyValueString(key); - if (!ConfigPropertiesCascadeUtils.isBlank(value)) { - return true; - } - String error = "Cant find property " + key + " in resource: " + this.getMainConfigClasspath() + ", it is required"; - System.err.println("CSRF guard error: " + error); - ILogger iLogger = iLogger(); - if (iLogger != null) { - iLogger.log(LogLevel.Error, error); - } - return false; - } - - /** - * make sure a value is boolean in properties - * @param key property key - * @param required whether or not the key is required to be present - * @return true if ok, false if not - */ - public boolean assertPropertyValueBoolean(String key, boolean required) { - - if (required && !assertPropertyValueRequired(key)) { - return false; - } - - String value = propertyValueString(key); - //maybe ok not there - if (!required && ConfigPropertiesCascadeUtils.isBlank(value)) { - return true; - } - try { - ConfigPropertiesCascadeUtils.booleanValue(value); - return true; - } catch (Exception e) { - - } - String error = "Expecting true or false property " + key + " in resource: " + this.getMainConfigClasspath() + ", but is '" + value + "'"; - System.err.println("csrf guard error: " + error); - ILogger iLogger = iLogger(); - if (iLogger != null) { - iLogger.log(LogLevel.Error, error); - } - return false; - } - - /** - * make sure a property is a class of a certain type - * @param key property key - * @param classType Desired class type - * @param required Whether or not key must be present and have non-blank value - * @return true if ok - */ - public boolean assertPropertyValueClass( - String key, Class classType, boolean required) { - - if (required && !assertPropertyValueRequired(key)) { - return false; - } - String value = propertyValueString(key); - - //maybe ok not there - if (!required && ConfigPropertiesCascadeUtils.isBlank(value)) { - return true; - } - - String extraError = ""; - try { - - - Class theClass = ConfigPropertiesCascadeUtils.forName(value); - if (classType.isAssignableFrom(theClass)) { - return true; - } - extraError = " does not derive from class: " + classType.getSimpleName(); - - } catch (Exception e) { - extraError = ", " + ConfigPropertiesCascadeUtils.getFullStackTrace(e); - } - String error = "Cant process property " + key + " in resource: " + this.getMainConfigClasspath() + ", the current" + - " value is '" + value + "', which should be of type: " - + classType.getName() + extraError; - System.err.println("csrf guard error: " + error); - ILogger iLogger = iLogger(); - if (iLogger != null) { - iLogger.log(LogLevel.Error, error); - } - return false; - } - - /** - * find all keys/values with a certain pattern in a properties file. - * return the keys. if none, will return the empty set, not null set - * @param pattern expression matched against property names - * @return the matching keys. if none, will return the empty set, not null set - */ - public Map propertiesMap(Pattern pattern) { - Map result = new LinkedHashMap(); - for (String key: propertyNames()) { - if (pattern.matcher(key).matches()) { - result.put(key, propertyValueString(key)); - } - } - - return result; - } - - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigPropertiesCascadeCommonUtils.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigPropertiesCascadeCommonUtils.java (.../ConfigPropertiesCascadeCommonUtils.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigPropertiesCascadeCommonUtils.java (.../ConfigPropertiesCascadeCommonUtils.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,20 +1,19 @@ - -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -27,182 +26,30 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.config.overlay; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.PushbackInputStream; -import java.io.Reader; -import java.io.Serializable; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.io.Writer; -import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.math.BigDecimal; -import java.net.InetAddress; +import java.io.*; +import java.lang.reflect.*; import java.net.URL; import java.net.URLDecoder; -import java.net.URLEncoder; import java.security.CodeSource; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Timestamp; -import java.text.DateFormat; -import java.text.DecimalFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.LinkedHashSet; import java.util.List; import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadFactory; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - - /** * utility methods for grouper. + * + * This code is copied from the Grouper project + * * @author mchyzer * */ @SuppressWarnings({ "serial", "unchecked" }) public class ConfigPropertiesCascadeCommonUtils { - /** override map for properties in thread local to be used in a web server or the like */ - private static ThreadLocal>> propertiesThreadLocalOverrideMap = new ThreadLocal>>(); - /** - * return the arg after the argBefore, or null if not there, or exception - * if argBefore is not found - * @param args array of arguments - * @param argBefore the argument immediately preceeding the desired value - * @return the arg that appears just after argBefore - */ - public static String argAfter(String[] args, String argBefore) { - if (length(args) <= 1) { - return null; - } - int argBeforeIndex = -1; - for (int i=0;i 0) { - displaySize = String.valueOf(size / ONE_GB) + " GB"; - } else if (size / ONE_MB > 0) { - displaySize = String.valueOf(size / ONE_MB) + " MB"; - } else if (size / ONE_KB > 0) { - displaySize = String.valueOf(size / ONE_KB) + " KB"; - } else { - displaySize = String.valueOf(size) + " bytes"; - } - - return displaySize; - } - /** - * see if options have a specific option by int bits - * @param options The options integer that holds option flag bits - * @param option The option flag bit to check - * @return true if the option flag is set in the options int - */ - public static boolean hasOption(int options, int option) { - return (options & option) > 0; - } - - /** * get canonical path of file * @param file The file from which the canonical path will be extracted * @return the canonical path @@ -215,232 +62,9 @@ throw new RuntimeException(ioe); } } - - /** - * return the suffix after a char. If the char doesn't exist, just return the string - * @param input string - * @param theChar the marker character such as "." - * @return Suffix of string after the last index of the specified character - */ - public static String suffixAfterChar(String input, char theChar) { - if (input == null) { - return null; - } - //get the real type off the end - int lastIndex = input.lastIndexOf(theChar); - if (lastIndex > -1) { - input = input.substring(lastIndex + 1, input.length()); - } - return input; - } - /** - * get the oracle underscore name e.g. javaNameHere → JAVA_NAME_HERE - * - * @param javaName - * the java convention name, in camelCase - * - * @return the oracle underscore name based on the java name - */ - public static String oracleStandardNameFromJava(String javaName) { - - StringBuilder result = new StringBuilder(); - - if ((javaName == null) || (0 == "".compareTo(javaName))) { - return javaName; - } - - //if package is specified, only look at class name - javaName = suffixAfterChar(javaName, '.'); - - //don't check the first char - result.append(javaName.charAt(0)); - - char currChar; - - boolean previousCap = false; - - //loop through the string, looking for uppercase - for (int i = 1; i < javaName.length(); i++) { - currChar = javaName.charAt(i); - - //if uppcase append an underscore - if (!previousCap && (currChar >= 'A') && (currChar <= 'Z')) { - result.append("_"); - } - - result.append(currChar); - if ((currChar >= 'A') && (currChar <= 'Z')) { - previousCap = true; - } else { - previousCap = false; - } - } - - //this is in upper-case - return result.toString().toUpperCase(); - } - /** - * see if two maps are the equivalent (based on number of entries, - * and the equals() method of the keys and values) - * - * @param key type - * @param value type - * @param first the first map to compare - * @param second the second map to compare - * @return true if equal - */ - public static boolean mapEquals(Map first, Map second) { - Set keysMismatch = new HashSet(); - mapDifferences(first, second, keysMismatch, null); - //if any keys mismatch, then not equal - return keysMismatch.size() == 0; - - } - - /** - * empty map - */ - private static final Map EMPTY_MAP = Collections.unmodifiableMap(new HashMap()); - - /** - * see if two maps are the equivalent (based on number of entries, - * and the equals() method of the keys and values) - * @param key type - * @param value type - * @param first map to check diffs - * @param second map to check diffs - * @param differences set of keys (with prefix) of the diffs - * @param prefix for the entries in the diffs (e.g. "attribute__") - */ - @SuppressWarnings("unchecked") - public static void mapDifferences(Map first, Map second, Set differences, String prefix) { - if (first == second) { - return; - } - //put the collections in new collections so we can remove and keep track - if (first == null) { - first = EMPTY_MAP; - } - if (second == null) { - second = EMPTY_MAP; - } else { - //make linked so the results are ordered - second = new LinkedHashMap(second); - } - int firstSize = first == null ? 0 : first.size(); - int secondSize = second == null ? 0 : second.size(); - //if both empty then all good - if (firstSize == 0 && secondSize == 0) { - return; - } - - for (K key : first.keySet()) { - - if (second.containsKey(key)) { - V firstValue = first.get(key); - V secondValue = second.get(key); - //keep track by removing from second - second.remove(key); - if (equals(firstValue, secondValue)) { - continue; - } - } - differences.add(isNotBlank(prefix) ? (K)(prefix + key) : key); - } - //add the ones left over in the second map which are not in the first map - for (K key : second.keySet()) { - differences.add(isNotBlank(prefix) ? (K)(prefix + key) : key); - } - } - - /** - * Sleep for the specified number of milliseconds and throw RuntimeExeption if interrupted. - * - * @param millis Number of milliseconds to sleep - * @see Thread#sleep - */ - public static void sleep(long millis) { - try { - Thread.sleep(millis); - } catch (InterruptedException ie) { - throw new RuntimeException(ie); - } - } - - /** - * If we can, inject this into the exception, else return false - * @param t The Throwable to inject - * @param message The message to append to the throwable's message - * @return true if success, false if not - */ - public static boolean injectInException(Throwable t, String message) { - - String throwableFieldName = "detailMessage"; - - try { - String currentValue = t.getMessage(); - if (!isBlank(currentValue)) { - currentValue += ",\n" + message; - } else { - currentValue = message; - } - assignField(t, throwableFieldName, currentValue); - return true; - } catch (Throwable t2) { - //dont worry about what the problem is, return false so the caller can log - return false; - } - - } - - /** - * get a unique string identifier based on the current time, - * this is not globally unique, just unique for as long as this - * server is running... - * - * @return String - */ - public static String uniqueId() { - //this needs to be threadsafe since we are using a static field - synchronized (ConfigPropertiesCascadeCommonUtils.class) { - lastId = incrementStringInt(lastId); - } - - return String.valueOf(lastId); - } - - /** - * get a file name from a resource name - * - * @param resourceName - * is the classpath location - * - * @return the file path on the system - */ - public static File fileFromResourceName(String resourceName) { - - URL url = computeUrl(resourceName, true); - - if (url == null) { - return null; - } - - try { - String fileName = URLDecoder.decode(url.getFile(), "UTF-8"); - - File configFile = new File(fileName); - - return configFile; - } catch (UnsupportedEncodingException uee) { - throw new RuntimeException(uee); - } - } - - - /** * compute a url of a resource * @param resourceName The resource name for which a URL will be built * @param canBeNull if can't be null, throw runtime @@ -480,19 +104,6 @@ } /** - * make sure a array is non null. If null, then return an empty array. - * Note: this will probably not work for primitive arrays (e.g. int[]) - * @param template type - * @param array the array to check - * @param theClass to make array from - * @return the list or empty list if null - */ - @SuppressWarnings("unchecked") - public static T[] nonNull(T[] array, Class theClass) { - return array == null ? ((T[])Array.newInstance(theClass, 0)) : array; - } - - /** * get the prefix or suffix of a string based on a separator * * @param startString @@ -536,38 +147,6 @@ } /** - * get the extension from name. if name is a:b:c, name is c - * @param name a name, potentially containing colon separators such as "a:b:c" - * @return the extension a.k.a. part of the name after the last colon character - */ - public static String extensionFromName(String name) { - if (isBlank(name)) { - return name; - } - int lastColonIndex = name.lastIndexOf(':'); - if (lastColonIndex == -1) { - return name; - } - String extension = name.substring(lastColonIndex+1); - return extension; - } - - /** - * Returns the class object for the given name. - * @param origClassName fully qualified class name - * @return the class - */ - public static Class forName(String origClassName) { - - try { - return Class.forName(origClassName); - } catch (Throwable t) { - throw new RuntimeException("Problem loading class: " + origClassName, t); - } - - } - - /** * Construct a class * @param template type * @param theClass the class @@ -614,146 +193,10 @@ throw new RuntimeException("Problem with class: " + theClass, e); } } - - /** - * get the parent stem name from name. if already a root stem - * then just return null. e.g. if the name is a:b:c then - * the return value is a:b - * @param name a colon-delimited name such as "a:b:c" - * @return the parent stem name or null if none - */ - public static String parentStemNameFromName(String name) { - int lastColonIndex = name.lastIndexOf(':'); - if (lastColonIndex == -1) { - return null; - } - String parentStemName = name.substring(0,lastColonIndex); - return parentStemName; - } - - /** - * return the string or the other if the first is blank - * @param string The string - * @param defaultStringIfBlank The string used when the first parameter is blank - * @return the string or the default one if the string was blank - */ - public static String defaultIfBlank(String string, String defaultStringIfBlank) { - return isBlank(string) ? defaultStringIfBlank : string; - } - - /** - * genericized method to see if first is null, if so then return second, else first. - * @param template type - * @param theValue first input - * @param defaultIfTheValueIsNull second input - * @return the first if not null, second if no - */ - public static T defaultIfNull(T theValue, T defaultIfTheValueIsNull) { - return theValue != null ? theValue : defaultIfTheValueIsNull; - } - - /** - * add each element of listToAdd if it is not already in list - * @param template type - * @param list to add to - * @param listToAdd each element will be added to list, or null if none - */ - public static void addIfNotThere(Collection list, Collection listToAdd) { - //maybe nothing to do - if (listToAdd == null) { - return; - } - for (T t : listToAdd) { - if (!list.contains(t)) { - list.add(t); - } - } - } - /** - * print out various types of objects - * - * @param object the object to convert into a human-readable string - * @param maxChars is where it should stop when figuring out object. note, result might be longer than max... - * need to abbreviate when back - * @param result is where to append to - */ - @SuppressWarnings("unchecked") - private static void toStringForLogHelper(Object object, int maxChars, StringBuilder result) { - - try { - if (object == null) { - result.append("null"); - } else if (object.getClass().isArray()) { - // handle arrays - int length = Array.getLength(object); - if (length == 0) { - result.append("Empty array"); - } else { - result.append("Array size: ").append(length).append(": "); - for (int i = 0; i < length; i++) { - result.append("[").append(i).append("]: ").append( - Array.get(object, i)).append("\n"); - if (maxChars != -1 && result.length() > maxChars) { - return; - } - } - } - } else if (object instanceof Collection) { - //give size and type if collection - Collection collection = (Collection) object; - int collectionSize = collection.size(); - if (collectionSize == 0) { - result.append("Empty ").append(object.getClass().getSimpleName()); - } else { - result.append(object.getClass().getSimpleName()).append(" size: ").append(collectionSize).append(": "); - int i=0; - for (Object collectionObject : collection) { - result.append("[").append(i).append("]: ").append( - collectionObject).append("\n"); - if (maxChars != -1 && result.length() > maxChars) { - return; - } - i++; - } - } - } else { - result.append(object.toString()); - } - } catch (Exception e) { - result.append("<> ").append(object.getClass()).append(":\n") - .append(getFullStackTrace(e)).append("\n"); - } - } - - /** * convert a set to a string (comma separate) - * @param set the set to convert into a human-readable string - * @return the String - */ - public static String setToString(Set set) { - if (set == null) { - return "null"; - } - if (set.size() == 0) { - return "empty"; - } - StringBuilder result = new StringBuilder(); - boolean first = true; - for (Object object : set) { - if (!first) { - result.append(", "); - } - first = false; - result.append(object); - } - return result.toString(); - } - - /** - * convert a set to a string (comma separate) * @param map the map to convert into a human-readable string * @return the String * @deprecated use mapToString(map) @@ -788,128 +231,6 @@ } /** - * print out various types of objects - * - * @param object the object to convert to a human-readable string - * @return the string value - */ - public static String toStringForLog(Object object) { - StringBuilder result = new StringBuilder(); - toStringForLogHelper(object, -1, result); - return result.toString(); - } - - /** - * print out various types of objects - * - * @param object the object to convert to a human-readable string - * @param maxChars is the max chars that should be returned (abbreviate if longer), or -1 for any amount - * @return the string value - */ - public static String toStringForLog(Object object, int maxChars) { - StringBuilder result = new StringBuilder(); - toStringForLogHelper(object, -1, result); - String resultString = result.toString(); - if (maxChars != -1) { - return abbreviate(resultString, maxChars); - } - return resultString; - } - - /** - * If batching this is the number of batches - * @param count is size of set - * @param batchSize the batch size - * @return the number of batches - */ - public static int batchNumberOfBatches(int count, int batchSize) { - int batches = 1 + ((count - 1) / batchSize); - return batches; - - } - - /** - * If batching this is the number of batches - * @param collection the collection - * @param batchSize the batch size - * @return the number of batches - */ - public static int batchNumberOfBatches(Collection collection, int batchSize) { - int arrraySize = length(collection); - return batchNumberOfBatches(arrraySize, batchSize); - - } - - /** - * retrieve a batch by 0 index. Will return an array of size batchSize or - * the remainder. the array will be full of elements. Note, this requires an - * ordered input (so use linkedhashset not hashset if doing sets) - * @param template type - * @param collection the collection - * @param batchSize the batch size - * @param batchIndex the batch index - * @return the list - * This never returns null, only empty list - */ - @SuppressWarnings("unchecked") - public static List batchList(Collection collection, int batchSize, - int batchIndex) { - - int numberOfBatches = batchNumberOfBatches(collection, batchSize); - int arraySize = length(collection); - - // short circuit - if (arraySize == 0) { - return new ArrayList(); - } - - List theBatchObjects = new ArrayList(); - - // lets get the type of the first element if possible -// Object first = get(arrayOrCollection, 0); -// -// Class theType = first == null ? Object.class : first.getClass(); - - // if last batch - if (batchIndex == numberOfBatches - 1) { - - // needs to work to 1-n - //int thisBatchSize = 1 + ((arraySize - 1) % batchSize); - - int collectionIndex = 0; - for (T t : collection) { - if (collectionIndex++ < batchIndex * batchSize) { - continue; - } - //just copy the rest - //if (collectionIndex >= (batchIndex * batchSize) + arraySize) { - // break; - //} - //we are in the copy mode - theBatchObjects.add(t); - } - - } else { - // if non-last batch - //int newIndex = 0; - int collectionIndex = 0; - for (T t : collection) { - if (collectionIndex < batchIndex * batchSize) { - collectionIndex++; - continue; - } - //done with batch - if (collectionIndex >= (batchIndex + 1) * batchSize) { - break; - } - theBatchObjects.add(t); - collectionIndex++; - } - } - return theBatchObjects; - } - - /** * split a string based on a separator into an array, and trim each entry (see * the Commons Util trim() for more details) * @@ -973,68 +294,6 @@ } /** - * escape url chars (e.g. a # is %23) - * @param string input - * @return the encoded string - */ - public static String escapeUrlEncode(String string) { - String result = null; - try { - result = URLEncoder.encode(string, "UTF-8"); - } catch (UnsupportedEncodingException ex) { - throw new RuntimeException("UTF-8 not supported", ex); - } - return result; - } - - /** - * unescape url chars (e.g. a space is %20) - * @param string input - * @return the encoded string - */ - public static String escapeUrlDecode(String string) { - String result = null; - try { - result = URLDecoder.decode(string, "UTF-8"); - } catch (UnsupportedEncodingException ex) { - throw new RuntimeException("UTF-8 not supported", ex); - } - return result; - } - - /** - * make sure a list is non null. If null, then return an empty list - * @param template type - * @param list the list, or null - * @return the list or empty list if null - */ - public static List nonNull(List list) { - return list == null ? new ArrayList() : list; - } - - /** - * make sure a list is non null. If null, then return an empty set - * @param template type - * @param set the set, or null - * @return the set or empty set if null - */ - public static Set nonNull(Set set) { - return set == null ? new HashSet() : set; - } - - /** - * make sure it is non null, if null, then give new map - * - * @param key of map - * @param value of map - * @param map is map - * @return set non null - */ - public static Map nonNull(Map map) { - return map == null ? new HashMap() : map; - } - - /** * return a list of objects from varargs. Though if there is one * object, and it is a list, return it. * @@ -1060,121 +319,6 @@ } /** - * convert classes to a list - * @param classes The classes to be returned as a List - * @return list of classes - */ - public static List> toListClasses(Class... classes) { - return toList(classes); - } - - - - /** - * return a set of objects from varargs. - * - * @param template type of the objects - * @param objects The objects to be returned as a Set - * @return the set - */ - public static Set toSet(T... objects) { - - Set result = new LinkedHashSet(); - for (T object : objects) { - result.add(object); - } - return result; - } - - /** - * cache separator - */ - private static final String CACHE_SEPARATOR = "__"; - - /** - * string format of dates - */ - public static final String DATE_FORMAT = "yyyyMMdd"; - - /** - * format including minutes and seconds: yyyy/MM/dd HH:mm:ss - */ - public static final String DATE_MINUTES_SECONDS_FORMAT = "yyyy/MM/dd HH:mm:ss"; - - /** - * format including minutes and seconds: yyyyMMdd HH:mm:ss - */ - public static final String DATE_MINUTES_SECONDS_NO_SLASH_FORMAT = "yyyyMMdd HH:mm:ss"; - - /** - * format on screen of config for milestone: yyyy/MM/dd HH:mm:ss.SSS - */ - public static final String TIMESTAMP_FORMAT = "yyyy/MM/dd HH:mm:ss.SSS"; - - /** - * format on screen of config for milestone: yyyyMMdd HH:mm:ss.SSS - */ - public static final String TIMESTAMP_NO_SLASH_FORMAT = "yyyyMMdd HH:mm:ss.SSS"; - - /** - * date format, make sure to synchronize - */ - final static SimpleDateFormat dateFormat = new SimpleDateFormat(DATE_FORMAT); - - /** - * synchronize code that uses this standard formatter for dates with minutes and seconds - */ - final static SimpleDateFormat dateMinutesSecondsFormat = new SimpleDateFormat( - DATE_MINUTES_SECONDS_FORMAT); - - /** - * synchronize code that uses this standard formatter for dates with minutes and seconds - */ - final static SimpleDateFormat dateMinutesSecondsNoSlashFormat = new SimpleDateFormat( - DATE_MINUTES_SECONDS_NO_SLASH_FORMAT); - - /** - *
 format: yyyy/MM/dd HH:mm:ss.SSS synchronize code that uses this standard formatter for timestamps 
- */ - final static SimpleDateFormat timestampFormat = new SimpleDateFormat(TIMESTAMP_FORMAT); - - /** - * synchronize code that uses this standard formatter for timestamps - */ - final static SimpleDateFormat timestampNoSlashFormat = new SimpleDateFormat( - TIMESTAMP_NO_SLASH_FORMAT); - - /** - * If false, throw an assertException, and give a reason - * - * @param isTrue when false, throw a RuntimeException. When true, do nothing. - * @param reason the message used for the exception - */ - public static void assertion(boolean isTrue, String reason) { - if (!isTrue) { - throw new RuntimeException(reason); - } - - } - - /** - * use the field cache, expire every day (just to be sure no leaks) - */ - private static ExpirableCache> fieldSetCache = null; - - /** - * lazy load - * @return field set cache - */ - private static ExpirableCache> fieldSetCache() { - if (fieldSetCache == null) { - fieldSetCache = new ExpirableCache>(60*24); - } - return fieldSetCache; - } - - - /** * make a cache with max size to cache declared methods */ private static ExpirableCache declaredMethodsCache = null; @@ -1189,318 +333,9 @@ } return declaredMethodsCache; } - - - /** - * use the field cache, expire every day (just to be sure no leaks) - */ - private static ExpirableCache> getterSetCache = null; - /** - * lazy load - * @return getter cache - */ - private static ExpirableCache> getterSetCache() { - if (getterSetCache == null) { - getterSetCache = new ExpirableCache>(60*24); - } - return getterSetCache; - } - - - - /** - * use the field cache, expire every day (just to be sure no leaks) - */ - private static ExpirableCache> setterSetCache = null; - - - /** - * lazy load - * @return setter cache - */ - private static ExpirableCache> setterSetCache() { - if (setterSetCache == null) { - setterSetCache = new ExpirableCache>(60*24); - } - return setterSetCache; - } - - - /** - * Field lastId. - */ - private static char[] lastId = convertLongToStringSmall(new Date().getTime()) - .toCharArray(); - - /** - * cache the properties read from resource - */ - private static Map resourcePropertiesCache = new HashMap(); - - /** - * assign data to a field - * - * @param theClass - * the class which has the method - * @param invokeOn - * to call on or null for static - * @param fieldName - * method name to call - * @param dataToAssign - * data - * @param callOnSupers - * if static and method not exists, try on supers - * @param overrideSecurity - * true to call on protected or private etc methods - * @param typeCast - * true if we should typecast - * @param annotationWithValueOverride - * annotation with value of override - */ - public static void assignField(Class theClass, Object invokeOn, - String fieldName, Object dataToAssign, boolean callOnSupers, - boolean overrideSecurity, boolean typeCast, - Class annotationWithValueOverride) { - if (theClass == null && invokeOn != null) { - theClass = invokeOn.getClass(); - } - Field field = field(theClass, fieldName, callOnSupers, true); - assignField(field, invokeOn, dataToAssign, overrideSecurity, typeCast, - annotationWithValueOverride); - } - - /** - * assign data to a field. Will find the field in superclasses, will - * typecast, and will override security (private, protected, etc) - * - * @param theClass - * the class which has the method - * @param invokeOn - * to call on or null for static - * @param fieldName - * method name to call - * @param dataToAssign - * data - * @param annotationWithValueOverride - * annotation with value of override - */ - public static void assignField(Class theClass, Object invokeOn, - String fieldName, Object dataToAssign, - Class annotationWithValueOverride) { - assignField(theClass, invokeOn, fieldName, dataToAssign, true, true, - true, annotationWithValueOverride); - } - - /** - * assign data to a field - * - * @param field - * is the field to assign to - * @param invokeOn - * to call on or null for static - * @param dataToAssign - * data - * @param overrideSecurity - * true to call on protected or private etc methods - * @param typeCast - * true if we should typecast - */ - @SuppressWarnings("unchecked") - public static void assignField(Field field, Object invokeOn, - Object dataToAssign, boolean overrideSecurity, boolean typeCast) { - - try { - Class fieldType = field.getType(); - // typecast - if (typeCast) { - dataToAssign = - typeCast(dataToAssign, fieldType, - true, true); - } - if (overrideSecurity) { - field.setAccessible(true); - } - field.set(invokeOn, dataToAssign); - } catch (Exception e) { - throw new RuntimeException("Cant assign reflection field: " - + (field == null ? null : field.getName()) + ", on: " - + className(invokeOn) + ", with args: " - + classNameCollection(dataToAssign), e); - } - } - - /** - * null safe iterator getter if the type if collection - * - * @param collection the collection - * @return the iterator - */ - public static Iterator iterator(Object collection) { - if (collection == null) { - return null; - } - // array list doesnt need an iterator - if (collection instanceof Collection - && !(collection instanceof ArrayList)) { - return ((Collection) collection).iterator(); - } - return null; - } - - /** - * Null safe array length or map - * - * @param arrayOrCollection The array, Collection, or Map for which to find the length or size. - * @return the length of the array (0 for null) - */ - public static int length(Object arrayOrCollection) { - if (arrayOrCollection == null) { - return 0; - } - if (arrayOrCollection.getClass().isArray()) { - return Array.getLength(arrayOrCollection); - } - if (arrayOrCollection instanceof Collection) { - return ((Collection) arrayOrCollection).size(); - } - if (arrayOrCollection instanceof Map) { - return ((Map) arrayOrCollection).size(); - } - // simple non array non collection object - return 1; - } - - /** - * If array, get the element based on index, if Collection, get it based on - * iterator. - * - * @param arrayOrCollection The array, ArrayList, or Collection from which to get the specified element - * @param iterator for Collections, this iterator is used to find the next object - * @param index The object at this specified index, or when 0, the arrayOrCollection itself - * @return the object - */ - public static Object next(Object arrayOrCollection, Iterator iterator, - int index) { - if (arrayOrCollection.getClass().isArray()) { - return Array.get(arrayOrCollection, index); - } - if (arrayOrCollection instanceof ArrayList) { - return ((ArrayList) arrayOrCollection).get(index); - } - if (arrayOrCollection instanceof Collection) { - return iterator.next(); - } - // simple object - if (0 == index) { - return arrayOrCollection; - } - throw new RuntimeException("Invalid class type: " - + arrayOrCollection.getClass().getName()); - } - - /** - * Remove the iterator or index - * - * @param arrayOrCollection The Array, List, or Collection from which to remove the object referenced by the iterator or index number - * @param index Index of the item that should be removed. - * @return the object list or new array - */ - public static Object remove(Object arrayOrCollection, - int index) { - return remove(arrayOrCollection, null, index); - } - - /** - * Remove the iterator or index - * - * @param arrayOrCollection The Array, List, or Collection from which to remove the object referenced by the iterator or index number - * @param iterator Iterator for the collection used to remove the object. Takes precedence over index parameter when non-null. - * @param index Index of the item that should be removed. - * @return the object list or new array - */ - public static Object remove(Object arrayOrCollection, Iterator iterator, - int index) { - - //if there's an iterator, just use that - if (iterator != null) { - iterator.remove(); - return arrayOrCollection; - } - if (arrayOrCollection.getClass().isArray()) { - int newLength = Array.getLength(arrayOrCollection) - 1; - Object newArray = Array.newInstance(arrayOrCollection.getClass().getComponentType(), newLength); - if (newLength == 0) { - return newArray; - } - if (index > 0) { - System.arraycopy(arrayOrCollection, 0, newArray, 0, index); - } - if (index < newLength) { - System.arraycopy(arrayOrCollection, index+1, newArray, index, newLength - index); - } - return newArray; - } - if (arrayOrCollection instanceof List) { - ((List)arrayOrCollection).remove(index); - return arrayOrCollection; - } else if (arrayOrCollection instanceof Collection) { - //this should work unless there are duplicates or something weird - ((Collection)arrayOrCollection).remove(get(arrayOrCollection, index)); - return arrayOrCollection; - } - throw new RuntimeException("Invalid class type: " - + arrayOrCollection.getClass().getName()); - } - - /** - * print the simple names of a list of classes - * @param object An array of objects - * @return the simple names for the objects in the array - * @see Class#getSimpleName() - */ - public static String classesString(Object object) { - StringBuilder result = new StringBuilder(); - if (object.getClass().isArray()) { - int length = Array.getLength(object); - for (int i=0;i annotationWithValueOverride) { - - if (annotationWithValueOverride != null) { - // see if in annotation - Annotation annotation = field - .getAnnotation(annotationWithValueOverride); - if (annotation != null) { - - // type of the value, or String if not specific Class - // typeOfAnnotationValue = typeCast ? field.getType() : - // String.class; dataToAssign = - // AnnotationUtils.retrieveAnnotationValue( - // typeOfAnnotationValue, annotation, "value"); - - throw new RuntimeException("Not supported"); - } - } - assignField(field, invokeOn, dataToAssign, overrideSecurity, typeCast); - } - - /** - * assign data to a field. Will find the field in superclasses, will - * typecast, and will override security (private, protected, etc) - * - * @param invokeOn - * to call on or null for static - * @param fieldName - * method name to call - * @param dataToAssign - * data - */ - public static void assignField(Object invokeOn, String fieldName, - Object dataToAssign) { - assignField(null, invokeOn, fieldName, dataToAssign, true, true, true, - null); - } - - /** - * get a field object for a class, potentially in superclasses - * - * @param theClass - * The class potentially containing the field - * @param fieldName - * The name of the desired class field - * @param callOnSupers - * true if superclasses should be looked in for the field - * @param throwExceptionIfNotFound - * will throw runtime exception if not found - * @return the field object or null if not found (or exception if param is - * set) - * @see Class#getDeclaredField(String) - */ - public static Field field(Class theClass, String fieldName, - boolean callOnSupers, boolean throwExceptionIfNotFound) { - try { - Field field = theClass.getDeclaredField(fieldName); - // found it - return field; - } catch (NoSuchFieldException e) { - // if method not found - // if traversing up, and not Object, and not instance method - if (callOnSupers && !theClass.equals(Object.class)) { - return field(theClass.getSuperclass(), fieldName, callOnSupers, - throwExceptionIfNotFound); - } - } - // maybe throw an exception - if (throwExceptionIfNotFound) { - throw new RuntimeException("Cant find field: " + fieldName - + ", in: " + theClass + ", callOnSupers: " + callOnSupers); - } - return null; - } - - /** - * return a set of Strings for a class and type. This is not for any - * supertypes, only for the type at hand. includes final fields - * - * @param theClass the class to look for fields in - * @param fieldType - * or null for all - * @param includeStaticFields when true, include static fields - * @return the set of strings, or the empty Set if none - */ - @SuppressWarnings("unchecked") - public static Set fieldNames(Class theClass, Class fieldType, - boolean includeStaticFields) { - return fieldNamesHelper(theClass, theClass, fieldType, true, true, - includeStaticFields, null, true); - } - - /** - * get all field names from a class, including superclasses (if specified) - * - * @param theClass - * to look for fields in - * @param superclassToStopAt - * to go up to or null to go up to Object - * @param fieldType - * is the type of the field to get - * @param includeSuperclassToStopAt - * if we should include the superclass - * @param includeStaticFields - * if include static fields - * @param includeFinalFields - * if final fields should be included - * @return the set of field names or empty set if none - */ - public static Set fieldNames(Class theClass, - Class superclassToStopAt, Class fieldType, - boolean includeSuperclassToStopAt, boolean includeStaticFields, - boolean includeFinalFields) { - return fieldNamesHelper(theClass, superclassToStopAt, fieldType, - includeSuperclassToStopAt, includeStaticFields, - includeFinalFields, null, true); - - } - - /** - * get all field names from a class, including superclasses (if specified). - * ignore a certain marker annotation - * - * @param theClass - * to look for fields in - * @param superclassToStopAt - * to go up to or null to go up to Object - * @param fieldType - * is the type of the field to get - * @param includeSuperclassToStopAt - * if we should include the superclass - * @param includeStaticFields - * if include static fields - * @param includeFinalFields - * if final fields should be included - * @param markerAnnotationToIngore - * if this is not null, then if the field has this annotation, - * then do not include in list - * @return the set of field names - */ - public static Set fieldNames(Class theClass, - Class superclassToStopAt, Class fieldType, - boolean includeSuperclassToStopAt, boolean includeStaticFields, - boolean includeFinalFields, - Class markerAnnotationToIngore) { - return fieldNamesHelper(theClass, superclassToStopAt, fieldType, - includeSuperclassToStopAt, includeStaticFields, - includeFinalFields, markerAnnotationToIngore, false); - - } - - /** - * get all field names from a class, including superclasses (if specified) - * (up to and including the specified superclass). ignore a certain marker - * annotation. Dont get static or final field, and get fields of all types - * - * @param theClass - * to look for fields in - * @param superclassToStopAt - * to go up to or null to go up to Object - * @param markerAnnotationToIngore - * if this is not null, then if the field has this annotation, - * then do not include in list - * @return the set of field names or empty set if none - */ - public static Set fieldNames(Class theClass, - Class superclassToStopAt, - Class markerAnnotationToIngore) { - return fieldNamesHelper(theClass, superclassToStopAt, null, true, - false, false, markerAnnotationToIngore, false); - } - - /** - * get all field names from a class, including superclasses (if specified) - * - * @param theClass - * to look for fields in - * @param superclassToStopAt - * to go up to or null to go up to Object - * @param fieldType - * is the type of the field to get - * @param includeSuperclassToStopAt - * if we should include the superclass - * @param includeStaticFields - * if include static fields - * @param includeFinalFields - * true to include finals - * @param markerAnnotation - * if this is not null, then if the field has this annotation, - * then do not include in list (if includeAnnotation is false) - * @param includeAnnotation - * true if the attribute should be included if annotation is - * present, false if exclude - * @return the set of field names or empty set if none - */ - @SuppressWarnings("unchecked") - static Set fieldNamesHelper(Class theClass, - Class superclassToStopAt, Class fieldType, - boolean includeSuperclassToStopAt, boolean includeStaticFields, - boolean includeFinalFields, - Class markerAnnotation, - boolean includeAnnotation) { - Set fieldSet = fieldsHelper(theClass, superclassToStopAt, - fieldType, includeSuperclassToStopAt, includeStaticFields, - includeFinalFields, markerAnnotation, includeAnnotation); - Set fieldNameSet = new LinkedHashSet(); - for (Field field : fieldSet) { - fieldNameSet.add(field.getName()); - } - return fieldNameSet; - - } - - /** - * get all fields from a class, including superclasses (if specified) - * - * @param theClass - * to look for fields in - * @param superclassToStopAt - * to go up to or null to go up to Object - * @param fieldType - * is the type of the field to get - * @param includeSuperclassToStopAt - * if we should include the superclass - * @param includeStaticFields - * if include static fields - * @param includeFinalFields - * if final fields should be included - * @param markerAnnotation - * if this is not null, then if the field has this annotation, - * then do not include in list (if includeAnnotation is false) - * @param includeAnnotation - * true if the attribute should be included if annotation is - * present, false if exclude - * @return the set of fields (wont return null) - */ - @SuppressWarnings("unchecked") - public static Set fields(Class theClass, Class superclassToStopAt, - Class fieldType, boolean includeSuperclassToStopAt, - boolean includeStaticFields, boolean includeFinalFields, - Class markerAnnotation, - boolean includeAnnotation) { - return fieldsHelper(theClass, superclassToStopAt, fieldType, - includeSuperclassToStopAt, includeStaticFields, - includeFinalFields, markerAnnotation, includeAnnotation); - } - - /** - * get all fields from a class, including superclasses (if specified) (up to - * and including the specified superclass). ignore a certain marker - * annotation, or only include it. Dont get static or final field, and get - * fields of all types - * - * @param theClass - * to look for fields in - * @param superclassToStopAt - * to go up to or null to go up to Object - * @param markerAnnotation - * if this is not null, then if the field has this annotation, - * then do not include in list (if includeAnnotation is false) - * @param includeAnnotation - * true if the attribute should be included if annotation is - * present, false if exclude - * @return the set of field names or empty set if none - */ - @SuppressWarnings("unchecked") - public static Set fields(Class theClass, Class superclassToStopAt, - Class markerAnnotation, - boolean includeAnnotation) { - return fieldsHelper(theClass, superclassToStopAt, null, true, false, - false, markerAnnotation, includeAnnotation); - } - - /** - * get all fields from a class, including superclasses (if specified) - * - * @param theClass - * to look for fields in - * @param superclassToStopAt - * to go up to or null to go up to Object - * @param fieldType - * is the type of the field to get - * @param includeSuperclassToStopAt - * if we should include the superclass - * @param includeStaticFields - * if include static fields - * @param includeFinalFields - * if final fields should be included - * @param markerAnnotation - * if this is not null, then if the field has this annotation, - * then do not include in list (if includeAnnotation is false) - * @param includeAnnotation - * true if the attribute should be included if annotation is - * present, false if exclude - * @return the set of fields (wont return null) - */ - @SuppressWarnings("unchecked") - static Set fieldsHelper(Class theClass, Class superclassToStopAt, - Class fieldType, boolean includeSuperclassToStopAt, - boolean includeStaticFields, boolean includeFinalFields, - Class markerAnnotation, - boolean includeAnnotation) { - // MAKE SURE IF ANY MORE PARAMS ARE ADDED, THE CACHE KEY IS CHANGED! - - Set fieldNameSet = null; - String cacheKey = theClass + CACHE_SEPARATOR + superclassToStopAt - + CACHE_SEPARATOR + fieldType + CACHE_SEPARATOR - + includeSuperclassToStopAt + CACHE_SEPARATOR - + includeStaticFields + CACHE_SEPARATOR + includeFinalFields - + CACHE_SEPARATOR + markerAnnotation + CACHE_SEPARATOR - + includeAnnotation; - fieldNameSet = fieldSetCache().get(cacheKey); - if (fieldNameSet != null) { - return fieldNameSet; - } - - fieldNameSet = new LinkedHashSet(); - fieldsHelper(theClass, superclassToStopAt, fieldType, - includeSuperclassToStopAt, includeStaticFields, - includeFinalFields, markerAnnotation, fieldNameSet, - includeAnnotation); - - // add to cache - fieldSetCache().put(cacheKey, fieldNameSet); - - return fieldNameSet; - - } - - /** - * compare two objects, compare primitives, Strings, maps of string attributes. - * if both objects equal each others references, then return empty set. - * Otherwise if not, then if either is null, return all fields - * - * @param first The first object to compare. - * @param second The second object to compare. - * @param fieldsToCompare The field names on both objects that should be compared - * @param mapPrefix is the prefix for maps which are compared (e.g. attribute__) - * @return the set of fields which are different. never returns null - */ - @SuppressWarnings("unchecked") - public static Set compareObjectFields(Object first, Object second, - Set fieldsToCompare, String mapPrefix) { - - Set differentFields = new LinkedHashSet(); - - if (first == second) { - return differentFields; - } - - //if either null, then all fields are different - if (first == null || second == null) { - differentFields.addAll(fieldsToCompare); - } - - for (String fieldName : fieldsToCompare) { - try { - Object firstValue = fieldValue(first, fieldName); - Object secondValue = fieldValue(second, fieldName); - - if (firstValue == secondValue) { - continue; - } - if (firstValue instanceof Map || secondValue instanceof Map) { - mapDifferences((Map)firstValue, (Map)secondValue, differentFields, mapPrefix); - continue; - } - //compare things... - //for strings, null is equal to empty - if (firstValue instanceof String || secondValue instanceof String) { - if (!equals(defaultString((String)firstValue), - defaultString((String)secondValue))) { - differentFields.add(fieldName); - } - continue; - } - //if one is null, that is not good - if (firstValue == null || secondValue == null) { - differentFields.add(fieldName); - continue; - } - //everything (numbers, dates, etc) should work with equals method... - if (!firstValue.equals(secondValue)) { - differentFields.add(fieldName); - } - - } catch (RuntimeException re) { - throw new RuntimeException("Problem comparing field " + fieldName - + " on objects: " + className(first) + ", " + className(second)); - } - - - } - return differentFields; - } - - /** - * clone an object, assign primitives, Strings, maps of string attributes. Clone GrouperCloneable fields. - * @param the type - * @param object the object to clone - * @param fieldsToClone the desired fields from the object - * @return the cloned object or null if input is null - */ - @SuppressWarnings("unchecked") - public static T clone(T object, Set fieldsToClone) { - - //make a return object - T result = (T)newInstance(object.getClass()); - - cloneFields(object, result, fieldsToClone); - - return result; - } - - /** - * clone an object, assign primitives, Strings, maps of string attributes. Clone GrouperCloneable fields. - * @param the type - * @param object the object to clone - * @param result the resulting object - * @param fieldsToClone the desired fields from the object - */ - public static void cloneFields(T object, T result, - Set fieldsToClone) { - - if (object == result) { - return; - } - - //if either null, then all fields are different - if (object == null || result == null) { - throw new RuntimeException("Cant copy from or to null: " + className(object) + ", " + className(result)); - } - - Class fieldValueClass = null; - - for (String fieldName : nonNull(fieldsToClone)) { - try { - - Object fieldValue = fieldValue(object, fieldName); - fieldValueClass = fieldValue == null ? null : fieldValue.getClass(); - - Object fieldValueToAssign = cloneValue(fieldValue); - - //assign the field to the clone - assignField(result, fieldName, fieldValueToAssign); - - } catch (RuntimeException re) { - throw new RuntimeException("Problem cloning field: " + object.getClass() - + ", " + fieldName + ", " + fieldValueClass, re); - } - } - } - - /** - * helper method to clone the value of a field. just returns the same - * reference for primitives and immutables. Will subclone GrouperCloneables, - * and will throw exception if not expecting the type. Will clone sets, lists, maps. - * @param template - * - * @param value The value to clone - * @return the cloned value - */ - @SuppressWarnings("unchecked") - public static T cloneValue(T value) { - - Object clonedValue = value; - - if (value == null || value instanceof String - || value.getClass().isPrimitive() || value instanceof Number - || value instanceof Boolean - || value instanceof Date) { - //clone things - //for strings, and immutable classes, just assign - //nothing to do, just assign the value - } else if (value instanceof Map) { - clonedValue = new LinkedHashMap(); - Map mapValue = (Map)value; - Map clonedMapValue = (Map)clonedValue; - for (Object key : mapValue.keySet()) { - clonedMapValue.put(cloneValue(key), cloneValue(mapValue.get(key))); - } - } else if (value instanceof Set) { - clonedValue = new LinkedHashSet(); - Set setValue = (Set)value; - Set clonedSetValue = (Set)clonedValue; - for (Object each : setValue) { - clonedSetValue.add(cloneValue(each)); - } - } else if (value instanceof List) { - clonedValue = new ArrayList(); - List listValue = (List)value; - List clonedListValue = (List)clonedValue; - for (Object each : listValue) { - clonedListValue.add(cloneValue(each)); - } - } else if (value.getClass().isArray()) { - clonedValue = Array.newInstance(value.getClass().getComponentType(), Array.getLength(value)); - for (int i=0;i methodNames(Class theClass, Class superclassToStopAt, - boolean includeSuperclassToStopAt, boolean includeStaticMethods) { - - Set methods = new LinkedHashSet(); - methodsHelper(theClass, superclassToStopAt, includeSuperclassToStopAt, includeStaticMethods, - null, false, methods); - Set methodNames = new HashSet(); - for (Method method : methods) { - methodNames.add(method.getName()); - } - return methodNames; - } - - /** - * get the set of methods and add them to the provided set - * @param theClass - * class with methods - * @param superclassToStopAt - * when recursing, stop at this class - * @param includeSuperclassToStopAt - * when true, bound is inclusive of stop class - * @param includeStaticMethods - * when true, include static methods (otherwise static methods are excluded) - * @param markerAnnotation - * a marker annotation - * @param includeAnnotation - * when true, include annotation - * @param methodSet - * Holds resulting Methods - * @see Class#getDeclaredMethods() - */ - public static void methodsHelper(Class theClass, Class superclassToStopAt, - boolean includeSuperclassToStopAt, - boolean includeStaticMethods, Class markerAnnotation, - boolean includeAnnotation, Set methodSet) { - Method[] methods = theClass.getDeclaredMethods(); - if (length(methods) != 0) { - for (Method method : methods) { - // if not static, then continue - if (!includeStaticMethods - && Modifier.isStatic(method.getModifiers())) { - continue; - } - // if checking for annotation - if (markerAnnotation != null - && (includeAnnotation != method - .isAnnotationPresent(markerAnnotation))) { - continue; - } - // go for it - methodSet.add(method); - } - } - // see if done recursing (if superclassToStopAt is null, then stop at - // Object - if (theClass.equals(superclassToStopAt) - || theClass.equals(Object.class)) { - return; - } - Class superclass = theClass.getSuperclass(); - if (!includeSuperclassToStopAt && superclass.equals(superclassToStopAt)) { - return; - } - // recurse - methodsHelper(superclass, superclassToStopAt, - includeSuperclassToStopAt, includeStaticMethods, - markerAnnotation, includeAnnotation, methodSet); - - } - - /** - * get the method - * @param theClass - * class with methods - * @param methodName - * the method name - * @param paramTypesOrArrayOrList - * types of the params - * @param superclassToStopAt - * the super class beyond which no more searching is performed - * @param includeSuperclassToStopAt - * when true, the superclassToStopAt is included in the search - * @param isStaticOrInstance true if static - * @param markerAnnotation the annotation to look for - * @param includeAnnotation when true, include the annotation - * @return the method or null if not found - * - */ - public static Method method(Class theClass, - String methodName, Object paramTypesOrArrayOrList, - Class superclassToStopAt, - boolean includeSuperclassToStopAt, - boolean isStaticOrInstance, Class markerAnnotation, - boolean includeAnnotation) { - - Class[] paramTypesArray = (Class[]) toArray(paramTypesOrArrayOrList); - - Method method = null; - - try { - method = theClass.getDeclaredMethod(methodName, paramTypesArray); - } catch (NoSuchMethodException nsme) { - //this is ok - } catch (Exception e) { - throw new RuntimeException("Problem retrieving method: " + theClass.getSimpleName() + ", " + methodName, e); - } - - if (method != null) { - //we found a method, make sure it is valid - // if not static, then return null (dont worry about superclass) - if (!isStaticOrInstance - && Modifier.isStatic(method.getModifiers())) { - return null; - } - // if checking for annotation, if not there, then recurse - if (markerAnnotation == null - || (includeAnnotation == method - .isAnnotationPresent(markerAnnotation))) { - return method; - } - } - // see if done recursing (if superclassToStopAt is null, then stop at - // Object - if (theClass.equals(superclassToStopAt) - || theClass.equals(Object.class)) { - return null; - } - Class superclass = theClass.getSuperclass(); - if (!includeSuperclassToStopAt && superclass.equals(superclassToStopAt)) { - return null; - } - // recurse - return method(superclass, methodName, paramTypesArray, superclassToStopAt, - includeSuperclassToStopAt, isStaticOrInstance, markerAnnotation, includeAnnotation); - } - - /** - * get all field names from a class, including superclasses (if specified) - * - * @param theClass - * to look for fields in - * @param superclassToStopAt - * to go up to or null to go up to Object - * @param fieldType - * is the type of the field to get - * @param includeSuperclassToStopAt - * if we should include the superclass - * @param includeStaticFields - * if include static fields - * @param includeFinalFields - * if final fields should be included - * @param markerAnnotation - * if this is not null, then if the field has this annotation, - * then do not include in list - * @param fieldSet - * set to add fields to - * @param includeAnnotation - * if include or exclude - */ - @SuppressWarnings("unchecked") - private static void fieldsHelper(Class theClass, Class superclassToStopAt, - Class fieldType, boolean includeSuperclassToStopAt, - boolean includeStaticFields, boolean includeFinalFields, - Class markerAnnotation, Set fieldSet, - boolean includeAnnotation) { - Field[] fields = theClass.getDeclaredFields(); - if (length(fields) != 0) { - for (Field field : fields) { - // if checking for type, and not right type, continue - if (fieldType != null - && !fieldType.isAssignableFrom(field.getType())) { - continue; - } - // if not static, then continue - if (!includeStaticFields - && Modifier.isStatic(field.getModifiers())) { - continue; - } - // if not final constinue - if (!includeFinalFields - && Modifier.isFinal(field.getModifiers())) { - continue; - } - // if checking for annotation - if (markerAnnotation != null - && (includeAnnotation != field - .isAnnotationPresent(markerAnnotation))) { - continue; - } - // go for it - fieldSet.add(field); - } - } - // see if done recursing (if superclassToStopAt is null, then stop at - // Object - if (theClass.equals(superclassToStopAt) - || theClass.equals(Object.class)) { - return; - } - Class superclass = theClass.getSuperclass(); - if (!includeSuperclassToStopAt && superclass.equals(superclassToStopAt)) { - return; - } - // recurse - fieldsHelper(superclass, superclassToStopAt, fieldType, - includeSuperclassToStopAt, includeStaticFields, - includeFinalFields, markerAnnotation, fieldSet, - includeAnnotation); - } - - /** - * find out a field value - * - * @param theClass - * the class which has the method - * @param invokeOn - * to call on or null for static - * @param fieldName - * method name to call - * @param callOnSupers - * if static and method not exists, try on supers - * @param overrideSecurity - * true to call on protected or private etc methods - * @return the current value - */ - public static Object fieldValue(Class theClass, Object invokeOn, - String fieldName, boolean callOnSupers, boolean overrideSecurity) { - Field field = null; - - // only if the method exists, try to execute - try { - // ok if null - if (theClass == null) { - theClass = invokeOn.getClass(); - } - field = field(theClass, fieldName, callOnSupers, true); - return fieldValue(field, invokeOn, overrideSecurity); - } catch (Exception e) { - throw new RuntimeException("Cant execute reflection field: " - + fieldName + ", on: " + className(invokeOn), e); - } - } - - /** - * get the value of a field, override security if needbe - * - * @param field the field - * @param invokeOn the object on which to invoke the field - * @return the value of the field - */ - public static Object fieldValue(Field field, Object invokeOn) { - return fieldValue(field, invokeOn, true); - } - - /** - * get the value of a field - * - * @param field the field - * @param invokeOn the object on which to invoke the field - * @param overrideSecurity when true, set accessible on the field - * @return the value of the field - * @see java.lang.reflect.Field#get(Object) - */ - public static Object fieldValue(Field field, Object invokeOn, - boolean overrideSecurity) { - if (overrideSecurity) { - field.setAccessible(true); - } - try { - return field.get(invokeOn); - } catch (Exception e) { - throw new RuntimeException("Cant execute reflection field: " - + field.getName() + ", on: " + className(invokeOn), e); - - } - - } - - /** - * find out a field value (invoke on supers, override security) - * - * @param invokeOn - * to call on or null for static - * @param fieldName - * method name to call - * @return the current value - */ - public static Object fieldValue(Object invokeOn, String fieldName) { - return fieldValue(null, invokeOn, fieldName, true, true); - } - - /** * get the decalred methods for a class, perhaps from cache * * @param theClass the class @@ -2359,2257 +362,8 @@ return methods; } - /** - * helper method for calling a method with no params (could be in - * superclass) - * - * @param theClass - * the class which has the method - * @param invokeOn - * to call on or null for static - * @param methodName - * method name to call - * @return the data - */ - public static Object callMethod(Class theClass, Object invokeOn, - String methodName) { - return callMethod(theClass, invokeOn, methodName, null, null); - } /** - * helper method for calling a method (could be in superclass) - * - * @param theClass - * the class which has the method - * @param invokeOn - * to call on or null for static - * @param methodName - * method name to call - * @param paramTypesOrArrayOrList - * types of the params - * @param paramsOrListOrArray - * data - * @return the data - */ - public static Object callMethod(Class theClass, Object invokeOn, - String methodName, Object paramTypesOrArrayOrList, - Object paramsOrListOrArray) { - return callMethod(theClass, invokeOn, methodName, - paramTypesOrArrayOrList, paramsOrListOrArray, true); - } - - /** - * helper method for calling a method - * - * @param theClass - * the class which has the method - * @param invokeOn - * to call on or null for static - * @param methodName - * method name to call - * @param paramTypesOrArrayOrList - * types of the params - * @param paramsOrListOrArray - * data - * @param callOnSupers - * if static and method not exists, try on supers - * @return the data - */ - public static Object callMethod(Class theClass, Object invokeOn, - String methodName, Object paramTypesOrArrayOrList, - Object paramsOrListOrArray, boolean callOnSupers) { - return callMethod(theClass, invokeOn, methodName, - paramTypesOrArrayOrList, paramsOrListOrArray, callOnSupers, - false); - } - - /** - * construct an instance by reflection - * @param the type - * @param theClass the class - * @param types the types array - * @param args the arguments array - * @return the instance - */ - public static T construct(Class theClass, Class[] types, Object[] args) { - try { - Constructor constructor = theClass.getConstructor(types); - - return constructor.newInstance(args); - - } catch (Exception e) { - throw new RuntimeException("Having trouble with constructor for class: " + theClass.getSimpleName() - + " and args: " + classesString(types), e); - } - } - - /** - * helper method for calling a method - * - * @param theClass - * the class which has the method - * @param invokeOn - * to call on or null for static - * @param methodName - * method name to call - * @param paramTypesOrArrayOrList - * types of the params - * @param paramsOrListOrArray - * data - * @param callOnSupers - * if static and method not exists, try on supers - * @param overrideSecurity - * true to call on protected or private etc methods - * @return the data - */ - public static Object callMethod(Class theClass, Object invokeOn, - String methodName, Object paramTypesOrArrayOrList, - Object paramsOrListOrArray, boolean callOnSupers, - boolean overrideSecurity) { - Method method = null; - - Class[] paramTypesArray = (Class[]) toArray(paramTypesOrArrayOrList); - - try { - method = theClass.getDeclaredMethod(methodName, paramTypesArray); - if (overrideSecurity) { - method.setAccessible(true); - } - } catch (Exception e) { - // if method not found - if (e instanceof NoSuchMethodException) { - // if traversing up, and not Object, and not instance method - // CH 070425 not sure why invokeOn needs to be null, removing - // this - if (callOnSupers /* && invokeOn == null */ - && !theClass.equals(Object.class)) { - return callMethod(theClass.getSuperclass(), invokeOn, - methodName, paramTypesOrArrayOrList, - paramsOrListOrArray, callOnSupers, overrideSecurity); - } - } - throw new RuntimeException("Problem calling method " + methodName - + " on " + theClass.getName(), e); - } - - return invokeMethod(method, invokeOn, paramsOrListOrArray); - - } - - /** pass this in the invokeOn to signify no params */ - private static final Object NO_PARAMS = new Object(); - - /** - * Safely invoke a reflection method that takes no args - * - * @param method - * to invoke - * @param invokeOn the object on which to invoke the method - * if NO_PARAMS then will not pass in params. - * @return the result - */ - public static Object invokeMethod(Method method, Object invokeOn) { - return invokeMethod(method, invokeOn, NO_PARAMS); - } - - /** - * Safely invoke a reflection method - * - * @param method - * to invoke - * @param invokeOn the object on which to invoke the method - * @param paramsOrListOrArray must be an arg. If null, will pass null. - * if NO_PARAMS then will not pass in params. - * @return the result - */ - public static Object invokeMethod(Method method, Object invokeOn, - Object paramsOrListOrArray) { - - Object[] args = paramsOrListOrArray == NO_PARAMS ? null : (Object[]) toArray(paramsOrListOrArray); - - //we want to make sure things are accessible - method.setAccessible(true); - - //only if the method exists, try to execute - Object result = null; - Exception e = null; - try { - result = method.invoke(invokeOn, args); - } catch (IllegalAccessException iae) { - e = iae; - } catch (IllegalArgumentException iae) { - e = iae; - } catch (InvocationTargetException ite) { - //this means the underlying call caused exception... its ok if runtime - if (ite.getCause() instanceof RuntimeException) { - throw (RuntimeException)ite.getCause(); - } - //else throw as invocation target... - e = ite; - } - if (e != null) { - throw new RuntimeException("Cant execute reflection method: " - + method.getName() + ", on: " + className(invokeOn) - + ", with args: " + classNameCollection(args), e); - } - return result; - } - - /** - * Convert a list to an array with the type of the first element e.g. if it - * is a list of Person objects, then the array is Person[] - * - * @param objectOrArrayOrCollection - * is a list - * @return the array of objects with type of the first element in the list - */ - public static Object toArray(Object objectOrArrayOrCollection) { - // do this before length since if array with null in it, we want ti get - // it back - if (objectOrArrayOrCollection != null - && objectOrArrayOrCollection.getClass().isArray()) { - return objectOrArrayOrCollection; - } - int length = length(objectOrArrayOrCollection); - if (length == 0) { - return null; - } - - if (objectOrArrayOrCollection instanceof Collection) { - Collection collection = (Collection) objectOrArrayOrCollection; - Object first = collection.iterator().next(); - return toArray(collection, first == null ? Object.class : first - .getClass()); - } - // make an array of the type of object passed in, size one - Object array = Array.newInstance(objectOrArrayOrCollection.getClass(), - 1); - Array.set(array, 0, objectOrArrayOrCollection); - return array; - } - - /** - * convert a list into an array of type of theClass - * @param is the type of the array - * @param collection list to convert - * @param theClass type of array to return - * @return array of type theClass[] filled with the objects from list - */ - @SuppressWarnings("unchecked") - public static T[] toArray(Collection collection, Class theClass) { - if (collection == null || collection.size() == 0) { - return null; - } - - return (T[])collection.toArray((Object[]) Array.newInstance(theClass, - collection.size())); - - } - - /** - * helper method for calling a static method up the stack. method takes no - * args (could be in superclass) - * - * @param theClass - * the class which has the method - * @param methodName - * method name to call - * @return the data - */ - public static Object callMethod(Class theClass, String methodName) { - return callMethod(theClass, null, methodName, null, null); - } - - /** - * helper method for calling a static method with no params - * - * @param theClass - * the class which has the method - * @param methodName - * method name to call - * @param callOnSupers - * if we should try the super classes if not exists in this class - * @return the data - */ - public static Object callMethod(Class theClass, String methodName, - boolean callOnSupers) { - return callMethod(theClass, null, methodName, null, null, callOnSupers); - } - - /** - * helper method for calling a static method up the stack - * - * @param theClass - * the class which has the method - * @param methodName - * method name to call - * @param paramTypesOrArrayOrList - * types of the params - * @param paramsOrListOrArray - * data - * @return the data - */ - public static Object callMethod(Class theClass, String methodName, - Object paramTypesOrArrayOrList, Object paramsOrListOrArray) { - return callMethod(theClass, null, methodName, paramTypesOrArrayOrList, - paramsOrListOrArray); - } - - /** - * helper method for calling a method with no params (could be in - * superclass), will override security - * - * @param invokeOn - * instance to invoke on - * @param methodName - * method name to call not exists in this class - * @return the data - */ - public static Object callMethod(Object invokeOn, String methodName) { - if (invokeOn == null) { - throw new NullPointerException("invokeOn is null: " + methodName); - } - return callMethod(invokeOn.getClass(), invokeOn, methodName, null, - null, true, true); - } - - /** - * replace a string or strings from a string, and put the output in a string - * buffer. This does not recurse - * - * @param text - * string to look in - * @param searchFor - * string array to search for - * @param replaceWith - * string array to replace with - * @return the string - */ - public static String replace(String text, Object searchFor, - Object replaceWith) { - return replace(null, null, text, searchFor, replaceWith, false, 0, - false); - } - - /** - * replace a string or strings from a string, and put the output in a string - * buffer - * - * @param text - * string to look in - * @param searchFor - * string array to search for - * @param replaceWith - * string array to replace with - * @param recurse - * if true then do multiple replaces (on the replacements) - * @return the string - */ - public static String replace(String text, Object searchFor, - Object replaceWith, boolean recurse) { - return replace(null, null, text, searchFor, replaceWith, recurse, - recurse ? length(searchFor) : 0, false); - } - - /** - * replace a string or strings from a string, and put the output in a string - * buffer - * - * @param text - * string to look in - * @param searchFor - * string array to search for - * @param replaceWith - * string array to replace with - * @param recurse - * if true then do multiple replaces (on the replacements) - * @param removeIfFound - * true if removing from searchFor and replaceWith if found - * @return the string - */ - public static String replace(String text, Object searchFor, - Object replaceWith, boolean recurse, boolean removeIfFound) { - return replace(null, null, text, searchFor, replaceWith, recurse, - recurse ? length(searchFor) : 0, removeIfFound); - } - - /** - *

- * Replaces all occurrences of a String within another String. - *

- * - *

- * A null reference passed to this method is a no-op. - *

- * - *
-   * replace(null, *, *)        = null
-   * replace("", *, *)          = ""
-   * replace("any", null, *)    = "any"
-   * replace("any", *, null)    = "any"
-   * replace("any", "", *)      = "any"
-   * replace("aba", "a", null)  = "aba"
-   * replace("aba", "a", "")    = "b"
-   * replace("aba", "a", "z")   = "zbz"
-   * 
- * - * @see #replace(String text, String repl, String with, int max) - * @param text - * text to search and replace in, may be null - * @param repl - * the String to search for, may be null - * @param with - * the String to replace with, may be null - * @return the text with any replacements processed, null if - * null String input - */ - public static String replace(String text, String repl, String with) { - return replace(text, repl, with, -1); - } - - /** - *

- * Replaces a String with another String inside a larger String, for the - * first max values of the search String. - *

- * - *

- * A null reference passed to this method is a no-op. - *

- * - *
-   * replace(null, *, *, *)         = null
-   * replace("", *, *, *)           = ""
-   * replace("any", null, *, *)     = "any"
-   * replace("any", *, null, *)     = "any"
-   * replace("any", "", *, *)       = "any"
-   * replace("any", *, *, 0)        = "any"
-   * replace("abaa", "a", null, -1) = "abaa"
-   * replace("abaa", "a", "", -1)   = "b"
-   * replace("abaa", "a", "z", 0)   = "abaa"
-   * replace("abaa", "a", "z", 1)   = "zbaa"
-   * replace("abaa", "a", "z", 2)   = "zbza"
-   * replace("abaa", "a", "z", -1)  = "zbzz"
-   * 
- * - * @param text - * text to search and replace in, may be null - * @param repl - * the String to search for, may be null - * @param with - * the String to replace with, may be null - * @param max - * maximum number of values to replace, or -1 if - * no maximum - * @return the text with any replacements processed, null if - * null String input - */ - public static String replace(String text, String repl, String with, int max) { - if (text == null || isEmpty(repl) || with == null || max == 0) { - return text; - } - - StringBuffer buf = new StringBuffer(text.length()); - int start = 0, end = 0; - while ((end = text.indexOf(repl, start)) != -1) { - buf.append(text.substring(start, end)).append(with); - start = end + repl.length(); - - if (--max == 0) { - break; - } - } - buf.append(text.substring(start)); - return buf.toString(); - } - - /** - *

- * Checks if a String is empty ("") or null. - *

- * - *
-   * isEmpty(null)      = true
-   * isEmpty("")        = true
-   * isEmpty(" ")       = false
-   * isEmpty("bob")     = false
-   * isEmpty("  bob  ") = false
-   * 
- * - *

- * NOTE: This method changed in Lang version 2.0. It no longer trims the - * String. That functionality is available in isBlank(). - *

- * - * @param str - * the String to check, may be null - * @return true if the String is empty or null - */ - public static boolean isEmpty(String str) { - return str == null || str.length() == 0; - } - - /** - * replace a string or strings from a string, and put the output in a string - * buffer. This does not recurse - * - * @param outBuffer - * stringbuffer to write to - * @param text - * string to look in - * @param searchFor - * string array to search for - * @param replaceWith - * string array to replace with - */ - public static void replace(StringBuffer outBuffer, String text, - Object searchFor, Object replaceWith) { - replace(outBuffer, null, text, searchFor, replaceWith, false, 0, false); - } - - /** - * replace a string or strings from a string, and put the output in a string - * buffer - * - * @param outBuffer - * stringbuffer to write to - * @param text - * string to look in - * @param searchFor - * string array to search for - * @param replaceWith - * string array to replace with - * @param recurse - * if true then do multiple replaces (on the replacements) - */ - public static void replace(StringBuffer outBuffer, String text, - Object searchFor, Object replaceWith, boolean recurse) { - replace(outBuffer, null, text, searchFor, replaceWith, recurse, - recurse ? length(searchFor) : 0, false); - } - - /** - * replace a string with other strings, and either write to outWriter, or - * StringBuffer, and if StringBuffer potentially return a string. If - * outBuffer and outWriter are null, then return the String - * - * @param outBuffer - * stringbuffer to write to, or null to not - * @param outWriter - * Writer to write to, or null to not. - * @param text - * string to look in - * @param searchFor - * string array to search for, or string, or list - * @param replaceWith - * string array to replace with, or string, or list - * @param recurse - * if true then do multiple replaces (on the replacements) - * @param timeToLive - * if recursing, prevent endless loops - * @param removeIfFound - * true if removing from searchFor and replaceWith if found - * @return the String if outBuffer and outWriter are null - * @throws IndexOutOfBoundsException - * if the lengths of the arrays are not the same (null is ok, - * and/or size 0) - * @throws IllegalArgumentException - * if the search is recursive and there is an endless loop due - * to outputs of one being inputs to another - */ - private static String replace(StringBuffer outBuffer, Writer outWriter, - String text, Object searchFor, Object replaceWith, boolean recurse, - int timeToLive, boolean removeIfFound) { - - // if recursing, we need to get the string, then print to buffer (since - // we need multiple passes) - if (!recurse) { - return replaceHelper(outBuffer, outWriter, text, searchFor, - replaceWith, recurse, timeToLive, removeIfFound); - } - // get the string - String result = replaceHelper(null, null, text, searchFor, replaceWith, - recurse, timeToLive, removeIfFound); - if (outBuffer != null) { - outBuffer.append(result); - return null; - } - - if (outWriter != null) { - try { - outWriter.write(result); - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - return null; - } - - return result; - - } - - /** - * replace a string or strings from a string, and put the output in a string - * buffer. This does not recurse - * - * @param outWriter - * writer to write to - * @param text - * string to look in - * @param searchFor - * string array to search for - * @param replaceWith - * string array to replace with - */ - public static void replace(Writer outWriter, String text, Object searchFor, - Object replaceWith) { - replace(null, outWriter, text, searchFor, replaceWith, false, 0, false); - } - - /** - * replace a string or strings from a string, and put the output in a string - * buffer - * - * @param outWriter - * writer to write to - * @param text - * string to look in - * @param searchFor - * string array to search for - * @param replaceWith - * string array to replace with - * @param recurse - * if true then do multiple replaces (on the replacements) - */ - public static void replace(Writer outWriter, String text, Object searchFor, - Object replaceWith, boolean recurse) { - replace(null, outWriter, text, searchFor, replaceWith, recurse, - recurse ? length(searchFor) : 0, false); - } - - /** - * replace a string with other strings, and either write to outWriter, or - * StringBuffer, and if StringBuffer potentially return a string. If - * outBuffer and outWriter are null, then return the String - * - * @param outBuffer - * stringbuffer to write to, or null to not - * @param outWriter - * Writer to write to, or null to not. - * @param text - * string to look in - * @param searchFor - * string array to search for, or string, or list - * @param replaceWith - * string array to replace with, or string, or list - * @param recurse - * if true then do multiple replaces (on the replacements) - * @param timeToLive - * if recursing, prevent endless loops - * @param removeIfFound - * true if removing from searchFor and replaceWith if found - * @return the String if outBuffer and outWriter are null - * @throws IllegalArgumentException - * if the search is recursive and there is an endless loop due - * to outputs of one being inputs to another - * @throws IndexOutOfBoundsException - * if the lengths of the arrays are not the same (null is ok, - * and/or size 0) - */ - private static String replaceHelper(StringBuffer outBuffer, - Writer outWriter, String text, Object searchFor, - Object replaceWith, boolean recurse, int timeToLive, - boolean removeIfFound) { - - try { - // if recursing, this shouldnt be less than 0 - if (timeToLive < 0) { - throw new IllegalArgumentException("TimeToLive under 0: " - + timeToLive + ", " + text); - } - - int searchForLength = length(searchFor); - boolean done = false; - // no need to do anything - if (isEmpty(text)) { - return text; - } - // need to write the input to output, later - if (searchForLength == 0) { - done = true; - } - - boolean[] noMoreMatchesForReplIndex = null; - int inputIndex = -1; - int replaceIndex = -1; - long resultPacked = -1; - - if (!done) { - // make sure lengths are ok, these need to be equal - if (searchForLength != length(replaceWith)) { - throw new IndexOutOfBoundsException("Lengths dont match: " - + searchForLength + ", " + length(replaceWith)); - } - - // keep track of which still have matches - noMoreMatchesForReplIndex = new boolean[searchForLength]; - - // index of replace array that will replace the search string - // found - - - resultPacked = findNextIndexHelper(searchForLength, searchFor, - replaceWith, - noMoreMatchesForReplIndex, text, 0); - - inputIndex = unpackInt(resultPacked, true); - replaceIndex = unpackInt(resultPacked, false); - } - - // get a good guess on the size of the result buffer so it doesnt - // have to double if it - // goes over a bit - boolean writeToWriter = outWriter != null; - - // no search strings found, we are done - if (done || inputIndex == -1) { - if (writeToWriter) { - outWriter.write(text, 0, text.length()); - return null; - } - if (outBuffer != null) { - appendSubstring(outBuffer, text, 0, text.length()); - return null; - } - return text; - } - - // no buffer if writing to writer - StringBuffer bufferToWriteTo = outBuffer != null ? outBuffer - : (writeToWriter ? null : new StringBuffer(text.length() - + replaceStringsBufferIncrease(text, searchFor, - replaceWith))); - - String searchString = null; - String replaceString = null; - - int start = 0; - - while (inputIndex != -1) { - - searchString = (String) get(searchFor, replaceIndex); - replaceString = (String) get(replaceWith, replaceIndex); - if (writeToWriter) { - outWriter.write(text, start, inputIndex - start); - outWriter.write(replaceString); - } else { - appendSubstring(bufferToWriteTo, text, start, inputIndex) - .append(replaceString); - } - - if (removeIfFound) { - // better be an iterator based find replace - searchFor = remove(searchFor, replaceIndex); - replaceWith = remove(replaceWith, replaceIndex); - noMoreMatchesForReplIndex = (boolean[])remove(noMoreMatchesForReplIndex, replaceIndex); - // we now have a lesser size if we removed one - searchForLength--; - } - - start = inputIndex + searchString.length(); - - resultPacked = findNextIndexHelper(searchForLength, searchFor, - replaceWith, - noMoreMatchesForReplIndex, text, start); - inputIndex = unpackInt(resultPacked, true); - replaceIndex = unpackInt(resultPacked, false); - } - if (writeToWriter) { - outWriter.write(text, start, text.length() - start); - - } else { - appendSubstring(bufferToWriteTo, text, start, text.length()); - } - - // no need to convert to string if incoming buffer or writer - if (writeToWriter || outBuffer != null) { - if (recurse) { - throw new IllegalArgumentException( - "Cannot recurse and write to existing buffer or writer!"); - } - return null; - } - String resultString = bufferToWriteTo.toString(); - - if (recurse) { - return replaceHelper(outBuffer, outWriter, resultString, - searchFor, replaceWith, recurse, timeToLive - 1, false); - } - // this might be null for writer - return resultString; - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - } - - /** - * give a best guess on buffer increase for String[] replace get a good - * guess on the size of the result buffer so it doesnt have to double if it - * goes over a bit - * - * @param text - * @param repl - * @param with - * @return the increase, with 20% cap - */ - static int replaceStringsBufferIncrease(String text, Object repl, - Object with) { - // count the greaters - int increase = 0; - Iterator iteratorReplace = iterator(repl); - Iterator iteratorWith = iterator(with); - int replLength = length(repl); - String currentRepl = null; - String currentWith = null; - for (int i = 0; i < replLength; i++) { - currentRepl = (String) next(repl, iteratorReplace, i); - currentWith = (String) next(with, iteratorWith, i); - if (currentRepl == null || currentWith == null) { - throw new NullPointerException("Replace string is null: " - + text + ", " + currentRepl + ", " + currentWith); - } - int greater = currentWith.length() - currentRepl.length(); - increase += greater > 0 ? 3 * greater : 0; // assume 3 matches - } - // have upper-bound at 20% increase, then let Java take over - increase = Math.min(increase, text.length() / 5); - return increase; - } - - /** - * Helper method to find the next match in an array of strings replace - * - * @param searchForLength - * @param searchFor - * @param replaceWith - * @param noMoreMatchesForReplIndex - * @param input - * @param start - * is where to start looking - * @return result packed into a long, inputIndex first, then replaceIndex - */ - private static long findNextIndexHelper(int searchForLength, - Object searchFor, Object replaceWith, boolean[] noMoreMatchesForReplIndex, - String input, int start) { - - int inputIndex = -1; - int replaceIndex = -1; - - Iterator iteratorSearchFor = iterator(searchFor); - Iterator iteratorReplaceWith = iterator(replaceWith); - - String currentSearchFor = null; - String currentReplaceWith = null; - int tempIndex = -1; - for (int i = 0; i < searchForLength; i++) { - currentSearchFor = (String) next(searchFor, iteratorSearchFor, i); - currentReplaceWith = (String) next(replaceWith, - iteratorReplaceWith, i); - if (noMoreMatchesForReplIndex[i] || isEmpty(currentSearchFor) - || currentReplaceWith == null) { - continue; - } - tempIndex = input.indexOf(currentSearchFor, start); - - // see if we need to keep searching for this - noMoreMatchesForReplIndex[i] = tempIndex == -1; - - if (tempIndex != -1 && (inputIndex == -1 || tempIndex < inputIndex)) { - inputIndex = tempIndex; - replaceIndex = i; - } - - } - // dont create an array, no more objects - long resultPacked = packInts(inputIndex, replaceIndex); - return resultPacked; - } - - /** - * pack two ints into a long. Note: the first is held in the left bits, the - * second is held in the right bits - * - * @param first - * is first int - * @param second - * is second int - * @return the long which has two ints in there - */ - public static long packInts(int first, int second) { - long result = first; - result <<= 32; - result |= second; - return result; - } - - /** - * take a long - * - * @param theLong - * to unpack - * @param isFirst - * true for first, false for second - * @return one of the packed ints, first or second - */ - public static int unpackInt(long theLong, boolean isFirst) { - - int result = 0; - // put this in the position of the second one - if (isFirst) { - theLong >>= 32; - } - // only look at right part - result = (int) (theLong & 0xffffffff); - return result; - } - - /** - * append a substring to a stringbuffer. removes dependency on substring - * which creates objects - * - * @param buf - * stringbuffer - * @param string - * source string - * @param start - * start index of source string - * @param end - * end index of source string - * @return the string buffer for chaining - */ - private static StringBuffer appendSubstring(StringBuffer buf, - String string, int start, int end) { - for (int i = start; i < end; i++) { - buf.append(string.charAt(i)); - } - return buf; - } - - /** - * Get a specific index of an array or collection (note for collections and - * iterating, it is more efficient to get an iterator and iterate - * - * @param arrayOrCollection the array, List, or Collection - * @param index the index of the desired object - * @return the object at that index - */ - public static Object get(Object arrayOrCollection, int index) { - - if (arrayOrCollection == null) { - if (index == 0) { - return null; - } - throw new RuntimeException("Trying to access index " + index - + " of null"); - } - - // no need to iterator on list (e.g. FastProxyList has no iterator - if (arrayOrCollection instanceof List) { - return ((List) arrayOrCollection).get(index); - } - if (arrayOrCollection instanceof Collection) { - Iterator iterator = iterator(arrayOrCollection); - for (int i = 0; i < index; i++) { - next(arrayOrCollection, iterator, i); - } - return next(arrayOrCollection, iterator, index); - } - - if (arrayOrCollection.getClass().isArray()) { - return Array.get(arrayOrCollection, index); - } - - if (index == 0) { - return arrayOrCollection; - } - - throw new RuntimeException("Trying to access index " + index - + " of and object: " + arrayOrCollection); - } - - - - /** - * fail safe toString for Exception blocks, and include the stack - * if there is a problem with toString() - * @param object object to convert to human-readable string. - * @return the toStringSafe string - */ - @SuppressWarnings("unchecked") - public static String toStringSafe(Object object) { - if (object == null) { - return null; - } - - try { - //give size and type if collection - if (object instanceof Collection) { - Collection collection = (Collection) object; - int collectionSize = collection.size(); - if (collectionSize == 0) { - return "Empty " + object.getClass().getSimpleName(); - } - Object first = collection.iterator().next(); - return object.getClass().getSimpleName() + " of size " - + collectionSize + " with first type: " + - (first == null ? null : first.getClass()); - } - - return object.toString(); - } catch (Exception e) { - return "<> " + object.getClass() + ":\n" + getFullStackTrace(e) + "\n"; - } - } - - /** - * get the boolean value for an object, cant be null or blank - * - * @param object object to convert to a boolean. Supports string values of "true", "t", "yes" and "y" as true. - * @return the boolean - */ - public static boolean booleanValue(Object object) { - // first handle blanks - if (nullOrBlank(object)) { - throw new RuntimeException( - "Expecting something which can be converted to boolean, but is null or blank: '" - + object + "'"); - } - // its not blank, just convert - if (object instanceof Boolean) { - return (Boolean) object; - } - if (object instanceof String) { - String string = (String) object; - if (equalsIgnoreCase(string, "true") - || equalsIgnoreCase(string, "t") - || equalsIgnoreCase(string, "yes") - || equalsIgnoreCase(string, "y")) { - return true; - } - if (equalsIgnoreCase(string, "false") - || equalsIgnoreCase(string, "f") - || equalsIgnoreCase(string, "no") - || equalsIgnoreCase(string, "n")) { - return false; - } - throw new RuntimeException( - "Invalid string to boolean conversion: '" + string - + "' expecting true|false or t|f or yes|no or y|n case insensitive"); - - } - throw new RuntimeException("Cant convert object to boolean: " - + object.getClass()); - - } - - /** - * get the boolean value for an object - * - * @param object object to convert to a boolean - * @param defaultBoolean - * if object is null or empty - * @return the boolean - */ - public static boolean booleanValue(Object object, boolean defaultBoolean) { - if (nullOrBlank(object)) { - return defaultBoolean; - } - return booleanValue(object); - } - - /** - * get the Boolean value for an object - * - * @param object object to convert to a boolean - * @return the Boolean or null if null or empty - */ - public static Boolean booleanObjectValue(Object object) { - if (nullOrBlank(object)) { - return null; - } - return booleanValue(object); - } - - /** - * is an object null or blank - * - * @param object object to test for null or String to test for blank - * @return true if null or blank - */ - public static boolean nullOrBlank(Object object) { - // first handle blanks and nulls - if (object == null) { - return true; - } - if (object instanceof String && isBlank(((String) object))) { - return true; - } - return false; - - } - - /** - * get a getter method object for a class, potentially in superclasses - * @param theClass the class - * @param fieldName the field name - * @param callOnSupers true if superclasses should be looked in for the getter - * @param throwExceptionIfNotFound will throw runtime exception if not found - * @return the getter object or null if not found (or exception if param is set) - */ - public static Method getter(Class theClass, String fieldName, boolean callOnSupers, - boolean throwExceptionIfNotFound) { - String getterName = getterNameFromPropertyName(fieldName); - return getterHelper(theClass, fieldName, getterName, callOnSupers, throwExceptionIfNotFound); - } - - /** - * get a setter method object for a class, potentially in superclasses - * @param theClass the class - * @param fieldName the field name - * @param getterName name of setter - * @param callOnSupers true if superclasses should be looked in for the setter - * @param throwExceptionIfNotFound will throw runtime exception if not found - * @return the setter object or null if not found (or exception if param is set) - */ - public static Method getterHelper(Class theClass, String fieldName, String getterName, - boolean callOnSupers, boolean throwExceptionIfNotFound) { - Method[] methods = retrieveDeclaredMethods(theClass); - if (methods != null) { - for (Method method : methods) { - if (equals(getterName, method.getName()) && isGetter(method)) { - return method; - } - } - } - //if method not found - //if traversing up, and not Object, and not instance method - if (callOnSupers && !theClass.equals(Object.class)) { - return getterHelper(theClass.getSuperclass(), fieldName, getterName, - callOnSupers, throwExceptionIfNotFound); - } - //maybe throw an exception - if (throwExceptionIfNotFound) { - throw new RuntimeException("Cant find getter: " - + getterName + ", in: " + theClass - + ", callOnSupers: " + callOnSupers); - } - return null; - } - - /** - * generate getFoo from foo - * @param propertyName the property name such as "foo" for which to generate method name "getFoo" - * @return the getter method name - */ - public static String getterNameFromPropertyName(String propertyName) { - return "get" + capitalize(propertyName); - } - - /** - * get all getters from a class, including superclasses (if specified) (up to and including the specified superclass). - * ignore a certain marker annotation, or only include it. - * Dont get static or final getters, and get getters of all types - * @param theClass to look for fields in - * @param superclassToStopAt to go up to or null to go up to Object - * @param markerAnnotation if this is not null, then if the field has this annotation, then do not - * include in list (if includeAnnotation is false) - * @param includeAnnotation true if the attribute should be included if annotation is present, false if exclude - * @return the set of field names or empty set if none - */ - @SuppressWarnings("unchecked") - public static Set getters(Class theClass, Class superclassToStopAt, - Class markerAnnotation, Boolean includeAnnotation) { - return gettersHelper(theClass, superclassToStopAt, null, true, - markerAnnotation, includeAnnotation); - } - - /** - * get all getters from a class, including superclasses (if specified) - * @param theClass to look for fields in - * @param superclassToStopAt to go up to or null to go up to Object - * @param fieldType is the type of the field to get - * @param includeSuperclassToStopAt if we should include the superclass - * @param markerAnnotation if this is not null, then if the field has this annotation, then do not - * include in list (if includeAnnotation is false) - * @param includeAnnotation true if the attribute should be included if annotation is present, false if exclude - * @return the set of fields (wont return null) - */ - @SuppressWarnings("unchecked") - static Set gettersHelper(Class theClass, Class superclassToStopAt, Class fieldType, - boolean includeSuperclassToStopAt, - Class markerAnnotation, Boolean includeAnnotation) { - //MAKE SURE IF ANY MORE PARAMS ARE ADDED, THE CACHE KEY IS CHANGED! - - Set getterSet = null; - String cacheKey = theClass + CACHE_SEPARATOR + superclassToStopAt + CACHE_SEPARATOR + fieldType + CACHE_SEPARATOR - + includeSuperclassToStopAt + CACHE_SEPARATOR + markerAnnotation + CACHE_SEPARATOR + includeAnnotation; - getterSet = getterSetCache().get(cacheKey); - if (getterSet != null) { - return getterSet; - } - - getterSet = new LinkedHashSet(); - gettersHelper(theClass, superclassToStopAt, fieldType, includeSuperclassToStopAt, - markerAnnotation, getterSet, includeAnnotation); - - //add to cache - getterSetCache().put(cacheKey, getterSet); - - return getterSet; - - } - - /** - * get all getters from a class, including superclasses (if specified) - * @param theClass to look for fields in - * @param superclassToStopAt to go up to or null to go up to Object - * @param propertyType is the type of the field to get - * @param includeSuperclassToStopAt if we should include the superclass - * @param markerAnnotation if this is not null, then if the field has this annotation, then do not - * include in list - * @param getterSet set to add fields to - * @param includeAnnotation if include or exclude - */ - @SuppressWarnings("unchecked") - private static void gettersHelper(Class theClass, Class superclassToStopAt, Class propertyType, - boolean includeSuperclassToStopAt, - Class markerAnnotation, Set getterSet, Boolean includeAnnotation) { - - Method[] methods = retrieveDeclaredMethods(theClass); - if (length(methods) != 0) { - for (Method method: methods) { - //must be a getter - if (!isGetter(method)) { - continue; - } - //if checking for annotation - if (markerAnnotation != null - && (includeAnnotation != method.isAnnotationPresent(markerAnnotation))) { - continue; - } - //if checking for type, and not right type, continue - if (propertyType != null && !propertyType.isAssignableFrom(method.getReturnType())) { - continue; - } - - //go for it - getterSet.add(method); - } - } - //see if done recursing (if superclassToStopAt is null, then stop at Object - if (theClass.equals(superclassToStopAt) || theClass.equals(Object.class)) { - return; - } - Class superclass = theClass.getSuperclass(); - if (!includeSuperclassToStopAt && superclass.equals(superclassToStopAt)) { - return; - } - //recurse - gettersHelper(superclass, superclassToStopAt, propertyType, - includeSuperclassToStopAt, markerAnnotation, getterSet, - includeAnnotation); - } - - /** - * if the method name starts with get, and takes no args, and returns something, - * then getter - * @param method the method to check for "getter" semantics, such as starting with "get" or "is" - * @return true if method name starts with "get" or "is", is not static, is not void return type, and does not take arguments - */ - public static boolean isGetter(Method method) { - - //must start with get - String methodName = method.getName(); - if (!methodName.startsWith("get") && !methodName.startsWith("is")) { - return false; - } - - //must not be void - if (method.getReturnType() == Void.TYPE) { - return false; - } - - //must not take args - if (length(method.getParameterTypes()) != 0) { - return false; - } - - //must not be static - if (Modifier.isStatic(method.getModifiers())) { - return false; - } - - return true; - } - - /** - * assign data to a setter. Will find the field in superclasses, will typecast, - * and will override security (private, protected, etc) - * @param invokeOn to call on or null for static - * @param fieldName method name to call - * @param dataToAssign data - * @param typeCast will typecast if true - * @throws RuntimeException if not there - */ - public static void assignSetter(Object invokeOn, - String fieldName, Object dataToAssign, boolean typeCast) { - Class invokeOnClass = invokeOn.getClass(); - try { - Method setter = setter(invokeOnClass, fieldName, true, true); - setter.setAccessible(true); - if (typeCast) { - dataToAssign = typeCast(dataToAssign, setter.getParameterTypes()[0]); - } - setter.invoke(invokeOn, new Object[]{dataToAssign}); - } catch (Exception e) { - throw new RuntimeException("Problem assigning setter: " + fieldName - + " on class: " + invokeOnClass + ", type of data is: " + className(dataToAssign), e); - } - } - - /** - * Test for setter method. - * @param method the method to test for being a setter - * @return true if the method starts with "set", has a void return type, - * is not static, and takes only one argument. - */ - public static boolean isSetter(Method method) { - - //must start with set - if (!method.getName().startsWith("set")) { - return false; - } - - //must be void - if (method.getReturnType() != Void.TYPE) { - return false; - } - - //must take one arg - if (length(method.getParameterTypes()) != 1) { - return false; - } - - //must not be static - if (Modifier.isStatic(method.getModifiers())) { - return false; - } - - return true; - } - - /** - * get a setter method object for a class, potentially in superclasses - * @param theClass the class - * @param fieldName the field name - * @param callOnSupers true if superclasses should be looked in for the setter - * @param throwExceptionIfNotFound will throw runtime exception if not found - * @return the setter object or null if not found (or exception if param is set) - */ - public static Method setter(Class theClass, String fieldName, boolean callOnSupers, - boolean throwExceptionIfNotFound) { - String setterName = setterNameFromPropertyName(fieldName); - return setterHelper(theClass, fieldName, setterName, callOnSupers, throwExceptionIfNotFound); - } - - /** - * get a setter method object for a class, potentially in superclasses - * @param theClass the class - * @param fieldName the field name - * @param setterName name of setter - * @param callOnSupers true if superclasses should be looked in for the setter - * @param throwExceptionIfNotFound will throw runtime exception if not found - * @return the setter object or null if not found (or exception if param is set) - */ - public static Method setterHelper(Class theClass, String fieldName, String setterName, - boolean callOnSupers, boolean throwExceptionIfNotFound) { - Method[] methods = retrieveDeclaredMethods(theClass); - if (methods != null) { - for (Method method : methods) { - if (equals(setterName, method.getName()) && isSetter(method)) { - return method; - } - } - } - //if method not found - //if traversing up, and not Object, and not instance method - if (callOnSupers && !theClass.equals(Object.class)) { - return setterHelper(theClass.getSuperclass(), fieldName, setterName, - callOnSupers, throwExceptionIfNotFound); - } - //maybe throw an exception - if (throwExceptionIfNotFound) { - throw new RuntimeException("Cant find setter: " - + setterName + ", in: " + theClass - + ", callOnSupers: " + callOnSupers); - } - return null; - } - - /** - * generate setFoo from foo - * @param propertyName the property such as "foo" - * @return the setter method name such as "setFoo" - */ - public static String setterNameFromPropertyName(String propertyName) { - return "set" + capitalize(propertyName); - } - - /** - * get all setters from a class, including superclasses (if specified) - * @param theClass to look for fields in - * @param superclassToStopAt to go up to or null to go up to Object - * @param fieldType is the type of the field to get - * @param includeSuperclassToStopAt if we should include the superclass - * @param markerAnnotation if this is not null, then if the field has this annotation, then do not - * include in list (if includeAnnotation is false) - * @param includeAnnotation true if the attribute should be included if annotation is present, false if exclude - * @return the set of fields (wont return null) - */ - @SuppressWarnings("unchecked") - public static Set setters(Class theClass, Class superclassToStopAt, Class fieldType, - boolean includeSuperclassToStopAt, - Class markerAnnotation, boolean includeAnnotation) { - return settersHelper(theClass, superclassToStopAt, fieldType, - includeSuperclassToStopAt, markerAnnotation, includeAnnotation); - } - - /** - * get all setters from a class, including superclasses (if specified) - * @param theClass to look for fields in - * @param superclassToStopAt to go up to or null to go up to Object - * @param fieldType is the type of the field to get - * @param includeSuperclassToStopAt if we should include the superclass - * @param markerAnnotation if this is not null, then if the field has this annotation, then do not - * include in list (if includeAnnotation is false) - * @param includeAnnotation true if the attribute should be included if annotation is present, false if exclude - * @return the set of fields (wont return null) - */ - @SuppressWarnings("unchecked") - static Set settersHelper(Class theClass, Class superclassToStopAt, Class fieldType, - boolean includeSuperclassToStopAt, - Class markerAnnotation, boolean includeAnnotation) { - //MAKE SURE IF ANY MORE PARAMS ARE ADDED, THE CACHE KEY IS CHANGED! - - Set setterSet = null; - String cacheKey = theClass + CACHE_SEPARATOR + superclassToStopAt + CACHE_SEPARATOR + fieldType + CACHE_SEPARATOR - + includeSuperclassToStopAt + CACHE_SEPARATOR + markerAnnotation + CACHE_SEPARATOR + includeAnnotation; - setterSet = setterSetCache().get(cacheKey); - if (setterSet != null) { - return setterSet; - } - - setterSet = new LinkedHashSet(); - settersHelper(theClass, superclassToStopAt, fieldType, includeSuperclassToStopAt, - markerAnnotation, setterSet, includeAnnotation); - - //add to cache - setterSetCache().put(cacheKey, setterSet); - - return setterSet; - - } - - /** - * get all setters from a class, including superclasses (if specified) - * @param theClass to look for fields in - * @param superclassToStopAt to go up to or null to go up to Object - * @param propertyType is the type of the field to get - * @param includeSuperclassToStopAt if we should include the superclass - * @param markerAnnotation if this is not null, then if the field has this annotation, then do not - * include in list - * @param setterSet set to add fields to - * @param includeAnnotation if include or exclude (or null if not looking for annotations) - */ - @SuppressWarnings("unchecked") - private static void settersHelper(Class theClass, Class superclassToStopAt, Class propertyType, - boolean includeSuperclassToStopAt, - Class markerAnnotation, Set setterSet, Boolean includeAnnotation) { - - Method[] methods = retrieveDeclaredMethods(theClass); - if (length(methods) != 0) { - for (Method method: methods) { - //must be a getter - if (!isSetter(method)) { - continue; - } - //if checking for annotation - if (markerAnnotation != null - && (includeAnnotation != method.isAnnotationPresent(markerAnnotation))) { - continue; - } - //if checking for type, and not right type, continue - if (propertyType != null && !propertyType.isAssignableFrom(method.getParameterTypes()[0])) { - continue; - } - - //go for it - setterSet.add(method); - } - } - //see if done recursing (if superclassToStopAt is null, then stop at Object - if (theClass.equals(superclassToStopAt) || theClass.equals(Object.class)) { - return; - } - Class superclass = theClass.getSuperclass(); - if (!includeSuperclassToStopAt && superclass.equals(superclassToStopAt)) { - return; - } - //recurse - settersHelper(superclass, superclassToStopAt, propertyType, - includeSuperclassToStopAt, markerAnnotation, setterSet, - includeAnnotation); - } - - /** - * If this is a getter or setter, then get the property name - * @param method a method with name like "getFoo," "setFoo," or "isFoo." - * @return the property name inferred from the method name. For example, "getFoo" returns "foo." - */ - public static String propertyName(Method method) { - String methodName = method.getName(); - boolean isGetter = methodName.startsWith("get"); - boolean isSetter = methodName.startsWith("set"); - boolean isIsser = methodName.startsWith("is"); - int expectedLength = isIsser ? 2 : 3; - int length = methodName.length(); - if ((!(isGetter || isSetter || isIsser)) || (length <= expectedLength)) { - throw new RuntimeException("Not a getter or setter: " + methodName); - } - char fourthCharLower = Character.toLowerCase(methodName.charAt(expectedLength)); - //if size 4, then return the string - if (length == expectedLength +1) { - return Character.toString(fourthCharLower); - } - //return the lower appended with the rest - return fourthCharLower + methodName.substring(expectedLength+1, length); - } - - /** - * use reflection to get a property type based on getter or setter or field - * @param theClass the class - * @param propertyName the property name - * @return the property type - */ - public static Class propertyType(Class theClass, String propertyName) { - Method method = getter(theClass, propertyName, true, false); - if (method != null) { - return method.getReturnType(); - } - //use setter - method = setter(theClass, propertyName, true, false); - if (method != null) { - return method.getParameterTypes()[0]; - } - //no setter or getter, use field - Field field = field(theClass, propertyName, true, true); - return field.getType(); - } - - /** - * If necessary, convert an object to another type. if type is Object.class, just return the input. - * Do not convert null to an empty primitive - * @param is template type - * @param value The object to cast - * @param theClass the type of class to cast to - * @return the object of that instance converted into something else - */ - public static T typeCast(Object value, Class theClass) { - //default behavior is not to convert null to empty primitive - return typeCast(value, theClass, false, false); - } - - /** - *
-   * make a new file in the name prefix dir.  If parent dir name is c:\temp
-   * and namePrefix is grouperDdl and nameSuffix is sql, then the file will be:
-   * 
-   * c:\temp\grouperDdl_20080721_13_45_43_123.sql
-   *  
-   * If the file exists, it will make a new filename, and create the empty file, and return it
-   * 
- * - * @param parentDirName can be blank for current dir - * @param namePrefix the part before the date part - * @param nameSuffix the last part of file name (can contain dot or will be the extension - * @param createFile true to create the file - * @return the created file - */ - public static File newFileUniqueName(String parentDirName, String namePrefix, String nameSuffix, boolean createFile) { - DateFormat fileNameFormat = new SimpleDateFormat("yyyyMMdd_HH_mm_ss_SSS"); - if (!isBlank(parentDirName)) { - - if (!parentDirName.endsWith("/") && !parentDirName.endsWith("\\")) { - parentDirName += File.separator; - } - - //make sure it exists and is a dir - File parentDir = new File(parentDirName); - if (!parentDir.exists()) { - if (!parentDir.mkdirs()) { - throw new RuntimeException("Cant make dir: " + parentDir.getAbsolutePath()); - } - } else { - if (!parentDir.isDirectory()) { - throw new RuntimeException("Parent dir is not a directory: " + parentDir.getAbsolutePath()); - } - } - - } else { - //make it empty string so it will concatenate well - parentDirName = ""; - } - //make sure suffix has a dot in it - if (!nameSuffix.contains(".")) { - nameSuffix = "." + nameSuffix; - } - - String fileName = parentDirName + namePrefix + "_" + fileNameFormat.format(new Date()) + nameSuffix; - int dotLocation = fileName.lastIndexOf('.'); - String fileNamePre = fileName.substring(0,dotLocation); - String fileNamePost = fileName.substring(dotLocation); - File theFile = new File(fileName); - - int i; - - for (i=0;i<1000;i++) { - - if (!theFile.exists()) { - break; - } - - fileName = fileNamePre + "_" + i + fileNamePost; - theFile = new File(fileName); - - } - - if (i>=1000) { - throw new RuntimeException("Cant find filename to create: " + fileName); - } - - if (createFile) { - try { - if (!theFile.createNewFile()) { - throw new RuntimeException("Cant create file, it returned false"); - } - } catch (Exception e) { - throw new RuntimeException("Cant create file: " + fileName + ", make sure " + - "permissions and such are ok, or change file location in grouper.properties if applicable", e); - } - } - return theFile; - } - - /** - *
-   * Convert an object to a java.util.Date.  allows, dates, null, blank, 
-   * yyyymmdd or yyyymmdd hh24:mm:ss
-   * or yyyy/MM/dd HH:mm:ss.SSS
-   * 
- * @param inputObject - * is the String or Date to convert - * - * @return the Date - */ - public static Date dateValue(Object inputObject) { - if (inputObject == null) { - return null; - } - - if (inputObject instanceof java.util.Date) { - return (Date)inputObject; - } - - if (inputObject instanceof String) { - String input = (String)inputObject; - //trim and handle null and empty - if (isBlank(input)) { - return null; - } - - try { - if (input.length() == 8) { - - return dateFormat().parse(input); - } - if (!contains(input, '.')) { - if (contains(input, '/')) { - return dateMinutesSecondsFormat.parse(input); - } - //else no slash - return dateMinutesSecondsNoSlashFormat.parse(input); - } - if (contains(input, '/')) { - //see if the period is 6 back - int lastDotIndex = input.lastIndexOf('.'); - if (lastDotIndex == input.length() - 7) { - String nonNanoInput = input.substring(0,input.length()-3); - Date date = timestampFormat.parse(nonNanoInput); - //get the last 3 - String lastThree = input.substring(input.length()-3,input.length()); - int lastThreeInt = Integer.parseInt(lastThree); - Timestamp timestamp = new Timestamp(date.getTime()); - timestamp.setNanos(timestamp.getNanos() + (lastThreeInt * 1000)); - return timestamp; - } - return timestampFormat.parse(input); - } - //else no slash - return timestampNoSlashFormat.parse(input); - } catch (ParseException pe) { - throw new RuntimeException(errorStart + toStringForLog(input)); - } - } - - throw new RuntimeException("Cannot convert Object to date : " + toStringForLog(inputObject)); - } - - /** - * See if the input is null or if string, if it is empty or blank (whitespace) - * @param input object to test for null or String to check for blank - * @return true if null or blank string - */ - public static boolean isBlank(Object input) { - if (null == input) { - return true; - } - return (input instanceof String && isBlank((String)input)); - } - - /** - * If necessary, convert an object to another type. if type is Object.class, just return the input - * @param is the type to return - * @param value The object to cast - * @param theClass The desired cast class type - * @param convertNullToDefaultPrimitive if the value is null, and theClass is primitive, should we - * convert the null to a primitive default value - * @param useNewInstanceHooks if theClass is not recognized, then honor the string "null", "newInstance", - * or get a constructor with one param, and call it - * @return the object of that instance converted into something else - */ - @SuppressWarnings({ "unchecked", "cast" }) - public static T typeCast(Object value, Class theClass, - boolean convertNullToDefaultPrimitive, boolean useNewInstanceHooks) { - - if (Object.class.equals(theClass)) { - return (T)value; - } - - if (value==null) { - if (convertNullToDefaultPrimitive && theClass.isPrimitive()) { - if ( theClass == boolean.class ) { - return (T)Boolean.FALSE; - } - if ( theClass == char.class ) { - return (T)(Object)0; - } - //convert 0 to the type - return typeCast(0, theClass, false, false); - } - return null; - } - - if (theClass.isInstance(value)) { - return (T)value; - } - - //if array, get the base class - if (theClass.isArray() && theClass.getComponentType() != null) { - theClass = (Class)theClass.getComponentType(); - } - Object resultValue = null; - //loop through and see the primitive types etc - if (theClass.equals(Date.class)) { - resultValue = dateValue(value); - } else if (theClass.equals(String.class)) { - resultValue = stringValue(value); - } else if (theClass.equals(Timestamp.class)) { - resultValue = toTimestamp(value); - } else if (theClass.equals(Boolean.class) || theClass.equals(boolean.class)) { - resultValue = booleanObjectValue(value); - } else if (theClass.equals(Integer.class) || theClass.equals(int.class)) { - resultValue = intObjectValue(value, true); - } else if (theClass.equals(Double.class) || theClass.equals(double.class)) { - resultValue = doubleObjectValue(value, true); - } else if (theClass.equals(Float.class) || theClass.equals(float.class)) { - resultValue = floatObjectValue(value, true); - } else if (theClass.equals(Long.class) || theClass.equals(long.class)) { - resultValue = longObjectValue(value, true); - } else if (theClass.equals(Byte.class) || theClass.equals(byte.class)) { - resultValue = byteObjectValue(value); - } else if (theClass.equals(Character.class) || theClass.equals(char.class)) { - resultValue = charObjectValue(value); - } else if (theClass.equals(Short.class) || theClass.equals(short.class)) { - resultValue = shortObjectValue(value); - } else if ( theClass.isEnum() && (value instanceof String) ) { - resultValue = Enum.valueOf((Class)theClass, (String) value); - } else if ( theClass.equals(Class.class) && (value instanceof String) ) { - resultValue = forName((String)value); - } else if (useNewInstanceHooks && value instanceof String) { - String stringValue = (String)value; - if ( equals("null", stringValue)) { - resultValue = null; - } else if (equals("newInstance", stringValue)) { - resultValue = newInstance(theClass); - } else { // instantiate using string - //note, we could typecast this to fit whatever is there... right now this is used for annotation - try { - Constructor constructor = theClass.getConstructor(new Class[] {String.class} ); - resultValue = constructor.newInstance(new Object[] {stringValue} ); - } catch (Exception e) { - throw new RuntimeException("Cant find constructor with string for class: " + theClass); - } - } - } else { - throw new RuntimeException("Cannot convert from type: " + value.getClass() + " to type: " + theClass); - } - - return (T)resultValue; - } - - /** - * see if a class is a scalar (not bean, not array or list, etc) - * @param type the type to check - * @return true if scalar - */ - public static boolean isScalar(Class type) { - - if (type.isArray()) { - return false; - } - - //definitely all primitives - if (type.isPrimitive()) { - return true; - } - //Integer, Float, etc - if (Number.class.isAssignableFrom(type)) { - return true; - } - //Date, Timestamp - if (Date.class.isAssignableFrom(type)) { - return true; - } - if (Character.class.equals(type)) { - return true; - } - //handles strings and string builders - if (CharSequence.class.equals(type) || CharSequence.class.isAssignableFrom(type)) { - return true; - } - if (Class.class == type || Boolean.class == type || type.isEnum()) { - return true; - } - //appears not to be a scalar - return false; - } - - - /** - *
-   * Convert a string or object to a timestamp (could be string, date, timestamp, etc)
-   * yyyymmdd
-   * or
-   * yyyy/MM/dd HH:mm:ss
-   * or
-   * yyyy/MM/dd HH:mm:ss.SSS
-   * or
-   * yyyy/MM/dd HH:mm:ss.SSSSSS
-   * 
-   * 
- * - * @param input a String, java.sql.Timestamp, or java.sql.Date - * @return the timestamp - * @throws RuntimeException if invalid format - */ - public static Timestamp toTimestamp(Object input) { - - if (null == input) { - return null; - } else if (input instanceof java.sql.Timestamp) { - return (Timestamp) input; - } else if (input instanceof String) { - return stringToTimestamp((String) input); - } else if (input instanceof Date) { - return new Timestamp(((Date)input).getTime()); - } else if (input instanceof java.sql.Date) { - return new Timestamp(((java.sql.Date)input).getTime()); - } else { - throw new RuntimeException("Cannot convert Object to timestamp : " + input); - } - - } - - /** - * convert an object to a string - * - * @param input - * is the object to convert, such as a Timestamp, Date, or Number. - * - * @return the String conversion of the object - */ - public static String stringValue(Object input) { - //this isnt needed - if (input == null) { - return (String) input; - } - - if (input instanceof Timestamp) { - //convert to yyyy/MM/dd HH:mm:ss.SSS - return timestampToString((Timestamp) input); - } - - if (input instanceof Date) { - //convert to yyyymmdd - return stringValue((Date) input); - } - - if (input instanceof Number) { - DecimalFormat decimalFormat = new DecimalFormat( - "###################.###############"); - return decimalFormat.format(((Number) input).doubleValue()); - - } - - return input.toString(); - } - - /** - * Convert a timestamp into a string: yyyy/MM/dd HH:mm:ss.SSS - * @param timestamp Date object to be formatted as a string - * @return the string representation - */ - public synchronized static String timestampToString(Date timestamp) { - if (timestamp == null) { - return null; - } - return timestampFormat.format(timestamp); - } - - /** - * get the timestamp format for this thread - * if you call this make sure to synchronize on FastDateUtils.class - * @return the timestamp format - */ - synchronized static SimpleDateFormat dateFormat() { - return dateFormat; - } - - /** - * convert a date to the standard string yyyymmdd - * @param date the date to format - * @return the string value - */ - public static String stringValue(java.util.Date date) { - synchronized (ConfigPropertiesCascadeCommonUtils.class) { - if (date == null) { - return null; - } - - String theString = dateFormat().format(date); - - return theString; - } - } - - /** - * convert a string to timestamp based on the following formats: - *
-   * yyyyMMdd
-   * yyyy/MM/dd HH:mm:ss
-   * yyyy/MM/dd HH:mm:ss.SSS
-   * yyyy/MM/dd HH:mm:ss.SSSSSS
-   * 
- * @param input the string to be converted into a Timestamp - * @return the timestamp object - * @see #stringToTimestampHelper(String) - */ - public static Timestamp stringToTimestamp(String input) { - Date date = stringToTimestampHelper(input); - if (date == null) { - return null; - } - //maybe already a timestamp - if (date instanceof Timestamp) { - return (Timestamp)date; - } - return new Timestamp(date.getTime()); - } - - /** - * return a date based on input, null safe. Allow any of the three - * formats: - *
-   * yyyyMMdd
-   * yyyy/MM/dd HH:mm:ss
-   * yyyy/MM/dd HH:mm:ss.SSS
-   * yyyy/MM/dd HH:mm:ss.SSSSSS
-   * 
- * - * @param input The string to be converted into a Date - * @return a Date parsed from the input string - */ - synchronized static Date stringToTimestampHelper(String input) { - //trim and handle null and empty - if (isBlank(input)) { - return null; - } - - try { - //convert mainframe - if (equals("99999999", input) - || equals("999999", input)) { - input = "20991231"; - } - if (input.length() == 8) { - - return dateFormat().parse(input); - } - if (!contains(input, '.')) { - if (contains(input, '/')) { - return dateMinutesSecondsFormat.parse(input); - } - //else no slash - return dateMinutesSecondsNoSlashFormat.parse(input); - } - if (contains(input, '/')) { - //see if the period is 6 back - int lastDotIndex = input.lastIndexOf('.'); - if (lastDotIndex == input.length() - 7) { - String nonNanoInput = input.substring(0,input.length()-3); - Date date = timestampFormat.parse(nonNanoInput); - //get the last 3 - String lastThree = input.substring(input.length()-3,input.length()); - int lastThreeInt = Integer.parseInt(lastThree); - Timestamp timestamp = new Timestamp(date.getTime()); - timestamp.setNanos(timestamp.getNanos() + (lastThreeInt * 1000)); - return timestamp; - } - return timestampFormat.parse(input); - } - //else no slash - return timestampNoSlashFormat.parse(input); - } catch (ParseException pe) { - throw new RuntimeException(errorStart + input); - } - } - - /** - * start of error parsing messages - */ - private static final String errorStart = "Invalid timestamp, please use any of the formats: " - + DATE_FORMAT + ", " + TIMESTAMP_FORMAT - + ", " + DATE_MINUTES_SECONDS_FORMAT + ": "; - - /** - * Convert an object to a BigDecimal, allow nulls - * @param input the object to cast, or null - * @return the BigDecimal value of the input object - * @see java.math.BigDecimal#valueOf(double) - */ - public static BigDecimal bigDecimalObjectValue(Object input) { - if (input instanceof BigDecimal) { - return (BigDecimal)input; - } - if (isBlank(input)) { - return null; - } - return BigDecimal.valueOf(doubleValue(input)); - } - - /** - * Convert an object to a Byte, allow nulls - * @param input the object to cast, or null - * @return the Byte object value - */ - public static Byte byteObjectValue(Object input) { - if (input instanceof Byte) { - return (Byte)input; - } - if (isBlank(input)) { - return null; - } - return Byte.valueOf(byteValue(input)); - } - - /** - * convert an object to a byte - * @param input the object to convert to a byte - * @return the byte value of the given number, or the parsed byte of the string - */ - public static byte byteValue(Object input) { - if (input instanceof String) { - String string = (String)input; - return Byte.parseByte(string); - } - if (input instanceof Number) { - return ((Number)input).byteValue(); - } - throw new RuntimeException("Cannot convert to byte: " + className(input)); - } - - /** - * get the Double value of an object - * - * @param input - * is a number or String - * @param allowNullBlank used to default to false, if true, return null if nul inputted - * - * @return the Double equivalent - */ - public static Double doubleObjectValue(Object input, boolean allowNullBlank) { - - if (input instanceof Double) { - return (Double) input; - } - - if (allowNullBlank && isBlank(input)) { - return null; - } - - return Double.valueOf(doubleValue(input)); - } - - /** - * get the double value of an object - * - * @param input - * is a number or String - * - * @return the double equivalent - */ - public static double doubleValue(Object input) { - if (input instanceof String) { - String string = (String)input; - return Double.parseDouble(string); - } - if (input instanceof Number) { - return ((Number)input).doubleValue(); - } - throw new RuntimeException("Cannot convert to double: " + className(input)); - } - - /** - * get the double value of an object, do not throw an - * exception if there is an - * error - * - * @param input - * is a number or String - * - * @return the double equivalent - */ - public static double doubleValueNoError(Object input) { - if (input == null || (input instanceof String - && isBlank((String)input))) { - return NOT_FOUND; - } - - try { - return doubleValue(input); - } catch (Exception e) { - //no need to log here - } - - return NOT_FOUND; - } - - /** - * get the Float value of an object - * - * @param input - * is a number or String - * @param allowNullBlank true if allow null or blank - * - * @return the Float equivalent - */ - public static Float floatObjectValue(Object input, boolean allowNullBlank) { - - if (input instanceof Float) { - return (Float) input; - } - - if (allowNullBlank && isBlank(input)) { - return null; - } - return Float.valueOf(floatValue(input)); - } - - /** - * get the float value of an object - * - * @param input - * is a number or String - * - * @return the float equivalent - */ - public static float floatValue(Object input) { - if (input instanceof String) { - String string = (String)input; - return Float.parseFloat(string); - } - if (input instanceof Number) { - return ((Number)input).floatValue(); - } - throw new RuntimeException("Cannot convert to float: " + className(input)); - } - - /** - * get the float value of an object, do not throw an exception if there is an - * error - * - * @param input - * is a number or String - * - * @return the float equivalent - */ - public static float floatValueNoError(Object input) { - if (input == null || (input instanceof String - && isBlank((String)input))) { - return NOT_FOUND; - } - try { - return floatValue(input); - } catch (Exception e) { - e.printStackTrace(); - } - - return NOT_FOUND; - } - - /** - * get the Integer value of an object - * - * @param input - * is a number or String - * @param allowNullBlank true if convert null or blank to null - * - * @return the Integer equivalent - */ - public static Integer intObjectValue(Object input, boolean allowNullBlank) { - - if (input instanceof Integer) { - return (Integer) input; - } - - if (allowNullBlank && isBlank(input)) { - return null; - } - - return Integer.valueOf(intValue(input)); - } - - /** * convert an object to a int * @param input the object (String or Number) to parse or convert to an int * @return the number @@ -4635,396 +389,11 @@ } /** - * convert an object to a int - * @param input the object to convert to an int - * @param valueIfNull is if the input is null or empty, return this value - * @return the integer primitive represented by the object - */ - public static int intValue(Object input, int valueIfNull) { - if (input == null || "".equals(input)) { - return valueIfNull; - } - return intObjectValue(input, false); - } - - /** - * get the int value of an object, do not throw an exception if there is an - * error - * - * @param input - * is a number or String - * - * @return the int equivalent - */ - public static int intValueNoError(Object input) { - if (input == null || (input instanceof String - && isBlank((String)input))) { - return NOT_FOUND; - } - try { - return intValue(input); - } catch (Exception e) { - //no need to log here - } - - return NOT_FOUND; - } - - /** special number when a number is not found */ - public static final int NOT_FOUND = -999999999; - - /** * The name says it all. */ public static final int DEFAULT_BUFFER_SIZE = 1024 * 4; /** - * get the Long value of an object - * - * @param input - * is a number or String - * @param allowNullBlank true if null or blank converts to null - * - * @return the Long equivalent - */ - public static Long longObjectValue(Object input, boolean allowNullBlank) { - - if (input instanceof Long) { - return (Long) input; - } - - if (allowNullBlank && isBlank(input)) { - return null; - } - - return Long.valueOf(longValue(input)); - } - - /** - * convert an object to a long - * @param input String or Number - * @return the number - */ - public static long longValue(Object input) { - if (input instanceof String) { - String string = (String)input; - return Long.parseLong(string); - } - if (input instanceof Number) { - return ((Number)input).longValue(); - } - throw new RuntimeException("Cannot convert to long: " + className(input)); - } - - /** - * convert an object to a long - * @param input value to convert - * @param valueIfNull is if the input is null or empty, return this value - * @return the number - */ - public static long longValue(Object input, long valueIfNull) { - if (input == null || "".equals(input)) { - return valueIfNull; - } - return longObjectValue(input, false); - } - - /** - * get the long value of an object, do not throw an exception if there is an - * error - * - * @param input - * is a number or String - * - * @return the long equivalent - */ - public static long longValueNoError(Object input) { - if (input == null || (input instanceof String - && isBlank((String)input))) { - return NOT_FOUND; - } - try { - return longValue(input); - } catch (Exception e) { - //no need to log here - } - - return NOT_FOUND; - } - - /** - * get the Short value of an object. converts null or blank to null - * - * @param input - * is a number or String - * - * @return the Long equivalent - */ - public static Short shortObjectValue(Object input) { - - if (input instanceof Short) { - return (Short) input; - } - - if (isBlank(input)) { - return null; - } - - return Short.valueOf(shortValue(input)); - } - - /** - * convert an object to a short - * @param input String or Number value to convert - * @return the number - */ - public static short shortValue(Object input) { - if (input instanceof String) { - String string = (String)input; - return Short.parseShort(string); - } - if (input instanceof Number) { - return ((Number)input).shortValue(); - } - throw new RuntimeException("Cannot convert to short: " + className(input)); - } - - /** - * get the Character wrapper value for the input - * @param input allow null, return null - * @return the Character object wrapper - */ - public static Character charObjectValue(Object input) { - if (input instanceof Character) { - return (Character) input; - } - if (isBlank(input)) { - return null; - } - return new Character(charValue(input)); - } - - /** - * convert an object to a char - * @param input Character or String - * @return the number - */ - public static char charValue(Object input) { - if (input instanceof Character) { - return ((Character) input).charValue(); - } - //if string length 1, thats ok - if (input instanceof String) { - String inputString = (String) input; - if (inputString.length() == 1) { - return inputString.charAt(0); - } - } - throw new RuntimeException("Cannot convert to char: " - + (input == null ? null : (input.getClass() + ", " + input))); - } - - /** - * Create the parent directories for a file if they do not already exist - * @param file the File whose parent directories need creating - * @see File#mkdirs() - */ - public static void createParentDirectories(File file) { - if (!file.getParentFile().exists()) { - if (!file.getParentFile().mkdirs()) { - throw new RuntimeException("Could not create directory : " + file.getParentFile()); - } - } - } - - /** - * save a string into a file, file does not have to exist - * - * @param file - * is the file to save to - * @param contents - * is the contents of the file - */ - public static void saveStringIntoFile(File file, String contents) { - try { - writeStringToFile(file, contents, "UTF-8"); - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - } - - /** - * save a string into a file, file does not have to exist - * - * @param file - * is the file to save to - * @param contents - * is the contents of the file - * @param onlyIfDifferentContents true if only saving due to different contents - * @param ignoreWhitespace true to ignore whitespace - * @return true if contents were saved (thus different if param set) - */ - public static boolean saveStringIntoFile(File file, String contents, - boolean onlyIfDifferentContents, boolean ignoreWhitespace) { - if (onlyIfDifferentContents && file.exists()) { - String fileContents = readFileIntoString(file); - String compressedContents = contents; - if (ignoreWhitespace) { - compressedContents = replaceWhitespaceWithSpace(compressedContents); - fileContents = replaceWhitespaceWithSpace(fileContents); - } - - //they are the same, dont worry about it - if (equals(fileContents, compressedContents)) { - return false; - } - - } - saveStringIntoFile(file, contents); - return true; - } - - /** - *

- * Writes data to a file. The file will be created if it does not exist. - *

- *

- * There is no readFileToString method without encoding parameter because - * the default encoding can differ between platforms and therefore results - * in inconsistent results. - *

- * - * @param file the file to write. - * @param data The content to write to the file. - * @param encoding encoding to use - * @throws IOException in case of an I/O error - * @throws UnsupportedEncodingException if the encoding is not supported - * by the VM - */ - public static void writeStringToFile(File file, String data, String encoding) - throws IOException { - OutputStream out = new java.io.FileOutputStream(file); - try { - out.write(data.getBytes(encoding)); - } finally { - closeQuietly(out); - } - } - - /** - * @param file - * is the file to read into a string - * - * @return String - */ - public static String readFileIntoString(File file) { - - if (file == null) { - return null; - } - try { - return readFileToString(file, "UTF-8"); - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - } - - /** - * @param resourceName is the string resource from classpath to read (e.g. grouper.properties) - * @param allowNull is true if its ok if the resource is null or if it is not found or blank or whatever. - * - * @return String or null if allowed or RuntimeException if not allowed - */ - public static String readResourceIntoString(String resourceName, boolean allowNull) { - if (isBlank(resourceName)) { - if (allowNull) { - return null; - } - throw new RuntimeException("Resource name is blank"); - } - URL url = computeUrl(resourceName, allowNull); - - //this is ok - if (url == null && allowNull) { - return null; - } - - InputStream inputStream = null; - StringWriter stringWriter = new StringWriter(); - try { - inputStream = url.openStream(); - copy(inputStream, stringWriter, "UTF-8"); - } catch (IOException ioe) { - throw new RuntimeException("Error reading resource: '" + resourceName + "'", ioe); - } finally { - closeQuietly(inputStream); - closeQuietly(stringWriter); - } - return stringWriter.toString(); - } - - /** - * read resource into string - * @param resourceName the resource name - * @param classInJar if not null, then look for the jar where this file is, and look in the same dir - * @return the properties or null if not exist - */ - public static String readResourceIntoString(String resourceName, Class classInJar) { - - try { - return readResourceIntoString(resourceName, false); - } catch (Exception e) { - //try from jar location - } - - //lets look next to jar - File jarFile = classInJar == null ? null : jarFile(classInJar); - File parentDir = jarFile == null ? null : jarFile.getParentFile(); - String fileName = parentDir == null ? null - : (stripLastSlashIfExists(fileCanonicalPath(parentDir)) + File.separator + resourceName); - File configFile = fileName == null ? null - : new File(fileName); - - return readFileIntoString(configFile); - } - - /** - *

- * Reads the contents of a file into a String. - *

- *

- * There is no readFileToString method without encoding parameter because - * the default encoding can differ between platforms and therefore results - * in inconsistent results. - *

- * - * @param file the file to read. - * @param encoding the encoding to use - * @return The file contents or null if read failed. - * @throws IOException in case of an I/O error - */ - public static String readFileToString(File file, String encoding) throws IOException { - InputStream in = new java.io.FileInputStream(file); - try { - return toString(in, encoding); - } finally { - closeQuietly(in); - } - } - - /** - * replace all consecutive whitespace with single space character - * @param input the input string - * @return the string with redundant whitespace collapsed - */ - public static String replaceWhitespaceWithSpace(String input) { - if (input == null) { - return input; - } - return input.replaceAll("\\s+", " "); - } - - /** * Unconditionally close an InputStream. * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored. * @param input A (possibly null) InputStream @@ -5041,53 +410,6 @@ } /** - * Unconditionally close an OutputStream. - * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored. - * @param output A (possibly null) OutputStream - */ - public static void closeQuietly(OutputStream output) { - if (output == null) { - return; - } - - try { - output.close(); - } catch (IOException ioe) { - } - } - - /** - * Unconditionally close an Reader. - * Equivalent to {@link Reader#close()}, except any exceptions will be ignored. - * - * @param input A (possibly null) Reader - */ - public static void closeQuietly(Reader input) { - if (input == null) { - return; - } - - try { - input.close(); - } catch (IOException ioe) { - } - } - - /** - * close a writer quietly, swallowing IOException - * @param writer the writer to close - */ - public static void closeQuietly(Writer writer) { - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - //swallow, its ok - } - } - } - - /** * Get the contents of an InputStream as a String. * @param input the InputStream to read from * @param encoding The name of a supported character encoding. See the @@ -5137,259 +459,6 @@ } /** - * this method takes a long (less than 62) and converts it to a 1 character - * string (a-z, A-Z, 0-9) - * - * @param theLong - * is the long (less than 62) to convert to a 1 character string - * - * @return a one character string - */ - public static String convertLongToChar(long theLong) { - if ((theLong < 0) || (theLong >= 62)) { - throw new RuntimeException("convertLongToChar() " - + " invalid input (not >=0 && <62: " + theLong); - } else if (theLong < 26) { - return "" + (char) ('a' + theLong); - } else if (theLong < 52) { - return "" + (char) ('A' + (theLong - 26)); - } else { - return "" + (char) ('0' + (theLong - 52)); - } - } - - /** - * this method takes a long (less than 36) and converts it to a 1 character - * string (A-Z, 0-9) - * - * @param theLong - * is the long (less than 36) to convert to a 1 character string - * - * @return a one character string - */ - public static String convertLongToCharSmall(long theLong) { - if ((theLong < 0) || (theLong >= 36)) { - throw new RuntimeException("convertLongToCharSmall() " - + " invalid input (not >=0 && <36: " + theLong); - } else if (theLong < 26) { - return "" + (char) ('A' + theLong); - } else { - return "" + (char) ('0' + (theLong - 26)); - } - } - - /** - * convert a long to a string by converting it to base 62 (26 lower, 26 upper, - * 10 digits) - * - * @param theLong - * is the long to convert - * - * @return the String conversion of this - */ - public static String convertLongToString(long theLong) { - long quotient = theLong / 62; - long remainder = theLong % 62; - - if (quotient == 0) { - return convertLongToChar(remainder); - } - StringBuffer result = new StringBuffer(); - result.append(convertLongToString(quotient)); - result.append(convertLongToChar(remainder)); - - return result.toString(); - } - - /** - * convert a long to a string by converting it to base 36 (26 upper, 10 - * digits) - * - * @param theLong - * is the long to convert - * - * @return the String conversion of this - */ - public static String convertLongToStringSmall(long theLong) { - long quotient = theLong / 36; - long remainder = theLong % 36; - - if (quotient == 0) { - return convertLongToCharSmall(remainder); - } - StringBuffer result = new StringBuffer(); - result.append(convertLongToStringSmall(quotient)); - result.append(convertLongToCharSmall(remainder)); - - return result.toString(); - } - - /** - * increment a character (A-Z then 0-9) - * - * @param theChar The charater to be "incremented" - * - * @return the charcter that follows the input character, wrapping from 'Z' to '0' and '9' to 'A' in the set [A-Z0-9] - */ - public static char incrementChar(char theChar) { - if (theChar == 'Z') { - return '0'; - } - - if (theChar == '9') { - return 'A'; - } - - return ++theChar; - } - - /** - * Increment a string with A-Z and 0-9 (no lower case so case insensitive apps - * like windows IE will still work) - * - * @param string the character array to increment. - * - * @return the incremented character array - */ - public static char[] incrementStringInt(char[] string) { - if (string == null) { - return string; - } - - //loop through the string backwards - int i = 0; - - for (i = string.length - 1; i >= 0; i--) { - char inc = string[i]; - inc = incrementChar(inc); - string[i] = inc; - - if (inc != 'A') { - break; - } - } - - //if we are at 0, then it means we hit AAAAAAA (or more) - if (i < 0) { - return ("A" + new String(string)).toCharArray(); - } - - return string; - } - - /** - * read properties from a resource, don't modify the properties returned since they are cached - * @param resourceName the resource name - * @return the properties - */ - public synchronized static Properties propertiesFromResourceName(String resourceName) { - return propertiesFromResourceName(resourceName, true, true, null, null); - } - - /** - * clear properties cache (e.g. for testing) - */ - public static void propertiesCacheClear() { - resourcePropertiesCache.clear(); - } - - /** - * read properties from file - * @param file the properties file - * @return properties - */ - public static Properties propertiesFromFile(File file) { - Properties properties = new Properties(); - FileInputStream fileInputStream = null; - try { - - fileInputStream = new FileInputStream(file); - properties.load(fileInputStream); - - } catch (IOException ioe) { - throw new RuntimeException("Problem reading file into properties: " + file.getAbsolutePath()); - } finally { - closeQuietly(fileInputStream); - } - return properties; - } - - /** - * read properties from a resource, dont modify the properties returned since they are cached - * @param resourceName the resource name (property key) - * @param useCache whether or not to use cache - * @param exceptionIfNotExist throw an exception if the resource does not exist - * @param classInJar if not null, then look for the jar where this file is, and look in the same dir - * @param callingLog container for "Reading resource ... from" log messages - * @return the properties or null if not exist - */ - public synchronized static Properties propertiesFromResourceName(String resourceName, boolean useCache, - boolean exceptionIfNotExist, Class classInJar, StringBuilder callingLog) { - - Properties properties = resourcePropertiesCache.get(resourceName); - - if (!useCache || !resourcePropertiesCache.containsKey(resourceName)) { - - properties = new Properties(); - - boolean success = false; - - URL url = computeUrl(resourceName, true); - InputStream inputStream = null; - try { - inputStream = url.openStream(); - properties.load(inputStream); - success = true; - String theLog = "Reading resource: " + resourceName + ", from: " + url.toURI(); - if (callingLog != null) { - callingLog.append(theLog); - } - } catch (Exception e) { - - //clear out just in case - properties.clear(); - - //lets look next to jar - File jarFile = classInJar == null ? null : jarFile(classInJar); - File parentDir = jarFile == null ? null : jarFile.getParentFile(); - String fileName = parentDir == null ? null - : (stripLastSlashIfExists(fileCanonicalPath(parentDir)) + File.separator + resourceName); - File configFile = fileName == null ? null - : new File(fileName); - - try { - //looks like we have a match - if (configFile != null && configFile.exists() && configFile.isFile()) { - inputStream = new FileInputStream(configFile); - properties.load(inputStream); - success = true; - String theLog = "Reading resource: " + resourceName + ", from: " + fileCanonicalPath(configFile); - if (callingLog != null) { - callingLog.append(theLog); - } - } - - } catch (Exception e2) { - } - if (!success) { - properties = null; - if (exceptionIfNotExist) { - throw new RuntimeException("Problem with resource: '" + resourceName + "'", e); - } - } - } finally { - closeQuietly(inputStream); - - if (useCache && properties != null && properties.size() > 0) { - resourcePropertiesCache.put(resourceName, properties); - } - } - } - - return properties; - } - - /** * do a case-insensitive matching * @param theEnumClass class of the enum * @param generic type @@ -5422,435 +491,6 @@ /** - * this assumes the property exists, and is a simple property - * @param object the object - * @param property the property - * @return the value - */ - public static Object propertyValue(Object object, String property) { - Method getter = getter(object.getClass(), property, true, true); - Object result = invokeMethod(getter, object); - return result; - } - - /** - * get a value (trimmed to e) from a property file - * @param properties the properties - * @param key the key used to lookup the property value - * @return the property value - */ - public static String propertiesValue(Properties properties, String key) { - return propertiesValue(properties, null, key); - } - - /** - * get a value (trimmed to e) from a property file - * @param properties the properties - * @param overrideMap for testing, to override some properties values - * @param key the key used to lookup the property value - * @return the property value - */ - public static String propertiesValue(Properties properties, Map overrideMap, String key) { - return propertiesValue(properties, overrideMap, null, key); - } - - /** - * get a value (trimmed to e) from a property file - * @param properties the properties - * @param overrideMap for testing or threadlocal, to override some properties values - * @param overrideMap2 for testing, to provide some properties values - * @param key the key used to lookup the property value - * @return the property value - */ - public static String propertiesValue(Properties properties, Map overrideMap, Map overrideMap2, String key) { - String value = overrideMap == null ? null : overrideMap.get(key); - if (isBlank(value)) { - value = overrideMap2 == null ? null : overrideMap2.get(key); - } - if (isBlank(value)) { - value = properties.getProperty(key); - } - value = trim(value); - value = substituteCommonVars(value); - return value; - } - - /** - * substitute common vars like $space$ and $newline$ - * @param string The string that potentially contains '$space$' and '$newline$' tokens - * @return the string with tokens replaced by their represented characters - */ - public static String substituteCommonVars(String string) { - if (string == null) { - return string; - } - //short circuit - if (string.indexOf('$') < 0) { - return string; - } - //might have $space$ - string = replace(string, "$space$", " "); - - //note, at some point we could be OS specific - string = replace(string, "$newline$", "\n"); - return string; - } - - /** - * get a boolean property, or the default if can't find - * @param properties the properties - * @param propertyName the property name key - * @param defaultValue the value to use when key lookup is blank - * @return the boolean - */ - public static boolean propertiesValueBoolean(Properties properties, - String propertyName, boolean defaultValue) { - return propertiesValueBoolean(properties, null, propertyName, defaultValue); - } - - /** - * get a boolean property, or the default if cant find. Validate also with a descriptive exception if problem - * @param resourceName the resource name - * @param properties the properties - * @param overrideMap for testing to override properties - * @param propertyName the property name key - * @param defaultValue the value to use when key lookup is blank - * @param required whether or not a value is required - * @return the boolean - */ - public static boolean propertiesValueBoolean(String resourceName, Properties properties, - Map overrideMap, String propertyName, boolean defaultValue, boolean required) { - propertyValidateValueBoolean(resourceName, properties, overrideMap, propertyName, required, true); - - Map threadLocalMap = propertiesThreadLocalOverrideMap(resourceName); - - return propertiesValueBoolean(properties, threadLocalMap, overrideMap, propertyName, defaultValue); - } - - /** - * get an int property, or the default if can't find. Validate also with a descriptive exception if problem - * @param resourceName the resource name - * @param properties the properties - * @param overrideMap for testing to override properties - * @param propertyName the property name key - * @param defaultValue the value to use when key lookup is blank - * @param required whether or not a value is required - * @return the int - */ - public static int propertiesValueInt(String resourceName, Properties properties, - Map overrideMap, String propertyName, int defaultValue, boolean required) { - - propertyValidateValueInt(resourceName, properties, overrideMap, propertyName, required, true); - - Map threadLocalMap = propertiesThreadLocalOverrideMap(resourceName); - - return propertiesValueInt(properties, threadLocalMap, overrideMap, propertyName, defaultValue); - } - - /** - * get a property. Validate also with a descriptive exception if problem - * @param resourceName the resource name - * @param properties the properties - * @param overrideMap for threadlocal or testing to override properties - * @param propertyName the property name - * @param required whether or not a value is required - * @return the string - */ - public static String propertiesValue(String resourceName, Properties properties, - Map overrideMap, String propertyName, boolean required) { - - if (required) { - propertyValidateValueRequired(resourceName, properties, overrideMap, propertyName, true); - } - Map threadLocalMap = propertiesThreadLocalOverrideMap(resourceName); - - return propertiesValue(properties, threadLocalMap, overrideMap, propertyName); - } - - /** - * get a int property, or the default if cant find - * @param properties the properties - * @param overrideMap for testing to override properties - * @param propertyName the name of the property - * @param defaultValue the value to use when the property value is blank - * @return the int - */ - public static int propertiesValueInt(Properties properties, - Map overrideMap, String propertyName, int defaultValue) { - return propertiesValueInt(properties, overrideMap, null, propertyName, defaultValue); - } - - - /** - * get a int property, or the default if can't find - * @param properties the properties - * @param overrideMap for testing to override properties - * @param overrideMap2 for testing to override properties - * @param propertyName the name of the property - * @param defaultValue the value to use when the property value is blank - * @return the int - */ - public static int propertiesValueInt(Properties properties, - Map overrideMap, Map overrideMap2, String propertyName, int defaultValue) { - - String value = propertiesValue(properties, overrideMap, overrideMap2, propertyName); - if (isBlank(value)) { - return defaultValue; - } - - try { - return intValue(value); - } catch (Exception e) {} - - throw new RuntimeException("Invalid int value: '" + value + "' for property: " + propertyName + " in grouper.properties"); - - } - - /** - * get a boolean property, or the default if can't find - * @param properties the properties being searched - * @param overrideMap for testing to override properties - * @param propertyName the name of the property - * @param defaultValue the value to use when the property value is blank - * @return the boolean - */ - public static boolean propertiesValueBoolean(Properties properties, - Map overrideMap, String propertyName, boolean defaultValue) { - return propertiesValueBoolean(properties, overrideMap, null, propertyName, defaultValue); - } - - /** - * get a boolean property, or the default if can't find - * @param properties the properties being searched - * @param overrideMap for testing or threadlocal to override properties - * @param overrideMap2 for testing or threadlocal to override properties - * @param propertyName the name of the property - * @param defaultValue the value to use when the property value is blank - * @return the boolean - */ - public static boolean propertiesValueBoolean(Properties properties, - Map overrideMap, Map overrideMap2, String propertyName, boolean defaultValue) { - - - String value = propertiesValue(properties, overrideMap, overrideMap2, propertyName); - if (isBlank(value)) { - return defaultValue; - } - - if ("true".equalsIgnoreCase(value)) { - return true; - } - if ("false".equalsIgnoreCase(value)) { - return false; - } - if ("t".equalsIgnoreCase(value)) { - return true; - } - if ("f".equalsIgnoreCase(value)) { - return false; - } - throw new RuntimeException("Invalid boolean value: '" + value + "' for property: " + propertyName + " in properties file"); - - } - - /** - * close a connection null safe and don't throw exception - * @param connection the connection to close - */ - public static void closeQuietly(Connection connection) { - if (connection != null) { - try { - connection.close(); - } catch (Exception e) { - //ignore - } - } - } - - /** - * close a statement null safe and don't throw exception - * @param statement the statement to close - */ - public static void closeQuietly(Statement statement) { - if (statement != null) { - try { - statement.close(); - } catch (Exception e) { - //ignore - } - } - } - - /** - * close a resultSet null safe and don't throw exception - * @param resultSet the ResultSet to close - */ - public static void closeQuietly(ResultSet resultSet) { - if (resultSet != null) { - try { - resultSet.close(); - } catch (Exception e) { - //ignore - } - } - } - - /** cache the hostname, it won't change */ - private static String hostname = null; - - /** - * get the hostname of this machine - * @return the hostname - */ - public static String hostname() { - - if (isBlank(hostname)) { - - //get the hostname - hostname = "unknown"; - try { - InetAddress addr = InetAddress.getLocalHost(); - - // Get hostname - hostname = addr.getHostName(); - } catch (Exception e) { - System.err.println("Cant find servers hostname: "); - e.printStackTrace(); - } - } - - return hostname; - } - - /** - * is ascii char - * @param input the charater to test - * @return true if ascii (has value below 128) - */ - public static boolean isAscii(char input) { - return input < 128; - } - - /** - * find the length of ascii chars (non ascii are counted as two) - * @param input the input string - * @return the length of ascii chars - */ - public static int lengthAscii(String input) { - if (input == null) { - return 0; - } - //see what real length is - int utfLength = input.length(); - //count how many non asciis - int extras = 0; - for (int i=0;i requiredLength) { - //do not include the current char - return input.substring(0,i); - } - } - //must have fit - return input; - } - - /** - * if the input is a file, read string from file. if not, or if disabled from grouper.properties, return the input - * @param in A path to a file - * @param disableExternalFileLookup when true, no attempt is made to read the input file reference into a String - * @return the contents of the file referred to by the input, or the original input string - */ - public static String readFromFileIfFile(String in, boolean disableExternalFileLookup) { - - String theIn = in; - //convert both slashes to file slashes - if (File.separatorChar == '/') { - theIn = replace(theIn, "\\", "/"); - } else { - theIn = replace(theIn, "/", "\\"); - } - - //see if it is a file reference - if (theIn.indexOf(File.separatorChar) != -1 && !disableExternalFileLookup) { - //read the contents of the file into a string - theIn = readFileIntoString(new File(theIn)); - return theIn; - } - return in; - - } - - /** - * Create directories, throw exception if not possible. - * This is will be ok if the directory already exists (will not delete it) - * @param dir the directory to create - */ - public static void mkdirs(File dir) { - if (!dir.exists()) { - if (!dir.mkdirs()) { - throw new RuntimeException("Could not create directory : " + dir.getParentFile()); - } - return; - } - if (!dir.isDirectory()) { - throw new RuntimeException("Should be a directory but is not: " + dir); - } - } - - - /** * null safe string compare * @param first first string, or null * @param second second string, or null @@ -5895,15 +535,6 @@ } /** - * - * @param str string to check - * @return true if not blank - */ - public static boolean isNotBlank(String str) { - return !isBlank(str); - } - - /** * trim whitespace from string * @param str string to trim * @return trimmed string @@ -5922,172 +553,10 @@ return str1 == null ? str2 == null : str1.equalsIgnoreCase(str2); } - /** - * trim to empty, convert null to empty - * @param str a string containing whitespace, or null - * @return A trimmed string, potentially of length 0 in the case of all-whitespace or null input - */ - public static String trimToEmpty(String str) { - return str == null ? "" : str.trim(); - } - - /** - *

Abbreviates a String using ellipses. This will turn - * "Now is the time for all good men" into "Now is the time for..."

- * - *

Specifically:

- *
    - *
  • If str is less than maxWidth characters - * long, return it.
  • - *
  • Else abbreviate it to (substring(str, 0, max-3) + "...").
  • - *
  • If maxWidth is less than 4, throw an - * IllegalArgumentException.
  • - *
  • In no case will it return a String of length greater than - * maxWidth.
  • - *
- * - *
-   * StringUtils.abbreviate(null, *)      = null
-   * StringUtils.abbreviate("", 4)        = ""
-   * StringUtils.abbreviate("abcdefg", 6) = "abc..."
-   * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
-   * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
-   * StringUtils.abbreviate("abcdefg", 4) = "a..."
-   * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
-   * 
- * - * @param str the String to check, may be null - * @param maxWidth maximum length of result String, must be at least 4 - * @return abbreviated String, null if null String input - * @throws IllegalArgumentException if the width is too small - * @since 2.0 - */ - public static String abbreviate(String str, int maxWidth) { - return abbreviate(str, 0, maxWidth); - } - - /** - *

Abbreviates a String using ellipses. This will turn - * "Now is the time for all good men" into "...is the time for..."

- * - *

Works like abbreviate(String, int), but allows you to specify - * a "left edge" offset. Note that this left edge is not necessarily going to - * be the leftmost character in the result, or the first character following the - * ellipses, but it will appear somewhere in the result. - * - *

In no case will it return a String of length greater than - * maxWidth.

- * - *
-   * StringUtils.abbreviate(null, *, *)                = null
-   * StringUtils.abbreviate("", 0, 4)                  = ""
-   * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
-   * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
-   * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
-   * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
-   * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
-   * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
-   * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
-   * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
-   * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
-   * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
-   * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
-   * 
- * - * @param str the String to check, may be null - * @param offset left edge of source String - * @param maxWidth maximum length of result String, must be at least 4 - * @return abbreviated String, null if null String input - * @throws IllegalArgumentException if the width is too small - * @since 2.0 - */ - public static String abbreviate(String str, int offset, int maxWidth) { - if (str == null) { - return null; - } - if (maxWidth < 4) { - throw new IllegalArgumentException("Minimum abbreviation width is 4"); - } - if (str.length() <= maxWidth) { - return str; - } - if (offset > str.length()) { - offset = str.length(); - } - if ((str.length() - offset) < (maxWidth - 3)) { - offset = str.length() - (maxWidth - 3); - } - if (offset <= 4) { - return str.substring(0, maxWidth - 3) + "..."; - } - if (maxWidth < 7) { - throw new IllegalArgumentException("Minimum abbreviation width with offset is 7"); - } - if ((offset + (maxWidth - 3)) < str.length()) { - return "..." + abbreviate(str.substring(offset), maxWidth - 3); - } - return "..." + str.substring(str.length() - (maxWidth - 3)); - } - // Splitting //----------------------------------------------------------------------- - /** - *

Splits the provided text into an array, using whitespace as the - * separator. - * Whitespace is defined by {@link Character#isWhitespace(char)}.

- * - *

The separator is not included in the returned String array. - * Adjacent separators are treated as one separator. - * For more control over the split use the StrTokenizer class.

- * - *

A null input String returns null.

- * - *
-   * StringUtils.split(null)       = null
-   * StringUtils.split("")         = []
-   * StringUtils.split("abc def")  = ["abc", "def"]
-   * StringUtils.split("abc  def") = ["abc", "def"]
-   * StringUtils.split(" abc ")    = ["abc"]
-   * 
- * - * @param str the String to parse, may be null - * @return an array of parsed Strings, null if null String input - */ - public static String[] split(String str) { - return split(str, null, -1); - } /** - *

Splits the provided text into an array, separator specified. - * This is an alternative to using StringTokenizer.

- * - *

The separator is not included in the returned String array. - * Adjacent separators are treated as one separator. - * For more control over the split use the StrTokenizer class.

- * - *

A null input String returns null.

- * - *
-   * StringUtils.split(null, *)         = null
-   * StringUtils.split("", *)           = []
-   * StringUtils.split("a.b.c", '.')    = ["a", "b", "c"]
-   * StringUtils.split("a..b.c", '.')   = ["a", "b", "c"]
-   * StringUtils.split("a:b:c", '.')    = ["a:b:c"]
-   * StringUtils.split("a\tb\nc", null) = ["a", "b", "c"]
-   * StringUtils.split("a b c", ' ')    = ["a", "b", "c"]
-   * 
- * - * @param str the String to parse, may be null - * @param separatorChar the character used as the delimiter, - * null splits on whitespace - * @return an array of parsed Strings, null if null String input - * @since 2.0 - */ - public static String[] split(String str, char separatorChar) { - return splitWorker(str, separatorChar, false); - } - - /** *

Splits the provided text into an array, separators specified. * This is an alternative to using StringTokenizer.

* @@ -6116,266 +585,9 @@ return splitWorker(str, separatorChars, -1, false); } - /** - *

Splits the provided text into an array with a maximum length, - * separators specified.

- * - *

The separator is not included in the returned String array. - * Adjacent separators are treated as one separator.

- * - *

A null input String returns null. - * A null separatorChars splits on whitespace.

- * - *

If more than max delimited substrings are found, the last - * returned string includes all characters after the first max - 1 - * returned strings (including separator characters).

- * - *
-   * StringUtils.split(null, *, *)            = null
-   * StringUtils.split("", *, *)              = []
-   * StringUtils.split("ab de fg", null, 0)   = ["ab", "cd", "ef"]
-   * StringUtils.split("ab   de fg", null, 0) = ["ab", "cd", "ef"]
-   * StringUtils.split("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
-   * StringUtils.split("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
-   * 
- * - * @param str the String to parse, may be null - * @param separatorChars the characters used as the delimiters, - * null splits on whitespace - * @param max the maximum number of elements to include in the - * array. A zero or negative value implies no limit - * @return an array of parsed Strings, null if null String input - */ - public static String[] split(String str, String separatorChars, int max) { - return splitWorker(str, separatorChars, max, false); - } - - /** - *

Splits the provided text into an array, separator string specified.

- * - *

The separator(s) will not be included in the returned String array. - * Adjacent separators are treated as one separator.

- * - *

A null input String returns null. - * A null separator splits on whitespace.

- * - *
-   * StringUtils.split(null, *)            = null
-   * StringUtils.split("", *)              = []
-   * StringUtils.split("ab de fg", null)   = ["ab", "de", "fg"]
-   * StringUtils.split("ab   de fg", null) = ["ab", "de", "fg"]
-   * StringUtils.split("ab:cd:ef", ":")    = ["ab", "cd", "ef"]
-   * StringUtils.split("abstemiouslyaeiouyabstemiously", "aeiouy")  = ["bst", "m", "sl", "bst", "m", "sl"]
-   * StringUtils.split("abstemiouslyaeiouyabstemiously", "aeiouy")  = ["abstemiously", "abstemiously"]
-   * 
- * - * @param str the String to parse, may be null - * @param separator String containing the String to be used as a delimiter, - * null splits on whitespace - * @return an array of parsed Strings, null if null String was input - */ - public static String[] splitByWholeSeparator(String str, String separator) { - return splitByWholeSeparator(str, separator, -1); - } - - /** - *

Splits the provided text into an array, separator string specified. - * Returns a maximum of max substrings.

- * - *

The separator(s) will not be included in the returned String array. - * Adjacent separators are treated as one separator.

- * - *

A null input String returns null. - * A null separator splits on whitespace.

- * - *
-   * StringUtils.splitByWholeSeparator(null, *, *)               = null
-   * StringUtils.splitByWholeSeparator("", *, *)                 = []
-   * StringUtils.splitByWholeSeparator("ab de fg", null, 0)      = ["ab", "de", "fg"]
-   * StringUtils.splitByWholeSeparator("ab   de fg", null, 0)    = ["ab", "de", "fg"]
-   * StringUtils.splitByWholeSeparator("ab:cd:ef", ":", 2)       = ["ab", "cd"]
-   * StringUtils.splitByWholeSeparator("abstemiouslyaeiouyabstemiously", "aeiouy", 2) = ["bst", "m"]
-   * StringUtils.splitByWholeSeparator("abstemiouslyaeiouyabstemiously", "aeiouy", 2)  = ["abstemiously", "abstemiously"]
-   * 
- * - * @param str the String to parse, may be null - * @param separator String containing the String to be used as a delimiter, - * null splits on whitespace - * @param max the maximum number of elements to include in the returned - * array. A zero or negative value implies no limit. - * @return an array of parsed Strings, null if null String was input - */ - @SuppressWarnings("unchecked") - public static String[] splitByWholeSeparator(String str, String separator, int max) { - if (str == null) { - return null; - } - - int len = str.length(); - - if (len == 0) { - return EMPTY_STRING_ARRAY; - } - - if ((separator == null) || ("".equals(separator))) { - // Split on whitespace. - return split(str, null, max); - } - - int separatorLength = separator.length(); - - ArrayList substrings = new ArrayList(); - int numberOfSubstrings = 0; - int beg = 0; - int end = 0; - while (end < len) { - end = str.indexOf(separator, beg); - - if (end > -1) { - if (end > beg) { - numberOfSubstrings += 1; - - if (numberOfSubstrings == max) { - end = len; - substrings.add(str.substring(beg)); - } else { - // The following is OK, because String.substring( beg, end ) excludes - // the character at the position 'end'. - substrings.add(str.substring(beg, end)); - - // Set the starting point for the next search. - // The following is equivalent to beg = end + (separatorLength - 1) + 1, - // which is the right calculation: - beg = end + separatorLength; - } - } else { - // We found a consecutive occurrence of the separator, so skip it. - beg = end + separatorLength; - } - } else { - // String.substring( beg ) goes from 'beg' to the end of the String. - substrings.add(str.substring(beg)); - end = len; - } - } - - return (String[]) substrings.toArray(new String[substrings.size()]); - } - //----------------------------------------------------------------------- - /** - *

Splits the provided text into an array, using whitespace as the - * separator, preserving all tokens, including empty tokens created by - * adjacent separators. This is an alternative to using StringTokenizer. - * Whitespace is defined by {@link Character#isWhitespace(char)}.

- * - *

The separator is not included in the returned String array. - * Adjacent separators are treated as separators for empty tokens. - * For more control over the split use the StrTokenizer class.

- * - *

A null input String returns null.

- * - *
-   * StringUtils.splitPreserveAllTokens(null)       = null
-   * StringUtils.splitPreserveAllTokens("")         = []
-   * StringUtils.splitPreserveAllTokens("abc def")  = ["abc", "def"]
-   * StringUtils.splitPreserveAllTokens("abc  def") = ["abc", "", "def"]
-   * StringUtils.splitPreserveAllTokens(" abc ")    = ["", "abc", ""]
-   * 
- * - * @param str the String to parse, may be null - * @return an array of parsed Strings, null if null String input - * @since 2.1 - */ - public static String[] splitPreserveAllTokens(String str) { - return splitWorker(str, null, -1, true); - } /** - *

Splits the provided text into an array, separator specified, - * preserving all tokens, including empty tokens created by adjacent - * separators. This is an alternative to using StringTokenizer.

- * - *

The separator is not included in the returned String array. - * Adjacent separators are treated as separators for empty tokens. - * For more control over the split use the StrTokenizer class.

- * - *

A null input String returns null.

- * - *
-   * StringUtils.splitPreserveAllTokens(null, *)         = null
-   * StringUtils.splitPreserveAllTokens("", *)           = []
-   * StringUtils.splitPreserveAllTokens("a.b.c", '.')    = ["a", "b", "c"]
-   * StringUtils.splitPreserveAllTokens("a..b.c", '.')   = ["a", "b", "c"]
-   * StringUtils.splitPreserveAllTokens("a:b:c", '.')    = ["a:b:c"]
-   * StringUtils.splitPreserveAllTokens("a\tb\nc", null) = ["a", "b", "c"]
-   * StringUtils.splitPreserveAllTokens("a b c", ' ')    = ["a", "b", "c"]
-   * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", ""]
-   * StringUtils.splitPreserveAllTokens("a b c ", ' ')   = ["a", "b", "c", "", ""]
-   * StringUtils.splitPreserveAllTokens(" a b c", ' ')   = ["", a", "b", "c"]
-   * StringUtils.splitPreserveAllTokens("  a b c", ' ')  = ["", "", a", "b", "c"]
-   * StringUtils.splitPreserveAllTokens(" a b c ", ' ')  = ["", a", "b", "c", ""]
-   * 
- * - * @param str the String to parse, may be null - * @param separatorChar the character used as the delimiter, - * null splits on whitespace - * @return an array of parsed Strings, null if null String input - * @since 2.1 - */ - public static String[] splitPreserveAllTokens(String str, char separatorChar) { - return splitWorker(str, separatorChar, true); - } - - /** - * Performs the logic for the split and - * splitPreserveAllTokens methods that do not return a - * maximum array length. - * - * @param str the String to parse, may be null - * @param separatorChar the separate character - * @param preserveAllTokens if true, adjacent separators are - * treated as empty token separators; if false, adjacent - * separators are treated as one separator. - * @return an array of parsed Strings, null if null String input - */ - @SuppressWarnings("unchecked") - private static String[] splitWorker(String str, char separatorChar, - boolean preserveAllTokens) { - // Performance tuned for 2.0 (JDK1.4) - - if (str == null) { - return null; - } - int len = str.length(); - if (len == 0) { - return EMPTY_STRING_ARRAY; - } - List list = new ArrayList(); - int i = 0, start = 0; - boolean match = false; - boolean lastMatch = false; - while (i < len) { - if (str.charAt(i) == separatorChar) { - if (match || preserveAllTokens) { - list.add(str.substring(start, i)); - match = false; - lastMatch = true; - } - start = ++i; - continue; - } - lastMatch = false; - match = true; - i++; - } - if (match || (preserveAllTokens && lastMatch)) { - list.add(str.substring(start, i)); - } - return (String[]) list.toArray(new String[list.size()]); - } - - /** *

Splits the provided text into an array, separators specified, * preserving all tokens, including empty tokens created by adjacent * separators. This is an alternative to using StringTokenizer.

@@ -6413,46 +625,6 @@ } /** - *

Splits the provided text into an array with a maximum length, - * separators specified, preserving all tokens, including empty tokens - * created by adjacent separators.

- * - *

The separator is not included in the returned String array. - * Adjacent separators are treated as separators for empty tokens. - * Adjacent separators are treated as one separator.

- * - *

A null input String returns null. - * A null separatorChars splits on whitespace.

- * - *

If more than max delimited substrings are found, the last - * returned string includes all characters after the first max - 1 - * returned strings (including separator characters).

- * - *
-   * StringUtils.splitPreserveAllTokens(null, *, *)            = null
-   * StringUtils.splitPreserveAllTokens("", *, *)              = []
-   * StringUtils.splitPreserveAllTokens("ab de fg", null, 0)   = ["ab", "cd", "ef"]
-   * StringUtils.splitPreserveAllTokens("ab   de fg", null, 0) = ["ab", "cd", "ef"]
-   * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 0)    = ["ab", "cd", "ef"]
-   * StringUtils.splitPreserveAllTokens("ab:cd:ef", ":", 2)    = ["ab", "cd:ef"]
-   * StringUtils.splitPreserveAllTokens("ab   de fg", null, 2) = ["ab", "  de fg"]
-   * StringUtils.splitPreserveAllTokens("ab   de fg", null, 3) = ["ab", "", " de fg"]
-   * StringUtils.splitPreserveAllTokens("ab   de fg", null, 4) = ["ab", "", "", "de fg"]
-   * 
- * - * @param str the String to parse, may be null - * @param separatorChars the characters used as the delimiters, - * null splits on whitespace - * @param max the maximum number of elements to include in the - * array. A zero or negative value implies no limit - * @return an array of parsed Strings, null if null String input - * @since 2.1 - */ - public static String[] splitPreserveAllTokens(String str, String separatorChars, int max) { - return splitWorker(str, separatorChars, max, true); - } - - /** * Performs the logic for the split and * splitPreserveAllTokens methods that return a maximum array * length. @@ -6557,185 +729,6 @@ //----------------------------------------------------------------------- /** - *

Joins the elements of the provided array into a single String - * containing the provided list of elements.

- * - *

No separator is added to the joined String. - * Null objects or empty strings within the array are represented by - * empty strings.

- * - *
-   * StringUtils.join(null)            = null
-   * StringUtils.join([])              = ""
-   * StringUtils.join([null])          = ""
-   * StringUtils.join(["a", "b", "c"]) = "abc"
-   * StringUtils.join([null, "", "a"]) = "a"
-   * 
- * - * @param array the array of values to join together, may be null - * @return the joined String, null if null array input - * @since 2.0 - */ - public static String join(Object[] array) { - return join(array, null); - } - - /** - *

Joins the elements of the provided array into a single String - * containing the provided list of elements.

- * - *

No delimiter is added before or after the list. - * Null objects or empty strings within the array are represented by - * empty strings.

- * - *
-   * StringUtils.join(null, *)               = null
-   * StringUtils.join([], *)                 = ""
-   * StringUtils.join([null], *)             = ""
-   * StringUtils.join(["a", "b", "c"], ';')  = "a;b;c"
-   * StringUtils.join(["a", "b", "c"], null) = "abc"
-   * StringUtils.join([null, "", "a"], ';')  = ";;a"
-   * 
- * - * @param array the array of values to join together, may be null - * @param separator the separator character to use - * @return the joined String, null if null array input - * @since 2.0 - */ - public static String join(Object[] array, char separator) { - if (array == null) { - return null; - } - int arraySize = array.length; - int bufSize = (arraySize == 0 ? 0 : ((array[0] == null ? 16 : array[0].toString() - .length()) + 1) - * arraySize); - StringBuffer buf = new StringBuffer(bufSize); - - for (int i = 0; i < arraySize; i++) { - if (i > 0) { - buf.append(separator); - } - if (array[i] != null) { - buf.append(array[i]); - } - } - return buf.toString(); - } - - /** - *

Joins the elements of the provided array into a single String - * containing the provided list of elements.

- * - *

No delimiter is added before or after the list. - * A null separator is the same as an empty String (""). - * Null objects or empty strings within the array are represented by - * empty strings.

- * - *
-   * StringUtils.join(null, *)                = null
-   * StringUtils.join([], *)                  = ""
-   * StringUtils.join([null], *)              = ""
-   * StringUtils.join(["a", "b", "c"], "--")  = "a--b--c"
-   * StringUtils.join(["a", "b", "c"], null)  = "abc"
-   * StringUtils.join(["a", "b", "c"], "")    = "abc"
-   * StringUtils.join([null, "", "a"], ',')   = ",,a"
-   * 
- * - * @param array the array of values to join together, may be null - * @param separator the separator character to use, null treated as "" - * @return the joined String, null if null array input - */ - public static String join(Object[] array, String separator) { - if (array == null) { - return null; - } - if (separator == null) { - separator = ""; - } - int arraySize = array.length; - - // ArraySize == 0: Len = 0 - // ArraySize > 0: Len = NofStrings *(len(firstString) + len(separator)) - // (Assuming that all Strings are roughly equally long) - int bufSize = ((arraySize == 0) ? 0 : arraySize - * ((array[0] == null ? 16 : array[0].toString().length()) + separator.length())); - - StringBuffer buf = new StringBuffer(bufSize); - - for (int i = 0; i < arraySize; i++) { - if (i > 0) { - buf.append(separator); - } - if (array[i] != null) { - buf.append(array[i]); - } - } - return buf.toString(); - } - - /** - *

Joins the elements of the provided Iterator into - * a single String containing the provided elements.

- * - *

No delimiter is added before or after the list. Null objects or empty - * strings within the iteration are represented by empty strings.

- * - *

See the examples here: {@link #join(Object[],char)}.

- * - * @param iterator the Iterator of values to join together, may be null - * @param separator the separator character to use - * @return the joined String, null if null iterator input - * @since 2.0 - */ - public static String join(Iterator iterator, char separator) { - if (iterator == null) { - return null; - } - StringBuffer buf = new StringBuffer(256); // Java default is 16, probably too small - while (iterator.hasNext()) { - Object obj = iterator.next(); - if (obj != null) { - buf.append(obj); - } - if (iterator.hasNext()) { - buf.append(separator); - } - } - return buf.toString(); - } - - /** - *

Joins the elements of the provided Iterator into - * a single String containing the provided elements.

- * - *

No delimiter is added before or after the list. - * A null separator is the same as an empty String ("").

- * - *

See the examples here: {@link #join(Object[],String)}.

- * - * @param iterator the Iterator of values to join together, may be null - * @param separator the separator character to use, null treated as "" - * @return the joined String, null if null iterator input - */ - public static String join(Iterator iterator, String separator) { - if (iterator == null) { - return null; - } - StringBuffer buf = new StringBuffer(256); // Java default is 16, probably too small - while (iterator.hasNext()) { - Object obj = iterator.next(); - if (obj != null) { - buf.append(obj); - } - if ((separator != null) && iterator.hasNext()) { - buf.append(separator); - } - } - return buf.toString(); - } - - /** *

Returns either the passed in String, * or if the String is null, an empty String ("").

* @@ -6755,715 +748,11 @@ } /** - *

Returns either the passed in String, or if the String is - * null, the value of defaultStr.

- * - *
-   * StringUtils.defaultString(null, "NULL")  = "NULL"
-   * StringUtils.defaultString("", "NULL")    = ""
-   * StringUtils.defaultString("bat", "NULL") = "bat"
-   * 
- * - * @see String#valueOf(Object) - * @param str the String to check, may be null - * @param defaultStr the default String to return - * if the input is null, may be null - * @return the passed in String, or the default if it was null - */ - public static String defaultString(String str, String defaultStr) { - return str == null ? defaultStr : str; - } - - /** - *

Returns either the passed in String, or if the String is - * empty or null, the value of defaultStr.

- * - *
-   * StringUtils.defaultIfEmpty(null, "NULL")  = "NULL"
-   * StringUtils.defaultIfEmpty("", "NULL")    = "NULL"
-   * StringUtils.defaultIfEmpty("bat", "NULL") = "bat"
-   * 
- * - * @param str the String to check, may be null - * @param defaultStr the default String to return - * if the input is empty ("") or null, may be null - * @return the passed in String, or the default - */ - public static String defaultIfEmpty(String str, String defaultStr) { - return isEmpty(str) ? defaultStr : str; - } - - /** - *

Capitalizes a String changing the first letter to title case as - * per {@link Character#toTitleCase(char)}. No other letters are changed.

- * - *

A null input String returns null.

- * - *
-   * StringUtils.capitalize(null)  = null
-   * StringUtils.capitalize("")    = ""
-   * StringUtils.capitalize("cat") = "Cat"
-   * StringUtils.capitalize("cAt") = "CAt"
-   * 
- * - * @param str the String to capitalize, may be null - * @return the capitalized String, null if null String input - * @since 2.0 - */ - public static String capitalize(String str) { - int strLen; - if (str == null || (strLen = str.length()) == 0) { - return str; - } - return new StringBuffer(strLen).append(Character.toTitleCase(str.charAt(0))).append( - str.substring(1)).toString(); - } - - /** - *

Checks if String contains a search character, handling null. - * This method uses {@link String#indexOf(int)}.

- * - *

A null or empty ("") String will return false.

- * - *
-   * StringUtils.contains(null, *)    = false
-   * StringUtils.contains("", *)      = false
-   * StringUtils.contains("abc", 'a') = true
-   * StringUtils.contains("abc", 'z') = false
-   * 
- * - * @param str the String to check, may be null - * @param searchChar the character to find - * @return true if the String contains the search character, - * false if not or null string input - * @since 2.0 - */ - public static boolean contains(String str, char searchChar) { - if (isEmpty(str)) { - return false; - } - return str.indexOf(searchChar) >= 0; - } - - /** - *

Checks if String contains a search String, handling null. - * This method uses {@link String#indexOf(int)}.

- * - *

A null String will return false.

- * - *
-   * StringUtils.contains(null, *)     = false
-   * StringUtils.contains(*, null)     = false
-   * StringUtils.contains("", "")      = true
-   * StringUtils.contains("abc", "")   = true
-   * StringUtils.contains("abc", "a")  = true
-   * StringUtils.contains("abc", "z")  = false
-   * 
- * - * @param str the String to check, may be null - * @param searchStr the String to find, may be null - * @return true if the String contains the search String, - * false if not or null string input - * @since 2.0 - */ - public static boolean contains(String str, String searchStr) { - if (str == null || searchStr == null) { - return false; - } - return str.indexOf(searchStr) >= 0; - } - - /** * An empty immutable String array. */ public static final String[] EMPTY_STRING_ARRAY = new String[0]; /** - *

Compares two objects for equality, where either one or both - * objects may be null.

- * - *
-   * ObjectUtils.equals(null, null)                  = true
-   * ObjectUtils.equals(null, "")                    = false
-   * ObjectUtils.equals("", null)                    = false
-   * ObjectUtils.equals("", "")                      = true
-   * ObjectUtils.equals(Boolean.TRUE, null)          = false
-   * ObjectUtils.equals(Boolean.TRUE, "true")        = false
-   * ObjectUtils.equals(Boolean.TRUE, Boolean.TRUE)  = true
-   * ObjectUtils.equals(Boolean.TRUE, Boolean.FALSE) = false
-   * 
- * - * @param object1 the first object, may be null - * @param object2 the second object, may be null - * @return true if the values of both objects are the same - */ - public static boolean equals(Object object1, Object object2) { - if (object1 == object2) { - return true; - } - if ((object1 == null) || (object2 == null)) { - return false; - } - return object1.equals(object2); - } - - /** - *

A way to get the entire nested stack-trace of an throwable.

- * - * @param throwable the Throwable to be examined - * @return the nested stack trace, with the root cause first - * @since 2.0 - */ - public static String getFullStackTrace(Throwable throwable) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw, true); - Throwable[] ts = getThrowables(throwable); - for (int i = 0; i < ts.length; i++) { - ts[i].printStackTrace(pw); - if (isNestedThrowable(ts[i])) { - break; - } - } - return sw.getBuffer().toString(); - } - /** - *

Returns the list of Throwable objects in the - * exception chain.

- * - *

A throwable without cause will return an array containing - * one element - the input throwable. - * A throwable with one cause will return an array containing - * two elements. - the input throwable and the cause throwable. - * A null throwable will return an array size zero.

- * - * @param throwable the throwable to inspect, may be null - * @return the array of throwables, never null - */ - @SuppressWarnings("unchecked") - public static Throwable[] getThrowables(Throwable throwable) { - List list = new ArrayList(); - while (throwable != null) { - list.add(throwable); - throwable = getCause(throwable); - } - return (Throwable[]) list.toArray(new Throwable[list.size()]); - } - - /** - *

The names of methods commonly used to access a wrapped exception.

- */ - private static String[] CAUSE_METHOD_NAMES = { - "getCause", - "getNextException", - "getTargetException", - "getException", - "getSourceException", - "getRootCause", - "getCausedByException", - "getNested", - "getLinkedException", - "getNestedException", - "getLinkedCause", - "getThrowable", - }; - - /** - *

Checks whether this Throwable class can store a cause.

- * - *

This method does not check whether it actually does store a cause.

- * - * @param throwable the Throwable to examine, may be null - * @return boolean true if nested otherwise false - * @since 2.0 - */ - public static boolean isNestedThrowable(Throwable throwable) { - if (throwable == null) { - return false; - } - - if (throwable instanceof SQLException) { - return true; - } else if (throwable instanceof InvocationTargetException) { - return true; - } else if (isThrowableNested()) { - return true; - } - - Class cls = throwable.getClass(); - for (int i = 0, isize = CAUSE_METHOD_NAMES.length; i < isize; i++) { - try { - Method method = cls.getMethod(CAUSE_METHOD_NAMES[i], (Class[])null); - if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) { - return true; - } - } catch (NoSuchMethodException ignored) { - } catch (SecurityException ignored) { - } - } - - try { - Field field = cls.getField("detail"); - if (field != null) { - return true; - } - } catch (NoSuchFieldException ignored) { - } catch (SecurityException ignored) { - } - - return false; - } - - /** - *

The Method object for JDK1.4 getCause.

- */ - private static final Method THROWABLE_CAUSE_METHOD; - static { - Method getCauseMethod; - try { - getCauseMethod = Throwable.class.getMethod("getCause", (Class[])null); - } catch (Exception e) { - getCauseMethod = null; - } - THROWABLE_CAUSE_METHOD = getCauseMethod; - } - - /** - *

Checks if the Throwable class has a getCause method.

- * - *

This is true for JDK 1.4 and above.

- * - * @return true if Throwable is nestable - * @since 2.0 - */ - public static boolean isThrowableNested() { - return THROWABLE_CAUSE_METHOD != null; - } - - /** - *

Introspects the Throwable to obtain the cause.

- * - *

The method searches for methods with specific names that return a - * Throwable object. This will pick up most wrapping exceptions, - * including those from JDK 1.4, and

- * - *

The default list searched for are:

- *
    - *
  • getCause()
  • - *
  • getNextException()
  • - *
  • getTargetException()
  • - *
  • getException()
  • - *
  • getSourceException()
  • - *
  • getRootCause()
  • - *
  • getCausedByException()
  • - *
  • getNested()
  • - *
- * - *

In the absence of any such method, the object is inspected for a - * detail field assignable to a Throwable.

- * - *

If none of the above is found, returns null.

- * - * @param throwable the throwable to introspect for a cause, may be null - * @return the cause of the Throwable, - * null if none found or null throwable input - * @since 1.0 - */ - public static Throwable getCause(Throwable throwable) { - return getCause(throwable, CAUSE_METHOD_NAMES); - } - - /** - *

Introspects the Throwable to obtain the cause.

- * - *
    - *
  1. Try known exception types.
  2. - *
  3. Try the supplied array of method names.
  4. - *
  5. Try the field 'detail'.
  6. - *
- * - *

A null set of method names means use the default set. - * A null in the set of method names will be ignored.

- * - * @param throwable the throwable to introspect for a cause, may be null - * @param methodNames the method names, null treated as default set - * @return the cause of the Throwable, - * null if none found or null throwable input - * @since 1.0 - */ - public static Throwable getCause(Throwable throwable, String[] methodNames) { - if (throwable == null) { - return null; - } - Throwable cause = getCauseUsingWellKnownTypes(throwable); - if (cause == null) { - if (methodNames == null) { - methodNames = CAUSE_METHOD_NAMES; - } - for (int i = 0; i < methodNames.length; i++) { - String methodName = methodNames[i]; - if (methodName != null) { - cause = getCauseUsingMethodName(throwable, methodName); - if (cause != null) { - break; - } - } - } - - if (cause == null) { - cause = getCauseUsingFieldName(throwable, "detail"); - } - } - return cause; - } - - /** - *

Finds a Throwable by method name.

- * - * @param throwable the exception to examine - * @param methodName the name of the method to find and invoke - * @return the wrapped exception, or null if not found - */ - private static Throwable getCauseUsingMethodName(Throwable throwable, String methodName) { - Method method = null; - try { - method = throwable.getClass().getMethod(methodName, (Class[])null); - } catch (NoSuchMethodException ignored) { - } catch (SecurityException ignored) { - } - - if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) { - try { - return (Throwable) method.invoke(throwable, EMPTY_OBJECT_ARRAY); - } catch (IllegalAccessException ignored) { - } catch (IllegalArgumentException ignored) { - } catch (InvocationTargetException ignored) { - } - } - return null; - } - - /** - *

Finds a Throwable by field name.

- * - * @param throwable the exception to examine - * @param fieldName the name of the attribute to examine - * @return the wrapped exception, or null if not found - */ - private static Throwable getCauseUsingFieldName(Throwable throwable, String fieldName) { - Field field = null; - try { - field = throwable.getClass().getField(fieldName); - } catch (NoSuchFieldException ignored) { - } catch (SecurityException ignored) { - } - - if (field != null && Throwable.class.isAssignableFrom(field.getType())) { - try { - return (Throwable) field.get(throwable); - } catch (IllegalAccessException ignored) { - } catch (IllegalArgumentException ignored) { - } - } - return null; - } - - /** - *

Finds a Throwable for known types.

- * - *

Uses instanceof checks to examine the exception, - * looking for well known types which could contain chained or - * wrapped exceptions.

- * - * @param throwable the exception to examine - * @return the wrapped exception, or null if not found - */ - private static Throwable getCauseUsingWellKnownTypes(Throwable throwable) { - if (throwable instanceof SQLException) { - return ((SQLException) throwable).getNextException(); - } else if (throwable instanceof InvocationTargetException) { - return ((InvocationTargetException) throwable).getTargetException(); - } else { - return null; - } - } - - /** - * An empty immutable Object array. - */ - public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; - - /** - * from a command line arg, get the key. e.g. if input is --whatever=something - * then key is whatever, value is something - * @param option string such as "--key=value" - * @return the key portion of the argument - */ - public static String argKey(String option) { - int equalsIndex = option.indexOf("="); - if (equalsIndex == -1) { - throw new RuntimeException("Invalid option: " + option + ", it should look like: --someOption=someValue"); - } - String key = option.substring(0,equalsIndex); - if (!key.startsWith("--")) { - throw new RuntimeException("Invalid option: " + option + ", it should look like: --someOption=someValue"); - } - key = key.substring(2); - return key; - } - - /** - * from a command line arg, get the key. e.g. if input is --whatever=something - * then key is whatever, value is something - * @param option The option string such as "--someOption=value" - * @return the value of the option - */ - public static String argValue(String option) { - int equalsIndex = option.indexOf("="); - if (equalsIndex == -1) { - throw new RuntimeException("Invalid option: " + option + ", it should look like: --someOption=someValue"); - } - String value = option.substring(equalsIndex+1, option.length()); - return value; - } - - /** add an option: --whatever=val to a map of options where --whatever is key, and val is value - * @param args Arguments array - * @return the map - */ - public static Map argMap(String[] args) { - - Map result = new LinkedHashMap(); - - for (String arg : nonNull(args,String.class)) { - String key = argKey(arg); - String value = argValue(arg); - if (result.containsKey(key)) { - throw new RuntimeException("Passing key twice: " + key); - } - result.put(key, value); - } - - return result; - } - - /** - * get the value from the argMap, throw exception if not there and required - * @param argMap map of argument key/values - * @param argMapNotUsed keeps track of unused arguments - * @param key the key to lookup - * @param required whether or not the key is required to be present - * @return the value or null or exception - */ - public static String argMapString(Map argMap, Map argMapNotUsed, - String key, boolean required) { - - if (argMap.containsKey(key)) { - - //keep track that this is gone - argMapNotUsed.remove(key); - - return argMap.get(key); - } - if (required) { - throw new RuntimeException("Argument '--" + key + "' is required, but not specified. e.g. --" + key + "=value"); - } - return null; - - } - - /** - * get the value from the argMap, throw exception if not there and required - * @param argMap map of argument key/values - * @param argMapNotUsed keeps track of unused arguments - * @param key the key to lookup - * @param required whether or not the key is required to be present - * @param defaultValue the value to use when the key lookup results in blank / null - * @return the value or null or exception - */ - public static boolean argMapBoolean(Map argMap, Map argMapNotUsed, - String key, boolean required, boolean defaultValue) { - String argString = argMapString(argMap, argMapNotUsed, key, required); - - if (isBlank(argString) && required) { - throw new RuntimeException("Argument '--" + key + "' is required, but not specified. e.g. --" + key + "=true"); - } - return booleanValue(argString, defaultValue); - } - - /** - * get the value from the argMap, throw exception if not there and required - * @param argMap map of argument key/values - * @param argMapNotUsed keeps track of unused arguments - * @param key the key to lookup - * @return the value or null or exception - */ - public static Timestamp argMapTimestamp(Map argMap, Map argMapNotUsed, - String key) { - String argString = argMapString(argMap, argMapNotUsed, key, false); - if (isBlank(argString)) { - return null; - } - Date date = stringToDate2(argString); - return new Timestamp(date.getTime()); - } - - /** - * get the value from the argMap - * @param argMap map of argument key/values - * @param argMapNotUsed keeps track of unused arguments - * @param key the key to lookup - * @return the value or null or exception - */ - public static Boolean argMapBoolean(Map argMap, Map argMapNotUsed, - String key) { - String argString = argMapString(argMap, argMapNotUsed, key, false); - - return booleanObjectValue(argString); - } - - /** - * get the set from comma separated from the argMap, throw exception if not there and required - * @param argMap map of argument key/values - * @param argMapNotUsed keeps track of unused arguments - * @param key the key to lookup - * @param required whether or not the key is required to be present - * @return the value or null or exception - */ - public static Set argMapSet(Map argMap, Map argMapNotUsed, - String key, boolean required) { - List list = argMapList(argMap, argMapNotUsed, key, required); - return list == null ? null : new LinkedHashSet(list); - } - - /** - * get the list from comma separated from the argMap, throw exception if not there and required - * @param argMap map of argument key/values - * @param argMapNotUsed keeps track of unused arguments - * @param key the key to lookup - * @param required whether or not the key is required to be present - * @return the value or null or exception - */ - public static List argMapList(Map argMap, Map argMapNotUsed, - String key, boolean required) { - String argString = argMapString(argMap, argMapNotUsed, key, required); - if (isBlank(argString)) { - return null; - } - return splitTrimToList(argString, ","); - } - - /** - * get the list from comma separated from the argMap, throw exception if not there and required - * @param argMap map of argument key/values - * @param argMapNotUsed keeps track of unused arguments - * @param key the key to lookup - * @param required whether or not the key is required to be present - * @return the value or null or exception - */ - public static List argMapFileList(Map argMap, Map argMapNotUsed, - String key, boolean required) { - String argString = argMapString(argMap, argMapNotUsed, key, required); - if (isBlank(argString)) { - return null; - } - //read from file - File file = new File(argString); - try { - //do this by regex, since we dont know what platform we are on - String listString = readFileIntoString(file); - String[] array = listString.split("\\s+"); - List list = new ArrayList(); - for (String string : array) { - //dont know if any here will be blank or whatnot - if (!isBlank(string)) { - //should already be trimmed, but just in case - list.add(trim(string)); - } - } - return list; - } catch (Exception e) { - throw new RuntimeException("Error reading file: '" - + fileCanonicalPath(file) + "' from command line arg: " + key, e ); - } - } - - /** - * Copy bytes from an InputStream to chars on a - * Writer using the default character encoding of the platform. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - *

- * This method uses {@link InputStreamReader}. - * - * @param input the InputStream to read from - * @param output the Writer to write to - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.1 - */ - public static void copy(InputStream input, Writer output) - throws IOException { - String charsetName = "UTF-8"; - InputStreamReader in = new InputStreamReader(input, charsetName); - copy(in, output); - } - - /** - * Copy bytes from an InputStream to an - * OutputStream. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - *

- * Large streams (over 2GB) will return a bytes copied value of - * -1 after the copy has completed since the correct - * number of bytes cannot be returned as an int. For large streams - * use the copyLarge(InputStream, OutputStream) method. - * - * @param input the InputStream to read from - * @param output the OutputStream to write to - * @return the number of bytes copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @throws ArithmeticException if the byte count is too large - * @since Commons IO 1.1 - */ - public static int copy(InputStream input, OutputStream output) throws IOException { - long count = copyLarge(input, output); - if (count > Integer.MAX_VALUE) { - return -1; - } - return (int) count; - } - - /** - * Copy bytes from a large (over 2GB) InputStream to an - * OutputStream. - *

- * This method buffers the input internally, so there is no need to use a - * BufferedInputStream. - * - * @param input the InputStream to read from - * @param output the OutputStream to write to - * @return the number of bytes copied - * @throws NullPointerException if the input or output is null - * @throws IOException if an I/O error occurs - * @since Commons IO 1.3 - */ - public static long copyLarge(InputStream input, OutputStream output) - throws IOException { - byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; - long count = 0; - int n = 0; - while (-1 != (n = input.read(buffer))) { - output.write(buffer, 0, n); - count += n; - } - return count; - } - - /** * get a jar file from a sample class * @param sampleClass the class for which the jar is looked up * @return the jar file @@ -7519,1799 +808,4 @@ return input; } - - /** - * retrieve a password from stdin - * @param dontMask when true, the user's typing will appear on the screen - * @param prompt to print to user - * @return the password - */ - public static String retrievePasswordFromStdin(boolean dontMask, String prompt) { - String passwordString = null; - - if (dontMask) { - - System.out.print(prompt); - // open up standard input - BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); - - // read the username from the command-line; need to use try/catch with the - // readLine() method - try { - passwordString = br.readLine(); - } catch (IOException ioe) { - System.out.println("IO error! " + getFullStackTrace(ioe)); - System.exit(1); - } - - } else { - char password[] = null; - try { - password = retrievePasswordFromStdin(System.in, prompt); - } catch (IOException ioe) { - ioe.printStackTrace(); - } - passwordString = String.valueOf(password); - } - return passwordString; - - } - - /** - * @param in stream to be used (e.g. System.in) - * @param prompt The prompt to display to the user. - * @return The password as entered by the user. - * @throws IOException when there was a problem with the input stream - */ - public static final char[] retrievePasswordFromStdin(InputStream in, String prompt) throws IOException { - MaskingThread maskingthread = new MaskingThread(prompt); - - Thread thread = new Thread(maskingthread); - thread.start(); - - char[] lineBuffer; - char[] buf; - - buf = lineBuffer = new char[128]; - - int room = buf.length; - int offset = 0; - int c; - - loop: while (true) { - switch (c = in.read()) { - case -1: - case '\n': - break loop; - - case '\r': - int c2 = in.read(); - if ((c2 != '\n') && (c2 != -1)) { - if (!(in instanceof PushbackInputStream)) { - in = new PushbackInputStream(in); - } - ((PushbackInputStream) in).unread(c2); - } else { - break loop; - } - - default: - if (--room < 0) { - buf = new char[offset + 128]; - room = buf.length - offset - 1; - System.arraycopy(lineBuffer, 0, buf, 0, offset); - Arrays.fill(lineBuffer, ' '); - lineBuffer = buf; - } - buf[offset++] = (char) c; - break; - } - } - maskingthread.stopMasking(); - if (offset == 0) { - return null; - } - char[] ret = new char[offset]; - System.arraycopy(buf, 0, ret, 0, offset); - Arrays.fill(buf, ' '); - return ret; - } - - /** - * thread to mask input - */ - static class MaskingThread extends Thread { - - /** stop */ - private volatile boolean stop; - - /** echo char, this doesnt work correctly, so make a space so people dont notice... - * prints out too many */ - private char echochar = ' '; - - /** - *@param prompt The prompt displayed to the user - */ - public MaskingThread(String prompt) { - System.out.print(prompt); - } - - /** - * Begin masking until asked to stop. - */ - @Override - public void run() { - - int priority = Thread.currentThread().getPriority(); - Thread.currentThread().setPriority(Thread.MAX_PRIORITY); - - try { - this.stop = true; - while (this.stop) { - System.out.print("\010" + this.echochar); - try { - // attempt masking at this rate - Thread.sleep(1); - } catch (InterruptedException iex) { - Thread.currentThread().interrupt(); - return; - } - } - } finally { // restore the original priority - Thread.currentThread().setPriority(priority); - } - } - - /** - * Instruct the thread to stop masking. - */ - public void stopMasking() { - this.stop = false; - } - } - - /** - * make sure a value exists in properties - * @param resourceName the resource name - * @param properties the properties - * @param overrideMap a map overriding some properties, used in testing or debug - * @param key the property key - * @param exceptionOnError when true, throw an exception if property is not the proper value type - * @return true if ok, false if not - */ - public static boolean propertyValidateValueRequired(String resourceName, Properties properties, - Map overrideMap, String key, boolean exceptionOnError) { - - Map threadLocalMap = propertiesThreadLocalOverrideMap(resourceName); - - String value = propertiesValue(properties, threadLocalMap, overrideMap, key); - - if (!isBlank(value)) { - return true; - } - String error = "Cant find property " + key + " in resource: " + resourceName + ", it is required"; - - if (exceptionOnError) { - throw new RuntimeException(error); - } - - System.err.println("Grouper error: " + error); - return false; - } - - /** - * make sure a value is boolean in properties - * @param resourceName the resource name - * @param properties the properties - * @param overrideMap a map overriding some properties, used in testing or debug - * @param key the property key - * @param required whether or not a value is required for the key - * @param exceptionOnError when true, throw an exception if property is not the proper value type - * @return true if ok, false if not - */ - public static boolean propertyValidateValueBoolean(String resourceName, Properties properties, - Map overrideMap, String key, - boolean required, boolean exceptionOnError) { - - if (required && !propertyValidateValueRequired(resourceName, properties, - overrideMap, key, exceptionOnError)) { - return false; - } - - Map threadLocalMap = propertiesThreadLocalOverrideMap(resourceName); - - String value = propertiesValue(properties, threadLocalMap, overrideMap, key); - //maybe ok not there - if (!required && isBlank(value)) { - return true; - } - try { - booleanValue(value); - return true; - } catch (Exception e) { - - } - String error = "Expecting true or false property " + key + " in resource: " + resourceName + ", but is '" + value + "'"; - if (exceptionOnError) { - throw new RuntimeException(error); - } - System.err.println("Grouper error: " + error); - return false; - } - - - /** - * make sure a value is int in properties - * @param resourceName the resource name - * @param properties the properties - * @param overrideMap a map overriding some properties, used in testing or debug - * @param key the property key - * @param required whether or not a value is required for the key - * @param exceptionOnError when true, throw an exception if property is not the proper value type - * @return true if ok, false if not - */ - public static boolean propertyValidateValueInt(String resourceName, Properties properties, - Map overrideMap, String key, - boolean required, boolean exceptionOnError) { - - if (required && !propertyValidateValueRequired(resourceName, properties, - overrideMap, key, exceptionOnError)) { - return false; - } - - Map threadLocalMap = propertiesThreadLocalOverrideMap(resourceName); - - String value = propertiesValue(properties, threadLocalMap, overrideMap, key); - //maybe ok not there - if (!required && isBlank(value)) { - return true; - } - try { - intValue(value); - return true; - } catch (Exception e) { - - } - String error = "Expecting integer property " + key + " in resource: " + resourceName + ", but is '" + value + "'"; - if (exceptionOnError) { - throw new RuntimeException(error); - } - System.err.println("Grouper error: " + error); - return false; - } - - /** - * make sure a property is a class of a certain type - * @param resourceName the property resource name - * @param properties the set of properties - * @param overrideMap for testing, to override some properties values - * @param key the lookup key - * @param classType the desired class type - * @param required whether or not a value is required - * @param exceptionOnError throw an exception when there is an error - * @return true if ok - */ - public static boolean propertyValidateValueClass(String resourceName, Properties properties, - Map overrideMap, String key, Class classType, boolean required, boolean exceptionOnError) { - - if (required && !propertyValidateValueRequired(resourceName, properties, - overrideMap, key, exceptionOnError)) { - return false; - } - String value = propertiesValue(properties, overrideMap, key); - - //maybe ok not there - if (!required && isBlank(value)) { - return true; - } - - String extraError = ""; - try { - - - Class theClass = forName(value); - if (classType.isAssignableFrom(theClass)) { - return true; - } - extraError = " does not derive from class: " + classType.getSimpleName(); - - } catch (Exception e) { - extraError = ", " + getFullStackTrace(e); - } - String error = "Cant process property " + key + " in resource: " + resourceName + ", the current" + - " value is '" + value + "', which should be of type: " - + classType.getName() + extraError; - if (exceptionOnError) { - throw new RuntimeException(error); - } - System.err.println("Grouper error: " + error); - return false; - - } - - /** - *

Strips any of a set of characters from the start of a String.

- * - *

A null input String returns null. - * An empty string ("") input returns the empty string.

- * - *

If the stripChars String is null, whitespace is - * stripped as defined by {@link Character#isWhitespace(char)}.

- * - *
-   * StringUtils.stripStart(null, *)          = null
-   * StringUtils.stripStart("", *)            = ""
-   * StringUtils.stripStart("abc", "")        = "abc"
-   * StringUtils.stripStart("abc", null)      = "abc"
-   * StringUtils.stripStart("  abc", null)    = "abc"
-   * StringUtils.stripStart("abc  ", null)    = "abc  "
-   * StringUtils.stripStart(" abc ", null)    = "abc "
-   * StringUtils.stripStart("yxabc  ", "xyz") = "abc  "
-   * 
- * - * @param str the String to remove characters from, may be null - * @param stripChars the characters to remove, null treated as whitespace - * @return the stripped String, null if null String input - */ - public static String stripStart(String str, String stripChars) { - int strLen; - if (str == null || (strLen = str.length()) == 0) { - return str; - } - int start = 0; - if (stripChars == null) { - while ((start != strLen) && Character.isWhitespace(str.charAt(start))) { - start++; - } - } else if (stripChars.length() == 0) { - return str; - } else { - while ((start != strLen) && (stripChars.indexOf(str.charAt(start)) != -1)) { - start++; - } - } - return str.substring(start); - } - - /** - *

Strips any of a set of characters from the end of a String.

- * - *

A null input String returns null. - * An empty string ("") input returns the empty string.

- * - *

If the stripChars String is null, whitespace is - * stripped as defined by {@link Character#isWhitespace(char)}.

- * - *
-   * StringUtils.stripEnd(null, *)          = null
-   * StringUtils.stripEnd("", *)            = ""
-   * StringUtils.stripEnd("abc", "")        = "abc"
-   * StringUtils.stripEnd("abc", null)      = "abc"
-   * StringUtils.stripEnd("  abc", null)    = "  abc"
-   * StringUtils.stripEnd("abc  ", null)    = "abc"
-   * StringUtils.stripEnd(" abc ", null)    = " abc"
-   * StringUtils.stripEnd("  abcyx", "xyz") = "  abc"
-   * 
- * - * @param str the String to remove characters from, may be null - * @param stripChars the characters to remove, null treated as whitespace - * @return the stripped String, null if null String input - */ - public static String stripEnd(String str, String stripChars) { - int end; - if (str == null || (end = str.length()) == 0) { - return str; - } - - if (stripChars == null) { - while ((end != 0) && Character.isWhitespace(str.charAt(end - 1))) { - end--; - } - } else if (stripChars.length() == 0) { - return str; - } else { - while ((end != 0) && (stripChars.indexOf(str.charAt(end - 1)) != -1)) { - end--; - } - } - return str.substring(0, end); - } - - /** - * The empty String "". - * @since 2.0 - */ - public static final String EMPTY = ""; - - /** - * Represents a failed index search. - * @since 2.1 - */ - public static final int INDEX_NOT_FOUND = -1; - - /** - *

The maximum size to which the padding constant(s) can expand.

- */ - private static final int PAD_LIMIT = 8192; - - /** - *

An array of Strings used for padding.

- * - *

Used for efficient space padding. The length of each String expands as needed.

- */ - private static final String[] PADDING = new String[Character.MAX_VALUE]; - - static { - // space padding is most common, start with 64 chars - PADDING[32] = " "; - } - - /** - *

Repeat a String repeat times to form a - * new String.

- * - *
-   * StringUtils.repeat(null, 2) = null
-   * StringUtils.repeat("", 0)   = ""
-   * StringUtils.repeat("", 2)   = ""
-   * StringUtils.repeat("a", 3)  = "aaa"
-   * StringUtils.repeat("ab", 2) = "abab"
-   * StringUtils.repeat("a", -2) = ""
-   * 
- * - * @param str the String to repeat, may be null - * @param repeat number of times to repeat str, negative treated as zero - * @return a new String consisting of the original String repeated, - * null if null String input - */ - public static String repeat(String str, int repeat) { - // Performance tuned for 2.0 (JDK1.4) - - if (str == null) { - return null; - } - if (repeat <= 0) { - return EMPTY; - } - int inputLength = str.length(); - if (repeat == 1 || inputLength == 0) { - return str; - } - if (inputLength == 1 && repeat <= PAD_LIMIT) { - return padding(repeat, str.charAt(0)); - } - - int outputLength = inputLength * repeat; - switch (inputLength) { - case 1: - char ch = str.charAt(0); - char[] output1 = new char[outputLength]; - for (int i = repeat - 1; i >= 0; i--) { - output1[i] = ch; - } - return new String(output1); - case 2: - char ch0 = str.charAt(0); - char ch1 = str.charAt(1); - char[] output2 = new char[outputLength]; - for (int i = repeat * 2 - 2; i >= 0; i--, i--) { - output2[i] = ch0; - output2[i + 1] = ch1; - } - return new String(output2); - default: - StringBuffer buf = new StringBuffer(outputLength); - for (int i = 0; i < repeat; i++) { - buf.append(str); - } - return buf.toString(); - } - } - - /** - *

Returns padding using the specified delimiter repeated - * to a given length.

- * - *
-   * StringUtils.padding(0, 'e')  = ""
-   * StringUtils.padding(3, 'e')  = "eee"
-   * StringUtils.padding(-2, 'e') = IndexOutOfBoundsException
-   * 
- * - * @param repeat number of times to repeat delim - * @param padChar character to repeat - * @return String with repeated character - * @throws IndexOutOfBoundsException if repeat < 0 - */ - private static String padding(int repeat, char padChar) { - // be careful of synchronization in this method - // we are assuming that get and set from an array index is atomic - String pad = PADDING[padChar]; - if (pad == null) { - pad = String.valueOf(padChar); - } - while (pad.length() < repeat) { - pad = pad.concat(pad); - } - PADDING[padChar] = pad; - return pad.substring(0, repeat); - } - - /** - *

Right pad a String with spaces (' ').

- * - *

The String is padded to the size of size.

- * - *
-   * StringUtils.rightPad(null, *)   = null
-   * StringUtils.rightPad("", 3)     = "   "
-   * StringUtils.rightPad("bat", 3)  = "bat"
-   * StringUtils.rightPad("bat", 5)  = "bat  "
-   * StringUtils.rightPad("bat", 1)  = "bat"
-   * StringUtils.rightPad("bat", -1) = "bat"
-   * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @return right padded String or original String if no padding is necessary, - * null if null String input - */ - public static String rightPad(String str, int size) { - return rightPad(str, size, ' '); - } - - /** - *

Right pad a String with a specified character.

- * - *

The String is padded to the size of size.

- * - *
-   * StringUtils.rightPad(null, *, *)     = null
-   * StringUtils.rightPad("", 3, 'z')     = "zzz"
-   * StringUtils.rightPad("bat", 3, 'z')  = "bat"
-   * StringUtils.rightPad("bat", 5, 'z')  = "batzz"
-   * StringUtils.rightPad("bat", 1, 'z')  = "bat"
-   * StringUtils.rightPad("bat", -1, 'z') = "bat"
-   * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @param padChar the character to pad with - * @return right padded String or original String if no padding is necessary, - * null if null String input - * @since 2.0 - */ - public static String rightPad(String str, int size, char padChar) { - if (str == null) { - return null; - } - int pads = size - str.length(); - if (pads <= 0) { - return str; // returns original String when possible - } - if (pads > PAD_LIMIT) { - return rightPad(str, size, String.valueOf(padChar)); - } - return str.concat(padding(pads, padChar)); - } - - /** - *

Right pad a String with a specified String.

- * - *

The String is padded to the size of size.

- * - *
-   * StringUtils.rightPad(null, *, *)      = null
-   * StringUtils.rightPad("", 3, "z")      = "zzz"
-   * StringUtils.rightPad("bat", 3, "yz")  = "bat"
-   * StringUtils.rightPad("bat", 5, "yz")  = "batyz"
-   * StringUtils.rightPad("bat", 8, "yz")  = "batyzyzy"
-   * StringUtils.rightPad("bat", 1, "yz")  = "bat"
-   * StringUtils.rightPad("bat", -1, "yz") = "bat"
-   * StringUtils.rightPad("bat", 5, null)  = "bat  "
-   * StringUtils.rightPad("bat", 5, "")    = "bat  "
-   * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @param padStr the String to pad with, null or empty treated as single space - * @return right padded String or original String if no padding is necessary, - * null if null String input - */ - public static String rightPad(String str, int size, String padStr) { - if (str == null) { - return null; - } - if (isEmpty(padStr)) { - padStr = " "; - } - int padLen = padStr.length(); - int strLen = str.length(); - int pads = size - strLen; - if (pads <= 0) { - return str; // returns original String when possible - } - if (padLen == 1 && pads <= PAD_LIMIT) { - return rightPad(str, size, padStr.charAt(0)); - } - - if (pads == padLen) { - return str.concat(padStr); - } else if (pads < padLen) { - return str.concat(padStr.substring(0, pads)); - } else { - char[] padding = new char[pads]; - char[] padChars = padStr.toCharArray(); - for (int i = 0; i < pads; i++) { - padding[i] = padChars[i % padLen]; - } - return str.concat(new String(padding)); - } - } - - /** - *

Left pad a String with spaces (' ').

- * - *

The String is padded to the size of size.

- * - *
-   * StringUtils.leftPad(null, *)   = null
-   * StringUtils.leftPad("", 3)     = "   "
-   * StringUtils.leftPad("bat", 3)  = "bat"
-   * StringUtils.leftPad("bat", 5)  = "  bat"
-   * StringUtils.leftPad("bat", 1)  = "bat"
-   * StringUtils.leftPad("bat", -1) = "bat"
-   * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @return left padded String or original String if no padding is necessary, - * null if null String input - */ - public static String leftPad(String str, int size) { - return leftPad(str, size, ' '); - } - - /** - *

Left pad a String with a specified character.

- * - *

Pad to a size of size.

- * - *
-   * StringUtils.leftPad(null, *, *)     = null
-   * StringUtils.leftPad("", 3, 'z')     = "zzz"
-   * StringUtils.leftPad("bat", 3, 'z')  = "bat"
-   * StringUtils.leftPad("bat", 5, 'z')  = "zzbat"
-   * StringUtils.leftPad("bat", 1, 'z')  = "bat"
-   * StringUtils.leftPad("bat", -1, 'z') = "bat"
-   * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @param padChar the character to pad with - * @return left padded String or original String if no padding is necessary, - * null if null String input - * @since 2.0 - */ - public static String leftPad(String str, int size, char padChar) { - if (str == null) { - return null; - } - int pads = size - str.length(); - if (pads <= 0) { - return str; // returns original String when possible - } - if (pads > PAD_LIMIT) { - return leftPad(str, size, String.valueOf(padChar)); - } - return padding(pads, padChar).concat(str); - } - - /** - *

Left pad a String with a specified String.

- * - *

Pad to a size of size.

- * - *
-   * StringUtils.leftPad(null, *, *)      = null
-   * StringUtils.leftPad("", 3, "z")      = "zzz"
-   * StringUtils.leftPad("bat", 3, "yz")  = "bat"
-   * StringUtils.leftPad("bat", 5, "yz")  = "yzbat"
-   * StringUtils.leftPad("bat", 8, "yz")  = "yzyzybat"
-   * StringUtils.leftPad("bat", 1, "yz")  = "bat"
-   * StringUtils.leftPad("bat", -1, "yz") = "bat"
-   * StringUtils.leftPad("bat", 5, null)  = "  bat"
-   * StringUtils.leftPad("bat", 5, "")    = "  bat"
-   * 
- * - * @param str the String to pad out, may be null - * @param size the size to pad to - * @param padStr the String to pad with, null or empty treated as single space - * @return left padded String or original String if no padding is necessary, - * null if null String input - */ - public static String leftPad(String str, int size, String padStr) { - if (str == null) { - return null; - } - if (isEmpty(padStr)) { - padStr = " "; - } - int padLen = padStr.length(); - int strLen = str.length(); - int pads = size - strLen; - if (pads <= 0) { - return str; // returns original String when possible - } - if (padLen == 1 && pads <= PAD_LIMIT) { - return leftPad(str, size, padStr.charAt(0)); - } - - if (pads == padLen) { - return padStr.concat(str); - } else if (pads < padLen) { - return padStr.substring(0, pads).concat(str); - } else { - char[] padding = new char[pads]; - char[] padChars = padStr.toCharArray(); - for (int i = 0; i < pads; i++) { - padding[i] = padChars[i % padLen]; - } - return new String(padding).concat(str); - } - } - - /** - * convert an exception to a runtime exception - * @param e the exception to convert - */ - public static void convertToRuntimeException(Exception e) { - if (e instanceof RuntimeException) { - throw (RuntimeException)e; - } - throw new RuntimeException(e.getMessage(), e); - } - - /** - *

Gets the substring before the first occurrence of a separator. - * The separator is not returned.

- * - *

A null string input will return null. - * An empty ("") string input will return the empty string. - * A null separator will return the input string.

- * - *
-   * StringUtils.substringBefore(null, *)      = null
-   * StringUtils.substringBefore("", *)        = ""
-   * StringUtils.substringBefore("abc", "a")   = ""
-   * StringUtils.substringBefore("abcba", "b") = "a"
-   * StringUtils.substringBefore("abc", "c")   = "ab"
-   * StringUtils.substringBefore("abc", "d")   = "abc"
-   * StringUtils.substringBefore("abc", "")    = ""
-   * StringUtils.substringBefore("abc", null)  = "abc"
-   * 
- * - * @param str the String to get a substring from, may be null - * @param separator the String to search for, may be null - * @return the substring before the first occurrence of the separator, - * null if null String input - * @since 2.0 - */ - public static String substringBefore(String str, String separator) { - if (isEmpty(str) || separator == null) { - return str; - } - if (separator.length() == 0) { - return EMPTY; - } - int pos = str.indexOf(separator); - if (pos == -1) { - return str; - } - return str.substring(0, pos); - } - - /** - *

Gets the substring after the first occurrence of a separator. - * The separator is not returned.

- * - *

A null string input will return null. - * An empty ("") string input will return the empty string. - * A null separator will return the empty string if the - * input string is not null.

- * - *
-   * StringUtils.substringAfter(null, *)      = null
-   * StringUtils.substringAfter("", *)        = ""
-   * StringUtils.substringAfter(*, null)      = ""
-   * StringUtils.substringAfter("abc", "a")   = "bc"
-   * StringUtils.substringAfter("abcba", "b") = "cba"
-   * StringUtils.substringAfter("abc", "c")   = ""
-   * StringUtils.substringAfter("abc", "d")   = ""
-   * StringUtils.substringAfter("abc", "")    = "abc"
-   * 
- * - * @param str the String to get a substring from, may be null - * @param separator the String to search for, may be null - * @return the substring after the first occurrence of the separator, - * null if null String input - * @since 2.0 - */ - public static String substringAfter(String str, String separator) { - if (isEmpty(str)) { - return str; - } - if (separator == null) { - return EMPTY; - } - int pos = str.indexOf(separator); - if (pos == -1) { - return EMPTY; - } - return str.substring(pos + separator.length()); - } - - /** - *

Gets the substring before the last occurrence of a separator. - * The separator is not returned.

- * - *

A null string input will return null. - * An empty ("") string input will return the empty string. - * An empty or null separator will return the input string.

- * - *
-   * StringUtils.substringBeforeLast(null, *)      = null
-   * StringUtils.substringBeforeLast("", *)        = ""
-   * StringUtils.substringBeforeLast("abcba", "b") = "abc"
-   * StringUtils.substringBeforeLast("abc", "c")   = "ab"
-   * StringUtils.substringBeforeLast("a", "a")     = ""
-   * StringUtils.substringBeforeLast("a", "z")     = "a"
-   * StringUtils.substringBeforeLast("a", null)    = "a"
-   * StringUtils.substringBeforeLast("a", "")      = "a"
-   * 
- * - * @param str the String to get a substring from, may be null - * @param separator the String to search for, may be null - * @return the substring before the last occurrence of the separator, - * null if null String input - * @since 2.0 - */ - public static String substringBeforeLast(String str, String separator) { - if (isEmpty(str) || isEmpty(separator)) { - return str; - } - int pos = str.lastIndexOf(separator); - if (pos == -1) { - return str; - } - return str.substring(0, pos); - } - - /** - *

Gets the substring after the last occurrence of a separator. - * The separator is not returned.

- * - *

A null string input will return null. - * An empty ("") string input will return the empty string. - * An empty or null separator will return the empty string if - * the input string is not null.

- * - *
-   * StringUtils.substringAfterLast(null, *)      = null
-   * StringUtils.substringAfterLast("", *)        = ""
-   * StringUtils.substringAfterLast(*, "")        = ""
-   * StringUtils.substringAfterLast(*, null)      = ""
-   * StringUtils.substringAfterLast("abc", "a")   = "bc"
-   * StringUtils.substringAfterLast("abcba", "b") = "a"
-   * StringUtils.substringAfterLast("abc", "c")   = ""
-   * StringUtils.substringAfterLast("a", "a")     = ""
-   * StringUtils.substringAfterLast("a", "z")     = ""
-   * 
- * - * @param str the String to get a substring from, may be null - * @param separator the String to search for, may be null - * @return the substring after the last occurrence of the separator, - * null if null String input - * @since 2.0 - */ - public static String substringAfterLast(String str, String separator) { - if (isEmpty(str)) { - return str; - } - if (isEmpty(separator)) { - return EMPTY; - } - int pos = str.lastIndexOf(separator); - if (pos == -1 || pos == (str.length() - separator.length())) { - return EMPTY; - } - return str.substring(pos + separator.length()); - } - - /** - * get the value from the argMap, throw exception if not there and required - * @param argMap the map of arguments - * @param argMapNotUsed map that tracks unused arguments - * @param key argument key - * @param required wheter or not the key is required to be present - * @param defaultValue the value to use when the value looked up from key is blank - * @return the value or null or exception - */ - public static Integer argMapInteger(Map argMap, Map argMapNotUsed, - String key, boolean required, Integer defaultValue) { - String argString = argMapString(argMap, argMapNotUsed, key, required); - - if (isBlank(argString) && required) { - throw new RuntimeException("Argument '--" + key + "' is required, but not specified. e.g. --" + key + "=5"); - } - if (isBlank(argString)) { - if (defaultValue != null) { - return defaultValue; - } - return null; - } - return intValue(argString); - } - - /** - * null safe convert from java.util.Date to java.sql.Date - * @param date the java Date to be converted - * @return the sql date - */ - public static java.sql.Date toSqlDate(Date date) { - if (date == null) { - return null; - } - return new java.sql.Date(date.getTime()); - } - - /** - *

Find the index of the given object in the array.

- * - *

This method returns -1 if null array input.

- * - * @param array the array to search through for the object, may be null - * @param objectToFind the object to find, may be null - * @return the index of the object within the array, - * -1 if not found or null array input - */ - public static int indexOf(Object[] array, Object objectToFind) { - return indexOf(array, objectToFind, 0); - } - - /** - *

Checks if the object is in the given array.

- * - *

The method returns false if a null array is passed in.

- * - * @param array the array to search through - * @param objectToFind the object to find - * @return true if the array contains the object - */ - public static boolean contains(Object[] array, Object objectToFind) { - return indexOf(array, objectToFind) != -1; - } - - /** - *

Find the index of the given object in the array starting at the given index.

- * - *

This method returns -1 if null array input.

- * - *

A negative startIndex is treated as zero. A startIndex larger than the array - * length will return -1.

- * - * @param array the array to search through for the object, may be null - * @param objectToFind the object to find, may be null - * @param startIndex the index to start searching at - * @return the index of the object within the array starting at the index, - * -1 if not found or null array input - */ - public static int indexOf(Object[] array, Object objectToFind, int startIndex) { - if (array == null) { - return -1; - } - if (startIndex < 0) { - startIndex = 0; - } - if (objectToFind == null) { - for (int i = startIndex; i < array.length; i++) { - if (array[i] == null) { - return i; - } - } - } else { - for (int i = startIndex; i < array.length; i++) { - if (objectToFind.equals(array[i])) { - return i; - } - } - } - return -1; - } - - /** - * Note, this is web service format string - */ - private static final String WS_DATE_FORMAT = "yyyy/MM/dd HH:mm:ss.SSS"; - - /** - * Note, this is web service format string - */ - private static final String WS_DATE_FORMAT2 = "yyyy/MM/dd_HH:mm:ss.SSS"; - - /** - * convert a date to a string using the standard web service pattern - * yyyy/MM/dd HH:mm:ss.SSS Note that HH is 0-23 - * - * @param date the date to convert - * @return the string, or null if the date is null - */ - public static String dateToString(Date date) { - if (date == null) { - return null; - } - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WS_DATE_FORMAT); - return simpleDateFormat.format(date); - } - - /** - * convert a string to a date using the standard web service pattern Note - * that HH is 0-23 - * - * @param dateString the string to parse into a date - * @return the string, or null if the date was null - */ - public static Date stringToDate(String dateString) { - if (isBlank(dateString)) { - return null; - } - SimpleDateFormat simpleDateFormat = new SimpleDateFormat(WS_DATE_FORMAT); - try { - return simpleDateFormat.parse(dateString); - } catch (ParseException e) { - SimpleDateFormat simpleDateFormat2 = new SimpleDateFormat(WS_DATE_FORMAT2); - try { - return simpleDateFormat2.parse(dateString); - } catch (ParseException e2) { - throw new RuntimeException("Cannot convert '" + dateString - + "' to a date based on format: " + WS_DATE_FORMAT, e); - } - } - } - - /** - * match regex pattern yyyy-mm-dd or yyyy/mm/dd - */ - private static Pattern datePattern_yyyy_mm_dd = Pattern.compile("^(\\d{4})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})$"); - - /** - * match regex pattern dd-mon-yyyy or dd/mon/yyyy - */ - private static Pattern datePattern_dd_mon_yyyy = Pattern.compile("^(\\d{1,2})[^\\d]+([a-zA-Z]{3,15})[^\\d]+(\\d{4})$"); - - /** - * match regex pattern yyyy-mm-dd hh:mm:ss or yyyy/mm/dd hh:mm:ss - */ - private static Pattern datePattern_yyyy_mm_dd_hhmmss = Pattern.compile("^(\\d{4})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})$"); - - /** - * match regex pattern dd-mon-yyyy hh:mm:ss or dd/mon/yyyy hh:mm:ss - */ - private static Pattern datePattern_dd_mon_yyyy_hhmmss = Pattern.compile("^(\\d{1,2})[^\\d]+([a-zA-Z]{3,15})[^\\d]+(\\d{4})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})$"); - - /** - * match regex pattern yyyy-mm-dd hh:mm:ss.SSS or yyyy/mm/dd hh:mm:ss.SSS - */ - private static Pattern datePattern_yyyy_mm_dd_hhmmss_SSS = Pattern.compile("^(\\d{4})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,3})$"); - - /** - * match regex pattern dd-mon-yyyy hh:mm:ss.SSS or dd/mon/yyyy hh:mm:ss.SSS - */ - private static Pattern datePattern_dd_mon_yyyy_hhmmss_SSS = Pattern.compile("^(\\d{1,2})[^\\d]+([a-zA-Z]{3,15})[^\\d]+(\\d{4})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,2})[^\\d]+(\\d{1,3})$"); - - /** - * take as input: - * yyyy/mm/dd - * yyyy-mm-dd - * dd-mon-yyyy - * yyyy/mm/dd hh:mm:ss - * dd-mon-yyyy hh:mm:ss - * yyyy/mm/dd hh:mm:ss.SSS - * dd-mon-yyyy hh:mm:ss.SSS - * @param input the string to parse into a date - * @return the date - */ - public static Date stringToDate2(String input) { - - if (isBlank(input)) { - return null; - } - input = input.trim(); - Matcher matcher = null; - - int month = 0; - int day = 0; - int year = 0; - int hour = 0; - int minute = 0; - int second = 0; - int milli = 0; - - boolean foundMatch = false; - - //yyyy/mm/dd - if (!foundMatch) { - matcher = datePattern_yyyy_mm_dd.matcher(input); - if (matcher.matches()) { - year = intValue(matcher.group(1)); - month = intValue(matcher.group(2)); - day = intValue(matcher.group(3)); - foundMatch = true; - } - } - - //dd-mon-yyyy - if (!foundMatch) { - matcher = datePattern_dd_mon_yyyy.matcher(input); - if (matcher.matches()) { - day = intValue(matcher.group(1)); - month = monthInt(matcher.group(2)); - year = intValue(matcher.group(3)); - foundMatch = true; - } - } - - //yyyy/mm/dd hh:mm:ss - if (!foundMatch) { - matcher = datePattern_yyyy_mm_dd_hhmmss.matcher(input); - if (matcher.matches()) { - year = intValue(matcher.group(1)); - month = intValue(matcher.group(2)); - day = intValue(matcher.group(3)); - hour = intValue(matcher.group(4)); - minute = intValue(matcher.group(5)); - second = intValue(matcher.group(6)); - foundMatch = true; - } - } - - //dd-mon-yyyy hh:mm:ss - if (!foundMatch) { - matcher = datePattern_dd_mon_yyyy_hhmmss.matcher(input); - if (matcher.matches()) { - day = intValue(matcher.group(1)); - month = monthInt(matcher.group(2)); - year = intValue(matcher.group(3)); - hour = intValue(matcher.group(4)); - minute = intValue(matcher.group(5)); - second = intValue(matcher.group(6)); - foundMatch = true; - } - } - - //yyyy/mm/dd hh:mm:ss.SSS - if (!foundMatch) { - matcher = datePattern_yyyy_mm_dd_hhmmss_SSS.matcher(input); - if (matcher.matches()) { - year = intValue(matcher.group(1)); - month = intValue(matcher.group(2)); - day = intValue(matcher.group(3)); - hour = intValue(matcher.group(4)); - minute = intValue(matcher.group(5)); - second = intValue(matcher.group(6)); - milli = intValue(matcher.group(7)); - foundMatch = true; - } - } - - //dd-mon-yyyy hh:mm:ss.SSS - if (!foundMatch) { - matcher = datePattern_dd_mon_yyyy_hhmmss_SSS.matcher(input); - if (matcher.matches()) { - day = intValue(matcher.group(1)); - month = monthInt(matcher.group(2)); - year = intValue(matcher.group(3)); - hour = intValue(matcher.group(4)); - minute = intValue(matcher.group(5)); - second = intValue(matcher.group(6)); - milli = intValue(matcher.group(7)); - foundMatch = true; - } - } - - Calendar calendar = Calendar.getInstance(); - calendar.set(Calendar.YEAR, year); - calendar.set(Calendar.MONTH, month-1); - calendar.set(Calendar.DAY_OF_MONTH, day); - calendar.set(Calendar.HOUR_OF_DAY, hour); - calendar.set(Calendar.MINUTE, minute); - calendar.set(Calendar.SECOND, second); - calendar.set(Calendar.MILLISECOND, milli); - return calendar.getTime(); - } - - /** - * convert a month string to an int (1 indexed). - * e.g. if input is feb or Feb or february or February return 2 - * @param mon English month string such as "jan, feb, march, april, may, jun, june, ..." - * @return the month number 1 - 12 for "january" - "december" - */ - public static int monthInt(String mon) { - - if (!isBlank(mon)) { - mon = mon.toLowerCase(); - - if (equals(mon, "jan") || equals(mon, "january")) { - return 1; - } - - if (equals(mon, "feb") || equals(mon, "february")) { - return 2; - } - - if (equals(mon, "mar") || equals(mon, "march")) { - return 3; - } - - if (equals(mon, "apr") || equals(mon, "april")) { - return 4; - } - - if (equals(mon, "may")) { - return 5; - } - - if (equals(mon, "jun") || equals(mon, "june")) { - return 6; - } - - if (equals(mon, "jul") || equals(mon, "july")) { - return 7; - } - - if (equals(mon, "aug") || equals(mon, "august")) { - return 8; - } - - if (equals(mon, "sep") || equals(mon, "september")) { - return 9; - } - - if (equals(mon, "oct") || equals(mon, "october")) { - return 10; - } - - if (equals(mon, "nov") || equals(mon, "november")) { - return 11; - } - - if (equals(mon, "dec") || equals(mon, "december")) { - return 12; - } - - } - - throw new RuntimeException("Invalid month: " + mon); - } - - /** - * override map for properties in thread local to be used in a web server or the like, based on property file name - * @param propertiesFileName properties file name - * @return the override map - */ - public static Map propertiesThreadLocalOverrideMap(String propertiesFileName) { - Map> overrideMap = propertiesThreadLocalOverrideMap.get(); - if (overrideMap == null) { - overrideMap = new HashMap>(); - propertiesThreadLocalOverrideMap.set(overrideMap); - } - Map propertiesOverrideMap = overrideMap.get(propertiesFileName); - if (propertiesOverrideMap == null) { - propertiesOverrideMap = new HashMap(); - overrideMap.put(propertiesFileName, propertiesOverrideMap); - } - return propertiesOverrideMap; - } - - - /** - * This will execute a command, and split spaces for args (might not be what - * you want if you are using quotes) - * - * @param command The command string to execute - */ - public static void execCommand(String command) { - String[] args = splitTrim(command, " "); - execCommand(args); - } - - /** - * Gobble up a stream from a runtime - * @author mchyzer - * @param the gobbler type - */ - private static class StreamGobbler implements Callable { - - /** stream to read */ - InputStream inputStream; - - /** where to put the result */ - String resultString; - - /** type of the output for logging purposes */ - String type; - - /** command to log */ - String command; - /** - * construct - * @param is - * @param theType - * @param theCommand - */ - StreamGobbler(InputStream is, String theType, String theCommand) { - this.inputStream = is; - this.type = theType; - this.command = theCommand; - } - - /** - * get the string result - * @return the result - */ - public String getResultString() { - return this.resultString; - } - - // @Override - public V call() throws Exception { - try { - - StringWriter stringWriter = new StringWriter(); - copy(this.inputStream, stringWriter); - this.resultString = stringWriter.toString(); - - } catch (Exception e) { - - throw new RuntimeException(e); - - } - return null; - } - } - - /** - *
This will execute a command (with args). In this method, 
-   * if the exit code of the command is not zero, an exception will be thrown.
-   * Example call: execCommand(new String[]{"/bin/bash", "-c", "cd /someFolder; runSomeScript.sh"}, true);
-   * 
- * @param arguments are the commands - * @return the output text of the command. - */ - public static CommandResult execCommand(String[] arguments) { - return execCommand(arguments, true); - } - - /** - * threadpool - */ - private static ExecutorService executorService = Executors.newCachedThreadPool(new DaemonThreadFactory()); - - - /** - * - * @return executor service - */ - public static ExecutorService retrieveExecutorService() { - return executorService; - } - - /** - *
This will execute a command (with args). Under normal operation, 
-   * if the exit code of the command is not zero, an exception will be thrown.
-   * If the parameter exceptionOnExitValueNeZero is set to true, the 
-   * results of the call will be returned regardless of the exit status.
-   * Example call: execCommand(new String[]{"/bin/bash", "-c", "cd /someFolder; runSomeScript.sh"}, true);
-   * 
- * @param arguments are the commands - * @param exceptionOnExitValueNeZero if this is set to false, the - * results of the call will be returned regardless of the exit status - * @return the output text of the command, and the error and return code if exceptionOnExitValueNeZero is false. - */ - public static CommandResult execCommand(String[] arguments, boolean exceptionOnExitValueNeZero) { - Process process = null; - - StringBuilder commandBuilder = new StringBuilder(); - for (int i = 0; i < arguments.length; i++) { - commandBuilder.append(arguments[i]).append(" "); - } - String command = commandBuilder.toString(); - StreamGobbler outputGobbler = null; - StreamGobbler errorGobbler = null; - try { - process = Runtime.getRuntime().exec(arguments); - - outputGobbler = new StreamGobbler(process.getInputStream(), ".out", command); - errorGobbler = new StreamGobbler(process.getErrorStream(), ".err", command); - - Future futureOutput = retrieveExecutorService().submit(outputGobbler); - Future futureError = retrieveExecutorService().submit(errorGobbler); - - try { - process.waitFor(); - } finally { - - //finish running these threads - try { - futureOutput.get(); - } finally { - //ignore if cant get - } - try { - futureError.get(); - } finally { - //ignore if cant get - } - } - } catch (Exception e) { - throw new RuntimeException("Error running command", e); - } finally { - try { - process.destroy(); - } catch (Exception e) { - } - } - - //was not successful??? - if (process.exitValue() != 0 && exceptionOnExitValueNeZero) { - String message = "Process exit status=" + process.exitValue() + ": out: " + - (outputGobbler == null ? null : outputGobbler.getResultString()) - + ", err: " + (errorGobbler == null ? null : errorGobbler.getResultString()); - throw new RuntimeException(message); - } - - int exitValue = process.exitValue(); - return new CommandResult(outputGobbler.getResultString(), errorGobbler.getResultString(), exitValue); - } - - - /** - * The results of executing a command. - */ - public static class CommandResult{ - /** - * If any error text was generated by the call, it will be set here. - */ - private String errorText; - - /** - * If any output text was generated by the call, it will be set here. - */ - private String outputText; - - /** - * If any exit code was generated by the call, it will be set here. - */ - private int exitCode; - - - /** - * Create a container to hold the results of an execution. - * @param _errorText the error text - * @param _outputText the output text - * @param _exitCode the exit code - */ - public CommandResult(String _errorText, String _outputText, int _exitCode){ - this.errorText = _errorText; - this.outputText = _outputText; - this.exitCode = _exitCode; - } - - - - /** - * If any error text was generated by the call, it will be set here. - * @return the errorText - */ - public String getErrorText() { - return this.errorText; - } - - - - /** - * If any output text was generated by the call, it will be set here. - * @return the outputText - */ - public String getOutputText() { - return this.outputText; - } - - - - /** - * If any exit code was generated by the call, it will be set here. - * @return the exitCode - */ - public int getExitCode() { - return this.exitCode; - } - - - - } - - /** - * thread factory with daemon threads so the JVM exits - * @author mchyzer - * - */ - private static class DaemonThreadFactory implements ThreadFactory { - private ThreadFactory threadFactory = Executors.defaultThreadFactory(); - - @Override - public Thread newThread(Runnable r) { - Thread thread = threadFactory.newThread(r); - thread.setDaemon(true); - return thread; - } - - } - - /** - * serialize an object to a file (create parent dir if necessary) - * @param object the serializable object - * @param file the destination file - */ - public static void serializeObjectToFile(Serializable object, File file) { - - //delete, make sure parents are there - deleteCreateFile(file); - - FileOutputStream fos = null; - ObjectOutputStream out = null; - try { - fos = new FileOutputStream(file); - out = new ObjectOutputStream(fos); - out.writeObject(object); - } catch(IOException ex) { - //we had a problem, don't leave the file partway created... - closeQuietly(out); - out = null; - deleteFile(file); - throw new RuntimeException("Error writing file: " + absolutePath(file) - + ", " + className(object), ex); - } finally { - closeQuietly(out); - } - - } - - /** - * unserialize an object from a file if it exists - * @param file the file containing the serialized object - * @param nullIfException true if null should be returned instead of exception - * @param deleteFileOnException true if file should be deleted on exception - * @return the object or null - */ - public static Serializable unserializeObjectFromFile(File file, boolean nullIfException, - boolean deleteFileOnException) { - - if (!file.exists() || file.length() == 0) { - return null; - } - - FileInputStream fis = null; - ObjectInputStream ois = null; - try { - fis = new FileInputStream(file); - ois = new ObjectInputStream(fis); - return (Serializable)ois.readObject(); - } catch(Exception ex) { - String error = "Error writing file: " + absolutePath(file); - if (!nullIfException) { - throw new RuntimeException(error, ex); - } - //maybe clear the file if problem - if (deleteFileOnException) { - //close before deleting - closeQuietly(ois); - ois = null; - deleteFile(file); - } - return null; - } finally { - closeQuietly(ois); - } - - } - - /** - * delete and create a new file. If its a directory, delete, and create a new dir. - * - * @param file - * is the file to delete and create - */ - public static void deleteCreateFile(File file) { - - deleteFile(file); - - createParentDirectories(file); - - try { - if (!file.createNewFile()) { - throw new IOException("createNewFile returned false: "); - } - } catch (IOException ioe) { - throw new RuntimeException("Couldnt create new file: " + file.toString(), ioe); - } - - } - - /** - * Delete a file, throw exception if cannot - * @param file the file or directory to delete - */ - public static void deleteFile(File file) { - //delete and create - if (file != null && file.exists()) { - - if (file.isDirectory()) { - deleteRecursiveDirectory(file.getAbsolutePath()); - } else if (!file.delete()) { - throw new RuntimeException("Couldnt delete file: " + file.toString()); - } - } - } - - /** - * copy a file to a new file - * @param fromFile source file - * @param toFile target file - */ - public static void copy(File fromFile, File toFile) { - if (toFile.exists()) { - deleteFile(toFile); - } - FileInputStream fromFileStream = null; - FileOutputStream toFileStream = null; - try { - fromFileStream = new FileInputStream(fromFile); - toFileStream = new FileOutputStream(toFile); - copy(fromFileStream, toFileStream); - } catch (Exception e) { - throw new RuntimeException("Problem copying file: " + fromFile.getAbsolutePath() - + " to file: " + toFile.getAbsolutePath()); - } - // Adding finally block to ensure streams are closed - finally { - try{ - fromFileStream.close(); - toFileStream.close(); - } - catch (IOException e) { - throw new RuntimeException("Problem closing FileStream while copying file: " + fromFile.getAbsolutePath() - + " to file: " + toFile.getAbsolutePath()); - } - } - } - - /** - * rename a file to another file and throw runtime exception if not ok - * @param fromFile source file - * @param toFile target file - */ - public static void renameTo(File fromFile, File toFile) { - - if (!fromFile.renameTo(toFile)) { - throw new RuntimeException("Cannot rename file: '" + fromFile.getAbsolutePath() - + "', to file: '" + toFile.getAbsolutePath() + "'"); - } - - } - - /** - * clear out all files recursively in a directory, including the directory - * itself - * @param dirName the directory name to delete - * - * @throws RuntimeException - * when something goes wrong - */ - public static void deleteRecursiveDirectory(String dirName) { - //delete all files in the directory - File dir = new File(dirName); - - //if it doesnt exist then we are done - if (!dir.exists()) { - return; - } - - //see if its a directory - if (!dir.isDirectory()) { - throw new RuntimeException("The directory: " + dirName + " is not a directory"); - } - - //get the files into a vector - File[] allFiles = dir.listFiles(); - - //loop through the array - for (int i = 0; i < allFiles.length; i++) { - if (-1 < allFiles[i].getName().indexOf("..")) { - continue; //dont go to the parent directory - } - - if (allFiles[i].isFile()) { - //delete the file - if (!allFiles[i].delete()) { - throw new RuntimeException("Could not delete file: " + allFiles[i].getPath()); - } - } else { - //its a directory - deleteRecursiveDirectory(allFiles[i].getPath()); - } - } - - //delete the directory itself - if (!dir.delete()) { - throw new RuntimeException("Could not delete directory: " + dir.getPath()); - } - } - - /** - * absolute path null safe - * @param file the absolute path of the given file, or null - * @return absolute path null safe - */ - public static String absolutePath(File file) { - return file == null ? null : file.getAbsolutePath(); - } - - - /** - * pattern to get the file path or resource location for a file - */ - private static Pattern fileLocationPattern = Pattern.compile("^(file|classpath)\\s*:(.*)$"); - - /** - * file or classpath location - * @param typeAndLocation the string describing the resource. Begins with "file:" or "classpath:". - * @param logHint used as prefix for RuntimeException messages - * @return the inputstream - */ - public static InputStream fileOrClasspathInputstream(String typeAndLocation, String logHint) { - Matcher matcher = fileLocationPattern.matcher(typeAndLocation); - if (!matcher.matches()) { - throw new RuntimeException(logHint + " must start with file: or classpath:"); - } - String typeString = matcher.group(1); - String location = trim(matcher.group(2)); - - if (equals(typeString, "file")) { - File file = new File(location); - if (!file.exists() || !file.isFile()) { - throw new RuntimeException(logHint + " File does not exist: " + file.getAbsolutePath()); - } - try { - return new FileInputStream(file); - } catch (Exception e) { - throw new RuntimeException(logHint + " Problem with file: " + file.getAbsolutePath()); - } - } else if (equals(typeString, "classpath")) { - if (!location.startsWith("/")) { - location = "/" + location; - } - try { - return ConfigPropertiesCascadeCommonUtils.class.getResourceAsStream(location); - } catch (Exception e) { - throw new RuntimeException(logHint + " Problem with classpath location: " + location); - } - } else { - throw new RuntimeException(logHint + " Not expecting type string: " + typeString); - } - - } - - - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigPropertiesCascadeUtils.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigPropertiesCascadeUtils.java (.../ConfigPropertiesCascadeUtils.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigPropertiesCascadeUtils.java (.../ConfigPropertiesCascadeUtils.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,10 +26,9 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.config.overlay; - - import java.util.Map; /** @@ -44,11 +43,8 @@ * @return the string The modified strings, with replacements */ public static String substituteExpressionLanguage(String stringToParse, Map variableMap) { - return substituteExpressionLanguage(stringToParse, variableMap, true, true, true, false); - } - /** * substitute an EL for objects @@ -67,6 +63,4 @@ //we don't have jexl so don't do this logic return stringToParse; } - - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigurationAutodetectProviderFactory.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigurationAutodetectProviderFactory.java (.../ConfigurationAutodetectProviderFactory.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigurationAutodetectProviderFactory.java (.../ConfigurationAutodetectProviderFactory.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,36 +1,62 @@ -/** - * @author mchyzer - * $Id$ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.config.overlay; -import java.io.IOException; -import java.io.InputStream; -import java.util.Properties; - +import org.owasp.csrfguard.config.properties.ConfigParameters; import org.owasp.csrfguard.config.ConfigurationProvider; import org.owasp.csrfguard.config.ConfigurationProviderFactory; import org.owasp.csrfguard.config.PropertiesConfigurationProviderFactory; import org.owasp.csrfguard.util.CsrfGuardUtils; +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + /** - * The default configuration provider is: org.owasp.csrfguard.config.overlay.ConfigurationAutodetectProviderFactory - * which will look for an overlay file, it is there, and the factory inside that file is set it will use it, otherwise will be PropertiesConfigurationProviderFactory - * it needs to implement org.owasp.csrfguard.config.ConfigurationProviderFactory + * The default configuration provider is: {@link org.owasp.csrfguard.config.overlay.ConfigurationAutodetectProviderFactory} + * which will look for an overlay file, it is there, and the factory inside that file is set it will use it, otherwise will be {@link PropertiesConfigurationProviderFactory} + * it needs to implement {@link org.owasp.csrfguard.config.ConfigurationProviderFactory} + * + * @author mchyzer */ -public class ConfigurationAutodetectProviderFactory implements - ConfigurationProviderFactory { +public class ConfigurationAutodetectProviderFactory implements ConfigurationProviderFactory { /** - * + * TODO document */ - public ConfigurationAutodetectProviderFactory() { - } + public ConfigurationAutodetectProviderFactory() {} /** * configuration provider cached */ - private static ExpirableCache configurationProviderCache = new ExpirableCache(2); + private static ExpirableCache configurationProviderCache = new ExpirableCache(2); // TODO does this really reload the configurations in every 2 minutes?! /** * @see org.owasp.csrfguard.config.ConfigurationProviderFactory#retrieveConfiguration(java.util.Properties) @@ -54,9 +80,9 @@ } catch (IOException ioe) { throw new RuntimeException("Error reading config file: " + ConfigurationOverlayProvider.OWASP_CSRF_GUARD_OVERLAY_PROPERTIES, ioe); } - CsrfGuardUtils.closeQuietly(inputStream); + ConfigPropertiesCascadeCommonUtils.closeQuietly(inputStream); - String factoryClassName = theProperties.getProperty("org.owasp.csrfguard.configuration.provider.factory"); + String factoryClassName = theProperties.getProperty(ConfigParameters.CONFIG_PROVIDER_FACTORY_PROPERTY_NAME); if (factoryClassName != null && !"".equals(factoryClassName)) { if (ConfigurationAutodetectProviderFactory.class.getName().equals(factoryClassName)) { throw new RuntimeException("Cannot specify auto detect factory in override file (recursion), pick the actual factory: " + factoryClassName); @@ -79,5 +105,4 @@ return configurationProvider; } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigurationOverlayProvider.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigurationOverlayProvider.java (.../ConfigurationOverlayProvider.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigurationOverlayProvider.java (.../ConfigurationOverlayProvider.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,14 +1,43 @@ -/** +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* * @author mchyzer * $Id$ */ package org.owasp.csrfguard.config.overlay; -import java.io.InputStream; - +import org.apache.commons.lang3.StringUtils; import org.owasp.csrfguard.CsrfGuardServletContextListener; -import org.owasp.csrfguard.util.CsrfGuardUtils; +import org.owasp.csrfguard.config.properties.ConfigParameters; +import java.io.InputStream; /** * Use configuration overlays that use the base properties as a default, and then decorate with an overlay file @@ -44,45 +73,26 @@ public ConfigurationOverlayProvider() { } - /** - * @see org.owasp.csrfguard.config.overlay.ConfigPropertiesCascadeBase#getSecondsToCheckConfigKey() - */ @Override protected String getSecondsToCheckConfigKey() { - return "org.owasp.csrfguard.configOverlay.secondsBetweenUpdateChecks"; + return ConfigParameters.CONFIG_OVERLAY_UPDATE_CHECK_PROPERTY_NAME; } - /** - * @see org.owasp.csrfguard.config.overlay.ConfigPropertiesCascadeBase#clearCachedCalculatedValues() - */ @Override - public void clearCachedCalculatedValues() { - } - - /** - * @see org.owasp.csrfguard.config.overlay.ConfigPropertiesCascadeBase#getMainConfigClasspath() - */ - @Override protected String getMainConfigClasspath() { return OWASP_CSRF_GUARD_OVERLAY_PROPERTIES; } - /** - * @see org.owasp.csrfguard.config.overlay.ConfigPropertiesCascadeBase#getHierarchyConfigKey() - */ @Override protected String getHierarchyConfigKey() { - return "org.owasp.csrfguard.configOverlay.hierarchy"; + return ConfigParameters.CONFIG_OVERLAY_HIERARCHY_PROPERTY_NAME; } /** * see which configs are available */ private static String mainExampleConfigClasspath = null; - /** - * @see org.owasp.csrfguard.config.overlay.ConfigPropertiesCascadeBase#getMainExampleConfigClasspath() - */ @Override protected String getMainExampleConfigClasspath() { @@ -93,23 +103,20 @@ InputStream inputStream = getClass().getClassLoader().getResourceAsStream(OWASP_CSRF_GUARD_PROPERTIES); if (inputStream != null) { mainExampleConfigClasspath = OWASP_CSRF_GUARD_PROPERTIES; - CsrfGuardUtils.closeQuietly(inputStream); + ConfigPropertiesCascadeCommonUtils.closeQuietly(inputStream); } else { inputStream = getClass().getClassLoader().getResourceAsStream(META_INF_CSRFGUARD_PROPERTIES); if (inputStream != null) { mainExampleConfigClasspath = META_INF_CSRFGUARD_PROPERTIES; - CsrfGuardUtils.closeQuietly(inputStream); + ConfigPropertiesCascadeCommonUtils.closeQuietly(inputStream); } else { //hmm, its not there, but use it anyways mainExampleConfigClasspath = OWASP_CSRF_GUARD_PROPERTIES; } } - } //generally this is Owasp.CsrfGuard.properties - return ConfigPropertiesCascadeUtils.defaultIfBlank(CsrfGuardServletContextListener.getConfigFileName(), - mainExampleConfigClasspath); + return StringUtils.defaultIfBlank(CsrfGuardServletContextListener.getConfigFileName(), mainExampleConfigClasspath); } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigurationOverlayProviderFactory.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigurationOverlayProviderFactory.java (.../ConfigurationOverlayProviderFactory.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ConfigurationOverlayProviderFactory.java (.../ConfigurationOverlayProviderFactory.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,35 +1,61 @@ -/** +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* * @author mchyzer * $Id$ */ package org.owasp.csrfguard.config.overlay; -import java.util.Properties; - import org.owasp.csrfguard.config.ConfigurationProvider; import org.owasp.csrfguard.config.ConfigurationProviderFactory; import org.owasp.csrfguard.config.PropertiesConfigurationProvider; +import java.util.Properties; + /** - * + * TODO document */ -public class ConfigurationOverlayProviderFactory implements - ConfigurationProviderFactory { +public class ConfigurationOverlayProviderFactory implements ConfigurationProviderFactory { /** - * + * TODO document */ - public ConfigurationOverlayProviderFactory() { - } + public ConfigurationOverlayProviderFactory() {} /** * @see org.owasp.csrfguard.config.ConfigurationProviderFactory#retrieveConfiguration(java.util.Properties) */ - public ConfigurationProvider retrieveConfiguration(Properties originalProperties) { - ConfigurationOverlayProvider configurationOverlayProvider = ConfigurationOverlayProvider.retrieveConfig(); - Properties properties = configurationOverlayProvider.properties(); + public ConfigurationProvider retrieveConfiguration(final Properties originalProperties) { + final ConfigurationOverlayProvider configurationOverlayProvider = ConfigurationOverlayProvider.retrieveConfig(); + final Properties properties = configurationOverlayProvider.properties(); return new PropertiesConfigurationProvider(properties); } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ExpirableCache.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ExpirableCache.java (.../ExpirableCache.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ExpirableCache.java (.../ExpirableCache.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,6 +26,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.config.overlay; import java.io.Serializable; @@ -232,7 +233,7 @@ this.checkForEvictions(true); long newTimeToLiveInMillis = this.defaultTimeToLiveInMillis; - //dont use what was inputted if it is out of range + // don't use what was inputted if it is out of range if (proposedTimeToLiveInMillis > 0 && proposedTimeToLiveInMillis <= ExpirableCache.MAX_TIME_TO_LIVE_MILLIS) { newTimeToLiveInMillis = proposedTimeToLiveInMillis; @@ -308,7 +309,7 @@ ExpirableValue value = this.cache.get(key); if (value == null) { - //shouldnt have a key with no value, probably doesnt exist, but just in case + // shouldn't have a key with no value, probably doesn't exist, but just in case this.cache.remove(key); return null; } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ExpirableValue.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ExpirableValue.java (.../ExpirableValue.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/overlay/ExpirableValue.java (.../ExpirableValue.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,6 +26,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.config.overlay; import java.io.Serializable; @@ -57,7 +58,7 @@ */ ExpirableValue(T theContent, long theTimeToLiveInCacheMillis) { super(); - //cant be longer then the max + // can't be longer then the max if (theTimeToLiveInCacheMillis > 0 && theTimeToLiveInCacheMillis <= ExpirableCache.MAX_TIME_TO_LIVE_MILLIS) { this.timeToLiveInCacheMillis = theTimeToLiveInCacheMillis; @@ -66,7 +67,7 @@ } /** - * dont call this on expired content! check first. get the content + * don't call this on expired content! check first. get the content * @return Returns the content. */ T getContent() { Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/ConfigParameters.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/ConfigParameters.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/ConfigParameters.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,81 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.owasp.csrfguard.config.properties; + +import org.apache.commons.lang3.tuple.Pair; + +import java.time.Duration; +import java.time.temporal.ChronoUnit; + +public final class ConfigParameters { + + public static final SimpleBooleanConfigParameter ROTATE = new SimpleBooleanConfigParameter("org.owasp.csrfguard.Rotate", false); + public static final SimpleBooleanConfigParameter TOKEN_PER_PAGE = new SimpleBooleanConfigParameter("org.owasp.csrfguard.TokenPerPage", false); + public static final SimpleBooleanConfigParameter VALIDATE_WHEN_NO_SESSION_EXISTS = new SimpleBooleanConfigParameter("org.owasp.csrfguard.ValidateWhenNoSessionExists", true); + public static final SimpleBooleanConfigParameter TOKEN_PER_PAGE_PRECREATE = new SimpleBooleanConfigParameter("org.owasp.csrfguard.TokenPerPagePrecreate", false); + public static final SimpleBooleanConfigParameter PRINT_ENABLED = new SimpleBooleanConfigParameter("org.owasp.csrfguard.Config.Print", false); + public static final SimpleBooleanConfigParameter CSRFGUARD_ENABLED = new SimpleBooleanConfigParameter("org.owasp.csrfguard.Enabled", true); + public static final SimpleBooleanConfigParameter AJAX_ENABLED = new SimpleBooleanConfigParameter("org.owasp.csrfguard.Ajax", false); + public static final SimpleBooleanConfigParameter CSRFGUARD_PROTECT = new SimpleBooleanConfigParameter("org.owasp.csrfguard.Protect", false); + public static final SimpleBooleanConfigParameter FORCE_SYNCHRONOUS_AJAX = new SimpleBooleanConfigParameter("org.owasp.csrfguard.forceSynchronousAjax", false); + + public static final SimpleIntConfigParameter TOKEN_LENGTH = new SimpleIntConfigParameter("org.owasp.csrfguard.TokenLength", 32); + public static final SimpleDurationParameter PAGE_TOKEN_SYNCHRONIZATION_TOLERANCE = new SimpleDurationParameter("org.owasp.csrfguard.PageTokenSynchronizationTolerance", Duration.of(2, ChronoUnit.SECONDS)); + + public static final Pair TOKEN_NAME = Pair.of("org.owasp.csrfguard.TokenName", "OWASP-CSRFGUARD"); + public static final Pair DOMAIN_ORIGIN = Pair.of("org.owasp.csrfguard.domainOrigin", null); + public static final Pair DEFAULT_PRNG = Pair.of("SUN", "SHA1PRNG"); + public static final Pair PRNG = Pair.of("org.owasp.csrfguard.PRNG", DEFAULT_PRNG.getValue()); + public static final Pair PRNG_PROVIDER = Pair.of("org.owasp.csrfguard.PRNG.Provider", DEFAULT_PRNG.getKey()); + public static final Pair TOKEN_HOLDER = Pair.of("org.owasp.csrfguard.TokenHolder", "org.owasp.csrfguard.token.storage.impl.InMemoryTokenHolder"); + + public static final String LOGICAL_SESSION_EXTRACTOR_NAME = "org.owasp.csrfguard.LogicalSessionExtractor"; + + public static final String NEW_TOKEN_LANDING_PAGE = "org.owasp.csrfguard.NewTokenLandingPage"; + public static final String UNPROTECTED_METHODS = "org.owasp.csrfguard.UnprotectedMethods"; + public static final String PROTECTED_METHODS = "org.owasp.csrfguard.ProtectedMethods"; + + public static final String CONFIG_OVERLAY_HIERARCHY_PROPERTY_NAME = "org.owasp.csrfguard.configOverlay.hierarchy"; + public static final String CONFIG_OVERLAY_UPDATE_CHECK_PROPERTY_NAME = "org.owasp.csrfguard.configOverlay.secondsBetweenUpdateChecks"; + public static final String CONFIG_PROVIDER_FACTORY_PROPERTY_NAME = "org.owasp.csrfguard.configuration.provider.factory"; + + public static final String ACTION_PREFIX = "org.owasp.csrfguard.action."; + public static final String ACTION_ATTRIBUTE_NAME = "AttributeName"; + + public static final String PROTECTED_PAGE_PREFIX = "org.owasp.csrfguard.protected."; + public static final String UNPROTECTED_PAGE_PREFIX = "org.owasp.csrfguard.unprotected."; + + private ConfigParameters() {} + + public static SimpleBooleanConfigParameter getUseNewTokenLandingPage(final String newTokenLandingPage) { + final String newTokenLandingPagePropertyName = "org.owasp.csrfguard.UseNewTokenLandingPage"; + return new SimpleBooleanConfigParameter(newTokenLandingPagePropertyName, newTokenLandingPage != null); + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/HttpMethod.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/HttpMethod.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/HttpMethod.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,48 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.config.properties; + +import java.util.Arrays; +import java.util.Collection; + +public enum HttpMethod { + + GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH; + + public static void validate(final Collection httpMethods) { + httpMethods.forEach(HttpMethod::validate); + } + + public static void validate(final String input) { + Arrays.stream(values()) + .filter(value -> input.equalsIgnoreCase(value.toString())) + .findAny() + .orElseThrow(() -> new IllegalArgumentException(String.format("The provided input '%s' is not a valid HTTP method!", input))); + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/PropertyUtils.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/PropertyUtils.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/PropertyUtils.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,122 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.owasp.csrfguard.config.properties; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.Pair; +import org.owasp.csrfguard.CsrfGuardServletContextListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Duration; +import java.util.Objects; +import java.util.Properties; +import java.util.function.Function; + +public final class PropertyUtils { + + private static final Logger LOGGER = LoggerFactory.getLogger(PropertyUtils.class); + + private PropertyUtils() {} + + /** + * property string and substitutions + * + * @param properties The properties from which to fetch a value + * @param propertyName The name of the desired property + * @return the value, with common substitutions performed + * @see #commonSubstitutions(String) + */ + public static String getProperty(final Properties properties, final String propertyName) { + return getProperty(properties, propertyName, null); + } + + public static String getProperty(final Properties properties, final Pair propertyWithDefaultValue) { + return getProperty(properties, propertyWithDefaultValue.getKey(), propertyWithDefaultValue.getValue()); + } + + public static int getProperty(final Properties properties, final SimpleIntConfigParameter configParameter) { + return getProperty(properties, configParameter, Integer::parseInt); + } + + public static boolean getProperty(final Properties properties, final SimpleBooleanConfigParameter configParameter) { + return getProperty(properties, configParameter, Boolean::parseBoolean); + } + + public static T getProperty(final Properties properties, final SimpleConfigParameter configParameter, final Function function) { + return getProperty(properties, configParameter.getName(), configParameter.getDefaultValue(), function); + } + + public static Duration getProperty(final Properties properties, final SimpleDurationParameter configParameter) { + return getProperty(properties, configParameter.getName(), configParameter.getDefaultValue(), millis -> Duration.ofMillis(Long.parseLong(millis))); + } + + public static T getProperty(final Properties properties, final String propertyName, final T defaultValue, final Function function) { + final String property = getProperty(properties, propertyName); + return StringUtils.isBlank(property) ? defaultValue : function.apply(property); + } + + /** + * property string and substitutions + * + * @param properties The properties from which to fetch a value + * @param propertyName The name of the desired property + * @param defaultValue The value to use when the propertyName does not exist + * @return the value, with common substitutions performed + * @see #commonSubstitutions(String) + */ + public static String getProperty(final Properties properties, final String propertyName, final String defaultValue) { + final String value; + if (Objects.isNull(defaultValue)) { + value = properties.getProperty(propertyName); + } else { + if (!properties.containsKey(propertyName)) { + LOGGER.info("The '{}' property was not defined, using '{}' as default value. %n", propertyName, defaultValue); + } + value = properties.getProperty(propertyName, defaultValue); + } + + return commonSubstitutions(value); + } + + /** + * Replaces percent-bounded expressions such as "%servletContext%." + * common substitutions in config values + * + * @param input A string with expressions that should be replaced + * @return new string with "common" expressions replaced by configuration values + */ + public static String commonSubstitutions(final String input) { + if (!StringUtils.contains(input, "%")) { + return input; + } + return input.replace("%servletContext%", StringUtils.defaultString(CsrfGuardServletContextListener.getServletContext())); + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/SimpleBooleanConfigParameter.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/SimpleBooleanConfigParameter.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/SimpleBooleanConfigParameter.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,51 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.owasp.csrfguard.config.properties; + +public class SimpleBooleanConfigParameter implements SimpleConfigParameter { + + private final String propertyName; + private final boolean propertyValue; + + public SimpleBooleanConfigParameter(final String propertyName, final boolean propertyValue) { + this.propertyName = propertyName; + this.propertyValue = propertyValue; + } + + @Override + public String getName() { + return this.propertyName; + } + + @Override + public Boolean getDefaultValue() { + return this.propertyValue; + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/SimpleConfigParameter.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/SimpleConfigParameter.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/SimpleConfigParameter.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,46 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.config.properties; + +/** + * Interface describing a simple configuration parameter + * @param The type of the configuration parameter + */ +public interface SimpleConfigParameter { + + /** + * @return the name of the configuration parameter + */ + String getName(); + + /** + * @return the default value associated to the configuration parameter + */ + T getDefaultValue(); +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/SimpleDurationParameter.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/SimpleDurationParameter.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/SimpleDurationParameter.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,52 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.config.properties; + +import java.time.Duration; + +public class SimpleDurationParameter implements SimpleConfigParameter { + + private final String name; + private final Duration defaultDuration; + + public SimpleDurationParameter(final String name, final Duration defaultDuration) { + this.name = name; + this.defaultDuration = defaultDuration; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public Duration getDefaultValue() { + return this.defaultDuration; + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/SimpleIntConfigParameter.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/SimpleIntConfigParameter.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/SimpleIntConfigParameter.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,51 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.owasp.csrfguard.config.properties; + +public class SimpleIntConfigParameter implements SimpleConfigParameter { + + private final String propertyName; + private final int propertyValue; + + public SimpleIntConfigParameter(final String propertyName, final int propertyValue) { + this.propertyName = propertyName; + this.propertyValue = propertyValue; + } + + @Override + public String getName() { + return this.propertyName; + } + + @Override + public Integer getDefaultValue() { + return this.propertyValue; + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/javascript/BooleanJsConfigParameter.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/javascript/BooleanJsConfigParameter.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/javascript/BooleanJsConfigParameter.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,54 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.owasp.csrfguard.config.properties.javascript; + +import org.owasp.csrfguard.config.properties.PropertyUtils; + +import javax.servlet.ServletConfig; +import java.util.Properties; + +public class BooleanJsConfigParameter extends JsConfigParameter { + + private final String propertyName; + private final String propertyKey; + private final boolean defaultValue; + + public BooleanJsConfigParameter(final String propertyName, final String propertyKey, final boolean defaultValue) { + this.propertyName = propertyName; + this.propertyKey = propertyKey; + this.defaultValue = defaultValue; + } + + @Override + public Boolean getProperty(final ServletConfig servletConfig, final Properties propertyCache) { + final String configParamValue = PropertyUtils.getProperty(propertyCache, this.propertyKey); + return getInitParameter(servletConfig, this.propertyName, configParamValue, this.defaultValue); + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/javascript/JavaScriptConfigParameters.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/javascript/JavaScriptConfigParameters.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/javascript/JavaScriptConfigParameters.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,57 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.owasp.csrfguard.config.properties.javascript; + +import org.apache.commons.lang3.StringUtils; + +public final class JavaScriptConfigParameters { + + private JavaScriptConfigParameters() {} + + public static final String DEFAULT_REFERER_PATTERN = ".*"; + + // TODO document the names of the configurations that can be used for overriding the values from the web.xml in the properties file + + public static final StringJsConfigParameter CACHE_CONTROL = new StringJsConfigParameter("cache-control", "org.owasp.csrfguard.JavascriptServlet.cacheControl", "private, max-age=28800"); + public static final StringJsConfigParameter REFERER_PATTERN = new StringJsConfigParameter("referer-pattern", "org.owasp.csrfguard.JavascriptServlet.refererPattern", DEFAULT_REFERER_PATTERN); + public static final StringJsConfigParameter UNPROTECTED_EXTENSIONS = new StringJsConfigParameter("unprotected-extensions", "org.owasp.csrfguard.JavascriptServlet.UnprotectedExtensions", StringUtils.EMPTY); + public static final StringJsConfigParameter SOURCE_FILE = new StringJsConfigParameter("source-file", "org.owasp.csrfguard.JavascriptServlet.sourceFile", null); + public static final StringJsConfigParameter X_REQUESTED_WITH = new StringJsConfigParameter("x-requested-with", "org.owasp.csrfguard.JavascriptServlet.xRequestedWith", "OWASP CSRFGuard Project"); + public static final StringJsConfigParameter DYNAMIC_NODE_CREATION_EVENT_NAME = new StringJsConfigParameter("dynamic-node-creation-event", "org.owasp.csrfguard.JavascriptServlet.dynamicNodeCreationEventName", null); + + public static final BooleanJsConfigParameter DOMAIN_STRICT = new BooleanJsConfigParameter("domain-strict", "org.owasp.csrfguard.JavascriptServlet.domainStrict", true); + public static final BooleanJsConfigParameter INJECT_INTO_ATTRIBUTES = new BooleanJsConfigParameter("inject-into-attributes", "org.owasp.csrfguard.JavascriptServlet.injectIntoAttributes", true); + public static final BooleanJsConfigParameter INJECT_GET_FORMS = new BooleanJsConfigParameter("inject-get-forms", "org.owasp.csrfguard.JavascriptServlet.injectGetForms", true); + public static final BooleanJsConfigParameter INJECT_FORM_ATTRIBUTES = new BooleanJsConfigParameter("inject-form-attributes", "org.owasp.csrfguard.JavascriptServlet.injectFormAttributes", true); + public static final BooleanJsConfigParameter INJECT_INTO_FORMS = new BooleanJsConfigParameter("inject-into-forms", "org.owasp.csrfguard.JavascriptServlet.injectIntoForms", true); + public static final BooleanJsConfigParameter INJECT_INTO_DYNAMICALLY_CREATED_NODES = new BooleanJsConfigParameter("inject-into-dynamic", "org.owasp.csrfguard.JavascriptServlet.injectIntoDynamicNodes", false); + public static final BooleanJsConfigParameter REFERER_MATCH_PROTOCOL = new BooleanJsConfigParameter("referer-match-protocol", "org.owasp.csrfguard.JavascriptServlet.refererMatchProtocol", true); + public static final BooleanJsConfigParameter REFERER_MATCH_DOMAIN = new BooleanJsConfigParameter("referer-match-domain", "org.owasp.csrfguard.JavascriptServlet.refererMatchDomain", true); +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/javascript/JsConfigParameter.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/javascript/JsConfigParameter.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/javascript/JsConfigParameter.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,64 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.config.properties.javascript; + +import org.apache.commons.lang3.StringUtils; + +import javax.servlet.ServletConfig; +import java.util.Properties; +import java.util.function.Function; + +public abstract class JsConfigParameter { + + public abstract T getProperty(final ServletConfig servletConfig, final Properties propertyCache); + + public static String getInitParameter(final ServletConfig servletConfig, final String name, final String configFileDefaultParamValue, final String defaultValue) { + return getInitParameter(servletConfig, name, configFileDefaultParamValue, defaultValue, Function.identity()); + } + + public static boolean getInitParameter(final ServletConfig servletConfig, final String name, final String configFileDefaultParamValue, final boolean defaultValue) { + return getInitParameter(servletConfig, name, configFileDefaultParamValue, defaultValue, Boolean::parseBoolean); + } + + public static T getInitParameter(final ServletConfig servletConfig, final String name, final String configFileDefaultParamValue, final T defaultValue, final Function function) { + final T result; + + final String initParameter = servletConfig.getInitParameter(name); + + if (StringUtils.isNotBlank(initParameter)) { + result = function.apply(initParameter); + } else if (StringUtils.isNotBlank(configFileDefaultParamValue)) { + result = function.apply(configFileDefaultParamValue); + } else { + result = defaultValue; + } + + return result; + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/javascript/StringJsConfigParameter.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/javascript/StringJsConfigParameter.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/config/properties/javascript/StringJsConfigParameter.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,54 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.owasp.csrfguard.config.properties.javascript; + +import org.owasp.csrfguard.config.properties.PropertyUtils; + +import javax.servlet.ServletConfig; +import java.util.Properties; + +public class StringJsConfigParameter extends JsConfigParameter { + + private final String propertyName; + private final String propertyKey; + private final String defaultValue; + + public StringJsConfigParameter(final String propertyName, final String propertyKey, final String defaultValue) { + this.propertyName = propertyName; + this.propertyKey = propertyKey; + this.defaultValue = defaultValue; + } + + @Override + public String getProperty(final ServletConfig servletConfig, final Properties propertyCache) { + final String configParamValue = PropertyUtils.getProperty(propertyCache, this.propertyKey); + return getInitParameter(servletConfig, this.propertyName, configParamValue, this.defaultValue); + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/exception/CSRFGuardTokenException.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/exception/CSRFGuardTokenException.java (.../CSRFGuardTokenException.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/exception/CSRFGuardTokenException.java (.../CSRFGuardTokenException.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,6 +26,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.exception; /** @@ -36,15 +37,15 @@ */ public class CSRFGuardTokenException extends RuntimeException { - public CSRFGuardTokenException(String message) { + public CSRFGuardTokenException(final String message) { super(message); } - public CSRFGuardTokenException(String message, Throwable cause) { + public CSRFGuardTokenException(final String message, final Throwable cause) { super(message, cause); } - public CSRFGuardTokenException(Throwable cause) { + public CSRFGuardTokenException(final Throwable cause) { super(cause); } } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/http/InterceptRedirectResponse.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/http/InterceptRedirectResponse.java (.../InterceptRedirectResponse.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/http/InterceptRedirectResponse.java (.../InterceptRedirectResponse.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,72 +1,109 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + package org.owasp.csrfguard.http; -import java.io.IOException; +import org.owasp.csrfguard.CsrfGuard; +import org.owasp.csrfguard.CsrfValidator; +import org.owasp.csrfguard.ProtectionResult; +import org.owasp.csrfguard.session.LogicalSession; +import org.owasp.csrfguard.token.service.TokenService; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponseWrapper; +import java.io.IOException; +import java.util.Objects; -import org.owasp.csrfguard.CsrfGuard; - public class InterceptRedirectResponse extends HttpServletResponseWrapper { - private HttpServletResponse response = null; + private final HttpServletResponse response; - private CsrfGuard csrfGuard; + private final CsrfGuard csrfGuard; - private HttpServletRequest request; + private final HttpServletRequest request; - public InterceptRedirectResponse(HttpServletResponse response, HttpServletRequest request, CsrfGuard csrfGuard) { - super(response); - this.response = response; - this.request = request; - this.csrfGuard = csrfGuard; - } + public InterceptRedirectResponse(final HttpServletResponse response, final HttpServletRequest request, final CsrfGuard csrfGuard) { + super(response); + this.response = response; + this.request = request; + this.csrfGuard = csrfGuard; + } - @Override - public void sendRedirect(String location) throws IOException { - // Remove CR and LF characters to prevent CRLF injection - String sanitizedLocation = location.replaceAll("(\\r|\\n|%0D|%0A|%0a|%0d)", ""); - - /** ensure token included in redirects **/ - if (!sanitizedLocation.contains("://") && csrfGuard.isProtectedPageAndMethod(sanitizedLocation, "GET")) { - /** update tokens **/ - csrfGuard.updateTokens(request); - - // Separate URL fragment from path, e.g. /myPath#myFragment becomes - //[0]: /myPath [1]: myFragment - String[] splitOnFragement = location.split("#", 2); - location = splitOnFragement[0]; + @Override + public void sendRedirect(final String location) throws IOException { + // Remove CR and LF characters to prevent CRLF injection + final String sanitizedLocation = location.replaceAll("(\\r|\\n|%0D|%0A|%0a|%0d)", ""); - StringBuilder sb = new StringBuilder(); + /* ensure token included in redirects */ + final ProtectionResult protectionResult = new CsrfValidator().isProtectedPageAndMethod(sanitizedLocation, "GET"); + if (!sanitizedLocation.contains("://") && protectionResult.isProtected()) { + // Separate URL fragments from path, e.g. /myPath#myFragment becomes [0]: /myPath [1]: myFragment + final String[] splitOnFragment = location.split("#", 2); - if (!sanitizedLocation.startsWith("/")) { - sb.append(request.getContextPath() + "/" + sanitizedLocation); - } else { - sb.append(sanitizedLocation); - } - - if (sanitizedLocation.contains("?")) { - sb.append('&'); - } else { - sb.append('?'); - } + final StringBuilder stringBuilder = new StringBuilder(); - // remove any query parameters from the sanitizedLocation - String locationUri = sanitizedLocation.split("\\?", 2)[0]; + if (sanitizedLocation.startsWith("/")) { + stringBuilder.append(sanitizedLocation); + } else { + stringBuilder.append(this.request.getContextPath()).append('/').append(sanitizedLocation); + } - sb.append(csrfGuard.getTokenName()); - sb.append('='); - sb.append(csrfGuard.getTokenValue(request, locationUri)); - - // Add back fragment, if one exists - if(splitOnFragement.length > 1) { - sb.append('#').append(splitOnFragement[1]); - } + if (sanitizedLocation.contains("?")) { + stringBuilder.append('&'); + } else { + stringBuilder.append('?'); + } - response.sendRedirect(sb.toString()); - } else { - response.sendRedirect(sanitizedLocation); - } - } + // remove any query parameters from the sanitizedLocation + final String locationUri = sanitizedLocation.split("\\?", 2)[0]; + + stringBuilder.append(this.csrfGuard.getTokenName()) + .append('=') + .append(computeTokenValue(locationUri)); + + // Add back fragment, if one exists + if (splitOnFragment.length > 1) { + stringBuilder.append('#').append(splitOnFragment[1]); + } + + this.response.sendRedirect(stringBuilder.toString()); + } else { + this.response.sendRedirect(sanitizedLocation); + } + } + + private String computeTokenValue(final String locationUri) { + final TokenService tokenService = CsrfGuard.getInstance().getTokenService(); + + final LogicalSession logicalSession = this.csrfGuard.getLogicalSessionExtractor().extract(this.request); + + return Objects.nonNull(logicalSession) ? tokenService.generateTokensIfAbsent(logicalSession.getKey(), "GET", locationUri) : null; + } } Fisheye: Tag d25fe80a3034172a51168d74cd1476895df0e8cd refers to a dead (removed) revision in file `3rdParty_sources/csrfguard/org/owasp/csrfguard/log/ConsoleLogger.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag d25fe80a3034172a51168d74cd1476895df0e8cd refers to a dead (removed) revision in file `3rdParty_sources/csrfguard/org/owasp/csrfguard/log/ILogger.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag d25fe80a3034172a51168d74cd1476895df0e8cd refers to a dead (removed) revision in file `3rdParty_sources/csrfguard/org/owasp/csrfguard/log/JavaLogger.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag d25fe80a3034172a51168d74cd1476895df0e8cd refers to a dead (removed) revision in file `3rdParty_sources/csrfguard/org/owasp/csrfguard/log/LogLevel.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/servlet/JavaScriptServlet.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/servlet/JavaScriptServlet.java (.../JavaScriptServlet.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/servlet/JavaScriptServlet.java (.../JavaScriptServlet.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,235 +26,257 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.servlet; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; import org.owasp.csrfguard.CsrfGuard; import org.owasp.csrfguard.CsrfGuardServletContextListener; -import org.owasp.csrfguard.log.LogLevel; +import org.owasp.csrfguard.CsrfValidator; +import org.owasp.csrfguard.config.properties.javascript.JavaScriptConfigParameters; +import org.owasp.csrfguard.session.LogicalSession; +import org.owasp.csrfguard.token.storage.LogicalSessionExtractor; +import org.owasp.csrfguard.token.transferobject.TokenTO; import org.owasp.csrfguard.util.CsrfGuardUtils; -import org.owasp.csrfguard.util.Strings; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; +import java.nio.charset.Charset; import java.util.HashSet; -import java.util.Iterator; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.regex.Pattern; public final class JavaScriptServlet extends HttpServlet { - private static final long serialVersionUID = -1459584282530150483L; - - private static final String TOKEN_NAME_IDENTIFIER = "%TOKEN_NAME%"; - - private static final String TOKEN_VALUE_IDENTIFIER = "%TOKEN_VALUE%"; - - private static final String DOMAIN_ORIGIN_IDENTIFIER = "%DOMAIN_ORIGIN%"; - - private static final String DOMAIN_STRICT_IDENTIFIER = "%DOMAIN_STRICT%"; - - private static final String INJECT_INTO_XHR_IDENTIFIER = "%INJECT_XHR%"; - - private static final String INJECT_INTO_FORMS_IDENTIFIER = "%INJECT_FORMS%"; + private static final long serialVersionUID = -1459584282530150483L; - private static final String INJECT_GET_FORMS_IDENTIFIER = "%INJECT_GET_FORMS%"; - - private static final String INJECT_FORM_ATTRIBUTES_IDENTIFIER = "%INJECT_FORM_ATTRIBUTES%"; - - private static final String INJECT_INTO_ATTRIBUTES_IDENTIFIER = "%INJECT_ATTRIBUTES%"; - - private static final String CONTEXT_PATH_IDENTIFIER = "%CONTEXT_PATH%"; - - private static final String SERVLET_PATH_IDENTIFIER = "%SERVLET_PATH%"; - - private static final String X_REQUESTED_WITH_IDENTIFIER = "%X_REQUESTED_WITH%"; - - private static final String TOKENS_PER_PAGE_IDENTIFIER = "%TOKENS_PER_PAGE%"; - - private static final String UNPROTECTED_EXTENSIONS_IDENTIFIER = "%UNPROTECTED_EXTENSIONS%"; - - private static ServletConfig servletConfig = null; + private static final String TOKEN_NAME_IDENTIFIER = "%TOKEN_NAME%"; - public static ServletConfig getStaticServletConfig() { - return servletConfig; - } - - @Override - public void init(ServletConfig theServletConfig) { - servletConfig = theServletConfig; - //print again since it might change based on servlet config of javascript servlet - CsrfGuardServletContextListener.printConfigIfConfigured(servletConfig.getServletContext(), - "Printing properties after Javascript servlet, note, the javascript properties have now been initialized: "); - } + private static final String TOKEN_VALUE_IDENTIFIER = "%TOKEN_VALUE%"; - @Override - public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { - String refererHeader = request.getHeader("referer"); - boolean hasError = false; - Pattern javascriptRefererPattern = CsrfGuard.getInstance().getJavascriptRefererPattern(); - if(refererHeader != null && !javascriptRefererPattern.matcher(refererHeader).matches()) { - CsrfGuard.getInstance().getLogger().log(LogLevel.Error, "Referer domain " + refererHeader + " does not match regex: " + javascriptRefererPattern.pattern()); - response.sendError(404); - hasError = true; - } - - if (refererHeader != null && CsrfGuard.getInstance().isJavascriptRefererMatchDomain()) { - boolean isJavascriptRefererMatchProtocol = CsrfGuard.getInstance().isJavascriptRefererMatchProtocol(); - //this is something like http://something.com/path or https://something.com/path - String url = request.getRequestURL().toString(); - String requestProtocolAndDomain = CsrfGuardUtils.httpProtocolAndDomain(url, isJavascriptRefererMatchProtocol); - String refererProtocolAndDomain = CsrfGuardUtils.httpProtocolAndDomain(refererHeader, isJavascriptRefererMatchProtocol); - if (!refererProtocolAndDomain.equals(requestProtocolAndDomain)) { - CsrfGuard.getInstance().getLogger().log(LogLevel.Error, "Referer domain " + refererHeader + " does not match request domain: " + url); - hasError = true; - response.sendError(404); - } - - } - if (!hasError) { - - //save this path so javascript is whitelisted - String javascriptPath = request.getContextPath() + request.getServletPath(); - - //dont know why there would be more than one... hmmm - if (javascriptUris.size() < 100) { - javascriptUris.add(javascriptPath); - } - - writeJavaScript(request, response); - } - } + private static final String DOMAIN_ORIGIN_IDENTIFIER = "%DOMAIN_ORIGIN%"; - /** - * whitelist the javascript servlet from csrf errors - * @return the javascriptUris - */ - public static Set getJavascriptUris() { - return javascriptUris; - } + private static final String CONTEXT_PATH_IDENTIFIER = "%CONTEXT_PATH%"; - /** whitelist the javascript servlet from csrf errors */ - private static Set javascriptUris = new HashSet(); - + private static final String SERVLET_PATH_IDENTIFIER = "%SERVLET_PATH%"; - @Override - public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { - CsrfGuard csrfGuard = CsrfGuard.getInstance(); - String isFetchCsrfToken = request.getHeader("FETCH-CSRF-TOKEN"); - - if (csrfGuard != null && isFetchCsrfToken != null){ - fetchCsrfToken(request, response); - } else { - if (csrfGuard != null && csrfGuard.isTokenPerPageEnabled()) { - writePageTokens(request, response); - } else { - response.sendError(404); - } - } - } + private static final String X_REQUESTED_WITH_IDENTIFIER = "%X_REQUESTED_WITH%"; - private void fetchCsrfToken(HttpServletRequest request, HttpServletResponse response) throws IOException { - HttpSession session = request.getSession(true); - @SuppressWarnings("unchecked") - CsrfGuard csrfGuard = CsrfGuard.getInstance(); - String token_name = csrfGuard.getTokenName(); - String token_value = (String) session.getAttribute(csrfGuard.getSessionKey()); - String token_pair = token_name + ":" + token_value; + private static final String UNPROTECTED_EXTENSIONS_IDENTIFIER = "%UNPROTECTED_EXTENSIONS%"; - /** setup headers **/ - response.setContentType("text/plain"); + private static final String DYNAMIC_NODE_CREATION_EVENT_NAME_IDENTIFIER = "%DYNAMIC_NODE_CREATION_EVENT_NAME%"; - /** write dynamic javascript **/ - response.getWriter().write(token_pair); - } + /** + * Non-string configuration placeholder names that has to be replaced together with the single quotes + * The single quotes around the attribute names are needed so the template code would be parsable by linters and automated code minifiers. + */ + private static final String DOMAIN_STRICT_IDENTIFIER = "'%DOMAIN_STRICT%'"; + private static final String INJECT_INTO_XHR_IDENTIFIER = "'%INJECT_XHR%'"; - private void writePageTokens(HttpServletRequest request, HttpServletResponse response) throws IOException { - HttpSession session = request.getSession(true); - @SuppressWarnings("unchecked") - Map pageTokens = (Map) session.getAttribute(CsrfGuard.PAGE_TOKENS_KEY); - String pageTokensString = (pageTokens != null ? parsePageTokens(pageTokens) : Strings.EMPTY); + private static final String INJECT_INTO_FORMS_IDENTIFIER = "'%INJECT_FORMS%'"; - /** setup headers **/ - response.setContentType("text/plain"); - response.setContentLength(pageTokensString.length()); + private static final String INJECT_GET_FORMS_IDENTIFIER = "'%INJECT_GET_FORMS%'"; - /** write dynamic javascript **/ - response.getWriter().write(pageTokensString); - } + private static final String INJECT_FORM_ATTRIBUTES_IDENTIFIER = "'%INJECT_FORM_ATTRIBUTES%'"; - private void writeJavaScript(HttpServletRequest request, HttpServletResponse response) throws IOException { - HttpSession session = request.getSession(true); - CsrfGuard csrfGuard = CsrfGuard.getInstance(); + private static final String INJECT_INTO_ATTRIBUTES_IDENTIFIER = "'%INJECT_ATTRIBUTES%'"; - /** cannot cache if rotate or token-per-page is enabled **/ - if (csrfGuard.isRotateEnabled() || csrfGuard.isTokenPerPageEnabled()) { - response.setHeader("Cache-Control", "no-cache, no-store"); - response.setHeader("Pragma", "no-cache"); - response.setHeader("Expires", "0"); - } else { - response.setHeader("Cache-Control", CsrfGuard.getInstance().getJavascriptCacheControl()); - } + private static final String INJECT_INTO_DYNAMIC_NODES_IDENTIFIER = "'%INJECT_DYNAMIC_NODES%'"; - response.setContentType("text/javascript"); + private static final String TOKENS_PER_PAGE_IDENTIFIER = "'%TOKENS_PER_PAGE%'"; - /** build dynamic javascript **/ - String code = CsrfGuard.getInstance().getJavascriptTemplateCode(); + private static final String ASYNC_XHR = "'%ASYNC_XHR%'"; - code = code.replace(TOKEN_NAME_IDENTIFIER, CsrfGuardUtils.defaultString(csrfGuard.getTokenName())); - code = code.replace(TOKEN_VALUE_IDENTIFIER, CsrfGuardUtils.defaultString((String) session.getAttribute(csrfGuard.getSessionKey()))); - code = code.replace(INJECT_INTO_FORMS_IDENTIFIER, Boolean.toString(csrfGuard.isJavascriptInjectIntoForms())); - code = code.replace(INJECT_GET_FORMS_IDENTIFIER, Boolean.toString(csrfGuard.isJavascriptInjectGetForms())); - code = code.replace(INJECT_FORM_ATTRIBUTES_IDENTIFIER, Boolean.toString(csrfGuard.isJavascriptInjectFormAttributes())); - code = code.replace(INJECT_INTO_ATTRIBUTES_IDENTIFIER, Boolean.toString(csrfGuard.isJavascriptInjectIntoAttributes())); - code = code.replace(INJECT_INTO_XHR_IDENTIFIER, String.valueOf(csrfGuard.isAjaxEnabled())); - code = code.replace(TOKENS_PER_PAGE_IDENTIFIER, String.valueOf(csrfGuard.isTokenPerPageEnabled())); - code = code.replace(UNPROTECTED_EXTENSIONS_IDENTIFIER, String.valueOf(csrfGuard.getJavascriptUnprotectedExtensions())); - code = code.replace(DOMAIN_ORIGIN_IDENTIFIER, csrfGuard.getDomainOrigin() == null ? CsrfGuardUtils.defaultString(parseDomain(request.getRequestURL())) : csrfGuard.getDomainOrigin()); - code = code.replace(DOMAIN_STRICT_IDENTIFIER, Boolean.toString(csrfGuard.isJavascriptDomainStrict())); - code = code.replace(CONTEXT_PATH_IDENTIFIER, CsrfGuardUtils.defaultString(request.getContextPath())); - code = code.replace(SERVLET_PATH_IDENTIFIER, CsrfGuardUtils.defaultString(request.getContextPath() + request.getServletPath())); - code = code.replace(X_REQUESTED_WITH_IDENTIFIER, CsrfGuardUtils.defaultString(csrfGuard.getJavascriptXrequestedWith())); + /* MIME Type constants */ + private static final String JSON_MIME_TYPE = "application/json"; + private static final String JAVASCRIPT_MIME_TYPE = "text/javascript; charset=utf-8"; - /** write dynamic javascript **/ - response.getWriter().write(code); - } + /** + * whitelist the javascript servlet from csrf errors + */ + private static final Set javascriptUris = new HashSet<>(); - private String parsePageTokens(Map pageTokens) { - StringBuilder sb = new StringBuilder(); - Iterator keys = pageTokens.keySet().iterator(); + private static final Logger LOGGER = LoggerFactory.getLogger(JavaScriptServlet.class); - while (keys.hasNext()) { - String key = keys.next(); - String value = pageTokens.get(key); + private static ServletConfig servletConfig = null; - sb.append(key); - sb.append(':'); - sb.append(value); + public static ServletConfig getStaticServletConfig() { + return servletConfig; + } - if (keys.hasNext()) { - sb.append(','); - } - } + /** + * whitelist the javascript servlet from csrf errors + * + * @return the javascriptUris + */ + public static Set getJavascriptUris() { + return javascriptUris; + } - return sb.toString(); - } - + @Override + public void init(final ServletConfig theServletConfig) { + servletConfig = theServletConfig; - private String parseDomain(StringBuffer url) { - try { - return new URL(url.toString()).getHost(); - } catch (MalformedURLException e) { - //Should not occur. javax.servlet.http.HttpServletRequest.getRequestURL should only returns valid URLs. - return "INVALID_URL: " + url.toString(); - } - } - + final CsrfGuard csrfGuard = CsrfGuard.getInstance(); + csrfGuard.initializeJavaScriptConfiguration(); + + // print again since it might change based on servlet config of javascript servlet + CsrfGuardServletContextListener.printConfigIfConfigured(servletConfig.getServletContext(), + "Printing properties after JavaScript servlet, note, the javascript properties have now been initialized: "); + } + + @Override + public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException { + final CsrfGuard csrfGuard = CsrfGuard.getInstance(); + + if (csrfGuard.isEnabled()) { + writeJavaScript(csrfGuard, request, response); + } else { + response.setContentType(JAVASCRIPT_MIME_TYPE); + final String javaScriptCode = "console.log('CSRFGuard is disabled');"; + response.getWriter().write(javaScriptCode); + } + } + + @Override + public void doPost(final HttpServletRequest request, final HttpServletResponse response) throws IOException { + final CsrfGuard csrfGuard = CsrfGuard.getInstance(); + + if (new CsrfValidator().isValid(request, response)) { + if (csrfGuard.isTokenPerPageEnabled()) { + // TODO pass the logical session downstream, see whether the null check can be done from here + final LogicalSession logicalSession = csrfGuard.getLogicalSessionExtractor().extract(request); + if (Objects.isNull(logicalSession)) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Could not create a logical session from the current request."); + } else { + final Map pageTokens = csrfGuard.getTokenService().getPageTokens(logicalSession.getKey()); + final TokenTO tokenTO = new TokenTO(pageTokens); + writeTokens(response, tokenTO); + } + } else { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, "This endpoint should not be invoked if the Token-Per-Page functionality is disabled!"); + } + } else { + response.sendError(HttpServletResponse.SC_FORBIDDEN, "Master token missing from the request."); + } + } + + private static void writeTokens(final HttpServletResponse response, final TokenTO tokenTO) throws IOException { + final String jsonTokenTO = tokenTO.toString(); + + response.setContentType(JSON_MIME_TYPE); + response.setContentLength(jsonTokenTO.length()); + response.setCharacterEncoding(Charset.defaultCharset().displayName()); + + response.getWriter().write(jsonTokenTO); + } + + private static void writeJavaScript(final HttpServletRequest request, final HttpServletResponse response) throws IOException { + final CsrfGuard csrfGuard = CsrfGuard.getInstance(); + + /* cannot cache if rotate or token-per-page is enabled */ + if (csrfGuard.isRotateEnabled() || csrfGuard.isTokenPerPageEnabled()) { + response.setHeader("Cache-Control", "no-cache, no-store"); + response.setHeader("Pragma", "no-cache"); + response.setHeader("Expires", "0"); + } else { + response.setHeader("Cache-Control", csrfGuard.getJavascriptCacheControl()); + } + + response.setContentType(JAVASCRIPT_MIME_TYPE); + + String code = csrfGuard.getJavascriptTemplateCode(); + + code = code.replace(TOKEN_NAME_IDENTIFIER, StringUtils.defaultString(csrfGuard.getTokenName())) + .replace(TOKEN_VALUE_IDENTIFIER, StringUtils.defaultString(getMasterToken(request, csrfGuard))) + .replace(UNPROTECTED_EXTENSIONS_IDENTIFIER, String.valueOf(csrfGuard.getJavascriptUnprotectedExtensions())) + .replace(CONTEXT_PATH_IDENTIFIER, StringUtils.defaultString(request.getContextPath())) + .replace(SERVLET_PATH_IDENTIFIER, StringUtils.defaultString(request.getContextPath() + request.getServletPath())) + .replace(X_REQUESTED_WITH_IDENTIFIER, StringUtils.defaultString(csrfGuard.getJavascriptXrequestedWith())) + .replace(DYNAMIC_NODE_CREATION_EVENT_NAME_IDENTIFIER, StringUtils.defaultString(csrfGuard.getJavascriptDynamicNodeCreationEventName())) + .replace(DOMAIN_ORIGIN_IDENTIFIER, ObjectUtils.defaultIfNull(csrfGuard.getDomainOrigin(), StringUtils.defaultString(parseDomain(request.getRequestURL())))) + .replace(INJECT_INTO_FORMS_IDENTIFIER, Boolean.toString(csrfGuard.isJavascriptInjectIntoForms())) + .replace(INJECT_GET_FORMS_IDENTIFIER, Boolean.toString(csrfGuard.isJavascriptInjectGetForms())) + .replace(INJECT_FORM_ATTRIBUTES_IDENTIFIER, Boolean.toString(csrfGuard.isJavascriptInjectFormAttributes())) + .replace(INJECT_INTO_ATTRIBUTES_IDENTIFIER, Boolean.toString(csrfGuard.isJavascriptInjectIntoAttributes())) + .replace(INJECT_INTO_DYNAMIC_NODES_IDENTIFIER, Boolean.toString(csrfGuard.isJavascriptInjectIntoDynamicallyCreatedNodes())) + .replace(INJECT_INTO_XHR_IDENTIFIER, Boolean.toString(csrfGuard.isAjaxEnabled())) + .replace(TOKENS_PER_PAGE_IDENTIFIER, Boolean.toString(csrfGuard.isTokenPerPageEnabled())) + .replace(DOMAIN_STRICT_IDENTIFIER, Boolean.toString(csrfGuard.isJavascriptDomainStrict())) + .replace(ASYNC_XHR, Boolean.toString(!csrfGuard.isForceSynchronousAjax())); + + response.getWriter().write(code); + } + + private static String getMasterToken(final HttpServletRequest request, final CsrfGuard csrfGuard) { + final LogicalSessionExtractor sessionKeyExtractor = csrfGuard.getLogicalSessionExtractor(); + final LogicalSession logicalSession = sessionKeyExtractor.extractOrCreate(request); + + return csrfGuard.getTokenService().getMasterToken(logicalSession.getKey()); + } + + private static String parseDomain(final StringBuffer url) { + try { + return new URL(url.toString()).getHost(); + } catch (final MalformedURLException e) { + // Should not occur. javax.servlet.http.HttpServletRequest.getRequestURL should only return valid URLs. + return "INVALID_URL: " + url; + } + } + + private void writeJavaScript(final CsrfGuard csrfGuard, final HttpServletRequest request, final HttpServletResponse response) throws IOException { + final String refererHeader = request.getHeader("referer"); + + final Pattern javascriptRefererPattern = csrfGuard.getJavascriptRefererPattern(); + final String javaScriptReferer = javascriptRefererPattern.pattern(); + + if (refererHeader != null) { + if (!javascriptRefererPattern.matcher(refererHeader).matches()) { + LOGGER.error("Referer domain '{}' does not match regex: '{}'", refererHeader, javaScriptReferer); + response.sendError(HttpServletResponse.SC_FORBIDDEN); + return; + } + + if (csrfGuard.isJavascriptRefererMatchDomain()) { + final boolean isJavascriptRefererMatchProtocol = csrfGuard.isJavascriptRefererMatchProtocol(); + // this is something like http://something.com/path or https://something.com/path + final String url = request.getRequestURL().toString(); + final String requestProtocolAndDomain = CsrfGuardUtils.httpProtocolAndDomain(url, isJavascriptRefererMatchProtocol); + final String refererProtocolAndDomain = CsrfGuardUtils.httpProtocolAndDomain(refererHeader, isJavascriptRefererMatchProtocol); + if (!refererProtocolAndDomain.equals(requestProtocolAndDomain)) { + LOGGER.error("Referer domain '{}' does not match request domain: '{}'", refererHeader, url); + response.sendError(HttpServletResponse.SC_FORBIDDEN); + return; + } + } + } else { + if (!javaScriptReferer.equals(JavaScriptConfigParameters.DEFAULT_REFERER_PATTERN)) { + LOGGER.error("Missing referer headers are not accepted if a non-default referer pattern '{}' is configured!", javaScriptReferer); + + response.sendError(HttpServletResponse.SC_FORBIDDEN); + return; + } + } + + // save this path so javascript is whitelisted + final String javascriptPath = request.getContextPath() + request.getServletPath(); + + // don't know why there would be more than one... hmmm + if (javascriptUris.size() < 100) { + javascriptUris.add(javascriptPath); + } + + writeJavaScript(request, response); + } } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/session/ContainerSession.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/session/ContainerSession.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/session/ContainerSession.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,79 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.session; + +import javax.servlet.http.HttpSession; +import java.util.Objects; + +public class ContainerSession implements LogicalSession { + + private final HttpSession httpSession; + private boolean areTokensGenerated; + + public ContainerSession(final HttpSession httpSession) { + this.httpSession = httpSession; + } + + @Override + public String getKey() { + return this.httpSession.getId(); + } + + @Override + public boolean isNew() { + return Objects.nonNull(this.httpSession) && this.httpSession.isNew(); + } + + @Override + public void invalidate() { + if (Objects.nonNull(this.httpSession)) { + this.httpSession.invalidate(); + } + } + + @Override + public boolean areTokensGenerated() { + return this.areTokensGenerated; + } + + @Override + public void setTokensGenerated(final boolean areTokensGenerated) { + this.areTokensGenerated = areTokensGenerated; + } + + @Override + public void setAttribute(final String name, final Object value) { + this.httpSession.setAttribute(name, value); + } + + @Override + public Object getAttribute(final String attributeName) { + return this.httpSession.getAttribute(attributeName); + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/session/LogicalSession.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/session/LogicalSession.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/session/LogicalSession.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,90 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.session; + +import javax.servlet.http.HttpSession; + +/** + * Represents a logical session that enables decoupling from the container's session implementation in case the client application uses a stateless approach (e.g. token based authentication) + */ +public interface LogicalSession { + + /** + * Returns the logical session key + * @return identifier that uniquely identifies the current actor + */ + String getKey(); + + /** + * Returns true if the client does not yet know about the + * session or if the client chooses not to join the session. + * + * @see javax.servlet.http.HttpSession#isNew() + * + * @return true if the server has created a session, but the client has not yet joined + */ + boolean isNew(); + + /** + * Invalidates this session then unbinds any objects bound to it. + */ + void invalidate(); + + /** + * @return whether the objects were generated or not. + */ + boolean areTokensGenerated(); + + /** + * Set whether the objects were generated or not. + * + * @param areTokensGenerated set true if the tokens were generated, false otherwise + */ + void setTokensGenerated(boolean areTokensGenerated); + + /** + * Saves an object to the current session + * + * @see HttpSession#setAttribute(java.lang.String, java.lang.Object) + * + * @param attribute the name to which the object is bound; cannot be null + * @param value the object to be bound + */ + void setAttribute(final String attribute, final Object value); + + /** + * Retrieves an object from the session using its name + * + * @see HttpSession#getAttribute(String) + * + * @param attributeName - identifies a certain object on the session + * @return the object associated to the attribute name + */ + Object getAttribute(String attributeName); +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/session/SessionTokenKeyExtractor.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/session/SessionTokenKeyExtractor.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/session/SessionTokenKeyExtractor.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,58 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.session; + +import org.owasp.csrfguard.token.storage.LogicalSessionExtractor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import java.util.Objects; + +public class SessionTokenKeyExtractor implements LogicalSessionExtractor { + + /** + * @param httpServletRequest the current HTTP servlet request + * @return a wrapped container session implementation if a session exists, null otherwise + */ + @Override + public LogicalSession extract(final HttpServletRequest httpServletRequest) { + return extractOrCreate(httpServletRequest, false); + } + + @Override + public LogicalSession extractOrCreate(final HttpServletRequest httpServletRequest) { + return extractOrCreate(httpServletRequest, true); + } + + private LogicalSession extractOrCreate(final HttpServletRequest httpServletRequest, final boolean create) { + final HttpSession session = httpServletRequest.getSession(create); + + return Objects.isNull(session) ? null : new ContainerSession(session); + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/tag/ATag.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/tag/ATag.java (.../ATag.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/tag/ATag.java (.../ATag.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,34 +26,38 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.tag; -import java.io.*; -import java.util.*; - -import javax.servlet.http.*; -import javax.servlet.jsp.*; -import javax.servlet.jsp.tagext.*; - -import org.owasp.csrfguard.*; +import org.owasp.csrfguard.CsrfGuard; +import org.owasp.csrfguard.session.LogicalSession; import org.owasp.csrfguard.util.BrowserEncoder; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.jsp.tagext.DynamicAttributes; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + public final class ATag extends AbstractUriTag implements DynamicAttributes { private final static long serialVersionUID = 0x00202937; - - private Map attributes = new HashMap(); + private final Map attributes = new HashMap<>(); + @Override public int doStartTag() { - CsrfGuard csrfGuard = CsrfGuard.getInstance(); - String tokenValue = csrfGuard.getTokenValue((HttpServletRequest) pageContext.getRequest(), buildUri(attributes.get("href"))); - String tokenName = csrfGuard.getTokenName(); + final CsrfGuard csrfGuard = CsrfGuard.getInstance(); + final String tokenName = csrfGuard.getTokenName(); + final LogicalSession logicalSession = csrfGuard.getLogicalSessionExtractor().extract((HttpServletRequest) this.pageContext.getRequest()); + final String tokenValue = Objects.nonNull(logicalSession) ? csrfGuard.getTokenService().getTokenValue(logicalSession.getKey(), buildUri(this.attributes.get("href"))) : null; + try { - pageContext.getOut().write(buildStartHtml(tokenName, tokenValue)); - } catch (IOException e) { - pageContext.getServletContext().log(e.getLocalizedMessage(), e); + this.pageContext.getOut().write(buildStartHtml(tokenName, tokenValue)); + } catch (final IOException e) { + this.pageContext.getServletContext().log(e.getLocalizedMessage(), e); } return EVAL_BODY_INCLUDE; @@ -62,26 +66,26 @@ @Override public int doEndTag() { try { - pageContext.getOut().write(""); - } catch (IOException e) { - pageContext.getServletContext().log(e.getLocalizedMessage(), e); + this.pageContext.getOut().write(""); + } catch (final IOException e) { + this.pageContext.getServletContext().log(e.getLocalizedMessage(), e); } return EVAL_PAGE; } @Override - public void setDynamicAttribute(String arg0, String arg1, Object arg2) throws JspException { - attributes.put(arg1.toLowerCase(), String.valueOf(arg2)); + public void setDynamicAttribute(final String arg0, final String arg1, final Object arg2) { + this.attributes.put(arg1.toLowerCase(), String.valueOf(arg2)); } - private String buildStartHtml(String tokenName, String tokenValue) { - StringBuilder sb = new StringBuilder(); + private String buildStartHtml(final String tokenName, final String tokenValue) { + final StringBuilder sb = new StringBuilder(); sb.append(""); + sb.append('>'); return sb.toString(); } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/tag/AbstractTag.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/tag/AbstractTag.java (.../AbstractTag.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/tag/AbstractTag.java (.../AbstractTag.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,22 +26,36 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.tag; -import javax.servlet.jsp.tagext.*; +import org.owasp.csrfguard.CsrfValidator; +import org.owasp.csrfguard.ProtectionResult; +import javax.servlet.jsp.tagext.TagSupport; + public abstract class AbstractTag extends TagSupport { private final static long serialVersionUID = 0xadede854; - public String buildUri(String page) { - String uri = page; + public String buildUri(final String uri) { + return calculateExtendedPageDescriptorUri(normalizeUri(uri)); + } - if (!page.startsWith("/")) { - uri = pageContext.getServletContext().getContextPath() + "/" + page; - } + /** + * @param normalizedUri the current normalizedUri + * @return if the protected/un-protected page descriptors were defined using wildcards or regexes, this method + * will return the extended page descriptor definition of the normalizedUri, otherwise returns itself + */ + private String calculateExtendedPageDescriptorUri(final String normalizedUri) { + final ProtectionResult protectionResult = new CsrfValidator().isProtectedPage(normalizedUri); - return uri; + return protectionResult.isProtected() ? protectionResult.getResourceIdentifier() + : normalizedUri; } - + + private String normalizeUri(final String uri) { + return uri.startsWith("/") ? uri + : this.pageContext.getServletContext().getContextPath() + '/' + uri; + } } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/tag/AbstractUriTag.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/tag/AbstractUriTag.java (.../AbstractUriTag.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/tag/AbstractUriTag.java (.../AbstractUriTag.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,6 +26,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.tag; public abstract class AbstractUriTag extends AbstractTag { @@ -35,11 +36,10 @@ private String uri = null; public String getUri() { - return uri; + return this.uri; } - public void setUri(String uri) { + public void setUri(final String uri) { this.uri = buildUri(uri); } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/tag/FormTag.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/tag/FormTag.java (.../FormTag.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/tag/FormTag.java (.../FormTag.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,34 +26,39 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.tag; -import java.io.*; -import java.util.*; - -import javax.servlet.http.*; -import javax.servlet.jsp.*; -import javax.servlet.jsp.tagext.*; - -import org.owasp.csrfguard.*; +import org.owasp.csrfguard.CsrfGuard; +import org.owasp.csrfguard.session.LogicalSession; import org.owasp.csrfguard.util.BrowserEncoder; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.tagext.DynamicAttributes; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + public final class FormTag extends AbstractUriTag implements DynamicAttributes { private final static long serialVersionUID = 0xbefee742; - private Map attributes = new HashMap(); + private final Map attributes = new HashMap<>(); @Override public int doStartTag() { - CsrfGuard csrfGuard = CsrfGuard.getInstance(); - String tokenValue = csrfGuard.getTokenValue((HttpServletRequest) pageContext.getRequest(), buildUri(attributes.get("action"))); - String tokenName = csrfGuard.getTokenName(); + final CsrfGuard csrfGuard = CsrfGuard.getInstance(); + final String tokenName = csrfGuard.getTokenName(); + final LogicalSession logicalSession = csrfGuard.getLogicalSessionExtractor().extract((HttpServletRequest) this.pageContext.getRequest()); + final String tokenValue = Objects.nonNull(logicalSession) ? csrfGuard.getTokenService().getTokenValue(logicalSession.getKey(), buildUri(this.attributes.get("action"))) : null; + try { - pageContext.getOut().write(buildStartHtml(tokenName, tokenValue)); - } catch (IOException e) { - pageContext.getServletContext().log(e.getLocalizedMessage(), e); + this.pageContext.getOut().write(buildStartHtml(tokenName, tokenValue)); + } catch (final IOException e) { + this.pageContext.getServletContext().log(e.getLocalizedMessage(), e); } return EVAL_BODY_INCLUDE; @@ -62,26 +67,26 @@ @Override public int doEndTag() { try { - pageContext.getOut().write(""); - } catch (IOException e) { - pageContext.getServletContext().log(e.getLocalizedMessage(), e); + this.pageContext.getOut().write(""); + } catch (final IOException e) { + this.pageContext.getServletContext().log(e.getLocalizedMessage(), e); } return EVAL_PAGE; } @Override - public void setDynamicAttribute(String arg0, String arg1, Object arg2) throws JspException { - attributes.put(arg1.toLowerCase(), String.valueOf(arg2)); + public void setDynamicAttribute(final String arg0, final String arg1, final Object arg2) throws JspException { + this.attributes.put(arg1.toLowerCase(), String.valueOf(arg2)); } - private String buildStartHtml(String tokenName, String tokenValue) { - StringBuilder sb = new StringBuilder(); + private String buildStartHtml(final String tokenName, final String tokenValue) { + final StringBuilder sb = new StringBuilder(); sb.append("
updatedPageTokens; + + private String updatedMasterToken; + + private Pair usedToken; + + public TokenBO() { + this(null, new HashMap<>()); + } + + public TokenBO(final String updatedMasterToken) { + this(updatedMasterToken, null); + } + + public TokenBO(final Map updatedPageTokens) { + this(null, updatedPageTokens); + } + + public TokenBO(final String updatedMasterToken, final Map updatedPageTokens) { + this.updatedMasterToken = updatedMasterToken; + this.updatedPageTokens = updatedPageTokens; + } + + public TokenBO setUsedPageToken(final String tokenValue) { + setUsedToken(TokenType.PAGE, tokenValue); + return this; + } + + public TokenBO setUpdatedPageToken(final String uri, final String pageTokenValue) { + if (this.updatedPageTokens.containsKey(uri)) { + throw new IllegalStateException(String.format("Logical Error! A new value for the page token with the URI [%s] has already been prepared for update.", uri)); + } else { + this.updatedPageTokens.put(uri, pageTokenValue); + } + return this; + } + + public String getUpdatedMasterToken() { + return this.updatedMasterToken; + } + + public TokenBO setUpdatedMasterToken(final String masterToken) { + if (Objects.isNull(this.updatedMasterToken)) { + this.updatedMasterToken = masterToken; + return this; + } else { + throw new IllegalStateException("Logical Error! A new value for the master token has already been prepared for update."); + } + } + + public Map getUpdatedPageTokens() { + return this.updatedPageTokens; + } + + public boolean isUsedMasterToken() { + if (Objects.isNull(this.usedToken)) { + throw new IllegalStateException("Internal error! The token used to validate the request is not set."); + } else { + return this.usedToken.getKey() == TokenType.MASTER; + } + } + + public TokenBO setUsedMasterToken(final String tokenValue) { + setUsedToken(TokenType.MASTER, tokenValue); + return this; + } + + private void setUsedToken(final TokenType page, final String tokenValue) { + if (Objects.isNull(this.usedToken)) { + this.usedToken = Pair.of(page, tokenValue); + } else { + throw new IllegalStateException("Used token was already set. A request cannot be validated by two different tokens!"); + } + } + + private enum TokenType { + MASTER, PAGE + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/mapper/TokenMapper.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/mapper/TokenMapper.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/mapper/TokenMapper.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,41 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.token.mapper; + +import org.owasp.csrfguard.token.businessobject.TokenBO; +import org.owasp.csrfguard.token.transferobject.TokenTO; + +public final class TokenMapper { + + private TokenMapper() {} + + public static TokenTO toTransferObject(final TokenBO tokenBO) { + return new TokenTO(tokenBO.getUpdatedMasterToken(), tokenBO.getUpdatedPageTokens()); + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/service/TokenService.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/service/TokenService.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/service/TokenService.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,297 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.token.service; + +import org.owasp.csrfguard.CsrfGuard; +import org.owasp.csrfguard.CsrfGuardException; +import org.owasp.csrfguard.CsrfValidator; +import org.owasp.csrfguard.ProtectionResult; +import org.owasp.csrfguard.session.LogicalSession; +import org.owasp.csrfguard.token.TokenUtils; +import org.owasp.csrfguard.token.businessobject.TokenBO; +import org.owasp.csrfguard.token.mapper.TokenMapper; +import org.owasp.csrfguard.token.storage.Token; +import org.owasp.csrfguard.token.storage.TokenHolder; +import org.owasp.csrfguard.token.storage.impl.PageTokenValue; +import org.owasp.csrfguard.token.transferobject.TokenTO; +import org.owasp.csrfguard.util.CsrfGuardUtils; +import org.owasp.csrfguard.util.MessageConstants; + +import javax.servlet.http.HttpServletRequest; +import java.time.LocalDateTime; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class TokenService { + + private final CsrfGuard csrfGuard; + + public TokenService(final CsrfGuard csrfGuard) { + this.csrfGuard = csrfGuard; + } + + /** + * Invalidates the logical session and removes all tokens from the storage + * + * @param logicalSession a not null logical session implementation + */ + public void invalidate(final LogicalSession logicalSession) { + final String logicalSessionKey = logicalSession.getKey(); + + final TokenHolder tokenHolder = this.csrfGuard.getTokenHolder(); + + tokenHolder.remove(logicalSessionKey); + + logicalSession.invalidate(); + } + + /** + * Returns the master token assigned to the unique identifier extracted from the current request. + * This identifier could be for example the sessionId of the current user, or the username extracted from a JWT token + *

+ * + * @param logicalSessionKey identifies the current logical session uniquely + * @return the master token + */ + public String getMasterToken(final String logicalSessionKey) { + final TokenHolder tokenHolder = this.csrfGuard.getTokenHolder(); + + return getMasterToken(tokenHolder, logicalSessionKey); + } + + /** + * Return the page tokens if the functionality is enabled and the client has already accessed a protected resource, + * or if the token pre-creation is enabled. + *

+ * Note: this method returns a copy of the page tokens in order to prevent outside modification. + *

+ * + * @param logicalSessionKey identifies the current logical session uniquely + * @return the page tokens or an empty map + */ + public Map getPageTokens(final String logicalSessionKey) { + final TokenHolder tokenHolder = this.csrfGuard.getTokenHolder(); + + return new HashMap<>(tokenHolder.getPageTokens(logicalSessionKey)); + } + + /** + * Generates master token and page token for the current resource if the token-per-page configuration is enabled + *

+ * + * @param logicalSessionKey identifies the current logical session uniquely + * @param httpMethod the current HTTP method used to request the resource + * @param requestURI the URI of the desired HTTP resource + * @return returns the generated page or master token + */ + public String generateTokensIfAbsent(final String logicalSessionKey, final String httpMethod, final String requestURI) { + final TokenHolder tokenHolder = this.csrfGuard.getTokenHolder(); + + if (this.csrfGuard.isTokenPerPageEnabled()) { + final ProtectionResult protectionResult = new CsrfValidator().isProtectedPageAndMethod(requestURI, httpMethod); + if (protectionResult.isProtected()) { + return tokenHolder.createPageTokenIfAbsent(logicalSessionKey, protectionResult.getResourceIdentifier(), TokenUtils::generateRandomToken); + } + } + + return tokenHolder.createMasterTokenIfAbsent(logicalSessionKey, TokenUtils::generateRandomToken); + } + + /** + * Creates master token if it does not exist already. + * + * @param logicalSessionKey identifies the current logical session uniquely + */ + public void createMasterTokenIfAbsent(final String logicalSessionKey) { + final TokenHolder tokenHolder = this.csrfGuard.getTokenHolder(); + tokenHolder.createMasterTokenIfAbsent(logicalSessionKey, TokenUtils::generateRandomToken); + } + + /** + * Generates new random tokens for configured protected pages. + * This method creates a new master token if it did not exist previously. + * Existing page tokens with the same session key will be overwritten. + * + * @param logicalSessionKey identifies the current logical session uniquely + */ + public void generateProtectedPageTokens(final String logicalSessionKey) { + final HashMap generatedPageTokens = this.csrfGuard.getProtectedPages().stream() + .collect(Collectors.toMap(Function.identity(), + k -> TokenUtils.generateRandomToken(), + (a, b) -> b, + HashMap::new)); + final TokenHolder tokenHolder = this.csrfGuard.getTokenHolder(); + + tokenHolder.createMasterTokenIfAbsent(logicalSessionKey, TokenUtils::generateRandomToken); + tokenHolder.setPageTokens(logicalSessionKey, generatedPageTokens); + } + + /** + * Rotates the used master or the currently requested page token if the token-per-page functionality is enabled. + * + * @param logicalSessionKey identifies the current logical session uniquely + * @param requestURI the URI of the desired HTTP resource + * @param usedValidToken a verified token that has validated the current request + * @return a TokenTO transfer object containing the updated token values that will be sent back to the client + */ + public TokenTO rotateUsedToken(final String logicalSessionKey, final String requestURI, final TokenBO usedValidToken) { + final TokenHolder tokenHolder = this.csrfGuard.getTokenHolder(); + + final String newTokenValue = TokenUtils.generateRandomToken(); + + if (usedValidToken.isUsedMasterToken()) { + tokenHolder.setMasterToken(logicalSessionKey, newTokenValue); + usedValidToken.setUpdatedMasterToken(newTokenValue); + } else { + tokenHolder.setPageToken(logicalSessionKey, requestURI, newTokenValue); + usedValidToken.setUpdatedPageToken(requestURI, newTokenValue); + } + + return TokenMapper.toTransferObject(usedValidToken); + } + + /** + * Rotates (re-generates) the master token and all page tokens if the token-per-page functionality is enabled. + * + * @param logicalSessionKey identifies the current logical session uniquely + */ + public void rotateAllTokens(final String logicalSessionKey) { + final TokenHolder tokenHolder = this.csrfGuard.getTokenHolder(); + + tokenHolder.setMasterToken(logicalSessionKey, TokenUtils.generateRandomToken()); + + tokenHolder.rotateAllPageTokens(logicalSessionKey, TokenUtils::generateRandomToken); + } + + /** + * Returns the master or the page token for the associated resource depending on whether the token-per-page + * configuration is enabled or not. + *

+ * If the token does not currently exists, it creates a new one. + *

+ * + * @param logicalSessionKey identifies the current logical session uniquely + * @param resourceUri the URI of the desired HTTP resource + * @return a valid token for the specified resourceUri + */ + public String getTokenValue(final String logicalSessionKey, final String resourceUri) { + final TokenHolder tokenHolder = this.csrfGuard.getTokenHolder(); + + return this.csrfGuard.isTokenPerPageEnabled() ? tokenHolder.createPageTokenIfAbsent(logicalSessionKey, resourceUri, TokenUtils::generateRandomToken) + : tokenHolder.createMasterTokenIfAbsent(logicalSessionKey, TokenUtils::generateRandomToken); + + } + + /** + * Verifies the validity of the current request. + *

+ * + * @param request current HTTP Servlet Request + * @param resourceIdentifier the requested resource identifier + * @param logicalSessionKey identifies the current logical session uniquely + * @param masterToken the master token + * @return The TokenBO business object that contains the updated tokens and the token used to validate the current request + * @throws CsrfGuardException if the request does not have a valid token associated + */ + public TokenBO verifyToken(final HttpServletRequest request, final String resourceIdentifier, final String logicalSessionKey, final String masterToken) throws CsrfGuardException { + final String tokenName = this.csrfGuard.getTokenName(); + + final boolean isAjaxRequest = this.csrfGuard.isAjaxEnabled() && CsrfGuardUtils.isAjaxRequest(request); + final String tokenFromRequest = isAjaxRequest ? request.getHeader(tokenName) : request.getParameter(tokenName); + final TokenBO tokenBO; + if (Objects.isNull(tokenFromRequest)) { + throw new CsrfGuardException(MessageConstants.REQUEST_MISSING_TOKEN_MSG); + } else { + tokenBO = this.csrfGuard.isTokenPerPageEnabled() ? verifyPageToken(logicalSessionKey, masterToken, tokenFromRequest, resourceIdentifier, isAjaxRequest) + : verifyMasterToken(masterToken, tokenFromRequest); + } + + return tokenBO; + } + + private String getMasterToken(final TokenHolder tokenHolder, final String tokenKey) { + final Token token = tokenHolder.getToken(tokenKey); + return Objects.nonNull(token) ? token.getMasterToken() : null; + } + + private TokenBO verifyPageToken(final String logicalSessionKey, final String masterToken, final String tokenFromRequest, final String requestURI, final boolean isAjaxRequest) throws CsrfGuardException { + final TokenHolder tokenHolder = this.csrfGuard.getTokenHolder(); + + final Token token = tokenHolder.getToken(logicalSessionKey); + final PageTokenValue timedPageToken = token.getTimedPageToken(requestURI); + + final TokenBO tokenBO; + if (timedPageToken == null) { + /* if there is no token for the current resource, create it and rely on the master token for validation */ + final String newPageToken = TokenUtils.generateRandomToken(); + tokenHolder.setPageToken(logicalSessionKey, requestURI, newPageToken); + + tokenBO = verifyMasterToken(masterToken, tokenFromRequest).setUpdatedPageToken(requestURI, newPageToken); + } else { + final String pageToken = timedPageToken.getValue(); + if (pageToken.equals(tokenFromRequest)) { + tokenBO = new TokenBO().setUsedPageToken(tokenFromRequest); + } else if (initIsWithinTimeTolerance(this.csrfGuard, isAjaxRequest, timedPageToken)) { + tokenBO = verifyMasterToken(masterToken, tokenFromRequest).setUpdatedPageToken(requestURI, pageToken); + } else { + /* TODO Is this necessary? If the Rotate action is registered, the exception handler will call it and re-generate the tokens */ + if (masterToken.equals(pageToken)) { + tokenHolder.setMasterToken(logicalSessionKey, TokenUtils.generateRandomToken()); + } + + tokenHolder.regenerateUsedPageToken(logicalSessionKey, tokenFromRequest, TokenUtils::generateRandomToken); + + throw new CsrfGuardException(MessageConstants.MISMATCH_PAGE_TOKEN_MSG); + } + } + return tokenBO; + } + + /** + * The race condition only happens in case of AJAX requests when the token pre-creation is not enabled. + * NOTE: If the combination of the Token Rotation and AJAX support will be implemented, this logic must also be adjusted. + * @return true if the page token creation is within the configured time tolerance and the application should also accept the master token for validation + */ + private boolean initIsWithinTimeTolerance(final CsrfGuard csrfGuard, final boolean isAjaxRequest, final PageTokenValue tokenTimedPageToken) { + return isAjaxRequest + && !csrfGuard.isTokenPerPagePrecreate() + && tokenTimedPageToken.getCreationTime().plus(this.csrfGuard.getPageTokenSynchronizationTolerance()).isAfter(LocalDateTime.now()); + } + + private TokenBO verifyMasterToken(final String storedToken, final String tokenFromRequest) throws CsrfGuardException { + if (storedToken.equals(tokenFromRequest)) { + return new TokenBO().setUsedMasterToken(tokenFromRequest); + } else { + throw new CsrfGuardException(MessageConstants.MISMATCH_MASTER_TOKEN_MSG); + } + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/LogicalSessionExtractor.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/LogicalSessionExtractor.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/LogicalSessionExtractor.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,53 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.token.storage; + +import org.owasp.csrfguard.session.LogicalSession; + +import javax.servlet.http.HttpServletRequest; + +public interface LogicalSessionExtractor { + + /** + * Returns a logical session implementation based on the information extracted from the current HTTP request or null if that was not possible + * + * @param httpServletRequest current request + * + * @return a logical session created based on the current request or null if that was not possible + */ + LogicalSession extract(final HttpServletRequest httpServletRequest); + + /** + * Returns a logical session implementation based on the information extracted from the current HTTP request or creates a new one + * + * @param httpServletRequest current request + * @return logical session implementation based on the information extracted from the current HTTP request or creates a new one + */ + LogicalSession extractOrCreate(HttpServletRequest httpServletRequest); +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/Token.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/Token.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/Token.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,102 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.token.storage; + +import org.owasp.csrfguard.token.storage.impl.PageTokenValue; + +import java.util.Map; +import java.util.function.Supplier; + +/** + * Interface used to interact with CSRF tokens + */ +public interface Token { + + /** + * Returns the master token + * @return the current master token + */ + String getMasterToken(); + + /** + * Sets the new master token + * @param masterToken the new master token + */ + void setMasterToken(final String masterToken); + + /** + * @param uri the URI to which the page token should be returned + * @return the page token for the requested uri + */ + String getPageToken(final String uri); + + /** + * @param uri the URI to which the timed page token should be returned + * @return a timed page token containing a page token and its creation date + */ + PageTokenValue getTimedPageToken(final String uri); + + /** + * @param uri the URI to which the page token should be associated + * @param pageToken the new page token + */ + void setPageToken(final String uri, final String pageToken); + + /** + * @param uri the URI to which the page token should be associated + * @param valueSupplier a supplier that generates new, unique tokens at each invocation + * @return the newly generated token + */ + String setPageTokenIfAbsent(final String uri, final Supplier valueSupplier); + + /** + * @return a map of URIs and their associated page tokens + */ + Map getPageTokens(); + + /** + * Initialize or overwrite the entire page-token map + * @param pageTokens a map of URIs and their associated page tokens + */ + void setPageTokens(final Map pageTokens); + + /** + * Rotates all the existing page token values + * @param tokenValueSupplier a supplier that generates new, unique tokens at each invocation + */ + void rotateAllPageTokens(final Supplier tokenValueSupplier); + + /** + * TODO is it worth the added performance penalty in case of a large application with a lot of pages? What would be the risk if this would be contextual to the assigned resource? + * Disposes the current token from all the stored valid page tokens, disregarding to which resource it was assigned and replaces with a newly generated one. + * @param tokenFromRequest the current token which needs to be rotated + * @param tokenValueSupplier a supplier that generates new, unique tokens at each invocation + */ + void regenerateUsedPageToken(final String tokenFromRequest, final Supplier tokenValueSupplier); +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/TokenHolder.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/TokenHolder.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/TokenHolder.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,140 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.owasp.csrfguard.token.storage; + +import org.owasp.csrfguard.token.service.TokenService; + +import java.util.Map; +import java.util.function.Supplier; + +/** + * Interface used for storing and manipulating tokens across the solution. + * + * Methods of this class should only be used through the {@link TokenService} and its relevant subclass(es) + */ +public interface TokenHolder { + + /** + * Sets or overwrites the master token bound to a specific session key. + * It does not overwrite the session key associated page tokens. + * + * @param sessionKey identifies the current logical session uniquely + * @param value the value to be used as master token + */ + void setMasterToken(final String sessionKey, final String value); + + /** + * Creates and returns a new master token bound to the provided session key if there wasn't any or returns the existing value. + * + * @param sessionKey identifies the current logical session uniquely + * @param valueSupplier produces a new master token value lazily/on demand + * @return the created master token + */ + String createMasterTokenIfAbsent(final String sessionKey, final Supplier valueSupplier); + + /** + * Creates and returns a new page token bound to the provided resource URI and mapped to the session key if there wasn't any or returns the existing value. + * + * If there are no tokens associated to the session key it also creates a new master token. + * + * @param sessionKey identifies the current logical session uniquely + * @param resourceUri the URI of the desired HTTP resource + * @param valueSupplier produces a new page token value lazily/on demand + * @return the existing or newly created page token + */ + String createPageTokenIfAbsent(String sessionKey, String resourceUri, Supplier valueSupplier); + + /** + * Returns the master and page tokens associated to a logical session key + * + * @param sessionKey identifies the current logical session uniquely + * @return a token object containing the master and page tokens + */ + Token getToken(final String sessionKey); + + /** + * Returns the page token based on the desired HTTP resource URI and logical session key + * + * @param sessionKey identifies the current logical session uniquely + * @param resourceUri the URI of the desired HTTP resource + * @return a page token bound to a resource URI and associated to a logical session key + * or NULL if there is no token with identified by the session key + */ + String getPageToken(String sessionKey, String resourceUri); + + /** + * Sets the value of a page token based on the desired HTTP resource URI and logical session key + * + * @param sessionKey identifies the current logical session uniquely + * @param resourceUri the URI of the desired HTTP resource + * @param value the value to be used as token for the page + */ + void setPageToken(String sessionKey, String resourceUri, String value); + + /** + * Sets/overwrites the page tokens with the provided values + * + * @param sessionKey identifies the current logical session uniquely + * @param pageTokens page tokens mapped to their resource URIs + */ + void setPageTokens(final String sessionKey, final Map pageTokens); + + /** + * Returns all page tokens associated to the provided logical session key + * + * @param sessionKey identifies the current logical session uniquely + * @return page tokens mapped to their resource URIs + */ + Map getPageTokens(String sessionKey); + + /** + * Removes all tokens related to a specific logical session key + * + * @param sessionKey identifies the current logical session uniquely + */ + void remove(String sessionKey); + + /** + * Re-generates all existing tokens associated to the provided logical session key + * + * @param sessionKey identifies the current logical session uniquely + * @param tokenValueSupplier produces a new page token value lazily/on demand + */ + void rotateAllPageTokens(final String sessionKey, final Supplier tokenValueSupplier); + + /** + * Re-generates the value of a used page token + * + * @param sessionKey identifies the current logical session uniquely + * @param tokenFromRequest the token extracted from the request + * @param tokenValueSupplier produces a new page token value lazily/on demand + */ + void regenerateUsedPageToken(final String sessionKey, final String tokenFromRequest, final Supplier tokenValueSupplier); +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/impl/InMemoryToken.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/impl/InMemoryToken.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/impl/InMemoryToken.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,122 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.token.storage.impl; + +import org.apache.commons.lang3.tuple.Pair; +import org.owasp.csrfguard.token.storage.Token; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class InMemoryToken implements Token { + + private String masterToken; + private Map pageTokens; + + public InMemoryToken(final String masterToken) { + this(masterToken, new ConcurrentHashMap<>()); + } + + public InMemoryToken(final String masterToken, final Pair pageToken) { + this(masterToken, toMap(pageToken)); + } + + private InMemoryToken(final String masterToken, final Map pageTokens) { + Objects.requireNonNull(masterToken, "Master token cannot be null"); + Objects.requireNonNull(pageTokens, "Page tokens cannot be null"); + + this.masterToken = masterToken; + this.pageTokens = new ConcurrentHashMap<>(pageTokens); + } + + @Override + public String getMasterToken() { + return this.masterToken; + } + + @Override + public void setMasterToken(final String masterToken) { + this.masterToken = masterToken; + } + + @Override + public String getPageToken(final String uri) { + return this.pageTokens.get(uri).getValue(); + } + + @Override + public PageTokenValue getTimedPageToken(final String uri) { + return this.pageTokens.get(uri); + } + + @Override + public void setPageToken(final String uri, final String pageToken) { + this.pageTokens.put(uri, PageTokenValue.from(pageToken)); + } + + @Override + public String setPageTokenIfAbsent(final String uri, final Supplier valueSupplier) { + return this.pageTokens.computeIfAbsent(uri, k -> PageTokenValue.from(valueSupplier.get())).getValue(); + } + + @Override + public Map getPageTokens() { + return this.pageTokens.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, + e -> e.getValue().getValue())); + } + + @Override + public void setPageTokens(final Map pageTokens) { + this.pageTokens = pageTokens.entrySet().stream() + .collect(Collectors.toMap(Map.Entry::getKey, + e -> PageTokenValue.from(e.getValue()), + (e1, e2) -> e2, + ConcurrentHashMap::new + )); + } + + @Override + public void rotateAllPageTokens(final Supplier tokenValueSupplier) { + this.pageTokens.entrySet().forEach(e -> e.setValue(PageTokenValue.from(tokenValueSupplier.get()))); + } + + @Override + public void regenerateUsedPageToken(final String tokenFromRequest, final Supplier tokenValueSupplier) { + this.pageTokens.replaceAll((k, v) -> v.getValue().equals(tokenFromRequest) ? PageTokenValue.from(tokenValueSupplier.get()) : v); + } + + private static Map toMap(final Pair pageToken) { + final Map pageTokens = new ConcurrentHashMap<>(); + pageTokens.put(pageToken.getKey(), PageTokenValue.from(pageToken.getValue())); + return pageTokens; + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/impl/InMemoryTokenHolder.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/impl/InMemoryTokenHolder.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/impl/InMemoryTokenHolder.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,132 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.owasp.csrfguard.token.storage.impl; + +import org.apache.commons.lang3.tuple.Pair; +import org.owasp.csrfguard.token.storage.Token; +import org.owasp.csrfguard.token.storage.TokenHolder; + +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Supplier; + +public class InMemoryTokenHolder implements TokenHolder { + + private static final Map TOKENS = new ConcurrentHashMap<>(); + + public InMemoryTokenHolder() {} + + @Override + public void setMasterToken(final String sessionKey, final String value) { + TOKENS.compute(sessionKey, (k, v) -> { + final Token result; + if (Objects.isNull(v)) { + result = new InMemoryToken(value); + } else { + v.setMasterToken(value); + result = v; + } + return result; + }); + } + + @Override + public String createMasterTokenIfAbsent(final String sessionKey, final Supplier valueSupplier) { + final Token token = TOKENS.computeIfAbsent(sessionKey, k -> new InMemoryToken(valueSupplier.get())); + return token.getMasterToken(); + } + + @Override + public String createPageTokenIfAbsent(final String sessionKey, final String resourceUri, final Supplier valueSupplier) { + final Token token = TOKENS.get(sessionKey); + if (Objects.isNull(token)) { + final String newPageToken = valueSupplier.get(); + TOKENS.computeIfAbsent(sessionKey, k -> new InMemoryToken(valueSupplier.get(), Pair.of(resourceUri, newPageToken))); + return newPageToken; + } else { + return token.setPageTokenIfAbsent(resourceUri, valueSupplier); + } + } + + @Override + public Token getToken(final String sessionKey) { + return TOKENS.get(sessionKey); + } + + @Override + public String getPageToken(final String sessionKey, final String resourceUri) { + final Token token = TOKENS.get(sessionKey); + + return Objects.nonNull(token) ? token.getPageToken(resourceUri) : null; + } + + @Override + public void setPageToken(final String sessionKey, final String resourceUri, final String value) { + getTokenOrException(sessionKey).setPageToken(resourceUri, value); + } + + @Override + public void setPageTokens(final String sessionKey, final Map pageTokens) { + getTokenOrException(sessionKey).setPageTokens(pageTokens); + } + + @Override + public Map getPageTokens(final String sessionKey) { + return getTokenOrException(sessionKey).getPageTokens(); + } + + @Override + public void remove(final String sessionKey) { + TOKENS.remove(sessionKey); + } + + @Override + public void rotateAllPageTokens(final String sessionKey, final Supplier tokenValueSupplier) { + final Token token = getTokenOrException(sessionKey); + token.rotateAllPageTokens(tokenValueSupplier); + } + + @Override + public void regenerateUsedPageToken(final String sessionKey, final String tokenFromRequest, final Supplier tokenValueSupplier) { + final Token token = getTokenOrException(sessionKey); + token.regenerateUsedPageToken(tokenFromRequest, tokenValueSupplier); + } + + private Token getTokenOrException(final String sessionKey) { + final Token token = TOKENS.get(sessionKey); + + if (Objects.isNull(token)) { + throw new IllegalStateException("Token with the provided session key does not exist!"); + } else { + return token; + } + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/impl/PageTokenValue.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/impl/PageTokenValue.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/storage/impl/PageTokenValue.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,62 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.token.storage.impl; + +import java.time.LocalDateTime; + +public final class PageTokenValue { + + private final String pageTokenValue; + private final LocalDateTime localDateTime; + + private PageTokenValue(final String pageTokenValue) { + this(pageTokenValue, LocalDateTime.now()); + } + + private PageTokenValue(final String pageTokenValue, final LocalDateTime localDateTime) { + this.pageTokenValue = pageTokenValue; + this.localDateTime = localDateTime; + } + + public static PageTokenValue from(final String pageTokenValue) { + return new PageTokenValue(pageTokenValue); + } + + public static PageTokenValue from(final String pageTokenValue, final LocalDateTime localDateTime) { + return new PageTokenValue(pageTokenValue, localDateTime); + } + + public String getValue() { + return this.pageTokenValue; + } + + public LocalDateTime getCreationTime() { + return this.localDateTime; + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/transferobject/TokenTO.java =================================================================== diff -u --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/transferobject/TokenTO.java (revision 0) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/token/transferobject/TokenTO.java (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -0,0 +1,64 @@ +/* + * The OWASP CSRFGuard Project, BSD License + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.owasp.csrfguard.token.transferobject; + +import com.google.gson.Gson; +import org.apache.commons.lang3.StringUtils; + +import java.util.Collections; +import java.util.Map; + +public class TokenTO { + + private final String masterToken; + + private final Map pageTokens; + + public TokenTO(final String masterToken) { + this(masterToken, Collections.emptyMap()); + } + + public TokenTO(final Map pageTokens) { + this(null, pageTokens); + } + + public TokenTO(final String masterToken, final Map pageTokens) { + this.masterToken = masterToken; + this.pageTokens = pageTokens; + } + + public boolean isEmpty() { + return StringUtils.isBlank(this.masterToken) && this.pageTokens.isEmpty(); + } + + @Override + public String toString() { + return new Gson().toJson(this); + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/BrowserEncoder.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/BrowserEncoder.java (.../BrowserEncoder.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/BrowserEncoder.java (.../BrowserEncoder.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,63 +26,71 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.util; public final class BrowserEncoder { private BrowserEncoder() { - /** enforce use of static methods **/ + /* enforce use of static methods */ } @Override public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } - - public static String encodeForHtml(String s) { - StringBuilder sb = new StringBuilder(); - int len = (s == null ? -1 : s.length()); - - for(int i=0; i') { - sb.append(">"); - } else if(c == '"') { - sb.append("""); - } else if(c == '\'') { - sb.append("'"); - } else if(c == '/') { - sb.append("/"); - } else { - sb.append(c); + + public static String encodeForHtml(final String s) { + final StringBuilder stringBuilder = new StringBuilder(); + final int length = (s == null ? -1 : s.length()); + + for (int i = 0; i < length; i++) { + final char c = s.charAt(i); + + switch (c) { + case '&': + stringBuilder.append("&"); + break; + case '<': + stringBuilder.append("<"); + break; + case '>': + stringBuilder.append(">"); + break; + case '"': + stringBuilder.append("""); + break; + case '\'': + stringBuilder.append("'"); + break; + case '/': + stringBuilder.append("/"); + break; + default: + stringBuilder.append(c); + break; } } - - return sb.toString(); + + return stringBuilder.toString(); } - - public static String encodeForAttribute(String s) { - StringBuilder sb = new StringBuilder(); - int len = (s == null ? -1 : s.length()); - - for(int i=0; i FIELD_NAME_TRANSFORMER = fieldName -> StringUtils.capitalize(StringUtils.join(StringUtils.splitByCharacterTypeCamelCase(fieldName), StringUtils.SPACE)); + + private static final String[] FIELDS_TO_EXCLUDE = {"propertiesCache", "javascriptTemplateCode"}; + + public CsrfGuardPropertiesToStringBuilder(final Object object) { + super(object, new CustomStyle()); + setExcludeFieldNames(FIELDS_TO_EXCLUDE); + } + + @Override + public String toString() { + final String marginals = Stream.generate(() -> PREFIX_CHARACTER).limit(CONFIG_DELIMITER_LENGTH).collect(Collectors.joining(StringUtils.EMPTY, NEW_LINE, NEW_LINE)); + + return marginals + + PREFIX + "OWASP CSRFGuard properties" + NEW_LINE + + NEW_LINE + + PREFIX + super.toString() + + marginals; + } + + @Override + public ToStringBuilder append(final String fieldName, final boolean value) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), value); + } + + @Override + public ToStringBuilder append(final String fieldName, final boolean[] array) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array); + } + + @Override + public ToStringBuilder append(final String fieldName, final boolean[] array, final boolean fullDetail) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array, fullDetail); + } + + @Override + public ToStringBuilder append(final String fieldName, final byte value) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), value); + } + + @Override + public ToStringBuilder append(final String fieldName, final byte[] array) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array); + } + + @Override + public ToStringBuilder append(final String fieldName, final byte[] array, final boolean fullDetail) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array, fullDetail); + } + + @Override + public ToStringBuilder append(final String fieldName, final char value) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), value); + } + + @Override + public ToStringBuilder append(final String fieldName, final char[] array) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array); + } + + @Override + public ToStringBuilder append(final String fieldName, final char[] array, final boolean fullDetail) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array, fullDetail); + } + + @Override + public ToStringBuilder append(final String fieldName, final double value) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), value); + } + + @Override + public ToStringBuilder append(final String fieldName, final double[] array) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array); + } + + @Override + public ToStringBuilder append(final String fieldName, final double[] array, final boolean fullDetail) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array, fullDetail); + } + + @Override + public ToStringBuilder append(final String fieldName, final float value) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), value); + } + + @Override + public ToStringBuilder append(final String fieldName, final float[] array) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array); + } + + @Override + public ToStringBuilder append(final String fieldName, final float[] array, final boolean fullDetail) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array, fullDetail); + } + + @Override + public ToStringBuilder append(final String fieldName, final int value) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), value); + } + + @Override + public ToStringBuilder append(final String fieldName, final int[] array) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array); + } + + @Override + public ToStringBuilder append(final String fieldName, final int[] array, final boolean fullDetail) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array, fullDetail); + } + + @Override + public ToStringBuilder append(final String fieldName, final long value) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), value); + } + + @Override + public ToStringBuilder append(final String fieldName, final long[] array) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array); + } + + @Override + public ToStringBuilder append(final String fieldName, final long[] array, final boolean fullDetail) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array, fullDetail); + } + + @Override + public ToStringBuilder append(final String fieldName, final Object obj) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), obj); + } + + @Override + public ToStringBuilder append(final String fieldName, final Object obj, final boolean fullDetail) { + final Object value = customToString(obj); + return Objects.isNull(value) ? this + : super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), value, fullDetail); + } + + @Override + public ToStringBuilder append(final String fieldName, final Object[] array) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array); + } + + @Override + public ToStringBuilder append(final String fieldName, final Object[] array, final boolean fullDetail) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array, fullDetail); + } + + @Override + public ToStringBuilder append(final String fieldName, final short value) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), value); + } + + @Override + public ToStringBuilder append(final String fieldName, final short[] array) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array); + } + + @Override + public ToStringBuilder append(final String fieldName, final short[] array, final boolean fullDetail) { + return super.append(FIELD_NAME_TRANSFORMER.apply(fieldName), array, fullDetail); + } + + private Object customToString(final Object obj) { + return customToString(obj, StringUtils.EMPTY); + } + + private Object customToString(final Object obj, final String prefixOffset) { + final Object result; + if (Objects.isNull(obj)) { + result = null; + } else { + final String className = obj.getClass().getName(); + if (obj instanceof Collection) { + result = handleCollections((Collection) obj); + } else if (obj instanceof SecureRandom) { + final SecureRandom secureRandom = (SecureRandom) obj; + result = String.format("%s(algorithm: %s, provider: %s)", secureRandom.getClass().getName(), secureRandom.getAlgorithm(), secureRandom.getProvider()); + } else if (obj instanceof Duration) { + result = ((Duration) obj).toMillis() + " ms"; + } else if (obj instanceof IAction) { + result = handleActions((IAction) obj, prefixOffset); + } else if (className.startsWith("org.owasp.csrfguard")) { // TODO extract and reuse + result = className; + } else { + result = obj; + } + } + return result; + } + + private Object handleActions(final IAction action, final String prefixOffset) { + final String parameters = action.getParameterMap().entrySet().stream() + .map(e -> String.format("%s\t%sParameter: %s = %s", prefixOffset, PREFIX, e.getKey(), e.getValue())) + .collect(Collectors.joining(NEW_LINE)); + + final String actionString = action.getClass().getName(); + return StringUtils.isBlank(parameters) ? actionString + : actionString + NEW_LINE + parameters; + } + + private Object handleCollections(final Collection collection) { + return collection.isEmpty() ? null + : collection.stream() + .map(element -> NEW_LINE + '\t' + PREFIX + customToString(element, "\t")) + .collect(Collectors.joining()); + } + + private static class CustomStyle extends RecursiveToStringStyle { + public CustomStyle() { + super(); + + setUseClassName(false); + setUseIdentityHashCode(false); + setFieldSeparator(NEW_LINE + PREFIX); + setFieldNameValueSeparator(':' + StringUtils.SPACE); + setContentStart(StringUtils.EMPTY); + setContentEnd(StringUtils.EMPTY); + } + } +} Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/CsrfGuardUtils.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/CsrfGuardUtils.java (.../CsrfGuardUtils.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/CsrfGuardUtils.java (.../CsrfGuardUtils.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,1410 +26,135 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.util; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.owasp.csrfguard.CsrfGuard; +import org.owasp.csrfguard.config.overlay.ConfigPropertiesCascadeCommonUtils; +import org.owasp.csrfguard.token.transferobject.TokenTO; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.StringWriter; -import java.io.Writer; -import java.lang.annotation.Annotation; -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Objects; -import javax.servlet.ServletConfig; -import javax.xml.stream.XMLStreamException; -import javax.xml.stream.XMLStreamWriter; - /** - * + * Various utility methods/helpers. */ -public class CsrfGuardUtils { +public final class CsrfGuardUtils { - private CsrfGuardUtils() {} + private CsrfGuardUtils() {} - /** - * for a url, get the protocol and domain, e.g. for url https://a.b/path, will return https://a.b - * @param url a string representing a URL - * @param includeProtocol - * @return the path with or without the protocol - */ - public static String httpProtocolAndDomain(String url, boolean includeProtocol) { - if (includeProtocol) { - return httpProtocolAndDomain(url); - } + /** + * for a url, get the protocol and domain, e.g. for url https://a.b/path, will return https://a.b + * + * @param url a string representing a URL + * @param includeProtocol whether to include the HTTP or HTTPS protocol in the result + * @return the path with or without the protocol + */ + public static String httpProtocolAndDomain(final String url, final boolean includeProtocol) { + if (includeProtocol) { + return httpProtocolAndDomain(url); + } - return httpProtocolAndDomain(url.replaceFirst("^(http[s]?)://","")); - } + return httpProtocolAndDomain(url.replaceFirst("^(http[s]?)://", StringUtils.EMPTY)); + } - /** - * for a url, get the protocol and domain, e.g. for url https://a.b/path, will return https://a.b - * @param url a string representing a URL - * @return the protocol and path - */ - public static String httpProtocolAndDomain(String url) { - int firstSlashAfterProtocol = url.indexOf('/', 8); - if (firstSlashAfterProtocol < 0) { - //must not have a path - return url; - } + /** + *

Returns the class object.
+ * + * @param the type of the desired class + * @param origClassName is fully qualified + * @return the class + */ + public static Class forName(final String origClassName) { + try { + return (Class) Class.forName(origClassName); + } catch (final Throwable t) { + throw new RuntimeException("Problem loading class: " + origClassName, t); + } + } - return url.substring(0, firstSlashAfterProtocol); - } + public static String readResourceFileContent(final String resourceName) { + try (final InputStream inputStream = CsrfGuardUtils.class.getClassLoader().getResourceAsStream(resourceName)) { + if (inputStream == null) { + throw new IllegalStateException("Could not find resource " + resourceName); + } else { + return readInputStreamContent(inputStream); + } + } catch (final IOException e) { + throw new RuntimeException(e); + } + } - /** - * helper method for calling a method with no params (could be in - * superclass) - * - * @param theClass - * the class which has the method - * @param invokeOn - * to call on or null for static - * @param methodName - * method name to call - * @return the data - */ - public static Object callMethod(Class theClass, Object invokeOn, - String methodName) { - return callMethod(theClass, invokeOn, methodName, null, null); - } + public static String readFileContent(final String fileNameWithAbsolutePath) { + try (final InputStream inputStream = new FileInputStream(fileNameWithAbsolutePath)) { + return readInputStreamContent(inputStream); + } catch (final IOException ioe) { + throw new RuntimeException(ioe); + } + } - /** - * helper method for calling a method (could be in superclass) - * - * @param theClass - * the class which has the method - * @param invokeOn - * to call on or null for static - * @param methodName - * method name to call - * @param paramTypesOrArrayOrList - * types of the params - * @param paramsOrListOrArray - * data - * @return the data - */ - public static Object callMethod(Class theClass, Object invokeOn, - String methodName, Object paramTypesOrArrayOrList, - Object paramsOrListOrArray) { - return callMethod(theClass, invokeOn, methodName, - paramTypesOrArrayOrList, paramsOrListOrArray, true); - } + /** + * Construct a class + * + * @param template type + * @param theClass the class on which to invoke newInstance() + * @return the instance + */ + public static T newInstance(final Class theClass) { + return ConfigPropertiesCascadeCommonUtils.newInstance(theClass); + } - /** - * helper method for calling a method - * - * @param theClass - * the class which has the method - * @param invokeOn - * to call on or null for static - * @param methodName - * method name to call - * @param paramTypesOrArrayOrList - * types of the params - * @param paramsOrListOrArray - * data - * @param callOnSupers - * if static and method not exists, try on supers - * @return the data - */ - public static Object callMethod(Class theClass, Object invokeOn, - String methodName, Object paramTypesOrArrayOrList, - Object paramsOrListOrArray, boolean callOnSupers) { - return callMethod(theClass, invokeOn, methodName, - paramTypesOrArrayOrList, paramsOrListOrArray, callOnSupers, - false); - } + public static void addResponseTokenHeader(final CsrfGuard csrfGuard, final HttpServletRequest httpServletRequest, final HttpServletResponse httpServletResponse, final TokenTO tokenTO) { + if (csrfGuard.isAjaxEnabled() && CsrfGuardUtils.isAjaxRequest(httpServletRequest)) { + if (!tokenTO.isEmpty()) { + httpServletResponse.setHeader(csrfGuard.getTokenName(), tokenTO.toString()); + } + } + } - /** - * helper method for calling a method - * - * @param theClass - * the class which has the method - * @param invokeOn - * to call on or null for static - * @param methodName - * method name to call - * @param paramTypesOrArrayOrList - * types of the params - * @param paramsOrListOrArray - * data - * @param callOnSupers - * if static and method not exists, try on supers - * @param overrideSecurity - * true to call on protected or private etc methods - * @return the data - */ - public static Object callMethod(Class theClass, Object invokeOn, - String methodName, Object paramTypesOrArrayOrList, - Object paramsOrListOrArray, boolean callOnSupers, - boolean overrideSecurity) { - try { - Method method = null; + public static boolean isAjaxRequest(final HttpServletRequest request) { + final Enumeration headers = request.getHeaders("X-Requested-With"); + return Objects.nonNull(headers) && Collections.list(headers).stream() + .flatMap(headerValue -> Arrays.stream(headerValue.split(","))) + .map(String::trim) + .anyMatch("XMLHttpRequest"::equals); + } - Class[] paramTypesArray = (Class[]) toArray(paramTypesOrArrayOrList); + public static String normalizeResourceURI(final HttpServletRequest httpServletRequest) { + return normalizeResourceURI(httpServletRequest.getRequestURI()); + } - try { - method = theClass.getDeclaredMethod(methodName, paramTypesArray); - if (overrideSecurity) { - method.setAccessible(true); - } - } catch (Exception e) { - // if method not found - if (e instanceof NoSuchMethodException) { - // if traversing up, and not Object, and not instance method - // CH 070425 not sure why invokeOn needs to be null, removing - // this - if (callOnSupers /* && invokeOn == null */ - && !theClass.equals(Object.class)) { - return callMethod(theClass.getSuperclass(), invokeOn, - methodName, paramTypesOrArrayOrList, - paramsOrListOrArray, callOnSupers, overrideSecurity); - } - } - throw new RuntimeException("Problem calling method " + methodName - + " on " + theClass.getName(), e); - } + public static String normalizeResourceURI(final String resourceURI) { + return resourceURI.startsWith("/") ? resourceURI : '/' + resourceURI; + } - return invokeMethod(method, invokeOn, paramsOrListOrArray); - } catch (RuntimeException re) { - String message = "Problem calling method " + methodName - + " on " + (theClass == null ? null : theClass.getName()); - if (injectInException(re, message)) { - throw re; - } - throw new RuntimeException(message, re); - } - } - - - /** - *
Returns the class object.
- * @param origClassName is fully qualified - * @return the class - */ - public static Class forName(String origClassName) { - - try { - return Class.forName(origClassName); - } catch (Throwable t) { - throw new RuntimeException("Problem loading class: " + origClassName, t); - } - - } - - public static String getInitParameter(ServletConfig servletConfig, String name, - String configFileDefaultParamValue, String defaultValue) { - String value = servletConfig.getInitParameter(name); - - if (value == null || "".equals(value.trim())) { - value = configFileDefaultParamValue; - } - - if (value == null || "".equals(value.trim())) { - value = defaultValue; - } - - return value; - } - - public static String readResourceFileContent(String resourceName, boolean errorIfNotFound) { - InputStream is = null; - - try { - is = CsrfGuardUtils.class.getClassLoader().getResourceAsStream(resourceName); - if(is == null) { - if (errorIfNotFound) { - throw new IllegalStateException("Could not find resource " + resourceName); - } - //not error if not found? then null - return null; - } - return readInputStreamContent(is); - } finally { - Streams.close(is); - } - } - public static String readFileContent(String fileName) { - InputStream is = null; - - try { - is = new FileInputStream(fileName); - return readInputStreamContent(is); - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } finally { - Streams.close(is); - } - } - public static String readInputStreamContent(InputStream is) { - StringBuilder sb = new StringBuilder(); - - try { - int i; - - while ((i = is.read()) > 0) { - sb.append((char) i); - } - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - - return sb.toString(); - } - - /** - * If we can, inject this into the exception, else return false - * @param t the throwable - * @param message the method to inject - * @return true if success, false if not - */ - public static boolean injectInException(Throwable t, String message) { - - //this is the field for sun java 1.5 - String throwableFieldName = "detailMessage"; - - try { - String currentValue = t.getMessage(); - if (!isBlank(currentValue)) { - currentValue += ",\n" + message; - } else { - currentValue = message; - } - assignField(t, throwableFieldName, currentValue); - return true; - } catch (Throwable t2) { - //dont worry about what the problem is, return false so the caller can log - return false; - } - - } - - /** - * See if the input is null or if string, if it is empty or blank (whitespace) - * @param input the object being tested for blank - * @return true if blank - */ - public static boolean isBlank(Object input) { - if (null == input) { - return true; - } - return (input instanceof String && isBlank((String)input)); - } - - /** - *

Checks if a String is whitespace, empty ("") or null.

- * - *
-	 * isBlank(null)      = true
-	 * isBlank("")        = true
-	 * isBlank(" ")       = true
-	 * isBlank("bob")     = false
-	 * isBlank("  bob  ") = false
-	 * 
- * - * @param str the String to check, may be null - * @return true if the String is null, empty or whitespace - * @since 2.0 - */ - public static boolean isBlank(String str) { - int strLen; - if (str == null || (strLen = str.length()) == 0) { - return true; - } - for (int i = 0; i < strLen; i++) { - if ((Character.isWhitespace(str.charAt(i)) == false)) { - return false; - } - } - return true; - } - - /** - * assign data to a field - * - * @param theClass - * the class which has the method - * @param invokeOn - * to call on or null for static - * @param fieldName - * method name to call - * @param dataToAssign - * data - * @param callOnSupers - * if static and method not exists, try on supers - * @param overrideSecurity - * true to call on protected or private etc methods - * @param typeCast - * true if we should typecast - * @param annotationWithValueOverride - * annotation with value of override - */ - public static void assignField(Class theClass, Object invokeOn, - String fieldName, Object dataToAssign, boolean callOnSupers, - boolean overrideSecurity, boolean typeCast, - Class annotationWithValueOverride) { - if (theClass == null && invokeOn != null) { - theClass = invokeOn.getClass(); - } - Field field = field(theClass, fieldName, callOnSupers, true); - assignField(field, invokeOn, dataToAssign, overrideSecurity, typeCast, - annotationWithValueOverride); - } - - /** - * Convert a list to an array with the type of the first element e.g. if it - * is a list of Person objects, then the array is Person[] - * - * @param objectOrArrayOrCollection - * is a list - * @return the array of objects with type of the first element in the list - */ - public static Object toArray(Object objectOrArrayOrCollection) { - // do this before length since if array with null in it, we want ti get - // it back - if (objectOrArrayOrCollection != null - && objectOrArrayOrCollection.getClass().isArray()) { - return objectOrArrayOrCollection; - } - int length = length(objectOrArrayOrCollection); - if (length == 0) { - return null; - } - - if (objectOrArrayOrCollection instanceof Collection) { - Collection collection = (Collection) objectOrArrayOrCollection; - Object first = collection.iterator().next(); - return toArray(collection, first == null ? Object.class : first - .getClass()); - } - // make an array of the type of object passed in, size one - Object array = Array.newInstance(objectOrArrayOrCollection.getClass(), - 1); - Array.set(array, 0, objectOrArrayOrCollection); - return array; - } - - /** - * Null safe array length or map - * - * @param arrayOrCollection an arrar, Collection, or Map - * @return the length of the array (0 for null, 1 for non-array non-collection objects) - */ - public static int length(Object arrayOrCollection) { - if (arrayOrCollection == null) { - return 0; - } - if (arrayOrCollection.getClass().isArray()) { - return Array.getLength(arrayOrCollection); - } - if (arrayOrCollection instanceof Collection) { - return ((Collection) arrayOrCollection).size(); - } - if (arrayOrCollection instanceof Map) { - return ((Map) arrayOrCollection).size(); - } - // simple non array non collection object - return 1; - } - - /** - * convert a list into an array of type of theClass - * @param is the type of the array - * @param collection list to convert - * @param theClass type of array to return - * @return array of type theClass[] filled with the objects from list - */ - @SuppressWarnings("unchecked") - public static T[] toArray(Collection collection, Class theClass) { - if (collection == null || collection.size() == 0) { - return null; - } - - return (T[])collection.toArray((Object[]) Array.newInstance(theClass, - collection.size())); - - } - - /** - * assign data to a field. Will find the field in superclasses, will - * typecast, and will override security (private, protected, etc) - * - * @param invokeOn - * to call on or null for static - * @param fieldName - * method name to call - * @param dataToAssign - * data - */ - public static void assignField(Object invokeOn, String fieldName, - Object dataToAssign) { - assignField(null, invokeOn, fieldName, dataToAssign, true, true, true, - null); - } - - /** pass this in the invokeOn to signify no params */ - private static final Object NO_PARAMS = new Object(); - - /** - * Safely invoke a reflection method that takes no args - * - * @param method - * to invoke - * @param invokeOn the object on which to invoke the method - * if NO_PARAMS then will not pass in params. - * @return the result - */ - public static Object invokeMethod(Method method, Object invokeOn) { - return invokeMethod(method, invokeOn, NO_PARAMS); - } - - /** - * Safely invoke a reflection method - * - * @param method - * to invoke - * @param invokeOn the object on which to invoke the method - * @param paramsOrListOrArray must be an arg. If null, will pass null. - * if NO_PARAMS then will not pass in params. - * @return the result - */ - public static Object invokeMethod(Method method, Object invokeOn, - Object paramsOrListOrArray) { - - Object[] args = paramsOrListOrArray == NO_PARAMS ? null : (Object[]) toArray(paramsOrListOrArray); - - //we want to make sure things are accessible - method.setAccessible(true); - - //only if the method exists, try to execute - Object result = null; - Exception e = null; - try { - result = method.invoke(invokeOn, args); - } catch (IllegalAccessException iae) { - e = iae; - } catch (IllegalArgumentException iae) { - e = iae; - } catch (InvocationTargetException ite) { - //this means the underlying call caused exception... its ok if runtime - if (ite.getCause() instanceof RuntimeException) { - throw (RuntimeException)ite.getCause(); - } - //else throw as invocation target... - e = ite; - } - if (e != null) { - throw new RuntimeException("Cant execute reflection method: " - + method.getName() + ", on: " + className(invokeOn) - + ", with args: " + classNameCollection(args), e); - } - return result; - } - - /** - * null safe classname method, gets the unenhanced name - * - * @param object the object for which to get the class name - * @return the classname - */ - public static String className(Object object) { - return object == null ? null : object.getClass() - .getName(); - } - - /** - * null safe classname method, max out at 20 - * - * @param object the collection - * @return the classname - */ - public static String classNameCollection(Object object) { - if (object == null) { - return null; - } - StringBuffer result = new StringBuffer(); - - Iterator iterator = iterator(object); - int length = length(object); - for (int i = 0; i < length && i < 20; i++) { - result.append(className(next(object, iterator, i))); - if (i != length - 1) { - result.append(", "); - } - } - return result.toString(); - } - - /** - * null safe iterator getter if the type if collection - * - * @param collection the collection for which to return an iterator - * @return the iterator - */ - public static Iterator iterator(Object collection) { - if (collection == null) { - return null; - } - // array list doesn't need an iterator - if (collection instanceof Collection - && !(collection instanceof ArrayList)) { - return ((Collection) collection).iterator(); - } - return null; - } - - /** - * If array, get the element based on index, if Collection, get it based on - * iterator. - * - * @param arrayOrCollection an array, ArraList, or Collection - * @param iterator the iterator for the collection - * @param index the index into the array - * @return the object at the specified index or iterator.next() - */ - public static Object next(Object arrayOrCollection, Iterator iterator, - int index) { - if (arrayOrCollection.getClass().isArray()) { - return Array.get(arrayOrCollection, index); - } - if (arrayOrCollection instanceof ArrayList) { - return ((ArrayList) arrayOrCollection).get(index); - } - if (arrayOrCollection instanceof Collection) { - return iterator.next(); - } - // simple object - if (0 == index) { - return arrayOrCollection; - } - throw new RuntimeException("Invalid class type: " - + arrayOrCollection.getClass().getName()); - } - - /** - * assign data to a field - * - * @param field - * is the field to assign to - * @param invokeOn - * to call on or null for static - * @param dataToAssign - * data - * @param overrideSecurity - * true to call on protected or private etc methods - * @param typeCast - * true if we should typecast - * @param annotationWithValueOverride - * annotation with value of override, or null if none - */ - @SuppressWarnings("unchecked") - public static void assignField(Field field, Object invokeOn, - Object dataToAssign, boolean overrideSecurity, boolean typeCast, - Class annotationWithValueOverride) { - - if (annotationWithValueOverride != null) { - // see if in annotation - Annotation annotation = field - .getAnnotation(annotationWithValueOverride); - if (annotation != null) { - - // type of the value, or String if not specific Class - // typeOfAnnotationValue = typeCast ? field.getType() : - // String.class; dataToAssign = - // AnnotationUtils.retrieveAnnotationValue( - // typeOfAnnotationValue, annotation, "value"); - - throw new RuntimeException("Not supported"); - } - } - assignField(field, invokeOn, dataToAssign, overrideSecurity, typeCast); - } - - /** - * get a field object for a class, potentially in superclasses - * - * @param theClass the class containing the desired field - * @param fieldName the name of the field - * @param callOnSupers - * true if superclasses should be looked in for the field - * @param throwExceptionIfNotFound - * will throw runtime exception if not found - * @return the field object or null if not found (or exception if param is - * set) - */ - public static Field field(Class theClass, String fieldName, - boolean callOnSupers, boolean throwExceptionIfNotFound) { - try { - Field field = theClass.getDeclaredField(fieldName); - // found it - return field; - } catch (NoSuchFieldException e) { - // if method not found - // if traversing up, and not Object, and not instance method - if (callOnSupers && !theClass.equals(Object.class)) { - return field(theClass.getSuperclass(), fieldName, callOnSupers, - throwExceptionIfNotFound); - } - } - // maybe throw an exception - if (throwExceptionIfNotFound) { - throw new RuntimeException("Cant find field: " + fieldName - + ", in: " + theClass + ", callOnSupers: " + callOnSupers); - } - return null; - } - - /** - * assign data to a field - * - * @param field - * is the field to assign to - * @param invokeOn - * to call on or null for static - * @param dataToAssign - * data - * @param overrideSecurity - * true to call on protected or private etc methods - * @param typeCast - * true if we should typecast - */ - public static void assignField(Field field, Object invokeOn, - Object dataToAssign, boolean overrideSecurity, boolean typeCast) { - - try { - Class fieldType = field.getType(); - // typecast - if (typeCast) { - dataToAssign = - typeCast(dataToAssign, fieldType, - true, true); - } - if (overrideSecurity) { - field.setAccessible(true); - } - field.set(invokeOn, dataToAssign); - } catch (Exception e) { - throw new RuntimeException("Cant assign reflection field: " - + (field == null ? null : field.getName()) + ", on: " - + className(invokeOn) + ", with args: " - + classNameCollection(dataToAssign), e); - } - } - - /** - * If necessary, convert an object to another type. if type is Object.class, just return the input. - * Do not convert null to an empty primitive - * @param is template type - * @param value the value object - * @param theClass the class type - * @return the object of that instance converted into something else - */ - public static T typeCast(Object value, Class theClass) { - //default behavior is not to convert null to empty primitive - return typeCast(value, theClass, false, false); - } - - /** - * If necessary, convert an object to another type. if type is Object.class, just return the input - * @param is the type to return - * @param value the value object - * @param theClass the class type - * @param convertNullToDefaultPrimitive if the value is null, and theClass is primitive, should we - * convert the null to a primitive default value - * @param useNewInstanceHooks if theClass is not recognized, then honor the string "null", "newInstance", - * or get a constructor with one param, and call it - * @return the object of that instance converted into something else - */ - @SuppressWarnings("unchecked") - public static T typeCast(Object value, Class theClass, - boolean convertNullToDefaultPrimitive, boolean useNewInstanceHooks) { - - if (Object.class.equals(theClass)) { - return (T)value; - } - - if (value==null) { - if (convertNullToDefaultPrimitive && theClass.isPrimitive()) { - if ( theClass == boolean.class ) { - return (T)Boolean.FALSE; - } - if ( theClass == char.class ) { - return (T)(Object)0; - } - //convert 0 to the type - return typeCast(0, theClass, false, false); - } - return null; - } - - if (theClass.isInstance(value)) { - return (T)value; - } - - //if array, get the base class - if (theClass.isArray() && theClass.getComponentType() != null) { - theClass = (Class)theClass.getComponentType(); - } - Object resultValue = null; - if (theClass.equals(String.class)) { - resultValue = value == null ? null : value.toString(); - } else if (theClass.equals(value.getClass())) { - resultValue = value; - } else { - throw new RuntimeException("Cannot convert from type: " + value.getClass() + " to type: " + theClass); - } - - return (T)resultValue; - } - - /** - * Construct a class - * @param template type - * @param theClass the class on which to invoke newInstance() - * @return the instance - */ - public static T newInstance(Class theClass) { - try { - return theClass.newInstance(); - } catch (Throwable e) { - if (theClass != null && Modifier.isAbstract(theClass.getModifiers())) { - throw new RuntimeException("Problem with class: " + theClass + ", maybe because it is abstract!", e); - } - throw new RuntimeException("Problem with class: " + theClass, e); - } - } - - /** - * close a connection null safe and don't throw exception - * @param connection the connection to close - */ - public static void closeQuietly(Connection connection) { - if (connection != null) { - try { - connection.close(); - } catch (Exception e) { - //ignore - } - } - } - - /** - * Unconditionally close an InputStream. - * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored. - * @param input A (possibly null) InputStream - */ - public static void closeQuietly(InputStream input) { - if (input == null) { - return; - } - - try { - input.close(); - } catch (IOException ioe) { - } - } - - /** - * Unconditionally close an OutputStream. - * Equivalent to {@link OutputStream#close()}, except any exceptions will be ignored. - * @param output A (possibly null) OutputStream - */ - public static void closeQuietly(OutputStream output) { - if (output == null) { - return; - } - - try { - output.close(); - } catch (IOException ioe) { - } - } - - /** - * Unconditionally close an Reader. - * Equivalent to {@link Reader#close()}, except any exceptions will be ignored. - * - * @param input A (possibly null) Reader to close - */ - public static void closeQuietly(Reader input) { - if (input == null) { - return; - } - - try { - input.close(); - } catch (IOException ioe) { - } - } - - /** - * close a resultSet null safe and dont throw exception - * @param resultSet the result set to close - */ - public static void closeQuietly(ResultSet resultSet) { - if (resultSet != null) { - try { - resultSet.close(); - } catch (Exception e) { - //ignore - } - } - } - - /** - * close a statement null safe and dont throw exception - * @param statement the statement to close - */ - public static void closeQuietly(Statement statement) { - if (statement != null) { - try { - statement.close(); - } catch (Exception e) { - //ignore - } - } - } - - /** - * close a writer quietly - * @param writer the writer to close - */ - public static void closeQuietly(Writer writer) { - if (writer != null) { - try { - writer.close(); - } catch (IOException e) { - //swallow, its ok - } - } - } - - /** - * close a writer quietly - * @param writer the xml stream writer to close - */ - public static void closeQuietly(XMLStreamWriter writer) { - if (writer != null) { - try { - writer.close(); - } catch (XMLStreamException e) { - //swallow, its ok - } - } - } - - /** - * print out various types of objects - * - * @param object the object for which to generate a string representation - * @return the string value - */ - public static String toStringForLog(Object object) { - StringBuilder result = new StringBuilder(); - toStringForLogHelper(object, -1, result); - return result.toString(); - } - - /** - * print out various types of objects - * - * @param object the object for which to generate a string representation - * @param maxChars is the max chars that should be returned (abbreviate if longer), or -1 for any amount - * @return the string value - */ - public static String toStringForLog(Object object, int maxChars) { - StringBuilder result = new StringBuilder(); - toStringForLogHelper(object, -1, result); - String resultString = result.toString(); - if (maxChars != -1) { - return abbreviate(resultString, maxChars); - } - return resultString; - } - - /** - * print out various types of objects - * - * @param object the object for which to generate a string representation - * @param maxChars is where it should stop when figuring out object. note, result might be longer than max... - * need to abbreviate when back - * @param result is where to append to - */ - private static void toStringForLogHelper(Object object, int maxChars, StringBuilder result) { - - try { - if (object == null) { - result.append("null"); - } else if (object.getClass().isArray()) { - // handle arrays - int length = Array.getLength(object); - if (length == 0) { - result.append("Empty array"); - } else { - result.append("Array size: ").append(length).append(": "); - for (int i = 0; i < length; i++) { - result.append("[").append(i).append("]: ").append( - toStringForLog(Array.get(object, i), maxChars)).append("\n"); - if (maxChars != -1 && result.length() > maxChars) { - return; - } - } - } - } else if (object instanceof Collection) { - //give size and type if collection - Collection collection = (Collection) object; - int collectionSize = collection.size(); - if (collectionSize == 0) { - result.append("Empty ").append(object.getClass().getSimpleName()); - } else { - result.append(object.getClass().getSimpleName()).append(" size: ").append(collectionSize).append(": "); - int i=0; - for (Object collectionObject : collection) { - result.append("[").append(i).append("]: ").append( - toStringForLog(collectionObject, maxChars)).append("\n"); - if (maxChars != -1 && result.length() > maxChars) { - return; - } - i++; - } - } - } else { - result.append(object.toString()); - } - } catch (Exception e) { - result.append("<> ").append(object.getClass()).append(":\n") - .append(getFullStackTrace(e)).append("\n"); - } - } - - /** - *

Abbreviates a String using ellipses. This will turn - * "Now is the time for all good men" into "Now is the time for..."

- * - *

Specifically:

- *
    - *
  • If str is less than maxWidth characters - * long, return it.
  • - *
  • Else abbreviate it to (substring(str, 0, max-3) + "...").
  • - *
  • If maxWidth is less than 4, throw an - * IllegalArgumentException.
  • - *
  • In no case will it return a String of length greater than - * maxWidth.
  • - *
- * - *
-	 * StringUtils.abbreviate(null, *)      = null
-	 * StringUtils.abbreviate("", 4)        = ""
-	 * StringUtils.abbreviate("abcdefg", 6) = "abc..."
-	 * StringUtils.abbreviate("abcdefg", 7) = "abcdefg"
-	 * StringUtils.abbreviate("abcdefg", 8) = "abcdefg"
-	 * StringUtils.abbreviate("abcdefg", 4) = "a..."
-	 * StringUtils.abbreviate("abcdefg", 3) = IllegalArgumentException
-	 * 
- * - * @param str the String to check, may be null - * @param maxWidth maximum length of result String, must be at least 4 - * @return abbreviated String, null if null String input - * @throws IllegalArgumentException if the width is too small - * @since 2.0 - */ - public static String abbreviate(String str, int maxWidth) { - return abbreviate(str, 0, maxWidth); - } - - /** - *

Abbreviates a String using ellipses. This will turn - * "Now is the time for all good men" into "...is the time for..."

- * - *

Works like abbreviate(String, int), but allows you to specify - * a "left edge" offset. Note that this left edge is not necessarily going to - * be the leftmost character in the result, or the first character following the - * ellipses, but it will appear somewhere in the result. - * - *

In no case will it return a String of length greater than - * maxWidth.

- * - *
-	 * StringUtils.abbreviate(null, *, *)                = null
-	 * StringUtils.abbreviate("", 0, 4)                  = ""
-	 * StringUtils.abbreviate("abcdefghijklmno", -1, 10) = "abcdefg..."
-	 * StringUtils.abbreviate("abcdefghijklmno", 0, 10)  = "abcdefg..."
-	 * StringUtils.abbreviate("abcdefghijklmno", 1, 10)  = "abcdefg..."
-	 * StringUtils.abbreviate("abcdefghijklmno", 4, 10)  = "abcdefg..."
-	 * StringUtils.abbreviate("abcdefghijklmno", 5, 10)  = "...fghi..."
-	 * StringUtils.abbreviate("abcdefghijklmno", 6, 10)  = "...ghij..."
-	 * StringUtils.abbreviate("abcdefghijklmno", 8, 10)  = "...ijklmno"
-	 * StringUtils.abbreviate("abcdefghijklmno", 10, 10) = "...ijklmno"
-	 * StringUtils.abbreviate("abcdefghijklmno", 12, 10) = "...ijklmno"
-	 * StringUtils.abbreviate("abcdefghij", 0, 3)        = IllegalArgumentException
-	 * StringUtils.abbreviate("abcdefghij", 5, 6)        = IllegalArgumentException
-	 * 
- * - * @param str the String to check, may be null - * @param offset left edge of source String - * @param maxWidth maximum length of result String, must be at least 4 - * @return abbreviated String, null if null String input - * @throws IllegalArgumentException if the width is too small - * @since 2.0 - */ - public static String abbreviate(String str, int offset, int maxWidth) { - if (str == null) { - return null; - } - if (maxWidth < 4) { - throw new IllegalArgumentException("Minimum abbreviation width is 4"); - } - if (str.length() <= maxWidth) { - return str; - } - if (offset > str.length()) { - offset = str.length(); - } - if ((str.length() - offset) < (maxWidth - 3)) { - offset = str.length() - (maxWidth - 3); - } - if (offset <= 4) { - return str.substring(0, maxWidth - 3) + "..."; - } - if (maxWidth < 7) { - throw new IllegalArgumentException("Minimum abbreviation width with offset is 7"); - } - if ((offset + (maxWidth - 3)) < str.length()) { - return "..." + abbreviate(str.substring(offset), maxWidth - 3); - } - return "..." + str.substring(str.length() - (maxWidth - 3)); - } - - /** - *

A way to get the entire nested stack-trace of an throwable.

- * - * @param throwable the Throwable to be examined - * @return the nested stack trace, with the root cause first - * @since 2.0 - */ - public static String getFullStackTrace(Throwable throwable) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw, true); - Throwable[] ts = getThrowables(throwable); - for (int i = 0; i < ts.length; i++) { - ts[i].printStackTrace(pw); - if (isNestedThrowable(ts[i])) { - break; - } - } - return sw.getBuffer().toString(); - } - - /** - *

Returns the list of Throwable objects in the - * exception chain.

- * - *

A throwable without cause will return an array containing - * one element - the input throwable. - * A throwable with one cause will return an array containing - * two elements. - the input throwable and the cause throwable. - * A null throwable will return an array size zero.

- * - * @param throwable the throwable to inspect, may be null - * @return the array of throwables, never null - */ - public static Throwable[] getThrowables(Throwable throwable) { - List list = new ArrayList(); - while (throwable != null) { - list.add(throwable); - throwable = getCause(throwable); - } - return (Throwable[]) list.toArray(new Throwable[list.size()]); - } - - /** - *

Checks whether this Throwable class can store a cause.

- * - *

This method does not check whether it actually does store a cause.

- * - * @param throwable the Throwable to examine, may be null - * @return boolean true if nested otherwise false - * @since 2.0 - */ - public static boolean isNestedThrowable(Throwable throwable) { - if (throwable == null) { - return false; - } - - if (throwable instanceof SQLException) { - return true; - } else if (throwable instanceof InvocationTargetException) { - return true; - } else if (isThrowableNested()) { - return true; - } - - Class cls = throwable.getClass(); - for (int i = 0, isize = CAUSE_METHOD_NAMES.length; i < isize; i++) { - try { - Method method = cls.getMethod(CAUSE_METHOD_NAMES[i], (Class[])null); - if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) { - return true; - } - } catch (NoSuchMethodException ignored) { - } catch (SecurityException ignored) { - } - } - - try { - Field field = cls.getField("detail"); - if (field != null) { - return true; - } - } catch (NoSuchFieldException ignored) { - } catch (SecurityException ignored) { - } - - return false; - } - - /** - *

The names of methods commonly used to access a wrapped exception.

- */ - private static String[] CAUSE_METHOD_NAMES = { - "getCause", - "getNextException", - "getTargetException", - "getException", - "getSourceException", - "getRootCause", - "getCausedByException", - "getNested", - "getLinkedException", - "getNestedException", - "getLinkedCause", - "getThrowable", - }; - - /** - *

Introspects the Throwable to obtain the cause.

- * - *

The method searches for methods with specific names that return a - * Throwable object. This will pick up most wrapping exceptions, - * including those from JDK 1.4, and Apache Commons Lang™ - * - * NestableException. - * - *

The default list searched for are:

- *
    - *
  • getCause()
  • - *
  • getNextException()
  • - *
  • getTargetException()
  • - *
  • getException()
  • - *
  • getSourceException()
  • - *
  • getRootCause()
  • - *
  • getCausedByException()
  • - *
  • getNested()
  • - *
- * - *

In the absence of any such method, the object is inspected for a - * detail field assignable to a Throwable.

- * - *

If none of the above is found, returns null.

- * - * @param throwable the throwable to introspect for a cause, may be null - * @return the cause of the Throwable, - * null if none found or null throwable input - * @since 1.0 - */ - public static Throwable getCause(Throwable throwable) { - return getCause(throwable, CAUSE_METHOD_NAMES); - } - - /** - *

Introspects the Throwable to obtain the cause.

- * - *
    - *
  1. Try known exception types.
  2. - *
  3. Try the supplied array of method names.
  4. - *
  5. Try the field 'detail'.
  6. - *
- * - *

A null set of method names means use the default set. - * A null in the set of method names will be ignored.

- * - * @param throwable the throwable to introspect for a cause, may be null - * @param methodNames the method names, null treated as default set - * @return the cause of the Throwable, - * null if none found or null throwable input - * @since 1.0 - */ - public static Throwable getCause(Throwable throwable, String[] methodNames) { - if (throwable == null) { - return null; - } - Throwable cause = getCauseUsingWellKnownTypes(throwable); - if (cause == null) { - if (methodNames == null) { - methodNames = CAUSE_METHOD_NAMES; - } - for (int i = 0; i < methodNames.length; i++) { - String methodName = methodNames[i]; - if (methodName != null) { - cause = getCauseUsingMethodName(throwable, methodName); - if (cause != null) { - break; - } - } - } - - if (cause == null) { - cause = getCauseUsingFieldName(throwable, "detail"); - } - } - return cause; - } - - /** - *

Finds a Throwable by field name.

- * - * @param throwable the exception to examine - * @param fieldName the name of the attribute to examine - * @return the wrapped exception, or null if not found - */ - private static Throwable getCauseUsingFieldName(Throwable throwable, String fieldName) { - Field field = null; - try { - field = throwable.getClass().getField(fieldName); - } catch (NoSuchFieldException ignored) { - } catch (SecurityException ignored) { - } - - if (field != null && Throwable.class.isAssignableFrom(field.getType())) { - try { - return (Throwable) field.get(throwable); - } catch (IllegalAccessException ignored) { - } catch (IllegalArgumentException ignored) { - } - } - return null; - } - - /** - *

Finds a Throwable by method name.

- * - * @param throwable the exception to examine - * @param methodName the name of the method to find and invoke - * @return the wrapped exception, or null if not found - */ - private static Throwable getCauseUsingMethodName(Throwable throwable, String methodName) { - Method method = null; - try { - method = throwable.getClass().getMethod(methodName, (Class[])null); - } catch (NoSuchMethodException ignored) { - } catch (SecurityException ignored) { - } - - if (method != null && Throwable.class.isAssignableFrom(method.getReturnType())) { - try { - return (Throwable) method.invoke(throwable, EMPTY_OBJECT_ARRAY); - } catch (IllegalAccessException ignored) { - } catch (IllegalArgumentException ignored) { - } catch (InvocationTargetException ignored) { - } - } - return null; - } - - /** - *

Finds a Throwable for known types.

- * - *

Uses instanceof checks to examine the exception, - * looking for well known types which could contain chained or - * wrapped exceptions.

- * - * @param throwable the exception to examine - * @return the wrapped exception, or null if not found - */ - private static Throwable getCauseUsingWellKnownTypes(Throwable throwable) { - if (throwable instanceof SQLException) { - return ((SQLException) throwable).getNextException(); - } else if (throwable instanceof InvocationTargetException) { - return ((InvocationTargetException) throwable).getTargetException(); - } else { - return null; - } - } - - /** - *

The Method object for JDK1.4 getCause.

- */ - private static final Method THROWABLE_CAUSE_METHOD; - static { - Method getCauseMethod; - try { - getCauseMethod = Throwable.class.getMethod("getCause", (Class[])null); - } catch (Exception e) { - getCauseMethod = null; - } - THROWABLE_CAUSE_METHOD = getCauseMethod; - } - - /** - *

Checks if the Throwable class has a getCause method.

- * - *

This is true for JDK 1.4 and above.

- * - * @return true if Throwable is nestable - * @since 2.0 - */ - public static boolean isThrowableNested() { - return THROWABLE_CAUSE_METHOD != null; - } - - /** - * An empty immutable Object array. - */ - public static final Object[] EMPTY_OBJECT_ARRAY = new Object[0]; - - /** - *

Returns either the passed in String, - * or if the String is null, an empty String ("").

- * - *
-	   * StringUtils.defaultString(null)  = ""
-	   * StringUtils.defaultString("")    = ""
-	   * StringUtils.defaultString("bat") = "bat"
-	   * 
- * - * @see String#valueOf(Object) - * @param str the String to check, may be null - * @return the passed in String, or the empty String if it - * was null - */ - public static String defaultString(String str) { - return str == null ? "" : str; - } - - @SuppressWarnings("unchecked") - public static T getMapKeyByValue(Map map, E value) { - for (Map.Entry entry : map.entrySet()) { - if (entry.getValue().equals(value)) { - return entry.getKey(); - } + private static String readInputStreamContent(final InputStream inputStream) { + try { + return IOUtils.toString(inputStream, Charset.defaultCharset()); + } catch (final IOException ioe) { + throw new RuntimeException(ioe); } - return null; } + /** + * for a url, get the protocol and domain, e.g. for url https://a.b/path, will return https://a.b + * + * @param url a string representing a URL + * @return the protocol and path + */ + private static String httpProtocolAndDomain(final String url) { + final int firstSlashAfterProtocol = url.indexOf('/', 8); // FIXME this should be rewritten.. + return firstSlashAfterProtocol < 0 ? url // must not have a path + : url.substring(0, firstSlashAfterProtocol); + } } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/MessageConstants.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/MessageConstants.java (.../MessageConstants.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/MessageConstants.java (.../MessageConstants.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,4 +1,4 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 * All rights reserved. @@ -30,20 +30,16 @@ /** * MessageConstants - Maintains all the message constant literals. - * - * @author - srijas - * @since - 11/7/2019. */ -public class MessageConstants { +public final class MessageConstants { private MessageConstants() { - //Utility Class + // Utility Class } - public static final String MISSING_TOKEN_MSG = "Required Token is missing from the Request"; + public static final String REQUEST_MISSING_TOKEN_MSG = "Required Token is missing from the Request"; public static final String MISMATCH_PAGE_TOKEN_MSG = "Request Token does not match Page Token"; - public static final String MISMATCH_SESSION_TOKEN_MSG = "Request Token does not match Session Token"; + public static final String MISMATCH_MASTER_TOKEN_MSG = "Request Token does not match the Master Token"; public static final String RANDOM_TOKEN_FAILURE_MSG = "Unable to generate the Random Token"; - public static final String SESSION_TOKEN_MSG = "CSRFGuard expects the token to exist in " + - "session at this point"; + public static final String TOKEN_MISSING_FROM_STORAGE_MSG = "The token should exist in the storage at this point"; } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/RandomGenerator.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/RandomGenerator.java (.../RandomGenerator.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/RandomGenerator.java (.../RandomGenerator.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,48 +26,46 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.util; +import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; -import java.security.NoSuchAlgorithmException; public final class RandomGenerator { - private final static char[] CHARSET = new char[] { 'A', 'B', 'C', 'D', 'E', + private static final char[] CHARSET = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; private RandomGenerator() { - /** - * Intentionally blank to force static usage - */ + /* Intentionally blank to force static usage */ } @Override public Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } - public static String generateRandomId(String prng, String provider, int len) throws NoSuchAlgorithmException, NoSuchProviderException { + public static String generateRandomId(final String prng, final String provider, final int len) throws NoSuchAlgorithmException, NoSuchProviderException { return generateRandomId(SecureRandom.getInstance(prng, provider), len); } - public static String generateRandomId(SecureRandom sr, int len) { - StringBuilder sb = new StringBuilder(); + public static String generateRandomId(final SecureRandom secureRandom, final int len) { + final StringBuilder sb = new StringBuilder(); for (int i = 1; i < len + 1; i++) { - int index = sr.nextInt(CHARSET.length); - char c = CHARSET[index]; + final int index = secureRandom.nextInt(CHARSET.length); + final char c = CHARSET[index]; sb.append(c); - if ((i % 4) == 0 && i != 0 && i < len) { + if ((i % 4) == 0 && i < len) { sb.append('-'); } } return sb.toString(); } - } Index: 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/RegexValidationUtil.java =================================================================== diff -u -r0c1d8c6e66d5b95ff3487b8362c86f629c42d88b -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/RegexValidationUtil.java (.../RegexValidationUtil.java) (revision 0c1d8c6e66d5b95ff3487b8362c86f629c42d88b) +++ 3rdParty_sources/csrfguard/org/owasp/csrfguard/util/RegexValidationUtil.java (.../RegexValidationUtil.java) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -1,19 +1,19 @@ -/** +/* * The OWASP CSRFGuard Project, BSD License - * Eric Sheridan (eric@infraredsecurity.com), Copyright (c) 2011 + * Copyright (c) 2011, Eric Sheridan (eric@infraredsecurity.com) * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of OWASP nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific - * prior written permission. + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of OWASP nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE @@ -26,6 +26,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ + package org.owasp.csrfguard.util; /** @@ -34,18 +35,18 @@ * @author - srijas * @since - 11/7/2019. */ -public class RegexValidationUtil { +public final class RegexValidationUtil { private RegexValidationUtil() { - //Utility Class + // Utility Class } /** * see if a test path starts with ^ and ends with $ thus making it a regex * @param testPath The path string to test * @return true if regex (starts with "^" and ends with "$") */ - public static boolean isTestPathRegex(String testPath) { + public static boolean isTestPathRegex(final String testPath) { return testPath != null && testPath.startsWith("^") && testPath.endsWith("$"); } } Fisheye: Tag d25fe80a3034172a51168d74cd1476895df0e8cd refers to a dead (removed) revision in file `3rdParty_sources/csrfguard/org/owasp/csrfguard/util/SessionUtils.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag d25fe80a3034172a51168d74cd1476895df0e8cd refers to a dead (removed) revision in file `3rdParty_sources/csrfguard/org/owasp/csrfguard/util/Streams.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag d25fe80a3034172a51168d74cd1476895df0e8cd refers to a dead (removed) revision in file `3rdParty_sources/csrfguard/org/owasp/csrfguard/util/Strings.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag d25fe80a3034172a51168d74cd1476895df0e8cd refers to a dead (removed) revision in file `3rdParty_sources/csrfguard/org/owasp/csrfguard/util/TokenUtils.java'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag d25fe80a3034172a51168d74cd1476895df0e8cd refers to a dead (removed) revision in file `3rdParty_sources/csrfguard/org/owasp/csrfguard/util/Writers.java'. Fisheye: No comparison available. Pass `N' to diff? Index: 3rdParty_sources/versions.txt =================================================================== diff -u -rc5558ac236e59c76783daa2e4337da7f09d8549a -rd25fe80a3034172a51168d74cd1476895df0e8cd --- 3rdParty_sources/versions.txt (.../versions.txt) (revision c5558ac236e59c76783daa2e4337da7f09d8549a) +++ 3rdParty_sources/versions.txt (.../versions.txt) (revision d25fe80a3034172a51168d74cd1476895df0e8cd) @@ -25,7 +25,7 @@ Commons Validator 1.6 -CSRF Guard master from 2020.01.07 with a custom modification in CsrfGuard.java +CSRF Guard 4.1.3 Etherpad Client 1.2.13