diff --git a/src/main/java/org/olat/admin/security/SecurityAdminController.java b/src/main/java/org/olat/admin/security/SecurityAdminController.java index 0c8b51e889c03e70b51afe0f28bd14ff160f8a4d..bec26974dd994fb3dbfac87b5435ebe9c1f8f1d3 100644 --- a/src/main/java/org/olat/admin/security/SecurityAdminController.java +++ b/src/main/java/org/olat/admin/security/SecurityAdminController.java @@ -39,8 +39,17 @@ import org.olat.core.gui.control.WindowControl; * */ public class SecurityAdminController extends FormBasicController { + + private static final String[] keys = new String[]{ "on" }; + private static final String[] values = new String[]{ "" }; + + private MultipleSelectionElement wikiEl; + private MultipleSelectionElement topFrameEl; + private MultipleSelectionElement forceDownloadEl; - private MultipleSelectionElement wikiEl, topFrameEl, forceDownloadEl, xFrameOptionsSameoriginEl; + private MultipleSelectionElement strictTransportSecurityEl; + private MultipleSelectionElement xContentTypeOptionsEl; + private MultipleSelectionElement xFrameOptionsSameoriginEl; private final FolderModule folderModule; private final BaseSecurityModule securityModule; @@ -57,9 +66,6 @@ public class SecurityAdminController extends FormBasicController { setFormTitle("sec.title"); setFormDescription("sec.description"); setFormContextHelp("Security"); - - String[] keys = new String[]{ "on" }; - String[] values = new String[]{ "" }; // on: force top top frame (more security); off: allow in frame (less security) topFrameEl = uifactory.addCheckboxesHorizontal("sec.topframe", "sec.topframe", formLayout, keys, values); @@ -70,18 +76,36 @@ public class SecurityAdminController extends FormBasicController { // on: send HTTP header X-FRAME-OPTIONS -> SAMEDOMAIN to prevent click-jack attacks. JS-top frame hack not save enough xFrameOptionsSameoriginEl = uifactory.addCheckboxesHorizontal("sec.xframe.sameorigin", "sec.xframe.sameorigin", formLayout, keys, values); - xFrameOptionsSameoriginEl.select("off", securityModule.isXFrameOptionsSameoriginEnabled()); xFrameOptionsSameoriginEl.addActionListener(FormEvent.ONCHANGE); + if(securityModule.isXFrameOptionsSameoriginEnabled()) { + xFrameOptionsSameoriginEl.select("on", true); + } + + strictTransportSecurityEl = uifactory.addCheckboxesHorizontal("sec.strict.transport.sec", "sec.strict.transport.sec", formLayout, keys, values); + strictTransportSecurityEl.addActionListener(FormEvent.ONCHANGE); + if(securityModule.isStrictTransportSecurityEnabled()) { + strictTransportSecurityEl.select("on", true); + } + + xContentTypeOptionsEl = uifactory.addCheckboxesHorizontal("sec.content.type.options", "sec.content.type.options", formLayout, keys, values); + xContentTypeOptionsEl.addActionListener(FormEvent.ONCHANGE); + if(securityModule.isXContentTypeOptionsEnabled()) { + xContentTypeOptionsEl.select("on", true); + } // on: block wiki (more security); off: do not block wiki (less security) wikiEl = uifactory.addCheckboxesHorizontal("sec.wiki", "sec.wiki", formLayout, keys, values); - wikiEl.select("off", securityModule.isWikiEnabled()); wikiEl.addActionListener(FormEvent.ONCHANGE); + if(!securityModule.isWikiEnabled()) { + wikiEl.select("on", true); + } // on: force file download in folder component (more security); off: allow execution of content (less security) forceDownloadEl = uifactory.addCheckboxesHorizontal("sec.download", "sec.force.download", formLayout, keys, values); - forceDownloadEl.select("on", folderModule.isForceDownload()); forceDownloadEl.addActionListener(FormEvent.ONCHANGE); + if(folderModule.isForceDownload()) { + forceDownloadEl.select("on", true); + } } @Override @@ -95,16 +119,17 @@ public class SecurityAdminController extends FormBasicController { boolean enabled = topFrameEl.isAtLeastSelected(1); securityModule.setForceTopFrame(enabled); } else if(wikiEl == source) { - boolean enabled = wikiEl.isAtLeastSelected(1); - securityModule.setWikiEnabled(!enabled); + securityModule.setWikiEnabled(!wikiEl.isAtLeastSelected(1)); // update collaboration tools list CollaborationToolsFactory.getInstance().initAvailableTools(); } else if(xFrameOptionsSameoriginEl == source) { - boolean enabled = xFrameOptionsSameoriginEl.isAtLeastSelected(1); - securityModule.setXFrameOptionsSameoriginEnabled(enabled); + securityModule.setXFrameOptionsSameoriginEnabled(xFrameOptionsSameoriginEl.isAtLeastSelected(1)); + } else if(strictTransportSecurityEl == source) { + securityModule.setStrictTransportSecurity(strictTransportSecurityEl.isAtLeastSelected(1)); + } else if(xContentTypeOptionsEl == source) { + securityModule.setxContentTypeOptions(xContentTypeOptionsEl.isAtLeastSelected(1)); } else if(forceDownloadEl == source) { - boolean enabled = forceDownloadEl.isAtLeastSelected(1); - folderModule.setForceDownload(enabled); + folderModule.setForceDownload(forceDownloadEl.isAtLeastSelected(1)); } super.formInnerEvent(ureq, source, event); } diff --git a/src/main/java/org/olat/admin/security/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/security/_i18n/LocalStrings_de.properties index 817a54b88c9cd0586c794f24bb8b5e090f8e11b1..d7fd22ec743661360bed55211e6f2932c1e8dbe7 100644 --- a/src/main/java/org/olat/admin/security/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/admin/security/_i18n/LocalStrings_de.properties @@ -1,10 +1,12 @@ #Tue Jan 14 11:03:57 CET 2014 admin.menu.title=Sicherheit admin.menu.title.alt=Sicherheitseinstellungen anpassen +sec.content.type.options=Verhindert Browser Script und Style Dateien mit HTTP Header zu raten sec.description=W\u00E4hlen Sie den notwendigen Sicherheitslevel je nach Anforderungen Ihrer Institution. Um die h\u00F6chste Sicherheitsstufe zu erreichen m\u00FCssen s\u00E4mtliche untenstehenden Sicherheitsfunktionen eingeschaltet sein. sec.force.download=Dateidownload in Ordner erzwingen sec.title=Sicherheitseinstellungen sec.topframe=Frame Einbettung per JavaScript verhindern +sec.strict.transport.sec=Verhindern HTTPS zu HTTP downgrade mit HTTP Header sec.wiki=Wiki Ressourcen blockieren sec.top.frame.explanation=Aus Kompatibilit\u00e4tsgr\u00fcnden k\u00F6nnen einige Komponenten von OpenOLAT (TinyMCE) nicht in einem Frame dargestellt werden. sec.xframe.sameorigin=Frame Einbettung mit HTTP header X-FRAME-OPTIONS=SAMEDOMAIN verhindern diff --git a/src/main/java/org/olat/admin/security/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/security/_i18n/LocalStrings_en.properties index f0f7cf2fa42dfef4826d706078d7e44c899f7eb1..29a3b47408e4442df5c934dd14344a9d2c89c549 100644 --- a/src/main/java/org/olat/admin/security/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/admin/security/_i18n/LocalStrings_en.properties @@ -1,11 +1,13 @@ #Thu Aug 06 11:28:42 CEST 2009 admin.menu.title=Security admin.menu.title.alt=Change security settings +sec.content.type.options=Prevent browser to guess script and style content with HTTP header sec.title=Security settings sec.description=Choose the security level depending on the requirements of your institution. To achieve the highest security level, all of the security features listed below have to be activated. sec.force.download=Force file download in folders sec.topframe=Prevent embedding in frames using JavaScript code sec.wiki=Block wiki resources +sec.strict.transport.sec=Prevent downgrade of HTTPS to HTTP with HTTP header sec.top.frame.explanation=Due to compatibility reasons, the rich text component (TinyMCE) of OpenOLAT cannot be embedded in a frame. sec.xframe.sameorigin=Prevent embedding in frames by sending HTTP header X-FRAME-OPTIONS=SAMEDOMAIN diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityModule.java b/src/main/java/org/olat/basesecurity/BaseSecurityModule.java index d7ceaabd90a8a27e958628b1e4074eeeeb71916c..8829e0c54262cae6da7d498eae8022a7985e3e2a 100644 --- a/src/main/java/org/olat/basesecurity/BaseSecurityModule.java +++ b/src/main/java/org/olat/basesecurity/BaseSecurityModule.java @@ -73,28 +73,31 @@ public class BaseSecurityModule extends AbstractSpringModule { /** The feature is enabled, always */ private static final String FORCE_TOP_FRAME = "forceTopFrame"; private static final String X_FRAME_OPTIONS_SAMEORIGIN = "xFrameOptionsSameOrigin"; + private static final String STRICT_TRANSPORT_SECURITY = "strictTransportSecurity"; + private static final String X_CONTENT_TYPES_OPTIONS = "xContentTypeOptions"; + private static final String CONTENT_SECURITY_POLICY = "contentSecurityPolicy"; private static final String WIKI_ENABLED = "wiki"; /** * default values */ - public static Boolean USERMANAGER_CAN_CREATE_USER = true; - public static Boolean USERMANAGER_CAN_DELETE_USER = false; - public static Boolean USERMANAGER_CAN_CREATE_PWD = true; - public static Boolean USERMANAGER_CAN_MODIFY_PWD = true; - public static Boolean USERMANAGER_CAN_START_GROUPS = true; - public static Boolean USERMANAGER_CAN_MODIFY_SUBSCRIPTIONS = true; - public static Boolean USERMANAGER_ACCESS_TO_QUOTA = true; - public static Boolean USERMANAGER_ACCESS_TO_PROP = false; - public static Boolean USERMANAGER_ACCESS_TO_AUTH = false; - public static Boolean USERMANAGER_CAN_MANAGE_POOLMANAGERS = true; - public static Boolean USERMANAGER_CAN_MANAGE_GROUPMANAGERS = true; - public static Boolean USERMANAGER_CAN_MANAGE_INSTITUTIONAL_RESOURCE_MANAGER = true; - public static Boolean USERMANAGER_CAN_MANAGE_AUTHORS = true; - public static Boolean USERMANAGER_CAN_MANAGE_GUESTS = false; - public static Boolean USERMANAGER_CAN_MANAGE_STATUS = true; - public static Boolean USERMANAGER_CAN_BYPASS_EMAILVERIFICATION = true; - public static Boolean USERMANAGER_CAN_EDIT_ALL_PROFILE_FIELDS = true; + public static final Boolean USERMANAGER_CAN_CREATE_USER = true; + public static final Boolean USERMANAGER_CAN_DELETE_USER = false; + public static final Boolean USERMANAGER_CAN_CREATE_PWD = true; + public static final Boolean USERMANAGER_CAN_MODIFY_PWD = true; + public static final Boolean USERMANAGER_CAN_START_GROUPS = true; + public static final Boolean USERMANAGER_CAN_MODIFY_SUBSCRIPTIONS = true; + public static final Boolean USERMANAGER_ACCESS_TO_QUOTA = true; + public static final Boolean USERMANAGER_ACCESS_TO_PROP = false; + public static final Boolean USERMANAGER_ACCESS_TO_AUTH = false; + public static final Boolean USERMANAGER_CAN_MANAGE_POOLMANAGERS = true; + public static final Boolean USERMANAGER_CAN_MANAGE_GROUPMANAGERS = true; + public static final Boolean USERMANAGER_CAN_MANAGE_INSTITUTIONAL_RESOURCE_MANAGER = true; + public static final Boolean USERMANAGER_CAN_MANAGE_AUTHORS = true; + public static final Boolean USERMANAGER_CAN_MANAGE_GUESTS = false; + public static final Boolean USERMANAGER_CAN_MANAGE_STATUS = true; + public static final Boolean USERMANAGER_CAN_BYPASS_EMAILVERIFICATION = true; + public static final Boolean USERMANAGER_CAN_EDIT_ALL_PROFILE_FIELDS = true; private static String defaultAuthProviderIdentifier; @@ -136,9 +139,17 @@ public class BaseSecurityModule extends AbstractSpringModule { @Value("${userinfos.tunnelcoursebuildingblock}") private String userInfosTunnelCourseBuildingBlock; - private String forceTopFrame = "disabled"; - private String xFrameOptionsSameorigin = "disabled"; - private String wikiEnabled = "enabled"; + @Value("${base.security.wiki:enabled}") + private String wikiEnabled; + @Value("${base.security.frameOptionsSameOrigine:disabled}") + private String xFrameOptionsSameorigin; + @Value("${base.security.strictTransportSecurity:disabled}") + private String strictTransportSecurity; + @Value("${base.security.xContentTypeOptions:disabled}") + private String xContentTypeOptions; + @Value("${base.security.contentSecurityPolicy:disabled}") + private String contentSecurityPolicy; + @Autowired public BaseSecurityModule(CoordinatorManager coordinatorManager) { @@ -239,15 +250,23 @@ public class BaseSecurityModule extends AbstractSpringModule { if(StringHelper.containsNonWhitespace(enabled)) { userInfosTunnelCourseBuildingBlock = enabled; } - - enabled = getStringPropertyValue(FORCE_TOP_FRAME, true); - if(StringHelper.containsNonWhitespace(enabled)) { - forceTopFrame = enabled; - } + enabled = getStringPropertyValue(X_FRAME_OPTIONS_SAMEORIGIN, true); if(StringHelper.containsNonWhitespace(enabled)) { xFrameOptionsSameorigin = enabled; } + enabled = getStringPropertyValue(STRICT_TRANSPORT_SECURITY, true); + if(StringHelper.containsNonWhitespace(enabled)) { + strictTransportSecurity = enabled; + } + enabled = getStringPropertyValue(X_CONTENT_TYPES_OPTIONS, true); + if(StringHelper.containsNonWhitespace(enabled)) { + xContentTypeOptions = enabled; + } + enabled = getStringPropertyValue(CONTENT_SECURITY_POLICY, true); + if(StringHelper.containsNonWhitespace(enabled)) { + contentSecurityPolicy = enabled; + } enabled = getStringPropertyValue(WIKI_ENABLED, true); if(StringHelper.containsNonWhitespace(enabled)) { wikiEnabled = enabled; @@ -462,7 +481,7 @@ public class BaseSecurityModule extends AbstractSpringModule { } public boolean isForceTopFrame() { - return true;//"enabled".equals(forceTopFrame); + return true; } public void setForceTopFrame(boolean enable) { @@ -474,17 +493,49 @@ public class BaseSecurityModule extends AbstractSpringModule { return "enabled".equals(wikiEnabled); } - public boolean isXFrameOptionsSameoriginEnabled() { - return "enabled".equals(xFrameOptionsSameorigin); - } - public void setWikiEnabled(boolean enable) { String enabled = enable ? "enabled" : "disabled"; + wikiEnabled = enabled; setStringProperty(WIKI_ENABLED, enabled, true); } + public boolean isXFrameOptionsSameoriginEnabled() { + return "enabled".equals(xFrameOptionsSameorigin); + } + public void setXFrameOptionsSameoriginEnabled(boolean enable) { String enabled = enable ? "enabled" : "disabled"; + xFrameOptionsSameorigin = enabled; setStringProperty(X_FRAME_OPTIONS_SAMEORIGIN, enabled, true); } + + public boolean isStrictTransportSecurityEnabled() { + return "enabled".equals(strictTransportSecurity); + } + + public void setStrictTransportSecurity(boolean enable) { + String enabled = enable ? "enabled" : "disabled"; + strictTransportSecurity = enabled; + setStringProperty(STRICT_TRANSPORT_SECURITY, enabled, true); + } + + public boolean isXContentTypeOptionsEnabled() { + return "enabled".equals(xContentTypeOptions); + } + + public void setxContentTypeOptions(boolean enable) { + String enabled = enable ? "enabled" : "disabled"; + xContentTypeOptions = enabled; + setStringProperty(X_CONTENT_TYPES_OPTIONS, enabled, true); + } + + public boolean isContentSecurityPolicyEnabled() { + return "enabled".equals(contentSecurityPolicy); + } + + public void setContentSecurityPolicy(boolean enable) { + String enabled = enable ? "enabled" : "disabled"; + contentSecurityPolicy = enabled; + setStringProperty(CONTENT_SECURITY_POLICY, enabled, true); + } } \ No newline at end of file diff --git a/src/main/java/org/olat/core/gui/control/winmgr/AjaxController.java b/src/main/java/org/olat/core/gui/control/winmgr/AjaxController.java index 003a053c58d43d9cdb4c681de165eddc2c36010d..d6a4a1aa1753654ff6f34af18232eb44fe4a8cbb 100644 --- a/src/main/java/org/olat/core/gui/control/winmgr/AjaxController.java +++ b/src/main/java/org/olat/core/gui/control/winmgr/AjaxController.java @@ -116,10 +116,10 @@ public class AjaxController extends DefaultController { this.wboImpl = wboImpl; pollPeriodContent = new VelocityContainer("jsserverpartpoll", VELOCITY_ROOT + "/pollperiod.html", null, this); - pollPeriodContent.contextPut("pollperiod", new Integer(pollperiod)); + pollPeriodContent.contextPut("pollperiod", Integer.valueOf(pollperiod)); myContent = new VelocityContainer("jsserverpart", VELOCITY_ROOT + "/serverpart.html", null, this); - myContent.contextPut("pollperiod", new Integer(pollperiod)); + myContent.contextPut("pollperiod", Integer.valueOf(pollperiod)); //more debug information: OLAT-3529 if (ajaxEnabled) myContent.contextPut("isAdmin", Boolean.valueOf(ureq.getUserSession().getRoles().isOLATAdmin())); @@ -200,14 +200,13 @@ public class AjaxController extends DefaultController { StringMediaResource smr = new StringMediaResource(); smr.setContentType("text/html;charset=utf-8"); smr.setEncoding("utf-8"); - try { - - StringOutput slink = new StringOutput(50); + try(StringOutput slink = new StringOutput(50); + StringOutput blink = new StringOutput(50)) { + StaticMediaDispatcher.renderStaticURI(slink, null); //slink now holds static url base like /olat/raw/700/ URLBuilder ubu = new URLBuilder(WebappHelper.getServletContextPath() + DispatcherModule.PATH_AUTHENTICATED, "1", "1"); - StringOutput blink = new StringOutput(50); ubu.buildURI(blink, null, null); //blink holds the link back to olat like /olat/auth/1%3A1%3A0%3A0%3A0/ @@ -224,7 +223,7 @@ public class AjaxController extends DefaultController { } catch (Exception e) { smr.setData(e.toString()); - }; + } return smr; } }; @@ -257,9 +256,7 @@ public class AjaxController extends DefaultController { // -> in all cases, do not show the json command, but reload the window which contained the link clicked (= window id of url) .append(" try{ parent.window.o_removeIframe(document.defaultView.frameElement.id); } catch(e) {} ") .append("} else {") - // inform user that ajax-request cannot be opened in a new window, - // todo felix: maybe send back request to bookmark-launch current url? -> new window? - // we could then come near to what the user probably wanted when he/she opened a link in a new window + // inform user that ajax-request cannot be opened in a new window .append("this.document.location=\"") .append(StaticMediaDispatcher.createStaticURIFor("msg/json/en/info.html")) .append("\";") @@ -339,9 +336,7 @@ public class AjaxController extends DefaultController { // c) ... // -> in all cases, do not show the json command, but reload the window which contained the link clicked (= window id of url) .append("} else {") - // inform user that ajax-request cannot be opened in a new window, - // todo felix: maybe send back request to bookmark-launch current url? -> new window? - // we could then come near to what the user probably wanted when he/she opened a link in a new window + // inform user that ajax-request cannot be opened in a new window .append(" this.document.location=\"").append(StaticMediaDispatcher.createStaticURIFor("msg/json/en/info.html")).append("\";") .append("}}") .append("\n/* ]]> */\n</script></head><body onLoad=\"invoke()\"></body></html>"); @@ -414,7 +409,7 @@ public class AjaxController extends DefaultController { */ @Override protected void doDispose() { - List<MapperKey> mappers = new ArrayList<MapperKey>(); + List<MapperKey> mappers = new ArrayList<>(); mappers.add(mKey); mappers.add(sbmKey); CoreSpringFactory.getImpl(MapperService.class).cleanUp(mappers); diff --git a/src/main/java/org/olat/core/gui/media/ServletUtil.java b/src/main/java/org/olat/core/gui/media/ServletUtil.java index 6b2ec1c1ca2abaf0b58e55449c11f21e1fd5cc1b..05379379cf231fc32664b16c76a0a5a1e47f3133 100644 --- a/src/main/java/org/olat/core/gui/media/ServletUtil.java +++ b/src/main/java/org/olat/core/gui/media/ServletUtil.java @@ -45,7 +45,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.IOUtils; -import org.olat.basesecurity.BaseSecurityModule; import org.olat.core.CoreSpringFactory; import org.olat.core.gui.Windows; import org.olat.core.gui.render.StringOutput; @@ -63,10 +62,6 @@ import org.olat.core.util.session.UserSessionManager; */ public class ServletUtil { private static final OLog log = Tracing.createLoggerFor(ServletUtil.class); - private static final BaseSecurityModule securityModule = CoreSpringFactory.getImpl(BaseSecurityModule.class); - - private static final String KEY_X_FRAME_OPTION = "X-FRAME-OPTIONS"; - private static final String VALUE_SAMEORIGIN = "SAMEORIGIN"; public static final long CACHE_NO_CACHE = 0l; public static final long CACHE_ONE_HOUR = 60l * 60l; @@ -105,8 +100,6 @@ public class ServletUtil { */ public static void serveResource(HttpServletRequest httpReq, HttpServletResponse httpResp, MediaResource mr) { boolean debug = log.isDebug(); - - setXFrameHeader(httpResp); try { Long lastModified = mr.getLastModified(); if (lastModified != null) { @@ -469,7 +462,6 @@ public class ServletUtil { */ public static void serveStringResource(HttpServletRequest httpReq, HttpServletResponse response, String result) { setStringResourceHeaders(response); - setXFrameHeader(response); // log the response headers prior to sending the output boolean isDebug = log.isDebug(); @@ -528,7 +520,6 @@ public class ServletUtil { public static void serveStringResource(HttpServletResponse response, StringOutput result) { setStringResourceHeaders(response); - setXFrameHeader(response); // log the response headers prior to sending the output boolean isDebug = log.isDebug(); @@ -563,18 +554,6 @@ public class ServletUtil { } } - /** - * Set the X-FRAME-OPTIONS header to SAMEORIGIN if the security module is - * configured to add this header - * - * @param response - */ - public static void setXFrameHeader(HttpServletResponse response) { - if (securityModule.isXFrameOptionsSameoriginEnabled()) { - response.setHeader(KEY_X_FRAME_OPTION, VALUE_SAMEORIGIN); - } - } - public static void setStringResourceHeaders(HttpServletResponse response) { // we ignore the accept-charset from the request and always write in utf-8 // -> see comment below diff --git a/src/main/java/org/olat/core/servlets/HeadersFilter.java b/src/main/java/org/olat/core/servlets/HeadersFilter.java new file mode 100644 index 0000000000000000000000000000000000000000..eb7519c89b79afdcb779e5ba86eda030bd7d1600 --- /dev/null +++ b/src/main/java/org/olat/core/servlets/HeadersFilter.java @@ -0,0 +1,63 @@ +/** + * <p> + * Copyright (c) frentix GmbH<br> + * http://www.frentix.com<br> + */ +package org.olat.core.servlets; + +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.http.HttpServletResponse; + +import org.olat.basesecurity.BaseSecurityModule; +import org.olat.core.CoreSpringFactory; + +/** + * + * + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + */ +public class HeadersFilter implements Filter { + + private BaseSecurityModule securityModule; + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + // + } + + @Override + public void destroy() { + // + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + if(securityModule == null) { + securityModule = CoreSpringFactory.getImpl(BaseSecurityModule.class); + } + addSecurityHeaders(response); + chain.doFilter(request, response); + } + + private void addSecurityHeaders(ServletResponse response) { + if(response instanceof HttpServletResponse) { + HttpServletResponse httpResponse = (HttpServletResponse)response; + if(securityModule.isStrictTransportSecurityEnabled()) { + httpResponse.setHeader("Strict-Transport-Security", "max-age=31536000; includeSubDomains"); + } + if(securityModule.isXContentTypeOptionsEnabled()) { + httpResponse.setHeader("X-Content-Type-Options", "nosniff"); + } + if (securityModule.isXFrameOptionsSameoriginEnabled()) { + httpResponse.setHeader("X-FRAME-OPTIONS", "SAMEORIGIN"); + } + } + } +} \ No newline at end of file diff --git a/src/main/webapp-tomcat/WEB-INF/web.xml b/src/main/webapp-tomcat/WEB-INF/web.xml index 7c0d385909dee88be9c88aa4f706430352c94f8a..13364d944e468b1226422bbd32c6a4cca4371f6b 100644 --- a/src/main/webapp-tomcat/WEB-INF/web.xml +++ b/src/main/webapp-tomcat/WEB-INF/web.xml @@ -42,6 +42,11 @@ <filter-class>org.olat.restapi.security.RestApiLoginFilter</filter-class> </filter> + <filter> + <filter-name>HeadersFilter</filter-name> + <filter-class>org.olat.core.servlets.HeadersFilter</filter-class> + </filter> + <!-- The mapping to the Login filter REST API --> <filter-mapping> <filter-name>PaypalIPNFilter</filter-name> @@ -52,6 +57,11 @@ <filter-name>RESTApiLoginFilter</filter-name> <url-pattern>/restapi/*</url-pattern> </filter-mapping> + + <filter-mapping> + <filter-name>HeadersFilter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> <!-- 3. Listeners --> <!-- triggers the above spring files to be processed by the spring framework --> diff --git a/src/main/webapp-wildfly/WEB-INF/web.xml b/src/main/webapp-wildfly/WEB-INF/web.xml index 52e67b1a0c4a7e68c6f679070ff7defb59a676cf..987cff64b0de1f92d6699c002eece95e71bf7b32 100644 --- a/src/main/webapp-wildfly/WEB-INF/web.xml +++ b/src/main/webapp-wildfly/WEB-INF/web.xml @@ -47,6 +47,11 @@ <filter-class>org.olat.restapi.security.RestApiLoginFilter</filter-class> </filter> + <filter> + <filter-name>HeadersFilter</filter-name> + <filter-class>org.olat.core.servlets.HeadersFilter</filter-class> + </filter> + <filter> <filter-name>Resteasy</filter-name> <filter-class> @@ -73,8 +78,12 @@ <filter-name>Resteasy</filter-name> <url-pattern>/restapi/*</url-pattern> </filter-mapping> - + <filter-mapping> + <filter-name>HeadersFilter</filter-name> + <url-pattern>/*</url-pattern> + </filter-mapping> + <!-- 3. Listeners --> <!-- triggers the above spring files to be processed by the spring framework --> <listener> diff --git a/src/test/profile/mysql/olat.local.properties b/src/test/profile/mysql/olat.local.properties index 8a2a7d6d0383c890c64e3c5ebb9ddc01d091aec3..ae69c889ea67b39e8a584448f98d19fd14330bcd 100644 --- a/src/test/profile/mysql/olat.local.properties +++ b/src/test/profile/mysql/olat.local.properties @@ -76,4 +76,9 @@ group.accept.membership.groupmanagers=false group.accept.membership.administrators=false #make sure the test for QTI 1.2 works -qti12.create.resources.enabled=true \ No newline at end of file +qti12.create.resources.enabled=true + +#security +base.security.frameOptionsSameOrigine=enabled +base.security.strictTransportSecurity=enabled +base.security.xContentTypeOptions=enabled diff --git a/src/test/profile/postgresql/olat.local.properties b/src/test/profile/postgresql/olat.local.properties index 94c154777bfb6bbf2de0515eccf21dc858f23d47..500272f3fa6a627f0d46d240be9578e0547c3297 100644 --- a/src/test/profile/postgresql/olat.local.properties +++ b/src/test/profile/postgresql/olat.local.properties @@ -77,4 +77,9 @@ group.accept.membership.groupmanagers=false group.accept.membership.administrators=false #make sure the test for QTI 1.2 works -qti12.create.resources.enabled=true \ No newline at end of file +qti12.create.resources.enabled=true + +#security +base.security.frameOptionsSameOrigine=enabled +base.security.strictTransportSecurity=enabled +base.security.xContentTypeOptions=enabled