commit
afb2685664
14 changed files with 415 additions and 65 deletions
2
.github/workflows/buildReporting.yml
vendored
2
.github/workflows/buildReporting.yml
vendored
|
@ -94,7 +94,7 @@ jobs:
|
||||||
uses: docker/setup-qemu-action@v3
|
uses: docker/setup-qemu-action@v3
|
||||||
-
|
-
|
||||||
name: Set up Docker Buildx
|
name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v4
|
uses: docker/setup-buildx-action@v3.2.0
|
||||||
-
|
-
|
||||||
name: Login to DockerHub
|
name: Login to DockerHub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
|
|
|
@ -102,6 +102,8 @@ public final class Constants {
|
||||||
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
|
||||||
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
|
public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";
|
||||||
|
|
||||||
|
public static final Long LIGHT_ADMIN_USER_ID = 1L;
|
||||||
|
|
||||||
public static final DateTimeFormatter STANDARD_DATE_TIME_MILLIS_FORMATTER = DateTimeFormat
|
public static final DateTimeFormatter STANDARD_DATE_TIME_MILLIS_FORMATTER = DateTimeFormat
|
||||||
.forPattern(DEFAULT_DATE_TIME_MILLIS_FORMAT)
|
.forPattern(DEFAULT_DATE_TIME_MILLIS_FORMAT)
|
||||||
.withZoneUTC();
|
.withZoneUTC();
|
||||||
|
|
|
@ -126,6 +126,8 @@ public final class API {
|
||||||
|
|
||||||
public static final String EXAM_API_CONFIGURATION_REQUEST_ENDPOINT = "/examconfig";
|
public static final String EXAM_API_CONFIGURATION_REQUEST_ENDPOINT = "/examconfig";
|
||||||
|
|
||||||
|
public static final String EXAM_API_CONFIGURATION_LIGHT_ENDPOINT = "/light-config";
|
||||||
|
|
||||||
public static final String EXAM_API_PING_ENDPOINT = "/sebping";
|
public static final String EXAM_API_PING_ENDPOINT = "/sebping";
|
||||||
|
|
||||||
public static final String EXAM_API_PING_TIMESTAMP = "timestamp";
|
public static final String EXAM_API_PING_TIMESTAMP = "timestamp";
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.springframework.security.core.GrantedAuthority;
|
import org.springframework.security.core.GrantedAuthority;
|
||||||
|
|
||||||
|
@ -60,4 +61,10 @@ public enum UserRole implements Entity, GrantedAuthority {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<String> getNamesForAllRoles(){
|
||||||
|
return Arrays.stream(UserRole.values())
|
||||||
|
.map(UserRole::getName)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,8 @@ public class GuiWebsecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
.antMatchers(API.ERROR_PATH).permitAll()
|
.antMatchers(API.ERROR_PATH).permitAll()
|
||||||
.antMatchers(API.CHECK_PATH).permitAll()
|
.antMatchers(API.CHECK_PATH).permitAll()
|
||||||
.antMatchers(this.examAPIDiscoveryEndpoint).permitAll()
|
.antMatchers(this.examAPIDiscoveryEndpoint).permitAll()
|
||||||
|
.antMatchers(this.examAPIDiscoveryEndpoint + API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT).permitAll()
|
||||||
|
.antMatchers(this.examAPIDiscoveryEndpoint + API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT + API.PASSWORD_PATH_SEGMENT).permitAll()
|
||||||
.antMatchers(adminAPIEndpoint + API.INFO_ENDPOINT + API.LOGO_PATH_SEGMENT + "/**").permitAll()
|
.antMatchers(adminAPIEndpoint + API.INFO_ENDPOINT + API.LOGO_PATH_SEGMENT + "/**").permitAll()
|
||||||
.antMatchers(adminAPIEndpoint + API.INFO_ENDPOINT + API.INFO_INST_PATH_SEGMENT + "/**").permitAll()
|
.antMatchers(adminAPIEndpoint + API.INFO_ENDPOINT + API.INFO_INST_PATH_SEGMENT + "/**").permitAll()
|
||||||
.antMatchers(adminAPIEndpoint + API.REGISTER_ENDPOINT).permitAll()
|
.antMatchers(adminAPIEndpoint + API.REGISTER_ENDPOINT).permitAll()
|
||||||
|
|
|
@ -8,10 +8,16 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice;
|
package ch.ethz.seb.sebserver.webservice;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.AdditionalAttributesDAO;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -40,26 +46,32 @@ class AdminUserInitializer {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(AdminUserInitializer.class);
|
private static final Logger log = LoggerFactory.getLogger(AdminUserInitializer.class);
|
||||||
|
|
||||||
|
private final WebserviceInfo webserviceInfo;
|
||||||
private final UserDAO userDAO;
|
private final UserDAO userDAO;
|
||||||
private final InstitutionDAO institutionDAO;
|
private final InstitutionDAO institutionDAO;
|
||||||
private final PasswordEncoder passwordEncoder;
|
private final PasswordEncoder passwordEncoder;
|
||||||
|
private final AdditionalAttributesDAO additionalAttributesDAO;
|
||||||
private final boolean initializeAdmin;
|
private final boolean initializeAdmin;
|
||||||
private final String adminName;
|
private final String adminName;
|
||||||
private final String orgName;
|
private final String orgName;
|
||||||
private final Environment environment;
|
private final Environment environment;
|
||||||
|
|
||||||
public AdminUserInitializer(
|
public AdminUserInitializer(
|
||||||
|
final WebserviceInfo webserviceInfo,
|
||||||
final UserDAO userDAO,
|
final UserDAO userDAO,
|
||||||
final InstitutionDAO institutionDAO,
|
final InstitutionDAO institutionDAO,
|
||||||
|
final AdditionalAttributesDAO additionalAttributesDAO,
|
||||||
final Environment environment,
|
final Environment environment,
|
||||||
@Qualifier(WebSecurityConfig.USER_PASSWORD_ENCODER_BEAN_NAME) final PasswordEncoder passwordEncoder,
|
@Qualifier(WebSecurityConfig.USER_PASSWORD_ENCODER_BEAN_NAME) final PasswordEncoder passwordEncoder,
|
||||||
@Value("${sebserver.init.adminaccount.gen-on-init:false}") final boolean initializeAdmin,
|
@Value("${sebserver.init.adminaccount.gen-on-init:false}") final boolean initializeAdmin,
|
||||||
@Value("${sebserver.init.adminaccount.username:seb-server-admin}") final String adminName,
|
@Value("${sebserver.init.adminaccount.username:seb-server-admin}") final String adminName,
|
||||||
@Value("${sebserver.init.organisation.name:[SET_ORGANIZATION_NAME]}") final String orgName) {
|
@Value("${sebserver.init.organisation.name:[SET_ORGANIZATION_NAME]}") final String orgName) {
|
||||||
|
|
||||||
|
this.webserviceInfo = webserviceInfo;
|
||||||
this.environment = environment;
|
this.environment = environment;
|
||||||
this.userDAO = userDAO;
|
this.userDAO = userDAO;
|
||||||
this.institutionDAO = institutionDAO;
|
this.institutionDAO = institutionDAO;
|
||||||
|
this.additionalAttributesDAO = additionalAttributesDAO;
|
||||||
this.passwordEncoder = passwordEncoder;
|
this.passwordEncoder = passwordEncoder;
|
||||||
this.initializeAdmin = initializeAdmin;
|
this.initializeAdmin = initializeAdmin;
|
||||||
this.adminName = adminName;
|
this.adminName = adminName;
|
||||||
|
@ -68,7 +80,7 @@ class AdminUserInitializer {
|
||||||
|
|
||||||
void initAdminAccount() {
|
void initAdminAccount() {
|
||||||
if (!this.initializeAdmin) {
|
if (!this.initializeAdmin) {
|
||||||
log.debug("Create initial admin account is switched on off");
|
log.debug("Create initial admin account is switched off");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +102,7 @@ class AdminUserInitializer {
|
||||||
this.userDAO.changePassword(
|
this.userDAO.changePassword(
|
||||||
sebServerUser.getUserInfo().getModelId(),
|
sebServerUser.getUserInfo().getModelId(),
|
||||||
generateAdminPassword);
|
generateAdminPassword);
|
||||||
this.writeAdminCredentials(this.adminName, generateAdminPassword);
|
this.printAdminCredentials(this.adminName, generateAdminPassword);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -133,10 +145,16 @@ class AdminUserInitializer {
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
new HashSet<>(Arrays.asList(UserRole.SEB_SERVER_ADMIN.name()))))
|
new HashSet<>(this.webserviceInfo.isLightSetup() ?
|
||||||
|
UserRole.getNamesForAllRoles() :
|
||||||
|
List.of(UserRole.SEB_SERVER_ADMIN.name())
|
||||||
|
)))
|
||||||
.flatMap(account -> this.userDAO.setActive(account, true))
|
.flatMap(account -> this.userDAO.setActive(account, true))
|
||||||
.map(account -> {
|
.map(account -> {
|
||||||
writeAdminCredentials(this.adminName, generateAdminPassword);
|
printAdminCredentials(this.adminName, generateAdminPassword);
|
||||||
|
if(this.webserviceInfo.isLightSetup()) {
|
||||||
|
writeInitialAdminCredentialsIntoDB(this.adminName, generateAdminPassword);
|
||||||
|
}
|
||||||
return account;
|
return account;
|
||||||
})
|
})
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
@ -148,7 +166,7 @@ class AdminUserInitializer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeAdminCredentials(final String name, final CharSequence pwd) {
|
private void printAdminCredentials(final String name, final CharSequence pwd) {
|
||||||
SEBServerInit.INIT_LOGGER.info("---->");
|
SEBServerInit.INIT_LOGGER.info("---->");
|
||||||
SEBServerInit.INIT_LOGGER.info(
|
SEBServerInit.INIT_LOGGER.info(
|
||||||
"----> ******************************************************************************************"
|
"----> ******************************************************************************************"
|
||||||
|
@ -163,6 +181,23 @@ class AdminUserInitializer {
|
||||||
SEBServerInit.INIT_LOGGER.info("---->");
|
SEBServerInit.INIT_LOGGER.info("---->");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void writeInitialAdminCredentialsIntoDB(final String name, final CharSequence pwd){
|
||||||
|
try {
|
||||||
|
final Map<String, String> attributes = new HashMap<>();
|
||||||
|
attributes.put(
|
||||||
|
Domain.USER.ATTR_USERNAME,
|
||||||
|
name);
|
||||||
|
attributes.put(
|
||||||
|
Domain.USER.ATTR_PASSWORD,
|
||||||
|
String.valueOf(pwd));
|
||||||
|
|
||||||
|
this.additionalAttributesDAO.saveAdditionalAttributes(EntityType.USER, Constants.LIGHT_ADMIN_USER_ID, attributes);
|
||||||
|
|
||||||
|
} catch (final Exception e) {
|
||||||
|
log.error("Unable to write initial admin credentials into the additional attributes table: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private CharSequence generateAdminPassword() {
|
private CharSequence generateAdminPassword() {
|
||||||
try {
|
try {
|
||||||
return ClientCredentialServiceImpl.generateClientSecret();
|
return ClientCredentialServiceImpl.generateClientSecret();
|
||||||
|
|
|
@ -102,14 +102,16 @@ public class WebserviceInit implements ApplicationListener<ApplicationReadyEvent
|
||||||
SEBServerInit.INIT_LOGGER.info("----> Initialize Services...");
|
SEBServerInit.INIT_LOGGER.info("----> Initialize Services...");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> ");
|
SEBServerInit.INIT_LOGGER.info("----> ");
|
||||||
|
|
||||||
this.applicationEventPublisher.publishEvent(new SEBServerInitEvent(this));
|
|
||||||
|
|
||||||
// Run the database integrity checks and fixes if configured
|
// Run the database integrity checks and fixes if configured
|
||||||
this.dbIntegrityChecker.checkIntegrity();
|
this.dbIntegrityChecker.checkIntegrity();
|
||||||
|
|
||||||
// Create an initial admin account if requested and not already in the database
|
// Create an initial admin account if requested and not already in the database
|
||||||
this.adminUserInitializer.initAdminAccount();
|
this.adminUserInitializer.initAdminAccount();
|
||||||
|
|
||||||
|
//emits SEBServerInitEvent
|
||||||
|
this.applicationEventPublisher.publishEvent(new SEBServerInitEvent(this));
|
||||||
|
|
||||||
|
|
||||||
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> *** Webservice Info: ***");
|
SEBServerInit.INIT_LOGGER.info("----> *** Webservice Info: ***");
|
||||||
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
SEBServerInit.INIT_LOGGER.info("----> *********************************************************");
|
||||||
|
|
|
@ -0,0 +1,78 @@
|
||||||
|
package ch.ethz.seb.sebserver.webservice.servicelayer.light.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.SEBServerInitEvent;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SEBClientConfigDAO;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.context.event.EventListener;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@Lazy
|
||||||
|
@Service
|
||||||
|
@ConditionalOnExpression("'${sebserver.webservice.light.setup}'.equals('true')")
|
||||||
|
public class LightInit {
|
||||||
|
|
||||||
|
private final SEBClientConfigDAO sebClientConfigDAO;
|
||||||
|
|
||||||
|
public LightInit(final SEBClientConfigDAO sebClientConfigDAO){
|
||||||
|
this.sebClientConfigDAO = sebClientConfigDAO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventListener(SEBServerInitEvent.class)
|
||||||
|
public void init() {
|
||||||
|
if(isConnectionConfigAbsent()){
|
||||||
|
this.sebClientConfigDAO.createNew(createLightConnectionConfiguration())
|
||||||
|
.getOrThrow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isConnectionConfigAbsent() {
|
||||||
|
Collection<SEBClientConfig> connectionConfigs = this.sebClientConfigDAO
|
||||||
|
.all(null, null)
|
||||||
|
.getOrThrow();
|
||||||
|
|
||||||
|
if(connectionConfigs.size() == 0){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SEBClientConfig createLightConnectionConfiguration(){
|
||||||
|
return new SEBClientConfig(
|
||||||
|
1L,
|
||||||
|
1L,
|
||||||
|
"light-config",
|
||||||
|
SEBClientConfig.ConfigPurpose.CONFIGURE_CLIENT,
|
||||||
|
1000L,
|
||||||
|
SEBClientConfig.VDIType.NO,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -9,6 +9,7 @@
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.session;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.session;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
|
@ -173,4 +174,8 @@ public interface SEBClientConnectionService {
|
||||||
String ipAddress,
|
String ipAddress,
|
||||||
HttpServletResponse response);
|
HttpServletResponse response);
|
||||||
|
|
||||||
|
void streamLightExamConfig(
|
||||||
|
String modelId,
|
||||||
|
HttpServletResponse response) throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,23 +8,36 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
|
package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
|
||||||
|
|
||||||
import javax.servlet.ServletOutputStream;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.security.Principal;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
import ch.ethz.seb.sebserver.gbl.api.JSONMapper;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
import ch.ethz.seb.sebserver.gbl.model.Entity;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings;
|
import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.ScreenProctoringSettings;
|
import ch.ethz.seb.sebserver.gbl.model.exam.ScreenProctoringSettings;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.VDIType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
||||||
|
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.ClientEvent;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientEvent;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
|
import ch.ethz.seb.sebserver.gbl.model.session.ClientInstruction;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SEBClientConfigDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamAdminService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.institution.SecurityKeyService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.sebconfig.ClientConfigService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientConnectionService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientInstructionService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientInstructionService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator.DistributedIndicatorValueService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.weblayer.api.APIConstraintViolationException;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.lang3.BooleanUtils;
|
import org.apache.commons.lang3.BooleanUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
|
@ -34,25 +47,20 @@ import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.security.access.AccessDeniedException;
|
import org.springframework.security.access.AccessDeniedException;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.gbl.Constants;
|
import javax.servlet.ServletOutputStream;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
|
import java.io.IOException;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig;
|
import java.io.PipedInputStream;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.sebconfig.SEBClientConfig.VDIType;
|
import java.io.PipedOutputStream;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
|
import java.security.Principal;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection.ConnectionStatus;
|
import java.util.Arrays;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData;
|
import java.util.Collection;
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
import java.util.Collections;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
import java.util.Objects;
|
||||||
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
import java.util.UUID;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.ClientConnectionDAO;
|
import java.util.function.Predicate;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SEBClientConfigDAO;
|
import java.util.stream.Collectors;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.exam.ExamAdminService;
|
import java.util.stream.Stream;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.institution.SecurityKeyService;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientConnectionService;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.indicator.DistributedIndicatorValueService;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.weblayer.api.APIConstraintViolationException;
|
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
@Service
|
@Service
|
||||||
|
@ -79,6 +87,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
private final SecurityKeyService securityKeyService;
|
private final SecurityKeyService securityKeyService;
|
||||||
private final SEBClientEventBatchService sebClientEventBatchService;
|
private final SEBClientEventBatchService sebClientEventBatchService;
|
||||||
private final SEBClientInstructionService sebClientInstructionService;
|
private final SEBClientInstructionService sebClientInstructionService;
|
||||||
|
private final ClientConfigService clientConfigService;
|
||||||
private final JSONMapper jsonMapper;
|
private final JSONMapper jsonMapper;
|
||||||
private final boolean isDistributedSetup;
|
private final boolean isDistributedSetup;
|
||||||
|
|
||||||
|
@ -92,6 +101,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
final WebserviceInfo webserviceInfo,
|
final WebserviceInfo webserviceInfo,
|
||||||
final SEBClientEventBatchService sebClientEventBatchService,
|
final SEBClientEventBatchService sebClientEventBatchService,
|
||||||
final SEBClientInstructionService sebClientInstructionService,
|
final SEBClientInstructionService sebClientInstructionService,
|
||||||
|
final ClientConfigService clientConfigService,
|
||||||
final JSONMapper jsonMapper) {
|
final JSONMapper jsonMapper) {
|
||||||
|
|
||||||
this.examSessionService = examSessionService;
|
this.examSessionService = examSessionService;
|
||||||
|
@ -105,6 +115,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
this.isDistributedSetup = webserviceInfo.isDistributed();
|
this.isDistributedSetup = webserviceInfo.isDistributed();
|
||||||
this.sebClientEventBatchService = sebClientEventBatchService;
|
this.sebClientEventBatchService = sebClientEventBatchService;
|
||||||
this.sebClientInstructionService = sebClientInstructionService;
|
this.sebClientInstructionService = sebClientInstructionService;
|
||||||
|
this.clientConfigService = clientConfigService;
|
||||||
this.jsonMapper = jsonMapper;
|
this.jsonMapper = jsonMapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -623,6 +634,42 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void streamLightExamConfig(final String modelId, final HttpServletResponse response) throws IOException{
|
||||||
|
|
||||||
|
final ServletOutputStream outputStream = response.getOutputStream();
|
||||||
|
PipedOutputStream pout;
|
||||||
|
PipedInputStream pin;
|
||||||
|
|
||||||
|
try {
|
||||||
|
pout = new PipedOutputStream();
|
||||||
|
pin = new PipedInputStream(pout);
|
||||||
|
|
||||||
|
this.clientConfigService.exportSEBClientConfiguration(
|
||||||
|
pout,
|
||||||
|
modelId,
|
||||||
|
null);
|
||||||
|
|
||||||
|
IOUtils.copyLarge(pin, outputStream);
|
||||||
|
|
||||||
|
response.setStatus(HttpStatus.OK.value());
|
||||||
|
|
||||||
|
}catch(Exception e){
|
||||||
|
final APIMessage errorMessage = APIMessage.ErrorMessage.GENERIC.of(e.getMessage());
|
||||||
|
outputStream.write(Utils.toByteArray(this.jsonMapper.writeValueAsString(errorMessage)));
|
||||||
|
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
|
||||||
|
try {
|
||||||
|
outputStream.flush();
|
||||||
|
outputStream.close();
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("error while flushing / closing output stream", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void writeSEBClientErrors(
|
private void writeSEBClientErrors(
|
||||||
final HttpServletResponse response,
|
final HttpServletResponse response,
|
||||||
final Collection<APIMessage> errorMessages) {
|
final Collection<APIMessage> errorMessages) {
|
||||||
|
@ -938,4 +985,4 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic
|
||||||
return (exam != null && exam.lmsSetupId == null && status == ConnectionStatus.READY) ||
|
return (exam != null && exam.lmsSetupId == null && status == ConnectionStatus.READY) ||
|
||||||
status == ConnectionStatus.ACTIVE;
|
status == ConnectionStatus.ACTIVE;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,132 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 ETH Zürich, IT Services / Informatikdienste (ID)
|
||||||
|
*
|
||||||
|
* 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.weblayer.api;
|
||||||
|
|
||||||
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.async.AsyncServiceSpringConfig;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Utils;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.AdditionalAttributesDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SEBClientConfigDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.SEBClientConnectionService;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
@WebServiceProfile
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("${sebserver.webservice.api.exam.endpoint.discovery}")
|
||||||
|
@ConditionalOnExpression("'${sebserver.webservice.light.setup}'.equals('true')")
|
||||||
|
public class LightController {
|
||||||
|
|
||||||
|
private final SEBClientConnectionService sebClientConnectionService;
|
||||||
|
private final SEBClientConfigDAO sebClientConfigDAO;
|
||||||
|
private final AdditionalAttributesDAO additionalAttributesDAO;
|
||||||
|
private final Executor executor;
|
||||||
|
|
||||||
|
protected LightController(
|
||||||
|
final SEBClientConnectionService sebClientConnectionService,
|
||||||
|
final SEBClientConfigDAO sebClientConfigDAO,
|
||||||
|
final AdditionalAttributesDAO additionalAttributesDAO,
|
||||||
|
@Qualifier(AsyncServiceSpringConfig.EXAM_API_EXECUTOR_BEAN_NAME) final Executor executor) {
|
||||||
|
|
||||||
|
this.sebClientConnectionService = sebClientConnectionService;
|
||||||
|
this.sebClientConfigDAO = sebClientConfigDAO;
|
||||||
|
this.additionalAttributesDAO = additionalAttributesDAO;
|
||||||
|
this.executor = executor;
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(
|
||||||
|
path = API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT,
|
||||||
|
method = RequestMethod.GET,
|
||||||
|
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
|
||||||
|
public CompletableFuture<Void> getLightConfig(
|
||||||
|
final HttpServletRequest request,
|
||||||
|
final HttpServletResponse response){
|
||||||
|
|
||||||
|
return CompletableFuture.runAsync(
|
||||||
|
() -> {
|
||||||
|
try {
|
||||||
|
this.sebClientConnectionService.streamLightExamConfig("1", response);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
this.executor
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequestMapping(
|
||||||
|
path = API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT + API.PASSWORD_PATH_SEGMENT,
|
||||||
|
method = RequestMethod.GET,
|
||||||
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
|
public UsernamePasswordView getInitialAdminPassword(
|
||||||
|
final HttpServletRequest request,
|
||||||
|
final HttpServletResponse response){
|
||||||
|
|
||||||
|
try {
|
||||||
|
final String username = this.additionalAttributesDAO.getAdditionalAttribute(EntityType.USER, Constants.LIGHT_ADMIN_USER_ID, Domain.USER.ATTR_USERNAME)
|
||||||
|
.getOrThrow()
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
final String password = this.additionalAttributesDAO.getAdditionalAttribute(EntityType.USER, Constants.LIGHT_ADMIN_USER_ID, Domain.USER.ATTR_PASSWORD)
|
||||||
|
.getOrThrow()
|
||||||
|
.getValue();
|
||||||
|
|
||||||
|
return new UsernamePasswordView(
|
||||||
|
username,
|
||||||
|
password
|
||||||
|
);
|
||||||
|
|
||||||
|
} catch (final Exception e) {
|
||||||
|
return new UsernamePasswordView(
|
||||||
|
"initial username missing or changed",
|
||||||
|
"inital password missing or changed"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getSebClientConfigId() {
|
||||||
|
return this.sebClientConfigDAO
|
||||||
|
.allMatching(
|
||||||
|
new FilterMap().putIfAbsent(
|
||||||
|
"active",
|
||||||
|
String.valueOf(true)
|
||||||
|
),
|
||||||
|
Utils.truePredicate()
|
||||||
|
)
|
||||||
|
.getOrThrow()
|
||||||
|
.stream()
|
||||||
|
.toList()
|
||||||
|
.get(0)
|
||||||
|
.getModelId();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
record UsernamePasswordView(String username, String password) {
|
||||||
|
@JsonCreator
|
||||||
|
UsernamePasswordView {
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,19 +8,43 @@
|
||||||
|
|
||||||
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
package ch.ethz.seb.sebserver.webservice.weblayer.api;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
||||||
import java.util.Collection;
|
import ch.ethz.seb.sebserver.gbl.Constants;
|
||||||
import java.util.EnumSet;
|
import ch.ethz.seb.sebserver.gbl.api.API;
|
||||||
import java.util.List;
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
|
||||||
import javax.validation.Valid;
|
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.Domain;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
import ch.ethz.seb.sebserver.gbl.model.EntityProcessingReport;
|
||||||
import ch.ethz.seb.sebserver.gbl.model.user.*;
|
import ch.ethz.seb.sebserver.gbl.model.user.PasswordChange;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.user.UserAccount;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.user.UserFeatures;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.user.UserInfo;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.user.UserLogActivityType;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.user.UserMod;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.model.user.UserRole;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Pair;
|
import ch.ethz.seb.sebserver.gbl.util.Pair;
|
||||||
|
import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.WebserviceInfo;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.FeatureService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.FeatureService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.AdditionalAttributesDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserDAO;
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringService;
|
import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
|
||||||
|
import ch.ethz.seb.sebserver.webservice.weblayer.oauth.RevokeTokenEndpoint;
|
||||||
import org.mybatis.dynamic.sql.SqlTable;
|
import org.mybatis.dynamic.sql.SqlTable;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.context.ApplicationEventPublisher;
|
import org.springframework.context.ApplicationEventPublisher;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
|
@ -32,35 +56,25 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
import org.springframework.web.bind.annotation.RequestMethod;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import ch.ethz.seb.sebserver.WebSecurityConfig;
|
import javax.validation.Valid;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.API;
|
import java.util.ArrayList;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
|
import java.util.Collection;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException;
|
import java.util.EnumSet;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.EntityType;
|
import java.util.List;
|
||||||
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.api.authorization.Privilege;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
|
|
||||||
import ch.ethz.seb.sebserver.gbl.util.Result;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.datalayer.batis.mapper.UserRecordDynamicSqlSupport;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.PaginationService;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.bulkaction.BulkActionService;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserActivityLogDAO;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.dao.UserDAO;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.servicelayer.validation.BeanValidationService;
|
|
||||||
import ch.ethz.seb.sebserver.webservice.weblayer.oauth.RevokeTokenEndpoint;
|
|
||||||
|
|
||||||
@WebServiceProfile
|
@WebServiceProfile
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("${sebserver.webservice.api.admin.endpoint}" + API.USER_ACCOUNT_ENDPOINT)
|
@RequestMapping("${sebserver.webservice.api.admin.endpoint}" + API.USER_ACCOUNT_ENDPOINT)
|
||||||
public class UserAccountController extends ActivatableEntityController<UserInfo, UserMod> {
|
public class UserAccountController extends ActivatableEntityController<UserInfo, UserMod> {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(UserAccountController.class);
|
||||||
|
|
||||||
private final ApplicationEventPublisher applicationEventPublisher;
|
private final ApplicationEventPublisher applicationEventPublisher;
|
||||||
private final UserDAO userDAO;
|
private final UserDAO userDAO;
|
||||||
private final PasswordEncoder userPasswordEncoder;
|
private final PasswordEncoder userPasswordEncoder;
|
||||||
private final ScreenProctoringService screenProctoringService;
|
private final ScreenProctoringService screenProctoringService;
|
||||||
|
private final AdditionalAttributesDAO additionalAttributesDAO;
|
||||||
|
private final WebserviceInfo webserviceInfo;
|
||||||
|
|
||||||
private final FeatureService featureService;
|
private final FeatureService featureService;
|
||||||
|
|
||||||
|
@ -73,6 +87,8 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
||||||
final ApplicationEventPublisher applicationEventPublisher,
|
final ApplicationEventPublisher applicationEventPublisher,
|
||||||
final BeanValidationService beanValidationService,
|
final BeanValidationService beanValidationService,
|
||||||
final ScreenProctoringService screenProctoringService,
|
final ScreenProctoringService screenProctoringService,
|
||||||
|
final AdditionalAttributesDAO additionalAttributesDAO,
|
||||||
|
final WebserviceInfo webserviceInfo,
|
||||||
final FeatureService featureService,
|
final FeatureService featureService,
|
||||||
@Qualifier(WebSecurityConfig.USER_PASSWORD_ENCODER_BEAN_NAME) final PasswordEncoder userPasswordEncoder) {
|
@Qualifier(WebSecurityConfig.USER_PASSWORD_ENCODER_BEAN_NAME) final PasswordEncoder userPasswordEncoder) {
|
||||||
|
|
||||||
|
@ -86,6 +102,8 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
||||||
this.userDAO = userDAO;
|
this.userDAO = userDAO;
|
||||||
this.userPasswordEncoder = userPasswordEncoder;
|
this.userPasswordEncoder = userPasswordEncoder;
|
||||||
this.screenProctoringService = screenProctoringService;
|
this.screenProctoringService = screenProctoringService;
|
||||||
|
this.additionalAttributesDAO = additionalAttributesDAO;
|
||||||
|
this.webserviceInfo = webserviceInfo;
|
||||||
this.featureService = featureService;
|
this.featureService = featureService;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,6 +206,7 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
||||||
.flatMap(this::revokeAccessToken)
|
.flatMap(this::revokeAccessToken)
|
||||||
.flatMap(e -> this.userActivityLogDAO.log(UserLogActivityType.PASSWORD_CHANGE, e))
|
.flatMap(e -> this.userActivityLogDAO.log(UserLogActivityType.PASSWORD_CHANGE, e))
|
||||||
.map(this::synchronizeUserWithSPS)
|
.map(this::synchronizeUserWithSPS)
|
||||||
|
.map(this::removeInitialAdminPasswordFromDB)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -293,4 +312,21 @@ public class UserAccountController extends ActivatableEntityController<UserInfo,
|
||||||
screenProctoringService.synchronizeSPSUser(userInfo.uuid);
|
screenProctoringService.synchronizeSPSUser(userInfo.uuid);
|
||||||
return userInfo;
|
return userInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UserInfo removeInitialAdminPasswordFromDB(final UserInfo userInfo){
|
||||||
|
if(!this.webserviceInfo.isLightSetup()){
|
||||||
|
return userInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
try{
|
||||||
|
this.additionalAttributesDAO.delete(EntityType.USER, Constants.LIGHT_ADMIN_USER_ID, Domain.USER.ATTR_USERNAME);
|
||||||
|
this.additionalAttributesDAO.delete(EntityType.USER, Constants.LIGHT_ADMIN_USER_ID, Domain.USER.ATTR_PASSWORD);
|
||||||
|
|
||||||
|
}catch(final Exception e){
|
||||||
|
log.error("Unable to delete initial admin credentials from the additional attributes table: ", e);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return userInfo;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,6 +82,8 @@ public abstract class WebserviceResourceConfiguration extends ResourceServerConf
|
||||||
.antMatchers(API.ERROR_PATH).permitAll()
|
.antMatchers(API.ERROR_PATH).permitAll()
|
||||||
.antMatchers(API.CHECK_PATH).permitAll()
|
.antMatchers(API.CHECK_PATH).permitAll()
|
||||||
.antMatchers(this.examAPIDiscoveryEndpoint).permitAll()
|
.antMatchers(this.examAPIDiscoveryEndpoint).permitAll()
|
||||||
|
.antMatchers(this.examAPIDiscoveryEndpoint + API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT).permitAll()
|
||||||
|
.antMatchers(this.examAPIDiscoveryEndpoint + API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT + API.PASSWORD_PATH_SEGMENT).permitAll()
|
||||||
.antMatchers(configurerAdapter.apiEndpoint + API.INFO_ENDPOINT + API.LOGO_PATH_SEGMENT + "/**").permitAll()
|
.antMatchers(configurerAdapter.apiEndpoint + API.INFO_ENDPOINT + API.LOGO_PATH_SEGMENT + "/**").permitAll()
|
||||||
.antMatchers(configurerAdapter.apiEndpoint + API.INFO_ENDPOINT + API.INFO_INST_PATH_SEGMENT + "/**").permitAll()
|
.antMatchers(configurerAdapter.apiEndpoint + API.INFO_ENDPOINT + API.INFO_INST_PATH_SEGMENT + "/**").permitAll()
|
||||||
.antMatchers(configurerAdapter.apiEndpoint + API.REGISTER_ENDPOINT).permitAll()
|
.antMatchers(configurerAdapter.apiEndpoint + API.REGISTER_ENDPOINT).permitAll()
|
||||||
|
|
|
@ -27,7 +27,7 @@ sebserver.init.database.integrity.try-fix=true
|
||||||
|
|
||||||
# webservice setup configuration
|
# webservice setup configuration
|
||||||
sebserver.init.adminaccount.gen-on-init=false
|
sebserver.init.adminaccount.gen-on-init=false
|
||||||
sebserver.webservice.light.setup=false
|
sebserver.webservice.light.setup=true
|
||||||
sebserver.webservice.distributed=false
|
sebserver.webservice.distributed=false
|
||||||
#sebserver.webservice.master.delay.threshold=10000
|
#sebserver.webservice.master.delay.threshold=10000
|
||||||
sebserver.webservice.http.external.scheme=http
|
sebserver.webservice.http.external.scheme=http
|
||||||
|
|
Loading…
Reference in a new issue