SEBSERV-417 fixed screen proctoring re-init plus autologin
This commit is contained in:
parent
9d93826a35
commit
1a5bb6ff7d
3 changed files with 106 additions and 26 deletions
|
@ -270,6 +270,11 @@ public class OAuth2AuthorizationContextHolder implements AuthorizationContextHol
|
||||||
@Override
|
@Override
|
||||||
public boolean autoLogin(final String oneTimeToken) {
|
public boolean autoLogin(final String oneTimeToken) {
|
||||||
try {
|
try {
|
||||||
|
// check first if we already have an active session if so, invalidate ir
|
||||||
|
if (this.isLoggedIn()) {
|
||||||
|
this.logout();
|
||||||
|
}
|
||||||
|
|
||||||
// Create ad-hoc RestTemplate and call token verification
|
// Create ad-hoc RestTemplate and call token verification
|
||||||
final RestTemplate verifyTemplate = new RestTemplate(this.clientHttpRequestFactory);
|
final RestTemplate verifyTemplate = new RestTemplate(this.clientHttpRequestFactory);
|
||||||
final HttpHeaders httpHeaders = new HttpHeaders();
|
final HttpHeaders httpHeaders = new HttpHeaders();
|
||||||
|
|
|
@ -333,8 +333,11 @@ class ScreenProctoringAPIBinding {
|
||||||
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, HttpMethod.GET);
|
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, HttpMethod.GET);
|
||||||
|
|
||||||
if (exchange.getStatusCode() == HttpStatus.NOT_FOUND) {
|
if (exchange.getStatusCode() == HttpStatus.NOT_FOUND) {
|
||||||
|
log.info("Exam not exists on SPS service, crate new one for exam: {}", exam)
|
||||||
|
;
|
||||||
return false;
|
return false;
|
||||||
} else if (exchange.getStatusCode() == HttpStatus.OK) {
|
} else if (exchange.getStatusCode() == HttpStatus.OK) {
|
||||||
|
log.info("Exam already exists on SPS, reuse it: {}", exchange.getBody());
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
log.warn("Failed to verify if Exam on SPS already exists: {}", exchange.getBody());
|
log.warn("Failed to verify if Exam on SPS already exists: {}", exchange.getBody());
|
||||||
|
@ -532,7 +535,7 @@ class ScreenProctoringAPIBinding {
|
||||||
synchronizeUserAccounts(exam);
|
synchronizeUserAccounts(exam);
|
||||||
createSEBAccess(exam, apiTemplate, spsData);
|
createSEBAccess(exam, apiTemplate, spsData);
|
||||||
createExam(exam, apiTemplate, spsData);
|
createExam(exam, apiTemplate, spsData);
|
||||||
final Collection<ScreenProctoringGroup> initializeGroups = initializeGroups(exam, apiTemplate, spsData);
|
final Collection<ScreenProctoringGroup> initializeGroups = initializeGroups(exam, apiTemplate, spsData, true);
|
||||||
|
|
||||||
// store encrypted spsData
|
// store encrypted spsData
|
||||||
final String spsDataJSON = this.jsonMapper.writeValueAsString(spsData);
|
final String spsDataJSON = this.jsonMapper.writeValueAsString(spsData);
|
||||||
|
@ -569,7 +572,7 @@ class ScreenProctoringAPIBinding {
|
||||||
throw new RuntimeException("Failed to get Exam from SPS. local exam uuid: " + examUUID);
|
throw new RuntimeException("Failed to get Exam from SPS. local exam uuid: " + examUUID);
|
||||||
}
|
}
|
||||||
final JsonNode requestJSON = this.jsonMapper.readTree(exchange.getBody());
|
final JsonNode requestJSON = this.jsonMapper.readTree(exchange.getBody());
|
||||||
final String spsExamId = requestJSON.get(SPS_API.EXAM.ATTR_ID).textValue();
|
final String spsExamId = requestJSON.get(SPS_API.EXAM.ATTR_ID).asText();
|
||||||
|
|
||||||
|
|
||||||
// check if Exam has SPSData, if not create and if check completeness
|
// check if Exam has SPSData, if not create and if check completeness
|
||||||
|
@ -604,8 +607,9 @@ class ScreenProctoringAPIBinding {
|
||||||
.queryParam(SPS_API.GROUP.ATTR_EXAM_ID, spsExamId)
|
.queryParam(SPS_API.GROUP.ATTR_EXAM_ID, spsExamId)
|
||||||
.build()
|
.build()
|
||||||
.toUriString();
|
.toUriString();
|
||||||
|
final ResponseEntity<String> exchangeGroups = apiTemplate.exchange(groupRequestURI, HttpMethod.GET);
|
||||||
|
|
||||||
final JsonNode groupsJSON = this.jsonMapper.readTree(exchange.getBody());
|
final JsonNode groupsJSON = this.jsonMapper.readTree(exchangeGroups.getBody());
|
||||||
final JsonNode pageContent = groupsJSON.get("content");
|
final JsonNode pageContent = groupsJSON.get("content");
|
||||||
if (pageContent.isArray()) {
|
if (pageContent.isArray()) {
|
||||||
for (final JsonNode group : pageContent) {
|
for (final JsonNode group : pageContent) {
|
||||||
|
@ -615,15 +619,22 @@ class ScreenProctoringAPIBinding {
|
||||||
group.get(SPS_API.GROUP.ATTR_UUID).textValue(),
|
group.get(SPS_API.GROUP.ATTR_UUID).textValue(),
|
||||||
group.get(SPS_API.GROUP.ATTR_NAME).textValue(),
|
group.get(SPS_API.GROUP.ATTR_NAME).textValue(),
|
||||||
0,
|
0,
|
||||||
null
|
group.toString()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (groups.isEmpty()) {
|
||||||
|
log.info("No groups for exam {} and spsExam {} found on SPS, try to initialize default groups...",
|
||||||
|
exam.name,
|
||||||
|
spsExamId);
|
||||||
|
return initializeGroups(exam, apiTemplate, spsData, false);
|
||||||
|
}
|
||||||
|
|
||||||
return groups;
|
return groups;
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.error("Failed to get exam groups from SPS due to reinitialization: ", e);
|
log.error("Failed to get exam groups from SPS due to reinitialization: ", e);
|
||||||
return initializeGroups(exam, apiTemplate, spsData);
|
return initializeGroups(exam, apiTemplate, spsData, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
|
@ -695,6 +706,51 @@ class ScreenProctoringAPIBinding {
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void deleteExamOnScreenProctoring(final Exam exam) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (!BooleanUtils.toBoolean(exam.additionalAttributes.get(SPSData.ATTR_SPS_ACTIVE))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("Deactivate exam and groups on SPS site and send deletion request for exam {}", exam);
|
||||||
|
}
|
||||||
|
|
||||||
|
final ScreenProctoringServiceOAuthTemplate apiTemplate = this.getAPITemplate(exam.id);
|
||||||
|
final SPSData spsData = this.getSPSData(exam.id);
|
||||||
|
deletion(SPS_API.SEB_ACCESS_ENDPOINT, spsData.spsSEBAccessUUID, apiTemplate);
|
||||||
|
activation(exam, SPS_API.EXAM_ENDPOINT, spsData.spsExamUUID, false, apiTemplate);
|
||||||
|
|
||||||
|
// exam delete request on SPS
|
||||||
|
final String uri = UriComponentsBuilder
|
||||||
|
.fromUriString(apiTemplate.spsAPIAccessData.getSpsServiceURL())
|
||||||
|
.path(SPS_API.EXAM_ENDPOINT)
|
||||||
|
.pathSegment(spsData.spsExamUUID)
|
||||||
|
.pathSegment(SPS_API.EXAM_DELETE_REQUEST_ENDPOINT)
|
||||||
|
.build()
|
||||||
|
.toUriString();
|
||||||
|
|
||||||
|
final ResponseEntity<String> exchange = apiTemplate.exchange(uri, HttpMethod.DELETE);
|
||||||
|
if (exchange.getStatusCode() != HttpStatus.OK) {
|
||||||
|
log.error("Failed to request delete on SPS for Exam: {} with response: {}", exam, exchange);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark successfully dispose on SPS side
|
||||||
|
this.additionalAttributesDAO.saveAdditionalAttribute(
|
||||||
|
EntityType.EXAM,
|
||||||
|
exam.id,
|
||||||
|
SPSData.ATTR_SPS_ACTIVE,
|
||||||
|
Constants.FALSE_STRING);
|
||||||
|
|
||||||
|
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.warn("Failed to apply SPS deletion of exam: {} error: {}", exam, e.getMessage());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
private void synchronizeUserAccount(
|
private void synchronizeUserAccount(
|
||||||
final String userUUID,
|
final String userUUID,
|
||||||
final ScreenProctoringServiceOAuthTemplate apiTemplate) {
|
final ScreenProctoringServiceOAuthTemplate apiTemplate) {
|
||||||
|
@ -783,7 +839,8 @@ class ScreenProctoringAPIBinding {
|
||||||
private Collection<ScreenProctoringGroup> initializeGroups(
|
private Collection<ScreenProctoringGroup> initializeGroups(
|
||||||
final Exam exam,
|
final Exam exam,
|
||||||
final ScreenProctoringServiceOAuthTemplate apiTemplate,
|
final ScreenProctoringServiceOAuthTemplate apiTemplate,
|
||||||
final SPSData spsData) {
|
final SPSData spsData,
|
||||||
|
boolean applyRollback) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
@ -824,11 +881,13 @@ class ScreenProctoringAPIBinding {
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.error(
|
if (applyRollback) {
|
||||||
"Failed to initialize SPS Groups for screen proctoring. perform rollback. exam: {} error: {}",
|
log.error(
|
||||||
exam,
|
"Failed to initialize SPS Groups for screen proctoring. perform rollback. exam: {} error: {}",
|
||||||
e.getMessage());
|
exam,
|
||||||
rollbackOnSPS(exam, spsData, apiTemplate);
|
e.getMessage());
|
||||||
|
rollbackOnSPS(exam, spsData, apiTemplate);
|
||||||
|
}
|
||||||
throw new RuntimeException("Failed to apply screen proctoring:", e);
|
throw new RuntimeException("Failed to apply screen proctoring:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -948,7 +1007,7 @@ class ScreenProctoringAPIBinding {
|
||||||
final SPSData spsData) {
|
final SPSData spsData) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final String name = SEB_SERVER_SCREEN_PROCTORING_SEB_ACCESS_PREFIX + exam.externalId;
|
String name = SEB_SERVER_SCREEN_PROCTORING_SEB_ACCESS_PREFIX + exam.externalId;
|
||||||
final String description = "This SEB access was auto-generated by SEB Server";
|
final String description = "This SEB access was auto-generated by SEB Server";
|
||||||
|
|
||||||
// first try to get existing one by name and link it if available
|
// first try to get existing one by name and link it if available
|
||||||
|
@ -966,20 +1025,25 @@ class ScreenProctoringAPIBinding {
|
||||||
final JsonNode content = requestJSON.get("content");
|
final JsonNode content = requestJSON.get("content");
|
||||||
if (content.isArray()) {
|
if (content.isArray()) {
|
||||||
|
|
||||||
final JsonNode sebConnection = content.get(0);
|
if (content.size() == 1) {
|
||||||
|
final JsonNode sebConnection = content.get(0);
|
||||||
|
|
||||||
// TODO remove when tested
|
// TODO remove when tested
|
||||||
final JsonNode uuidNode = sebConnection.get(SPS_API.SEB_ACCESS.ATTR_UUID);
|
final JsonNode uuidNode = sebConnection.get(SPS_API.SEB_ACCESS.ATTR_UUID);
|
||||||
final JsonNode sebClientNode = sebConnection.get(SPS_API.SEB_ACCESS.ATTR_CLIENT_NAME);
|
final JsonNode sebClientNode = sebConnection.get(SPS_API.SEB_ACCESS.ATTR_CLIENT_NAME);
|
||||||
final JsonNode sebSecretNode = sebConnection.get(SPS_API.SEB_ACCESS.ATTR_CLIENT_SECRET);
|
final JsonNode sebSecretNode = sebConnection.get(SPS_API.SEB_ACCESS.ATTR_CLIENT_SECRET);
|
||||||
log.info(" uuidNode: {}", uuidNode);
|
log.info(" uuidNode: {}", uuidNode);
|
||||||
log.info(" sebClientNode: {}", sebClientNode);
|
log.info(" sebClientNode: {}", sebClientNode);
|
||||||
log.info(" sebSecretNode: {}", sebSecretNode);
|
log.info(" sebSecretNode: {}", sebSecretNode);
|
||||||
|
|
||||||
spsData.spsSEBAccessUUID = uuidNode.textValue();
|
spsData.spsSEBAccessUUID = uuidNode.textValue();
|
||||||
spsData.spsSEBAccessName = sebClientNode.textValue();
|
spsData.spsSEBAccessName = sebClientNode.textValue();
|
||||||
spsData.spsSEBAccessPWD = sebSecretNode.textValue();
|
spsData.spsSEBAccessPWD = sebSecretNode.textValue();
|
||||||
return;
|
return;
|
||||||
|
} else if (content.size() > 1) {
|
||||||
|
log.warn("Got more then 1 SEB Client Access object for query, create new one with name suffix...");
|
||||||
|
name = name + "_(" + content.size() + ")";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (final Exception e) {
|
} catch (final Exception e) {
|
||||||
log.warn("Failed to extract existing SEB Account from JSON: {}", e.getMessage());
|
log.warn("Failed to extract existing SEB Account from JSON: {}", e.getMessage());
|
||||||
|
|
|
@ -488,8 +488,19 @@ public class ScreenProctoringServiceImpl implements ScreenProctoringService {
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> {
|
||||||
final Exam exam = this.examDAO.byPK(examId).getOrThrow();
|
final Exam exam = this.examDAO.byPK(examId).getOrThrow();
|
||||||
|
|
||||||
this.screenProctoringAPIBinding.deactivateScreenProctoring(exam)
|
// Note: We delete the Exam on SPS site if there are no SEB client connection yet.
|
||||||
.onError(error -> log.error("Failed to deactivate screen proctoring for exam: {}", exam.name, error));
|
// Otherwise, the Exam on SPS site gets just closed
|
||||||
|
|
||||||
|
final Collection<Long> sebConnections = clientConnectionDAO
|
||||||
|
.getAllConnectionIdsForExam(examId)
|
||||||
|
.getOr(Collections.emptyList());
|
||||||
|
|
||||||
|
if (sebConnections == null || sebConnections.isEmpty()) {
|
||||||
|
this.screenProctoringAPIBinding.deleteExamOnScreenProctoring(exam);
|
||||||
|
} else {
|
||||||
|
this.screenProctoringAPIBinding.deactivateScreenProctoring(exam)
|
||||||
|
.onError(error -> log.error("Failed to deactivate screen proctoring for exam: {}", exam.name, error));
|
||||||
|
}
|
||||||
|
|
||||||
return this.cleanupAllLocalGroups(exam);
|
return this.cleanupAllLocalGroups(exam);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue