summaryrefslogtreecommitdiff
path: root/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SAMLVerificationEngine.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/verification/SAMLVerificationEngine.java')
-rw-r--r--eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SAMLVerificationEngine.java183
1 files changed, 183 insertions, 0 deletions
diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SAMLVerificationEngine.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SAMLVerificationEngine.java
new file mode 100644
index 00000000..fe147ea7
--- /dev/null
+++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/SAMLVerificationEngine.java
@@ -0,0 +1,183 @@
+/*******************************************************************************
+ *******************************************************************************/
+package at.gv.egiz.eaaf.modules.pvp2.impl.verification;
+
+import javax.xml.namespace.QName;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.Validator;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opensaml.common.xml.SAMLConstants;
+import org.opensaml.common.xml.SAMLSchemaBuilder;
+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.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;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+import at.gv.egiz.eaaf.core.exceptions.InvalidProtocolRequestException;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider;
+import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException;
+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;
+
+@Service("SAMLVerificationEngine")
+public class SAMLVerificationEngine {
+ private static final Logger log = LoggerFactory.getLogger(SAMLVerificationEngine.class);
+
+
+ @Autowired(required=true) IPVPMetadataProvider metadataProvider;
+
+ public void verify(InboundMessage msg, SignatureTrustEngine sigTrustEngine ) throws org.opensaml.xml.security.SecurityException, Exception {
+ try {
+ if (msg instanceof PVPSProfileRequest &&
+ ((PVPSProfileRequest)msg).getSamlRequest() instanceof RequestAbstractType)
+ verifyRequest(((RequestAbstractType)((PVPSProfileRequest)msg).getSamlRequest()), sigTrustEngine);
+
+ else
+ verifyIDPResponse(((PVPSProfileResponse)msg).getResponse(), sigTrustEngine);
+
+ } catch (InvalidProtocolRequestException e) {
+ if (StringUtils.isEmpty(msg.getEntityID())) {
+ throw e;
+
+ }
+ log.debug("PVP2X message validation FAILED. Relead metadata for entityID: " + msg.getEntityID());
+
+ if (metadataProvider == null ||
+ !(metadataProvider instanceof IRefreshableMetadataProvider) ||
+ !((IRefreshableMetadataProvider)metadataProvider).refreshMetadataProvider(msg.getEntityID()))
+ throw e;
+
+ else {
+ log.trace("PVP2X metadata reload finished. Check validate message again.");
+
+ if (msg instanceof PVPSProfileRequest &&
+ ((PVPSProfileRequest)msg).getSamlRequest() instanceof RequestAbstractType)
+ verifyRequest(((RequestAbstractType)((PVPSProfileRequest)msg).getSamlRequest()), sigTrustEngine);
+
+ else
+ verifyIDPResponse(((PVPSProfileResponse)msg).getResponse(), sigTrustEngine);
+
+ }
+ log.trace("Second PVP2X message validation finished");
+ }
+ }
+
+ public void verifySLOResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine ) throws InvalidProtocolRequestException {
+ verifyResponse(samlObj, sigTrustEngine, SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+
+ }
+
+ public void verifyIDPResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine) throws InvalidProtocolRequestException{
+ verifyResponse(samlObj, sigTrustEngine, IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
+
+ }
+
+ private void verifyResponse(StatusResponseType samlObj, SignatureTrustEngine sigTrustEngine, QName defaultElementName) throws InvalidProtocolRequestException{
+ SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
+ try {
+ profileValidator.validate(samlObj.getSignature());
+ performSchemaValidation(samlObj.getDOM());
+
+ } catch (ValidationException e) {
+ log.warn("Signature is not conform to SAML signature profile", e);
+ throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}, "Signature is not conform to SAML signature profile");
+
+ } catch (SchemaValidationException e) {
+ throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}, "SAML response does not fit XML scheme");
+
+ }
+
+ CriteriaSet criteriaSet = new CriteriaSet();
+ criteriaSet.add( new EntityIDCriteria(samlObj.getIssuer().getValue()) );
+ criteriaSet.add( new MetadataCriteria(defaultElementName, SAMLConstants.SAML20P_NS) );
+ criteriaSet.add( new UsageCriteria(UsageType.SIGNING) );
+
+ try {
+ if (!sigTrustEngine.validate(samlObj.getSignature(), criteriaSet)) {
+ throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}, "Signature verification FAILED on SAML response");
+ }
+ } catch (org.opensaml.xml.security.SecurityException e) {
+ log.warn("PVP2x message signature validation FAILED.", e);
+ throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}, "Signature verification FAILED on SAML response");
+ }
+ }
+
+ private void verifyRequest(RequestAbstractType samlObj, SignatureTrustEngine sigTrustEngine ) throws InvalidProtocolRequestException {
+ SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator();
+ try {
+ profileValidator.validate(samlObj.getSignature());
+ performSchemaValidation(samlObj.getDOM());
+
+ } catch (ValidationException e) {
+ log.warn("Signature is not conform to SAML signature profile", e);
+ throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}, "Scheme validation FAILED on SAML request");
+
+ } catch (SchemaValidationException e) {
+ throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}, "Scheme verification FAILED on SAML request");
+
+ }
+
+ 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 InvalidProtocolRequestException("pvp2.21", new Object[] {}, "Signature verification FAILED on SAML request");
+ }
+ } catch (org.opensaml.xml.security.SecurityException e) {
+ log.warn("PVP2x message signature validation FAILED.", e);
+ throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}, "Signature verification FAILED on SAML request");
+ }
+ }
+
+ protected void performSchemaValidation(Element source) throws SchemaValidationException {
+
+ String err = null;
+ try {
+ Schema test = SAMLSchemaBuilder.getSAML11Schema();
+ Validator val = test.newValidator();
+ val.validate(new DOMSource(source));
+ log.debug("Schema validation check done OK");
+ return;
+
+ } catch (SAXException e) {
+ err = e.getMessage();
+ if (log.isDebugEnabled() || log.isTraceEnabled())
+ log.warn("Schema validation FAILED with exception:", e);
+ else
+ log.warn("Schema validation FAILED with message: "+ e.getMessage());
+
+ } catch (Exception e) {
+ err = e.getMessage();
+ if (log.isDebugEnabled() || log.isTraceEnabled())
+ log.warn("Schema validation FAILED with exception:", e);
+ else
+ log.warn("Schema validation FAILED with message: "+ e.getMessage());
+
+ }
+
+ throw new SchemaValidationException("pvp2.22", new Object[]{err});
+
+ }
+
+}