summaryrefslogtreecommitdiff
path: root/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java
diff options
context:
space:
mode:
Diffstat (limited to 'eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java')
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/binding/RedirectBinding.java418
1 files changed, 192 insertions, 226 deletions
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 ca9b3d98..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
@@ -1,239 +1,205 @@
-/*******************************************************************************
- * Copyright 2017 Graz University of Technology
- * EAAF-Core Components has been developed in a cooperation between EGIZ,
- * A-SIT Plus, A-SIT, and Graz University of Technology.
+/*
+ * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a
+ * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology.
*
- * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
- * the European Commission - subsequent versions of the EUPL (the "Licence");
- * You may not use this work except in compliance with the Licence.
- * You may obtain a copy of the Licence at:
+ * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European
+ * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in
+ * compliance with the Licence. You may obtain a copy of the Licence at:
* https://joinup.ec.europa.eu/news/understanding-eupl-v12
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the Licence is distributed on an "AS IS" basis,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the Licence for the specific language governing permissions and
- * limitations under the Licence.
- *
- * This product combines work with different licenses. See the "NOTICE" text
- * file for details on the various modules and licenses.
- * The "NOTICE" text file is part of the distribution. Any derivative works
- * that you distribute must include a readable copy of the "NOTICE" text file.
- *******************************************************************************/
-/*******************************************************************************
- *******************************************************************************/
-/*******************************************************************************
- *******************************************************************************/
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence
+ * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the Licence for the specific language governing permissions and limitations under
+ * the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text file for details on the
+ * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative
+ * works that you distribute must include a readable copy of the "NOTICE" text file.
+*/
+
package at.gv.egiz.eaaf.modules.pvp2.impl.binding;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-
-import org.apache.commons.lang3.StringUtils;
-import org.opensaml.common.SAMLObject;
-import org.opensaml.common.binding.BasicSAMLMessageContext;
-import org.opensaml.common.binding.decoding.URIComparator;
-import org.opensaml.common.xml.SAMLConstants;
-import org.opensaml.saml2.binding.decoding.HTTPRedirectDeflateDecoder;
-import org.opensaml.saml2.binding.encoding.HTTPRedirectDeflateEncoder;
-import org.opensaml.saml2.binding.security.SAML2HTTPRedirectDeflateSignatureRule;
-import org.opensaml.saml2.core.RequestAbstractType;
-import org.opensaml.saml2.core.StatusResponseType;
-import org.opensaml.saml2.metadata.IDPSSODescriptor;
-import org.opensaml.saml2.metadata.SPSSODescriptor;
-import org.opensaml.saml2.metadata.SingleSignOnService;
-import org.opensaml.saml2.metadata.impl.SingleSignOnServiceBuilder;
-import org.opensaml.saml2.metadata.provider.MetadataProvider;
-import org.opensaml.ws.message.decoder.MessageDecodingException;
-import org.opensaml.ws.message.encoder.MessageEncodingException;
-import org.opensaml.ws.security.SecurityPolicyResolver;
-import org.opensaml.ws.security.provider.BasicSecurityPolicy;
-import org.opensaml.ws.security.provider.StaticSecurityPolicyResolver;
-import org.opensaml.ws.transport.http.HttpServletRequestAdapter;
-import org.opensaml.ws.transport.http.HttpServletResponseAdapter;
-import org.opensaml.xml.parse.BasicParserPool;
-import org.opensaml.xml.security.SecurityException;
-import org.opensaml.xml.security.credential.Credential;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
+import javax.xml.namespace.QName;
import at.gv.egiz.eaaf.core.api.IRequest;
-import at.gv.egiz.eaaf.modules.pvp2.PVPConstants;
+import at.gv.egiz.eaaf.modules.pvp2.PvpConstants;
import at.gv.egiz.eaaf.modules.pvp2.api.binding.IDecoder;
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.IRefreshableMetadataProvider;
-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.initialize.EAAFDefaultSAML2Bootstrap;
-import at.gv.egiz.eaaf.modules.pvp2.impl.validation.TrustEngineFactory;
-import at.gv.egiz.eaaf.modules.pvp2.impl.verification.PVPAuthRequestSignedRole;
-
-@Service("PVPRedirectBinding")
-public class RedirectBinding implements IDecoder, IEncoder {
-
- private static final Logger log = LoggerFactory.getLogger(RedirectBinding.class);
-
- public void encodeRequest(HttpServletRequest req, HttpServletResponse resp,
- RequestAbstractType request, String targetLocation, String relayState, Credential credentials, IRequest pendingReq)
- throws MessageEncodingException, SecurityException {
-
- //load default PVP security configurations
- EAAFDefaultSAML2Bootstrap.initializeDefaultPVPConfiguration();
-
- log.debug("create SAML RedirectBinding response");
-
- HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder();
- HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(
- resp, true);
- BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
- SingleSignOnService service = new SingleSignOnServiceBuilder()
- .buildObject();
- service.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
- service.setLocation(targetLocation);
- context.setOutboundSAMLMessageSigningCredential(credentials);
- context.setPeerEntityEndpoint(service);
- context.setOutboundSAMLMessage(request);
- context.setOutboundMessageTransport(responseAdapter);
- context.setRelayState(relayState);
-
- encoder.encode(context);
- }
-
- public void encodeRespone(HttpServletRequest req, HttpServletResponse resp,
- StatusResponseType response, String targetLocation, String relayState,
- Credential credentials, IRequest pendingReq) throws MessageEncodingException, SecurityException {
-
- //load default PVP security configurations
- EAAFDefaultSAML2Bootstrap.initializeDefaultPVPConfiguration();
-
- log.debug("create SAML RedirectBinding response");
-
- HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder();
- HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter(
- resp, true);
- BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject> context = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
- SingleSignOnService service = new SingleSignOnServiceBuilder()
- .buildObject();
- service.setBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
- service.setLocation(targetLocation);
- context.setOutboundSAMLMessageSigningCredential(credentials);
- context.setPeerEntityEndpoint(service);
- context.setOutboundSAMLMessage(response);
- context.setOutboundMessageTransport(responseAdapter);
- context.setRelayState(relayState);
-
- encoder.encode(context);
-
- }
-
- public InboundMessageInterface decode(HttpServletRequest req,
- HttpServletResponse resp, MetadataProvider metadataProvider, boolean isSPEndPoint, URIComparator comparator) throws MessageDecodingException,
- SecurityException {
-
- HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder(
- new BasicParserPool());
-
- BasicSAMLMessageContext<SAMLObject, ?, ?> messageContext = new BasicSAMLMessageContext<SAMLObject, SAMLObject, SAMLObject>();
- 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);
-
- SAML2HTTPRedirectDeflateSignatureRule signatureRule = new SAML2HTTPRedirectDeflateSignatureRule(
- TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider));
- PVPAuthRequestSignedRole signedRole = new PVPAuthRequestSignedRole();
- BasicSecurityPolicy policy = new BasicSecurityPolicy();
- policy.getPolicyRules().add(signedRole);
- policy.getPolicyRules().add(signatureRule);
- 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);
-
- try {
- decode.decode(messageContext);
-
- //check signature
- signatureRule.evaluate(messageContext);
-
- } catch (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) {
- RequestAbstractType inboundMessage = (RequestAbstractType) messageContext
- .getInboundMessage();
- msg = new PVPSProfileRequest(inboundMessage, getSAML2BindingName());
-
-
- } else if (messageContext.getInboundMessage() instanceof StatusResponseType){
- 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;
- }
-
- public boolean handleDecode(String action, HttpServletRequest req) {
- return ((action.equals(PVPConstants.REDIRECT) || action.equals(PVPConstants.SINGLELOGOUT))
- && req.getMethod().equals("GET"));
- }
-
- public String getSAML2BindingName() {
- return SAMLConstants.SAML2_REDIRECT_BINDING_URI;
- }
+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.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.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.messaging.context.SAMLBindingContext;
+import org.opensaml.saml.common.xml.SAMLConstants;
+import org.opensaml.saml.saml2.binding.encoding.impl.HTTPRedirectDeflateEncoder;
+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.net.URIComparator;
+
+public class RedirectBinding extends AbstractBinding implements IDecoder, IEncoder {
+
+ private static final Logger log = LoggerFactory.getLogger(RedirectBinding.class);
+
+ @Override
+ public void encodeRequest(final HttpServletRequest req, final HttpServletResponse resp,
+ final RequestAbstractType request, final String targetLocation, final String relayState,
+ final EaafX509Credential credentials, final IRequest pendingReq)
+ throws Pvp2Exception {
+
+ try {
+ log.debug("create SAML RedirectBinding response");
+ final HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder();
+ encoder.setHttpServletResponse(resp);
+
+ final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, request);
+
+ // set endpoint url
+ messageContext.addSubcontext(injectEndpointInfos(request, targetLocation));
+
+ // inject signing context
+ messageContext.addSubcontext(injectSigningInfos(credentials));
+
+ // set relayState of exists
+ SAMLBindingSupport.setRelayState(messageContext, relayState);
+
+ // encode message
+ encoder.initialize();
+ encoder.encode();
+
+ } catch (final Exception e) {
+ log.warn("Can not encode SAML2 Redirect-Binding request", e);
+ throw new SamlBindingException("internal.pvp.95",
+ new Object[] { PvpConstants.REDIRECT, "encoding", e.getMessage() },
+ e);
+
+ }
+
+ }
+
+ @Override
+ public void encodeResponse(final HttpServletRequest req, final HttpServletResponse resp,
+ final StatusResponseType response, final String targetLocation, final String relayState,
+ final EaafX509Credential credentials, final IRequest pendingReq)
+ throws Pvp2Exception {
+
+ try {
+ log.debug("create SAML RedirectBinding response");
+
+ final HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder();
+ encoder.setHttpServletResponse(resp);
+
+ final MessageContext<SAMLObject> messageContext = buildBasicMessageContext(encoder, response);
+
+ // set endpoint url
+ messageContext.addSubcontext(injectEndpointInfos(response, targetLocation));
+
+ // inject signing context
+ messageContext.addSubcontext(injectSigningInfos(credentials));
+
+ // set relayState of exists
+ SAMLBindingSupport.setRelayState(messageContext, relayState);
+
+ // encode message
+ encoder.initialize();
+ encoder.encode();
+
+ } catch (final Exception e) {
+ log.warn("Can not encode SAML2 Redirect-Binding request", e);
+ throw new SamlBindingException("internal.pvp.95",
+ new Object[] { PvpConstants.REDIRECT, "encoding", e.getMessage() },
+ e);
+
+ }
+
+ }
+
+ @Override
+ public InboundMessageInterface decode(final HttpServletRequest req,
+ final HttpServletResponse resp, final IPvp2MetadataProvider metadataProvider,
+ QName peerEntityRole, final URIComparator comparator)
+ throws Pvp2Exception {
+
+ 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()) {
+ log.info("SAML Redirect-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, peerEntityRole);
+ final PvpSamlMessageHandlerChain messageValidatorChain =
+ buildMessageValidationChain(req, metadataProvider);
+
+ log.trace("Message validation (Signature, ...) on binding-level starts ... ");
+ performMessageValidation(messageValidatorChain, messageContext);
+
+ log.trace("Message validation successful");
+ return performMessageDecodePostProcessing(messageContext, true);
+
+ }
+
+ @Override
+ public boolean handleDecode(final String action, final HttpServletRequest req) {
+ return (action.equals(PvpConstants.REDIRECT) || action.equals(PvpConstants.SINGLELOGOUT))
+ && req.getMethod().equals("GET");
+ }
+
+ @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;
+
+ }
}