Skip to content

Commit

Permalink
Added headers to response roda 6 (#3271)
Browse files Browse the repository at this point in the history
  • Loading branch information
carlosjepard authored Aug 8, 2024
1 parent 0d0c112 commit 938b5d3
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public static RequestContext parseHTTPRequest(HttpServletRequest request) {
RequestContext requestContext = new RequestContext();

// get user
User user = UserUtility.getApiUser(request);
User user = UserUtility.getUser(request, true);

// get headers
RequestHeaders headers = new RequestHeaders();
Expand Down
33 changes: 33 additions & 0 deletions roda-ui/roda-wui/src/main/java/org/roda/wui/config/RodaConfig.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package org.roda.wui.config;

import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import org.apereo.cas.client.session.SingleSignOutHttpSessionListener;
import org.roda.wui.filter.OnOffFilter;
import org.roda.wui.filter.SecurityHeadersFilter;
import org.roda.wui.servlets.ContextListener;
import org.roda.wui.servlets.RodaWuiServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.boot.web.servlet.server.CookieSameSiteSupplier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
Expand Down Expand Up @@ -168,6 +173,34 @@ public FilterRegistrationBean<OnOffFilter> casWebAuthFilter() {
return registrationBean;
}

@Bean
public FilterRegistrationBean<SecurityHeadersFilter> securityHeadersFilter() {
FilterRegistrationBean<SecurityHeadersFilter> registrationBean = new FilterRegistrationBean<>();
registrationBean.setFilter(new SecurityHeadersFilter());
registrationBean.addUrlPatterns("/*"); // Apply the filter to all requests
return registrationBean;
}

@Bean
public ServletContextInitializer servletContextInitializer() {
return new ServletContextInitializer() {

@Override
public void onStartup(ServletContext servletContext) throws ServletException {
servletContext.getSessionCookieConfig().setSecure(true);
servletContext.getSessionCookieConfig().setHttpOnly(true);
}
};
}

@Configuration(proxyBeanMethods = false)
public class SameSiteConfiguration {
@Bean
public CookieSameSiteSupplier applicationCookieSameSiteSupplier() {
return CookieSameSiteSupplier.ofStrict();
}
}

@Configuration
public static class DefaultView implements WebMvcConfigurer {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package org.roda.wui.filter;

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.http.HttpServletResponse;

public class SecurityHeadersFilter implements Filter {

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;

httpServletResponse.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
httpServletResponse.setHeader("Content-Security-Policy",
"default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://www.google.com " +
"https://www.google-analytics.com https://www.gstatic.com; style-src 'self' 'unsafe-inline'; " +
"img-src 'self'; font-src 'self';");
httpServletResponse.setHeader("X-XSS-Protection", "1; mode=block");
httpServletResponse.setHeader("X-Permitted-Cross-Domain-Policies", "none");
httpServletResponse.setHeader("Feature-Policy", "camera 'none'; fullscreen 'self'; geolocation *; " +
"microphone 'self'");
httpServletResponse.setHeader("X-Frame-Options", "SAMEORIGIN");
httpServletResponse.setHeader("X-Content-Type-Options", "nosniff");
httpServletResponse.setHeader("Referrer-Policy", "no-referrer");
httpServletResponse.setHeader("Permissions-Policy", "geolocation=(self)");

chain.doFilter(request, response);
}

@Override
public void init(FilterConfig filterConfig) {
}

@Override
public void destroy() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,16 @@
// Change cookie consent options on the fly.
var OPTIONS_UPDATER = 'update_cookieconsent_options';

// Name of cookie to be set when dismissed
var DISMISSED_COOKIE = 'cookieconsent_dismissed';
// Key used to store consent status in localStorage
var DISMISSED_KEY = 'cookieconsent_dismissed';

// The path to built in themes
// Note: Directly linking to a version on the CDN like this is horrible, but it's less horrible than people downloading the code
// then discovering that their CSS bucket disappeared
var THEME_BUCKET_PATH = '//cdnjs.cloudflare.com/ajax/libs/cookieconsent2/1.0.10/';

// No point going further if they've already dismissed.
if (document.cookie.indexOf(DISMISSED_COOKIE) > -1 || (window.navigator && window.navigator.CookiesOK)) {
if (localStorage.getItem(DISMISSED_KEY) || (window.navigator && window.navigator.CookiesOK)) {
return;
}

Expand Down Expand Up @@ -93,25 +93,8 @@
return null;
},

setCookie: function (name, value, expiryDays, domain, path) {
expiryDays = expiryDays || 365;

var exdate = new Date();
exdate.setDate(exdate.getDate() + expiryDays);

var cookie = [
name + '=' + value,
'expires=' + exdate.toUTCString(),
'path=' + path || '/'
];

if (domain) {
cookie.push(
'domain=' + domain
);
}

document.cookie = cookie.join(';');
setLocalStorage: function (key, value) {
localStorage.setItem(key, value);
},

addEventListener: function (el, event, eventListener) {
Expand Down Expand Up @@ -332,12 +315,12 @@
dismiss: function (evt) {
evt.preventDefault && evt.preventDefault();
evt.returnValue = false;
this.setDismissedCookie();
this.setDismissed();
this.container.removeChild(this.element);
},

setDismissedCookie: function () {
Util.setCookie(DISMISSED_COOKIE, 'yes', this.options.expiryDays, this.options.domain, this.options.path);
setDismissed: function () {
Util.setLocalStorage(DISMISSED_KEY, 'yes');
}
};

Expand Down

0 comments on commit 938b5d3

Please sign in to comment.