diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnection.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnection.java index ad4c54ab..76e1bfd9 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnection.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientConnection.java @@ -13,8 +13,6 @@ import java.util.EnumSet; import java.util.List; import java.util.function.Predicate; -import org.apache.commons.lang3.BooleanUtils; - import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -327,11 +325,6 @@ public final class ClientConnection implements GrantEntity { return this.securityCheckGranted; } - @JsonIgnore - public boolean isSecurityCheckGranted() { - return BooleanUtils.isTrue(this.securityCheckGranted); - } - @Override public int hashCode() { final int prime = 31; diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientMonitoringData.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientMonitoringData.java index 679d81e3..74275320 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientMonitoringData.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientMonitoringData.java @@ -25,7 +25,7 @@ public class ClientMonitoringData implements ClientMonitoringDataView { public final ConnectionStatus status; public final Map indicatorVals; public final boolean missingPing; - public final boolean missingGrant; + public final Boolean grantDenied; public final boolean pendingNotification; @JsonCreator @@ -34,14 +34,14 @@ public class ClientMonitoringData implements ClientMonitoringDataView { @JsonProperty(ATTR_STATUS) final ConnectionStatus status, @JsonProperty(ATTR_INDICATOR_VALUES) final Map indicatorVals, @JsonProperty(ATTR_MISSING_PING) final boolean missingPing, - @JsonProperty(ATTR_MISSING_GRANT) final boolean missingGrant, + @JsonProperty(ATTR_GRANT_DENIED) final Boolean grantDenied, @JsonProperty(ATTR_PENDING_NOTIFICATION) final boolean pendingNotification) { this.id = id; this.status = status; this.indicatorVals = indicatorVals; this.missingPing = missingPing; - this.missingGrant = missingGrant; + this.grantDenied = grantDenied; this.pendingNotification = pendingNotification; } @@ -66,9 +66,8 @@ public class ClientMonitoringData implements ClientMonitoringDataView { } @Override - public boolean isMissingGrant() { - // TODO Auto-generated method stub - return false; + public Boolean isGrantDenied() { + return this.grantDenied; } @Override @@ -76,6 +75,12 @@ public class ClientMonitoringData implements ClientMonitoringDataView { return this.pendingNotification; } + public boolean hasChanged(final ClientMonitoringData other) { + return this.status != other.status || + this.missingPing != other.missingPing || + !Objects.equals(this.grantDenied, other.grantDenied); + } + public boolean indicatorValuesEquals(final ClientMonitoringData other) { return Objects.equals(this.indicatorVals, other.indicatorVals); } diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientMonitoringDataView.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientMonitoringDataView.java index 01284c32..30c9fde6 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientMonitoringDataView.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientMonitoringDataView.java @@ -27,7 +27,7 @@ public interface ClientMonitoringDataView { public static final String ATTR_INDICATOR_VALUES = "iv"; public static final String ATTR_CLIENT_GROUPS = "cg"; public static final String ATTR_MISSING_PING = "mp"; - public static final String ATTR_MISSING_GRANT = "mg"; + public static final String ATTR_GRANT_DENIED = "gd"; public static final String ATTR_PENDING_NOTIFICATION = "pn"; @JsonProperty(Domain.CLIENT_CONNECTION.ATTR_ID) @@ -42,8 +42,8 @@ public interface ClientMonitoringDataView { @JsonProperty(ATTR_MISSING_PING) boolean isMissingPing(); - @JsonProperty(ATTR_MISSING_GRANT) - boolean isMissingGrant(); + @JsonProperty(ATTR_GRANT_DENIED) + Boolean isGrantDenied(); @JsonProperty(ATTR_PENDING_NOTIFICATION) boolean isPendingNotification(); diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientStaticData.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientStaticData.java index 077fd1bc..2b88db59 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientStaticData.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/session/ClientStaticData.java @@ -22,7 +22,7 @@ import ch.ethz.seb.sebserver.gbl.model.Domain; public class ClientStaticData { public static final ClientStaticData NULL_DATA = - new ClientStaticData(-1L, null, null, false, null, Collections.emptySet()); + new ClientStaticData(-1L, null, null, null, null, Collections.emptySet()); @JsonProperty(Domain.CLIENT_CONNECTION.ATTR_ID) public final Long id; @@ -33,8 +33,8 @@ public class ClientStaticData { @JsonProperty(Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID) public final String userSessionId; - @JsonProperty(Domain.CLIENT_CONNECTION.ATTR_SECURITY_CHECK_GRANTED) - public final boolean securityGrant; + @JsonProperty(Domain.CLIENT_CONNECTION.ATTR_ASK) + public final String ask; @JsonProperty(ClientConnection.ATTR_INFO) public final String info; @@ -47,14 +47,14 @@ public class ClientStaticData { @JsonProperty(Domain.CLIENT_CONNECTION.ATTR_ID) final Long id, @JsonProperty(Domain.CLIENT_CONNECTION.ATTR_CONNECTION_TOKEN) final String connectionToken, @JsonProperty(Domain.CLIENT_CONNECTION.ATTR_EXAM_USER_SESSION_ID) final String userSessionId, - @JsonProperty(Domain.CLIENT_CONNECTION.ATTR_SECURITY_CHECK_GRANTED) final boolean securityGrant, + @JsonProperty(Domain.CLIENT_CONNECTION.ATTR_ASK) final String ask, @JsonProperty(ClientConnection.ATTR_INFO) final String info, @JsonProperty(ClientConnectionData.ATTR_CLIENT_GROUPS) final Set groups) { this.id = id; this.connectionToken = connectionToken; this.userSessionId = userSessionId; - this.securityGrant = securityGrant; + this.ask = ask; this.info = info; this.groups = groups; } @@ -71,8 +71,8 @@ public class ClientStaticData { return this.userSessionId; } - public boolean isSecurityGrant() { - return this.securityGrant; + public String getAsk() { + return this.ask; } public String getInfo() { diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java index 3aa79f44..4232834d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/util/Utils.java @@ -835,6 +835,13 @@ public final class Utils { return BooleanUtils.toIntegerObject(b, 1, 0, 0).byteValue(); } + public static Boolean fromByteOrNull(final Byte b) { + if (b == null) { + return null; + } + return BooleanUtils.toBooleanObject(b); + } + public static Boolean fromByte(final Byte b) { return BooleanUtils.toBooleanObject((b == null) ? 0 : b); } 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 1cdb270e..b0e26b86 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 @@ -410,7 +410,7 @@ public class MonitoringClientConnection implements TemplateComposer { .call() .getOrThrow(); - if (securityKey.id == null || securityKey.id < 0) { + if (securityKey.key != null && (securityKey.id == null || securityKey.id < 0)) { actionBuilder .newAction(ActionDefinition.MONITOR_EXAM_CLIENT_CONNECTION_GRANT_SIGNATURE_KEY) .withParentEntityKey(parentEntityKey) diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java index 2e23f3e2..768a7daa 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/ResourceService.java @@ -98,6 +98,7 @@ public class ResourceService { private static final Logger log = LoggerFactory.getLogger(ResourceService.class); private static final String MISSING_CLIENT_PING_NAME_KEY = "MISSING_PING"; + private static final String DENIED_CLIENT_SEC_GRANT_NAME_KEY = "GRANT_DENIED"; private static final String MISSING_CLIENT_SEC_GRANT_NAME_KEY = "MISSING_GRANT"; public static final Comparator> RESOURCE_COMPARATOR = Comparator.comparing(t -> t._2); @@ -625,46 +626,16 @@ public class ResourceService { .getText(ResourceService.EXAMCONFIG_STATUS_PREFIX + config.configStatus.name()); } -// public Function localizedClientConnectionStatusNameFunction() { -// -// // Memoizing -// final String missing = this.i18nSupport.getText( -// SEB_CONNECTION_STATUS_KEY_PREFIX + MISSING_CLIENT_PING_NAME_KEY, -// MISSING_CLIENT_PING_NAME_KEY); -// final String missingGrant = this.i18nSupport.getText( -// SEB_CONNECTION_STATUS_KEY_PREFIX + MISSING_CLIENT_SEC_GRANT_NAME_KEY, -// MISSING_CLIENT_SEC_GRANT_NAME_KEY); -// final EnumMap localizedNames = new EnumMap<>(ConnectionStatus.class); -// Arrays.asList(ConnectionStatus.values()).stream().forEach(state -> localizedNames.put(state, this.i18nSupport -// .getText(SEB_CONNECTION_STATUS_KEY_PREFIX + state.name(), state.name()))); -// -// return connectionData -> { -// if (connectionData == null) { -// localizedNames.get(ConnectionStatus.UNDEFINED); -// } -// if (connectionData.clientConnection.status.establishedStatus) { -// if (connectionData.c !connectionData.clientConnection.securityCheckGranted) { -// return missingGrant; -// } -// if (connectionData.missingPing) { -// return missing; -// } -// } -// if (connectionData.missingPing && connectionData.clientConnection.status.establishedStatus) { -// return missing; -// } else { -// return localizedNames.get(connectionData.clientConnection.status); -// } -// }; -// } - public Function localizedClientMonitoringStatusNameFunction() { // Memoizing final String missingPing = this.i18nSupport.getText( SEB_CONNECTION_STATUS_KEY_PREFIX + MISSING_CLIENT_PING_NAME_KEY, MISSING_CLIENT_PING_NAME_KEY); - final String missingGrant = this.i18nSupport.getText( + final String grantDeniedText = this.i18nSupport.getText( + SEB_CONNECTION_STATUS_KEY_PREFIX + DENIED_CLIENT_SEC_GRANT_NAME_KEY, + DENIED_CLIENT_SEC_GRANT_NAME_KEY); + final String grantMissingText = this.i18nSupport.getText( SEB_CONNECTION_STATUS_KEY_PREFIX + MISSING_CLIENT_SEC_GRANT_NAME_KEY, MISSING_CLIENT_SEC_GRANT_NAME_KEY); final EnumMap localizedNames = new EnumMap<>(ConnectionStatus.class); @@ -674,12 +645,18 @@ public class ResourceService { return monitoringEntry -> { final ConnectionStatus status = monitoringEntry.getStatus(); if (status.establishedStatus) { - if (monitoringEntry.hasMissingGrant()) { - return missingGrant; - } if (monitoringEntry.hasMissingPing()) { return missingPing; } + final Boolean grantDenied = monitoringEntry.grantDenied(); + if (grantDenied != null) { + if (grantDenied) { + return grantDeniedText; + } + } else if (monitoringEntry.showNoGrantCheckApplied()) { + return localizedNames.get(status) + grantMissingText; + } + } return localizedNames.get(status); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionDetails.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionDetails.java index 828f8b36..60ca502b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionDetails.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionDetails.java @@ -77,6 +77,7 @@ public class ClientConnectionDetails implements MonitoringEntry { public final boolean checkSecurityGrant; private ClientConnectionData connectionData = null; + public Boolean grantDenied = null; private boolean statusChanged = true; private boolean missingChanged = true; private long startTime = -1; @@ -98,6 +99,7 @@ public class ClientConnectionDetails implements MonitoringEntry { this.colorData = new ColorData(display); this.checkSecurityGrant = BooleanUtils.toBoolean( exam.additionalAttributes.get(Exam.ADDITIONAL_ATTR_SIGNATURE_KEY_CHECK_ENABLED)); + this.indicatorMapping = IndicatorData.createFormIndicators( indicators, display, @@ -167,9 +169,13 @@ public class ClientConnectionDetails implements MonitoringEntry { } @Override - public boolean hasMissingGrant() { - return (this.connectionData != null) - ? this.checkSecurityGrant && !this.connectionData.clientConnection.securityCheckGranted : false; + public Boolean grantDenied() { + return this.grantDenied; + } + + @Override + public boolean showNoGrantCheckApplied() { + return this.checkSecurityGrant; } public void setStatusChangeListener(final Consumer statusChangeListener) { @@ -194,6 +200,11 @@ public class ClientConnectionDetails implements MonitoringEntry { .toBoolean(connectionData.missingPing); } this.connectionData = connectionData; + if (this.connectionData == null || this.connectionData.clientConnection.securityCheckGranted == null) { + this.grantDenied = null; + } else { + this.grantDenied = !this.connectionData.clientConnection.securityCheckGranted; + } if (this.startTime < 0) { this.startTime = System.currentTimeMillis(); } @@ -230,11 +241,13 @@ public class ClientConnectionDetails implements MonitoringEntry { getGroupInfo()); } - if (this.missingChanged) { + if (this.missingChanged || this.statusChanged) { // update status - form.setFieldValue( - Domain.CLIENT_CONNECTION.ATTR_STATUS, - this.localizedClientConnectionStatusNameFunction.apply(this)); + String stateName = this.localizedClientConnectionStatusNameFunction.apply(this); + if (stateName != null) { + stateName = stateName.replace(" ", " "); + } + form.setFieldValue(Domain.CLIENT_CONNECTION.ATTR_STATUS, stateName); final Color statusColor = this.colorData.getStatusColor(this); final Color statusTextColor = this.colorData.getStatusTextColor(statusColor); form.setFieldColor(Domain.CLIENT_CONNECTION.ATTR_STATUS, statusColor); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java index f2111873..52d8750e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ClientConnectionTable.java @@ -479,9 +479,13 @@ public final class ClientConnectionTable implements FullPageMonitoringGUIUpdate } @Override - public boolean hasMissingGrant() { - return (this.staticData != null) - ? ClientConnectionTable.this.checkSecurityGrant && !this.staticData.securityGrant : false; + public Boolean grantDenied() { + return this.monitoringData.grantDenied; + } + + @Override + public boolean showNoGrantCheckApplied() { + return ClientConnectionTable.this.checkSecurityGrant; } private void update(final TableItem tableItem, final boolean force) { @@ -670,10 +674,7 @@ public final class ClientConnectionTable implements FullPageMonitoringGUIUpdate } boolean push(final ClientMonitoringData monitoringData) { - this.dataChanged = this.monitoringData == null || - this.monitoringData.status != monitoringData.status || - this.monitoringData.missingPing != monitoringData.missingPing || - this.monitoringData.missingGrant != monitoringData.missingGrant; + this.dataChanged = this.monitoringData == null || this.monitoringData.hasChanged(monitoringData); this.indicatorValueChanged = this.monitoringData == null || (this.monitoringData.status.clientActiveStatus && !this.monitoringData.indicatorValuesEquals(monitoringData)); @@ -739,7 +740,6 @@ public final class ClientConnectionTable implements FullPageMonitoringGUIUpdate private ClientConnectionTable getOuterType() { return ClientConnectionTable.this; } - } private void fetchStaticClientConnectionData() { diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ColorData.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ColorData.java index 50fd2952..832cc919 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ColorData.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/ColorData.java @@ -41,13 +41,12 @@ public class ColorData { return this.defaultColor; } + final Boolean grantDenied = entry.grantDenied(); switch (status) { case ACTIVE: - return (entry.hasMissingGrant()) - ? this.color3 - : (entry.hasMissingPing()) - ? this.color2 - : this.color1; + return (grantDenied != null && grantDenied) + ? this.color3 : (entry.hasMissingPing()) + ? this.color2 : this.color1; default: return this.defaultColor; } @@ -67,8 +66,9 @@ public class ColorData { case AUTHENTICATED: return 1; case ACTIVE: - return (connectionData.clientConnection.securityCheckGranted) ? -1 - : (connectionData.missingPing) ? 0 : 2; + return (connectionData.clientConnection.securityCheckGranted) + ? -1 : (connectionData.missingPing) + ? 0 : 2; case CLOSED: return 3; default: @@ -81,12 +81,16 @@ public class ColorData { return 100; } + final Boolean grantDenied = entry.grantDenied(); switch (entry.getStatus()) { case CONNECTION_REQUESTED: case AUTHENTICATED: return 1; case ACTIVE: - return (entry.hasMissingGrant()) ? -1 : (entry.hasMissingPing()) ? 0 : 2; + return (grantDenied == null) + ? -1 : (grantDenied) + ? -2 : (entry.hasMissingPing()) + ? 0 : 2; case CLOSED: return 4; default: diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/MonitoringEntry.java b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/MonitoringEntry.java index 087454f3..4c6082b0 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/service/session/MonitoringEntry.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/service/session/MonitoringEntry.java @@ -1,6 +1,6 @@ /* * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) - * + * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. @@ -11,10 +11,19 @@ package ch.ethz.seb.sebserver.gui.service.session; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus; public interface MonitoringEntry { - + ConnectionStatus getStatus(); boolean hasMissingPing(); - boolean hasMissingGrant(); + /** Indicates the security key grant check state + * true = grant denied + * false = granted + * null = not checked yet + * + * @return the security key grant check state */ + Boolean grantDenied(); + + boolean showNoGrantCheckApplied(); + } \ No newline at end of file diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/checks/TableCharsetCheck.java b/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/checks/TableCharsetCheck.java new file mode 100644 index 00000000..85798699 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/datalayer/checks/TableCharsetCheck.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.webservice.datalayer.checks; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +import javax.sql.DataSource; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.annotation.Lazy; +import org.springframework.core.env.Environment; +import org.springframework.stereotype.Component; + +import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; +import ch.ethz.seb.sebserver.gbl.util.Result; +import ch.ethz.seb.sebserver.webservice.DBIntegrityCheck; + +@Lazy +@Component +@WebServiceProfile +public class TableCharsetCheck implements DBIntegrityCheck { + + private static final String UTF8MB4_GENERAL_CI = "utf8mb4_general_ci"; + + private static final Logger log = LoggerFactory.getLogger(TableCharsetCheck.class); + + private final DataSource dataSource; + private final String schemaName; + + public TableCharsetCheck( + final DataSource dataSource, + final Environment environment) { + super(); + this.dataSource = dataSource; + this.schemaName = environment.getProperty("sebserver.init.database.integrity.check.schema", (String) null); + } + + @Override + public String name() { + return "TableCharsetCheck"; + } + + @Override + public String description() { + return "Checks the char-set and collation of DB tables if correct utf8mb4_general_ci is set"; + } + + @Override + public Result applyCheck(final boolean tryFix) { + + if (StringUtils.isEmpty(this.schemaName)) { + return Result.of("Skip check since sebserver.init.database.integrity.check.schema is not defined"); + } + + Connection connection = null; + try { + connection = this.dataSource.getConnection(); + + final PreparedStatement prepareStatement = + connection.prepareStatement( + "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = \"" + this.schemaName + "\""); + prepareStatement.execute(); + final ResultSet resultSet = prepareStatement.getResultSet(); + final Map tablesWithWrongCollation = new HashMap<>(); + while (resultSet.next()) { + final String collation = resultSet.getString("TABLE_COLLATION"); + if (!UTF8MB4_GENERAL_CI.equals(collation)) { + tablesWithWrongCollation.put(resultSet.getString("TABLE_NAME"), collation); + } + } + + final Connection con = connection; + if (!tablesWithWrongCollation.isEmpty()) { + if (tryFix) { + tablesWithWrongCollation.entrySet().forEach(entry -> tryFix(con, entry)); + } else { + return Result.of("Found tables with wrong collation: " + tablesWithWrongCollation); + } + } + + } catch (final Exception e) { + log.error("Failed to apply database table check: ", e); + } finally { + if (connection != null) { + try { + connection.close(); + } catch (final SQLException e) { + log.error("Failed to close connection: ", e); + } + } + } + + return Result.of("OK"); + } + + private void tryFix(final Connection connection, final Map.Entry entry) { + try { + + log.info("Try to fix collation for table: {}", entry); + + final PreparedStatement prepareStatement = connection.prepareStatement( + "ALTER TABLE " + entry.getKey() + " CONVERT TO CHARACTER SET 'utf8mb4' COLLATE '" + + UTF8MB4_GENERAL_CI + + "'"); + + prepareStatement.execute(); + + log.info("Successfully changed collision for table: {}", entry.getKey()); + + } catch (final Exception e) { + log.error("Failed to changed collision for table", e); + } + } + +} diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java index a2d2d264..6d19183a 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/dao/impl/ClientConnectionDAOImpl.java @@ -791,7 +791,10 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { SqlBuilder.isIn(ClientConnection.SECURE_CHECK_STATES)) .and( ClientConnectionRecordDynamicSqlSupport.securityCheckGranted, - SqlBuilder.isEqualTo(Constants.BYTE_FALSE)) + SqlBuilder.isEqualTo(Constants.BYTE_FALSE), SqlBuilder.or( + ClientConnectionRecordDynamicSqlSupport.securityCheckGranted, + SqlBuilder.isNull())) + .and(ClientConnectionRecordDynamicSqlSupport.ask, SqlBuilder.isNotNull()) .build() .execute()); } @@ -864,7 +867,7 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO { record.getUpdateTime(), record.getRemoteProctoringRoomId(), BooleanUtils.toBooleanObject(record.getRemoteProctoringRoomUpdate()), - Utils.fromByte(record.getSecurityCheckGranted()), + Utils.fromByteOrNull(record.getSecurityCheckGranted()), record.getAsk()); }); } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/institution/impl/SecurityKeyServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/institution/impl/SecurityKeyServiceImpl.java index d85bcaf3..357d3bbb 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/institution/impl/SecurityKeyServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/institution/impl/SecurityKeyServiceImpl.java @@ -22,6 +22,7 @@ import org.slf4j.LoggerFactory; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.api.APIMessage.FieldValidationException; import ch.ethz.seb.sebserver.gbl.api.EntityType; import ch.ethz.seb.sebserver.gbl.model.Domain; @@ -181,7 +182,8 @@ public class SecurityKeyServiceImpl implements SecurityKeyService { @Override public void updateAppSignatureKeyGrant(final ClientConnectionRecord record) { try { - if (!Utils.fromByte(record.getSecurityCheckGranted())) { + final Byte securityCheckGranted = record.getSecurityCheckGranted(); + if (securityCheckGranted == null || securityCheckGranted == Constants.BYTE_FALSE) { final String token = record.getConnectionToken(); if (applyAppSignatureCheck( record.getInstitutionId(), @@ -195,14 +197,9 @@ public class SecurityKeyServiceImpl implements SecurityKeyService { log.debug("Update app-signature-key grant for client connection: {}", token); } - this.clientConnectionDAO - .save(new ClientConnection( - record.getId(), null, - null, null, null, null, null, null, null, null, - null, null, null, null, null, null, null, true, null)) - .onError(error -> log.error("Failed to save ClientConnection grant: ", - error)) - .onSuccess(c -> this.examSessionCacheService.evictClientConnection(token)); + saveSecurityCheckState(record, true); + } else if (securityCheckGranted == null) { + saveSecurityCheckState(record, false); } } } catch (final Exception e) { @@ -365,4 +362,15 @@ public class SecurityKeyServiceImpl implements SecurityKeyService { return m; } + private void saveSecurityCheckState(final ClientConnectionRecord record, final Boolean checkStatus) { + this.clientConnectionDAO + .save(new ClientConnection( + record.getId(), null, + null, null, null, null, null, null, null, null, + null, null, null, null, null, null, null, checkStatus, null)) + .onError(error -> log.error("Failed to save ClientConnection grant: ", + error)) + .onSuccess(c -> this.examSessionCacheService.evictClientConnection(record.getConnectionToken())); + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ClientConnectionDataInternal.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ClientConnectionDataInternal.java index 709442b3..56cdbc88 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ClientConnectionDataInternal.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/ClientConnectionDataInternal.java @@ -44,6 +44,8 @@ public class ClientConnectionDataInternal extends ClientConnectionData { PingIntervalClientIndicator pingIndicator = null; private final PendingNotificationIndication pendingNotificationIndication; + private final Boolean grantDenied; + protected ClientConnectionDataInternal( final ClientConnection clientConnection, final PendingNotificationIndication pendingNotificationIndication, @@ -68,6 +70,12 @@ public class ClientConnectionDataInternal extends ClientConnectionData { .add(clientIndicator); } } + + if (clientConnection.securityCheckGranted == null) { + this.grantDenied = null; + } else { + this.grantDenied = !clientConnection.securityCheckGranted; + } } public final void notifyPing(final long timestamp, final int pingNumber) { @@ -143,9 +151,10 @@ public class ClientConnectionDataInternal extends ClientConnectionData { } @Override - public boolean isMissingGrant() { - return BooleanUtils.isFalse(ClientConnectionDataInternal.this.clientConnection.securityCheckGranted); + public Boolean isGrantDenied() { + return ClientConnectionDataInternal.this.grantDenied; } + }; /** This is a static monitoring connection data wrapper/holder */ @@ -155,7 +164,7 @@ public class ClientConnectionDataInternal extends ClientConnectionData { ClientConnectionDataInternal.this.clientConnection.id, ClientConnectionDataInternal.this.clientConnection.connectionToken, ClientConnectionDataInternal.this.clientConnection.userSessionId, - ClientConnectionDataInternal.this.clientConnection.getSecurityCheckGranted(), + ClientConnectionDataInternal.this.clientConnection.ask, ClientConnectionDataInternal.this.clientConnection.info, this.groups); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientConnectionServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientConnectionServiceImpl.java index 2e07b79e..7aca42f0 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientConnectionServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/SEBClientConnectionServiceImpl.java @@ -278,7 +278,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic null, null, null, - false, + null, getSignatureHash(appSignatureKey, connectionToken))) .getOrThrow(); @@ -400,7 +400,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic null, null, proctoringEnabled, - false, + null, getSignatureHash(appSignatureKey, connectionToken)); // ClientConnection integrity check diff --git a/src/main/resources/config/application-ws.properties b/src/main/resources/config/application-ws.properties index 91ee3796..a67ea9b4 100644 --- a/src/main/resources/config/application-ws.properties +++ b/src/main/resources/config/application-ws.properties @@ -9,6 +9,7 @@ sebserver.init.organisation.name=SEB Server sebserver.init.adminaccount.username=sebserver-admin sebserver.init.database.integrity.checks=true sebserver.init.database.integrity.try-fix=true +sebserver.init.database.integrity.check.schema=SEBServer ### webservice caching spring.cache.jcache.provider=org.ehcache.jsr107.EhcacheCachingProvider diff --git a/src/main/resources/messages.properties b/src/main/resources/messages.properties index 4a89d82b..3db5d0d0 100644 --- a/src/main/resources/messages.properties +++ b/src/main/resources/messages.properties @@ -2077,7 +2077,8 @@ sebserver.monitoring.exam.connection.status.CLOSED=Closed sebserver.monitoring.exam.connection.status.ABORTED=Aborted sebserver.monitoring.exam.connection.status.DISABLED=Canceled sebserver.monitoring.exam.connection.status.MISSING_PING=Missing -sebserver.monitoring.exam.connection.status.MISSING_GRANT=Not Granted (ASK) +sebserver.monitoring.exam.connection.status.MISSING_GRANT=  (No ASK Grant) +sebserver.monitoring.exam.connection.status.GRANT_DENIED=ASK Grant Denied sebserver.monitoring.lock.title=Lock SEB Clients sebserver.monitoring.lock.form.info.title=Info