diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java index 13b8a250..a0e8b7d9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/activity/ActivitiesPane.java @@ -301,6 +301,9 @@ public class ActivitiesPane implements TemplateComposer { .newAction(ActionDefinition.EXAM_VIEW_LIST) .create()); + } + + if (this.currentUser.hasInstitutionalPrivilege(PrivilegeType.READ, EntityType.EXAM_TEMPLATE)) { // Exam Template final TreeItem examTemplate = this.widgetFactory.treeItemLocalized( examAdmin, @@ -310,7 +313,6 @@ public class ActivitiesPane implements TemplateComposer { actionBuilder .newAction(ActionDefinition.EXAM_TEMPLATE_VIEW_LIST) .create()); - } examAdmin.setExpanded(this.currentUser.get().hasAnyRole(UserRole.EXAM_ADMIN)); @@ -322,7 +324,8 @@ public class ActivitiesPane implements TemplateComposer { //-------------------------------------------------------------------------------------- // ---- MONITORING --------------------------------------------------------------------- - final boolean isSupporter = this.currentUser.get().hasAnyRole(UserRole.EXAM_SUPPORTER); + final boolean isSupporter = this.currentUser.get().hasAnyRole(UserRole.EXAM_SUPPORTER) || + this.currentUser.get().hasAnyRole(UserRole.EXAM_ADMIN); final boolean viewSEBClientLogs = this.currentUser.hasInstitutionalPrivilege( PrivilegeType.READ, EntityType.EXAM) || diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringClientConnection.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringClientConnection.java index 4cff2082..01657e54 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringClientConnection.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringClientConnection.java @@ -9,6 +9,7 @@ package ch.ethz.seb.sebserver.gui.content.monitoring; import java.util.Collection; +import java.util.function.BooleanSupplier; import java.util.function.Supplier; import org.eclipse.swt.widgets.Composite; @@ -32,6 +33,7 @@ import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData; import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent; import ch.ethz.seb.sebserver.gbl.model.session.ClientNotification; import ch.ethz.seb.sebserver.gbl.model.session.ExtendedClientEvent; +import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.util.Utils; @@ -171,6 +173,10 @@ public class MonitoringClientConnection implements TemplateComposer { .call() .onError(error -> pageContext.notifyLoadError(EntityType.EXAM, error)) .getOrThrow(); + final UserInfo user = currentUser.get(); + final boolean supporting = user.hasRole(UserRole.EXAM_SUPPORTER) && + exam.supporter.contains(user.uuid); + final BooleanSupplier isExamSupporter = () -> supporting || user.hasRole(UserRole.EXAM_ADMIN); final Collection indicators = restService.getBuilder(GetIndicators.class) .withQueryParam(Indicator.FILTER_ATTR_EXAM_ID, parentEntityKey.modelId) @@ -260,7 +266,7 @@ public class MonitoringClientConnection implements TemplateComposer { NOTIFICATION_LIST_NO_SELECTION_KEY) .noEventPropagation() - .publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER), false); + .publishIf(isExamSupporter, false); _notificationTableSupplier = () -> notificationTable; } @@ -353,7 +359,7 @@ public class MonitoringClientConnection implements TemplateComposer { actionBuilder .newAction(ActionDefinition.MONITOR_EXAM_BACK_TO_OVERVIEW) .withEntityKey(parentEntityKey) - .publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER)) + .publishIf(isExamSupporter) .newAction(ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION_QUIT) .withConfirm(() -> CONFIRM_QUIT) @@ -365,7 +371,7 @@ public class MonitoringClientConnection implements TemplateComposer { return action; }) .noEventPropagation() - .publishIf(() -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER) && + .publishIf(() -> isExamSupporter.getAsBoolean() && connectionData.clientConnection.status.clientActiveStatus); if (connectionData.clientConnection.status == ConnectionStatus.ACTIVE) { diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringRunningExam.java b/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringRunningExam.java index 75d68544..2178b27a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringRunningExam.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/content/monitoring/MonitoringRunningExam.java @@ -37,6 +37,7 @@ import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings.ProctoringFeature; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData; +import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.profile.GuiProfile; import ch.ethz.seb.sebserver.gbl.util.Tuple; @@ -130,6 +131,10 @@ public class MonitoringRunningExam implements TemplateComposer { .withURIVariable(API.PARAM_MODEL_ID, entityKey.modelId) .call() .getOrThrow(); + final UserInfo user = currentUser.get(); + final boolean supporting = user.hasRole(UserRole.EXAM_SUPPORTER) && + exam.supporter.contains(user.uuid); + final BooleanSupplier isExamSupporter = () -> supporting || user.hasRole(UserRole.EXAM_ADMIN); final Collection indicators = restService.getBuilder(GetIndicators.class) .withQueryParam(Indicator.FILTER_ATTR_EXAM_ID, entityKey.modelId) @@ -191,8 +196,6 @@ public class MonitoringRunningExam implements TemplateComposer { context -> clientTable.updateValues(), updateTableGUI(clientTable)); - final BooleanSupplier isExamSupporter = () -> currentUser.get().hasRole(UserRole.EXAM_SUPPORTER); - actionBuilder .newAction(ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION) diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/impl/AuthorizationServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/impl/AuthorizationServiceImpl.java index ee20e82c..782beec5 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/impl/AuthorizationServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/authorization/impl/AuthorizationServiceImpl.java @@ -132,8 +132,6 @@ public class AuthorizationServiceImpl implements AuthorizationService { .withInstitutionalPrivilege(PrivilegeType.READ) .andForRole(UserRole.EXAM_ADMIN) .withInstitutionalPrivilege(PrivilegeType.WRITE) - .andForRole(UserRole.EXAM_SUPPORTER) - .withOwnerPrivilege(PrivilegeType.MODIFY) .create(); // grants for configuration node diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamMonitoringController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamMonitoringController.java index 2302d637..b819c75d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamMonitoringController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamMonitoringController.java @@ -41,6 +41,7 @@ import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData; import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction; import ch.ethz.seb.sebserver.gbl.model.session.ClientNotification; +import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.model.user.UserRole; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService; @@ -129,7 +130,8 @@ public class ExamMonitoringController { this.authorization.checkRole( institutionId, EntityType.EXAM, - UserRole.EXAM_SUPPORTER); + UserRole.EXAM_SUPPORTER, + UserRole.EXAM_ADMIN); final FilterMap filterMap = new FilterMap(allRequestParams, request.getQueryString()); @@ -166,19 +168,7 @@ public class ExamMonitoringController { @PathVariable(name = API.PARAM_PARENT_MODEL_ID, required = true) final Long examId, @RequestHeader(name = API.EXAM_MONITORING_STATE_FILTER, required = false) final String hiddenStates) { - // check overall privilege - this.authorization.checkRole( - institutionId, - EntityType.EXAM, - UserRole.EXAM_SUPPORTER); - - // check running exam privilege for specified exam - if (!hasRunningExamPrivilege(examId, institutionId)) { - throw new PermissionDeniedException( - EntityType.EXAM, - PrivilegeType.READ, - this.authorization.getUserService().getCurrentUser().getUserInfo()); - } + checkPrivileges(institutionId, examId); final EnumSet filterStates = EnumSet.noneOf(ConnectionStatus.class); if (StringUtils.isNoneBlank(hiddenStates)) { @@ -211,20 +201,7 @@ public class ExamMonitoringController { @PathVariable(name = API.PARAM_PARENT_MODEL_ID, required = true) final Long examId, @PathVariable(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken) { - // check overall privilege - this.authorization.checkRole( - institutionId, - EntityType.EXAM, - UserRole.EXAM_SUPPORTER); - - // check running exam privilege for specified exam - if (!hasRunningExamPrivilege(examId, institutionId)) { - throw new PermissionDeniedException( - EntityType.EXAM, - PrivilegeType.READ, - this.authorization.getUserService().getCurrentUser().getUserInfo()); - } - + checkPrivileges(institutionId, examId); return this.examSessionService .getConnectionData(connectionToken) .getOrThrow(); @@ -243,6 +220,7 @@ public class ExamMonitoringController { @PathVariable(name = API.PARAM_PARENT_MODEL_ID, required = true) final Long examId, @Valid @RequestBody final ClientInstruction clientInstruction) { + checkPrivileges(institutionId, examId); this.sebClientInstructionService.registerInstruction(clientInstruction); } @@ -261,6 +239,8 @@ public class ExamMonitoringController { @PathVariable(name = API.PARAM_PARENT_MODEL_ID, required = true) final Long examId, @PathVariable(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken) { + checkPrivileges(institutionId, examId); + final ClientConnectionData connection = getConnectionDataForSingleConnection( institutionId, examId, @@ -286,6 +266,7 @@ public class ExamMonitoringController { @PathVariable(name = API.PARAM_MODEL_ID, required = true) final Long notificationId, @PathVariable(name = API.EXAM_API_SEB_CONNECTION_TOKEN, required = true) final String connectionToken) { + checkPrivileges(institutionId, examId); this.sebClientNotificationService.confirmPendingNotification( notificationId, examId, @@ -308,6 +289,8 @@ public class ExamMonitoringController { name = Domain.CLIENT_CONNECTION.ATTR_CONNECTION_TOKEN, required = true) final String connectionToken) { + checkPrivileges(institutionId, examId); + if (connectionToken.contains(Constants.LIST_SEPARATOR)) { final String[] tokens = StringUtils.split(connectionToken, Constants.LIST_SEPARATOR); for (int i = 0; i < tokens.length; i++) { @@ -322,6 +305,23 @@ public class ExamMonitoringController { } } + private void checkPrivileges(final Long institutionId, final Long examId) { + // check overall privilege + this.authorization.checkRole( + institutionId, + EntityType.EXAM, + UserRole.EXAM_SUPPORTER, + UserRole.EXAM_ADMIN); + + // check running exam privilege for specified exam + if (!hasRunningExamPrivilege(examId, institutionId)) { + throw new PermissionDeniedException( + EntityType.EXAM, + PrivilegeType.READ, + this.authorization.getUserService().getCurrentUser().getUserInfo()); + } + } + private boolean hasRunningExamPrivilege(final Long examId, final Long institution) { return hasRunningExamPrivilege( this.examSessionService.getRunningExam(examId).getOr(null), @@ -333,8 +333,10 @@ public class ExamMonitoringController { return false; } - final String userId = this.authorization.getUserService().getCurrentUser().getUserInfo().uuid; - return exam.institutionId.equals(institution) && exam.isOwner(userId); + final UserInfo userInfo = this.authorization.getUserService().getCurrentUser().getUserInfo(); + final String userId = userInfo.uuid; + return exam.institutionId.equals(institution) + && (exam.isOwner(userId) || userInfo.hasRole(UserRole.EXAM_ADMIN)); } }