SEBSERV-372 finished testing with user account

This commit is contained in:
anhefti 2023-01-26 09:46:35 +01:00
parent a5bab8fc9f
commit b9553c93ba
15 changed files with 66 additions and 45 deletions

View file

@ -170,7 +170,12 @@ public interface ClientConnectionDAO extends
* @return Result refer to a collection of client connection records or to an error when happened */ * @return Result refer to a collection of client connection records or to an error when happened */
Result<Collection<ClientConnectionRecord>> getsecurityKeyConnectionRecords(Long examId); Result<Collection<ClientConnectionRecord>> getsecurityKeyConnectionRecords(Long examId);
Result<Collection<ClientConnectionRecord>> getAllActiveNotGranted(); /** Get all client connection records that don't have an security access grant yet
* and for specific exam.
*
* @param examId The exam identifier
* @return Result refer to client connection records to the an error when happened */
Result<Collection<ClientConnectionRecord>> getAllActiveNotGranted(Long examId);
Result<Long> countSignatureHashes(Long examId, String signatureHash); Result<Long> countSignatureHashes(Long examId, String signatureHash);

View file

@ -783,12 +783,15 @@ public class ClientConnectionDAOImpl implements ClientConnectionDAO {
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public Result<Collection<ClientConnectionRecord>> getAllActiveNotGranted() { public Result<Collection<ClientConnectionRecord>> getAllActiveNotGranted(final Long examId) {
return Result.tryCatch(() -> this.clientConnectionRecordMapper return Result.tryCatch(() -> this.clientConnectionRecordMapper
.selectByExample() .selectByExample()
.where( .where(
ClientConnectionRecordDynamicSqlSupport.status, ClientConnectionRecordDynamicSqlSupport.status,
SqlBuilder.isIn(ClientConnection.SECURE_CHECK_STATES)) SqlBuilder.isIn(ClientConnection.SECURE_CHECK_STATES))
.and(
ClientConnectionRecordDynamicSqlSupport.examId,
SqlBuilder.isEqualTo(examId))
.and( .and(
ClientConnectionRecordDynamicSqlSupport.securityCheckGranted, ClientConnectionRecordDynamicSqlSupport.securityCheckGranted,
SqlBuilder.isEqualTo(Constants.BYTE_FALSE), SqlBuilder.isEqualTo(Constants.BYTE_FALSE),

View file

@ -31,8 +31,6 @@ public interface MoodleAPIRestTemplate {
String getService(); String getService();
void setService(String service);
CharSequence getAccessToken(); CharSequence getAccessToken();
void testAPIConnection(String... functions); void testAPIConnection(String... functions);

View file

@ -34,14 +34,16 @@ public interface MoodleRestTemplateFactory {
/** Creates a MoodleAPIRestTemplate for the bundled LMSSetup of this factory. /** Creates a MoodleAPIRestTemplate for the bundled LMSSetup of this factory.
* *
* @param service The moodle web service name to within requesting an access token for
* @return Result refer to the MoodleAPIRestTemplate or to an error when happened */ * @return Result refer to the MoodleAPIRestTemplate or to an error when happened */
Result<MoodleAPIRestTemplate> createRestTemplate(); Result<MoodleAPIRestTemplate> createRestTemplate(String service);
/** Creates a MoodleAPIRestTemplate for the bundled LMSSetup of this factory. /** Creates a MoodleAPIRestTemplate for the bundled LMSSetup of this factory.
* Uses specified access token request path to request an access token. * Uses specified access token request path to request an access token.
* *
* @param service The moodle web service name to within requesting an access token for
* @param accessTokenPath access token request path to request an access token * @param accessTokenPath access token request path to request an access token
* @return Result refer to the MoodleAPIRestTemplate or to an error when happened */ * @return Result refer to the MoodleAPIRestTemplate or to an error when happened */
Result<MoodleAPIRestTemplate> createRestTemplate(final String accessTokenPath); Result<MoodleAPIRestTemplate> createRestTemplate(String service, String accessTokenPath);
} }

View file

@ -136,13 +136,13 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory
} }
@Override @Override
public Result<MoodleAPIRestTemplate> createRestTemplate() { public Result<MoodleAPIRestTemplate> createRestTemplate(final String service) {
final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup(); final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup();
return this.knownTokenAccessPaths return this.knownTokenAccessPaths
.stream() .stream()
.map(this::createRestTemplate) .map(path -> this.createRestTemplate(service, path))
.map(result -> { .map(result -> {
if (result.hasError()) { if (result.hasError()) {
log.warn("Failed to get access token for LMS: {}({})", log.warn("Failed to get access token for LMS: {}({})",
@ -161,7 +161,7 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory
} }
@Override @Override
public Result<MoodleAPIRestTemplate> createRestTemplate(final String accessTokenPath) { public Result<MoodleAPIRestTemplate> createRestTemplate(final String service, final String accessTokenPath) {
final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup(); final LmsSetup lmsSetup = this.apiTemplateDataSupplier.getLmsSetup();
@ -182,6 +182,7 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory
this.apiTemplateDataSupplier, this.apiTemplateDataSupplier,
lmsSetup.lmsApiUrl, lmsSetup.lmsApiUrl,
accessTokenPath, accessTokenPath,
service,
plainAPIToken, plainAPIToken,
plainClientId, plainClientId,
plainClientSecret); plainClientSecret);
@ -205,7 +206,6 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory
public static class MoodleAPIRestTemplateImpl extends RestTemplate implements MoodleAPIRestTemplate { public static class MoodleAPIRestTemplateImpl extends RestTemplate implements MoodleAPIRestTemplate {
private static final String MOODLE_MOBILE_APP_SERVICE = "moodle_mobile_app";
private static final String REST_API_TEST_FUNCTION = "core_webservice_get_site_info"; private static final String REST_API_TEST_FUNCTION = "core_webservice_get_site_info";
final JSONMapper jsonMapper; final JSONMapper jsonMapper;
@ -225,6 +225,7 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory
final APITemplateDataSupplier apiTemplateDataSupplier, final APITemplateDataSupplier apiTemplateDataSupplier,
final String serverURL, final String serverURL,
final String tokenPath, final String tokenPath,
final String service,
final CharSequence apiToken, final CharSequence apiToken,
final CharSequence username, final CharSequence username,
final CharSequence password) { final CharSequence password) {
@ -240,8 +241,7 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory
this.tokenReqURIVars = new HashMap<>(); this.tokenReqURIVars = new HashMap<>();
this.tokenReqURIVars.put(URI_VAR_USER_NAME, String.valueOf(username)); this.tokenReqURIVars.put(URI_VAR_USER_NAME, String.valueOf(username));
this.tokenReqURIVars.put(URI_VAR_PASSWORD, String.valueOf(password)); this.tokenReqURIVars.put(URI_VAR_PASSWORD, String.valueOf(password));
this.tokenReqURIVars.put(URI_VAR_SERVICE, MOODLE_MOBILE_APP_SERVICE); this.tokenReqURIVars.put(URI_VAR_SERVICE, service);
} }
@Override @Override
@ -249,11 +249,6 @@ public class MoodleRestTemplateFactoryImpl implements MoodleRestTemplateFactory
return this.tokenReqURIVars.get(URI_VAR_SERVICE); return this.tokenReqURIVars.get(URI_VAR_SERVICE);
} }
@Override
public void setService(final String service) {
this.tokenReqURIVars.put(URI_VAR_SERVICE, service);
}
@Override @Override
public CharSequence getAccessToken() { public CharSequence getAccessToken() {
if (this.accessToken == null) { if (this.accessToken == null) {

View file

@ -722,7 +722,7 @@ public class MoodleCourseAccess implements CourseAccessAPI {
private Result<MoodleAPIRestTemplate> getRestTemplate() { private Result<MoodleAPIRestTemplate> getRestTemplate() {
if (this.restTemplate == null) { if (this.restTemplate == null) {
final Result<MoodleAPIRestTemplate> templateRequest = this.restTemplateFactory final Result<MoodleAPIRestTemplate> templateRequest = this.restTemplateFactory
.createRestTemplate(); .createRestTemplate(MoodleLmsAPITemplateFactory.MOODLE_MOBILE_APP_SERVICE);
if (templateRequest.hasError()) { if (templateRequest.hasError()) {
return templateRequest; return templateRequest;
} else { } else {

View file

@ -36,6 +36,8 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestT
@WebServiceProfile @WebServiceProfile
public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory { public class MoodleLmsAPITemplateFactory implements LmsAPITemplateFactory {
static final String MOODLE_MOBILE_APP_SERVICE = "moodle_mobile_app";
private final JSONMapper jsonMapper; private final JSONMapper jsonMapper;
private final AsyncService asyncService; private final AsyncService asyncService;
private final Environment environment; private final Environment environment;

View file

@ -6,7 +6,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle; package ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -15,7 +15,8 @@ import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult; import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetupTestResult;
import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile; import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.plugin.MoodlePluginCourseAccess; import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleAPIRestTemplate;
import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestTemplateFactory;
@Lazy @Lazy
@Service @Service
@ -41,7 +42,7 @@ public class MoodlePluginCheck {
} }
final MoodleAPIRestTemplate restTemplate = restTemplateFactory final MoodleAPIRestTemplate restTemplate = restTemplateFactory
.createRestTemplate() .createRestTemplate(MooldePluginLmsAPITemplateFactory.SEB_SERVER_SERVICE_NAME)
.getOrThrow(); .getOrThrow();
try { try {

View file

@ -575,12 +575,11 @@ public class MoodlePluginCourseAccess extends AbstractCachedCourseAccess impleme
private Result<MoodleAPIRestTemplate> getRestTemplate() { private Result<MoodleAPIRestTemplate> getRestTemplate() {
if (this.restTemplate == null) { if (this.restTemplate == null) {
final Result<MoodleAPIRestTemplate> templateRequest = this.restTemplateFactory final Result<MoodleAPIRestTemplate> templateRequest = this.restTemplateFactory
.createRestTemplate(); .createRestTemplate(MooldePluginLmsAPITemplateFactory.SEB_SERVER_SERVICE_NAME);
if (templateRequest.hasError()) { if (templateRequest.hasError()) {
return templateRequest; return templateRequest;
} else { } else {
final MoodleAPIRestTemplate moodleAPIRestTemplate = templateRequest.get(); final MoodleAPIRestTemplate moodleAPIRestTemplate = templateRequest.get();
moodleAPIRestTemplate.setService(MooldePluginLmsAPITemplateFactory.SEB_SERVER_SERVICE_NAME);
this.restTemplate = moodleAPIRestTemplate; this.restTemplate = moodleAPIRestTemplate;
} }
} }

View file

@ -265,12 +265,11 @@ public class MoodlePluginCourseRestriction implements SEBRestrictionAPI {
private Result<MoodleAPIRestTemplate> getRestTemplate() { private Result<MoodleAPIRestTemplate> getRestTemplate() {
if (this.restTemplate == null) { if (this.restTemplate == null) {
final Result<MoodleAPIRestTemplate> templateRequest = this.restTemplateFactory final Result<MoodleAPIRestTemplate> templateRequest = this.restTemplateFactory
.createRestTemplate(); .createRestTemplate(MooldePluginLmsAPITemplateFactory.SEB_SERVER_SERVICE_NAME);
if (templateRequest.hasError()) { if (templateRequest.hasError()) {
return templateRequest; return templateRequest;
} else { } else {
final MoodleAPIRestTemplate moodleAPIRestTemplate = templateRequest.get(); final MoodleAPIRestTemplate moodleAPIRestTemplate = templateRequest.get();
moodleAPIRestTemplate.setService(MooldePluginLmsAPITemplateFactory.SEB_SERVER_SERVICE_NAME);
this.restTemplate = moodleAPIRestTemplate; this.restTemplate = moodleAPIRestTemplate;
} }
} }

View file

@ -36,7 +36,7 @@ import ch.ethz.seb.sebserver.webservice.servicelayer.lms.impl.moodle.MoodleRestT
@WebServiceProfile @WebServiceProfile
public class MooldePluginLmsAPITemplateFactory implements LmsAPITemplateFactory { public class MooldePluginLmsAPITemplateFactory implements LmsAPITemplateFactory {
public static final String SEB_SERVER_SERVICE_NAME = "seb-server-service"; public static final String SEB_SERVER_SERVICE_NAME = "SEB-Server-Webservice";
private final JSONMapper jsonMapper; private final JSONMapper jsonMapper;
private final CacheManager cacheManager; private final CacheManager cacheManager;

View file

@ -12,11 +12,13 @@ import java.math.BigDecimal;
import java.util.Collections; import java.util.Collections;
import java.util.Objects; import java.util.Objects;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection; import ch.ethz.seb.sebserver.gbl.model.session.ClientConnection;
import ch.ethz.seb.sebserver.gbl.model.session.ClientConnectionData; 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;
@ -92,14 +94,11 @@ public class SEBClientSessionServiceImpl implements SEBClientSessionService {
@Override @Override
public void updateASKGrants() { public void updateASKGrants() {
this.examSessionService
// TODO check only for exams with enabled ASK check!!! .getExamDAO()
.allRunningExamIds()
this.clientConnectionDAO .onSuccess(ids -> ids.stream().forEach(examId -> updateASKGrant(examId)))
.getAllActiveNotGranted() .onError(error -> log.error("Unexpected error while trying to updateASKGrants: ", error));
.onError(error -> log.error("Failed to get none granted active client connections: ", error))
.getOr(Collections.emptyList())
.forEach(this.securityKeyService::updateAppSignatureKeyGrant);
} }
@Override @Override
@ -202,4 +201,21 @@ public class SEBClientSessionServiceImpl implements SEBClientSessionService {
} }
} }
private void updateASKGrant(final Long examId) {
if (this.examSessionService
.getRunningExam(examId)
.map(exam -> exam.getAdditionalAttribute(Exam.ADDITIONAL_ATTR_SIGNATURE_KEY_CHECK_ENABLED))
.map(BooleanUtils::toBoolean)
.getOr(true)) {
this.clientConnectionDAO
.getAllActiveNotGranted(examId)
.onError(error -> log.error(
"Failed to get none granted active client connections: ",
error))
.getOr(Collections.emptyList())
.forEach(this.securityKeyService::updateAppSignatureKeyGrant);
}
}
} }

View file

@ -328,7 +328,7 @@ sebserver.useraccount.delete.confirm.message.noDeps=The User Account ({0}) was s
sebserver.lmssetup.type.MOCKUP=Testing sebserver.lmssetup.type.MOCKUP=Testing
sebserver.lmssetup.type.MOODLE=Moodle sebserver.lmssetup.type.MOODLE=Moodle
sebserver.lmssetup.type.MOODLE_PLUGIN=Moodle Plugin sebserver.lmssetup.type.MOODLE_PLUGIN=Moodle with SEB Server Plugin
sebserver.lmssetup.type.MOODLE_PLUGIN.tooltip=Moodle with SEB Server integration plugin installed sebserver.lmssetup.type.MOODLE_PLUGIN.tooltip=Moodle with SEB Server integration plugin installed
sebserver.lmssetup.type.OPEN_EDX=Open edX sebserver.lmssetup.type.OPEN_EDX=Open edX
sebserver.lmssetup.type.ANS_DELFT=Ans Delft sebserver.lmssetup.type.ANS_DELFT=Ans Delft

View file

@ -68,12 +68,12 @@ public class MoodleMockupRestTemplateFactory implements MoodleRestTemplateFactor
} }
@Override @Override
public Result<MoodleAPIRestTemplate> createRestTemplate() { public Result<MoodleAPIRestTemplate> createRestTemplate(final String service) {
return Result.of(new MockupMoodleRestTemplate(this.apiTemplateDataSupplier.getLmsSetup().lmsApiUrl)); return Result.of(new MockupMoodleRestTemplate(this.apiTemplateDataSupplier.getLmsSetup().lmsApiUrl));
} }
@Override @Override
public Result<MoodleAPIRestTemplate> createRestTemplate(final String accessTokenPath) { public Result<MoodleAPIRestTemplate> createRestTemplate(final String service, final String accessTokenPath) {
return Result.of(new MockupMoodleRestTemplate(this.apiTemplateDataSupplier.getLmsSetup().lmsApiUrl)); return Result.of(new MockupMoodleRestTemplate(this.apiTemplateDataSupplier.getLmsSetup().lmsApiUrl));
} }
@ -101,10 +101,6 @@ public class MoodleMockupRestTemplateFactory implements MoodleRestTemplateFactor
return "mockup-service"; return "mockup-service";
} }
@Override
public void setService(final String service) {
}
@Override @Override
public CharSequence getAccessToken() { public CharSequence getAccessToken() {
return this.accessToken; return this.accessToken;

View file

@ -16,6 +16,7 @@ import java.util.TreeMap;
import org.junit.Test; import org.junit.Test;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.mock.env.MockEnvironment; import org.springframework.mock.env.MockEnvironment;
import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.LinkedMultiValueMap;
@ -44,7 +45,8 @@ public class MoodleCourseAccessTest {
final MoodleRestTemplateFactoryImpl moodleRestTemplateFactory = mock(MoodleRestTemplateFactoryImpl.class); final MoodleRestTemplateFactoryImpl moodleRestTemplateFactory = mock(MoodleRestTemplateFactoryImpl.class);
final MoodleAPIRestTemplateImpl moodleAPIRestTemplate = mock(MoodleAPIRestTemplateImpl.class); final MoodleAPIRestTemplateImpl moodleAPIRestTemplate = mock(MoodleAPIRestTemplateImpl.class);
when(moodleRestTemplateFactory.createRestTemplate()).thenReturn(Result.of(moodleAPIRestTemplate)); when(moodleRestTemplateFactory.createRestTemplate(Mockito.anyString()))
.thenReturn(Result.of(moodleAPIRestTemplate));
when(moodleAPIRestTemplate.callMoodleAPIFunction( when(moodleAPIRestTemplate.callMoodleAPIFunction(
anyString(), anyString(),
any())).thenReturn("[\r\n" + any())).thenReturn("[\r\n" +
@ -119,7 +121,8 @@ public class MoodleCourseAccessTest {
@Test @Test
public void testInitAPIAccessError1() { public void testInitAPIAccessError1() {
final MoodleRestTemplateFactoryImpl moodleRestTemplateFactory = mock(MoodleRestTemplateFactoryImpl.class); final MoodleRestTemplateFactoryImpl moodleRestTemplateFactory = mock(MoodleRestTemplateFactoryImpl.class);
when(moodleRestTemplateFactory.createRestTemplate()).thenReturn(Result.ofRuntimeError("Error1")); when(moodleRestTemplateFactory.createRestTemplate(Mockito.anyString()))
.thenReturn(Result.ofRuntimeError("Error1"));
when(moodleRestTemplateFactory.test()).thenReturn(LmsSetupTestResult.ofOkay(LmsType.MOODLE)); when(moodleRestTemplateFactory.test()).thenReturn(LmsSetupTestResult.ofOkay(LmsType.MOODLE));
final MoodleCourseAccess moodleCourseAccess = new MoodleCourseAccess( final MoodleCourseAccess moodleCourseAccess = new MoodleCourseAccess(
@ -140,7 +143,8 @@ public class MoodleCourseAccessTest {
public void testInitAPIAccessError2() { public void testInitAPIAccessError2() {
final MoodleRestTemplateFactoryImpl moodleRestTemplateFactory = mock(MoodleRestTemplateFactoryImpl.class); final MoodleRestTemplateFactoryImpl moodleRestTemplateFactory = mock(MoodleRestTemplateFactoryImpl.class);
final MoodleAPIRestTemplateImpl moodleAPIRestTemplate = mock(MoodleAPIRestTemplateImpl.class); final MoodleAPIRestTemplateImpl moodleAPIRestTemplate = mock(MoodleAPIRestTemplateImpl.class);
when(moodleRestTemplateFactory.createRestTemplate()).thenReturn(Result.of(moodleAPIRestTemplate)); when(moodleRestTemplateFactory.createRestTemplate(Mockito.anyString()))
.thenReturn(Result.of(moodleAPIRestTemplate));
doThrow(RuntimeException.class).when(moodleAPIRestTemplate).testAPIConnection(any()); doThrow(RuntimeException.class).when(moodleAPIRestTemplate).testAPIConnection(any());
when(moodleRestTemplateFactory.test()).thenReturn(LmsSetupTestResult.ofOkay(LmsType.MOODLE)); when(moodleRestTemplateFactory.test()).thenReturn(LmsSetupTestResult.ofOkay(LmsType.MOODLE));
@ -162,7 +166,8 @@ public class MoodleCourseAccessTest {
public void testInitAPIAccessOK() { public void testInitAPIAccessOK() {
final MoodleRestTemplateFactoryImpl moodleRestTemplateFactory = mock(MoodleRestTemplateFactoryImpl.class); final MoodleRestTemplateFactoryImpl moodleRestTemplateFactory = mock(MoodleRestTemplateFactoryImpl.class);
final MoodleAPIRestTemplateImpl moodleAPIRestTemplate = mock(MoodleAPIRestTemplateImpl.class); final MoodleAPIRestTemplateImpl moodleAPIRestTemplate = mock(MoodleAPIRestTemplateImpl.class);
when(moodleRestTemplateFactory.createRestTemplate()).thenReturn(Result.of(moodleAPIRestTemplate)); when(moodleRestTemplateFactory.createRestTemplate(Mockito.anyString()))
.thenReturn(Result.of(moodleAPIRestTemplate));
when(moodleRestTemplateFactory.test()).thenReturn(LmsSetupTestResult.ofOkay(LmsType.MOODLE)); when(moodleRestTemplateFactory.test()).thenReturn(LmsSetupTestResult.ofOkay(LmsType.MOODLE));
final MoodleCourseAccess moodleCourseAccess = new MoodleCourseAccess( final MoodleCourseAccess moodleCourseAccess = new MoodleCourseAccess(