SEBSERV-90 fornt-end implementation and fixes on back-end
This commit is contained in:
parent
5d481d8933
commit
307177f426
9 changed files with 92 additions and 123 deletions
|
@ -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()
|
||||
|
|
|
@ -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);
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue