Skip to content

Commit

Permalink
SEBSERV-596, SEBSP-172, SEBSP-173 finished implementation still testing
Browse files Browse the repository at this point in the history
  • Loading branch information
anhefti committed Nov 26, 2024
1 parent 21e2ec0 commit cbd0cc9
Show file tree
Hide file tree
Showing 24 changed files with 421 additions and 218 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public AllowedSEBVersion(final String wholeVersionString) {

if (split.length > 3) {
try {
num = Integer.valueOf(split[3]);
num = Integer.parseInt(split[3]);
} catch (final Exception e) {
num = 0;
if (split[3].equals(ALLIANCE_EDITION_IDENTIFIER)) {
Expand Down Expand Up @@ -174,19 +174,12 @@ public ClientVersion(

@Override
public String toString() {
final StringBuilder builder = new StringBuilder();
builder.append("ClientVersion [osTypeString=");
builder.append(this.osTypeString);
builder.append(", major=");
builder.append(this.major);
builder.append(", minor=");
builder.append(this.minor);
builder.append(", patch=");
builder.append(this.patch);
builder.append(", isAllianceVersion=");
builder.append(this.isAllianceEdition);
builder.append("]");
return builder.toString();
return "ClientVersion [osTypeString=" +
this.osTypeString + ", major=" +
this.major + ", minor=" +
this.minor + ", patch=" +
this.patch + ", isAllianceVersion=" +
this.isAllianceEdition + "]";
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,57 +49,58 @@ public static enum ProctoringRoomType {
}

public interface SEB_INSTRUCTION_ATTRIBUTES {
public interface SEB_PROCTORING {
public static final String SERVICE_TYPE = "service-type";
public static final String METHOD = "method";

public static final String JITSI_URL = "jitsiMeetServerURL";
public static final String JITSI_ROOM = "jitsiMeetRoom";
public static final String JITSI_ROOM_SUBJECT = "jitsiMeetSubject";
public static final String JITSI_TOKEN = "jitsiMeetToken";
public static final String JITSI_RECEIVE_AUDIO = "jitsiMeetReceiveAudio";
public static final String JITSI_RECEIVE_VIDEO = "jitsiMeetReceiveVideo";
public static final String JITSI_ALLOW_CHAT = "jitsiFeatureFlagChat";

public static final String ZOOM_URL = "zoomServerURL";
public static final String ZOOM_ROOM = "zoomRoom";
public static final String ZOOM_ROOM_SUBJECT = "zoomSubject";
public static final String ZOOM_USER_NAME = "zoomUserName";
public static final String ZOOM_API_KEY = "zoomAPIKey";
public static final String ZOOM_TOKEN = "zoomToken";
public static final String ZOOM_SDK_TOKEN = "zoomSDKToken";
public static final String ZOOM_MEETING_KEY = "zoomMeetingKey";
public static final String ZOOM_RECEIVE_AUDIO = "zoomReceiveAudio";
public static final String ZOOM_RECEIVE_VIDEO = "zoomReceiveVideo";
public static final String ZOOM_ALLOW_CHAT = "zoomFeatureFlagChat";

public static final String PROCTORING_ROOM_TYPE = "roomType";
interface SEB_PROCTORING {
String SERVICE_TYPE = "service-type";
String METHOD = "method";

String JITSI_URL = "jitsiMeetServerURL";
String JITSI_ROOM = "jitsiMeetRoom";
String JITSI_ROOM_SUBJECT = "jitsiMeetSubject";
String JITSI_TOKEN = "jitsiMeetToken";
String JITSI_RECEIVE_AUDIO = "jitsiMeetReceiveAudio";
String JITSI_RECEIVE_VIDEO = "jitsiMeetReceiveVideo";
String JITSI_ALLOW_CHAT = "jitsiFeatureFlagChat";

String ZOOM_URL = "zoomServerURL";
String ZOOM_ROOM = "zoomRoom";
String ZOOM_ROOM_SUBJECT = "zoomSubject";
String ZOOM_USER_NAME = "zoomUserName";
String ZOOM_API_KEY = "zoomAPIKey";
String ZOOM_TOKEN = "zoomToken";
String ZOOM_SDK_TOKEN = "zoomSDKToken";
String ZOOM_MEETING_KEY = "zoomMeetingKey";
String ZOOM_RECEIVE_AUDIO = "zoomReceiveAudio";
String ZOOM_RECEIVE_VIDEO = "zoomReceiveVideo";
String ZOOM_ALLOW_CHAT = "zoomFeatureFlagChat";

String PROCTORING_ROOM_TYPE = "roomType";
}

public interface SEB_RECONFIGURE_SETTINGS {
public static final String JITSI_RECEIVE_AUDIO = "jitsiMeetReceiveAudio";
public static final String JITSI_RECEIVE_VIDEO = "jitsiMeetReceiveVideo";
public static final String JITSI_ALLOW_CHAT = "jitsiMeetFeatureFlagChat";
public static final String JITSI_PIN_USER_ID = "jitsiMeetPinUser";
public static final String ZOOM_RECEIVE_AUDIO = "zoomReceiveAudio";
public static final String ZOOM_RECEIVE_VIDEO = "zoomReceiveVideo";
public static final String ZOOM_ALLOW_CHAT = "zoomFeatureFlagChat";
String JITSI_RECEIVE_AUDIO = "jitsiMeetReceiveAudio";
String JITSI_RECEIVE_VIDEO = "jitsiMeetReceiveVideo";
String JITSI_ALLOW_CHAT = "jitsiMeetFeatureFlagChat";
String JITSI_PIN_USER_ID = "jitsiMeetPinUser";
String ZOOM_RECEIVE_AUDIO = "zoomReceiveAudio";
String ZOOM_RECEIVE_VIDEO = "zoomReceiveVideo";
String ZOOM_ALLOW_CHAT = "zoomFeatureFlagChat";
}

public interface SEB_FORCE_LOCK_SCREEN {
public static final String MESSAGE = "message";
public static final String IMAGE_URL = "imageURL";
String MESSAGE = "message";
String IMAGE_URL = "imageURL";
}

public interface SEB_SCREEN_PROCTORING {
public static final String METHOD = "method";
public static final String SERVICE_TYPE = "service-type";
public static final String SERVICE_TYPE_NAME = "SCREEN_PROCTORING";
public static final String URL = "screenProctoringServiceURL";
public static final String CLIENT_ID = "screenProctoringClientId";
public static final String CLIENT_SECRET = "screenProctoringClientSecret";
public static final String GROUP_ID = "screenProctoringGroupId";
public static final String SESSION_ID = "screenProctoringClientSessionId";
String METHOD = "method";
String SERVICE_TYPE = "service-type";
String SERVICE_TYPE_NAME = "SCREEN_PROCTORING";
String URL = "screenProctoringServiceURL";
String CLIENT_ID = "screenProctoringClientId";
String CLIENT_SECRET = "screenProctoringClientSecret";
String GROUP_ID = "screenProctoringGroupId";
String SESSION_ID = "screenProctoringClientSessionId";
String SESSION_ENCRYPTION_KEY = "screenProctoringEncryptSecret";
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ default boolean isGrantDenied() {

default boolean isSEBVersionDenied() {
final Integer notificationFlag = notificationFlag();
System.out.println("************** notificationFlag: " + notificationFlag);
return notificationFlag != null && (notificationFlag & FLAG_INVALID_SEB_VERSION) > 0;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ public void createCell(final ViewGridBuilder builder) {

int h = (value.size() + ((groups.size() > 0) ? groups.size() + 1 : 0)) * HEIGHT_PER_FIELD;
if (expandItemKey.equals("ScreenProctoring")) {
h = h + 50;
h = h + 80;
}

expandItem.setHeight(h);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,9 @@ public ClientConnectionTable(
this.exam = exam;
this.checkSecurityGrant = BooleanUtils.toBoolean(
exam.additionalAttributes.get(Exam.ADDITIONAL_ATTR_SIGNATURE_KEY_CHECK_ENABLED));
this.checkSEBVersion = exam.additionalAttributes.containsKey(Exam.ADDITIONAL_ATTR_ALLOWED_SEB_VERSIONS);
this.checkSEBVersion = exam.additionalAttributes.containsKey(Exam.ADDITIONAL_ATTR_ALLOWED_SEB_VERSIONS) ||
exam.additionalAttributes.containsKey("spsExamActive");

this.distributedSetup = distributedSetup;

final WidgetFactory widgetFactory = pageService.getWidgetFactory();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ public void onApplicationEvent(final ApplicationReadyEvent event) {
SEBServerInit.INIT_LOGGER.info("----> Screen Proctoring Bundle enabled: {}", spsBundle.bundled);
if (spsBundle.bundled) {
SEBServerInit.INIT_LOGGER.info("------> {}", spsBundle);
} else {
throw new IllegalStateException("Only bundled SEB Server Screen Proctoring is supported yet");
}

SEBServerInit.INIT_LOGGER.info("----> ");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public interface ClientConnectionDAO extends
cacheNames = CONNECTION_TOKENS_CACHE,
key = "#examId")
default void evictConnectionTokenCache(final Long examId) {
if (log.isDebugEnabled()) {
if (log.isTraceEnabled()) {
log.debug("Evict SEB connection tokens for exam: {}", examId);
}
}
Expand Down Expand Up @@ -150,10 +150,14 @@ default void evictConnectionTokenCache(final Long examId) {
key = "#connectionToken")
Result<Void> assignToScreenProctoringGroup(Long connectionId, String connectionToken, Long groupId);


@CacheEvict(
cacheNames = ExamSessionCacheService.CACHE_NAME_ACTIVE_CLIENT_CONNECTION,
key = "#connectionToken")
Result<Void> markScreenProctoringApplied(Long connectionId, String connectionToken);
void markScreenProctoringApplied(Long connectionId, String connectionToken);

/** Used to re-mark a client connection record for screen proctoring update. */
void markForScreenProctoringUpdate(final Long id);

/** Get a ClientConnection by connection token.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -573,8 +573,6 @@ public Result<Collection<ClientConnectionRecord>> getAllForScreenProctoringUpdat
.selectByExample()
.where(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupUpdate, isNotEqualTo((byte) 0))
.and(ClientConnectionRecordDynamicSqlSupport.examId, isIn(examIds))
.and(ClientConnectionRecordDynamicSqlSupport.status, isEqualTo(ConnectionStatus.ACTIVE.name()),
or(ClientConnectionRecordDynamicSqlSupport.status, isEqualTo(ConnectionStatus.READY.name())))
.build()
.execute();

Expand Down Expand Up @@ -620,17 +618,37 @@ public Result<Void> assignToScreenProctoringGroup(
}

@Override
public Result<Void> markScreenProctoringApplied(final Long connectionId, final String connectionToken) {
return Result.tryCatch(() -> {
@Transactional
public void markScreenProctoringApplied(final Long connectionId, final String connectionToken) {
try {
UpdateDSL.updateWithMapper(
this.clientConnectionRecordMapper::update,
ClientConnectionRecordDynamicSqlSupport.clientConnectionRecord)
this.clientConnectionRecordMapper::update,
ClientConnectionRecordDynamicSqlSupport.clientConnectionRecord)
.set(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupUpdate).equalTo((byte) 0)
.where(ClientConnectionRecordDynamicSqlSupport.id, isEqualTo(connectionId))
.build()
.execute();
})
.onError(TransactionHandler::rollback);
} catch (final Exception e) {
log.error("Failed to unmark SPS for SEB client connection: {}", connectionToken, e);
TransactionHandler.rollback(e);
}
}

@Override
@Transactional
public void markForScreenProctoringUpdate(final Long id) {
try {
UpdateDSL.updateWithMapper(
this.clientConnectionRecordMapper::update,
ClientConnectionRecordDynamicSqlSupport.clientConnectionRecord)
.set(ClientConnectionRecordDynamicSqlSupport.screenProctoringGroupUpdate).equalTo( (byte) 1)
.where(ClientConnectionRecordDynamicSqlSupport.id, isEqualTo(id))
.build()
.execute();
} catch (final Exception e) {
log.error("Failed to mark SEB connection for screen proctoring update: {}", id);
TransactionHandler.rollback(e);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ boolean isAllowedVersion(
String clientVersion,
List<AllowedSEBVersion> allowedSEBVersions);

void checkVersionAndUpdateClientConnection(
boolean checkVersionAndUpdateClientConnection(
ClientConnectionRecord record,
List<AllowedSEBVersion> allowedSEBVersions);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ default void processSessionUpdateTask() {
* @return Result refer to the given Exam or to an error when happened */
Result<Exam> applyScreenProctoringForExam(EntityKey entityKey);

Result<Collection<ProctoringGroupMonitoringData>> getCollectingGroupsMonitoringData(final Long examId);
Result<Collection<ProctoringGroupMonitoringData>> getCollectingGroupsMonitoringData(Long examId);

/** Get map of all screen proctoring collecting groups for a particular exam.
* The ScreenProctoringGroup is mapped to its uuids.
Expand Down Expand Up @@ -85,10 +85,10 @@ default void processSessionUpdateTask() {
*
* @param event The ExamDeletionEvent reference all PKs of Exams that are going to be deleted. */
@EventListener(ExamDeletionEvent.class)
void notifyExamDeletion(final ExamDeletionEvent event);
void notifyExamDeletion(ExamDeletionEvent event);

@EventListener(LmsSetupChangeEvent.class)
void notifyLmsSetupChange(final LmsSetupChangeEvent event);
void notifyLmsSetupChange(LmsSetupChangeEvent event);

/** This is used to update the exam equivalent on the screen proctoring service side
* if screen proctoring is enabled for the specified exam.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public Integer notificationFlag() {
| (!isGrantChecked() ? ClientMonitoringDataView.FLAG_GRANT_NOT_CHECKED : 0)
| (isGrantDenied() ? ClientMonitoringDataView.FLAG_GRANT_DENIED : 0)
| (isSEBVersionDenied() ? ClientMonitoringDataView.FLAG_INVALID_SEB_VERSION : 0);

return (flag > 0) ? flag : null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -552,18 +552,6 @@ public void notifyExamFinished(final ExamFinishedEvent event) {

@Override
public void updateExamCache(final Long examId) {

// TODO is this really needed?
// try {
// final Cache cache = this.cacheManager.getCache(ExamSessionCacheService.CACHE_NAME_RUNNING_EXAM);
// final ValueWrapper valueWrapper = cache.get(examId);
// if (valueWrapper == null || valueWrapper.get() == null) {
// return Result.ofEmpty();
// }
// } catch (final Exception e) {
// log.error("Failed to check exam cache: {}", e.getMessage());
// }

final Exam exam = this.examSessionCacheService.getRunningExam(examId);
if (exam != null) {
final long now = Utils.getMillisecondsNow();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -467,12 +467,10 @@ public Result<ClientConnection> closeConnection(
updatedClientConnection = clientConnection;
}

// if proctoring is enabled for exam, mark for room update
final Boolean proctoringEnabled = this.examAdminService
.isProctoringEnabled(clientConnection.examId)
.getOr(false);
if (proctoringEnabled) {
this.clientConnectionDAO.markForProctoringUpdate(updatedClientConnection.id);
// if screen proctoring is enabled, close the client session also on SPS site
// usually it should have been closed by SEB but if not, SEB Server closes it
if (BooleanUtils.isTrue(this.examAdminService.isScreenProctoringEnabled(clientConnection.examId).getOr(false))) {
this.clientConnectionDAO.markForScreenProctoringUpdate(updatedClientConnection.id);
}

// delete stored ping if this is a distributed setup
Expand Down Expand Up @@ -527,13 +525,10 @@ public Result<ClientConnection> disableConnection(final String connectionToken,
log.warn("SEB client connection in invalid state for disabling: {}", clientConnection);
updatedClientConnection = clientConnection;
}

// if proctoring is enabled for exam, mark for room update
final Boolean proctoringEnabled = this.examAdminService
.isProctoringEnabled(clientConnection.examId)
.getOr(false);
if (proctoringEnabled) {
this.clientConnectionDAO.markForProctoringUpdate(updatedClientConnection.id);

// if screen proctoring is enabled, close the client session also on SPS site
if (BooleanUtils.isTrue(this.examAdminService.isScreenProctoringEnabled(clientConnection.examId).getOr(false))) {
this.clientConnectionDAO.markForScreenProctoringUpdate(updatedClientConnection.id);
}

// delete stored ping if this is a distributed setup
Expand Down Expand Up @@ -906,14 +901,10 @@ private void checkExamIntegrity(
}

private ClientConnection saveInState(final ClientConnection clientConnection, final ConnectionStatus status) {
final Boolean proctoringEnabled = this.examAdminService
.isProctoringEnabled(clientConnection.examId)
.getOr(false);

return this.clientConnectionDAO.save(new ClientConnection(
clientConnection.id, null, null, status,
null, null, null, null, null, null, null, null, null, null, null, null, null, null,
proctoringEnabled, null, null, null))
false, null, null, null))
.getOrThrow();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,16 @@ public boolean isAllowedVersion(
}

@Override
public void checkVersionAndUpdateClientConnection(
public boolean checkVersionAndUpdateClientConnection(
final ClientConnectionRecord record,
final List<AllowedSEBVersion> allowedSEBVersions) {

if (isAllowedVersion(record.getClientOsName(), record.getClientVersion(), allowedSEBVersions)) {
saveSecurityCheckState(record, true);
return true;
} else {
saveSecurityCheckState(record, false);
return false;
}
}

Expand All @@ -108,7 +110,7 @@ private int extractVersionNumber(final String versionNumPart) {
protected ClientVersion extractClientVersion(final String clientOSName, final String clientVersion) {
try {
// first check if this is a known restricted version
if (this.knownRestrictedVersions.stream().filter(clientVersion::contains).findFirst().isPresent()) {
if (this.knownRestrictedVersions.stream().anyMatch(clientVersion::contains)) {
log.warn("Found default restricted SEB client version: {}", clientVersion);
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public RemoteProctoringServiceFactory(final Collection<RemoteProctoringService>
this.services = new EnumMap<>(proctorServices
.stream()
.collect(Collectors.<RemoteProctoringService, ProctoringServerType, RemoteProctoringService> toMap(
s -> s.getType(),
RemoteProctoringService::getType,
Function.identity())));
}

Expand Down
Loading

0 comments on commit cbd0cc9

Please sign in to comment.