From cecce64ba096eaf8466ecdbce50e5887d50b03c7 Mon Sep 17 00:00:00 2001 From: Nadim Ritter Date: Wed, 21 Feb 2024 16:10:59 +0100 Subject: [PATCH 01/10] SEBSLI-9 create new endpoint for light setup to stream exam config --- .../ethz/seb/sebserver/WebSecurityConfig.java | 1 + .../ch/ethz/seb/sebserver/gbl/api/API.java | 2 + .../session/SEBClientConnectionService.java | 5 + .../impl/SEBClientConnectionServiceImpl.java | 97 +++++++++++++------ .../api/ExamAPIDiscoveryLightController.java | 95 ++++++++++++++++++ 5 files changed, 173 insertions(+), 27 deletions(-) create mode 100644 src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAPIDiscoveryLightController.java diff --git a/src/main/java/ch/ethz/seb/sebserver/WebSecurityConfig.java b/src/main/java/ch/ethz/seb/sebserver/WebSecurityConfig.java index d627365a..56f97369 100644 --- a/src/main/java/ch/ethz/seb/sebserver/WebSecurityConfig.java +++ b/src/main/java/ch/ethz/seb/sebserver/WebSecurityConfig.java @@ -84,6 +84,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E .antMatchers(ERROR_PATH) .antMatchers(CHECK_PATH) .antMatchers(this.examAPIDiscoveryEndpoint) + .antMatchers(this.examAPIDiscoveryEndpoint + API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT) .antMatchers(this.adminAPIEndpoint + API.INFO_ENDPOINT + API.LOGO_PATH_SEGMENT + "/**") .antMatchers(this.adminAPIEndpoint + API.INFO_ENDPOINT + API.INFO_INST_PATH_SEGMENT + "/**") .antMatchers(this.adminAPIEndpoint + API.REGISTER_ENDPOINT); diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java b/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java index 5f963fe7..124d6979 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/api/API.java @@ -123,6 +123,8 @@ public final class API { 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_TIMESTAMP = "timestamp"; diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/SEBClientConnectionService.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/SEBClientConnectionService.java index c28fe531..991df767 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/SEBClientConnectionService.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/SEBClientConnectionService.java @@ -9,6 +9,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session; import javax.servlet.http.HttpServletResponse; +import java.io.IOException; import java.security.Principal; import java.util.Collection; @@ -173,4 +174,8 @@ public interface SEBClientConnectionService { String ipAddress, HttpServletResponse response); + void streamLightExamConfig( + String modelId, + HttpServletResponse response) throws IOException; + } 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 f3f064bb..c02c6d06 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 @@ -8,23 +8,36 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl; -import javax.servlet.ServletOutputStream; -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.Constants; import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.JSONMapper; 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.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.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.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.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.StringUtils; import org.slf4j.Logger; @@ -34,25 +47,20 @@ import org.springframework.http.HttpStatus; import org.springframework.security.access.AccessDeniedException; import org.springframework.stereotype.Service; -import ch.ethz.seb.sebserver.gbl.Constants; -import ch.ethz.seb.sebserver.gbl.model.EntityKey; -import ch.ethz.seb.sebserver.gbl.model.exam.Exam; -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.profile.WebServiceProfile; -import ch.ethz.seb.sebserver.gbl.util.Result; -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.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; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; +import java.security.Principal; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Objects; +import java.util.UUID; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.Stream; @Lazy @Service @@ -79,6 +87,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic private final SecurityKeyService securityKeyService; private final SEBClientEventBatchService sebClientEventBatchService; private final SEBClientInstructionService sebClientInstructionService; + private final ClientConfigService clientConfigService; private final JSONMapper jsonMapper; private final boolean isDistributedSetup; @@ -92,6 +101,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic final WebserviceInfo webserviceInfo, final SEBClientEventBatchService sebClientEventBatchService, final SEBClientInstructionService sebClientInstructionService, + final ClientConfigService clientConfigService, final JSONMapper jsonMapper) { this.examSessionService = examSessionService; @@ -105,6 +115,7 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic this.isDistributedSetup = webserviceInfo.isDistributed(); this.sebClientEventBatchService = sebClientEventBatchService; this.sebClientInstructionService = sebClientInstructionService; + this.clientConfigService = clientConfigService; this.jsonMapper = jsonMapper; } @@ -623,6 +634,38 @@ 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()); + + outputStream.flush(); + + }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 { + outputStream.flush(); + outputStream.close(); + } + } + private void writeSEBClientErrors( final HttpServletResponse response, final Collection errorMessages) { diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAPIDiscoveryLightController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAPIDiscoveryLightController.java new file mode 100644 index 00000000..09aab832 --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAPIDiscoveryLightController.java @@ -0,0 +1,95 @@ +/* + * 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.api.API; +import ch.ethz.seb.sebserver.gbl.async.AsyncServiceSpringConfig; +import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; +import ch.ethz.seb.sebserver.gbl.util.Utils; +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 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; +import java.util.stream.Collectors; + +@WebServiceProfile +@RestController +@RequestMapping("${sebserver.webservice.api.exam.endpoint.discovery}") +@ConditionalOnExpression("'${sebserver.webservice.light.setup}'.equals('true')") +public class ExamAPIDiscoveryLightController { + + private final SEBClientConnectionService sebClientConnectionService; + private final SEBClientConfigDAO sebClientConfigDAO; + private final Executor executor; + + protected ExamAPIDiscoveryLightController( + final SEBClientConnectionService sebClientConnectionService, + final SEBClientConfigDAO sebClientConfigDAO, + @Qualifier(AsyncServiceSpringConfig.EXAM_API_EXECUTOR_BEAN_NAME) final Executor executor) { + + this.sebClientConnectionService = sebClientConnectionService; + this.sebClientConfigDAO = sebClientConfigDAO; + this.executor = executor; + } + + //this.examAPI_V1_Endpoint + API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT + //http://localhost:8080/exam-api/discovery/light-config + @RequestMapping( + path = API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT, + method = RequestMethod.GET, + produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + public CompletableFuture getLightConfig( + final HttpServletRequest request, + final HttpServletResponse response){ + + //temp solution: get first active seb client config we can get --> + //in a light setup there should be only one setup so this step is not necessary and we can just use the first and only item in the db + String modelId = getSebClientConfigId(); + + return CompletableFuture.runAsync( + () -> { + try { + this.sebClientConnectionService.streamLightExamConfig(modelId, response); + } catch (IOException e) { + throw new RuntimeException(e); + } + }, + this.executor + ); + + } + + private String getSebClientConfigId() { + return this.sebClientConfigDAO + .allMatching( + new FilterMap().putIfAbsent( + "active", + String.valueOf(true) + ), + Utils.truePredicate() + ) + .getOrThrow() + .stream() + .collect(Collectors.toList()) + .get(0) + .getModelId(); + } + +} From 8f8ede317ca3bdb7be8a32efbc3a590bef3f7f5e Mon Sep 17 00:00:00 2001 From: NadimETH <138491408+NadimETH@users.noreply.github.com> Date: Mon, 4 Mar 2024 17:34:53 +0100 Subject: [PATCH 02/10] upgrade to java 17 in build yaml --- .github/workflows/buildReporting.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/buildReporting.yml b/.github/workflows/buildReporting.yml index 52608a2d..51f2ae9e 100644 --- a/.github/workflows/buildReporting.yml +++ b/.github/workflows/buildReporting.yml @@ -20,11 +20,11 @@ jobs: name: Checkout repository uses: actions/checkout@v4 - - name: Set up JDK 8 - uses: actions/setup-java@v4 + name: Set up JDK 17 + uses: actions/setup-java@v4.1 with: - java-version: '8' - distribution: 'adopt' + java-version: '17' + distribution: 'temurin' - name: Cache Maven packages uses: actions/cache@v4 @@ -72,10 +72,10 @@ jobs: uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v4 + uses: actions/setup-java@v4.1 with: java-version: '17' - distribution: 'adopt' + distribution: 'temurin' - name: Cache Maven packages uses: actions/cache@v4 From cd7c759b58c1b8843f0d590453f79fdcb141a160 Mon Sep 17 00:00:00 2001 From: NadimETH <138491408+NadimETH@users.noreply.github.com> Date: Mon, 4 Mar 2024 17:37:35 +0100 Subject: [PATCH 03/10] use correct version tag in build yaml --- .github/workflows/buildReporting.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/buildReporting.yml b/.github/workflows/buildReporting.yml index 51f2ae9e..01e2bb7e 100644 --- a/.github/workflows/buildReporting.yml +++ b/.github/workflows/buildReporting.yml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v4.1 + uses: actions/setup-java@v4.1.0 with: java-version: '17' distribution: 'temurin' @@ -72,7 +72,7 @@ jobs: uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v4.1 + uses: actions/setup-java@v4.1.0 with: java-version: '17' distribution: 'temurin' From ed68a5c74f82e1e6331a4782a9be134a5fbef872 Mon Sep 17 00:00:00 2001 From: Nadim Ritter Date: Tue, 5 Mar 2024 09:33:28 +0100 Subject: [PATCH 04/10] SEBSLI-9 reset build yaml to development state --- .github/workflows/buildReporting.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/buildReporting.yml b/.github/workflows/buildReporting.yml index 01e2bb7e..52608a2d 100644 --- a/.github/workflows/buildReporting.yml +++ b/.github/workflows/buildReporting.yml @@ -20,11 +20,11 @@ jobs: name: Checkout repository uses: actions/checkout@v4 - - name: Set up JDK 17 - uses: actions/setup-java@v4.1.0 + name: Set up JDK 8 + uses: actions/setup-java@v4 with: - java-version: '17' - distribution: 'temurin' + java-version: '8' + distribution: 'adopt' - name: Cache Maven packages uses: actions/cache@v4 @@ -72,10 +72,10 @@ jobs: uses: actions/checkout@v4 - name: Set up JDK 17 - uses: actions/setup-java@v4.1.0 + uses: actions/setup-java@v4 with: java-version: '17' - distribution: 'temurin' + distribution: 'adopt' - name: Cache Maven packages uses: actions/cache@v4 From 7594a03de5c1e29f3fcec26ba144adc659a62268 Mon Sep 17 00:00:00 2001 From: Nadim Ritter Date: Fri, 15 Mar 2024 13:42:04 +0100 Subject: [PATCH 05/10] SEBSLI-9 new light init class --- .../servicelayer/light/impl/LightInit.java | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java new file mode 100644 index 00000000..bf06779f --- /dev/null +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java @@ -0,0 +1,85 @@ +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.gbl.util.Result; +import ch.ethz.seb.sebserver.gbl.util.Utils; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; +import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SEBClientConfigDAO; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +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; +import java.util.stream.Collectors; + +@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 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); + } + + + +} From 4a97e8d32c98d3f98729bf2f251396b6e4ab4f37 Mon Sep 17 00:00:00 2001 From: Nadim Ritter Date: Fri, 15 Mar 2024 15:49:57 +0100 Subject: [PATCH 06/10] SEBSLI-9 comment out creation of connection config --- .../webservice/servicelayer/light/impl/LightInit.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java index bf06779f..28ecf0c8 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java @@ -32,9 +32,9 @@ public class LightInit { @EventListener(SEBServerInitEvent.class) public void init() { - if(isConnectionConfigAbsent()){ - this.sebClientConfigDAO.createNew(createLightConnectionConfiguration()).getOrThrow(); - } +// if(isConnectionConfigAbsent()){ +// this.sebClientConfigDAO.createNew(createLightConnectionConfiguration()).getOrThrow(); +// } } private boolean isConnectionConfigAbsent() { From 32fc2817d45282040a9b41d2e57834766cf5b84d Mon Sep 17 00:00:00 2001 From: Nadim Ritter Date: Mon, 18 Mar 2024 13:57:42 +0100 Subject: [PATCH 07/10] SEBSLI-9 move init event below admin account create event --- .../seb/sebserver/webservice/WebserviceInit.java | 6 ++++-- .../servicelayer/light/impl/LightInit.java | 12 +++--------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceInit.java b/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceInit.java index 962947b7..e12b5bff 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceInit.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/WebserviceInit.java @@ -102,14 +102,16 @@ public class WebserviceInit implements ApplicationListener Initialize Services..."); SEBServerInit.INIT_LOGGER.info("----> "); - this.applicationEventPublisher.publishEvent(new SEBServerInitEvent(this)); - // Run the database integrity checks and fixes if configured this.dbIntegrityChecker.checkIntegrity(); // Create an initial admin account if requested and not already in the database this.adminUserInitializer.initAdminAccount(); + //emits SEBServerInitEvent + this.applicationEventPublisher.publishEvent(new SEBServerInitEvent(this)); + + SEBServerInit.INIT_LOGGER.info("----> *********************************************************"); SEBServerInit.INIT_LOGGER.info("----> *** Webservice Info: ***"); SEBServerInit.INIT_LOGGER.info("----> *********************************************************"); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java index 28ecf0c8..7f60c9fc 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java @@ -3,19 +3,13 @@ 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.gbl.util.Result; -import ch.ethz.seb.sebserver.gbl.util.Utils; -import ch.ethz.seb.sebserver.webservice.servicelayer.dao.FilterMap; import ch.ethz.seb.sebserver.webservice.servicelayer.dao.SEBClientConfigDAO; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; 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; -import java.util.stream.Collectors; @Lazy @Service @@ -32,9 +26,9 @@ public class LightInit { @EventListener(SEBServerInitEvent.class) public void init() { -// if(isConnectionConfigAbsent()){ -// this.sebClientConfigDAO.createNew(createLightConnectionConfiguration()).getOrThrow(); -// } + if(isConnectionConfigAbsent()){ + this.sebClientConfigDAO.createNew(createLightConnectionConfiguration()).getOrThrow(); + } } private boolean isConnectionConfigAbsent() { From ed9e86436bf9d36303e9c2c3ce8f81447dd05ac0 Mon Sep 17 00:00:00 2001 From: Nadim Ritter Date: Wed, 20 Mar 2024 16:04:00 +0100 Subject: [PATCH 08/10] SEBSLI-9 store admin pw in db + expose endpoint in ssl mode + remove admin pw after pw change --- .../ethz/seb/sebserver/WebSecurityConfig.java | 1 + .../sebserver/gbl/model/user/UserRole.java | 8 ++ .../webservice/AdminUserInitializer.java | 44 ++++++++-- .../servicelayer/light/impl/LightInit.java | 5 +- ...htController.java => LightController.java} | 52 ++++++++++-- .../weblayer/api/UserAccountController.java | 82 +++++++++++++------ 6 files changed, 151 insertions(+), 41 deletions(-) rename src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/{ExamAPIDiscoveryLightController.java => LightController.java} (66%) diff --git a/src/main/java/ch/ethz/seb/sebserver/WebSecurityConfig.java b/src/main/java/ch/ethz/seb/sebserver/WebSecurityConfig.java index f8587bbb..9dd9029f 100644 --- a/src/main/java/ch/ethz/seb/sebserver/WebSecurityConfig.java +++ b/src/main/java/ch/ethz/seb/sebserver/WebSecurityConfig.java @@ -85,6 +85,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E .antMatchers(CHECK_PATH) .antMatchers(this.examAPIDiscoveryEndpoint) .antMatchers(this.examAPIDiscoveryEndpoint + API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT) + .antMatchers(this.examAPIDiscoveryEndpoint + API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT + API.PASSWORD_PATH_SEGMENT) .antMatchers(this.adminAPIEndpoint + API.INFO_ENDPOINT + API.LOGO_PATH_SEGMENT + "/**") .antMatchers(this.adminAPIEndpoint + API.INFO_ENDPOINT + API.INFO_INST_PATH_SEGMENT + "/**") .antMatchers(this.adminAPIEndpoint + API.REGISTER_ENDPOINT); diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserRole.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserRole.java index 506d4306..03bc5cba 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserRole.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserRole.java @@ -60,4 +60,12 @@ public enum UserRole implements Entity, GrantedAuthority { } } + public static List getNamesForAllRoles(){ + return List.of( + SEB_SERVER_ADMIN.getName(), + INSTITUTIONAL_ADMIN.getName(), + EXAM_ADMIN.getName(), + EXAM_SUPPORTER.getName()); + } + } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/AdminUserInitializer.java b/src/main/java/ch/ethz/seb/sebserver/webservice/AdminUserInitializer.java index f5720243..6398f79e 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/AdminUserInitializer.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/AdminUserInitializer.java @@ -8,10 +8,15 @@ package ch.ethz.seb.sebserver.webservice; -import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; +import java.util.Map; +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.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,26 +45,32 @@ class AdminUserInitializer { private static final Logger log = LoggerFactory.getLogger(AdminUserInitializer.class); + private final WebserviceInfo webserviceInfo; private final UserDAO userDAO; private final InstitutionDAO institutionDAO; private final PasswordEncoder passwordEncoder; + private final AdditionalAttributesDAO additionalAttributesDAO; private final boolean initializeAdmin; private final String adminName; private final String orgName; private final Environment environment; public AdminUserInitializer( + final WebserviceInfo webserviceInfo, final UserDAO userDAO, final InstitutionDAO institutionDAO, + final AdditionalAttributesDAO additionalAttributesDAO, final Environment environment, @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.username:seb-server-admin}") final String adminName, @Value("${sebserver.init.organisation.name:[SET_ORGANIZATION_NAME]}") final String orgName) { + this.webserviceInfo = webserviceInfo; this.environment = environment; this.userDAO = userDAO; this.institutionDAO = institutionDAO; + this.additionalAttributesDAO = additionalAttributesDAO; this.passwordEncoder = passwordEncoder; this.initializeAdmin = initializeAdmin; this.adminName = adminName; @@ -68,7 +79,7 @@ class AdminUserInitializer { void initAdminAccount() { if (!this.initializeAdmin) { - log.debug("Create initial admin account is switched on off"); + log.debug("Create initial admin account is switched off"); return; } @@ -90,7 +101,7 @@ class AdminUserInitializer { this.userDAO.changePassword( sebServerUser.getUserInfo().getModelId(), generateAdminPassword); - this.writeAdminCredentials(this.adminName, generateAdminPassword); + this.printAdminCredentials(this.adminName, generateAdminPassword); } } } else { @@ -133,10 +144,14 @@ class AdminUserInitializer { 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)) .map(account -> { - writeAdminCredentials(this.adminName, generateAdminPassword); + printAdminCredentials(this.adminName, generateAdminPassword); + if(this.webserviceInfo.isLightSetup()) writeInitialAdminCredentialsIntoDB(this.adminName, generateAdminPassword); return account; }) .getOrThrow(); @@ -148,7 +163,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( "----> ******************************************************************************************" @@ -163,6 +178,23 @@ class AdminUserInitializer { SEBServerInit.INIT_LOGGER.info("---->"); } + private void writeInitialAdminCredentialsIntoDB(final String name, final CharSequence pwd){ + Result.tryCatch(() -> { + final Map attributes = new HashMap<>(); + attributes.put( + Domain.USER.ATTR_USERNAME, + name); + attributes.put( + Domain.USER.ATTR_PASSWORD, + String.valueOf(pwd)); + + this.additionalAttributesDAO.saveAdditionalAttributes( + EntityType.USER, + 2L, + attributes); + }); + } + private CharSequence generateAdminPassword() { try { return ClientCredentialServiceImpl.generateClientSecret(); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java index 7f60c9fc..7f66c462 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/servicelayer/light/impl/LightInit.java @@ -22,12 +22,11 @@ public class LightInit { this.sebClientConfigDAO = sebClientConfigDAO; } - - @EventListener(SEBServerInitEvent.class) public void init() { if(isConnectionConfigAbsent()){ - this.sebClientConfigDAO.createNew(createLightConnectionConfiguration()).getOrThrow(); + this.sebClientConfigDAO.createNew(createLightConnectionConfiguration()) + .getOrThrow(); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAPIDiscoveryLightController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LightController.java similarity index 66% rename from src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAPIDiscoveryLightController.java rename to src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LightController.java index 09aab832..a34b3047 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/ExamAPIDiscoveryLightController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LightController.java @@ -9,12 +9,16 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api; 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; @@ -27,32 +31,34 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; -import java.util.stream.Collectors; @WebServiceProfile @RestController @RequestMapping("${sebserver.webservice.api.exam.endpoint.discovery}") @ConditionalOnExpression("'${sebserver.webservice.light.setup}'.equals('true')") -public class ExamAPIDiscoveryLightController { +public class LightController { private final SEBClientConnectionService sebClientConnectionService; private final SEBClientConfigDAO sebClientConfigDAO; + private final AdditionalAttributesDAO additionalAttributesDAO; private final Executor executor; - protected ExamAPIDiscoveryLightController( + 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; } //this.examAPI_V1_Endpoint + API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT //http://localhost:8080/exam-api/discovery/light-config @RequestMapping( - path = API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT, + path = API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT, method = RequestMethod.GET, produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) public CompletableFuture getLightConfig( @@ -76,6 +82,36 @@ public class ExamAPIDiscoveryLightController { } + @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, 2L, Domain.USER.ATTR_USERNAME) + .getOrThrow() + .getValue(); + + final String password = this.additionalAttributesDAO.getAdditionalAttribute(EntityType.USER, 2L, 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( @@ -87,9 +123,15 @@ public class ExamAPIDiscoveryLightController { ) .getOrThrow() .stream() - .collect(Collectors.toList()) + .toList() .get(0) .getModelId(); } } + +record UsernamePasswordView(String username, String password) { + @JsonCreator + UsernamePasswordView { + } +} \ No newline at end of file diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java index 3db81134..346f12f0 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java @@ -8,18 +8,39 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api; -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumSet; -import java.util.List; - -import javax.validation.Valid; - +import ch.ethz.seb.sebserver.WebSecurityConfig; +import ch.ethz.seb.sebserver.gbl.api.API; +import ch.ethz.seb.sebserver.gbl.api.APIMessage; +import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException; +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.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.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.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.validation.BeanValidationService; +import ch.ethz.seb.sebserver.webservice.weblayer.oauth.RevokeTokenEndpoint; import org.mybatis.dynamic.sql.SqlTable; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationEventPublisher; @@ -32,25 +53,11 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; -import ch.ethz.seb.sebserver.WebSecurityConfig; -import ch.ethz.seb.sebserver.gbl.api.API; -import ch.ethz.seb.sebserver.gbl.api.APIMessage; -import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException; -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.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; +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import java.util.List; @WebServiceProfile @RestController @@ -61,6 +68,8 @@ public class UserAccountController extends ActivatableEntityController this.userActivityLogDAO.log(UserLogActivityType.PASSWORD_CHANGE, e)) .map(this::synchronizeUserWithSPS) + .map(userInfo -> { + if(this.webserviceInfo.isLightSetup()){ + return removeInitialAdminPasswordFromDB(userInfo); + } + return userInfo; + }) .getOrThrow(); } @@ -293,4 +312,13 @@ public class UserAccountController extends ActivatableEntityController { + this.additionalAttributesDAO.delete(EntityType.USER, 2L, Domain.USER.ATTR_USERNAME); + this.additionalAttributesDAO.delete(EntityType.USER, 2L, Domain.USER.ATTR_PASSWORD); + }); + + return userInfo; + } } From 0b00724b2653008e5df1a8943980971dc284dd59 Mon Sep 17 00:00:00 2001 From: Nadim Ritter Date: Tue, 26 Mar 2024 16:39:33 +0100 Subject: [PATCH 09/10] SEBSLI-9 code clean-up and improvements --- .../ch/ethz/seb/sebserver/gbl/Constants.java | 2 ++ .../sebserver/gbl/model/user/UserRole.java | 9 +++--- .../webservice/AdminUserInitializer.java | 17 ++++++----- .../impl/SEBClientConnectionServiceImpl.java | 14 ++++++---- .../weblayer/api/LightController.java | 13 +++------ .../weblayer/api/UserAccountController.java | 28 ++++++++++++------- .../config/application-dev-ws.properties | 2 +- 7 files changed, 48 insertions(+), 37 deletions(-) diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java b/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java index d5299935..de9dc9a8 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/Constants.java @@ -102,6 +102,8 @@ public final class Constants { public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd"; 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 .forPattern(DEFAULT_DATE_TIME_MILLIS_FORMAT) .withZoneUTC(); diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserRole.java b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserRole.java index 03bc5cba..d1168083 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserRole.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/model/user/UserRole.java @@ -12,6 +12,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.List; +import java.util.stream.Collectors; import org.springframework.security.core.GrantedAuthority; @@ -61,11 +62,9 @@ public enum UserRole implements Entity, GrantedAuthority { } public static List getNamesForAllRoles(){ - return List.of( - SEB_SERVER_ADMIN.getName(), - INSTITUTIONAL_ADMIN.getName(), - EXAM_ADMIN.getName(), - EXAM_SUPPORTER.getName()); + return Arrays.stream(UserRole.values()) + .map(UserRole::getName) + .toList(); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/AdminUserInitializer.java b/src/main/java/ch/ethz/seb/sebserver/webservice/AdminUserInitializer.java index 6398f79e..aa164f60 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/AdminUserInitializer.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/AdminUserInitializer.java @@ -14,6 +14,7 @@ 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; @@ -151,7 +152,9 @@ class AdminUserInitializer { .flatMap(account -> this.userDAO.setActive(account, true)) .map(account -> { printAdminCredentials(this.adminName, generateAdminPassword); - if(this.webserviceInfo.isLightSetup()) writeInitialAdminCredentialsIntoDB(this.adminName, generateAdminPassword); + if(this.webserviceInfo.isLightSetup()) { + writeInitialAdminCredentialsIntoDB(this.adminName, generateAdminPassword); + } return account; }) .getOrThrow(); @@ -179,7 +182,7 @@ class AdminUserInitializer { } private void writeInitialAdminCredentialsIntoDB(final String name, final CharSequence pwd){ - Result.tryCatch(() -> { + try { final Map attributes = new HashMap<>(); attributes.put( Domain.USER.ATTR_USERNAME, @@ -188,11 +191,11 @@ class AdminUserInitializer { Domain.USER.ATTR_PASSWORD, String.valueOf(pwd)); - this.additionalAttributesDAO.saveAdditionalAttributes( - EntityType.USER, - 2L, - attributes); - }); + 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() { 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 ef1bd463..83328640 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 @@ -653,16 +653,20 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic response.setStatus(HttpStatus.OK.value()); - outputStream.flush(); - }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 { - outputStream.flush(); - outputStream.close(); + + try { + outputStream.flush(); + outputStream.close(); + + } catch (IOException e) { + log.error("error while flushing / closing output stream", e); + } } } @@ -981,4 +985,4 @@ public class SEBClientConnectionServiceImpl implements SEBClientConnectionServic return (exam != null && exam.lmsSetupId == null && status == ConnectionStatus.READY) || status == ConnectionStatus.ACTIVE; } -} +} \ No newline at end of file diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LightController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LightController.java index a34b3047..96bf02e5 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LightController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/LightController.java @@ -8,6 +8,7 @@ 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; @@ -55,8 +56,6 @@ public class LightController { this.executor = executor; } - //this.examAPI_V1_Endpoint + API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT - //http://localhost:8080/exam-api/discovery/light-config @RequestMapping( path = API.EXAM_API_CONFIGURATION_LIGHT_ENDPOINT, method = RequestMethod.GET, @@ -65,14 +64,10 @@ public class LightController { final HttpServletRequest request, final HttpServletResponse response){ - //temp solution: get first active seb client config we can get --> - //in a light setup there should be only one setup so this step is not necessary and we can just use the first and only item in the db - String modelId = getSebClientConfigId(); - return CompletableFuture.runAsync( () -> { try { - this.sebClientConnectionService.streamLightExamConfig(modelId, response); + this.sebClientConnectionService.streamLightExamConfig("1", response); } catch (IOException e) { throw new RuntimeException(e); } @@ -91,11 +86,11 @@ public class LightController { final HttpServletResponse response){ try { - final String username = this.additionalAttributesDAO.getAdditionalAttribute(EntityType.USER, 2L, Domain.USER.ATTR_USERNAME) + 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, 2L, Domain.USER.ATTR_PASSWORD) + final String password = this.additionalAttributesDAO.getAdditionalAttribute(EntityType.USER, Constants.LIGHT_ADMIN_USER_ID, Domain.USER.ATTR_PASSWORD) .getOrThrow() .getValue(); diff --git a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java index 346f12f0..4b08afc7 100644 --- a/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java +++ b/src/main/java/ch/ethz/seb/sebserver/webservice/weblayer/api/UserAccountController.java @@ -9,6 +9,7 @@ package ch.ethz.seb.sebserver.webservice.weblayer.api; import ch.ethz.seb.sebserver.WebSecurityConfig; +import ch.ethz.seb.sebserver.gbl.Constants; import ch.ethz.seb.sebserver.gbl.api.API; import ch.ethz.seb.sebserver.gbl.api.APIMessage; import ch.ethz.seb.sebserver.gbl.api.APIMessage.APIMessageException; @@ -42,6 +43,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.session.ScreenProctoringSer 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.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.ApplicationEventPublisher; import org.springframework.http.MediaType; @@ -64,6 +67,8 @@ import java.util.List; @RequestMapping("${sebserver.webservice.api.admin.endpoint}" + API.USER_ACCOUNT_ENDPOINT) public class UserAccountController extends ActivatableEntityController { + private static final Logger log = LoggerFactory.getLogger(UserAccountController.class); + private final ApplicationEventPublisher applicationEventPublisher; private final UserDAO userDAO; private final PasswordEncoder userPasswordEncoder; @@ -201,12 +206,7 @@ public class UserAccountController extends ActivatableEntityController this.userActivityLogDAO.log(UserLogActivityType.PASSWORD_CHANGE, e)) .map(this::synchronizeUserWithSPS) - .map(userInfo -> { - if(this.webserviceInfo.isLightSetup()){ - return removeInitialAdminPasswordFromDB(userInfo); - } - return userInfo; - }) + .map(this::removeInitialAdminPasswordFromDB) .getOrThrow(); } @@ -314,10 +314,18 @@ public class UserAccountController extends ActivatableEntityController { - this.additionalAttributesDAO.delete(EntityType.USER, 2L, Domain.USER.ATTR_USERNAME); - this.additionalAttributesDAO.delete(EntityType.USER, 2L, Domain.USER.ATTR_PASSWORD); - }); + 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; } diff --git a/src/main/resources/config/application-dev-ws.properties b/src/main/resources/config/application-dev-ws.properties index 750f47a7..e4a9be9c 100644 --- a/src/main/resources/config/application-dev-ws.properties +++ b/src/main/resources/config/application-dev-ws.properties @@ -27,7 +27,7 @@ sebserver.init.database.integrity.try-fix=true # webservice setup configuration sebserver.init.adminaccount.gen-on-init=false -sebserver.webservice.light.setup=false +sebserver.webservice.light.setup=true sebserver.webservice.distributed=false #sebserver.webservice.master.delay.threshold=10000 sebserver.webservice.http.external.scheme=http From db2d19b6ec50a6c6f27dbb4bf34f619d21af3670 Mon Sep 17 00:00:00 2001 From: NadimETH <138491408+NadimETH@users.noreply.github.com> Date: Tue, 26 Mar 2024 16:59:54 +0100 Subject: [PATCH 10/10] SEBSLI-9 update version in build file --- .github/workflows/buildReporting.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/buildReporting.yml b/.github/workflows/buildReporting.yml index 73222563..28aa6e18 100644 --- a/.github/workflows/buildReporting.yml +++ b/.github/workflows/buildReporting.yml @@ -94,7 +94,7 @@ jobs: uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v4 + uses: docker/setup-buildx-action@v3.2.0 - name: Login to DockerHub uses: docker/login-action@v2