From e7610325ee2f1d1f4e97e1e7a9b212e692836b5a Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 4 Feb 2020 17:37:34 +0100 Subject: first stable version that uses OpenSAML 3.x --- .../modules/pvp2/impl/binding/PostBinding.java | 147 ++++++++++----------- 1 file changed, 73 insertions(+), 74 deletions(-) (limited to 'eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java') diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java index 6f39392d..c679de20 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java @@ -21,6 +21,7 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.binding; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.xml.namespace.QName; import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfigurationFactory; @@ -36,16 +37,17 @@ import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPvpRequestException; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; import at.gv.egiz.eaaf.modules.pvp2.exception.SamlBindingException; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; -import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileResponse; import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.EaafHttpPostDecoder; import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.HttpPostEncoderWithOwnTemplate; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.EaafSamlProtocolMessageXmlSignatureSecurityHandler; +import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpSamlMessageHandlerChain; import org.opensaml.messaging.context.MessageContext; -import org.opensaml.messaging.decoder.MessageDecodingException; import org.opensaml.saml.common.SAMLObject; import org.opensaml.saml.common.binding.SAMLBindingSupport; +import org.opensaml.saml.common.binding.impl.CheckMessageVersionHandler; +import org.opensaml.saml.common.binding.security.impl.MessageLifetimeSecurityHandler; +import org.opensaml.saml.common.binding.security.impl.ReceivedEndpointSecurityHandler; import org.opensaml.saml.common.messaging.SAMLMessageSecuritySupport; import org.opensaml.saml.common.xml.SAMLConstants; import org.opensaml.saml.saml2.core.RequestAbstractType; @@ -53,7 +55,6 @@ import org.opensaml.saml.saml2.core.StatusResponseType; import org.springframework.beans.factory.annotation.Autowired; import lombok.extern.slf4j.Slf4j; -import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.net.URIComparator; @Slf4j @@ -78,35 +79,34 @@ public class PostBinding extends AbstractBinding implements IDecoder, IEncoder { guiConfigFactory.getSpSpecificSaml2PostConfiguration(pendingReq, "pvp_postbinding_template.html", authConfig.getConfigurationRootDirectory()); - final HttpPostEncoderWithOwnTemplate encoder - = new HttpPostEncoderWithOwnTemplate(guiConfig, guiBuilder); + final HttpPostEncoderWithOwnTemplate encoder = new HttpPostEncoderWithOwnTemplate(guiConfig, + guiBuilder); encoder.setHttpServletResponse(httpResp); - //inject message context + // inject message context final MessageContext messageContext = buildBasicMessageContext(encoder, request); - //inject signing context + // inject signing context messageContext.addSubcontext(injectSigningInfos(credentials)); - //set endpoint url + // set endpoint url messageContext.addSubcontext(injectEndpointInfos(request, targetLocation)); - - //set relayState of exists + // set relayState of exists SAMLBindingSupport.setRelayState(messageContext, relayState); - //sign SAML2 message + // sign SAML2 message SAMLMessageSecuritySupport.signMessage(messageContext); - //encode message + // encode message encoder.initialize(); encoder.encode(); } catch (final Exception e) { log.warn("Can not encode SAML2 Post-Binding request", e); throw new SamlBindingException("internal.pvp.95", - new Object[] {PvpConstants.POST, "encoding", e.getMessage()}, + new Object[] { PvpConstants.POST, "encoding", e.getMessage() }, e); } @@ -116,7 +116,7 @@ public class PostBinding extends AbstractBinding implements IDecoder, IEncoder { public void encodeResponse(final HttpServletRequest httpReq, final HttpServletResponse httpResp, final StatusResponseType response, final String targetLocation, final String relayState, final EaafX509Credential credentials, final IRequest pendingReq) - throws Pvp2Exception { + throws Pvp2Exception { try { log.debug("create SAML POSTBinding response"); @@ -130,99 +130,62 @@ public class PostBinding extends AbstractBinding implements IDecoder, IEncoder { encoder.setHttpServletResponse(httpResp); - //inject message context + // inject message context final MessageContext messageContext = buildBasicMessageContext(encoder, response); - //inject signing context + // inject signing context messageContext.addSubcontext(injectSigningInfos(credentials)); - //set endpoint url + // set endpoint url messageContext.addSubcontext(injectEndpointInfos(response, targetLocation)); - //set relayState of exists + // set relayState of exists SAMLBindingSupport.setRelayState(messageContext, relayState); - //sign SAML2 message + // sign SAML2 message SAMLMessageSecuritySupport.signMessage(messageContext); - //encode message + // encode message encoder.initialize(); encoder.encode(); } catch (final Exception e) { log.warn("Can not encode SAML2 Post-Binding response", e); throw new SamlBindingException("internal.pvp.95", - new Object[] {PvpConstants.POST, "encoding", e.getMessage()}, + new Object[] { PvpConstants.POST, "encoding", e.getMessage() }, e); } } - - - - @Override public InboundMessageInterface decode(final HttpServletRequest req, final HttpServletResponse resp, final IPvp2MetadataProvider metadataProvider, - final boolean isSpEndPoint, final URIComparator comparator) + QName peerEntityRole, final URIComparator comparator) throws Pvp2Exception { - //TODO: check, if we should re-implement HTTPPostDecoder to collect the last http parameter!!! - final EaafHttpPostDecoder decode = new EaafHttpPostDecoder(); - decode.setHttpServletRequest(req); - - //decode request - try { - decode.initialize(); - decode.decode(); - - } catch (MessageDecodingException | ComponentInitializationException e) { - throw new SamlBindingException("internal.pvp.95", - new Object[] {PvpConstants.POST, "decoding", e.getMessage()}, - e); - } - - final MessageContext messageContext = decode.getMessageContext(); + final EaafHttpPostDecoder decode = new EaafHttpPostDecoder(req); + final MessageContext messageContext = internalMessageDecode(decode, PvpConstants.POST); - if (SAMLBindingSupport.isSigningCapableBinding(messageContext)) { + // check if PVP2 AuthnRequest is signed + if (!SAMLBindingSupport.isMessageSigned(messageContext)) { log.info("SAML Post-Binding message contains no signature. Message will be rejected"); throw new InvalidPvpRequestException("internal.pvp.02", null); } - //inject informations into message context that are required for further processing - injectInboundMessageContexts(messageContext, metadataProvider); + // inject informations into message context that are required for further + // processing + injectInboundMessageContexts(messageContext, metadataProvider, peerEntityRole); + final PvpSamlMessageHandlerChain messageValidatorChain = + buildMessageValidationChain(req, comparator, metadataProvider); + log.trace("Message validation (Signature, ...) on binding-level starts ... "); + performMessageValidation(messageValidatorChain, messageContext); - //TODO: add sig validation!!! + log.trace("Message validation successful"); + return performMessageDecodePostProcessing(messageContext, true); - - - InboundMessage msg = null; - - if (messageContext.getMessage() instanceof RequestAbstractType) { - final RequestAbstractType inboundMessage = - (RequestAbstractType) messageContext.getMessage(); - msg = new PvpSProfileRequest(inboundMessage, getSaml2BindingName()); - msg.setEntityID(inboundMessage.getIssuer().getValue()); - - } else if (messageContext.getMessage() instanceof StatusResponseType) { - final StatusResponseType inboundMessage = - (StatusResponseType) messageContext.getMessage(); - msg = new PvpSProfileResponse(inboundMessage); - msg.setEntityID(inboundMessage.getIssuer().getValue()); - - } else { - // create empty container if request type is unknown - msg = new InboundMessage(); - - } - - msg.setVerified(false); - msg.setRelayState(SAMLBindingSupport.getRelayState(messageContext)); - - return msg; } @Override @@ -234,5 +197,41 @@ public class PostBinding extends AbstractBinding implements IDecoder, IEncoder { @Override public String getSaml2BindingName() { return SAMLConstants.SAML2_POST_BINDING_URI; + + } + + private PvpSamlMessageHandlerChain buildMessageValidationChain(HttpServletRequest req, + URIComparator comparator, IPvp2MetadataProvider metadataProvider) { + final PvpSamlMessageHandlerChain messageValidatorChain = new PvpSamlMessageHandlerChain(); + + final ReceivedEndpointSecurityHandler endpointSecurityHandler = new ReceivedEndpointSecurityHandler(); + endpointSecurityHandler.setHttpServletRequest(req); + endpointSecurityHandler.setURIComparator(comparator); + + messageValidatorChain.addHandler(new CheckMessageVersionHandler()); + messageValidatorChain.addHandler(endpointSecurityHandler); + messageValidatorChain.addHandler( + new EaafSamlProtocolMessageXmlSignatureSecurityHandler(metadataProvider)); + messageValidatorChain.addHandler(new MessageLifetimeSecurityHandler()); + + /* + * TODO: maybe we add it in a later version Because: - AuthnRequest replay + * should not be a problem on IDP side - Response replay will be not possible, + * because EAAF PVP implements countermeasure based on one-time tokens for each + * request + * + */ + // final MessageReplaySecurityHandler replaySecurityHandler = new + // MessageReplaySecurityHandler(); + // final StorageService replayCacheStorage = null; + // final ReplayCache replayCache = new ReplayCache(); + // replayCache.setId("Message replay cache"); + // replayCache.setStrict(true); + // replayCache.setStorage(replayCacheStorage); + // replaySecurityHandler.setReplayCache(replayCache ); + // messageValidatorChain.addHandler(replaySecurityHandler); + + return messageValidatorChain; + } } -- cgit v1.2.3