diff options
| author | Thomas <thomas.lenz@egiz.gv.at> | 2020-02-02 19:32:21 +0100 | 
|---|---|---|
| committer | Thomas <thomas.lenz@egiz.gv.at> | 2020-02-02 19:32:21 +0100 | 
| commit | 41ea2fdf782cd64d7d29f73c2e83f9c255810818 (patch) | |
| tree | 9710ca3937ae82391c6a2a0e5176923e0a49a5af /eaaf_modules | |
| parent | d41afe91ee59daf6b5f5037cecac52900fe2ccb2 (diff) | |
| download | EAAF-Components-41ea2fdf782cd64d7d29f73c2e83f9c255810818.tar.gz EAAF-Components-41ea2fdf782cd64d7d29f73c2e83f9c255810818.tar.bz2 EAAF-Components-41ea2fdf782cd64d7d29f73c2e83f9c255810818.zip | |
some more OpenSAML3 refactoring stuff
Diffstat (limited to 'eaaf_modules')
19 files changed, 658 insertions, 650 deletions
| diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvp2MetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvp2MetadataProvider.java index e2ee0c9d..1af8db7b 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvp2MetadataProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvp2MetadataProvider.java @@ -19,33 +19,13 @@  package at.gv.egiz.eaaf.modules.pvp2.api.metadata; -import java.util.List; - -import javax.xml.namespace.QName; - -import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; - -import org.opensaml.core.xml.XMLObject; -import org.opensaml.saml.metadata.resolver.MetadataResolver; -import org.opensaml.saml.saml2.metadata.EntitiesDescriptor; +import org.opensaml.saml.metadata.resolver.ExtendedRefreshableMetadataResolver;  import org.opensaml.saml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml.saml2.metadata.RoleDescriptor; - -public interface IPvp2MetadataProvider extends MetadataResolver { - -  XMLObject getMetadata() throws Pvp2MetadataException; - - -  EntitiesDescriptor getEntitiesDescriptor(String entitiesID) throws Pvp2MetadataException; - - -  EntityDescriptor getEntityDescriptor(String entityID) throws Pvp2MetadataException; - -  List<RoleDescriptor> getRole(String entityID, QName roleName) throws Pvp2MetadataException; +import net.shibboleth.utilities.java.support.resolver.ResolverException; +public interface IPvp2MetadataProvider extends ExtendedRefreshableMetadataResolver { -  RoleDescriptor getRole(String entityID, QName roleName, String supportedProtocol) -      throws Pvp2MetadataException; +  EntityDescriptor getEntityDescriptor(String entityID) throws ResolverException;  } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataBuilderConfiguration.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataBuilderConfiguration.java index 72cb3f3c..128d4c2f 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataBuilderConfiguration.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IPvpMetadataBuilderConfiguration.java @@ -22,14 +22,15 @@ package at.gv.egiz.eaaf.modules.pvp2.api.metadata;  import java.util.Collection;  import java.util.List; -import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; -  import org.opensaml.saml.saml2.core.Attribute;  import org.opensaml.saml.saml2.metadata.ContactPerson;  import org.opensaml.saml.saml2.metadata.Organization;  import org.opensaml.saml.saml2.metadata.RequestedAttribute;  import org.opensaml.security.credential.Credential; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +  /**   * PVP Metadata builder configuration.   * @@ -109,7 +110,7 @@ public interface IPvpMetadataBuilderConfiguration {     * @return Credentials     * @throws CredentialsNotAvailableException In case of an error     */ -  Credential getMetadataSigningCredentials() throws CredentialsNotAvailableException; +  EaafX509Credential getMetadataSigningCredentials() throws CredentialsNotAvailableException;    /**     * Set the credential for request/response signing IDP metadata: this credential diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java index 5f69ba62..39536771 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/api/metadata/IRefreshableMetadataProvider.java @@ -19,13 +19,15 @@  package at.gv.egiz.eaaf.modules.pvp2.api.metadata; +import org.opensaml.saml.metadata.resolver.RefreshableMetadataResolver; +  /**   * Metadata provider that supports dynamic refreshing on external events.   *   * @author tlenz   *   */ -public interface IRefreshableMetadataProvider { +public interface IRefreshableMetadataProvider extends RefreshableMetadataResolver{    /**     * Refresh a entity or load a entity in a metadata provider. diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PvpMetadataBuilder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PvpMetadataBuilder.java index 42f69a57..d5893d4a 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PvpMetadataBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/builder/PvpMetadataBuilder.java @@ -20,31 +20,19 @@  package at.gv.egiz.eaaf.modules.pvp2.impl.builder;  import java.io.IOException; -import java.io.StringWriter;  import java.util.Collection;  import java.util.List; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; +import javax.naming.ConfigurationException;  import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.Transformer;  import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory;  import javax.xml.transform.TransformerFactoryConfigurationError; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import at.gv.egiz.eaaf.core.exceptions.EaafException; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataBuilderConfiguration; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; - -import org.apache.commons.httpclient.auth.CredentialsNotAvailableException;  import org.apache.commons.lang3.StringUtils;  import org.joda.time.DateTime; -import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; -import org.opensaml.core.xml.io.Marshaller;  import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.saml.common.SignableSAMLObject;  import org.opensaml.saml.common.xml.SAMLConstants;  import org.opensaml.saml.saml2.metadata.AssertionConsumerService;  import org.opensaml.saml.saml2.metadata.AttributeConsumingService; @@ -64,16 +52,20 @@ import org.opensaml.saml.saml2.metadata.SingleSignOnService;  import org.opensaml.security.SecurityException;  import org.opensaml.security.credential.Credential;  import org.opensaml.security.credential.UsageType; -import org.opensaml.xml.security.SecurityHelper;  import org.opensaml.xmlsec.keyinfo.KeyInfoGenerator;  import org.opensaml.xmlsec.keyinfo.impl.X509KeyInfoGeneratorFactory; -import org.opensaml.xmlsec.signature.Signature;  import org.opensaml.xmlsec.signature.support.SignatureException; -import org.opensaml.xmlsec.signature.support.Signer;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory;  import org.springframework.stereotype.Service; -import org.w3c.dom.Document; +import org.w3c.dom.Element; + +import at.gv.egiz.eaaf.core.exceptions.EaafException; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataBuilderConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.exception.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import net.shibboleth.utilities.java.support.xml.SerializeSupport;  /**   * PVP metadata builder implementation. @@ -153,19 +145,9 @@ public class PvpMetadataBuilder {        }      } - -    // set metadata signature parameters -    final Credential metadataSignCred = config.getMetadataSigningCredentials(); -    final Signature signature = AbstractCredentialProvider.getIdpSignature(metadataSignCred); -    SecurityHelper.prepareSignatureParams(signature, metadataSignCred, null, null); - -    // initialize XML document builder -    DocumentBuilder builder; -    final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - -    builder = factory.newDocumentBuilder(); -    final Document document = builder.newDocument(); - +    +    SignableSAMLObject metadataToSign; +          // build entities descriptor      if (config.buildEntitiesDescriptorAsRootElement()) {        final EntitiesDescriptor entitiesDescriptor = @@ -174,45 +156,29 @@ public class PvpMetadataBuilder {        entitiesDescriptor.setID(Saml2Utils.getSecureIdentifier());        entitiesDescriptor.setValidUntil(date.plusHours(config.getMetadataValidUntil()));        entitiesDescriptor.getEntityDescriptors().add(entityDescriptor); - -      // load default PVP security configurations -      entitiesDescriptor.setSignature(signature); - -      // marshall document -      final Marshaller out = -          XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(entitiesDescriptor); -      out.marshall(entitiesDescriptor, document); - +      metadataToSign = entitiesDescriptor; +           } else {        entityDescriptor.setValidUntil(date.plusHours(config.getMetadataValidUntil()));        entityDescriptor.setID(Saml2Utils.getSecureIdentifier()); - -      entityDescriptor.setSignature(signature); - -      // marshall document -      final Marshaller out = -          XMLObjectProviderRegistrySupport.getMarshallerFactory().getMarshaller(entityDescriptor); -      out.marshall(entityDescriptor, document); - +      metadataToSign = entityDescriptor; +            }      // sign metadata -    Signer.signObject(signature); - -    // transform metadata object to XML string -    final Transformer transformer = TransformerFactory.newInstance().newTransformer(); - -    final StringWriter sw = new StringWriter(); -    final StreamResult sr = new StreamResult(sw); -    final DOMSource source = new DOMSource(document); -    transformer.transform(source, sr); -    sw.close(); - -    return sw.toString(); +    final EaafX509Credential metadataSignCred = config.getMetadataSigningCredentials(); +    SignableSAMLObject signedMetadata = Saml2Utils.signSamlObject(metadataToSign, metadataSignCred, true); +     +    +    // Serialize metadata +    final Element document =XMLObjectSupport.marshall(signedMetadata); +    String serializedMetadata = SerializeSupport.nodeToString(document); +    return serializedMetadata; +        }    private RoleDescriptor generateSpMetadata(final IPvpMetadataBuilderConfiguration config) -      throws CredentialsNotAvailableException, SecurityException, EaafException { +      throws SecurityException, EaafException {      final SPSSODescriptor spSsoDescriptor = Saml2Utils.createSamlObject(SPSSODescriptor.class);      spSsoDescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS);      spSsoDescriptor.setAuthnRequestsSigned(config.wantAuthnRequestSigned()); @@ -353,7 +319,7 @@ public class PvpMetadataBuilder {    }    private IDPSSODescriptor generateIdpMetadata(final IPvpMetadataBuilderConfiguration config) -      throws EaafException, CredentialsNotAvailableException, SecurityException { +      throws EaafException, SecurityException {      // check response signing credential      final Credential responseSignCred = config.getRequestorResponseSigningCredentials();      if (responseSignCred == null) { diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java index 8a741b69..da958d5b 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/message/InboundMessage.java @@ -25,18 +25,18 @@ import java.io.Serializable;  import javax.xml.parsers.ParserConfigurationException;  import javax.xml.transform.TransformerException; -import at.gv.egiz.eaaf.core.impl.utils.DomUtils; -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.NoMetadataInformationException; -import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; -  import org.opensaml.saml.saml2.metadata.EntityDescriptor;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory;  import org.w3c.dom.Element;  import org.xml.sax.SAXException; +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +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.NoMetadataInformationException; +import net.shibboleth.utilities.java.support.resolver.ResolverException; +  public class InboundMessage implements InboundMessageInterface, Serializable {    private static final Logger log = LoggerFactory.getLogger(InboundMessage.class); @@ -65,9 +65,10 @@ public class InboundMessage implements InboundMessageInterface, Serializable {        return metadataProvider.getEntityDescriptor(this.entityID); -    } catch (final Pvp2MetadataException e) { +    } catch (final ResolverException e) {        log.warn("No Metadata for EntitiyID " + entityID);        throw new NoMetadataInformationException(); +            }    } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java index ec59b1df..3fc675e9 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/AbstractChainingMetadataProvider.java @@ -27,46 +27,41 @@ import java.util.HashMap;  import java.util.Iterator;  import java.util.List;  import java.util.Map; -import java.util.Timer;  import java.util.UUID;  import javax.annotation.Nonnull; +import javax.annotation.Nullable;  import javax.naming.ConfigurationException; -import javax.xml.namespace.QName; - -import at.gv.egiz.components.spring.api.IDestroyableObject; -import at.gv.egiz.eaaf.core.api.IGarbageCollectorProcessing; -import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider;  import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime;  import org.opensaml.core.criterion.EntityIdCriterion;  import org.opensaml.saml.metadata.resolver.ClearableMetadataResolver;  import org.opensaml.saml.metadata.resolver.MetadataResolver;  import org.opensaml.saml.metadata.resolver.RefreshableMetadataResolver;  import org.opensaml.saml.metadata.resolver.filter.MetadataFilter;  import org.opensaml.saml.metadata.resolver.impl.AbstractMetadataResolver; -import org.opensaml.saml.saml2.metadata.EntitiesDescriptor;  import org.opensaml.saml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml.saml2.metadata.RoleDescriptor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import at.gv.egiz.components.spring.api.IDestroyableObject; +import at.gv.egiz.eaaf.core.api.IGarbageCollectorProcessing; +import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; +import lombok.extern.slf4j.Slf4j;  import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;  import net.shibboleth.utilities.java.support.component.IdentifiedComponent;  import net.shibboleth.utilities.java.support.resolver.CriteriaSet;  import net.shibboleth.utilities.java.support.resolver.ResolverException; -public abstract class AbstractChainingMetadataProvider extends SimpleMetadataResolver -    implements IGarbageCollectorProcessing, IRefreshableMetadataProvider, IDestroyableObject, IPvp2MetadataProvider, -    RefreshableMetadataResolver, ClearableMetadataResolver { - -  private static final Logger log = LoggerFactory.getLogger(AbstractChainingMetadataProvider.class); - +@Slf4j +public abstract class AbstractChainingMetadataProvider implements IGarbageCollectorProcessing, IRefreshableMetadataProvider,  +    IDestroyableObject, IPvp2MetadataProvider, ClearableMetadataResolver { +      @Nonnull @NonnullElements private final List<MetadataResolver> internalResolvers; +  private DateTime lastRefeshTimestamp; +  private boolean lastRefeshSuccessful;    private static Object mutex = new Object(); -  private Timer timer = null;    /**     * Build a chaining metadata resolver that requires valid metadata. @@ -77,10 +72,6 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataRes    } -  public final Timer getTimer() { -    return this.timer; - -  }    /*     * (non-Javadoc) @@ -145,10 +136,6 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataRes          } else {            // load new Metadata Provider -          if (timer == null) { -            timer = new Timer(true); -          } -            internalResolvers.add(createNewMetadataProvider(metadataUrl));            log.info("SAML2 metadata for service provider: " + entityId + " is added."); @@ -183,78 +170,22 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataRes        internalResolvers.clear(); -      if (timer != null) { -        timer.cancel(); -      } -    } - -  /* -   * (non-Javadoc) -   * -   * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider# -   * getMetadataFilter() -   */ -  @Override -  public MetadataFilter getMetadataFilter() { -    return internalProvider.getMetadataFilter(); -  } - -  /* -   * (non-Javadoc) -   * -   * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider# -   * setMetadataFilter(org. opensaml.saml2.metadata.provider.MetadataFilter) -   */ -  @Override -  public void setMetadataFilter(final MetadataFilter newFilter) throws MetadataProviderException { -    internalProvider.setMetadataFilter(newFilter); -  } - -  /* -   * (non-Javadoc) -   * -   * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider# -   * getMetadata() -   */ -  @Override -  public XMLObject getMetadata() throws MetadataProviderException { -    return internalProvider.getMetadata(); +  /** {@inheritDoc} */ +  @Override  +  public final MetadataFilter getMetadataFilter() { +      log.warn("{} does NOT support {}", AbstractChainingMetadataProvider.class.getName(), +          MetadataFilter.class.getName()); +      return null;    } -  /* -   * (non-Javadoc) -   * -   * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider# -   * getEntitiesDescriptor( java.lang.String) -   */ -  @Override -  public EntitiesDescriptor getEntitiesDescriptor(final String entitiesID) -      throws MetadataProviderException { -    EntitiesDescriptor entitiesDesc = null; -    try { -      entitiesDesc = internalProvider.getEntitiesDescriptor(entitiesID); - -      if (entitiesDesc == null) { -        log.debug("Can not find PVP metadata for entityID: " + entitiesID -            + " Start refreshing process ..."); -        if (refreshMetadataProvider(entitiesID)) { -          return internalProvider.getEntitiesDescriptor(entitiesID); -        } - -      } - -    } catch (final MetadataProviderException e) { -      log.debug("Can not find PVP metadata for entityID: " + entitiesID -          + " Start refreshing process ..."); -      if (refreshMetadataProvider(entitiesID)) { -        return internalProvider.getEntitiesDescriptor(entitiesID); -      } - -    } - -    return entitiesDesc; +  /** {@inheritDoc} */ +  @Override  +  public final void setMetadataFilter(final MetadataFilter newFilter) { +    log.warn("{} does NOT support {}", AbstractChainingMetadataProvider.class.getName(), +        MetadataFilter.class.getName()); +      throw new UnsupportedOperationException("Metadata filters are not supported on AbstractChainingMetadataProvider");    }    /* @@ -265,68 +196,133 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataRes     */    @Override    public EntityDescriptor getEntityDescriptor(final String entityID) -      throws MetadataProviderException { +      throws ResolverException {      EntityDescriptor entityDesc = null;      try { -      entityDesc = internalProvider.getEntityDescriptor(entityID); +      entityDesc = resolveEntityDescripor(entityID);        if (entityDesc == null) {          log.debug("Can not find PVP metadata for entityID: " + entityID              + " Start refreshing process ...");          if (refreshMetadataProvider(entityID)) { -          return internalProvider.getEntityDescriptor(entityID); +          return resolveEntityDescripor(entityID);          } -        } -    } catch (final MetadataProviderException e) { +    } catch (final ResolverException e) {        log.debug(            "Can not find PVP metadata for entityID: " + entityID + " Start refreshing process ...");        if (refreshMetadataProvider(entityID)) { -        return internalProvider.getEntityDescriptor(entityID); +        return resolveEntityDescripor(entityID);        }      } -    // if (entityDesc != null) -    // lastAccess.put(entityID, new Date()); -      return entityDesc;    } -  /* -   * (non-Javadoc) -   * -   * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider# -   * getRole(java.lang. String, javax.xml.namespace.QName) -   */    @Override -  public List<RoleDescriptor> getRole(final String entityID, final QName roleName) -      throws MetadataProviderException { -    final List<RoleDescriptor> result = internalProvider.getRole(entityID, roleName); +  @Nullable  +  public final EntityDescriptor resolveSingle(@Nullable final CriteriaSet criteria) throws ResolverException { +    for (final MetadataResolver resolver : internalResolvers) { +      try { +          final EntityDescriptor descriptors = resolver.resolveSingle(criteria); +          if (descriptors != null) { +              return descriptors; +          } + +      } catch (final ResolverException e) { +          continue; + +      } -    // if (result != null) -    // lastAccess.put(entityID, new Date()); +    } + +    return null; -    return result;    } -  /* -   * (non-Javadoc) -   * -   * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider# -   * getRole(java.lang. String, javax.xml.namespace.QName, java.lang.String) -   */    @Override -  public RoleDescriptor getRole(final String entityID, final QName roleName, -      final String supportedProtocol) throws MetadataProviderException { -    final RoleDescriptor result = internalProvider.getRole(entityID, roleName, supportedProtocol); +  @Nonnull  +  public final Iterable<EntityDescriptor> resolve(@Nullable final CriteriaSet criteria) throws ResolverException { +      for (final MetadataResolver resolver : internalResolvers) { +          try { +              final Iterable<EntityDescriptor> descriptors = resolver.resolve(criteria); +              if (descriptors != null && descriptors.iterator().hasNext()) { +                  return descriptors; +                   +              } +               +          } catch (final ResolverException e) { +              continue; +               +          } +      } + +      return Collections.emptyList(); +  } +   +  @Override +  public final void clear() throws ResolverException { +      for (final MetadataResolver resolver : internalResolvers) { +          if (resolver instanceof ClearableMetadataResolver) { +              ((ClearableMetadataResolver) resolver).clear(); +          } +      } +  } + +  @Override +  public final void clear(String entityID) throws ResolverException { +      for (final MetadataResolver resolver : internalResolvers) { +          if (resolver instanceof ClearableMetadataResolver) { +              ((ClearableMetadataResolver) resolver).clear(entityID); +          } +      } +  } -    // if (result != null) -    // lastAccess.put(entityID, new Date()); +  @Override final public void refresh() throws ResolverException { +      this.lastRefeshSuccessful = false; +      for (final MetadataResolver resolver : internalResolvers) { +          if (resolver instanceof RefreshableMetadataResolver) { +              ((RefreshableMetadataResolver) resolver).refresh(); +               +          } +      } +       +      this.lastRefeshTimestamp = DateTime.now(); +      this.lastRefeshSuccessful = true; +  } -    return result; +  @Override +  @Nullable public DateTime getLastUpdate() { +      DateTime ret = null; +      for (final MetadataResolver resolver : internalResolvers) { +          if (resolver instanceof RefreshableMetadataResolver) { +              final DateTime lastUpdate = ((RefreshableMetadataResolver) resolver).getLastUpdate(); +              if (ret == null || ret.isBefore(lastUpdate)) { +                  ret = lastUpdate; +              } +          } +      } +       +      return ret;    } +  @Override +  @Nullable final public DateTime getLastRefresh() { +      DateTime ret = null; +      for (final MetadataResolver resolver : internalResolvers) { +          if (resolver instanceof RefreshableMetadataResolver) { +              final DateTime lastRefresh = ((RefreshableMetadataResolver) resolver).getLastRefresh(); +              if (ret == null || ret.isBefore(lastRefresh)) { +                  ret = lastRefresh; +              } +          } +      } +       +      return ret; +  } +   +      /**     * Get the URL to metadata for a specific entityID.     * @@ -359,6 +355,20 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataRes        throws EaafConfigurationException; +  /** +   * Get a Id for this metadata provider. +   *  +   * @return +   */ +  @Nonnull +  protected abstract String getMetadataProviderId(); +   +  protected final MetadataResolver getMetadataResolver() { +    log.warn("{} does NOT support 'getMetadataResolver'", AbstractChainingMetadataProvider.class.getName()); +    return null; +     +  } +      private Map<String, MetadataResolver> getAllActuallyLoadedResolvers() {      final Map<String, MetadataResolver> loadedproviders =          new HashMap<>(); @@ -447,21 +457,7 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataRes    private EntityDescriptor resolveEntityDescripor(String entityId) throws ResolverException {      final CriteriaSet criteria = new CriteriaSet();      criteria.add(new EntityIdCriterion(entityId)); -    for (final MetadataResolver resolver : internalResolvers) { -      try { -          final EntityDescriptor descriptors = resolver.resolveSingle(criteria); -          if (descriptors != null) { -              return descriptors; -          } - -      } catch (final ResolverException e) { -          continue; - -      } - -    } - -    return null; +    return resolveSingle(criteria);    } @@ -477,4 +473,40 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataRes      }    } + +   +   +  @Override +  public DateTime getLastSuccessfulRefresh() { +    return this.lastRefeshTimestamp; +     +  } + + +  @Override +  public Boolean wasLastRefreshSuccess() { +    return this.lastRefeshSuccessful; +     +  } + + + +  /** {@inheritDoc} */ +  @Override public boolean isRequireValidMetadata() { +      log.warn("Attempt to access unsupported requireValidMetadata property on ChainingMetadataResolver"); +      return false; +  } + +  /** {@inheritDoc} */ +  @Override public void setRequireValidMetadata(final boolean requireValidMetadata) { +      throw new UnsupportedOperationException("Setting requireValidMetadata is not supported on chaining resolver"); +  } + + +  @Override +  public String getId() { +    return getMetadataProviderId(); +     +  } +    } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverAdapter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverAdapter.java new file mode 100644 index 00000000..bd2b79cb --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverAdapter.java @@ -0,0 +1,96 @@ +package at.gv.egiz.eaaf.modules.pvp2.impl.metadata; + +import org.joda.time.DateTime; +import org.opensaml.core.criterion.EntityIdCriterion; +import org.opensaml.saml.metadata.resolver.ExtendedRefreshableMetadataResolver; +import org.opensaml.saml.metadata.resolver.filter.MetadataFilter; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; + +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import net.shibboleth.utilities.java.support.resolver.CriteriaSet; +import net.shibboleth.utilities.java.support.resolver.ResolverException; + +public class PvpMetadataResolverAdapter implements IPvp2MetadataProvider { +   +  private ExtendedRefreshableMetadataResolver internalProvider; + +  public PvpMetadataResolverAdapter(ExtendedRefreshableMetadataResolver provider) { +    this.internalProvider = provider; +  } + +  @Override +  public void refresh() throws ResolverException { +    internalProvider.refresh(); + +  } + +  @Override +  public DateTime getLastRefresh() { +    return internalProvider.getLastRefresh(); +     +  } + +  @Override +  public DateTime getLastUpdate() { +    return internalProvider.getLastUpdate(); +  } + +  @Override +  public boolean isRequireValidMetadata() { +    return internalProvider.isRequireValidMetadata(); +     +  } + +  @Override +  public void setRequireValidMetadata(boolean requireValidMetadata) { +    internalProvider.setRequireValidMetadata(requireValidMetadata); + +  } + +  @Override +  public MetadataFilter getMetadataFilter() { +    return internalProvider.getMetadataFilter(); +     +  } + +  @Override +  public void setMetadataFilter(MetadataFilter newFilter) { +   internalProvider.setMetadataFilter(newFilter); + +  } + +  @Override +  public Iterable<EntityDescriptor> resolve(CriteriaSet criteria) throws ResolverException { +    return internalProvider.resolve(criteria); +  } + +  @Override +  public EntityDescriptor resolveSingle(CriteriaSet criteria) throws ResolverException { +    return internalProvider.resolveSingle(criteria); +     +  } + +  @Override +  public String getId() { +    return internalProvider.getId(); +  } + +  @Override +  public EntityDescriptor getEntityDescriptor(String entityId) throws ResolverException { +    final CriteriaSet criteria = new CriteriaSet(); +    criteria.add(new EntityIdCriterion(entityId)); +    return internalProvider.resolveSingle(criteria); +     +  } + +  @Override +  public DateTime getLastSuccessfulRefresh() { +    return internalProvider.getLastSuccessfulRefresh(); +  } + +  @Override +  public Boolean wasLastRefreshSuccess() { +    return internalProvider.wasLastRefreshSuccess(); +  } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataResolver.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java index 35ad3f97..f548bc7b 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataResolver.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java @@ -1,75 +1,70 @@ -/* - * 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: - * 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. -*/ -  package at.gv.egiz.eaaf.modules.pvp2.impl.metadata; -import java.io.File; -import java.net.MalformedURLException; +import java.io.IOException;  import java.util.Timer; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import javax.annotation.PostConstruct;  import javax.net.ssl.SSLHandshakeException; -import at.gv.egiz.eaaf.core.api.idp.IConfiguration; -import at.gv.egiz.eaaf.core.impl.utils.FileUtils; -import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; -import at.gv.egiz.eaaf.modules.pvp2.exception.SignatureValidationException; -  import org.apache.http.client.HttpClient; -import org.opensaml.saml.metadata.resolver.MetadataResolver; +import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; +import org.opensaml.saml.metadata.resolver.ExtendedRefreshableMetadataResolver;  import org.opensaml.saml.metadata.resolver.filter.MetadataFilter; -import org.opensaml.saml.metadata.resolver.impl.FilesystemMetadataResolver;  import org.opensaml.saml.metadata.resolver.impl.HTTPMetadataResolver; +import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver;  import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.io.ResourceLoader; +import at.gv.egiz.components.spring.api.IDestroyableObject; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.core.impl.utils.FileUtils; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SignatureValidationException; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.OpenSaml3ResourceAdapter;  import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.resource.Resource;  import net.shibboleth.utilities.java.support.xml.ParserPool; -/** - * Simple SAML2 metadata provider. - * - * @author tlenz - * - */  @Slf4j -public abstract class SimpleMetadataResolver implements MetadataResolver { +public class PvpMetadataResolverFactory implements IDestroyableObject { +    private static final String URI_PREFIX_HTTP = "http:";    private static final String URI_PREFIX_HTTPS = "https:"; -  private static final String URI_PREFIX_FILE = "file:"; - -  @Autowired -  protected IConfiguration authConfig; - -  @Override -  public final boolean isRequireValidMetadata() { -    return true; - -  } - -  @Override -  public final void setRequireValidMetadata(final boolean requireValidMetadata) { -    log.warn("EAAF {} requires always valid metadata. Setting will be ignored", -        SimpleMetadataResolver.class.getSimpleName()); +  private Timer timer = null; +   +  @Autowired private IConfiguration authConfig; +  @Autowired private ResourceLoader resourceLoader; +   +  /** +   * Create a single SAML2 metadata provider by using the default OpenSAML3 parser-pool. +   * +   * @param metadataLocation where the metadata should be loaded, but never null. +   *                         If the location starts with http(s):, than a http +   *                         based metadata provider is used. If the location +   *                         starts with file:, than a filesystem based metadata +   *                         provider is used +   * @param filter           Filters, which should be used to validate the +   *                         metadata +   * @param idForLogging     Id, which is used for Logging +   * @param httpClient       Apache commons 4.x http client +   * +   * @return SAML2 Metadata Provider, or null if the metadata provider can not +   *         initialized +   */ +  @Nullable  +  public IPvp2MetadataProvider createMetadataProvider(@Nonnull final String metadataLocation, +      @Nullable final MetadataFilter filter, @Nonnull final String idForLogging, +      @Nullable final HttpClient httpClient) { +    return createMetadataProvider(metadataLocation, filter, idForLogging,  +        XMLObjectProviderRegistrySupport.getParserPool(),  +        httpClient);   +        } - - - +      /**     * Create a single SAML2 metadata provider.     * @@ -81,24 +76,26 @@ public abstract class SimpleMetadataResolver implements MetadataResolver {     * @param filter           Filters, which should be used to validate the     *                         metadata     * @param idForLogging     Id, which is used for Logging -   * @param timer            {@link Timer} which is used to schedule metadata -   *                         refresh operations -   * @param httpClient       Apache commons 3.x http client +   * @param httpClient       Apache commons 4.x http client     *     * @return SAML2 Metadata Provider, or null if the metadata provider can not     *         initialized     */ -  protected MetadataResolver createNewSimpleMetadataProvider(final String metadataLocation, -      final MetadataFilter filter, final String idForLogging, final Timer timer, -      final ParserPool pool, final HttpClient httpClient) { +  @Nullable  +  public IPvp2MetadataProvider createMetadataProvider(@Nonnull final String metadataLocation, +      @Nullable final MetadataFilter filter, @Nonnull final String idForLogging, +      @Nullable final ParserPool pool, @Nullable final HttpClient httpClient) { +     +    ExtendedRefreshableMetadataResolver internalProvider = null; +          if (metadataLocation.startsWith(URI_PREFIX_HTTP)          || metadataLocation.startsWith(URI_PREFIX_HTTPS)) {        if (httpClient != null) { -        return createNewHttpMetaDataProvider(metadataLocation, filter, idForLogging, timer, pool, +        internalProvider = createNewHttpMetaDataProvider(metadataLocation, filter, idForLogging, timer, pool,              httpClient);        } else {          log.warn("Can not load http(s) based SAML2 metadata without a HTTP client"); -        return null; +                }      } else { @@ -107,28 +104,33 @@ public abstract class SimpleMetadataResolver implements MetadataResolver {          absoluteMetadataLocation =              FileUtils.makeAbsoluteUrl(metadataLocation, authConfig.getConfigurationRootDirectory()); -        if (absoluteMetadataLocation.startsWith(URI_PREFIX_FILE)) { -          final File metadataFile = new File(absoluteMetadataLocation); -          if (metadataFile.exists()) { -            return createNewFileSystemMetaDataProvider(metadataFile, filter, idForLogging, timer, +          org.springframework.core.io.Resource resource = resourceLoader.getResource(absoluteMetadataLocation); +          if (resource.exists()) { +             internalProvider = createNewFileSystemMetaDataProvider( +                new OpenSaml3ResourceAdapter(resource),  +                filter, idForLogging, timer,                  pool);            } else {              log.warn(                  "SAML2 metadata file: " + absoluteMetadataLocation + " not found or not exist"); -            return null; +                        } -        } -      } catch (final MalformedURLException e) { +      } catch (final IOException e) {          log.warn("SAML2 metadata URL is invalid: " + metadataLocation, e);        } -      } -    log.warn("SAML2 metadata has an unsupported metadata location prefix: " + metadataLocation); -    return null; +    if (internalProvider != null) { +      return new PvpMetadataResolverAdapter(internalProvider); +       +    } else { +      log.warn("SAML2 metadata has an unsupported metadata location prefix: " + metadataLocation); +      return null; +       +    }    } @@ -143,21 +145,32 @@ public abstract class SimpleMetadataResolver implements MetadataResolver {     * @param pool     *     * @return SAML2 Metadata Provider +   * @throws IOException      */ -  private MetadataResolver createNewFileSystemMetaDataProvider(final File metadataFile, +  private ExtendedRefreshableMetadataResolver createNewFileSystemMetaDataProvider(final Resource metadataFile,        final MetadataFilter filter, final String idForLogging, final Timer timer, -      final ParserPool pool) { -    FilesystemMetadataResolver fileSystemResolver = null; +      final ParserPool pool) throws IOException { +    ResourceBackedMetadataResolver fileSystemResolver = null;      try { -      fileSystemResolver = new FilesystemMetadataResolver(timer, metadataFile); -      fileSystemResolver.setParserPool(pool); +      //fileSystemResolver = new FilesystemMetadataResolver(timer, metadataFile); +       +      fileSystemResolver = new ResourceBackedMetadataResolver(timer, metadataFile); +       +      if (pool != null) { +        fileSystemResolver.setParserPool(pool); +         +      } else { +        fileSystemResolver.setParserPool( +            XMLObjectProviderRegistrySupport.getParserPool()); +         +      }        fileSystemResolver.setRequireValidMetadata(true);        fileSystemResolver.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes        fileSystemResolver.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours        fileSystemResolver.setMetadataFilter(filter);        fileSystemResolver.initialize(); -      fileSystemResolver.setId(metadataFile.getAbsolutePath()); +      fileSystemResolver.setId(metadataFile.getURI().toASCIIString());        fileSystemResolver.setRequireValidMetadata(true); @@ -165,10 +178,10 @@ public abstract class SimpleMetadataResolver implements MetadataResolver {      } catch (final Exception e) {        log.warn("Failed to load Metadata file for " + idForLogging + "[ " + "File: " -          + metadataFile.getAbsolutePath() + " Msg: " + e.getMessage() + " ]", e); +          + metadataFile.getURI().toASCIIString() + " Msg: " + e.getMessage() + " ]", e);        log.warn("Can not initialize SAML2 metadata provider from filesystem: " -          + metadataFile.getAbsolutePath() + " Reason: " + e.getMessage(), e); +          + metadataFile.getURI().toASCIIString() + " Reason: " + e.getMessage(), e);        if (fileSystemResolver != null) {          fileSystemResolver.destroy(); @@ -193,7 +206,7 @@ public abstract class SimpleMetadataResolver implements MetadataResolver {     *     * @return SAML2 Metadata Provider     */ -  private MetadataResolver createNewHttpMetaDataProvider(final String metadataUrl, +  private ExtendedRefreshableMetadataResolver createNewHttpMetaDataProvider(final String metadataUrl,        final MetadataFilter filter, final String idForLogging, final Timer timer,        final ParserPool pool, final HttpClient httpClient) {      HTTPMetadataResolver httpMetadataResolver = null; @@ -240,4 +253,19 @@ public abstract class SimpleMetadataResolver implements MetadataResolver {      return null;    } +  @Override +  public void fullyDestroy() { +    if (timer != null) { +      log.info("Stopping timer-thread for PVP metadata resolver ...  "); +      timer.cancel(); +    }     +  } +   +  @PostConstruct +  private void initialize() { +    log.info("Initializing timer-thread for PVP metadata resolver ... "); +    timer = new Timer("PVP metadata-resolver refresh"); +     +  } +    } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java index dc60019a..d23affba 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpPostDecoder.java @@ -7,10 +7,13 @@ import javax.annotation.Nonnull;  import javax.annotation.Nullable;  import javax.servlet.http.HttpServletRequest; +import org.opensaml.core.xml.XMLObject;  import org.opensaml.messaging.decoder.MessageDecodingException;  import org.opensaml.saml.saml2.binding.decoding.impl.HTTPPostDecoder;  import com.google.common.base.Strings; + +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;  import lombok.extern.slf4j.Slf4j;  import net.shibboleth.utilities.java.support.codec.Base64Support; @@ -34,8 +37,6 @@ public class EaafHttpPostDecoder extends HTTPPostDecoder {        encodedMessage = getLastParameterFromRequest(request, "SAMLResponse");      } - -      if (Strings.isNullOrEmpty(encodedMessage)) {        log.info("Request did not contain either a SAMLRequest or "            + "SAMLResponse paramter.  Invalid request for SAML 2 HTTP POST binding."); @@ -54,14 +55,27 @@ public class EaafHttpPostDecoder extends HTTPPostDecoder {    }    /** -   * Always read the last parameter with this name from request to get a strict deterministic behavior. -   * <br><br> -   * <b><i>If more than one parameters with the same name exists, -   * this method always select the last parameter value.</i></b> +   * EAAF specific unmarshaller perform XML schema validation before unmarshalling +   * the SAML message. +   * +   */ +  @Override +  protected XMLObject unmarshallMessage(final InputStream messageStream) throws MessageDecodingException { +      return Saml2Utils.unmarshallMessage(messageStream); +       +  } + +  /** +   * Always read the last parameter with this name from request to get a strict +   * deterministic behavior. <br> +   * <br> +   * <b><i>If more than one parameters with the same name exists, this method +   * always select the last parameter value.</i></b>     * -   * @param request Incoming http request +   * @param request   Incoming http request     * @param paramName Name of the http parameter -   * @return the last parameter value with this name, or <code>null</code> if the parameter not exists +   * @return the last parameter value with this name, or <code>null</code> if the +   *         parameter not exists     */    @Nullable    private String getLastParameterFromRequest(@Nonnull HttpServletRequest request, @Nonnull String paramName) { diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java index e9140f26..16d73296 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/EaafHttpRedirectDeflateDecoder.java @@ -4,6 +4,7 @@ import java.io.InputStream;  import javax.servlet.http.HttpServletRequest; +import org.opensaml.core.xml.XMLObject;  import org.opensaml.messaging.context.MessageContext;  import org.opensaml.messaging.decoder.MessageDecodingException;  import org.opensaml.saml.common.SAMLObject; @@ -12,6 +13,8 @@ import org.opensaml.saml.common.xml.SAMLConstants;  import org.opensaml.saml.saml2.binding.decoding.impl.HTTPRedirectDeflateDecoder;  import com.google.common.base.Strings; + +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;  import lombok.extern.slf4j.Slf4j;  import net.shibboleth.utilities.java.support.net.URISupport;  import net.shibboleth.utilities.java.support.primitive.StringSupport; @@ -58,7 +61,7 @@ public class EaafHttpRedirectDeflateDecoder extends HTTPRedirectDeflateDecoder {        throw new MessageDecodingException(            "No SAMLRequest or SAMLResponse query path parameter, invalid SAML 2 HTTP Redirect message");      } - +          final SAMLObject samlMessage = (SAMLObject) unmarshallMessage(samlMessageIns);      messageContext.setMessage(samlMessage);      log.debug("Decoded SAML message"); @@ -66,6 +69,18 @@ public class EaafHttpRedirectDeflateDecoder extends HTTPRedirectDeflateDecoder {      populateBindingContext(messageContext);      setMessageContext(messageContext); +     +  } +   +  /** +   * EAAF specific unmarshaller perform XML schema validation before unmarshalling +   * the SAML message. +   * +   */ +  @Override +  protected XMLObject unmarshallMessage(final InputStream messageStream) throws MessageDecodingException { +      return Saml2Utils.unmarshallMessage(messageStream); +          }  } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/OpenSaml3ResourceAdapter.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/OpenSaml3ResourceAdapter.java new file mode 100644 index 00000000..2e45aea2 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/opensaml/OpenSaml3ResourceAdapter.java @@ -0,0 +1,85 @@ +package at.gv.egiz.eaaf.modules.pvp2.impl.opensaml; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; + +import net.shibboleth.utilities.java.support.resource.Resource; + +/** + * Adapter that connects a Spring {@link org.springframework.core.io.Resource} to a {@link Resource}. + *  + * @author tlenz + * + */ +public class OpenSaml3ResourceAdapter implements Resource { + +  private org.springframework.core.io.Resource internalResource; + +  public OpenSaml3ResourceAdapter(org.springframework.core.io.Resource resource) { +    this.internalResource = resource; +  } +   +  @Override +  public boolean exists() { +    return  internalResource.exists(); +  } + +  @Override +  public boolean isReadable() { +    return internalResource.isReadable(); +  } + +  @Override +  public boolean isOpen() { +    return internalResource.isOpen(); +  } + +  @Override +  public URL getURL() throws IOException { +    return internalResource.getURL(); +  } + +  @Override +  public URI getURI() throws IOException { +    return internalResource.getURI(); +  } + +  @Override +  public File getFile() throws IOException { +    return internalResource.getFile(); +  } + +  @Override +  public InputStream getInputStream() throws IOException { +    return internalResource.getInputStream(); +  } + +  @Override +  public long contentLength() throws IOException { +    return internalResource.contentLength(); +  } + +  @Override +  public long lastModified() throws IOException { +    return internalResource.lastModified(); +  } + +  @Override +  public Resource createRelativeResource(String relativePath) throws IOException { +    throw new IOException("This method is not supperted by this adapter"); +  } + +  @Override +  public String getFilename() { +    return internalResource.getFilename(); +  } + +  @Override +  public String getDescription() { +    return internalResource.getDescription(); +  } + +} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java index 8b1b041b..763c07f6 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/utils/Saml2Utils.java @@ -20,6 +20,7 @@  package at.gv.egiz.eaaf.modules.pvp2.impl.utils;  import java.io.IOException; +import java.io.InputStream;  import java.security.PrivateKey;  import java.security.interfaces.ECPrivateKey;  import java.security.interfaces.ECPublicKey; @@ -36,12 +37,6 @@ import javax.xml.transform.dom.DOMSource;  import javax.xml.validation.Schema;  import javax.xml.validation.Validator; -import at.gv.egiz.eaaf.core.impl.utils.Random; -import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; -import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; -import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; -import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; -  import org.apache.commons.collections4.CollectionUtils;  import org.apache.commons.lang3.StringUtils;  import org.opensaml.core.xml.XMLObject; @@ -49,8 +44,12 @@ import org.opensaml.core.xml.XMLObjectBuilderFactory;  import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;  import org.opensaml.core.xml.io.Marshaller;  import org.opensaml.core.xml.io.MarshallingException; +import org.opensaml.core.xml.io.Unmarshaller; +import org.opensaml.core.xml.io.UnmarshallingException;  import org.opensaml.core.xml.schema.XSString;  import org.opensaml.core.xml.schema.impl.XSStringBuilder; +import org.opensaml.core.xml.util.XMLObjectSupport; +import org.opensaml.messaging.decoder.MessageDecodingException;  import org.opensaml.saml.common.SAMLObjectContentReference;  import org.opensaml.saml.common.xml.SAMLSchemaBuilder;  import org.opensaml.saml.common.xml.SAMLSchemaBuilder.SAML1Version; @@ -80,6 +79,18 @@ import org.opensaml.xmlsec.signature.support.Signer;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory;  import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import at.gv.egiz.eaaf.core.impl.utils.DomUtils; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.credential.EaafX509Credential; +import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EaafRequestedAttribute; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; +import net.shibboleth.utilities.java.support.xml.QNameSupport; +import net.shibboleth.utilities.java.support.xml.SerializeSupport;  public class Saml2Utils {    private static final Logger log = LoggerFactory.getLogger(Saml2Utils.class); @@ -153,6 +164,54 @@ public class Saml2Utils {    }    /** +   * SAML2 message unmarshaller that performs schema validation before unmarshall the message. +   *  +   * @param messageStream SAML2 message that shoulld be unmarshalled +   * @return OpenSAML XML object +   * @throws MessageDecodingException In case of a schema-validation or unmarshalling error +   */ +  public static XMLObject unmarshallMessage(final InputStream messageStream) throws MessageDecodingException { +    try { +      final Element samlElement = DomUtils.parseXmlValidating(messageStream); + +      if (log.isTraceEnabled()) { +        log.trace("Resultant DOM message was:"); +        log.trace(SerializeSupport.nodeToString(samlElement)); +      } + +      log.debug("Unmarshalling DOM parsed from InputStream"); +      final Unmarshaller unmarshaller = XMLObjectSupport.getUnmarshaller(samlElement); +      if (unmarshaller == null) { +        log.error("Unable to unmarshall InputStream, no unmarshaller registered for element " +            + QNameSupport.getNodeQName(samlElement)); +        throw new UnmarshallingException( +            "Unable to unmarshall InputStream, no unmarshaller registered for element " +                + QNameSupport.getNodeQName(samlElement)); +      } + +      final XMLObject message = unmarshaller.unmarshall(samlElement); + +      log.debug("InputStream succesfully unmarshalled"); + +      return message; + +    } catch (final UnmarshallingException e) { +      log.error("Error unmarshalling message from input stream", e); +      throw new MessageDecodingException("Error unmarshalling message from input stream", e); + +    } catch (ParserConfigurationException | SAXException e) { +      log.warn("Message schema-validation failed."); +      throw new MessageDecodingException("Message schema-validation failed.",  +          new SchemaValidationException("internal.pvp.03", new Object[] { e.getMessage() }, e)); + +    } catch (final IOException e) { +      log.error("Error read message from input stream", e); +      throw new MessageDecodingException("Error read message from input stream", e); +       +    } +  } +   +  /**     * Select signature algorithm for a given credential.     *     * @param credentials {@link X509Credential} that will be used for signing diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java deleted file mode 100644 index 380e735c..00000000 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/AbstractRequestSignedSecurityPolicyRule.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * 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: - * 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. -*/ - -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 at.gv.egiz.eaaf.modules.pvp2.exception.SchemaValidationException; - -import org.apache.commons.lang3.StringUtils; -import org.opensaml.core.criterion.EntityIdCriterion; -import org.opensaml.saml.common.SignableSAMLObject; -import org.opensaml.saml.common.xml.SAMLConstants; -import org.opensaml.saml.common.xml.SAMLSchemaBuilder; -import org.opensaml.saml.common.xml.SAMLSchemaBuilder.SAML1Version; -import org.opensaml.saml.security.impl.SAMLSignatureProfileValidator; -import org.opensaml.security.MetadataCriteria; -import org.opensaml.security.credential.UsageType; -import org.opensaml.security.criteria.UsageCriterion; -import org.opensaml.ws.security.SecurityPolicyException; -import org.opensaml.ws.security.SecurityPolicyRule; -import org.opensaml.xmlsec.signature.support.SignatureTrustEngine; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; - -import net.shibboleth.utilities.java.support.resolver.CriteriaSet; - -/** - * Signature Policy for SAML2 redirect-binding. - * - * @author tlenz - * - */ -public abstract class AbstractRequestSignedSecurityPolicyRule implements SecurityPolicyRule { - -  private static final Logger log = -      LoggerFactory.getLogger(AbstractRequestSignedSecurityPolicyRule.class); - -  private static SAMLSchemaBuilder schemaBuilder = new SAMLSchemaBuilder(SAML1Version.SAML_11); - -  private SignatureTrustEngine trustEngine = null; -  private QName peerEntityRole = null; - -  /** -   * Role initializer. -   * -   * @param peerEntityRole -   * -   */ -  public AbstractRequestSignedSecurityPolicyRule(final SignatureTrustEngine trustEngine, -      final QName peerEntityRole) { -    this.trustEngine = trustEngine; -    this.peerEntityRole = peerEntityRole; - -  } - -  /** -   * Reload the PVP metadata for a given entity. -   * -   * @param entityID for which the metadata should be refreshed. -   * @return true if the refresh was successful, otherwise false -   */ -  protected abstract boolean refreshMetadataProvider(String entityID); - -  protected abstract SignableSAMLObject getSignedSamlObject(XMLObject inboundData); - -  /* -   * (non-Javadoc) -   * -   * @see -   * org.opensaml.ws.security.SecurityPolicyRule#evaluate(org.opensaml.ws.message. -   * MessageContext) -   */ -  @Override -  public void evaluate(final MessageContext context) throws SecurityPolicyException { -    try { -      verifySignature(context); - -    } catch (final SecurityPolicyException e) { -      if (StringUtils.isEmpty(context.getInboundMessageIssuer())) { -        throw e; - -      } -      log.debug("PVP2X message validation FAILED. Reload metadata for entityID: " -          + context.getInboundMessageIssuer()); -      if (!refreshMetadataProvider(context.getInboundMessageIssuer())) { -        throw e; -      } else { -        log.trace("PVP2X metadata reload finished. Check validate message again."); -        verifySignature(context); - -      } -      log.trace("Second PVP2X message validation finished"); - -    } - -  } - -  private void verifySignature(final MessageContext context) throws SecurityPolicyException { -    final SignableSAMLObject samlObj = getSignedSamlObject(context.getInboundMessage()); -    if (samlObj != null && samlObj.getSignature() != null) { - -      final SAMLSignatureProfileValidator profileValidator = new SAMLSignatureProfileValidator(); -      try { -        profileValidator.validate(samlObj.getSignature()); -        performSchemaValidation(samlObj.getDOM()); - -      } catch (final ValidationException e) { -        log.warn("Signature is not conform to SAML signature profile", e); -        throw new SecurityPolicyException("Signature is not conform to SAML signature profile"); - -      } catch (final SchemaValidationException e) { -        log.warn("Signature is not conform to SAML signature profile", e); -        throw new SecurityPolicyException("Signature is not conform to SAML signature profile"); - -      } - -      final CriteriaSet criteriaSet = new CriteriaSet(); -      criteriaSet.add(new EntityIdCriterion(context.getInboundMessageIssuer())); -      criteriaSet.add(new MetadataCriteria(peerEntityRole, SAMLConstants.SAML20P_NS)); -      criteriaSet.add(new UsageCriterion(UsageType.SIGNING)); - -      try { -        if (!trustEngine.validate(samlObj.getSignature(), criteriaSet)) { -          throw new SecurityPolicyException("Signature validation FAILED."); - -        } -        log.debug("PVP message signature valid."); - -      } catch (final org.opensaml.xml.security.SecurityException e) { -        log.info("PVP2x message signature validation FAILED. Message:" + e.getMessage()); -        throw new SecurityPolicyException("Signature validation FAILED."); - -      } - -    } else { -      throw new SecurityPolicyException("PVP Message is not signed."); - -    } - -  } - -  private void performSchemaValidation(final Element source) throws SchemaValidationException { - -    String err = null; -    try { -      final Schema test = schemaBuilder.getSAMLSchema(); -      final Validator val = test.newValidator(); -      val.validate(new DOMSource(source)); -      log.debug("Schema validation check done OK"); -      return; - -    } catch (final 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 (final 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 }); - -  } - -} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSignedRequestPolicyRule.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSignedRequestPolicyRule.java deleted file mode 100644 index 9c02221c..00000000 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/verification/PvpSignedRequestPolicyRule.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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: - * 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. -*/ - -package at.gv.egiz.eaaf.modules.pvp2.impl.verification; - -import javax.xml.namespace.QName; - -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; - -import org.opensaml.saml.common.SignableSAMLObject; -import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.xmlsec.signature.support.SignatureTrustEngine; - -public class PvpSignedRequestPolicyRule extends AbstractRequestSignedSecurityPolicyRule { - -  private IRefreshableMetadataProvider metadataProvider = null; - -  /** -   * EAAF specific signature rule for OpenSAML2 redirect-binding. -   * -   * @param metadataProvider SAML2 metadata provider -   * @param trustEngine      SAML2 TrustEngine -   * @param peerEntityRole   Role of the Entity -   */ -  public PvpSignedRequestPolicyRule(final MetadataProvider metadataProvider, -      final SignatureTrustEngine trustEngine, final QName peerEntityRole) { -    super(trustEngine, peerEntityRole); -    if (metadataProvider instanceof IRefreshableMetadataProvider) { -      this.metadataProvider = (IRefreshableMetadataProvider) metadataProvider; -    } - -  } - -  /* -   * (non-Javadoc) -   * -   * @see at.gv.egovernment.moa.id.protocols.pvp2x.validation. -   * AbstractRequestSignedSecurityPolicyRule# -   * refreshMetadataProvider(java.lang.String) -   */ -  @Override -  protected boolean refreshMetadataProvider(final String entityID) { -    if (metadataProvider != null) { -      return metadataProvider.refreshMetadataProvider(entityID); -    } - -    return false; - -  } - -  /* -   * (non-Javadoc) -   * -   * @see at.gv.egovernment.moa.id.protocols.pvp2x.validation. -   * AbstractRequestSignedSecurityPolicyRule# -   * getSignedSAMLObject(org.opensaml.xml.XMLObject) -   */ -  @Override -  protected SignableSAMLObject getSignedSamlObject(final XMLObject inboundData) { -    if (inboundData instanceof SignableSAMLObject) { -      return (SignableSAMLObject) inboundData; -    } else { -      return null; -    } -  } - -} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/eaaf_pvp.beans.xml b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/eaaf_pvp.beans.xml index 2d5dc6ea..a2b52fbc 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/eaaf_pvp.beans.xml +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/eaaf_pvp.beans.xml @@ -13,6 +13,9 @@    <bean id="pvpLogMessageSource"          class="at.gv.egiz.eaaf.modules.pvp2.impl.logging.PvpModuleMessageSource" /> +  <bean id="pvpMetadataResolverFactory" +        class="at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory"/> +    <bean id="PVPMetadataBuilder"          class="at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpMetadataBuilder" /> diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/messages/pvp_messages.properties b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/messages/pvp_messages.properties index 6e647bd0..cee622c2 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/messages/pvp_messages.properties +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/resources/messages/pvp_messages.properties @@ -1,6 +1,9 @@  internal.pvp.00=KeyStore: {0} Key with alias: {0} not found or contains no PrivateKey.  internal.pvp.01=KeyStore: {0} contains an unsupported key with alias: {1}  internal.pvp.02=PVP message contains no signature. +internal.pvp.03=Schema-validation of SAML2 message failed with error: {0} +internal.pvp.04=Can not initialize metadata provider for metadata: {0} +internal.pvp.05=Can not initialize metadata provider for metadata: {0}. Reason: {1}  internal.pvp.95=OpenSAML {0}-binding message {1} failed. Reason: {2}  internal.pvp.96=OpenSAML signing FAILED with key: {0}. Reason: {1} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/RedirectBindingTest.java b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/RedirectBindingTest.java index 80dfc400..a99c8461 100644 --- a/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/RedirectBindingTest.java +++ b/eaaf_modules/eaaf_module_pvp2_core/src/test/java/at/gv/egiz/eaaf/modules/pvp2/test/binding/RedirectBindingTest.java @@ -6,18 +6,6 @@ import java.util.Base64;  import javax.xml.parsers.ParserConfigurationException; -import at.gv.egiz.eaaf.core.api.IRequest; -import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; -import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; -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.CredentialsNotAvailableException; -import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; -import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; -import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; -import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EaafUriCompare; -import at.gv.egiz.eaaf.modules.pvp2.test.dummy.DummyCredentialProvider; -  import org.apache.commons.io.IOUtils;  import org.apache.commons.lang3.RandomStringUtils;  import org.junit.Assert; @@ -42,6 +30,18 @@ import org.springframework.test.context.TestPropertySource;  import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;  import org.xml.sax.SAXException; +import at.gv.egiz.eaaf.core.api.IRequest; +import at.gv.egiz.eaaf.core.impl.idp.module.test.TestRequestImpl; +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +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.CredentialsNotAvailableException; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; +import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.PvpMetadataResolverFactory; +import at.gv.egiz.eaaf.modules.pvp2.impl.opensaml.initialize.EaafOpenSaml3xInitializer; +import at.gv.egiz.eaaf.modules.pvp2.impl.validation.EaafUriCompare; +import at.gv.egiz.eaaf.modules.pvp2.test.dummy.DummyCredentialProvider;  import net.shibboleth.utilities.java.support.component.ComponentInitializationException;  import net.shibboleth.utilities.java.support.net.URIComparator;  import net.shibboleth.utilities.java.support.xml.XMLParserException; @@ -60,6 +60,7 @@ public class RedirectBindingTest {    @Autowired private RedirectBinding bindingImpl;    @Autowired private DummyCredentialProvider credentialProvider; +  @Autowired private PvpMetadataResolverFactory metadataResolverFactory;    protected MockHttpServletRequest httpReq;    protected MockHttpServletResponse httpResp; @@ -98,8 +99,10 @@ public class RedirectBindingTest {    @Test    public void decodeRequestSuccess() throws MessageDecodingException, SecurityException, IOException, Pvp2Exception {      final String serviceUrl = "http://testservice.org"; - -    final IPvp2MetadataProvider metadataProvider = null; +     +    final IPvp2MetadataProvider metadataProvider =  +        metadataResolverFactory.createMetadataProvider( +            "classpath:/data/metadata_1.xml", null, "jUnit metadata resolver", null);      final boolean isSpEndPoint = false;      final URIComparator comparator = new EaafUriCompare(serviceUrl); diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java index 74224dbe..200d98c4 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java @@ -23,6 +23,19 @@ import javax.annotation.PostConstruct;  import javax.servlet.http.HttpServletRequest;  import javax.servlet.http.HttpServletResponse; +import org.joda.time.DateTime; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.Assertion; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.opensaml.saml.saml2.core.Response; +import org.opensaml.saml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; +  import at.gv.egiz.eaaf.core.api.IRequest;  import at.gv.egiz.eaaf.core.api.idp.IAction;  import at.gv.egiz.eaaf.core.api.idp.IAuthData; @@ -44,20 +57,6 @@ import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest;  import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider;  import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; -import org.joda.time.DateTime; -import org.opensaml.messaging.encoder.MessageEncodingException; -import org.opensaml.saml.common.xml.SAMLConstants; -import org.opensaml.saml.saml2.core.Assertion; -import org.opensaml.saml.saml2.core.AuthnRequest; -import org.opensaml.saml.saml2.core.Response; -import org.opensaml.saml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml.saml2.metadata.EntityDescriptor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.stereotype.Service; -  @Service("PVPAuthenticationRequestAction")  public class AuthenticationAction implements IAction {    private static final Logger log = LoggerFactory.getLogger(AuthenticationAction.class); @@ -142,7 +141,7 @@ public class AuthenticationAction implements IAction {        sloInformation.setSpEntityID(req.getServiceProviderConfiguration().getUniqueIdentifier());        return sloInformation; -    } catch (MessageEncodingException | SecurityException e) { +    } catch (SecurityException e) {        log.warn("Message Encoding exception", e);        throw new ResponderErrorException("pvp2.01", null, e); diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java index ac551612..8cafebb9 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java @@ -22,10 +22,6 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder;  import java.util.ArrayList;  import java.util.List; -import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; -import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; -  import org.joda.time.DateTime;  import org.opensaml.core.criterion.EntityIdCriterion;  import org.opensaml.saml.common.xml.SAMLConstants; @@ -38,17 +34,21 @@ import org.opensaml.saml.saml2.core.Response;  import org.opensaml.saml.saml2.encryption.Encrypter.KeyPlacement;  import org.opensaml.saml.saml2.metadata.SPSSODescriptor;  import org.opensaml.saml.security.impl.MetadataCredentialResolver; -import org.opensaml.saml2.metadata.provider.MetadataProvider;  import org.opensaml.security.MetadataCriteria;  import org.opensaml.security.credential.UsageType;  import org.opensaml.security.criteria.UsageCriterion;  import org.opensaml.security.x509.X509Credential;  import org.opensaml.xmlsec.EncryptionParameters; +import org.opensaml.xmlsec.encryption.support.EncryptionException;  import org.opensaml.xmlsec.encryption.support.KeyEncryptionParameters;  import org.opensaml.xmlsec.keyinfo.KeyInfoGeneratorFactory;  import org.slf4j.Logger;  import org.slf4j.LoggerFactory; +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils;  import net.shibboleth.utilities.java.support.resolver.CriteriaSet;  /** @@ -73,7 +73,7 @@ public class AuthResponseBuilder {     * @return PVP2 S-Profile authentication response     * @throws InvalidAssertionEncryptionException In case of an error     */ -  public static Response buildResponse(final MetadataProvider metadataProvider, +  public static Response buildResponse(final IPvp2MetadataProvider metadataProvider,        final String issuerEntityID, final RequestAbstractType req, final DateTime date,        final Assertion assertion, final boolean enableEncryption)        throws InvalidAssertionEncryptionException { | 
