diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/api/APIMessage.java b/src/main/java/ch/ethz/seb/sebserver/gbl/api/APIMessage.java index e3866c14..e8393fa0 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/api/APIMessage.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/api/APIMessage.java @@ -291,6 +291,7 @@ public class APIMessage implements Serializable { public final APIMessage apiMessage; public FieldValidationException(final String fieldName, final String defaultMessage) { + super(defaultMessage); this.apiMessage = APIMessage.fieldValidationError(fieldName, defaultMessage); } } diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/client/ClientCredentialServiceImpl.java b/src/main/java/ch/ethz/seb/sebserver/gbl/client/ClientCredentialServiceImpl.java index 89913ab7..79f632a1 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/client/ClientCredentialServiceImpl.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/client/ClientCredentialServiceImpl.java @@ -109,6 +109,7 @@ public class ClientCredentialServiceImpl implements ClientCredentialService { if (sequence instanceof CharBuffer) { ((CharBuffer) sequence).clear(); + ((CharBuffer) sequence).put(new char[((CharBuffer) sequence).capacity()]); return; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gbl/client/ClientCredentials.java b/src/main/java/ch/ethz/seb/sebserver/gbl/client/ClientCredentials.java index 5aac3b34..52d5304d 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gbl/client/ClientCredentials.java +++ b/src/main/java/ch/ethz/seb/sebserver/gbl/client/ClientCredentials.java @@ -58,4 +58,14 @@ public final class ClientCredentials { public String accessTokenAsString() { return hasAccessToken() ? this.accessToken.toString() : null; } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("ClientCredentials [clientId="); + builder.append(this.clientId); + builder.append("]"); + return builder.toString(); + } + } \ No newline at end of file diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/form/SelectionFieldBuilder.java b/src/main/java/ch/ethz/seb/sebserver/gui/form/SelectionFieldBuilder.java index 53b43572..0fc30983 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/form/SelectionFieldBuilder.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/form/SelectionFieldBuilder.java @@ -30,6 +30,7 @@ import ch.ethz.seb.sebserver.gui.service.i18n.PolyglotPageService; import ch.ethz.seb.sebserver.gui.service.page.PageService; import ch.ethz.seb.sebserver.gui.widget.Selection; import ch.ethz.seb.sebserver.gui.widget.Selection.Type; +import ch.ethz.seb.sebserver.gui.widget.WidgetFactory; public final class SelectionFieldBuilder extends FieldBuilder { @@ -110,6 +111,9 @@ public final class SelectionFieldBuilder extends FieldBuilder { label.setLayoutData(gridData); label.setText((this.value != null) ? this.value : Constants.EMPTY_NOTE); + if (this.label != null) { + WidgetFactory.setTestId(label, this.label.name); + } } else { final Collection keys = Arrays.asList(StringUtils.split(this.value, Constants.LIST_SEPARATOR)); this.itemsSupplier.get() @@ -156,6 +160,10 @@ public final class SelectionFieldBuilder extends FieldBuilder { label, this.tooltip); } + if (this.label != null) { + WidgetFactory.setTestId(label, this.label.name + "_" + valueKey); + } + return label; } diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/widget/FileUploadSelection.java b/src/main/java/ch/ethz/seb/sebserver/gui/widget/FileUploadSelection.java index 2f4efae5..62db048b 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/widget/FileUploadSelection.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/widget/FileUploadSelection.java @@ -65,6 +65,7 @@ public class FileUploadSelection extends Composite { final I18nSupport i18nSupport, final Collection supportedFiles, final boolean readonly, + final String testKey, final LocTextKey ariaLabel) { super(parent, SWT.NONE); @@ -85,6 +86,9 @@ public class FileUploadSelection extends Composite { if (ariaLabel != null) { WidgetFactory.setARIALabel(this.fileName, i18nSupport.getText(ariaLabel)); } + if (testKey != null) { + WidgetFactory.setTestId(this.fileName, testKey); + } this.fileUpload = null; this.uploadHandler = null; this.inputReceiver = null; @@ -96,6 +100,9 @@ public class FileUploadSelection extends Composite { if (ariaLabel != null) { WidgetFactory.setARIALabel(this.fileUpload, i18nSupport.getText(ariaLabel)); } + if (testKey != null) { + WidgetFactory.setTestId(this.fileUpload, testKey); + } WidgetFactory.setARIARole(this.fileUpload, AriaRole.button); this.fileUpload.setToolTipText(Utils.formatLineBreaks(this.i18nSupport.getText(PLEASE_SELECT_TEXT))); diff --git a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java index 6dc21cc9..b6848887 100644 --- a/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java +++ b/src/main/java/ch/ethz/seb/sebserver/gui/widget/WidgetFactory.java @@ -17,6 +17,7 @@ import java.util.List; import java.util.function.Consumer; import java.util.function.Supplier; +import org.apache.commons.lang3.StringUtils; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.client.service.JavaScriptExecutor; import org.eclipse.rap.rwt.widgets.WidgetUtil; @@ -966,6 +967,7 @@ public class WidgetFactory { this.i18nSupport, supportedFiles, readonly, + (label != null) ? label.name : null, label); if (supportedFiles != null) { @@ -990,6 +992,10 @@ public class WidgetFactory { } public static void setAttribute(final Widget widget, final String name, final String value) { + if (StringUtils.isBlank(name) || StringUtils.isBlank(value)) { + log.warn("Missing name or value for HTML attribute: name {} value {}", name, value); + return; + } if (!widget.isDisposed()) { final String $el = widget instanceof Text ? "$input" : "$el"; final String id = WidgetUtil.getId(widget); diff --git a/src/test/java/ch/ethz/seb/sebserver/gbl/client/ClientCredentialServiceImplTest.java b/src/test/java/ch/ethz/seb/sebserver/gbl/client/ClientCredentialServiceImplTest.java index ac430d89..4290311d 100644 --- a/src/test/java/ch/ethz/seb/sebserver/gbl/client/ClientCredentialServiceImplTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/gbl/client/ClientCredentialServiceImplTest.java @@ -12,18 +12,21 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +import java.nio.CharBuffer; + import org.junit.Test; import org.springframework.core.env.Environment; import ch.ethz.seb.sebserver.gbl.util.Cryptor; import ch.ethz.seb.sebserver.gbl.util.Result; +import ch.ethz.seb.sebserver.gbl.util.Utils; public class ClientCredentialServiceImplTest { @Test public void testGeneratedClientCredentials() { final Environment envMock = mock(Environment.class); - when(envMock.getRequiredProperty("sebserver.webservice.internalSecret")) + when(envMock.getProperty("sebserver.webservice.internalSecret")) .thenReturn("secret1"); final Cryptor cryptor = new Cryptor(envMock); @@ -38,4 +41,41 @@ public class ClientCredentialServiceImplTest { assertNull(clientCredentials.accessToken); } + @Test + public void testAccessToken() { + final Environment envMock = mock(Environment.class); + when(envMock.getProperty("sebserver.webservice.internalSecret")) + .thenReturn("secret1"); + + final Cryptor cryptor = new Cryptor(envMock); + final ClientCredentialServiceImpl service = new ClientCredentialServiceImpl(cryptor); + + final ClientCredentials cc = service + .encryptClientCredentials("", "", "") + .getOrThrow(); + + assertNotNull(cc); + assertNull(cc.accessToken); + assertNull(cc.secret); + assertEquals("", cc.clientId); + + final ClientCredentials cc2 = service + .encryptClientCredentials("c1", "password", "token") + .getOrThrow(); + + assertNotNull(cc2); + assertNotNull(cc2.accessToken); + assertNotNull(cc2.secret); + assertTrue(cc2.accessToken.length() > "token".length()); + assertTrue(cc2.secret.length() > "password".length()); + assertEquals("c1", cc2.clientId); + } + + @Test + public void testClearChars() { + final CharBuffer charBuffer = Utils.toCharBuffer(Utils.toByteBuffer("password")); + ClientCredentialServiceImpl.clearChars(charBuffer); + assertEquals("", String.valueOf(charBuffer)); + } + } diff --git a/src/test/java/ch/ethz/seb/sebserver/gbl/client/ProxyDataTest.java b/src/test/java/ch/ethz/seb/sebserver/gbl/client/ProxyDataTest.java new file mode 100644 index 00000000..f164e228 --- /dev/null +++ b/src/test/java/ch/ethz/seb/sebserver/gbl/client/ProxyDataTest.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 ETH Zürich, Educational Development and Technology (LET) + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +package ch.ethz.seb.sebserver.gbl.client; + +import static org.junit.Assert.assertEquals; + +import org.junit.jupiter.api.Test; + +public class ProxyDataTest { + + @Test + public void testCreation() { + final ProxyData proxyData = new ProxyData("proxyName", 8080, new ClientCredentials("user1", "password")); + assertEquals( + "ProxyData [proxyName=proxyName, proxyPort=8080, clientCredentials=ClientCredentials [clientId=user1]]", + proxyData.toString()); + } + +} diff --git a/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ExamJITSIProctoringServiceTest.java b/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ExamJITSIProctoringServiceTest.java index 37798fef..d5741993 100644 --- a/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ExamJITSIProctoringServiceTest.java +++ b/src/test/java/ch/ethz/seb/sebserver/webservice/servicelayer/session/impl/proctoring/ExamJITSIProctoringServiceTest.java @@ -8,8 +8,7 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl.proctoring; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.*; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; @@ -17,13 +16,66 @@ import java.security.NoSuchAlgorithmException; import org.junit.Test; import org.mockito.Mockito; +import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService; import ch.ethz.seb.sebserver.gbl.api.JSONMapper; import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringRoomConnection; +import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings; +import ch.ethz.seb.sebserver.gbl.model.exam.ProctoringServiceSettings.ProctoringServerType; +import ch.ethz.seb.sebserver.gbl.model.user.UserInfo; import ch.ethz.seb.sebserver.gbl.util.Cryptor; import ch.ethz.seb.sebserver.gbl.util.Result; +import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.AuthorizationService; +import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.UserService; +import ch.ethz.seb.sebserver.webservice.servicelayer.authorization.impl.SEBServerUser; +import ch.ethz.seb.sebserver.webservice.servicelayer.session.ExamSessionService; public class ExamJITSIProctoringServiceTest { + @Test + public void testType() { + final JitsiProctoringService jitsiProctoringService = getMockup(); + assertEquals(ProctoringServerType.JITSI_MEET, jitsiProctoringService.getType()); + } + + @Test + public void testTestExamProctoring() { + final JitsiProctoringService jitsiProctoringService = getMockup(); + + final ProctoringServiceSettings proctoringServiceSettings = new ProctoringServiceSettings( + 1L, true, ProctoringServerType.JITSI_MEET, "URL?", + null, null, null, null, null, null, null, null); + + final Result testExamProctoring = jitsiProctoringService + .testExamProctoring(proctoringServiceSettings); + assertNotNull(testExamProctoring); + assertTrue(testExamProctoring.hasError()); + final Exception error = testExamProctoring.getError(); + assertEquals("proctoringSettings:serverURL:invalidURL", error.getMessage()); + } + + @Test + public void testGetProctorRoomConnection() { + final JitsiProctoringService jitsiProctoringService = getMockup(); + + final ProctoringServiceSettings proctoringServiceSettings = new ProctoringServiceSettings( + 1L, true, ProctoringServerType.JITSI_MEET, "http://jitsi.ch", + 2, null, true, "key", "secret", null, null, false); + + final Result proctorRoomConnection = jitsiProctoringService + .getProctorRoomConnection(proctoringServiceSettings, "TestRoom", "Test-User"); + assertNotNull(proctorRoomConnection); + if (proctorRoomConnection.hasError()) { + proctorRoomConnection.getError().printStackTrace(); + } + assertFalse(proctorRoomConnection.hasError()); + final ProctoringRoomConnection proctoringRoomConnection = proctorRoomConnection.get(); + assertNotNull(proctoringRoomConnection); + assertEquals( + "SEBProctoringConnectionData [proctoringServerType=JITSI_MEET, serverHost=jitsi.ch, serverURL=http://jitsi.ch, roomName=TestRoom, subject=Test-User]", + proctoringRoomConnection.toString()); + assertNotNull(proctoringRoomConnection.accessToken); + } + @Test public void testTokenPayload() throws InvalidKeyException, NoSuchAlgorithmException { final Cryptor cryptorMock = Mockito.mock(Cryptor.class); @@ -88,4 +140,27 @@ public class ExamJITSIProctoringServiceTest { } + private JitsiProctoringService getMockup() { + final UserService userService = Mockito.mock(UserService.class); + Mockito.when(userService.getCurrentUser()).thenReturn(new SEBServerUser(1L, + new UserInfo("1", 1L, null, "proctor-user", null, null, null, null, null, null, null), "")); + + final AuthorizationService authorizationService = Mockito.mock(AuthorizationService.class); + Mockito.when(authorizationService.getUserService()).thenReturn(userService); + final ExamSessionService examSessionService = Mockito.mock(ExamSessionService.class); + final Cryptor cryptor = Mockito.mock(Cryptor.class); + Mockito.when(cryptor.decrypt(Mockito.any())).thenReturn(Result.of("pwd")); + + final ClientHttpRequestFactoryService clientHttpRequestFactoryService = + Mockito.mock(ClientHttpRequestFactoryService.class); + final JSONMapper jsonMapper = new JSONMapper(); + + return new JitsiProctoringService( + authorizationService, + examSessionService, + cryptor, + clientHttpRequestFactoryService, + jsonMapper); + } + }