Commit 83dc8480 authored by Gradl, Tobias's avatar Gradl, Tobias
Browse files

712: Implement error handling

Task-Url: https://minfba.de.dariah.eu/mantisbt/view.php?id=712
parent 4cbc5551
......@@ -9,6 +9,7 @@ public class AuthPojo {
private int level;
private String displayName;
private String language;
private boolean persistent;
private List<String> roles;
public boolean isAuth() { return auth; }
......@@ -29,6 +30,9 @@ public class AuthPojo {
public String getLanguage() { return language; }
public void setLanguage(String language) { this.language = language; }
public boolean isPersistent() { return persistent; }
public void setPersistent(boolean persistent) { this.persistent = persistent; }
public List<String> getRoles() { return roles; }
public void setRoles(List<String> roles) { this.roles = roles; }
}
......@@ -57,6 +57,7 @@ public class SAMLAttributeAggregationService {
if (exOpt.getExcludedEndpoints()!=null && exOpt.getExcludedEndpoints().contains(aggCredential.getRemoteEntityID())) {
if (exOpt.isAssumeRequiredAttributes() || aggCredential.isHasAllAttributes()) {
queryRequired = false;
aggCredential.setHasAllAttributes(true);
}
break;
}
......@@ -79,7 +80,7 @@ public class SAMLAttributeAggregationService {
}
aggCredential = new SAMLAggregatedCredential(aggCredential, queryReturnedAttributes, hasAllReqAttributes(overallAttributes, AUTHENTICATION_STAGE.ATTRIBUTES));
if (!aggCredential.isHasAllAttributes()) {
throw new UserCredentialsException(UserCredentialsExceptionTypes.ATTRIBUTESET_INCOMPLETE, "Incomplete set of attributes presented; terminating authentication");
logger.info("Incomplete set of attributes identified; user needs to complete registration");
}
}
} catch (UserCredentialsException e) {
......
......@@ -71,6 +71,12 @@ public abstract class BaseUserService implements UserService, SAMLUserDetailsSer
User uPersisted = this.loadUserByUsername(u.getEndpointId(), u.getUsername());
if (uPersisted!=null) {
uPersisted.setAuthorities(u.getRoles());
if (u instanceof SAMLUserImpl) {
uPersisted.setHasAllAttributes(((SAMLUserImpl)u).isHasAllAttributes());
}
u = uPersisted;
}
......@@ -175,6 +181,7 @@ public abstract class BaseUserService implements UserService, SAMLUserDetailsSer
if (credential instanceof SAMLAggregatedCredential) {
u.setAggregatedAttributes(this.convertAttributes(((SAMLAggregatedCredential)credential).getAggregatedAttributes()));
u.setHasAllAttributes(((SAMLAggregatedCredential)credential).isHasAllAttributes());
}
return u;
}
......
......@@ -77,6 +77,9 @@ public class AuthInfoHelper {
logger.error("Failed to set maxAutorityLevel for user", e);
}
pojo.setUserId(((UserImpl)user).getId());
pojo.setPersistent(((UserImpl)user).isPersistent());
} else {
pojo.setPersistent(true);
}
}
return pojo;
......
package eu.dariah.de.dariahsp.web;
import java.io.IOException;
import java.net.URLEncoder;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.filter.GenericFilterBean;
import eu.dariah.de.dariahsp.saml.model.SAMLUserImpl;
public class CheckUserFilter extends GenericFilterBean implements InitializingBean {
public static final String ATTRIBUTE_COMPLETION_REDIRECT_ATTR = "incompleteAttributesRedirect";
private String incompleteAttributesRedirect;
private String localRedirect;
private String hostedEntityId;
private boolean attributeAggregation;
public String getIncompleteAttributesRedirect() { return incompleteAttributesRedirect; }
public void setIncompleteAttributesRedirect(String incompleteAttributesRedirect) { this.incompleteAttributesRedirect = incompleteAttributesRedirect; }
public String getLocalRedirect() { return localRedirect; }
public void setLocalRedirect(String localRedirect) { this.localRedirect = localRedirect; }
public String getHostedEntityId() { return hostedEntityId; }
public void setHostedEntityId(String hostedEntityId) { this.hostedEntityId = hostedEntityId; }
public boolean isAttributeAggregation() { return attributeAggregation; }
public void setAttributeAggregation(boolean attributeAggregation) { this.attributeAggregation = attributeAggregation; }
@Override
public void afterPropertiesSet() throws ServletException {
if (attributeAggregation && incompleteAttributesRedirect==null || hostedEntityId==null) {
throw new ServletException("Invalid CheckUserFilter set up; redirect and entityId must be set if attribute aggregation is enabled");
}
super.afterPropertiesSet();
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
chain.doFilter(request, response);
return;
}
HttpServletRequest httpRequest = (HttpServletRequest)request;
HttpServletResponse httpResponse = (HttpServletResponse)response;
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth!=null && auth.isAuthenticated()==true) {
if (auth.getDetails()!=null && auth.getDetails() instanceof UserDetails) {
UserDetails user = (UserDetails)auth.getDetails();
if (user instanceof SAMLUserImpl) {
SAMLUserImpl samlUser = (SAMLUserImpl)user;
if (!samlUser.isHasAllAttributes()) {
if(!httpRequest.getServletPath().equals("/logout") && !httpRequest.getServletPath().endsWith(localRedirect)) {
httpResponse.sendRedirect(localRedirect);
incompleteAttributesRedirect = incompleteAttributesRedirect.replace("{0}", URLEncoder.encode(this.getHostedEntityId(), "UTF-8"));
incompleteAttributesRedirect = incompleteAttributesRedirect.replace("{1}", URLEncoder.encode("/", "UTF-8"));
httpRequest.getSession().setAttribute(ATTRIBUTE_COMPLETION_REDIRECT_ATTR, incompleteAttributesRedirect);
return;
}
}
}
} else if (auth.getPrincipal()!=null && auth.getPrincipal() instanceof User) {
// Local authentication -> nothing to check yet
}
}
chain.doFilter(request, response);
}
}
package eu.dariah.de.dariahsp.sample.controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
......@@ -10,6 +13,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
import eu.dariah.de.dariahsp.model.User;
import eu.dariah.de.dariahsp.service.UserService;
import eu.dariah.de.dariahsp.web.CheckUserFilter;
@Controller
......@@ -33,4 +37,18 @@ public class UserProfileController {
}
return null;
}
@RequestMapping(value="/incompleteProfile", method=RequestMethod.GET)
public String completeProfile(HttpServletRequest request, Model model) {
HttpSession session = request.getSession(false);
if (session != null) {
Object attr = session.getAttribute(CheckUserFilter.ATTRIBUTE_COMPLETION_REDIRECT_ATTR);
if (attr!=null) {
model.addAttribute("redirectUrl", attr.toString());
}
}
return "user/incomplete_profile";
}
}
......@@ -65,7 +65,8 @@ public class SampleExceptionController {
if (httpRequest.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION)!=null) {
Exception authEx = (Exception)httpRequest.getAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
if (authEx.getCause()!=null && authEx.getCause() instanceof SAMLException) {
this.handleSAMLException((SAMLException)authEx.getCause());
errorPage.addObject("exception", authEx.getCause());
errorMsg = "A SAML/Shibboleth related error has occurred. Please try again later. If the problem persists, please notify support.";
}
if (authEx instanceof UserCredentialsException) {
......@@ -77,14 +78,16 @@ public class SampleExceptionController {
} else {
errorPage.addObject("errorMsg", errorMsg);
errorPage.addObject("exception", this.getException(httpRequest));
}
errorPage.addObject("errorMsg", errorMsg);
errorPage.addObject("url", httpRequest.getRequestURL());
return errorPage;
}
private void handleSAMLException(SAMLException exception) {
// Special exception: IDP Authentication too old, needs refresh
if (exception.getCause()!=null && exception.getCause() instanceof CredentialsExpiredException) {
......
auth:
local:
users:
- username: 'admin'
......@@ -39,8 +38,8 @@ auth:
#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
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
......@@ -56,6 +55,8 @@ auth:
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
incompleteAttributesRedirect: "https://dariah.daasi.de/Shibboleth.sso/Login?target=/cgi-bin/selfservice/ldapportal.pl%3Fmode%3Dauthenticate%3Bshibboleth%3D1%3Bnextpage%3Dregistration%3Breturnurl%3D{1}&entityID={0}"
#incompleteAttributesRedirect: "https://auth.dariah.eu/Shibboleth.sso/Login?target=/cgi-bin/selfservice/ldapportal.pl%3Fmode%3Dauthenticate%3Bshibboleth%3D1%3Bnextpage%3Dregistration%3Breturnurl%3D{1}&entityID={0}"
requiredAttributes:
- stage: ATTRIBUTES
required: true
......
......@@ -28,6 +28,7 @@
<security:custom-filter after="BASIC_AUTH_FILTER" ref="authFilter"/>
<security:custom-filter before="REQUEST_CACHE_FILTER" ref="checkUserFilter"/>
<security:custom-filter ref="redirectionAwareFilter" before="PRE_AUTH_FILTER" />
<security:custom-filter ref="redirectionAwareFilter" after="REQUEST_CACHE_FILTER" />
......@@ -46,7 +47,12 @@
<property name="defaultTargetUrl" value="/logout"/>
</bean>
<bean id="checkUserFilter" class="eu.dariah.de.dariahsp.web.CheckUserFilter">
<property name="localRedirect" value="user/incompleteProfile" />
<property name="incompleteAttributesRedirect" value="${auth.saml.sp.attributeQuery.incompleteAttributesRedirect:#{null}}" />
<property name="hostedEntityId" value="${auth.saml.sp.entityId:#{null}}" />
<property name="attributeAggregation" value="${auth.saml.sp.attributeQuery.enabled:false}" />
</bean>
<!-- This probably needs to be changed to a persisting extension of BaseUserService -->
<bean id="userDetailsService" class="eu.dariah.de.dariahsp.sample.service.CachingUserServiceImpl">
......
......@@ -30,13 +30,11 @@
${errorMsg}
</p>
<pre>
Failed URL: ${url}
Exception: ${exception.message}
<c:forEach items="${exception.stackTrace}" var="ste"> ${ste}
</c:forEach>
</pre>
<pre>Failed URL: ${url}
Exception: ${exception.message}
<c:forEach items="${exception.stackTrace}" var="ste">
${ste}</c:forEach>
</pre>
</div>
</div>
</div>
......
......@@ -26,9 +26,13 @@
</ul>
<div id="main-content">
<h2>Home</h2>
<p>
Authenticated: ${_auth!=null && _auth.auth==true}
</p>
<table>
<tr><th>Authenticated:&nbsp;</th><td>${_auth!=null && _auth.auth==true}</td></tr>
<c:if test="${_auth!=null && _auth.auth==true}">
<tr><th>Display name:&nbsp;</th><td>${_auth.displayName}</td></tr>
<tr><th>Persistent:&nbsp;</th><td>${_auth.persistent}</td></tr>
</c:if>
</table>
</div>
</div>
</div>
......
<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="s" uri="http://www.springframework.org/tags" %>
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags/form" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<tiles:importAttribute name="fluidLayout" />
<div class="jumbotron">
<div class="container<c:if test="${fluidLayout==true}">-fluid</c:if>">
<div class="row">
<div class="xs-hidden sm-visible col-sm-3 col-lg-2 col-sm-offset-1">
<div class="pull-right dariah-flower-white-83">DARIAHSP Test App</div>
</div>
</div>
</div>
</div>
<div class="container<c:if test="${fluidLayout==true}">-fluid</c:if>">
<div class="row">
<div id="main-content-wrapper" class="col-sm-10 col-sm-offset-1">
<ul class="breadcrumb">
<li class="active">Home</li>
</ul>
<div id="main-content">
<h2>Insufficient Information</h2>
<p>Your home organisation did not provide sufficient attributes to this service.
You will be redirected to the <a href="_self" target="${redirectUrl}">DARIAH central user registry</a> and complete your profile in order to use this service.</p>
<p>After Registration, you will be able to access your resources provided you are authorized.</p>
<h3>More Details</h3>
Home Organisation Name: <b>...</b><br/>
Home Organisation entityID: <b>...</b><br/>
You were trying to access the following URL: <b>...></b>
<script type="text/javascript">
<!--
setTimeout(function() { window.location = "${redirectUrl}" }, 5000);
//-->
</script>
</div>
</div>
</div>
</div>
......@@ -59,6 +59,9 @@
<definition name="user" extends="template_simple">
<put-attribute name="content" value="/WEB-INF/view/jsp/user.jsp" />
</definition>
<definition name="user/incomplete_profile" extends="template_simple">
<put-attribute name="content" value="/WEB-INF/view/jsp/incomplete_profile.jsp" />
</definition>
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment