From 189cc1e3f1acb8a626f8d865716cc7b3cec03da9 Mon Sep 17 00:00:00 2001 From: Andreas Fitzek Date: Thu, 6 Jun 2013 17:12:43 +0200 Subject: Fixed Postbinding verification and metadata issue --- .../moa/id/moduls/AuthenticationSessionStore.java | 1 - .../moa/id/protocols/pvp2x/PVP2XProtocol.java | 48 +++++++--------- .../protocols/pvp2x/binding/ArtifactBinding.java | 2 +- .../moa/id/protocols/pvp2x/binding/IDecoder.java | 2 +- .../id/protocols/pvp2x/binding/PostBinding.java | 56 ++++++++++++++++-- .../protocols/pvp2x/binding/RedirectBinding.java | 13 ++++- .../id/protocols/pvp2x/binding/SoapBinding.java | 2 +- .../pvp2x/verification/SAMLVerificationEngine.java | 67 ++++++++++++++++++++++ .../pvp2x/verification/SAMLVerifierMOASP.java | 4 +- .../stork/vidp/messages/common/STORKBootstrap.java | 4 +- 10 files changed, 159 insertions(+), 40 deletions(-) create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java (limited to 'id') diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationSessionStore.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationSessionStore.java index e54bba10d..c149d1ce1 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationSessionStore.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationSessionStore.java @@ -5,7 +5,6 @@ import java.util.Iterator; import java.util.Set; import at.gv.egovernment.moa.id.AuthenticationException; -import at.gv.egovernment.moa.id.MOAIDException; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; import at.gv.egovernment.moa.id.util.Random; import at.gv.egovernment.moa.logging.Logger; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java index 5ea596eeb..33c8af197 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/PVP2XProtocol.java @@ -18,6 +18,9 @@ import org.opensaml.saml2.core.Status; import org.opensaml.saml2.core.StatusCode; import org.opensaml.saml2.core.StatusMessage; import org.opensaml.saml2.core.StatusResponseType; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.SPSSODescriptor; import at.gv.egovernment.moa.id.MOAIDException; import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; @@ -35,10 +38,8 @@ import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding; import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding; import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; -import at.gv.egovernment.moa.id.protocols.pvp2x.validation.ChainSAMLValidator; -import at.gv.egovernment.moa.id.protocols.pvp2x.validation.SAMLSignatureValidator; -import at.gv.egovernment.moa.id.protocols.pvp2x.verification.ChainSAMLVerifier; -import at.gv.egovernment.moa.id.protocols.pvp2x.verification.SAMLVerifierMOASP; +import at.gv.egovernment.moa.id.protocols.pvp2x.verification.SAMLVerificationEngine; +import at.gv.egovernment.moa.id.protocols.pvp2x.verification.TrustEngineFactory; import at.gv.egovernment.moa.id.util.ParamValidatorUtils; public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { @@ -57,10 +58,6 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { private static HashMap actions = new HashMap(); - private ChainSAMLVerifier samlVerifier = new ChainSAMLVerifier(); - - private ChainSAMLValidator samlValidator = new ChainSAMLValidator(); - static { servletList.add(new ServletInfo(PVPProcessor.class, REDIRECT, ServletType.AUTH)); @@ -98,11 +95,11 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { return PATH; } - private IDecoder findDecoder(String action) { + private IDecoder findDecoder(String action, HttpServletRequest req) { Iterator decoderIT = decoder.iterator(); while (decoderIT.hasNext()) { IDecoder decoder = decoderIT.next(); - if (decoder.handleDecode(action)) { + if (decoder.handleDecode(action, req)) { return decoder; } } @@ -112,10 +109,6 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { public PVP2XProtocol() { super(); - - samlVerifier.addVerifier(new SAMLVerifierMOASP()); - - samlValidator.addValidator(new SAMLSignatureValidator()); } public IRequest preProcess(HttpServletRequest request, @@ -125,7 +118,7 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { return new PVPTargetConfiguration(); } - IDecoder decoder = findDecoder(action); + IDecoder decoder = findDecoder(action, request); if (decoder == null) { return null; } @@ -140,12 +133,12 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { //Logger.info("SAML : " + xml); - // TODO: verify samlReq - //samlValidator.validateRequest(samlReq); - - // TODO: validate samlReq for - //samlVerifier.verifyRequest(samlReq); - + if(!moaRequest.isVerified()) { + // TODO: verify samlReq + SAMLVerificationEngine engine = new SAMLVerificationEngine(); + engine.verifyRequest(samlReq, TrustEngineFactory.getSignatureKnownKeysTrustEngine()); + moaRequest.setVerified(true); + } // TODO: OAURL is AssertionConsumerService URL from entitydescriptor ... if(!(samlReq instanceof AuthnRequest)) { @@ -161,9 +154,10 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { idx = aIdx.intValue(); } - String oaURL = moaRequest.getEntityMetadata(). - getSPSSODescriptor(SAMLConstants.SAML20P_NS). - getAssertionConsumerServices().get(idx).getLocation(); + EntityDescriptor metadata = moaRequest.getEntityMetadata(); + SPSSODescriptor spSSODescriptor = metadata.getSPSSODescriptor(SAMLConstants.SAML20P_NS); + AssertionConsumerService consumerService = spSSODescriptor.getAssertionConsumerServices().get(idx); + String oaURL = consumerService.getLocation(); String entityID = moaRequest.getEntityMetadata().getEntityID(); @@ -221,9 +215,11 @@ public class PVP2XProtocol implements IModulInfo, MOAIDAuthConstants { public IAction canHandleRequest(HttpServletRequest request, HttpServletResponse response) { - if(request.getParameter("SAMLRequest") != null) { + if(request.getParameter("SAMLRequest") != null && request.getMethod().equals("GET")) { return getAction(REDIRECT); - } + } else if(request.getParameter("SAMLRequest") != null && request.getMethod().equals("POST")) { + return getAction(POST); + } if(METADATA.equals(request.getParameter("action"))) { return getAction(METADATA); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java index 8f83812a6..a8c3dab48 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/ArtifactBinding.java @@ -97,7 +97,7 @@ public class ArtifactBinding implements IDecoder, IEncoder { return null; } - public boolean handleDecode(String action) { + public boolean handleDecode(String action, HttpServletRequest req) { // TODO Auto-generated method stub return false; } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IDecoder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IDecoder.java index 2778016ba..531ec0756 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IDecoder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/IDecoder.java @@ -15,5 +15,5 @@ public interface IDecoder { HttpServletResponse resp) throws MessageDecodingException, SecurityException; - public boolean handleDecode(String action); + public boolean handleDecode(String action, HttpServletRequest req); } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java index c7d779fa2..1b55d4b2e 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java @@ -9,13 +9,19 @@ import org.opensaml.common.SAMLObject; import org.opensaml.common.binding.BasicSAMLMessageContext; import org.opensaml.saml2.binding.decoding.HTTPPostDecoder; import org.opensaml.saml2.binding.encoding.HTTPPostEncoder; +import org.opensaml.saml2.binding.security.SAML2HTTPRedirectDeflateSignatureRule; import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.Response; import org.opensaml.saml2.core.StatusResponseType; +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.MetadataProviderException; 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; @@ -24,8 +30,10 @@ import org.opensaml.xml.security.credential.Credential; import org.opensaml.xml.signature.Signature; import at.gv.egovernment.moa.id.protocols.pvp2x.PVP2XProtocol; +import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; +import at.gv.egovernment.moa.id.protocols.pvp2x.verification.TrustEngineFactory; public class PostBinding implements IDecoder, IEncoder { @@ -86,13 +94,36 @@ public class PostBinding implements IDecoder, IEncoder { BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext(); messageContext .setInboundMessageTransport(new HttpServletRequestAdapter(req)); + + // TODO: used to verify signature! + SAML2HTTPRedirectDeflateSignatureRule signatureRule = new SAML2HTTPRedirectDeflateSignatureRule( + TrustEngineFactory.getSignatureKnownKeysTrustEngine()); + + // signatureRule.evaluate(messageContext); + BasicSecurityPolicy policy = new BasicSecurityPolicy(); + policy.getPolicyRules().add(signatureRule); + SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver( + policy); + messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); + messageContext.setSecurityPolicyResolver(resolver); + + MOAMetadataProvider provider = null; + try { + provider = new MOAMetadataProvider(); + } catch (MetadataProviderException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + messageContext.setMetadataProvider(provider); + decode.decode(messageContext); RequestAbstractType inboundMessage = (RequestAbstractType) messageContext .getInboundMessage(); - + MOARequest request = new MOARequest(inboundMessage); - + request.setVerified(false); + request.setEntityMetadata(messageContext.getPeerEntityMetadata()); return request; } @@ -105,16 +136,31 @@ public class PostBinding implements IDecoder, IEncoder { BasicSAMLMessageContext messageContext = new BasicSAMLMessageContext(); messageContext .setInboundMessageTransport(new HttpServletRequestAdapter(req)); + + // TODO: used to verify signature! + SAML2HTTPRedirectDeflateSignatureRule signatureRule = new SAML2HTTPRedirectDeflateSignatureRule( + TrustEngineFactory.getSignatureKnownKeysTrustEngine()); + + // signatureRule.evaluate(messageContext); + BasicSecurityPolicy policy = new BasicSecurityPolicy(); + policy.getPolicyRules().add(signatureRule); + SecurityPolicyResolver resolver = new StaticSecurityPolicyResolver( + policy); + messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); + messageContext.setSecurityPolicyResolver(resolver); + decode.decode(messageContext); Response inboundMessage = (Response) messageContext.getInboundMessage(); - + MOAResponse moaResponse = new MOAResponse(inboundMessage); + moaResponse.setVerified(false); + moaResponse.setEntityMetadata(messageContext.getPeerEntityMetadata()); return moaResponse; } - public boolean handleDecode(String action) { - return (action.equals(PVP2XProtocol.POST)); + public boolean handleDecode(String action, HttpServletRequest req) { + return (req.getMethod().equals("POST")); } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java index 92a6b6002..a4670d3fc 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/RedirectBinding.java @@ -99,6 +99,7 @@ public class RedirectBinding implements IDecoder, IEncoder { policy); messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); messageContext.setSecurityPolicyResolver(resolver); + decode.decode(messageContext); signatureRule.evaluate(messageContext); @@ -132,6 +133,14 @@ public class RedirectBinding implements IDecoder, IEncoder { policy); messageContext.setPeerEntityRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME); messageContext.setSecurityPolicyResolver(resolver); + MOAMetadataProvider provider = null; + try { + provider = new MOAMetadataProvider(); + } catch (MetadataProviderException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + messageContext.setMetadataProvider(provider); decode.decode(messageContext); @@ -143,7 +152,7 @@ public class RedirectBinding implements IDecoder, IEncoder { return moaResponse; } - public boolean handleDecode(String action) { - return (action.equals(PVP2XProtocol.REDIRECT)); + public boolean handleDecode(String action, HttpServletRequest req) { + return (action.equals(PVP2XProtocol.REDIRECT) && req.getMethod().equals("GET")); } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java index 027dab15a..558f19b4f 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/SoapBinding.java @@ -56,7 +56,7 @@ public class SoapBinding implements IDecoder, IEncoder { return moaResponse; } - public boolean handleDecode(String action) { + public boolean handleDecode(String action, HttpServletRequest req) { return (action.equals(PVP2XProtocol.SOAP)); } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java new file mode 100644 index 000000000..8df418f9a --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerificationEngine.java @@ -0,0 +1,67 @@ +package at.gv.egovernment.moa.id.protocols.pvp2x.verification; + +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.RequestAbstractType; +import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.metadata.IDPSSODescriptor; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.security.MetadataCriteria; +import org.opensaml.security.SAMLSignatureProfileValidator; +import org.opensaml.xml.security.CriteriaSet; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.criteria.EntityIDCriteria; +import org.opensaml.xml.security.criteria.UsageCriteria; +import org.opensaml.xml.signature.SignatureTrustEngine; +import org.opensaml.xml.validation.ValidationException; + +public class SAMLVerificationEngine { + + public void verifyResponse(Response samlObj, SignatureTrustEngine sigTrustEngine ) throws org.opensaml.xml.security.SecurityException, Exception { + SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); + try { + profileValidator.validate(samlObj.getSignature()); + } catch (ValidationException e) { + // Indicates signature did not conform to SAML Signature profile + e.printStackTrace(); + } + + CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add( new EntityIDCriteria(samlObj.getIssuer().getValue()) ); + criteriaSet.add( new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS) ); + criteriaSet.add( new UsageCriteria(UsageType.SIGNING) ); + + try { + if (!sigTrustEngine.validate(samlObj.getSignature(), criteriaSet)) { + throw new Exception("Signature was either invalid or signing key could not be established as trusted"); + } + } catch (SecurityException e) { + // Indicates processing error evaluating the signature + e.printStackTrace(); + } + } + + public void verifyRequest(RequestAbstractType samlObj, SignatureTrustEngine sigTrustEngine ) throws org.opensaml.xml.security.SecurityException, Exception { + SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); + try { + profileValidator.validate(samlObj.getSignature()); + } catch (ValidationException e) { + // Indicates signature did not conform to SAML Signature profile + e.printStackTrace(); + } + + CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add( new EntityIDCriteria(samlObj.getIssuer().getValue()) ); + criteriaSet.add( new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS) ); + criteriaSet.add( new UsageCriteria(UsageType.SIGNING) ); + + try { + if (!sigTrustEngine.validate(samlObj.getSignature(), criteriaSet)) { + throw new Exception("Signature was either invalid or signing key could not be established as trusted"); + } + } catch (SecurityException e) { + // Indicates processing error evaluating the signature + e.printStackTrace(); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerifierMOASP.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerifierMOASP.java index 37289a8e3..6dbaae0a1 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerifierMOASP.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/SAMLVerifierMOASP.java @@ -20,6 +20,8 @@ import eu.stork.vidp.messages.util.XMLUtil; public class SAMLVerifierMOASP implements ISAMLVerifier { + + //TODO: implement via metadata validator .... public void verifyRequest(RequestAbstractType request) throws MOAIDException { // validate Signature @@ -79,7 +81,7 @@ public class SAMLVerifierMOASP implements ISAMLVerifier { Logger.debug("Signing certificate of SAML response succesfully verified"); } else { - String msg = "SAML Response is not signed."; + String msg = "SAML Object is not signed."; throw new SecurityException(msg); } diff --git a/id/server/stork-saml-engine/src/main/java/eu/stork/vidp/messages/common/STORKBootstrap.java b/id/server/stork-saml-engine/src/main/java/eu/stork/vidp/messages/common/STORKBootstrap.java index d75a4c2eb..953affdf8 100644 --- a/id/server/stork-saml-engine/src/main/java/eu/stork/vidp/messages/common/STORKBootstrap.java +++ b/id/server/stork-saml-engine/src/main/java/eu/stork/vidp/messages/common/STORKBootstrap.java @@ -48,12 +48,12 @@ public class STORKBootstrap extends DefaultBootstrap { DefaultBootstrap.bootstrap(); - /*SAMLSchemaBuilder.addExtensionSchema("stork-schema-assertion-1.0.xsd"); + SAMLSchemaBuilder.addExtensionSchema("stork-schema-assertion-1.0.xsd"); SAMLSchemaBuilder.addExtensionSchema("stork-schema-protocol-1.0.xsd"); - initStorkConfig("saml2-stork-config.xml"); */ + initStorkConfig("saml2-stork-config.xml"); } -- cgit v1.2.3