SEBSERV-335 fixed corner cases
This commit is contained in:
parent
5faed87288
commit
4a8a2adc8f
18 changed files with 262 additions and 104 deletions
|
@ -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;
|
||||
|
|
|
@ -25,7 +25,7 @@ public class ClientMonitoringData implements ClientMonitoringDataView {
|
|||
public final ConnectionStatus status;
|
||||
public final Map<Long, String> 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<Long, String> 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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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<Long> 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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<Tuple<String>> RESOURCE_COMPARATOR = Comparator.comparing(t -> t._2);
|
||||
|
@ -625,46 +626,16 @@ public class ResourceService {
|
|||
.getText(ResourceService.EXAMCONFIG_STATUS_PREFIX + config.configStatus.name());
|
||||
}
|
||||
|
||||
// public Function<ClientConnectionData, String> 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<ConnectionStatus, String> 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<MonitoringEntry, String> 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<ConnectionStatus, String> 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);
|
||||
|
|
|
@ -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<ClientConnectionData> 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);
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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();
|
||||
|
||||
}
|
|
@ -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<String> 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<String, String> 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<String, String> 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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());
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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()));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue