Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions repository/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,22 @@
<artifactId>log4j-core</artifactId>
<scope>provided</scope>
</dependency>

<!-- include both servlet-api variants since we need their annotations -->
<!-- application container will pick up the class(es) with the annotations it supports and ignore the other(s) -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>5.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/**
* Copyright (C) 2016 - 2026 Order of the Bee
*
* This file is part of OOTBee Support Tools
*
* OOTBee Support Tools is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OOTBee Support Tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OOTBee Support Tools. If not, see
* <http://www.gnu.org/licenses/>.
*
* Linked to Alfresco
* Copyright (C) 2005 - 2026 Alfresco Software Limited.
*/
package org.orderofthebee.addons.support.tools.repo.spring;

import java.util.List;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.extensions.config.source.UrlConfigSource;

/**
* This Spring bean definition registry post processor enhanced the {@code webscripts.configsource} {@link UrlConfigSource} bean definition
* to include a custom file provided by our module.
*
* @author Axel Faust
*/
public class WebScriptConfigSourceEnhancer implements BeanDefinitionRegistryPostProcessor
{

private static final String REFERENCE_SOURCE_URL = "classpath:alfresco/web-client-security-config.xml";

private static final String OOTBEE_SOURCE_URL = "classpath:alfresco/module/ootbee-support-tools-repo/web-client-security-config.xml";

/**
* {@inheritDoc}
*/
@Override
public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException
{
// NO-OP
}

/**
* {@inheritDoc}
*/
@Override
public void postProcessBeanDefinitionRegistry(final BeanDefinitionRegistry registry) throws BeansException
{
if (registry.containsBeanDefinition("webscripts.configsource"))
{
final BeanDefinition beanDefinition = registry.getBeanDefinition("webscripts.configsource");
final ConstructorArgumentValues constructorArgumentValues = beanDefinition.getConstructorArgumentValues();
final List<ValueHolder> argumentValues = constructorArgumentValues.getGenericArgumentValues();
for (final ValueHolder argumentValue : argumentValues)
{
final Object source = argumentValue.getValue();
if (source instanceof List<?>)
{
@SuppressWarnings("unchecked")
final List<Object> urls = (List<Object>) source;
for (int i = 0; i < urls.size(); i++)
{
final Object urlCandidate = urls.get(i);
// we want to add our config after the default and before any extension file
if (REFERENCE_SOURCE_URL.equals(urlCandidate) || (urlCandidate instanceof TypedStringValue
&& ((TypedStringValue) urlCandidate).getValue().equals(REFERENCE_SOURCE_URL)))
{
urls.add(i + 1, OOTBEE_SOURCE_URL);
break;
}
}
break;
}
}
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* Copyright (C) 2016 - 2026 Order of the Bee
*
* This file is part of OOTBee Support Tools
*
* OOTBee Support Tools is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OOTBee Support Tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OOTBee Support Tools. If not, see
* <http://www.gnu.org/licenses/>.
*
* Linked to Alfresco
* Copyright (C) 2005 - 2026 Alfresco Software Limited.
*/
package org.orderofthebee.addons.support.tools.repo.web;

import java.io.IOException;

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;

/**
* This filter extends coverage of Alfresco CSRF handling to admin console web scripts of this addon.
*
* @author Axel Faust
*/
@WebFilter(filterName = "OOTBee CRSF Token Filter", urlPatterns = { "/service/ootbee/admin/*", "/s/ootbee/admin/*",
"/wcservice/ootbee/admin/*", "/wcs/ootbee/admin/*" })
public class JakartaCsrfFilter implements Filter
{

private Filter actualFilter;

/**
* {@inheritDoc}
*/
@Override
public void init(final FilterConfig filterConfig) throws ServletException
{
try
{
final Class<?> cls = Class.forName("org.springframework.extensions.webscripts.servlet.CSRFFilter");
this.actualFilter = (Filter) cls.newInstance();
}
catch (final ClassNotFoundException | InstantiationException | IllegalAccessException | ClassCastException e)
{
throw new ServletException("Failed to instantiate actual filter", e);
}
this.actualFilter.init(filterConfig);
}

/**
* {@inheritDoc}
*/
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain)
throws IOException, ServletException
{
this.actualFilter.doFilter(request, response, chain);
}

/**
* {@inheritDoc}
*/
@Override
public void destroy()
{
this.actualFilter.destroy();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* Copyright (C) 2016 - 2026 Order of the Bee
*
* This file is part of OOTBee Support Tools
*
* OOTBee Support Tools is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OOTBee Support Tools is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with OOTBee Support Tools. If not, see
* <http://www.gnu.org/licenses/>.
*
* Linked to Alfresco
* Copyright (C) 2005 - 2026 Alfresco Software Limited.
*/
package org.orderofthebee.addons.support.tools.repo.web;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;

/**
* This filter extends coverage of Alfresco CSRF handling to admin console web scripts of this addon.
*
* @author Axel Faust
*/
@WebFilter(filterName = "OOTBee CRSF Token Filter", urlPatterns = { "/service/ootbee/admin/*", "/s/ootbee/admin/*",
"/wcservice/ootbee/admin/*", "/wcs/ootbee/admin/*" })
public class JavaxCsrfFilter implements Filter
{

private Filter actualFilter;

/**
* {@inheritDoc}
*/
@Override
public void init(final FilterConfig filterConfig) throws ServletException
{
try
{
final Class<?> cls = Class.forName("org.springframework.extensions.webscripts.servlet.CSRFFilter");
this.actualFilter = (Filter) cls.newInstance();
}
catch (final ClassNotFoundException | InstantiationException | IllegalAccessException | ClassCastException e)
{
throw new ServletException("Failed to instantiate actual filter", e);
}
this.actualFilter.init(filterConfig);
}

/**
* {@inheritDoc}
*/
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException
{
this.actualFilter.doFilter(request, response, chain);
}

/**
* {@inheritDoc}
*/
@Override
public void destroy()
{
this.actualFilter.destroy();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,74 @@ var Admin = Admin || {};
_ids[key] = id;
};

// disabled default CSRF config
Admin.CSRF = {
enabled: false,
cookie: "",
header: "",
parameter: "",
properties: {}
};

/**
* Returns the CSRF token.
*
* Note! Make sure to use this method just before a request is made against the server since it might have been
* updated in another browser tab or window.
*
* @method CSRFToken
* @return {String} The CSRF token or null if not enable or not defined.
*/
Admin.CSRFToken = function CSRFToken()
{
var token = null, cookieName = Admin.CSRF.getCookie();
if (cookieName)
{
var matches = document.cookie.match(new RegExp("(?:^|; )" + cookieName + "=([^;]*)"));
if (matches)
{
// remove quotes to support Jetty app-server - bug where it quotes a valid cookie value see ALF-18823
token = decodeURIComponent(matches[1]).replace(/"/g, '');
}
}
return token;
};

Admin.CSRF.getCookie = function getCookie()
{
return Admin.substitute(Admin.CSRF.cookie, Admin.CSRF.properties || {});
};

Admin.CSRF.getParameter= function getParameter()
{
return Admin.substitute(Admin.CSRF.parameter, Admin.CSRF.properties || {});
};

Admin.CSRF.getHeader = function getHeader()
{
return Admin.substitute(Admin.CSRF.header, Admin.CSRF.properties || {});
};

/**
* Simple string substitution helper. Replaces simple instances of templated strings {name} within a string from
* a property object. Each key in the property object is replaced in the string with it's value if match is found.
*
* @param str String to replace into
* @param properties Object of key/value pairs to replace templates values with
*/
Admin.substitute = function substitute(str, properties)
{
var prop;
for (prop in properties)
{
if (properties.hasOwnProperty(prop))
{
str = str.replace("{" + prop + "}", properties[prop]);
}
}
return str;
};

/**
* String trim helper
*
Expand Down Expand Up @@ -318,6 +386,10 @@ var Admin = Admin || {};
req.overrideMimeType((config.responseContentType ? config.responseContentType : "application/json") + "; charset=utf-8");
}
req.open(config.method ? config.method : "GET", config.url);
if ((config.method === "POST" || config.method === "PUT") && Admin.CSRF.enabled)
{
req.setRequestHeader(Admin.CSRF.getHeader(), Admin.CSRFToken());
}
req.setRequestHeader("Content-Type", (config.requestContentType ? config.requestContentType : "application/json") + ";charset=UTF-8");
req.setRequestHeader("Accept", config.responseContentType ? config.responseContentType : "application/json");
req.onreadystatechange = function()
Expand Down Expand Up @@ -442,6 +514,10 @@ var Admin = Admin || {};
form.enctype = "multipart/form-data";
form.target = iframe.name;
form.action = url;
if (Admin.CSRF.enabled)
{
form.action += "?" + Admin.CSRF.getParameter() + "=" + encodeURIComponent(Admin.CSRFToken());
}
form.appendChild(file);
form.submit();
};
Expand Down Expand Up @@ -477,6 +553,14 @@ var Admin = Admin || {};
// get the root form element
var form = el(_ids.formId);

// add CSRF token if enabled
if (Admin.CSRF.enabled)
{
var url = form.attributes.action.value;
url += (url.lastIndexOf('?') === -1 ? "?" : "&") + Admin.CSRF.getParameter() + "=" + encodeURIComponent(Admin.CSRFToken());
form.attributes.action.value = url;
}

// ensure ENTER press in a Form field doesn't submit the Form
Admin.addEventListener(form, 'keypress', function(e)
{
Expand Down
Loading
Loading