added check endpoint and fixed gui endpoint

This commit is contained in:
anhefti 2021-03-25 20:47:58 +01:00
parent e73dd5105a
commit 9d5ed34ec6
6 changed files with 105 additions and 63 deletions

View file

@ -40,6 +40,9 @@ import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
@Order(7)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements ErrorController {
private static final String ERROR_PATH = "/sebserver/error";
private static final String CHECK_PATH = "/sebserver/check";
@Value("${sebserver.webservice.http.redirect.gui}")
private String guiRedirect;
@Value("${sebserver.webservice.api.exam.endpoint.discovery}")
@ -78,22 +81,27 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E
public void configure(final WebSecurity web) {
web
.ignoring()
.antMatchers("/error")
.antMatchers(ERROR_PATH)
.antMatchers(CHECK_PATH)
.antMatchers(this.examAPIDiscoveryEndpoint)
.antMatchers(this.adminAPIEndpoint + API.INFO_ENDPOINT + API.LOGO_PATH_SEGMENT + "/**")
.antMatchers(this.adminAPIEndpoint + API.INFO_ENDPOINT + API.INFO_INST_PATH_SEGMENT + "/**")
.antMatchers(this.adminAPIEndpoint + API.REGISTER_ENDPOINT);
}
@RequestMapping("/error")
@RequestMapping(CHECK_PATH)
public void check() throws IOException {
}
@RequestMapping(ERROR_PATH)
public void handleError(final HttpServletResponse response) throws IOException {
//response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
response.getOutputStream().print(response.getStatus());
response.setHeader(HttpHeaders.LOCATION, this.guiRedirect);
response.flushBuffer();
}
@Override
public String getErrorPath() {
return "/error";
return ERROR_PATH;
}
}

View file

@ -116,60 +116,56 @@ public final class InstitutionalAuthenticationEntryPoint implements Authenticati
final String institutionalEndpoint = extractInstitutionalEndpoint(request);
if (StringUtils.isNoneBlank(institutionalEndpoint) && log.isDebugEnabled()) {
log.debug("No default gui entrypoint requested: {}", institutionalEndpoint);
} else {
request.getSession().setAttribute(INST_SUFFIX_ATTRIBUTE, null);
request.getSession().removeAttribute(API.PARAM_LOGO_IMAGE);
forwardToEntryPoint(request, response, this.guiEntryPoint, false);
return;
}
try {
final RestTemplate restTemplate = new RestTemplate();
final List<EntityName> institutions = restTemplate
.exchange(
this.webserviceURIService.getURIBuilder()
.path(API.INFO_ENDPOINT + API.INFO_INST_ENDPOINT)
.toUriString(),
HttpMethod.GET,
HttpEntity.EMPTY,
new ParameterizedTypeReference<List<EntityName>>() {
},
institutionalEndpoint,
API.INFO_PARAM_INST_SUFFIX,
institutionalEndpoint)
.getBody();
if (institutions != null && !institutions.isEmpty()) {
request.getSession().setAttribute(
INST_SUFFIX_ATTRIBUTE,
StringUtils.isNotBlank(institutionalEndpoint)
? institutionalEndpoint
: null);
if (log.isDebugEnabled()) {
log.debug("Known and active gui entrypoint requested: {}", institutions);
}
final String logoImageBase64 = requestLogoImage(institutionalEndpoint);
if (StringUtils.isNotBlank(logoImageBase64)) {
request.getSession().setAttribute(API.PARAM_LOGO_IMAGE, logoImageBase64);
}
forwardToEntryPoint(request, response, this.guiEntryPoint, false);
return;
if (StringUtils.isNotBlank(institutionalEndpoint)) {
if (log.isDebugEnabled()) {
log.debug("No default gui entrypoint requested: {}", institutionalEndpoint);
}
} catch (final Exception e) {
log.error("Failed to extract and set institutional endpoint request: ", e);
try {
final RestTemplate restTemplate = new RestTemplate();
final List<EntityName> institutions = restTemplate
.exchange(
this.webserviceURIService.getURIBuilder()
.path(API.INFO_ENDPOINT + API.INFO_INST_ENDPOINT)
.toUriString(),
HttpMethod.GET,
HttpEntity.EMPTY,
new ParameterizedTypeReference<List<EntityName>>() {
},
institutionalEndpoint,
API.INFO_PARAM_INST_SUFFIX,
institutionalEndpoint)
.getBody();
if (institutions != null && !institutions.isEmpty()) {
request.getSession().setAttribute(
INST_SUFFIX_ATTRIBUTE,
StringUtils.isNotBlank(institutionalEndpoint)
? institutionalEndpoint
: null);
if (log.isDebugEnabled()) {
log.debug("Known and active gui entrypoint requested: {}", institutions);
}
final String logoImageBase64 = requestLogoImage(institutionalEndpoint);
if (StringUtils.isNotBlank(logoImageBase64)) {
request.getSession().setAttribute(API.PARAM_LOGO_IMAGE, logoImageBase64);
}
forwardToEntryPoint(request, response, this.guiEntryPoint, false);
return;
}
} catch (final Exception e) {
log.error("Failed to extract and set institutional endpoint request: ", e);
}
}
request.getSession().setAttribute(INST_SUFFIX_ATTRIBUTE, null);
request.getSession().removeAttribute(API.PARAM_LOGO_IMAGE);
response.setStatus(HttpStatus.UNAUTHORIZED.value());
forwardToEntryPoint(request, response, this.guiEntryPoint, true);
forwardToEntryPoint(request, response, this.guiEntryPoint, institutionalEndpoint == null);
}
@ -203,16 +199,25 @@ public final class InstitutionalAuthenticationEntryPoint implements Authenticati
public static String extractInstitutionalEndpoint(final HttpServletRequest request) {
final String requestURI = request.getRequestURI();
if (StringUtils.isBlank(requestURI) || requestURI.equals(Constants.SLASH.toString())) {
if (StringUtils.isBlank(requestURI)) {
return null;
}
if (log.isDebugEnabled()) {
log.debug("Trying to verify institution from requested entrypoint url: {}", requestURI);
if (requestURI.equals(Constants.SLASH.toString())) {
return StringUtils.EMPTY;
}
try {
return requestURI.substring(requestURI.lastIndexOf(Constants.SLASH) + 1);
if (log.isDebugEnabled()) {
log.debug("Trying to verify institution from requested entrypoint url: {}", requestURI);
}
final String[] split = StringUtils.split(requestURI, Constants.SLASH);
if (split.length > 1) {
return null;
}
return split[0];
} catch (final Exception e) {
log.error("Failed to extract institutional URL suffix: {}", e.getMessage());
return null;

View file

@ -102,7 +102,7 @@ public class RemoteProctoringRoomDAOImpl implements RemoteProctoringRoomDAO {
.execute();
if (active > 0) {
throw new IllegalStateException("Townhall, for exam: " + examId + " already existis");
throw new IllegalStateException("Townhall, for exam: " + examId + " already exists");
}
final String newCollectingRoomName = UUID.randomUUID().toString();

View file

@ -21,6 +21,7 @@ import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
@ -35,6 +36,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
@ -100,7 +102,7 @@ public class ExamAPI_V1_Controller {
final POSTMapper mapper = new POSTMapper(formParams, request.getQueryString());
final String remoteAddr = request.getRemoteAddr();
final String remoteAddr = this.getClientAddress(request);
final Long institutionId = (instIdRequestParam != null)
? instIdRequestParam
: mapper.getLong(API.PARAM_INSTITUTION_ID);
@ -158,7 +160,7 @@ public class ExamAPI_V1_Controller {
return CompletableFuture.runAsync(
() -> {
final String remoteAddr = request.getRemoteAddr();
final String remoteAddr = this.getClientAddress(request);
final Long institutionId = getInstitutionId(principal);
if (log.isDebugEnabled()) {
@ -198,7 +200,7 @@ public class ExamAPI_V1_Controller {
return CompletableFuture.runAsync(
() -> {
final String remoteAddr = request.getRemoteAddr();
final String remoteAddr = this.getClientAddress(request);
final Long institutionId = getInstitutionId(principal);
if (log.isDebugEnabled()) {
@ -234,7 +236,7 @@ public class ExamAPI_V1_Controller {
return CompletableFuture.runAsync(
() -> {
final String remoteAddr = request.getRemoteAddr();
final String remoteAddr = this.getClientAddress(request);
final Long institutionId = getInstitutionId(principal);
if (log.isDebugEnabled()) {
@ -419,4 +421,23 @@ public class ExamAPI_V1_Controller {
}
}
private String getClientAddress(final HttpServletRequest request) {
try {
final String ipAddress = request.getHeader("X-FORWARDED-FOR");
if (ipAddress == null) {
return request.getRemoteAddr();
}
if (ipAddress.contains(",")) {
return StringUtils.split(ipAddress, Constants.COMMA)[0];
}
return ipAddress;
} catch (final Exception e) {
log.warn("Failed to verify client IP address: {}", e.getMessage());
return request.getHeader("X-FORWARDED-FOR");
}
}
}

View file

@ -316,7 +316,7 @@ public class ExamProctoringController {
defaultValue = UserService.USERS_INSTITUTION_AS_DEFAULT) final Long institutionId,
@PathVariable(name = API.PARAM_MODEL_ID) final Long examId) {
checkAccess(institutionId, examId);
checkExamReadAccess(institutionId);
return this.examProcotringRoomService.getTownhallRoomData(examId)
.getOrElse(() -> RemoteProctoringRoom.NULL_ROOM);
@ -351,7 +351,8 @@ public class ExamProctoringController {
// first create and register a room to collect all connection of the exam
// As long as the room exists new connections will join this room immediately
// after have been applied to the default collecting room
final RemoteProctoringRoom townhallRoom = this.examProcotringRoomService.createTownhallRoom(examId, subject)
final RemoteProctoringRoom townhallRoom = this.examProcotringRoomService
.createTownhallRoom(examId, subject)
.onError(error -> this.examProcotringRoomService.disposeTownhallRoom(examId))
.getOrThrow();
@ -590,6 +591,13 @@ public class ExamProctoringController {
true);
}
private void checkExamReadAccess(final Long institutionId) {
this.authorization.check(
PrivilegeType.READ,
EntityType.EXAM,
institutionId);
}
private void checkAccess(final Long institutionId, final Long examId) {
this.authorization.check(
PrivilegeType.READ,

View file

@ -36,7 +36,7 @@ logging.level.ch=INFO
### spring actuator configuration
management.endpoints.web.base-path=/mprofile
management.endpoints.web.exposure.include=metrics,logfile,loggers,heapdump
management.endpoints.web.exposure.include=metrics,logfile,loggers,heapdump,health
##########################################################
### Overall Security Settings