SEBSERV-342 fixed with filter
This commit is contained in:
parent
ec4215b944
commit
340a61504d
5 changed files with 83 additions and 15 deletions
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 ETH Zürich, Educational Development and Technology (LET)
|
||||||
|
*
|
||||||
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ch.ethz.seb.sebserver.gui;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.Filter;
|
||||||
|
import javax.servlet.FilterChain;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.ServletRequest;
|
||||||
|
import javax.servlet.ServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Component
|
||||||
|
@GuiProfile
|
||||||
|
public class CrossOriginIsolationFilter implements Filter {
|
||||||
|
|
||||||
|
private static final String SAME_ORIGIN = "same-origin";
|
||||||
|
private static final String REQUIRE_CORP = "require-corp";
|
||||||
|
private static final String CROSS_ORIGIN_OPENER_POLICY = "Cross-Origin-Opener-Policy";
|
||||||
|
private static final String CROSS_ORIGIN_EMBEDDER_POLICY = "Cross-Origin-Embedder-Policy";
|
||||||
|
|
||||||
|
private final String adminEndpoint;
|
||||||
|
private final String examEndpoint;
|
||||||
|
|
||||||
|
public CrossOriginIsolationFilter(
|
||||||
|
@Value("${sebserver.webservice.api.exam.endpoint:/exam-api}") final String examEndpoint,
|
||||||
|
@Value("${sebserver.webservice.api.admin.endpoint:/admin-api/v1}") final String adminEndpoint) {
|
||||||
|
|
||||||
|
this.adminEndpoint = adminEndpoint;
|
||||||
|
this.examEndpoint = examEndpoint;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doFilter(
|
||||||
|
final ServletRequest request,
|
||||||
|
final ServletResponse response,
|
||||||
|
final FilterChain chain) throws IOException, ServletException {
|
||||||
|
|
||||||
|
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
processResponse((HttpServletRequest) request, (HttpServletResponse) response);
|
||||||
|
chain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void processResponse(final HttpServletRequest request, final HttpServletResponse response) {
|
||||||
|
final String url = request.getRequestURI();
|
||||||
|
|
||||||
|
if (url.startsWith(this.adminEndpoint) || url.startsWith(this.examEndpoint)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
response.setHeader(CROSS_ORIGIN_EMBEDDER_POLICY, REQUIRE_CORP);
|
||||||
|
response.setHeader(CROSS_ORIGIN_OPENER_POLICY, SAME_ORIGIN);
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||||
|
import org.springframework.security.web.access.channel.ChannelProcessingFilter;
|
||||||
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
import org.springframework.security.web.util.matcher.OrRequestMatcher;
|
||||||
import org.springframework.security.web.util.matcher.RequestMatcher;
|
import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||||
|
@ -30,6 +31,8 @@ public class GuiWebsecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private InstitutionalAuthenticationEntryPoint institutionalAuthenticationEntryPoint;
|
private InstitutionalAuthenticationEntryPoint institutionalAuthenticationEntryPoint;
|
||||||
|
@Autowired
|
||||||
|
private CrossOriginIsolationFilter crossOriginIsolationFilter;
|
||||||
|
|
||||||
@Value("${sebserver.gui.entrypoint:/gui}")
|
@Value("${sebserver.gui.entrypoint:/gui}")
|
||||||
private String guiEntryPoint;
|
private String guiEntryPoint;
|
||||||
|
@ -84,7 +87,10 @@ public class GuiWebsecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
.logout().disable()
|
.logout().disable()
|
||||||
.headers().frameOptions().disable()
|
.headers().frameOptions().disable()
|
||||||
.and()
|
.and()
|
||||||
.csrf().disable();
|
.csrf()
|
||||||
|
.disable()
|
||||||
|
// TODO Set filter to dedicated URL
|
||||||
|
.addFilterBefore(this.crossOriginIsolationFilter, ChannelProcessingFilter.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,6 @@ public class ProctoringServlet extends HttpServlet {
|
||||||
log.error("Failed to get proctoring window script for data: {}", proctoringData);
|
log.error("Failed to get proctoring window script for data: {}", proctoringData);
|
||||||
resp.getOutputStream().println("Failed to get proctoring window script");
|
resp.getOutputStream().println("Failed to get proctoring window script");
|
||||||
} else {
|
} else {
|
||||||
RAPConfiguration.setCORS(resp);
|
|
||||||
resp.getOutputStream().println(script);
|
resp.getOutputStream().println(script);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -87,7 +86,6 @@ public class ProctoringServlet extends HttpServlet {
|
||||||
protected void doOptions(final HttpServletRequest req, final HttpServletResponse resp)
|
protected void doOptions(final HttpServletRequest req, final HttpServletResponse resp)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
|
||||||
RAPConfiguration.setCORS(resp);
|
|
||||||
resp.setStatus(HttpServletResponse.SC_OK);
|
resp.setStatus(HttpServletResponse.SC_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,8 +125,6 @@ public class RAPConfiguration implements ApplicationConfiguration {
|
||||||
final EntryPointService entryPointService = webApplicationContext
|
final EntryPointService entryPointService = webApplicationContext
|
||||||
.getBean(EntryPointService.class);
|
.getBean(EntryPointService.class);
|
||||||
entryPointService.loadProctoringView(parent);
|
entryPointService.loadProctoringView(parent);
|
||||||
final HttpServletResponse response = RWT.getResponse();
|
|
||||||
setCORS(response);
|
|
||||||
} else {
|
} else {
|
||||||
final HttpServletResponse response = RWT.getResponse();
|
final HttpServletResponse response = RWT.getResponse();
|
||||||
response.setStatus(HttpStatus.FORBIDDEN.value());
|
response.setStatus(HttpStatus.FORBIDDEN.value());
|
||||||
|
@ -136,16 +134,6 @@ public class RAPConfiguration implements ApplicationConfiguration {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://developer.chrome.com/blog/enabling-shared-array-buffer/#cross-origin-isolation
|
|
||||||
public static final void setCORS(final HttpServletResponse resp) {
|
|
||||||
// resp.addHeader("Access-Control-Allow-Origin", "*");
|
|
||||||
// resp.setHeader("Access-Control-Allow-Methods", "GET");
|
|
||||||
// resp.setHeader("Vary", "Origin");
|
|
||||||
|
|
||||||
resp.addHeader("Cross-Origin-Embedder-Policy", "require-corp");
|
|
||||||
resp.addHeader("Cross-Origin-Opener-Policy", "same-origin");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class RAPSpringEntryPointFactory implements EntryPointFactory {
|
public static final class RAPSpringEntryPointFactory implements EntryPointFactory {
|
||||||
|
|
||||||
private boolean initialized = false;
|
private boolean initialized = false;
|
||||||
|
|
|
@ -195,6 +195,9 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO check if this is needed. If not remove it.
|
||||||
|
// This gets called many times for a page load
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final ResponseEntity<String> forEntity =
|
final ResponseEntity<String> forEntity =
|
||||||
this.restTemplate.getForEntity(this.currentUserURI, String.class);
|
this.restTemplate.getForEntity(this.currentUserURI, String.class);
|
||||||
|
|
Loading…
Reference in a new issue