SEBSERV-139 added moderator flag to the jitsi meet room token

This commit is contained in:
anhefti 2021-02-15 16:29:22 +01:00
parent b6e9e55106
commit a6a9988cbe
3 changed files with 100 additions and 23 deletions

View file

@ -16,10 +16,23 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
public interface ExamProctoringService {
/** Get the proctoring server type of the specific implementation
*
* @return the proctoring service type of the specific implementation */
ProctoringServerType getType();
/** Use this to test the proctoring service settings against the remote proctoring server.
*
* @param examProctoring the settings to test
* @return Result refer to true if the settings are correct and the proctoring server can be accessed. */
Result<Boolean> testExamProctoring(final ProctoringSettings examProctoring);
/** Used to get the proctor's room connection data.
*
* @param proctoringSettings the proctoring settings
* @param roomName the name of the room
* @param subject name of the room
* @return SEBProctoringConnectionData that contains all connection data */
Result<SEBProctoringConnectionData> createProctorPublicRoomConnection(
final ProctoringSettings proctoringSettings,
final String roomName,
@ -59,7 +72,8 @@ public interface ExamProctoringService {
final String clientKey,
final String roomName,
final String subject,
final Long expTime);
final Long expTime,
final boolean moderator);
Result<String> createClientAccessToken(
final ProctoringSettings proctoringSettings,

View file

@ -46,7 +46,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
"{\"alg\":\"HS256\",\"typ\":\"JWT\"}";
private static final String JITSI_ACCESS_TOKEN_PAYLOAD =
"{\"context\":{\"user\":{\"name\":\"%s\"}},\"iss\":\"%s\",\"aud\":\"%s\",\"sub\":\"%s\",\"room\":\"%s\"%s}";
"{\"context\":{\"user\":{\"name\":\"%s\"}},\"iss\":\"%s\",\"aud\":\"%s\",\"sub\":\"%s\",\"room\":\"%s\"%s%s}";
private final RemoteProctoringRoomDAO remoteProctoringRoomDAO;
private final AuthorizationService authorizationService;
@ -93,7 +93,8 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
"seb-server",
roomName,
subject,
forExam(proctoringSettings))
forExam(proctoringSettings),
true)
.getOrThrow();
});
}
@ -131,7 +132,8 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
"seb-client",
roomName,
connection.userSessionId,
forExam(proctoringSettings))
forExam(proctoringSettings),
false)
.getOrThrow();
});
}
@ -158,7 +160,8 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
"seb-client",
roomName,
subject,
forExam(proctoringSettings))
forExam(proctoringSettings),
false)
.getOrThrow();
});
}
@ -209,7 +212,8 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
"seb-client",
roomName,
subject,
expTime)
expTime,
false)
.getOrThrow();
});
@ -226,7 +230,8 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
final String clientKey,
final String roomName,
final String subject,
final Long expTime) {
final Long expTime,
final boolean moderator) {
return Result.tryCatch(() -> {
@ -242,7 +247,8 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
clientKey,
roomName,
expTime,
host);
host,
moderator);
return new SEBProctoringConnectionData(
proctoringServerType,
@ -279,34 +285,27 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
"seb-client",
roomName,
forExam(proctoringSettings),
host);
host,
false);
});
}
private String internalCreateAccessToken(
protected String internalCreateAccessToken(
final String appKey,
final CharSequence appSecret,
final String clientName,
final String clientKey,
final String roomName,
final Long expTime,
final String host) throws NoSuchAlgorithmException, InvalidKeyException {
final String host,
final boolean moderator) throws NoSuchAlgorithmException, InvalidKeyException {
final StringBuilder builder = new StringBuilder();
final Encoder urlEncoder = Base64.getUrlEncoder().withoutPadding();
final String jwtHeaderPart = urlEncoder
.encodeToString(JITSI_ACCESS_TOKEN_HEADER.getBytes(StandardCharsets.UTF_8));
final String jwtPayload = String.format(
JITSI_ACCESS_TOKEN_PAYLOAD.replaceAll(" ", "").replaceAll("\n", ""),
clientName,
appKey,
clientKey,
host,
roomName,
(expTime != null)
? String.format(",\"exp\":%s", String.valueOf(expTime))
: "");
final String jwtPayload = createPayload(appKey, clientName, clientKey, roomName, expTime, host, moderator);
final String jwtPayloadPart = urlEncoder
.encodeToString(jwtPayload.getBytes(StandardCharsets.UTF_8));
final String message = jwtHeaderPart + "." + jwtPayloadPart;
@ -324,6 +323,31 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
return builder.toString();
}
protected String createPayload(
final String appKey,
final String clientName,
final String clientKey,
final String roomName,
final Long expTime,
final String host,
final boolean moderator) {
final String jwtPayload = String.format(
JITSI_ACCESS_TOKEN_PAYLOAD.replaceAll(" ", "").replaceAll("\n", ""),
clientName,
appKey,
clientKey,
host,
roomName,
(moderator)
? ",\"moderator\":true"
: ",\"moderator\":false",
(expTime != null)
? String.format(",\"exp\":%s", String.valueOf(expTime))
: "");
return jwtPayload;
}
private long forExam(final ProctoringSettings examProctoring) {
if (examProctoring.examId == null) {
throw new IllegalStateException("Missing exam identifier from ExamProctoring data");

View file

@ -11,6 +11,9 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import org.junit.Test;
import org.mockito.Mockito;
@ -20,6 +23,40 @@ import ch.ethz.seb.sebserver.gbl.util.Cryptor;
public class ExamJITSIProctoringServiceTest {
@Test
public void testTokenPayload() throws InvalidKeyException, NoSuchAlgorithmException {
final Cryptor cryptorMock = Mockito.mock(Cryptor.class);
Mockito.when(cryptorMock.decrypt(Mockito.any())).thenReturn("fbvgeghergrgrthrehreg123");
final ExamJITSIProctoringService examJITSIProctoringService =
new ExamJITSIProctoringService(null, null, null, cryptorMock);
String accessToken = examJITSIProctoringService.createPayload(
"test-app",
"Test Name",
"test-client",
"SomeRoom",
1609459200L,
"https://test.ch",
false);
assertEquals(
"{\"context\":{\"user\":{\"name\":\"Test Name\"}},\"iss\":\"test-app\",\"aud\":\"test-client\",\"sub\":\"https://test.ch\",\"room\":\"SomeRoom\",\"moderator\":false,\"exp\":1609459200}",
accessToken);
accessToken = examJITSIProctoringService.createPayload(
"test-app",
"Test Name",
"test-client",
"SomeRoom",
1609459200L,
"https://test.ch",
true);
assertEquals(
"{\"context\":{\"user\":{\"name\":\"Test Name\"}},\"iss\":\"test-app\",\"aud\":\"test-client\",\"sub\":\"https://test.ch\",\"room\":\"SomeRoom\",\"moderator\":true,\"exp\":1609459200}",
accessToken);
}
@Test
public void testCreateProctoringURL() {
final Cryptor cryptorMock = Mockito.mock(Cryptor.class);
@ -36,15 +73,17 @@ public class ExamJITSIProctoringServiceTest {
"test-client",
"SomeRoom",
"Subject",
1609459200L)
1609459200L,
true)
.getOrThrow();
assertNotNull(data);
assertEquals(
"https://seb-jitsi.example.ch",
data.serverURL);
assertEquals(
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb250ZXh0Ijp7InVzZXIiOnsibmFtZSI6IlRlc3QgTmFtZSJ9fSwiaXNzIjoidGVzdC1hcHAiLCJhdWQiOiJ0ZXN0LWNsaWVudCIsInN1YiI6InNlYi1qaXRzaS5leGFtcGxlLmNoIiwicm9vbSI6IlNvbWVSb29tIiwiZXhwIjoxNjA5NDU5MjAwfQ.4ovqUkG6jrLvkDEZNdhbtFI_DFLDFsM2eBJHhcYq7a4",
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb250ZXh0Ijp7InVzZXIiOnsibmFtZSI6IlRlc3QgTmFtZSJ9fSwiaXNzIjoidGVzdC1hcHAiLCJhdWQiOiJ0ZXN0LWNsaWVudCIsInN1YiI6InNlYi1qaXRzaS5leGFtcGxlLmNoIiwicm9vbSI6IlNvbWVSb29tIiwibW9kZXJhdG9yIjogdHJ1ZSwiZXhwIjoxNjA5NDU5MjAwfQ.RjqLawNlBQgECKGZFi6jfcVXEw2dbZ1p9C1xEz-0e9w",
data.accessToken);
}