diff options
Diffstat (limited to 'id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java')
-rw-r--r-- | id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java | 376 |
1 files changed, 173 insertions, 203 deletions
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java index c67d10ab7..46e02d048 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/SingleLogOutAction.java @@ -22,26 +22,51 @@ */ package at.gv.egovernment.moa.id.protocols.pvp2x; +import java.io.Serializable; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.security.NoSuchAlgorithmException; +import java.util.ArrayList; +import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Map.Entry; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.apache.commons.lang.SerializationUtils; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.hibernate.HibernateException; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.opensaml.common.SAMLObject; +import org.opensaml.common.binding.BasicSAMLMessageContext; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.core.LogoutRequest; import org.opensaml.saml2.core.LogoutResponse; import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.Status; import org.opensaml.saml2.core.StatusCode; +import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.saml2.metadata.SingleLogoutService; +import org.opensaml.saml2.metadata.impl.SingleLogoutServiceBuilder; import org.opensaml.ws.message.encoder.MessageEncodingException; import org.opensaml.ws.soap.common.SOAPException; import org.opensaml.xml.XMLObject; import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.x509.X509Credential; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.auth.servlet.RedirectServlet; +import at.gv.egovernment.moa.id.commons.db.MOASessionDBUtils; +import at.gv.egovernment.moa.id.commons.db.dao.session.AssertionStore; +import at.gv.egovernment.moa.id.commons.db.dao.session.InterfederationSessionStore; import at.gv.egovernment.moa.id.commons.db.dao.session.OASessionStore; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; @@ -49,9 +74,11 @@ import at.gv.egovernment.moa.id.data.IAuthData; import at.gv.egovernment.moa.id.data.SLOInformationContainer; import at.gv.egovernment.moa.id.data.SLOInformationImpl; import at.gv.egovernment.moa.id.data.SLOInformationInterface; +import at.gv.egovernment.moa.id.moduls.AuthenticationManager; import at.gv.egovernment.moa.id.moduls.IAction; import at.gv.egovernment.moa.id.moduls.IRequest; import at.gv.egovernment.moa.id.moduls.SSOManager; +import at.gv.egovernment.moa.id.opemsaml.MOAStringRedirectDeflateEncoder; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IEncoder; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding; @@ -59,12 +86,17 @@ import at.gv.egovernment.moa.id.protocols.pvp2x.builder.SingleLogOutBuilder; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.BindingNotSupportedException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.SLOException; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest; +import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOAResponse; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.MOASAMLSOAPClient; import at.gv.egovernment.moa.id.storage.AssertionStorage; import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; import at.gv.egovernment.moa.id.util.Random; +import at.gv.egovernment.moa.id.util.VelocityProvider; import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MessageProvider; import at.gv.egovernment.moa.util.MiscUtil; +import at.gv.egovernment.moa.util.URLEncoder; /** * @author tlenz @@ -82,16 +114,16 @@ public class SingleLogOutAction implements IAction { PVPTargetConfiguration pvpReq = (PVPTargetConfiguration) req; - if (pvpReq.getRequest() instanceof MOARequest) { + if (pvpReq.getRequest() instanceof MOARequest && + ((MOARequest)pvpReq.getRequest()).getSamlRequest() instanceof LogoutRequest) { + Logger.debug("Process Single LogOut request"); MOARequest samlReq = (MOARequest) pvpReq.getRequest(); - if (samlReq.getSamlRequest() instanceof LogoutRequest) { - Logger.debug("Process Single LogOut request"); - LogoutRequest logOutReq = (LogoutRequest) samlReq.getSamlRequest(); + LogoutRequest logOutReq = (LogoutRequest) samlReq.getSamlRequest(); - AuthenticationSession session = - AuthenticationSessionStoreage.searchMOASessionWithNameIDandOAID( - logOutReq.getIssuer().getValue(), - logOutReq.getNameID().getValue()); + AuthenticationSession session = + AuthenticationSessionStoreage.searchMOASessionWithNameIDandOAID( + logOutReq.getIssuer().getValue(), + logOutReq.getNameID().getValue()); if (session == null) { Logger.warn("Can not find active SSO session with nameID " @@ -104,7 +136,7 @@ public class SingleLogOutAction implements IAction { Logger.warn("Can not find active Session. Single LogOut not possible!"); SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq); LogoutResponse message = SingleLogOutBuilder.buildSLOErrorResponse(sloService, pvpReq); - sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); + SingleLogOutBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); return null; } else { @@ -116,101 +148,150 @@ public class SingleLogOutAction implements IAction { Logger.warn("Can not find active Session. Single LogOut not possible!"); SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq); LogoutResponse message = SingleLogOutBuilder.buildSLOErrorResponse(sloService, pvpReq); - sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); + SingleLogOutBuilder.sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); return null; } } } - //store active OAs to SLOContaine - List<OASessionStore> dbOAs = AuthenticationSessionStoreage.getAllActiveOAFromMOASession(session); - SLOInformationContainer sloContainer = new SLOInformationContainer(); - sloContainer.setSloRequest(pvpReq); - sloContainer.parseActiveOAs(dbOAs, logOutReq.getIssuer().getValue()); - - //terminate MOASession - try { - AuthenticationSessionStoreage.destroySession(session.getSessionID()); - - } catch (MOADatabaseException e) { - Logger.warn("Delete MOASession FAILED."); - sloContainer.putFailedOA(AuthConfigurationProvider.getInstance().getPublicURLPrefix()); - - } - - //start service provider back channel logout process - Iterator<String> nextOAInterator = sloContainer.getNextBackChannelOA(); - while (nextOAInterator.hasNext()) { - SLOInformationImpl sloDescr = sloContainer.getBackChannelOASessionDescripten(nextOAInterator.next()); - LogoutRequest sloReq = SingleLogOutBuilder.buildSLORequestMessage(sloDescr); - - try { - List<XMLObject> soapResp = MOASAMLSOAPClient.send(sloDescr.getServiceURL(), sloReq); - - LogoutResponse sloResp = null; - for (XMLObject el : soapResp) { - if (el instanceof LogoutResponse) - sloResp = (LogoutResponse) el; - } - - if (sloResp == null) { - Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue() - + " FAILED. NO LogOut response received."); - sloContainer.putFailedOA(sloReq.getIssuer().getValue()); + AuthenticationManager authManager = AuthenticationManager.getInstance(); + authManager.performSingleLogOut(httpReq, httpResp, session, pvpReq); - } - - checkStatusCode(sloContainer, sloResp); - - } catch (SOAPException e) { - Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue() - + " FAILED.", e); - sloContainer.putFailedOA(sloReq.getIssuer().getValue()); - - } catch (SecurityException e) { - Logger.warn("Single LogOut for OA " + sloReq.getIssuer().getValue() - + " FAILED.", e); - sloContainer.putFailedOA(sloReq.getIssuer().getValue()); - - } - } - - //start service provider front channel logout process - try { - doFrontChannelLogOut(sloContainer, httpReq, httpResp); - - } catch (MOADatabaseException e) { - Logger.error("MOA AssertionDatabase ERROR", e); - SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq); - LogoutResponse message = SingleLogOutBuilder.buildSLOErrorResponse(sloService, pvpReq); - sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); - return null; - - } - - } else if (samlReq.getSamlRequest() instanceof LogoutResponse) { + } else if (pvpReq.getRequest() instanceof MOAResponse && + ((MOAResponse)pvpReq.getRequest()).getResponse() instanceof LogoutResponse) { Logger.debug("Process Single LogOut response"); - LogoutResponse logOutResp = (LogoutResponse) samlReq.getSamlRequest(); + LogoutResponse logOutResp = (LogoutResponse) ((MOAResponse)pvpReq.getRequest()).getResponse(); - try { - if (MiscUtil.isEmpty(samlReq.getRelayState())) { + try { + String relayState = pvpReq.getRequest().getRelayState(); + if (MiscUtil.isEmpty(relayState)) { Logger.warn("SLO Response from " + logOutResp.getIssuer().getValue() + " has no SAML2 RelayState."); throw new SLOException("pvp2.19", null); } - SLOInformationContainer sloContainer = - AssertionStorage.getInstance().get(samlReq.getRelayState(), SLOInformationContainer.class); - checkStatusCode(sloContainer, logOutResp); - sloContainer.removeFrontChannelOA(logOutResp.getIssuer().getValue()); - doFrontChannelLogOut(sloContainer, httpReq, httpResp); + Session session = MOASessionDBUtils.getCurrentSession(); + boolean storageSuccess = false; + int counter = 0; + + //TODO: add counter to prevent deadlock + + while (!storageSuccess) { + Transaction tx = session.beginTransaction(); + + List result; + Query query = session.getNamedQuery("getAssertionWithArtifact"); + query.setParameter("artifact", relayState); + result = query.list(); + Logger.trace("Found entries: " + result.size()); + + //Assertion requires an unique artifact + if (result.size() != 1) { + Logger.trace("No entries found."); + throw new MOADatabaseException("No sessioninformation found with this ID"); + } + + AssertionStore element = (AssertionStore) result.get(0); + Object data = SerializationUtils.deserialize(element.getAssertion()); + + if (data instanceof SLOInformationContainer) { + SLOInformationContainer sloContainer = (SLOInformationContainer) data; + + //check status + SingleLogOutBuilder.checkStatusCode(sloContainer, logOutResp); + + if (sloContainer.hasFrontChannelOA()) { + try { + //some response are open + byte[] serializedSLOContainer = SerializationUtils.serialize((Serializable) sloContainer); + element.setAssertion(serializedSLOContainer); + element.setType(sloContainer.getClass().getName()); + + session.saveOrUpdate(element); + tx.commit(); + + //sloContainer could be stored to database + storageSuccess = true; + + } catch(HibernateException e) { + tx.rollback(); + + counter++; + Logger.debug("SLOContainter could not stored to database. Wait some time and restart storage process ... "); + java.util.Random rand = new java.util.Random(); + + try { + Thread.sleep(rand.nextInt(20)*10); + + } catch (InterruptedException e1) { + Logger.warn("Thread could not stopped. ReStart storage process immediately", e1); + } + } + + } else { + //last response received. + try { + session.delete(element); + tx.commit(); + + } catch(HibernateException e) { + tx.rollback(); + Logger.error("SLOContainter could not deleted from database. "); + + } + + storageSuccess = true; + String redirectURL = null; + if (sloContainer.getSloRequest() != null) { + //send SLO response to SLO request issuer + SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(sloContainer.getSloRequest()); + LogoutResponse message = SingleLogOutBuilder.buildSLOResponseMessage(sloService, sloContainer.getSloRequest(), sloContainer.getSloFailedOAs()); + redirectURL = SingleLogOutBuilder.getFrontChannelSLOMessageURL(sloService, message, httpReq, httpResp, sloContainer.getSloRequest().getRequest().getRelayState()); + + } else { + //print SLO information directly + redirectURL = AuthConfigurationProvider.getInstance().getPublicURLPrefix() + "/idpSingleLogout"; + + String artifact = Random.nextRandom(); + + String statusCode = null; + if (sloContainer.getSloFailedOAs() == null || + sloContainer.getSloFailedOAs().size() == 0) + statusCode = SLOSTATUS_SUCCESS; + else + statusCode = SLOSTATUS_ERROR; + + AssertionStorage.getInstance().put(artifact, statusCode); + redirectURL = addURLParameter(redirectURL, PARAM_SLOSTATUS, artifact); + + } + //redirect to Redirect Servlet + String url = AuthConfigurationProvider.getInstance().getPublicURLPrefix() + "/RedirectServlet"; + url = addURLParameter(url, RedirectServlet.REDIRCT_PARAM_URL, URLEncoder.encode(redirectURL, "UTF-8")); + url = httpResp.encodeRedirectURL(url); + + httpResp.setContentType("text/html"); + httpResp.setStatus(302); + httpResp.addHeader("Location", url); + + } + } else { + Logger.warn("Sessioninformation Cast-Exception by using Artifact=" + relayState); + throw new MOADatabaseException("Sessioninformation Cast-Exception"); + + } + } } catch (MOADatabaseException e) { Logger.error("MOA AssertionDatabase ERROR", e); throw new SLOException("pvp2.19", null); + } catch (UnsupportedEncodingException e) { + Logger.error("Finale SLO redirct not possible.", e); + throw new AuthenticationException("pvp2.13", new Object[]{}); + } } else { @@ -218,13 +299,7 @@ public class SingleLogOutAction implements IAction { throw new MOAIDException("pvp2.13", null); } - - } else { - Logger.error("Process SingleLogOutAction but request is NOT of type MOARequest."); - throw new MOAIDException("pvp2.13", null); - - } - + return null; } @@ -245,117 +320,12 @@ public class SingleLogOutAction implements IAction { return PVP2XProtocol.SINGLELOGOUT; } - private void checkStatusCode(SLOInformationContainer sloContainer, LogoutResponse logOutResp) { - Status status = logOutResp.getStatus(); - if (!status.getStatusCode().equals(StatusCode.SUCCESS_URI)) { - Logger.warn("Single LogOut for OA " + logOutResp.getIssuer().getValue() - + " FAILED. (ResponseCode: " + status.getStatusCode().getValue() - + " Message: " + status.getStatusMessage().getMessage() + ")"); - sloContainer.putFailedOA(logOutResp.getIssuer().getValue()); - - } else - Logger.debug("Single LogOut for OA " + logOutResp.getIssuer().getValue() + " SUCCESS"); - + protected static String addURLParameter(String url, String paramname, + String paramvalue) { + String param = paramname + "=" + paramvalue; + if (url.indexOf("?") < 0) + return url + "?" + param; + else + return url + "&" + param; } - - private void doFrontChannelLogOut(SLOInformationContainer sloContainer, - HttpServletRequest httpReq, HttpServletResponse httpResp - ) throws MOAIDException, MOADatabaseException { - String nextOA = sloContainer.getNextFrontChannelOA(); - if (MiscUtil.isNotEmpty(nextOA)) { - SLOInformationImpl sloDescr = sloContainer.getFrontChannelOASessionDescripten(nextOA); - LogoutRequest sloReq = SingleLogOutBuilder.buildSLORequestMessage(sloDescr); - String relayState = Random.nextRandom(); - - AssertionStorage.getInstance().put(relayState, sloContainer); - - sendFrontChannelSLOMessage(sloDescr.getServiceURL(), sloDescr.getBinding(), - sloReq, httpReq, httpResp, relayState); - - } else { - //send SLO response to SLO request issuer - PVPTargetConfiguration pvpReq = sloContainer.getSloRequest(); - MOARequest samlReq = (MOARequest) pvpReq.getRequest(); - SingleLogoutService sloService = SingleLogOutBuilder.getResponseSLODescriptor(pvpReq); - LogoutResponse message = SingleLogOutBuilder.buildSLOResponseMessage(sloService, pvpReq, sloContainer.getSloFailedOAs()); - sendFrontChannelSLOMessage(sloService, message, httpReq, httpResp, samlReq.getRelayState()); - - } - } - - /** - * @param serviceURL - * @param binding - * @param sloReq - * @param httpReq - * @param httpResp - * @param relayState - */ - private void sendFrontChannelSLOMessage(String serviceURL, String bindingType, - RequestAbstractType sloReq, HttpServletRequest httpReq, - HttpServletResponse httpResp, String relayState) throws MOAIDException { - IEncoder binding = null; - if (bindingType.equals( - SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { - binding = new RedirectBinding(); - - } else if (bindingType.equals( - SAMLConstants.SAML2_POST_BINDING_URI)) { - binding = new PostBinding(); - - } - - if (binding == null) { - throw new BindingNotSupportedException(bindingType); - } - - try { - binding.encodeRequest(httpReq, httpResp, sloReq, - serviceURL, relayState); - - } catch (MessageEncodingException e) { - Logger.error("Message Encoding exception", e); - throw new MOAIDException("pvp2.01", null, e); - - } catch (SecurityException e) { - Logger.error("Security exception", e); - throw new MOAIDException("pvp2.01", null, e); - - } - - } - - private void sendFrontChannelSLOMessage(SingleLogoutService consumerService, - LogoutResponse sloResp, HttpServletRequest req, HttpServletResponse resp, - String relayState) throws MOAIDException { - IEncoder binding = null; - if (consumerService.getBinding().equals( - SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { - binding = new RedirectBinding(); - - } else if (consumerService.getBinding().equals( - SAMLConstants.SAML2_POST_BINDING_URI)) { - binding = new PostBinding(); - - } - - if (binding == null) { - throw new BindingNotSupportedException(consumerService.getBinding()); - } - - try { - binding.encodeRespone(req, resp, sloResp, - consumerService.getLocation(), relayState); - - } catch (MessageEncodingException e) { - Logger.error("Message Encoding exception", e); - throw new MOAIDException("pvp2.01", null, e); - - } catch (SecurityException e) { - Logger.error("Security exception", e); - throw new MOAIDException("pvp2.01", null, e); - - } - - } } |