summaryrefslogtreecommitdiff
path: root/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding
diff options
context:
space:
mode:
authorThomas Lenz <thomas.lenz@egiz.gv.at>2020-02-04 17:37:34 +0100
committerThomas Lenz <thomas.lenz@egiz.gv.at>2020-02-04 17:37:34 +0100
commite7610325ee2f1d1f4e97e1e7a9b212e692836b5a (patch)
treeed7c0dba5fed47e80e68b4ab5a63846c5724a8e7 /eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding
parent41ea2fdf782cd64d7d29f73c2e83f9c255810818 (diff)
downloadEAAF-Components-e7610325ee2f1d1f4e97e1e7a9b212e692836b5a.tar.gz
EAAF-Components-e7610325ee2f1d1f4e97e1e7a9b212e692836b5a.tar.bz2
EAAF-Components-e7610325ee2f1d1f4e97e1e7a9b212e692836b5a.zip
first stable version that uses OpenSAML 3.x
Diffstat (limited to 'eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding')
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java127
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/PostBinding.java147
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java234
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java104
4 files changed, 287 insertions, 325 deletions
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java
index ae108c35..3543d85a 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/AbstractBinding.java
@@ -1,15 +1,29 @@
package at.gv.egiz.eaaf.modules.pvp2.impl.binding;
+import javax.xml.namespace.QName;
+
import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential;
+import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface;
import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception;
+import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2InternalErrorException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SamlBindingException;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SamlMessageValidationException;
import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException;
+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.utils.Saml2Utils;
import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory;
+import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PvpSamlMessageHandlerChain;
import org.opensaml.core.config.ConfigurationService;
import org.opensaml.messaging.context.BaseContext;
import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.decoder.MessageDecodingException;
+import org.opensaml.messaging.decoder.servlet.HttpServletRequestMessageDecoder;
+import org.opensaml.messaging.handler.MessageHandlerException;
import org.opensaml.saml.common.SAMLObject;
import org.opensaml.saml.common.SignableSAMLObject;
import org.opensaml.saml.common.binding.SAMLBindingSupport;
@@ -19,6 +33,8 @@ import org.opensaml.saml.common.messaging.context.SAMLMessageInfoContext;
import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
import org.opensaml.saml.common.messaging.context.SAMLProtocolContext;
import org.opensaml.saml.common.xml.SAMLConstants;
+import org.opensaml.saml.saml2.core.RequestAbstractType;
+import org.opensaml.saml.saml2.core.StatusResponseType;
import org.opensaml.saml.saml2.metadata.SingleSignOnService;
import org.opensaml.saml.saml2.metadata.impl.SingleSignOnServiceBuilder;
import org.opensaml.xmlsec.SignatureSigningParameters;
@@ -28,21 +44,62 @@ import org.opensaml.xmlsec.context.SecurityParametersContext;
import org.opensaml.xmlsec.signature.support.SignatureConstants;
import org.springframework.beans.factory.annotation.Autowired;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicates;
+import com.google.common.base.Throwables;
+import com.google.common.collect.FluentIterable;
+import lombok.extern.slf4j.Slf4j;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+
/**
* Abstract Binding implements common code for SAML2 binding implementations.
*
* @author tlenz
*
*/
+@Slf4j
public abstract class AbstractBinding {
- @Autowired protected IConfiguration basicConfig;
+ @Autowired
+ protected IConfiguration basicConfig;
public abstract String getSaml2BindingName();
+ protected MessageContext<SAMLObject> internalMessageDecode(
+ HttpServletRequestMessageDecoder<SAMLObject> decoder,
+ String binding) throws Pvp2Exception {
+ try {
+ decoder.initialize();
+ decoder.decode();
+
+ } catch (final ComponentInitializationException e) {
+ log.warn("Internal initialization error. Reason: {}", e.getMessage());
+ throw new Pvp2InternalErrorException(e);
+
+ } catch (final MessageDecodingException e) {
+ final Optional<Throwable> pvpException = FluentIterable.from(
+ Throwables.getCausalChain(e)).filter(
+ Predicates.instanceOf(Pvp2Exception.class)).first();
+
+ if (pvpException.isPresent()) {
+ throw (Pvp2Exception) pvpException.get();
+
+ } else {
+ throw new SamlBindingException("internal.pvp.95",
+ new Object[] { binding, "decoding", e.getMessage() },
+ e);
+
+ }
+
+ }
+
+ return decoder.getMessageContext();
+
+ }
+
protected MessageContext<SAMLObject> buildBasicMessageContext(
SAMLMessageEncoder encoder, SignableSAMLObject response) {
- final MessageContext<SAMLObject> messageContext = new MessageContext<SAMLObject>();
+ final MessageContext<SAMLObject> messageContext = new MessageContext<>();
messageContext.setMessage(response);
encoder.setMessageContext(messageContext);
return messageContext;
@@ -63,7 +120,7 @@ public abstract class AbstractBinding {
signingParams.setSignatureReferenceDigestMethod(
Saml2Utils.getDigestAlgorithm(signingParams.getSignatureAlgorithm()));
- signingParams.setKeyInfoGenerator(Saml2Utils.getKeyInfoGenerator(credentials, false));
+ signingParams.setKeyInfoGenerator(Saml2Utils.getKeyInfoGenerator(credentials, true));
return securityParamContext;
@@ -83,16 +140,16 @@ public abstract class AbstractBinding {
}
protected void injectInboundMessageContexts(MessageContext<SAMLObject> messageContext,
- IPvp2MetadataProvider metadataProvider) {
- messageContext.addSubcontext(new SAMLPeerEntityContext());
+ IPvp2MetadataProvider metadataProvider, QName peerEntityRole) throws Pvp2InternalErrorException {
+ final SAMLPeerEntityContext peerEntityContext = new SAMLPeerEntityContext();
+ peerEntityContext.setRole(peerEntityRole);
+ messageContext.addSubcontext(peerEntityContext);
messageContext.addSubcontext(new SAMLMessageInfoContext());
-
final SAMLProtocolContext protocolContext = new SAMLProtocolContext();
protocolContext.setProtocol(SAMLConstants.SAML20P_NS);
messageContext.addSubcontext(protocolContext);
-
final SecurityParametersContext securityParameterContext = new SecurityParametersContext();
final SignatureValidationParameters sigValParameters = new SignatureValidationParameters();
securityParameterContext.setSignatureValidationParameters(sigValParameters);
@@ -100,9 +157,63 @@ public abstract class AbstractBinding {
sigValParameters.setBlacklistedAlgorithms(
ConfigurationService.get(SignatureValidationConfiguration.class)
- .getBlacklistedAlgorithms());
+ .getBlacklistedAlgorithms());
sigValParameters.setSignatureTrustEngine(
TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider));
}
+
+ protected void performMessageValidation(PvpSamlMessageHandlerChain messageValidatorChain,
+ MessageContext<SAMLObject> messageContext) throws Pvp2Exception {
+ try {
+ messageValidatorChain.initialize();
+ messageValidatorChain.invoke(messageContext);
+
+ } catch (final ComponentInitializationException e) {
+ log.warn("Internal initialization error. Reason: {}", e.getMessage());
+ throw new Pvp2InternalErrorException(e);
+
+ } catch (final MessageHandlerException e) {
+ log.info("SAML message validation error. Reason: {}", e.getMessage());
+ final Optional<Throwable> pvpException = FluentIterable.from(
+ Throwables.getCausalChain(e)).filter(
+ Predicates.instanceOf(Pvp2Exception.class)).first();
+
+ if (pvpException.isPresent()) {
+ throw (Pvp2Exception) pvpException.get();
+
+ } else {
+ throw new SamlMessageValidationException("internal.pvp.11",
+ new Object[] { e.getMessage() }, e);
+
+ }
+ }
+ }
+
+ protected InboundMessageInterface performMessageDecodePostProcessing(
+ MessageContext<SAMLObject> messageContext, boolean isVerified) {
+ 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(isVerified);
+ msg.setRelayState(SAMLBindingSupport.getRelayState(messageContext));
+
+ return msg;
+ }
}
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<SAMLObject> 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<SAMLObject> 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<SAMLObject> messageContext = decode.getMessageContext();
+ final EaafHttpPostDecoder decode = new EaafHttpPostDecoder(req);
+ final MessageContext<SAMLObject> 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;
+
}
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java
index 5f74053d..f62f8a11 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.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.modules.pvp2.PvpConstants;
@@ -32,15 +33,11 @@ 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.EaafHttpRedirectDeflateDecoder;
+import at.gv.egiz.eaaf.modules.pvp2.impl.verification.EaafSaml2HttpRedirectDeflateSignatureSecurityHandler;
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.messaging.handler.MessageHandlerException;
import org.opensaml.saml.common.SAMLObject;
import org.opensaml.saml.common.binding.SAMLBindingSupport;
import org.opensaml.saml.common.binding.impl.CheckMessageVersionHandler;
@@ -48,13 +45,11 @@ import org.opensaml.saml.common.binding.security.impl.MessageLifetimeSecurityHan
import org.opensaml.saml.common.messaging.context.SAMLBindingContext;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.binding.encoding.impl.HTTPRedirectDeflateEncoder;
-import org.opensaml.saml.saml2.binding.security.impl.SAML2HTTPRedirectDeflateSignatureSecurityHandler;
import org.opensaml.saml.saml2.core.RequestAbstractType;
import org.opensaml.saml.saml2.core.StatusResponseType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
import net.shibboleth.utilities.java.support.net.URIComparator;
public class RedirectBinding extends AbstractBinding implements IDecoder, IEncoder {
@@ -137,26 +132,11 @@ public class RedirectBinding extends AbstractBinding implements IDecoder, IEncod
@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: implement one flat decoder to get SAML2 request/response parametes as
- // same as in SAML2HTTPRedirectDeflateSignatureSecurityHandler
- final EaafHttpRedirectDeflateDecoder decode = new EaafHttpRedirectDeflateDecoder();
- decode.setHttpServletRequest(req);
-
- // decode request
- try {
- decode.initialize();
- decode.decode();
-
- } catch (MessageDecodingException | ComponentInitializationException e) {
- throw new SamlBindingException("internal.pvp.95",
- new Object[] { PvpConstants.REDIRECT, "decoding", e.getMessage() },
- e);
- }
-
- final MessageContext<SAMLObject> messageContext = decode.getMessageContext();
+ final EaafHttpRedirectDeflateDecoder decode = new EaafHttpRedirectDeflateDecoder(req);
+ final MessageContext<SAMLObject> messageContext = internalMessageDecode(decode, PvpConstants.REDIRECT);
final SAMLBindingContext bindingContext = messageContext.getSubcontext(SAMLBindingContext.class, true);
if (!bindingContext.hasBindingSignature()) {
@@ -165,171 +145,18 @@ public class RedirectBinding extends AbstractBinding implements IDecoder, IEncod
}
- //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, metadataProvider);
- log.trace("Signature validation on binding-level starts ... ");
- final PvpSamlMessageHandlerChain messageValidatorChain = new PvpSamlMessageHandlerChain();
- final SAML2HTTPRedirectDeflateSignatureSecurityHandler redirectBindingSignaturHandler =
- new SAML2HTTPRedirectDeflateSignatureSecurityHandler();
- redirectBindingSignaturHandler.setHttpServletRequest(req);
-
- messageValidatorChain.addHandler(new CheckMessageVersionHandler());
- messageValidatorChain.addHandler(redirectBindingSignaturHandler);
- 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);
+ log.trace("Message validation (Signature, ...) on binding-level starts ... ");
+ performMessageValidation(messageValidatorChain, messageContext);
+ log.trace("Message validation successful");
+ return performMessageDecodePostProcessing(messageContext, true);
- try {
- messageValidatorChain.initialize();
- messageValidatorChain.invoke(messageContext);
-
- } catch (final ComponentInitializationException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
-
- } catch (final MessageHandlerException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
-
- 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;
-
-// final BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext =
-// new BasicSAMLMessageContext<>();
-// messageContext.setInboundMessageTransport(new HttpServletRequestAdapter(req));
-//
-// // set metadata descriptor type
-// if (isSpEndPoint) {
-// messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
-// decode.setURIComparator(comparator);
-//
-// } else {
-// messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
-// decode.setURIComparator(comparator);
-// }
-//
-// messageContext.setMetadataProvider(metadataProvider);
-//
-// final SAML2HTTPRedirectDeflateSignatureRule signatureRule =
-// new SAML2HTTPRedirectDeflateSignatureRule(
-// TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider));
-// final PvpAuthRequestSignedRole signedRole = new PvpAuthRequestSignedRole();
-// final BasicSecurityPolicy policy = new BasicSecurityPolicy();
-// policy.getPolicyRules().add(signedRole);
-// policy.getPolicyRules().add(signatureRule);
-// final SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver(policy);
-// messageContext.setSecurityPolicyResolver(resolver);
-//
-// // set metadata descriptor type
-// if (isSpEndPoint) {
-// messageContext.setPeerEntityRole(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
-// } else {
-// messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
-// }
-//
-// SAML2AuthnRequestsSignedSecurityHandler
-//
-// try {
-// decode.decode(messageContext);
-//
-// // check signature
-// signatureRule.evaluate(messageContext);
-//
-// } catch (final SecurityException e) {
-// if (StringUtils.isEmpty(messageContext.getInboundMessageIssuer())) {
-// throw e;
-//
-// }
-//
-// if (metadataProvider instanceof IRefreshableMetadataProvider) {
-// log.debug("PVP2X message validation FAILED. Reload metadata for entityID: "
-// + messageContext.getInboundMessageIssuer());
-// if (!((IRefreshableMetadataProvider) metadataProvider)
-// .refreshMetadataProvider(messageContext.getInboundMessageIssuer())) {
-// throw e;
-// } else {
-// log.trace("PVP2X metadata reload finished. Check validate message again.");
-// decode.decode(messageContext);
-//
-// // check signature
-// signatureRule.evaluate(messageContext);
-//
-// }
-// log.trace("Second PVP2X message validation finished");
-//
-// } else {
-// throw e;
-//
-// }
-// }
-//
-// InboundMessage msg = null;
-// if (messageContext.getInboundMessage() instanceof RequestAbstractType) {
-// final RequestAbstractType inboundMessage =
-// (RequestAbstractType) messageContext.getInboundMessage();
-// msg = new PvpSProfileRequest(inboundMessage, getSaml2BindingName());
-//
-// } else if (messageContext.getInboundMessage() instanceof StatusResponseType) {
-// final StatusResponseType inboundMessage =
-// (StatusResponseType) messageContext.getInboundMessage();
-// msg = new PvpSProfileResponse(inboundMessage);
-//
-// } else {
-// // create empty container if request type is unknown
-// msg = new InboundMessage();
-// }
-//
-// if (messageContext.getPeerEntityMetadata() != null) {
-// msg.setEntityID(messageContext.getPeerEntityMetadata().getEntityID());
-// } else {
-// log.info(
-// "No Metadata found for OA with EntityID " + messageContext.getInboundMessageIssuer());
-// }
-//
-// msg.setVerified(true);
-// msg.setRelayState(messageContext.getRelayState());
-//
-// return msg;
}
@Override
@@ -341,5 +168,38 @@ public class RedirectBinding extends AbstractBinding implements IDecoder, IEncod
@Override
public String getSaml2BindingName() {
return SAMLConstants.SAML2_REDIRECT_BINDING_URI;
+
+ }
+
+ private PvpSamlMessageHandlerChain buildMessageValidationChain(HttpServletRequest req,
+ IPvp2MetadataProvider metadataProvider) {
+ final PvpSamlMessageHandlerChain messageValidatorChain = new PvpSamlMessageHandlerChain();
+ final EaafSaml2HttpRedirectDeflateSignatureSecurityHandler redirectBindingSignaturHandler =
+ new EaafSaml2HttpRedirectDeflateSignatureSecurityHandler(metadataProvider);
+ redirectBindingSignaturHandler.setHttpServletRequest(req);
+
+ messageValidatorChain.addHandler(new CheckMessageVersionHandler());
+ messageValidatorChain.addHandler(redirectBindingSignaturHandler);
+ 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;
+
}
}
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java
index e0df2d2a..49e93f0a 100644
--- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.java
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/SoapBinding.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.modules.pvp2.PvpConstants;
@@ -29,27 +30,29 @@ import at.gv.egiz.eaaf.modules.pvp2.api.binding.IEncoder;
import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential;
import at.gv.egiz.eaaf.modules.pvp2.api.message.InboundMessageInterface;
import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider;
-import at.gv.egiz.eaaf.modules.pvp2.exception.AttributQueryException;
+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.Pvp2InternalErrorException;
import at.gv.egiz.eaaf.modules.pvp2.exception.SamlBindingException;
+import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;
import at.gv.egiz.eaaf.modules.pvp2.impl.verification.EaafMessageContextInitializationHandler;
+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.impl.SAMLProtocolAndRoleHandler;
import org.opensaml.saml.common.binding.impl.SAMLSOAPDecoderBodyHandler;
import org.opensaml.saml.common.binding.security.impl.MessageLifetimeSecurityHandler;
-import org.opensaml.saml.common.binding.security.impl.SAMLProtocolMessageXMLSignatureSecurityHandler;
import org.opensaml.saml.common.messaging.SAMLMessageSecuritySupport;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.binding.decoding.impl.HTTPSOAP11Decoder;
import org.opensaml.saml.saml2.binding.encoding.impl.HTTPSOAP11Encoder;
import org.opensaml.saml.saml2.core.RequestAbstractType;
import org.opensaml.saml.saml2.core.StatusResponseType;
+import org.opensaml.soap.messaging.context.SOAP11Context;
import lombok.extern.slf4j.Slf4j;
import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
@@ -61,72 +64,55 @@ public class SoapBinding extends AbstractBinding implements IDecoder, IEncoder {
@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 {
- try {
- final HTTPSOAP11Decoder soapDecoder = new HTTPSOAP11Decoder();
+ final HTTPSOAP11Decoder soapDecoder = new HTTPSOAP11Decoder();
+ soapDecoder.setHttpServletRequest(req);
+
+ injectMessageHandlerChain(soapDecoder, metadataProvider, peerEntityRole);
+
+ final MessageContext<SAMLObject> messageContext =
+ internalMessageDecode(soapDecoder, PvpConstants.SOAP);
+
+ // 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);
+
+ }
+
+ return performMessageDecodePostProcessing(messageContext, true);
+ }
+ private void injectMessageHandlerChain(HTTPSOAP11Decoder soapDecoder,
+ IPvp2MetadataProvider metadataProvider, QName peerEntityRole) throws Pvp2InternalErrorException {
+ try {
final PvpSamlMessageHandlerChain messageValidatorChain = new PvpSamlMessageHandlerChain();
- soapDecoder.setBodyHandler(messageValidatorChain);
+ messageValidatorChain.addHandler(new EaafMessageContextInitializationHandler(metadataProvider));
+ messageValidatorChain.addHandler(new SAMLSOAPDecoderBodyHandler());
- final SAMLProtocolMessageXMLSignatureSecurityHandler msgSignatureValidationHandler =
- new SAMLProtocolMessageXMLSignatureSecurityHandler();
+ final SAMLProtocolAndRoleHandler samlProtocolHandler = new SAMLProtocolAndRoleHandler();
+ samlProtocolHandler.setProtocol(SAMLConstants.SAML20P_NS);
+ samlProtocolHandler.setRole(peerEntityRole);
+ messageValidatorChain.addHandler(samlProtocolHandler);
- messageValidatorChain.addHandler(new EaafMessageContextInitializationHandler());
messageValidatorChain.addHandler(new CheckMessageVersionHandler());
- messageValidatorChain.addHandler(new SAMLProtocolAndRoleHandler());
- messageValidatorChain.addHandler(msgSignatureValidationHandler);
+ messageValidatorChain.addHandler(
+ new EaafSamlProtocolMessageXmlSignatureSecurityHandler(metadataProvider));
messageValidatorChain.addHandler(new MessageLifetimeSecurityHandler());
- messageValidatorChain.addHandler(new SAMLSOAPDecoderBodyHandler());
- // decode message
- soapDecoder.initialize();
- soapDecoder.decode();
+ messageValidatorChain.initialize();
- final MessageContext<SAMLObject> messageContext = soapDecoder.getMessageContext();
- messageContext.getMessage();
+ soapDecoder.setBodyHandler(messageValidatorChain);
+
+ } catch (final ComponentInitializationException e) {
+ log.warn("Internal initialization error. Reason: {}", e.getMessage());
+ throw new Pvp2InternalErrorException(e);
- } catch (MessageDecodingException | ComponentInitializationException e) {
- throw new SamlBindingException("internal.pvp.95",
- new Object[] { PvpConstants.POST, "decoding", e.getMessage() },
- e);
}
-// final Envelope inboundMessage = (Envelope) messageContext.getMessage();
-//
-// if (inboundMessage.getBody() != null) {
-// final List<XMLObject> xmlElemList = inboundMessage.getBody().getUnknownXMLObjects();
-//
-// if (!xmlElemList.isEmpty()) {
-// final SignableXMLObject attrReq = (SignableXMLObject) xmlElemList.get(0);
-// final PvpSProfileRequest request = new PvpSProfileRequest(attrReq, getSaml2BindingName());
-//
-// if (messageContext.getPeerEntityMetadata() != null) {
-// request.setEntityID(messageContext.getPeerEntityMetadata().getEntityID());
-//
-// } else if (attrReq instanceof RequestAbstractType) {
-// final RequestAbstractType attributeRequest = (RequestAbstractType) attrReq;
-// try {
-// if (StringUtils.isNotEmpty(attributeRequest.getIssuer().getValue())
-// && metadataProvider.getRole(attributeRequest.getIssuer().getValue(),
-// SPSSODescriptor.DEFAULT_ELEMENT_NAME) != null) {
-// request.setEntityID(attributeRequest.getIssuer().getValue());
-// }
-//
-// } catch (final Exception e) {
-// log.warn("No Metadata found with EntityID " + attributeRequest.getIssuer().getValue());
-// }
-// }
-//
-// request.setVerified(false);
-// return request;
-//
-// }
-// }
-
- log.error("Receive empty PVP 2.1 attributequery request.");
- throw new AttributQueryException("Receive empty PVP 2.1 attributequery request.", null);
+
}
@Override
@@ -157,6 +143,11 @@ public class SoapBinding extends AbstractBinding implements IDecoder, IEncoder {
// inject message context
final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, response);
+ //inject SOAP enveloped
+ final SOAP11Context soap11Context = new SOAP11Context();
+ soap11Context.setEnvelope(Saml2Utils.buildSoap11Envelope(response));
+ messageContext.addSubcontext(soap11Context);
+
// inject signing context
messageContext.addSubcontext(injectSigningInfos(credentials));
@@ -172,6 +163,7 @@ public class SoapBinding extends AbstractBinding implements IDecoder, IEncoder {
// encode message
encoder.initialize();
encoder.encode();
+
} catch (final Exception e) {
log.warn("Can not encode SAML2 SOAP-Binding response", e);
throw new SamlBindingException("internal.pvp.95",