Commit 0aac4b17 authored by Gradl, Tobias's avatar Gradl, Tobias
Browse files

14: Finalize Spring MVC example app

Task-Url: #14
parent e3686e2f
Pipeline #17804 passed with stage
in 2 minutes and 22 seconds
package eu.dariah.de.dariahsp.sample.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import eu.dariah.de.dariahsp.config.SecurityConfig;
import eu.dariah.de.dariahsp.config.web.AuthInfoConfigurer;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.extern.slf4j.Slf4j;
@Data
@EqualsAndHashCode(callSuper=false)
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "auth")
@Import({AuthInfoConfigurer.class})
public class SampleSecurityConfig extends SecurityConfig {
}
package eu.dariah.de.dariahsp.sample;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import eu.dariah.de.dariahsp.sample.config.SampleMvcConfig;
public class SampleWebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return null;
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { SampleMvcConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
package eu.dariah.de.dariahsp.sample.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@ComponentScan({ "eu.dariah.de.dariahsp.sample" })
public class SampleMvcConfig implements WebMvcConfigurer {
}
package eu.dariah.de.dariahsp.sample.controller;
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import eu.dariah.de.dariahsp.web.AuthInfoHelper;
@Controller
@RequestMapping(value="")
public class HomeController {
@Autowired private ServletContext servletContext;
@Autowired private AuthInfoHelper authInfoHelper;
@Value("#{environment.saml!=null?environment.saml:false}")
private boolean saml;
@RequestMapping(value = {"", "/", "/protected/home", "/overprotected/home"}, method = RequestMethod.GET)
public String getHome(HttpServletResponse response) throws IOException {
return "home";
}
@RequestMapping("favicon.ico")
public String forwardFavicon() {
return "forward:/resources/img/page_icon.png";
}
@RequestMapping(value = "/logout", method = RequestMethod.GET)
public String getLogout(@RequestParam(value = "error", required = false) String error, @RequestParam(value = "url", defaultValue = "/") String url, HttpServletRequest request, HttpServletResponse response, Model model) throws IOException {
if (saml && authInfoHelper.getCurrentUserDetails().isAuth()) {
return "redirect:/saml/logout" + (!url.equals("/") ? "?loginRedirectUrl=" + url : "");
} else if (!saml && authInfoHelper.getCurrentUserDetails().isAuth()) {
return "redirect:/localsec/logout" + (!url.equals("/") ? "?loginRedirectUrl=" + url : "");
}
return "common/logout";
}
@RequestMapping(value = {"/throw/{code}", "/throw"}, method = RequestMethod.GET)
public void throwError(@PathVariable(required=false) Integer code, HttpServletRequest request, HttpServletResponse response) throws Exception {
throw new Exception("This is an expected error.");
}
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String getLogin(@RequestParam(value = "error", required = false) String error, @RequestParam(value = "url", defaultValue = "/") String url, HttpServletRequest request, HttpServletResponse response, Model model) throws IOException {
if (saml) {
return "redirect:/saml/login" + (!url.equals("/") ? "?loginRedirectUrl=" + url : "");
}
if (error != null) {
model.addAttribute("error", true);
}
String ctx = servletContext.getContextPath();
if (url.startsWith(ctx)) {
url = url.substring(ctx.length());
}
model.addAttribute("redirectUrl", url);
return "common/login";
}
}
package eu.dariah.de.dariahsp.sample.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
public class SampleController {
@RequestMapping("/greet")
public ModelAndView showview()
{
ModelAndView mv = new ModelAndView();
mv.setViewName("result.jsp");
mv.addObject("result",
"GeeksForGeeks Welcomes "
+ "you to Spring!");
return mv;
}
}
package eu.dariah.de.dariahsp.sample.exceptions;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.web.WebAttributes;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
*
* @author tobias
*
*/
@Controller
@RequestMapping(value="/errors")
public class SampleExceptionController {
protected static final Logger logger = LoggerFactory.getLogger(SampleExceptionController.class);
@RequestMapping(value = {"", "/"}, method = {RequestMethod.GET, RequestMethod.POST })
public String renderErrorPage(Model m, HttpServletRequest httpRequest) {
String errorHeading = "";
String errorDetail = null;
String errorLevel = "warning";
boolean hideHelpText = false;
Throwable e = null;
int httpErrorCode = getErrorCode(httpRequest);
switch (httpErrorCode) {
case 400: {
errorHeading = "Error 400: Bad Request";
break;
}
case 401: {
errorHeading = "Error 401: Unauthorized";
hideHelpText = true;
errorDetail = "Your account is not authorized for this action. Please contact the DARIAH-DE Helpdesk to seek support.";
break;
}
case 403: {
errorHeading = "Error 403: Forbidden";
hideHelpText = true;
errorDetail = "Your account does not have sufficient privileges. Please contact the DARIAH-DE Helpdesk to seek support.";
break;
}
case 404: {
errorHeading = "Error 404: Resource not found";
break;
}
default: {
errorHeading = "Internal Server Error";
break;
}
}
/*if (httpRequest.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION)!=null) {
Exception authEx = (Exception)httpRequest.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
if (authEx.getCause()!=null && authEx.getCause() instanceof SAMLException) {
e = authEx.getCause();
errorDetail = "A SAML/Shibboleth related error has occurred. Please try again later. If the problem persists, please notify support.";
errorLevel = "error";
}
if (authEx instanceof UserCredentialsException) {
e = authEx;
}
} else {*/
e = getException(httpRequest);
//}
m.addAttribute("exception", e);
m.addAttribute("errorHeading", errorHeading);
m.addAttribute("errorDetail", errorDetail);
m.addAttribute("errorLevel", errorLevel);
m.addAttribute("hideHelpText", hideHelpText);
if (e!=null) {
m.addAttribute("errorMsg", e.getMessage());
}
m.addAttribute("url", httpRequest.getRequestURL());
return "error";
}
@RequestMapping(value = "/loginFailed", method = {RequestMethod.GET, RequestMethod.POST })
public String handleLoginFailed(Model m, HttpServletRequest httpRequest) {
return "redirect:/login?error=true";
}
private Exception getException(HttpServletRequest httpRequest) {
if (httpRequest.getAttribute("javax.servlet.error.exception")==null) {
return null;
}
return (Exception) httpRequest.getAttribute("javax.servlet.error.exception");
}
private int getErrorCode(HttpServletRequest httpRequest) {
if (httpRequest.getAttribute("javax.servlet.error.status_code")==null) {
return -1;
}
return (Integer) httpRequest.getAttribute("javax.servlet.error.status_code");
}
}
package eu.dariah.de.dariahsp.sample.exceptions;
//import javax.activity.InvalidActivityException;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
@ControllerAdvice
public class SampleExceptionHandler {
protected static final Logger logger = LoggerFactory.getLogger(SampleExceptionHandler.class);
public static final String DEFAULT_ERROR_VIEW = "error";
@ResponseStatus(HttpStatus.CONFLICT) // 409
// @ExceptionHandler(InvalidActivityException.class)
// public void handleConflict() {
// // Nothing to do, just to show how individual errors could be handled
// }
@ExceptionHandler(value = Exception.class)
public String defaultErrorHandler(Model m, HttpServletRequest req, Exception e) throws Exception {
// If the exception is annotated with @ResponseStatus rethrow it and let
// the framework handle it - like the OrderNotFoundException example
// at the start of this post.
// AnnotationUtils is a Spring Framework utility class.
if (AnnotationUtils.findAnnotation(e.getClass(), ResponseStatus.class) != null) {
throw e;
}
// Otherwise setup and send the user to a default error-view.
m.addAttribute("errorHeading", "An internal server error has occurred");
m.addAttribute("errorMsg", e.getMessage());
m.addAttribute("url", req.getRequestURL());
m.addAttribute("exception", e);
return DEFAULT_ERROR_VIEW;
}
}
auth:
local:
users:
- username: 'admin'
passhash: '$2a$10$nbXRnAx5wKurTrbaUkT/MOLXKAJgpT8R71/jujzPwgXXrG.OqlBKW'
roles: ["ROLE_ADMINISTRATOR"]
- username: 'tgradl'
passhash: '$2a$10$EeajSQQUepa7H7.g4xQCaeO.hjUwh0yzYCMrfOkWCZGe1IiWaexa6'
roles: ["ROLE_CONTRIBUTOR"]
saml:
keystore:
path: /data/_srv/schereg/key/dfa-de-dariah-eu.jks
# Uncomment if keystore is protected by password
#pass: 'somepass'
alias: dfa.de.dariah.eu
aliaspass: ''
metadata:
url: https://www.aai.dfn.de/fileadmin/metadata/dfn-aai-test-metadata.xml
#url: https://www.aai.dfn.de/fileadmin/metadata/dfn-aai-basic-metadata.xml
sp:
local: true
alias: schereg
baseUrl: https://schereg.de.dariah.eu/schereg
entityId: https://schereg.de.dariah.eu
#externalMetadata : /home/tobias/Downloads/spring_saml_metadata.xml
#securityProfile: metaiop
#sslSecurityProfile: pkix
#requireArtifactResolveSigned: false
#requireLogoutRequestSigned: false
#requireLogoutResponseSigned: false
requireAttributeQuerySigned: false
maxAuthAge: -1 # in seconds
signMetadata : true
#signingAlgorithm : http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
discovery:
enabled: true
url: https://wayf.aai.dfn.de/DFN-AAI-Test/wayf
#url: https://auth.dariah.eu/CDS/WAYF
return: https://schereg.de.dariah.eu/schereg/saml/login/alias/schereg?disco:true
ecpEnabled: true
allowedNameIds: EMAIL, TRANSIENT, PERSISTENT, UNSPECIFIED, X509_SUBJECT
#allowedNameIds: EMAIL, PERSISTENT, X509_SUBJECT
signingKey: dfa.de.dariah.eu
encryptionKey: dfa.de.dariah.eu
tlsKey: dfa.de.dariah.eu
attributeQuery:
enabled: true
excludedEndpoints:
urls: ["https://ldap-dariah-clone.esc.rzg.mpg.de/idp/shibboleth", "https://idp.de.dariah.eu/idp/shibboleth"]
assumeAttributesComplete: true
queryIdp: https://ldap-dariah-clone.esc.rzg.mpg.de/idp/shibboleth
#queryIdp: https://idp.de.dariah.eu/idp/shibboleth
queryByNameID: false
queryAttribute:
friendlyName: eduPersonPrincipalName
name: urn:oid:1.3.6.1.4.1.5923.1.1.1.6
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
# For now without parameters bc DARIAH Self Service is broken
incompleteAttributesRedirect: "https://dariah.daasi.de/Shibboleth.sso/Login?target=/cgi-bin/selfservice/ldapportal.pl"
#incompleteAttributesRedirect: "https://dariah.daasi.de/Shibboleth.sso/Login?target=/cgi-bin/selfservice/ldapportal.pl%3Fmode%3Dauthenticate%3Bshibboleth%3D1%3Bnextpage%3Dregistration%3Breturnurl%3D{returnUrl}&entityID={entityId}"
#incompleteAttributesRedirect: "https://auth.dariah.eu/Shibboleth.sso/Login?target=/cgi-bin/selfservice/ldapportal.pl%3Fmode%3Dauthenticate%3Bshibboleth%3D1%3Bnextpage%3Dregistration%3Breturnurl%3D{returnUrl}&entityID={entityId}"
requiredAttributes:
- stage: ATTRIBUTES
required: true
attributeGroup:
- check: AND
attributes:
- friendlyName: mail
name: urn:oid:0.9.2342.19200300.100.1.3
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
- stage: ATTRIBUTES
required: true
attributeGroup:
- check: OR
attributes:
- friendlyName: dariahTermsOfUse
name: urn:oid:1.3.6.1.4.1.10126.1.52.4.15
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
value: Terms_of_Use_v5.pdf
- friendlyName: dariahTermsOfUse
name: urn:oid:1.3.6.1.4.1.10126.1.52.4.15
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
value: foobar-service-agreement_version1.pdf
- stage: AUTHENTICATION
required: true
attributeGroup:
- check: AND
attributes:
- friendlyName: eduPersonPrincipalName
name: urn:oid:1.3.6.1.4.1.5923.1.1.1.6
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
- stage: AUTHENTICATION
required: false
attributeGroup:
- check: OPTIONAL
attributes:
- friendlyName: mail
name: urn:oid:0.9.2342.19200300.100.1.3
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
- friendlyName: displayName
name: urn:oid:2.16.840.1.113730.3.1.241
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
\ No newline at end of file
auth:
local:
users:
- username: 'admin'
passhash: '$2a$10$nbXRnAx5wKurTrbaUkT/MOLXKAJgpT8R71/jujzPwgXXrG.OqlBKW'
roles: ["ROLE_ADMINISTRATOR"]
- username: 'tgradl'
passhash: '$2a$10$EeajSQQUepa7H7.g4xQCaeO.hjUwh0yzYCMrfOkWCZGe1IiWaexa6'
roles: ["ROLE_CONTRIBUTOR"]
saml:
keystore:
path: /data/_srv/minfba/minfba-de-dariah-eu.jks
# Comment if keystore is not protected by password
pass: 'hairad'
alias: minfba.de.dariah.eu
aliaspass: 'hairad'
sp:
requiredAttributes:
- stage: ATTRIBUTES
required: true
attributeGroup:
- check: AND
attributes:
- friendlyName: mail
name: urn:oid:0.9.2342.19200300.100.1.3
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
- stage: ATTRIBUTES
required: true
attributeGroup:
- check: OR
attributes:
- friendlyName: dariahTermsOfUse
name: urn:oid:1.3.6.1.4.1.10126.1.52.4.15
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
value: Terms_of_Use_v5.pdf
- friendlyName: dariahTermsOfUse
name: urn:oid:1.3.6.1.4.1.10126.1.52.4.15
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
value: foobar-service-agreement_version1.pdf
- stage: AUTHENTICATION
required: true
attributeGroup:
- check: AND
attributes:
- friendlyName: eduPersonPrincipalName
name: urn:oid:1.3.6.1.4.1.5923.1.1.1.6
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
- stage: AUTHENTICATION
required: false
attributeGroup:
- check: OPTIONAL
attributes:
- friendlyName: mail
name: urn:oid:0.9.2342.19200300.100.1.3
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
- friendlyName: displayName
name: urn:oid:2.16.840.1.113730.3.1.241
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
\ No newline at end of file
auth:
local:
users:
- username: 'admin'
passhash: '$2a$10$nbXRnAx5wKurTrbaUkT/MOLXKAJgpT8R71/jujzPwgXXrG.OqlBKW'
roles: ["ROLE_ADMINISTRATOR"]
- username: 'tgradl'
passhash: '$2a$10$EeajSQQUepa7H7.g4xQCaeO.hjUwh0yzYCMrfOkWCZGe1IiWaexa6'
roles: ["ROLE_CONTRIBUTOR"]
saml:
keystore:
path: /data/_srv/minfba/minfba-de-dariah-eu.jks
# Comment if keystore is not protected by password
pass: 'hairad'
alias: minfba.de.dariah.eu
aliaspass: 'hairad'
\ No newline at end of file
auth:
local:
users:
- username: 'admin'
passhash: '$2a$10$nbXRnAx5wKurTrbaUkT/MOLXKAJgpT8R71/jujzPwgXXrG.OqlBKW'
roles: ["ROLE_ADMINISTRATOR"]
- username: 'tgradl'
passhash: '$2a$10$EeajSQQUepa7H7.g4xQCaeO.hjUwh0yzYCMrfOkWCZGe1IiWaexa6'
roles: ["ROLE_CONTRIBUTOR"]
saml:
keystore:
path: /data/_srv/schereg/key/dfa-de-dariah-eu.jks
# Uncomment if keystore is protected by password
#pass: 'somepass'
alias: dfa.de.dariah.eu
aliaspass: ''
metadata:
url: https://www.aai.dfn.de/fileadmin/metadata/dfn-aai-test-metadata.xml
#url: https://www.aai.dfn.de/fileadmin/metadata/dfn-aai-basic-metadata.xml
sp:
externalMetadata: /home/tobias/Downloads/spring_saml_metadata.xml
alias: dariahsp
baseUrl: https://minfba.de.dariah.eu/dariahsp
entityId: minfba.de.dariah.eu_dariahsp
securityProfile: metaiop
sslSecurityProfile: pkix
sslHostnameVerification: default
signMetadata: true
signingAlgorithm: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
signingKey: minfba.de.dariah.eu
encryptionKey: minfba.de.dariah.eu
tlsKey: minfba.de.dariah.eu
requireArtifactResolveSigned: true
requireAttributeQuerySigned: false
requireLogoutRequestSigned: true
requireLogoutResponseSigned: false
discovery:
enabled: true
url: https://wayf.aai.dfn.de/DFN-AAI-Test/wayf
#url: https://auth.dariah.eu/CDS/WAYF
return: https://schereg.de.dariah.eu/schereg/saml/login/alias/schereg?disco:true
allowedNameIds : EMAIL, TRANSIENT, PERSISTENT, UNSPECIFIED, X509_SUBJECT
# Attribute querying
attributeQuery:
enabled: true
excludedEndpoints:
urls: ["https://ldap-dariah-clone.esc.rzg.mpg.de/idp/shibboleth", "https://idp.de.dariah.eu/idp/shibboleth"]
assumeAttributesComplete: true
queryIdp: https://ldap-dariah-clone.esc.rzg.mpg.de/idp/shibboleth
#queryIdp: https://idp.de.dariah.eu/idp/shibboleth
queryByNameID: false
queryAttribute:
friendlyName: eduPersonPrincipalName
name: urn:oid:1.3.6.1.4.1.5923.1.1.1.6
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
# For now without parameters bc DARIAH Self Service is broken
incompleteAttributesRedirect: "https://dariah.daasi.de/Shibboleth.sso/Login?target=/cgi-bin/selfservice/ldapportal.pl"
#incompleteAttributesRedirect: "https://dariah.daasi.de/Shibboleth.sso/Login?target=/cgi-bin/selfservice/ldapportal.pl%3Fmode%3Dauthenticate%3Bshibboleth%3D1%3Bnextpage%3Dregistration%3Breturnurl%3D{returnUrl}&entityID={entityId}"
#incompleteAttributesRedirect: "https://auth.dariah.eu/Shibboleth.sso/Login?target=/cgi-bin/selfservice/ldapportal.pl%3Fmode%3Dauthenticate%3Bshibboleth%3D1%3Bnextpage%3Dregistration%3Breturnurl%3D{returnUrl}&entityID={entityId}"
requiredAttributes:
- stage: ATTRIBUTES
required: true
attributeGroup:
- check: AND
attributes:
- friendlyName: mail
name: urn:oid:0.9.2342.19200300.100.1.3
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
- stage: ATTRIBUTES
required: true
attributeGroup:
- check: OR
attributes:
- friendlyName: dariahTermsOfUse
name: urn:oid:1.3.6.1.4.1.10126.1.52.4.15
nameFormat: urn:oasis:names:tc:SAML:2.0:attrname-format:uri
value: Terms_of_Use_v5.pdf
- friendlyName: dariahTermsOfUse