added check endpoint and fixed gui endpoint
This commit is contained in:
parent
e73dd5105a
commit
9d5ed34ec6
6 changed files with 105 additions and 63 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue