SEBSERV-90 fornt-end implementation and fixes on back-end

This commit is contained in:
anhefti 2019-10-07 13:46:15 +02:00
parent 5d481d8933
commit 307177f426
9 changed files with 92 additions and 123 deletions

View file

@ -44,8 +44,8 @@ import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ResourceUtils;
import ch.ethz.seb.sebserver.gbl.api.Proxy;
import ch.ethz.seb.sebserver.gbl.api.Proxy.ProxyAuthType;
import ch.ethz.seb.sebserver.gbl.api.ProxyData;
import ch.ethz.seb.sebserver.gbl.api.ProxyData.ProxyAuthType;
import ch.ethz.seb.sebserver.gbl.util.Result;
@Service
@ -66,7 +66,7 @@ public class ClientHttpRequestFactoryService {
return getClientHttpRequestFactory(null);
}
public Result<ClientHttpRequestFactory> getClientHttpRequestFactory(final Proxy proxy) {
public Result<ClientHttpRequestFactory> getClientHttpRequestFactory(final ProxyData proxy) {
return Result.tryCatch(() -> {
final List<String> activeProfiles = Arrays.asList(this.environment.getActiveProfiles());
if (CollectionUtils.containsAny(activeProfiles, DEV_PROFILES)) {
@ -83,7 +83,7 @@ public class ClientHttpRequestFactoryService {
* not following redirects on redirect responses.
*
* @return ClientHttpRequestFactory bean for development profiles */
private ClientHttpRequestFactory clientHttpRequestFactory(final Proxy proxy) {
private ClientHttpRequestFactory clientHttpRequestFactory(final ProxyData proxy) {
log.info("Initialize ClientHttpRequestFactory with insecure ClientHttpRequestFactory for development");
@ -113,7 +113,7 @@ public class ClientHttpRequestFactoryService {
* @throws KeyStoreException
* @throws NoSuchAlgorithmException
* @throws KeyManagementException */
private ClientHttpRequestFactory clientHttpRequestFactoryTLS(final Proxy proxy) throws KeyManagementException,
private ClientHttpRequestFactory clientHttpRequestFactoryTLS(final ProxyData proxy) throws KeyManagementException,
NoSuchAlgorithmException, KeyStoreException, CertificateException, FileNotFoundException, IOException {
log.info("Initialize with secure ClientHttpRequestFactory for production");
@ -157,9 +157,6 @@ public class ClientHttpRequestFactoryService {
.build();
}
final HttpClientBuilder clientBuilder = HttpClients.custom()
.setSSLContext(sslContext);
if (proxy.proxyAuthType != null && proxy.proxyAuthType != ProxyAuthType.NONE) {
log.info("Initialize ClientHttpRequestFactory with proxy auth: {} : {}",
@ -178,14 +175,14 @@ public class ClientHttpRequestFactoryService {
}
// TODO set connection and read timeout!? configurable!?
private HttpClient createProxiedClient(final Proxy proxy, final SSLContext sslContext) {
private HttpClient createProxiedClient(final ProxyData proxy, final SSLContext sslContext) {
final CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
AuthScope.ANY,
new UsernamePasswordCredentials(
proxy.proxyAuthUsername,
proxy.proxyAuthSecret));
proxy.getProxyAuthUsernameAsString(),
proxy.getProxyAuthSecretAsString()));
final HttpClientBuilder clientBuilder = HttpClients
.custom()

View file

@ -12,8 +12,6 @@ import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.error.ErrorController;
@ -42,8 +40,6 @@ import ch.ethz.seb.sebserver.gbl.profile.WebServiceProfile;
@Order(7)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements ErrorController {
private static final Logger log = LoggerFactory.getLogger(WebSecurityConfig.class);
@Value("${sebserver.webservice.http.redirect.gui}")
private String guiRedirect;
@Value("${sebserver.webservice.api.exam.endpoint.discovery}")
@ -98,99 +94,4 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements E
public String getErrorPath() {
return "/error";
}
// /** A ClientHttpRequestFactory for development profile with no TSL SSL protocol and
// * not following redirects on redirect responses.
// *
// * @return ClientHttpRequestFactory bean for development profiles */
// @Bean
// @DevGuiProfile
// @DevWebServiceProfile
// public ClientHttpRequestFactory clientHttpRequestFactory() {
//
// log.info("Initialize with insecure ClientHttpRequestFactory for development");
//
// final DevClientHttpRequestFactory devClientHttpRequestFactory = new DevClientHttpRequestFactory();
// devClientHttpRequestFactory.setOutputStreaming(false);
// return devClientHttpRequestFactory;
// }
//
// /** A ClientHttpRequestFactory used in production with TSL SSL configuration.
// *
// * @return ClientHttpRequestFactory with TLS / SSL configuration
// * @throws IOException
// * @throws FileNotFoundException
// * @throws CertificateException
// * @throws KeyStoreException
// * @throws NoSuchAlgorithmException
// * @throws KeyManagementException */
// @Bean
// @ProdGuiProfile
// @ProdWebServiceProfile
// public ClientHttpRequestFactory clientHttpRequestFactoryTLS(final Environment env) throws KeyManagementException,
// NoSuchAlgorithmException, KeyStoreException, CertificateException, FileNotFoundException, IOException {
//
// log.info("Initialize with secure ClientHttpRequestFactory for production");
//
// final String truststoreFilePath = env
// .getProperty("server.ssl.trust-store", "");
//
// SSLContext sslContext = null;
// if (StringUtils.isBlank(truststoreFilePath)) {
//
// log.info("Securing outgoing calls without trust-store by trusting all certificates");
//
// sslContext = org.apache.http.ssl.SSLContexts
// .custom()
// .loadTrustMaterial(null, new TrustAllStrategy())
// .build();
//
// } else {
//
// log.info("Securing with defined trust-store");
//
// final File trustStoreFile = ResourceUtils.getFile("file:" + truststoreFilePath);
//
// final char[] password = env
// .getProperty("server.ssl.trust-store-password", "")
// .toCharArray();
//
// if (password.length < 3) {
// log.error("Missing or incorrect trust-store password: " + String.valueOf(password));
// throw new IllegalArgumentException("Missing or incorrect trust-store password");
// }
//
// // Set the specified trust-store also on javax.net.ssl level
// System.setProperty("javax.net.ssl.trustStore", truststoreFilePath);
// System.setProperty("javax.net.ssl.trustStorePassword", String.valueOf(password));
//
// sslContext = SSLContextBuilder
// .create()
// .loadTrustMaterial(trustStoreFile, password)
// .setKeyStoreType("pkcs12")
// .build();
// }
//
// final HttpClient client = HttpClients.custom()
// .setSSLContext(sslContext)
// .build();
//
// // TODO set connection and read timeout!? configurable!?
// return new HttpComponentsClientHttpRequestFactory(client);
// }
//
// // TODO set connection and read timeout!? configurable!?
// private static class DevClientHttpRequestFactory extends SimpleClientHttpRequestFactory {
//
// @Override
// protected void prepareConnection(
// final HttpURLConnection connection,
// final String httpMethod) throws IOException {
//
// super.prepareConnection(connection, httpMethod);
// super.setBufferRequestBody(false);
// connection.setInstanceFollowRedirects(false);
// }
// }
}

View file

@ -8,7 +8,9 @@
package ch.ethz.seb.sebserver.gbl.api;
public class Proxy {
import ch.ethz.seb.sebserver.gbl.util.Utils;
public class ProxyData {
public enum ProxyAuthType {
NONE,
@ -18,15 +20,15 @@ public class Proxy {
public final ProxyAuthType proxyAuthType;
public final String proxyName;
public final int proxyPort;
public final String proxyAuthUsername;
public final String proxyAuthSecret;
public final CharSequence proxyAuthUsername;
public final CharSequence proxyAuthSecret;
protected Proxy(
public ProxyData(
final ProxyAuthType proxyAuthType,
final String proxyName,
final int proxyPort,
final String proxyAuthUsername,
final String proxyAuthSecret) {
final CharSequence proxyAuthUsername,
final CharSequence proxyAuthSecret) {
;
this.proxyAuthType = proxyAuthType;
this.proxyName = proxyName;
@ -47,12 +49,20 @@ public class Proxy {
return this.proxyAuthType;
}
public String getProxyAuthUsername() {
public CharSequence getProxyAuthUsername() {
return this.proxyAuthUsername;
}
public String getProxyAuthSecret() {
public CharSequence getProxyAuthSecret() {
return this.proxyAuthSecret;
}
public String getProxyAuthUsernameAsString() {
return Utils.toString(this.proxyAuthUsername);
}
public String getProxyAuthSecretAsString() {
return Utils.toString(this.proxyAuthSecret);
}
}

View file

@ -21,7 +21,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.POSTMapper;
import ch.ethz.seb.sebserver.gbl.api.Proxy.ProxyAuthType;
import ch.ethz.seb.sebserver.gbl.api.ProxyData.ProxyAuthType;
import ch.ethz.seb.sebserver.gbl.model.Activatable;
import ch.ethz.seb.sebserver.gbl.model.Domain.INSTITUTION;
import ch.ethz.seb.sebserver.gbl.model.Domain.LMS_SETUP;

View file

@ -19,6 +19,7 @@ import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
import ch.ethz.seb.sebserver.gbl.api.API;
import ch.ethz.seb.sebserver.gbl.api.ProxyData.ProxyAuthType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;
@ -73,6 +74,12 @@ public class LmsSetupForm implements TemplateComposer {
new LocTextKey("sebserver.lmssetup.form.name");
private static final LocTextKey FORM_INSTITUTION_TEXT_KEY =
new LocTextKey("sebserver.lmssetup.form.institution");
private static final LocTextKey FORM_PROXY_AUTH_TYPE_KEY =
new LocTextKey("sebserver.lmssetup.form.proxy.auth-type");
private static final LocTextKey FORM_PROXY_AUTH_NAME_KEY =
new LocTextKey("sebserver.lmssetup.form.proxy.auth-name");
private static final LocTextKey FORM_PROXY_AUTH_PASS_KEY =
new LocTextKey("sebserver.lmssetup.form.proxy.auth-secret");
private final PageService pageService;
private final ResourceService resourceService;
@ -141,6 +148,7 @@ public class LmsSetupForm implements TemplateComposer {
// The LMS Setup form
final LmsType lmsType = lmsSetup.getLmsType();
final ProxyAuthType proxyAuthType = lmsSetup.getProxyAuthType();
final FormHandle<LmsSetup> formHandle = this.pageService.formBuilder(
formContext.copyOf(content), 4)
.readonly(readonly)
@ -184,6 +192,20 @@ public class LmsSetupForm implements TemplateComposer {
FORM_SECRET_LMS_TEXT_KEY)
.asPasswordField())
.addField(FormBuilder.singleSelection(
Domain.LMS_SETUP.ATTR_LMS_PROXY_AUTH_TYPE,
FORM_PROXY_AUTH_TYPE_KEY,
(proxyAuthType != null) ? proxyAuthType.name() : null,
this.resourceService::lmsProxyAuthTypeResources))
.addField(FormBuilder.text(
Domain.LMS_SETUP.ATTR_LMS_PROXY_AUTH_USERNAME,
FORM_PROXY_AUTH_NAME_KEY,
(lmsSetup.getProxyAuthUsername() != null) ? lmsSetup.getProxyAuthUsername() : null))
.addField(FormBuilder.text(
Domain.LMS_SETUP.ATTR_LMS_PROXY_AUTH_SECRET,
FORM_PROXY_AUTH_PASS_KEY)
.asPasswordField())
.buildFor((entityKey == null)
? restService.getRestCall(NewLmsSetup.class)
: restService.getRestCall(SaveLmsSetup.class));

View file

@ -28,6 +28,7 @@ import org.springframework.stereotype.Service;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.EntityType;
import ch.ethz.seb.sebserver.gbl.api.ProxyData.ProxyAuthType;
import ch.ethz.seb.sebserver.gbl.model.Entity;
import ch.ethz.seb.sebserver.gbl.model.EntityName;
import ch.ethz.seb.sebserver.gbl.model.exam.Exam;
@ -89,6 +90,8 @@ public class ResourceService {
public static final String USERACCOUNT_ROLE_PREFIX = "sebserver.useraccount.role.";
public static final String EXAM_INDICATOR_TYPE_PREFIX = "sebserver.exam.indicator.type.";
public static final String LMSSETUP_TYPE_PREFIX = "sebserver.lmssetup.type.";
public static final String LMSSETUP_PROXY_AUTH_TYPE_PREFIX = "sebserver.lmssetup.form.proxy.auth-type.";
public static final String CLIENT_EVENT_TYPE_PREFIX = "sebserver.monitoring.exam.connection.event.type.";
public static final String USER_ACTIVITY_TYPE_PREFIX = "sebserver.overall.types.activityType.";
public static final String ENTITY_TYPE_PREFIX = "sebserver.overall.types.entityType.";
@ -149,6 +152,16 @@ public class ResourceService {
.collect(Collectors.toList());
}
public List<Tuple<String>> lmsProxyAuthTypeResources() {
return Arrays.asList(ProxyAuthType.values())
.stream()
.map(authType -> new Tuple<>(
authType.name(),
this.i18nSupport.getText(LMSSETUP_PROXY_AUTH_TYPE_PREFIX + authType.name(), authType.name())))
.sorted(RESOURCE_COMPARATOR)
.collect(Collectors.toList());
}
public List<Tuple<String>> clientEventTypeResources() {
return Arrays.asList(EventType.values())
.stream()

View file

@ -27,7 +27,7 @@ import org.springframework.transaction.annotation.Transactional;
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.Proxy.ProxyAuthType;
import ch.ethz.seb.sebserver.gbl.api.ProxyData.ProxyAuthType;
import ch.ethz.seb.sebserver.gbl.model.Domain;
import ch.ethz.seb.sebserver.gbl.model.EntityKey;
import ch.ethz.seb.sebserver.gbl.model.institution.LmsSetup;

View file

@ -50,6 +50,8 @@ import org.springframework.util.MultiValueMap;
import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService;
import ch.ethz.seb.sebserver.gbl.Constants;
import ch.ethz.seb.sebserver.gbl.api.APIMessage;
import ch.ethz.seb.sebserver.gbl.api.ProxyData;
import ch.ethz.seb.sebserver.gbl.api.ProxyData.ProxyAuthType;
import ch.ethz.seb.sebserver.gbl.async.AsyncService;
import ch.ethz.seb.sebserver.gbl.async.MemoizingCircuitBreaker;
import ch.ethz.seb.sebserver.gbl.model.exam.QuizData;
@ -226,9 +228,28 @@ final class OpenEdxLmsAPITemplate implements LmsAPITemplate {
details.setClientSecret(plainClientSecret.toString());
// TODO get with proxy configuration if applied in LMSSetup
final ClientHttpRequestFactory clientHttpRequestFactory = this.clientHttpRequestFactoryService
.getClientHttpRequestFactory()
.getOrThrow();
ClientHttpRequestFactory clientHttpRequestFactory = null;
if (lmsSetup.proxyAuthType != ProxyAuthType.NONE) {
final ClientCredentials proxyCredentials = new ClientCredentials(
lmsSetup.proxyAuthUsername,
lmsSetup.proxyAuthSecret);
final CharSequence proxySecretPlain = this.clientCredentialService.getPlainClientSecret(proxyCredentials);
final ProxyData proxyData = new ProxyData(
lmsSetup.proxyAuthType,
null,
-1,
proxyCredentials.clientId,
proxySecretPlain);
clientHttpRequestFactory = this.clientHttpRequestFactoryService
.getClientHttpRequestFactory(proxyData)
.getOrThrow();
} else {
clientHttpRequestFactory = this.clientHttpRequestFactoryService
.getClientHttpRequestFactory()
.getOrThrow();
}
final OAuth2RestTemplate template = new OAuth2RestTemplate(details);
template.setRequestFactory(clientHttpRequestFactory);

View file

@ -237,6 +237,11 @@ sebserver.lmssetup.form.secret.seb=SEB Auth. Password
sebserver.lmssetup.form.url=LMS Server Address
sebserver.lmssetup.form.clientname.lms=LMS Server Username
sebserver.lmssetup.form.secret.lms=LMS Server Password
sebserver.lmssetup.form.proxy.auth-type=Proxy Authentication
sebserver.lmssetup.form.proxy.auth-type.NONE=None
sebserver.lmssetup.form.proxy.auth-type.BASIC_AUTH=Basic Authentication
sebserver.lmssetup.form.proxy.auth-name=Proxy Username
sebserver.lmssetup.form.proxy.auth-secret=Proxy Password
################################
# Quiz Discovery