package at.gv.egiz.eaaf.modules.pvp2.impl.binding; import javax.xml.namespace.QName; 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.SignableSAMLObject; import org.opensaml.saml.common.binding.SAMLBindingSupport; import org.opensaml.saml.common.binding.encoding.SAMLMessageEncoder; import org.opensaml.saml.common.messaging.context.SAMLEndpointContext; 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; import org.opensaml.xmlsec.SignatureValidationConfiguration; import org.opensaml.xmlsec.SignatureValidationParameters; 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 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 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; public abstract String getSaml2BindingName(); protected MessageContext internalMessageDecode( HttpServletRequestMessageDecoder 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 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 buildBasicMessageContext( SAMLMessageEncoder encoder, SignableSAMLObject response) { final MessageContext messageContext = new MessageContext(); messageContext.setMessage(response); encoder.setMessageContext(messageContext); return messageContext; } protected BaseContext injectSigningInfos(EaafX509Credential credentials) throws SamlSigningException { final SecurityParametersContext securityParamContext = new SecurityParametersContext(); final SignatureSigningParameters signingParams = new SignatureSigningParameters(); securityParamContext.setSignatureSigningParameters(signingParams); signingParams.setSigningCredential(credentials); signingParams.setSignatureCanonicalizationAlgorithm( SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); signingParams.setSignatureReferenceCanonicalizationAlgorithm( SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); signingParams.setSignatureAlgorithm(credentials.getSignatureAlgorithmForSigning()); signingParams.setSignatureReferenceDigestMethod( Saml2Utils.getDigestAlgorithm(signingParams.getSignatureAlgorithm())); signingParams.setKeyInfoGenerator(Saml2Utils.getKeyInfoGenerator(credentials, true)); return securityParamContext; } protected BaseContext injectEndpointInfos(final SignableSAMLObject response, String targetLocation) { SAMLBindingSupport.setSAML2Destination(response, targetLocation); final SingleSignOnService service = new SingleSignOnServiceBuilder().buildObject(); service.setBinding(getSaml2BindingName()); service.setLocation(targetLocation); final SAMLPeerEntityContext peerEntityContext = new SAMLPeerEntityContext(); final SAMLEndpointContext endpointContext = new SAMLEndpointContext(); endpointContext.setEndpoint(service); peerEntityContext.addSubcontext(endpointContext); return peerEntityContext; } protected void injectInboundMessageContexts(MessageContext messageContext, 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); messageContext.addSubcontext(securityParameterContext); sigValParameters.setExcludedAlgorithms( ConfigurationService.get(SignatureValidationConfiguration.class) .getExcludedAlgorithms()); sigValParameters.setSignatureTrustEngine( TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); } protected void performMessageValidation(PvpSamlMessageHandlerChain messageValidatorChain, MessageContext 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 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 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; } }