/******************************************************************************* * Copyright 2014 Federal Chancellery Austria * MOA-ID has been developed in a cooperation between BRZ, the Federal * Chancellery Austria - ICT staff unit, and Graz University of Technology. * * Licensed under the EUPL, Version 1.1 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: * http://www.osor.eu/eupl/ * * 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.egovernment.moa.id.protocols.pvp2x.binding; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; 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.springframework.stereotype.Service; import at.gv.egovernment.moa.id.commons.api.IRequest; import at.gv.egovernment.moa.id.protocols.pvp2x.PVP2XProtocol; import at.gv.egovernment.moa.id.protocols.pvp2x.config.MOADefaultBootstrap; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessage; import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessageInterface; 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.metadata.IMOARefreshableMetadataProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.validation.MOASAML2AuthRequestSignedRole; import at.gv.egovernment.moa.id.protocols.pvp2x.verification.TrustEngineFactory; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; @Service("PVPRedirectBinding") public class RedirectBinding implements IDecoder, IEncoder { public void encodeRequest(HttpServletRequest req, HttpServletResponse resp, RequestAbstractType request, String targetLocation, String relayState, Credential credentials, IRequest pendingReq) throws MessageEncodingException, SecurityException { // try { // X509Credential credentials = credentialProvider // .getIDPAssertionSigningCredential(); //load default PVP security configurations MOADefaultBootstrap.initializeDefaultPVPConfiguration(); Logger.debug("create SAML RedirectBinding response"); HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder(); HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter( resp, true); BasicSAMLMessageContext context = new BasicSAMLMessageContext(); 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); // } catch (CredentialsNotAvailableException e) { // e.printStackTrace(); // throw new SecurityException(e); // } } public void encodeRespone(HttpServletRequest req, HttpServletResponse resp, StatusResponseType response, String targetLocation, String relayState, Credential credentials, IRequest pendingReq) throws MessageEncodingException, SecurityException { // try { // X509Credential credentials = credentialProvider // .getIDPAssertionSigningCredential(); //load default PVP security configurations MOADefaultBootstrap.initializeDefaultPVPConfiguration(); Logger.debug("create SAML RedirectBinding response"); HTTPRedirectDeflateEncoder encoder = new HTTPRedirectDeflateEncoder(); HttpServletResponseAdapter responseAdapter = new HttpServletResponseAdapter( resp, true); BasicSAMLMessageContext context = new BasicSAMLMessageContext(); 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); // } catch (CredentialsNotAvailableException e) { // e.printStackTrace(); // throw new SecurityException(e); // } } public InboundMessageInterface decode(HttpServletRequest req, HttpServletResponse resp, MetadataProvider metadataProvider, boolean isSPEndPoint, URIComparator comparator) throws MessageDecodingException, SecurityException { HTTPRedirectDeflateDecoder decode = new HTTPRedirectDeflateDecoder( new BasicParserPool()); BasicSAMLMessageContext 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); SAML2HTTPRedirectDeflateSignatureRule signatureRule = new SAML2HTTPRedirectDeflateSignatureRule( TrustEngineFactory.getSignatureKnownKeysTrustEngine(metadataProvider)); MOASAML2AuthRequestSignedRole signedRole = new MOASAML2AuthRequestSignedRole(); 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 (MiscUtil.isEmpty(messageContext.getInboundMessageIssuer())) { throw e; } if (metadataProvider instanceof IMOARefreshableMetadataProvider) { Logger.debug("PVP2X message validation FAILED. Reload metadata for entityID: " + messageContext.getInboundMessageIssuer()); if (!((IMOARefreshableMetadataProvider) metadataProvider).refreshMetadataProvider(messageContext.getInboundMessageIssuer())) throw e; else { Logger.trace("PVP2X metadata reload finished. Check validate message again."); decode.decode(messageContext); //check signature signatureRule.evaluate(messageContext); } Logger.trace("Second PVP2X message validation finished"); } else { throw e; } } InboundMessage msg = null; if (messageContext.getInboundMessage() instanceof RequestAbstractType) { RequestAbstractType inboundMessage = (RequestAbstractType) messageContext .getInboundMessage(); msg = new MOARequest(inboundMessage, getSAML2BindingName()); } else if (messageContext.getInboundMessage() instanceof StatusResponseType){ StatusResponseType inboundMessage = (StatusResponseType) messageContext.getInboundMessage(); msg = new MOAResponse(inboundMessage); } else //create empty container if request type is unknown msg = new InboundMessage(); if (messageContext.getPeerEntityMetadata() != null) msg.setEntityID(messageContext.getPeerEntityMetadata().getEntityID()); else Logger.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(PVP2XProtocol.REDIRECT) || action.equals(PVP2XProtocol.SINGLELOGOUT)) && req.getMethod().equals("GET")); } public String getSAML2BindingName() { return SAMLConstants.SAML2_REDIRECT_BINDING_URI; } }