SEBSERV-139 added moderator flag to the jitsi meet room token
This commit is contained in:
parent
b6e9e55106
commit
a6a9988cbe
3 changed files with 100 additions and 23 deletions
|
@ -16,10 +16,23 @@ import ch.ethz.seb.sebserver.gbl.util.Result;
|
||||||
|
|
||||||
public interface ExamProctoringService {
|
public interface ExamProctoringService {
|
||||||
|
|
||||||
|
/** Get the proctoring server type of the specific implementation
|
||||||
|
*
|
||||||
|
* @return the proctoring service type of the specific implementation */
|
||||||
ProctoringServerType getType();
|
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);
|
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(
|
Result<SEBProctoringConnectionData> createProctorPublicRoomConnection(
|
||||||
final ProctoringSettings proctoringSettings,
|
final ProctoringSettings proctoringSettings,
|
||||||
final String roomName,
|
final String roomName,
|
||||||
|
@ -59,7 +72,8 @@ public interface ExamProctoringService {
|
||||||
final String clientKey,
|
final String clientKey,
|
||||||
final String roomName,
|
final String roomName,
|
||||||
final String subject,
|
final String subject,
|
||||||
final Long expTime);
|
final Long expTime,
|
||||||
|
final boolean moderator);
|
||||||
|
|
||||||
Result<String> createClientAccessToken(
|
Result<String> createClientAccessToken(
|
||||||
final ProctoringSettings proctoringSettings,
|
final ProctoringSettings proctoringSettings,
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
|
||||||
"{\"alg\":\"HS256\",\"typ\":\"JWT\"}";
|
"{\"alg\":\"HS256\",\"typ\":\"JWT\"}";
|
||||||
|
|
||||||
private static final String JITSI_ACCESS_TOKEN_PAYLOAD =
|
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 RemoteProctoringRoomDAO remoteProctoringRoomDAO;
|
||||||
private final AuthorizationService authorizationService;
|
private final AuthorizationService authorizationService;
|
||||||
|
@ -93,7 +93,8 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
|
||||||
"seb-server",
|
"seb-server",
|
||||||
roomName,
|
roomName,
|
||||||
subject,
|
subject,
|
||||||
forExam(proctoringSettings))
|
forExam(proctoringSettings),
|
||||||
|
true)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -131,7 +132,8 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
|
||||||
"seb-client",
|
"seb-client",
|
||||||
roomName,
|
roomName,
|
||||||
connection.userSessionId,
|
connection.userSessionId,
|
||||||
forExam(proctoringSettings))
|
forExam(proctoringSettings),
|
||||||
|
false)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -158,7 +160,8 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
|
||||||
"seb-client",
|
"seb-client",
|
||||||
roomName,
|
roomName,
|
||||||
subject,
|
subject,
|
||||||
forExam(proctoringSettings))
|
forExam(proctoringSettings),
|
||||||
|
false)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -209,7 +212,8 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
|
||||||
"seb-client",
|
"seb-client",
|
||||||
roomName,
|
roomName,
|
||||||
subject,
|
subject,
|
||||||
expTime)
|
expTime,
|
||||||
|
false)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -226,7 +230,8 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
|
||||||
final String clientKey,
|
final String clientKey,
|
||||||
final String roomName,
|
final String roomName,
|
||||||
final String subject,
|
final String subject,
|
||||||
final Long expTime) {
|
final Long expTime,
|
||||||
|
final boolean moderator) {
|
||||||
|
|
||||||
return Result.tryCatch(() -> {
|
return Result.tryCatch(() -> {
|
||||||
|
|
||||||
|
@ -242,7 +247,8 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
|
||||||
clientKey,
|
clientKey,
|
||||||
roomName,
|
roomName,
|
||||||
expTime,
|
expTime,
|
||||||
host);
|
host,
|
||||||
|
moderator);
|
||||||
|
|
||||||
return new SEBProctoringConnectionData(
|
return new SEBProctoringConnectionData(
|
||||||
proctoringServerType,
|
proctoringServerType,
|
||||||
|
@ -279,34 +285,27 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
|
||||||
"seb-client",
|
"seb-client",
|
||||||
roomName,
|
roomName,
|
||||||
forExam(proctoringSettings),
|
forExam(proctoringSettings),
|
||||||
host);
|
host,
|
||||||
|
false);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private String internalCreateAccessToken(
|
protected String internalCreateAccessToken(
|
||||||
final String appKey,
|
final String appKey,
|
||||||
final CharSequence appSecret,
|
final CharSequence appSecret,
|
||||||
final String clientName,
|
final String clientName,
|
||||||
final String clientKey,
|
final String clientKey,
|
||||||
final String roomName,
|
final String roomName,
|
||||||
final Long expTime,
|
final Long expTime,
|
||||||
final String host) throws NoSuchAlgorithmException, InvalidKeyException {
|
final String host,
|
||||||
|
final boolean moderator) throws NoSuchAlgorithmException, InvalidKeyException {
|
||||||
|
|
||||||
final StringBuilder builder = new StringBuilder();
|
final StringBuilder builder = new StringBuilder();
|
||||||
final Encoder urlEncoder = Base64.getUrlEncoder().withoutPadding();
|
final Encoder urlEncoder = Base64.getUrlEncoder().withoutPadding();
|
||||||
|
|
||||||
final String jwtHeaderPart = urlEncoder
|
final String jwtHeaderPart = urlEncoder
|
||||||
.encodeToString(JITSI_ACCESS_TOKEN_HEADER.getBytes(StandardCharsets.UTF_8));
|
.encodeToString(JITSI_ACCESS_TOKEN_HEADER.getBytes(StandardCharsets.UTF_8));
|
||||||
final String jwtPayload = String.format(
|
final String jwtPayload = createPayload(appKey, clientName, clientKey, roomName, expTime, host, moderator);
|
||||||
JITSI_ACCESS_TOKEN_PAYLOAD.replaceAll(" ", "").replaceAll("\n", ""),
|
|
||||||
clientName,
|
|
||||||
appKey,
|
|
||||||
clientKey,
|
|
||||||
host,
|
|
||||||
roomName,
|
|
||||||
(expTime != null)
|
|
||||||
? String.format(",\"exp\":%s", String.valueOf(expTime))
|
|
||||||
: "");
|
|
||||||
final String jwtPayloadPart = urlEncoder
|
final String jwtPayloadPart = urlEncoder
|
||||||
.encodeToString(jwtPayload.getBytes(StandardCharsets.UTF_8));
|
.encodeToString(jwtPayload.getBytes(StandardCharsets.UTF_8));
|
||||||
final String message = jwtHeaderPart + "." + jwtPayloadPart;
|
final String message = jwtHeaderPart + "." + jwtPayloadPart;
|
||||||
|
@ -324,6 +323,31 @@ public class ExamJITSIProctoringService implements ExamProctoringService {
|
||||||
return builder.toString();
|
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) {
|
private long forExam(final ProctoringSettings examProctoring) {
|
||||||
if (examProctoring.examId == null) {
|
if (examProctoring.examId == null) {
|
||||||
throw new IllegalStateException("Missing exam identifier from ExamProctoring data");
|
throw new IllegalStateException("Missing exam identifier from ExamProctoring data");
|
||||||
|
|
|
@ -11,6 +11,9 @@ package ch.ethz.seb.sebserver.webservice.servicelayer.session.impl;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.Mockito;
|
import org.mockito.Mockito;
|
||||||
|
|
||||||
|
@ -20,6 +23,40 @@ import ch.ethz.seb.sebserver.gbl.util.Cryptor;
|
||||||
|
|
||||||
public class ExamJITSIProctoringServiceTest {
|
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
|
@Test
|
||||||
public void testCreateProctoringURL() {
|
public void testCreateProctoringURL() {
|
||||||
final Cryptor cryptorMock = Mockito.mock(Cryptor.class);
|
final Cryptor cryptorMock = Mockito.mock(Cryptor.class);
|
||||||
|
@ -36,15 +73,17 @@ public class ExamJITSIProctoringServiceTest {
|
||||||
"test-client",
|
"test-client",
|
||||||
"SomeRoom",
|
"SomeRoom",
|
||||||
"Subject",
|
"Subject",
|
||||||
1609459200L)
|
1609459200L,
|
||||||
|
true)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
|
|
||||||
assertNotNull(data);
|
assertNotNull(data);
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"https://seb-jitsi.example.ch",
|
"https://seb-jitsi.example.ch",
|
||||||
data.serverURL);
|
data.serverURL);
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb250ZXh0Ijp7InVzZXIiOnsibmFtZSI6IlRlc3QgTmFtZSJ9fSwiaXNzIjoidGVzdC1hcHAiLCJhdWQiOiJ0ZXN0LWNsaWVudCIsInN1YiI6InNlYi1qaXRzaS5leGFtcGxlLmNoIiwicm9vbSI6IlNvbWVSb29tIiwiZXhwIjoxNjA5NDU5MjAwfQ.4ovqUkG6jrLvkDEZNdhbtFI_DFLDFsM2eBJHhcYq7a4",
|
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb250ZXh0Ijp7InVzZXIiOnsibmFtZSI6IlRlc3QgTmFtZSJ9fSwiaXNzIjoidGVzdC1hcHAiLCJhdWQiOiJ0ZXN0LWNsaWVudCIsInN1YiI6InNlYi1qaXRzaS5leGFtcGxlLmNoIiwicm9vbSI6IlNvbWVSb29tIiwibW9kZXJhdG9yIjogdHJ1ZSwiZXhwIjoxNjA5NDU5MjAwfQ.RjqLawNlBQgECKGZFi6jfcVXEw2dbZ1p9C1xEz-0e9w",
|
||||||
data.accessToken);
|
data.accessToken);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue