From 1d6bd86b57c9c43f268bc6e12bc6b721a74db72b Mon Sep 17 00:00:00 2001 From: anhefti Date: Mon, 28 Feb 2022 13:44:46 +0100 Subject: [PATCH] SEBSERV-270 fixed and service test and validation improvements --- .../model/exam/ProctoringServiceSettings.java | 5 ++-- .../content/exam/ExamProctoringSettings.java | 9 ++++-- .../proctoring/JitsiProctoringService.java | 21 +++++++++++-- .../proctoring/ZoomProctoringService.java | 18 +++++++++-- .../ProctoringSettingsValidator.java | 30 ++----------------- .../api/ExamAdministrationController.java | 2 +- src/main/resources/messages.properties | 1 + 7 files changed, 48 insertions(+), 38 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/ProctoringServiceSettings.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/ProctoringServiceSettings.java index b1832f08..d2cc7fbd 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/ProctoringServiceSettings.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/exam/ProctoringServiceSettings.java @@ -11,6 +11,7 @@ package ch.ethz.seb.sebserver.gbl.model.exam; import java.util.EnumSet; import org.apache.commons.lang3.BooleanUtils; +import org.apache.commons.lang3.StringUtils; import org.hibernate.validator.constraints.URL; import com.fasterxml.jackson.annotation.JsonCreator; @@ -110,9 +111,9 @@ public class ProctoringServiceSettings implements Entity { this.collectingRoomSize = (collectingRoomSize != null) ? collectingRoomSize : 20; this.enabledFeatures = enabledFeatures != null ? enabledFeatures : EnumSet.allOf(ProctoringFeature.class); this.serviceInUse = serviceInUse; - this.appKey = appKey; + this.appKey = StringUtils.trim(appKey); this.appSecret = appSecret; - this.sdkKey = sdkKey; + this.sdkKey = StringUtils.trim(sdkKey); this.sdkSecret = sdkSecret; this.useZoomAppClientForCollectingRoom = BooleanUtils.toBoolean(useZoomAppClientForCollectingRoom); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/exam/ExamProctoringSettings.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/exam/ExamProctoringSettings.java index db4f6cbd..2eef3c2b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/exam/ExamProctoringSettings.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/exam/ExamProctoringSettings.java @@ -265,12 +265,14 @@ public class ExamProctoringSettings { .addField(FormBuilder.text( ProctoringServiceSettings.ATTR_SERVER_URL, SEB_PROCTORING_FORM_URL, - proctoringSettings.serverURL)) + proctoringSettings.serverURL) + .mandatory()) .addField(FormBuilder.text( ProctoringServiceSettings.ATTR_APP_KEY, SEB_PROCTORING_FORM_APPKEY, - proctoringSettings.appKey)) + proctoringSettings.appKey) + .mandatory()) .withEmptyCellSeparation(false) .addField(FormBuilder.password( @@ -278,7 +280,8 @@ public class ExamProctoringSettings { SEB_PROCTORING_FORM_SECRET, (proctoringSettings.appSecret != null) ? String.valueOf(proctoringSettings.appSecret) - : null)) + : null) + .mandatory()) .addField(FormBuilder.text( ProctoringServiceSettings.ATTR_SDK_KEY, diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/JitsiProctoringService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/JitsiProctoringService.java index 1f6c4e79..9e0162d5 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/JitsiProctoringService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/JitsiProctoringService.java @@ -141,25 +141,40 @@ public class JitsiProctoringService implements ExamProctoringService { "proctoringSettings:serverURL:invalidURL"); } + if (StringUtils.isBlank(proctoringSettings.appKey)) { + throw new APIMessageException(Arrays.asList( + APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_APP_KEY, + "proctoringSettings:appKey:notNull"), + APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of())); + } + + if (StringUtils.isBlank(proctoringSettings.appSecret)) { + throw new APIMessageException(Arrays.asList( + APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_APP_SECRET, + "proctoringSettings:appSecret:notNull"), + APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of())); + } + final ClientHttpRequestFactory clientHttpRequestFactory = this.clientHttpRequestFactoryService .getClientHttpRequestFactory() .getOrThrow(); try { + final String testURL = proctoringSettings.serverURL + "/external_api.js"; final RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory); final ResponseEntity result = - restTemplate.getForEntity(proctoringSettings.serverURL, String.class); + restTemplate.getForEntity(testURL, String.class); if (result.getStatusCode() != HttpStatus.OK) { throw new APIMessageException(Arrays.asList( APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_SERVER_URL, - "proctoringSettings:serverURL:url.invalid"), + "proctoringSettings:serverURL:url.noservice"), APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of())); } } catch (final Exception e) { log.error("Failed to access proctoring service: {}", e.getMessage()); throw new APIMessageException(Arrays.asList( APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_SERVER_URL, - "proctoringSettings:serverURL:url.invalid"), + "proctoringSettings:serverURL:url.noservice"), APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of(e))); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ZoomProctoringService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ZoomProctoringService.java index 02afee6a..bc41c1cc 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ZoomProctoringService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ZoomProctoringService.java @@ -172,6 +172,20 @@ public class ZoomProctoringService implements ExamProctoringService { "proctoringSettings:serverURL:invalidURL"); } + if (StringUtils.isBlank(proctoringSettings.appKey)) { + throw new APIMessageException(Arrays.asList( + APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_APP_KEY, + "proctoringSettings:appKey:notNull"), + APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of())); + } + + if (StringUtils.isBlank(proctoringSettings.appSecret)) { + throw new APIMessageException(Arrays.asList( + APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_APP_SECRET, + "proctoringSettings:appSecret:notNull"), + APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of())); + } + try { final ClientCredentials credentials = new ClientCredentials( @@ -192,10 +206,10 @@ public class ZoomProctoringService implements ExamProctoringService { APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of())); } } catch (final Exception e) { - log.error("Failed to access Zoom service at: {}", proctoringSettings.serverURL, e); + log.error("Failed to access Zoom service at: {}", proctoringSettings.serverURL, e.getMessage()); throw new APIMessageException(Arrays.asList( APIMessage.fieldValidationError(ProctoringServiceSettings.ATTR_SERVER_URL, - "proctoringSettings:serverURL:url.invalid"), + "proctoringSettings:serverURL:url.noservice"), APIMessage.ErrorMessage.EXTERNAL_SERVICE_BINDING_ERROR.of())); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/validation/ProctoringSettingsValidator.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/validation/ProctoringSettingsValidator.java index 77b4207a..67bc7541 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/validation/ProctoringSettingsValidator.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/validation/ProctoringSettingsValidator.java @@ -16,7 +16,8 @@ import org.apache.commons.lang3.StringUtils; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings.ProctoringServerType; -public class ProctoringSettingsValidator implements ConstraintValidator { +public class ProctoringSettingsValidator + implements ConstraintValidator { @Override public boolean isValid(final ProctoringServiceSettings value, final ConstraintValidatorContext context) { @@ -25,33 +26,8 @@ public class ProctoringSettingsValidator implements ConstraintValidator { return this.entityDAO.byPK(examId) .flatMap(this.authorization::checkModify) .map(exam -> { - if (proctoringServiceSettings.enableProctoring) { + if (StringUtils.isNotBlank(proctoringServiceSettings.serverURL)) { this.examAdminService.getExamProctoringService(proctoringServiceSettings.serverType) .flatMap(service -> service.testExamProctoring(proctoringServiceSettings)) .getOrThrow(); diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index a15be438..329c9841 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -95,6 +95,7 @@ sebserver.form.validation.fieldError.exists=This name already exists. Please cho sebserver.form.validation.fieldError.email=Invalid mail address sebserver.form.validation.fieldError.serverNotAvailable=No service seems to be available within the given URL sebserver.form.validation.fieldError.url.invalid=Invalid URL. The given URL cannot be reached. +sebserver.form.validation.fieldError.url.noservice=The expected service is not available within the given URL and API access. sebserver.form.validation.fieldError.thresholdDuplicate=There are duplicate threshold values. sebserver.form.validation.fieldError.thresholdEmpty=There are empty threshold entries. sebserver.error.unexpected=Unexpected Error