seb-server/src/main/java/ch/ethz/seb/sebserver/gui/InstitutionalAuthenticationEntryPoint.java

231 lines
9.5 KiB
Java
Raw Normal View History

2019-02-14 16:54:48 +01:00
/*
* Copyright (c) 2019 ETH Zürich, Educational Development and Technology (LET)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package ch.ethz.seb.sebserver.gui;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
2019-02-14 16:54:48 +01:00
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.binary.Base64InputStream;
2019-02-14 16:54:48 +01:00
import org.apache.commons.lang3.StringUtils;
2020-01-23 16:46:05 +01:00
import org.eclipse.rap.rwt.RWT;
2019-02-14 16:54:48 +01:00
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
2019-02-14 16:54:48 +01:00
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import org.springframework.util.FileCopyUtils;
2019-02-14 16:54:48 +01:00
import org.springframework.web.client.RestTemplate;
2019-10-07 13:18:16 +02:00
import ch.ethz.seb.sebserver.ClientHttpRequestFactoryService;
import ch.ethz.seb.sebserver.gbl.Constants;
2019-02-14 16:54:48 +01:00
import ch.ethz.seb.sebserver.gbl.api.API;
2020-01-23 16:46:05 +01:00
import ch.ethz.seb.sebserver.gbl.profile.GuiProfile;
2019-02-14 16:54:48 +01:00
import ch.ethz.seb.sebserver.gui.service.remote.webservice.auth.WebserviceURIService;
import ch.ethz.seb.sebserver.gui.widget.ImageUploadSelection;
2019-02-14 16:54:48 +01:00
@Lazy
@Component
2020-01-23 16:46:05 +01:00
@GuiProfile
public final class InstitutionalAuthenticationEntryPoint implements AuthenticationEntryPoint {
private static final String INST_SUFFIX_ATTRIBUTE = "instSuffix";
2019-02-14 16:54:48 +01:00
private static final Logger log = LoggerFactory.getLogger(InstitutionalAuthenticationEntryPoint.class);
private final String guiEntryPoint;
private final String defaultLogo;
2019-02-14 16:54:48 +01:00
private final WebserviceURIService webserviceURIService;
2019-10-07 13:18:16 +02:00
private final ClientHttpRequestFactoryService clientHttpRequestFactoryService;
2019-02-14 16:54:48 +01:00
protected InstitutionalAuthenticationEntryPoint(
@Value("${sebserver.gui.entrypoint}") final String guiEntryPoint,
@Value("${sebserver.gui.defaultLogo:" + Constants.NO_NAME + "}") final String defaultLogoFileName,
2019-02-14 16:54:48 +01:00
final WebserviceURIService webserviceURIService,
final ClientHttpRequestFactoryService clientHttpRequestFactoryService,
final ResourceLoader resourceLoader) {
2019-02-14 16:54:48 +01:00
this.guiEntryPoint = guiEntryPoint;
this.webserviceURIService = webserviceURIService;
2019-10-07 13:18:16 +02:00
this.clientHttpRequestFactoryService = clientHttpRequestFactoryService;
String _defaultLogo = null;
if (!Constants.NO_NAME.equals(defaultLogoFileName)) {
try {
final String extension = ImageUploadSelection.SUPPORTED_IMAGE_FILES.stream()
.filter(ext -> defaultLogoFileName.endsWith(ext))
.findFirst()
.orElse(null);
if (extension == null) {
throw new IllegalArgumentException("Image of type: " + defaultLogoFileName + " not supported");
}
2019-12-11 16:22:20 +01:00
final Resource resource = resourceLoader.getResource(defaultLogoFileName);
final Reader reader = new InputStreamReader(
new Base64InputStream(resource.getInputStream(), true),
Charsets.UTF_8);
_defaultLogo = FileCopyUtils.copyToString(reader);
2019-11-27 10:56:08 +01:00
} catch (final Exception e) {
log.warn("Failed to load default logo image from filesystem: {}", defaultLogoFileName);
_defaultLogo = null;
}
this.defaultLogo = _defaultLogo;
} else {
this.defaultLogo = null;
}
2019-02-14 16:54:48 +01:00
}
@Override
public void commence(
final HttpServletRequest request,
final HttpServletResponse response,
final AuthenticationException authException) throws IOException, ServletException {
2019-08-14 08:11:01 +02:00
final String institutionalEndpoint = extractInstitutionalEndpoint(request);
2019-02-14 16:54:48 +01:00
if (log.isDebugEnabled()) {
log.debug("No default gui entrypoint requested: {}", institutionalEndpoint);
}
2019-02-14 16:54:48 +01:00
2019-08-14 08:11:01 +02:00
final String logoImageBase64 = requestLogoImage(institutionalEndpoint);
2019-06-05 13:58:35 +02:00
if (StringUtils.isNotBlank(logoImageBase64)) {
2019-02-14 16:54:48 +01:00
request.getSession().setAttribute(API.PARAM_LOGO_IMAGE, logoImageBase64);
2020-01-23 16:46:05 +01:00
request.getSession().setAttribute(INST_SUFFIX_ATTRIBUTE, institutionalEndpoint);
2019-08-14 08:11:01 +02:00
forwardToEntryPoint(request, response, this.guiEntryPoint);
2019-02-14 16:54:48 +01:00
} else {
request.getSession().removeAttribute(API.PARAM_LOGO_IMAGE);
response.setStatus(HttpStatus.UNAUTHORIZED.value());
2019-08-14 08:11:01 +02:00
forwardToEntryPoint(request, response, this.guiEntryPoint);
2019-02-14 16:54:48 +01:00
}
2019-08-14 08:11:01 +02:00
}
private void forwardToEntryPoint(
final HttpServletRequest request,
final HttpServletResponse response,
final String entryPoint) throws ServletException, IOException {
final RequestDispatcher dispatcher = request
.getServletContext()
.getRequestDispatcher(entryPoint);
2019-08-08 20:35:57 +02:00
dispatcher.forward(request, response);
2019-02-14 16:54:48 +01:00
}
2020-01-23 16:46:05 +01:00
public static String extractInstitutionalEndpoint(final HttpServletRequest request) {
2019-08-14 08:11:01 +02:00
final String requestURI = request.getRequestURI();
if (log.isDebugEnabled()) {
log.debug("Trying to verify insitution from requested entrypoint url: {}", requestURI);
}
2019-08-08 20:35:57 +02:00
2020-01-23 16:46:05 +01:00
try {
return requestURI.substring(
requestURI.lastIndexOf(Constants.SLASH) + 1,
requestURI.length());
} catch (final Exception e) {
log.error("Fauled to extract institutional URL suffix: {}", e.getMessage());
2019-08-08 20:35:57 +02:00
return null;
}
2020-01-23 16:46:05 +01:00
}
2019-08-08 20:35:57 +02:00
2020-01-23 16:46:05 +01:00
public static String extractInstitutionalEndpoint() {
try {
final Object attribute = RWT.getUISession().getHttpSession().getAttribute(INST_SUFFIX_ATTRIBUTE);
return (attribute != null) ? String.valueOf(attribute) : null;
} catch (final Exception e) {
log.warn("Failed to extract institutional endpoint form user session: {}", e.getMessage());
return null;
}
2019-08-14 08:11:01 +02:00
}
private String requestLogoImage(final String institutionalEndpoint) {
if (StringUtils.isBlank(institutionalEndpoint)) {
return this.defaultLogo;
2019-08-14 08:11:01 +02:00
}
2019-02-14 16:54:48 +01:00
try {
final RestTemplate restTemplate = new RestTemplate();
2019-10-07 13:18:16 +02:00
final ClientHttpRequestFactory clientHttpRequestFactory = this.clientHttpRequestFactoryService
.getClientHttpRequestFactory()
.getOrThrow();
restTemplate.setRequestFactory(clientHttpRequestFactory);
2019-02-14 16:54:48 +01:00
final ResponseEntity<String> exchange = restTemplate
.exchange(
this.webserviceURIService.getURIBuilder()
.path(API.INFO_ENDPOINT + API.INSTITUTIONAL_LOGO_PATH)
.toUriString(),
HttpMethod.GET,
HttpEntity.EMPTY,
String.class,
2019-08-14 08:11:01 +02:00
institutionalEndpoint);
2019-02-14 16:54:48 +01:00
if (exchange.getStatusCodeValue() == HttpStatus.OK.value()) {
return exchange.getBody();
} else {
log.warn("Failed to verify insitution from requested entrypoint url: {}, response: {}",
2019-08-14 08:11:01 +02:00
institutionalEndpoint,
2019-02-14 16:54:48 +01:00
exchange);
}
} catch (final Exception e) {
log.warn("Failed to verify insitution from requested entrypoint url: {}",
2019-08-14 08:11:01 +02:00
institutionalEndpoint,
e);
2019-02-14 16:54:48 +01:00
}
return null;
}
2019-08-14 08:11:01 +02:00
2019-08-20 17:19:15 +02:00
/** TODO this seems not to work as expected. Different Theme is only possible in RAP on different
* entry-points and since entry-points are statically defined within the RAPConficuration
* there is no possibility to apply them dynamically within an institution so far.
2019-09-10 10:26:07 +02:00
*
2019-08-20 17:19:15 +02:00
* @param institutionalEndpoint
* @return */
2019-09-10 10:26:07 +02:00
// private boolean initInstitutionalBasedThemeEntryPoint(final String institutionalEndpoint) {
// try {
// final ApplicationContextImpl appContext = (ApplicationContextImpl) RWT.getApplicationContext();
// final Map<String, String> properties = new HashMap<>();
// properties.put(WebClient.THEME_ID, "sms");
// appContext.getEntryPointManager().register(
// institutionalEndpoint,
// new RAPSpringEntryPointFactory(),
// properties);
//
// return true;
// } catch (final Exception e) {
// log.warn("Failed to dynamically set entry point for institution: {}", institutionalEndpoint, e);
// return false;
// }
// }
2019-08-14 08:11:01 +02:00
2019-02-14 16:54:48 +01:00
}