diff options
Diffstat (limited to 'id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols')
5 files changed, 386 insertions, 245 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 92441e663..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,50 @@ */ 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; @@ -50,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; @@ -60,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 @@ -83,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 " @@ -105,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 { @@ -117,103 +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); - List<InterfederationSessionStore> dbIDPs = AuthenticationSessionStoreage.getAllActiveIDPsFromMOASession(session); - SLOInformationContainer sloContainer = new SLOInformationContainer(); - sloContainer.setSloRequest(pvpReq); - sloContainer.parseActiveIDPs(dbIDPs, logOutReq.getIssuer().getValue()); - 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 { @@ -221,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; } @@ -248,120 +320,12 @@ public class SingleLogOutAction implements IAction { return PVP2XProtocol.SINGLELOGOUT; } - private void checkStatusCode(SLOInformationContainer sloContainer, LogoutResponse logOutResp) { - Status status = logOutResp.getStatus(); - if (!status.getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { - String message = " Message: "; - if (status.getStatusMessage() != null) - message += status.getStatusMessage().getMessage(); - Logger.warn("Single LogOut for OA " + logOutResp.getIssuer().getValue() - + " FAILED. (ResponseCode: " + status.getStatusCode().getValue() - + message + ")"); - 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); - - } - - } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java index 7aa860c5c..eeb1dd104 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/SingleLogOutBuilder.java @@ -22,31 +22,53 @@ */ package at.gv.egovernment.moa.id.protocols.pvp2x.builder; +import java.security.NoSuchAlgorithmException; import java.util.List; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + import org.joda.time.DateTime; +import org.opensaml.common.SAMLObject; +import org.opensaml.common.binding.BasicSAMLMessageContext; +import org.opensaml.common.impl.SecureRandomIdentifierGenerator; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.core.Issuer; import org.opensaml.saml2.core.LogoutRequest; import org.opensaml.saml2.core.LogoutResponse; import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.Status; import org.opensaml.saml2.core.StatusCode; import org.opensaml.saml2.core.StatusMessage; +import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml2.metadata.SSODescriptor; import org.opensaml.saml2.metadata.SingleLogoutService; +import org.opensaml.saml2.metadata.impl.SingleLogoutServiceBuilder; import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.x509.X509Credential; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.data.SLOInformationContainer; import at.gv.egovernment.moa.id.data.SLOInformationImpl; +import at.gv.egovernment.moa.id.opemsaml.MOAStringRedirectDeflateEncoder; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration; +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; import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; +import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.BindingNotSupportedException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NOSLOServiceDescriptorException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.NoMetadataInformationException; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest; import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; import at.gv.egovernment.moa.logging.Logger; @@ -57,9 +79,141 @@ import at.gv.egovernment.moa.logging.Logger; */ public class SingleLogOutBuilder { - public static LogoutRequest buildSLORequestMessage(SLOInformationImpl sloInfo) throws ConfigurationException { + public static void checkStatusCode(SLOInformationContainer sloContainer, LogoutResponse logOutResp) { + Status status = logOutResp.getStatus(); + if (!status.getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { + String message = " Message: "; + if (status.getStatusMessage() != null) + message += status.getStatusMessage().getMessage(); + Logger.warn("Single LogOut for OA " + logOutResp.getIssuer().getValue() + + " FAILED. (ResponseCode: " + status.getStatusCode().getValue() + + message + ")"); + sloContainer.putFailedOA(logOutResp.getIssuer().getValue()); + + } else + sloContainer.removeFrontChannelOA(logOutResp.getIssuer().getValue()); + Logger.debug("Single LogOut for OA " + logOutResp.getIssuer().getValue() + " SUCCESS"); + + } + + /** + * @param serviceURL + * @param binding + * @param sloReq + * @param httpReq + * @param httpResp + * @param relayState + * @return + */ + public static String getFrontChannelSLOMessageURL(String serviceURL, String bindingType, + RequestAbstractType sloReq, HttpServletRequest httpReq, + HttpServletResponse httpResp, String relayState) throws MOAIDException { + + try { + X509Credential credentials = CredentialProvider + .getIDPAssertionSigningCredential(); + + Logger.debug("create SAML RedirectBinding response"); + + MOAStringRedirectDeflateEncoder encoder = new MOAStringRedirectDeflateEncoder(); + BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>(); + SingleLogoutService service = new SingleLogoutServiceBuilder() + .buildObject(); + service.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI); + service.setLocation(serviceURL); + context.setOutboundSAMLMessageSigningCredential(credentials); + context.setPeerEntityEndpoint(service); + context.setOutboundSAMLMessage(sloReq); + context.setRelayState(relayState); + + encoder.encode(context); + + return encoder.getRedirectURL(); + + } catch (MessageEncodingException e) { + Logger.error("Message Encoding exception", e); + throw new MOAIDException("pvp2.01", null, e); + + } + } + + public static String getFrontChannelSLOMessageURL(SingleLogoutService service, + StatusResponseType sloResp, HttpServletRequest httpReq, + HttpServletResponse httpResp, String relayState) throws MOAIDException { + + try { + X509Credential credentials = CredentialProvider + .getIDPAssertionSigningCredential(); + + Logger.debug("create SAML RedirectBinding response"); + + MOAStringRedirectDeflateEncoder encoder = new MOAStringRedirectDeflateEncoder(); + BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>(); + context.setOutboundSAMLMessageSigningCredential(credentials); + context.setPeerEntityEndpoint(service); + context.setOutboundSAMLMessage(sloResp); + context.setRelayState(relayState); + + encoder.encode(context); + + return encoder.getRedirectURL(); + + } catch (MessageEncodingException e) { + Logger.error("Message Encoding exception", e); + throw new MOAIDException("pvp2.01", null, e); + + } + } + + public static 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); + + } + } + + + public static LogoutRequest buildSLORequestMessage(SLOInformationImpl sloInfo) throws ConfigurationException, MOAIDException { LogoutRequest sloReq = SAML2Utils.createSAMLObject(LogoutRequest.class); + SecureRandomIdentifierGenerator gen; + try { + gen = new SecureRandomIdentifierGenerator(); + sloReq.setID(gen.generateIdentifier()); + + } catch (NoSuchAlgorithmException e) { + Logger.error("Internal server error", e); + throw new AuthenticationException("pvp2.13", new Object[]{}); + + } + + Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); issuer.setFormat(NameID.ENTITY); @@ -76,14 +230,9 @@ public class SingleLogOutBuilder { return sloReq; } - public static LogoutResponse buildSLOErrorResponse(SingleLogoutService sloService, PVPTargetConfiguration spRequest) throws ConfigurationException { - LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class); - Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); - issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); - issuer.setFormat(NameID.ENTITY); - sloResp.setIssuer(issuer); - sloResp.setIssueInstant(new DateTime()); - sloResp.setDestination(sloService.getLocation()); + public static LogoutResponse buildSLOErrorResponse(SingleLogoutService sloService, PVPTargetConfiguration spRequest) throws ConfigurationException, MOAIDException { + LogoutResponse sloResp = buildBasicResponse(sloService, spRequest); + Status status = SAML2Utils.createSAMLObject(Status.class); StatusCode statusCode = SAML2Utils.createSAMLObject(StatusCode.class); StatusMessage statusMessage = SAML2Utils.createSAMLObject(StatusMessage.class); @@ -95,14 +244,8 @@ public class SingleLogOutBuilder { return sloResp; } - public static LogoutResponse buildSLOResponseMessage(SingleLogoutService sloService, PVPTargetConfiguration spRequest, List<String> failedOAs) throws ConfigurationException { - LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class); - Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); - issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); - issuer.setFormat(NameID.ENTITY); - sloResp.setIssuer(issuer); - sloResp.setIssueInstant(new DateTime()); - sloResp.setDestination(sloService.getLocation()); + public static LogoutResponse buildSLOResponseMessage(SingleLogoutService sloService, PVPTargetConfiguration spRequest, List<String> failedOAs) throws MOAIDException { + LogoutResponse sloResp = buildBasicResponse(sloService, spRequest); Status status; if (failedOAs == null || failedOAs.size() == 0) { @@ -123,6 +266,37 @@ public class SingleLogOutBuilder { } + private static LogoutResponse buildBasicResponse(SingleLogoutService sloService, PVPTargetConfiguration spRequest) throws ConfigurationException, MOAIDException { + LogoutResponse sloResp = SAML2Utils.createSAMLObject(LogoutResponse.class); + Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); + issuer.setValue(PVPConfiguration.getInstance().getIDPPublicPath()); + issuer.setFormat(NameID.ENTITY); + sloResp.setIssuer(issuer); + sloResp.setIssueInstant(new DateTime()); + sloResp.setDestination(sloService.getLocation()); + + SecureRandomIdentifierGenerator gen; + try { + gen = new SecureRandomIdentifierGenerator(); + sloResp.setID(gen.generateIdentifier()); + + } catch (NoSuchAlgorithmException e) { + Logger.error("Internal server error", e); + throw new AuthenticationException("pvp2.13", new Object[]{}); + + } + + if (spRequest.getRequest() instanceof MOARequest && + ((MOARequest)spRequest.getRequest()).getSamlRequest() instanceof LogoutRequest) { + LogoutRequest sloReq = (LogoutRequest) ((MOARequest)spRequest.getRequest()).getSamlRequest(); + sloResp.setInResponseTo(sloReq.getID()); + + } + + return sloResp; + + } + public static SingleLogoutService getRequestSLODescriptor(String entityID) throws NOSLOServiceDescriptorException { try { EntityDescriptor entity = MOAMetadataProvider.getInstance().getEntityDescriptor(entityID); @@ -140,19 +314,19 @@ public class SingleLogOutBuilder { ) sloService = el; - else if (el.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI) - && ( - (sloService != null - && !sloService.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI) - && !sloService.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) - || sloService == null) - ) - sloService = el; +// else if (el.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI) +// && ( +// (sloService != null +// && !sloService.getBinding().equals(SAMLConstants.SAML2_SOAP11_BINDING_URI) +// && !sloService.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) +// || sloService == null) +// ) +// sloService = el; } if (sloService == null) { - Logger.error("Found no SLO ServiceDescriptor in Metadata"); - throw new NOSLOServiceDescriptorException("NO SLO ServiceDescriptor", null); + Logger.error("Found no valid SLO ServiceDescriptor in Metadata"); + throw new NOSLOServiceDescriptorException("NO valid SLO ServiceDescriptor", null); } return sloService; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/messages/MOAResponse.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/messages/MOAResponse.java index 870273cf3..f2512b122 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/messages/MOAResponse.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/messages/MOAResponse.java @@ -23,7 +23,7 @@ package at.gv.egovernment.moa.id.protocols.pvp2x.messages; import org.opensaml.Configuration; -import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.xml.io.Unmarshaller; import org.opensaml.xml.io.UnmarshallerFactory; import org.opensaml.xml.io.UnmarshallingException; @@ -35,16 +35,16 @@ public class MOAResponse extends InboundMessage { private static final long serialVersionUID = -1133012928130138501L; - public MOAResponse(Response response) { + public MOAResponse(StatusResponseType response) { setSAMLMessage(response.getDOM()); } - public Response getResponse() { + public StatusResponseType getResponse() { UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory(); Unmarshaller unmashaller = unmarshallerFactory.getUnmarshaller(getInboundMessage()); try { - return (Response) unmashaller.unmarshall(getInboundMessage()); + return (StatusResponseType) unmashaller.unmarshall(getInboundMessage()); } catch (UnmarshallingException e) { Logger.warn("AuthnResponse Unmarshaller error", e); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java index 61b481447..ee0088576 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java @@ -28,6 +28,7 @@ import org.opensaml.saml2.core.Assertion; import org.opensaml.saml2.core.AuthnContextClassRef; import org.opensaml.saml2.core.AuthnStatement; import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.saml2.core.Subject; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AssertionAttributeExtractorExeption; @@ -38,15 +39,16 @@ public class AssertionAttributeExtractor { private Assertion assertion = null; - public AssertionAttributeExtractor(Response samlResponse) throws AssertionAttributeExtractorExeption { - if (samlResponse != null) { - if (samlResponse.getAssertions().size() == 0) + public AssertionAttributeExtractor(StatusResponseType samlResponse) throws AssertionAttributeExtractorExeption { + if (samlResponse != null && samlResponse instanceof Response) { + List<Assertion> assertions = ((Response) samlResponse).getAssertions(); + if (assertions.size() == 0) throw new AssertionAttributeExtractorExeption("Assertion"); - else if (samlResponse.getAssertions().size() > 1) + else if (assertions.size() > 1) Logger.warn("Found more then ONE PVP2.1 assertions. Only the First is used."); - assertion = samlResponse.getAssertions().get(0); + assertion = assertions.get(0); } else throw new AssertionAttributeExtractorExeption(); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java index 6388042d9..3be5df917 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java @@ -32,6 +32,7 @@ import org.opensaml.saml2.core.EncryptedAssertion; import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.Response; import org.opensaml.saml2.core.StatusCode; +import org.opensaml.saml2.core.StatusResponseType; import org.opensaml.saml2.encryption.Decrypter; import org.opensaml.saml2.encryption.EncryptedElementTypeEncryptedKeyResolver; import org.opensaml.saml2.metadata.IDPSSODescriptor; @@ -76,7 +77,7 @@ public class SAMLVerificationEngine { } - public void verifyResponse(Response samlObj, SignatureTrustEngine sigTrustEngine ) throws org.opensaml.xml.security.SecurityException, Exception { + public void verifyResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine ) throws org.opensaml.xml.security.SecurityException, Exception { SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); try { profileValidator.validate(samlObj.getSignature()); |