From 41ea2fdf782cd64d7d29f73c2e83f9c255810818 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 2 Feb 2020 19:32:21 +0100 Subject: some more OpenSAML3 refactoring stuff --- .../impl/metadata/PvpMetadataResolverFactory.java | 271 +++++++++++++++++++++ 1 file changed, 271 insertions(+) create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java (limited to 'eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java') diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java new file mode 100644 index 00000000..f548bc7b --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/PvpMetadataResolverFactory.java @@ -0,0 +1,271 @@ +package at.gv.egiz.eaaf.modules.pvp2.impl.metadata; + +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 org.apache.http.client.HttpClient; +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.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; + +@Slf4j +public class PvpMetadataResolverFactory implements IDestroyableObject { + + private static final String URI_PREFIX_HTTP = "http:"; + private static final String URI_PREFIX_HTTPS = "https:"; + + 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. + * + * @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 ParserPool pool, @Nullable final HttpClient httpClient) { + + ExtendedRefreshableMetadataResolver internalProvider = null; + + if (metadataLocation.startsWith(URI_PREFIX_HTTP) + || metadataLocation.startsWith(URI_PREFIX_HTTPS)) { + if (httpClient != null) { + internalProvider = createNewHttpMetaDataProvider(metadataLocation, filter, idForLogging, timer, pool, + httpClient); + } else { + log.warn("Can not load http(s) based SAML2 metadata without a HTTP client"); + + } + + } else { + String absoluteMetadataLocation; + try { + absoluteMetadataLocation = + FileUtils.makeAbsoluteUrl(metadataLocation, authConfig.getConfigurationRootDirectory()); + + 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"); + + } + + + } catch (final IOException e) { + log.warn("SAML2 metadata URL is invalid: " + metadataLocation, e); + + } + } + + if (internalProvider != null) { + return new PvpMetadataResolverAdapter(internalProvider); + + } else { + log.warn("SAML2 metadata has an unsupported metadata location prefix: " + metadataLocation); + return null; + + } + + } + + /** + * Create a single SAML2 filesystem based metadata provider. + * + * @param metadataFile File, where the metadata should be loaded + * @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 pool + * + * @return SAML2 Metadata Provider + * @throws IOException + */ + private ExtendedRefreshableMetadataResolver createNewFileSystemMetaDataProvider(final Resource metadataFile, + final MetadataFilter filter, final String idForLogging, final Timer timer, + final ParserPool pool) throws IOException { + ResourceBackedMetadataResolver fileSystemResolver = null; + try { + //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.getURI().toASCIIString()); + + fileSystemResolver.setRequireValidMetadata(true); + + return fileSystemResolver; + + } catch (final Exception e) { + log.warn("Failed to load Metadata file for " + idForLogging + "[ " + "File: " + + metadataFile.getURI().toASCIIString() + " Msg: " + e.getMessage() + " ]", e); + + log.warn("Can not initialize SAML2 metadata provider from filesystem: " + + metadataFile.getURI().toASCIIString() + " Reason: " + e.getMessage(), e); + + if (fileSystemResolver != null) { + fileSystemResolver.destroy(); + + } + + } + + return null; + + } + + /** + * Create a single SAML2 HTTP metadata provider. + * + * @param metadataUrl URL, where the metadata should be loaded + * @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 pool + * + * @return SAML2 Metadata Provider + */ + private ExtendedRefreshableMetadataResolver createNewHttpMetaDataProvider(final String metadataUrl, + final MetadataFilter filter, final String idForLogging, final Timer timer, + final ParserPool pool, final HttpClient httpClient) { + HTTPMetadataResolver httpMetadataResolver = null; + try { + httpMetadataResolver = new HTTPMetadataResolver(timer, httpClient, metadataUrl); + httpMetadataResolver.setParserPool(pool); + httpMetadataResolver.setRequireValidMetadata(true); + httpMetadataResolver.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes + httpMetadataResolver.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours + // httpProvider.setRefreshDelayFactor(0.1F); + + httpMetadataResolver.setMetadataFilter(filter); + httpMetadataResolver.setId(metadataUrl); + httpMetadataResolver.initialize(); + + httpMetadataResolver.setRequireValidMetadata(true); + + return httpMetadataResolver; + + } catch (final Throwable e) { + if (e.getCause() != null && e.getCause().getCause() instanceof SSLHandshakeException) { + log.warn("SSL-Server certificate for metadata " + metadataUrl + " not trusted.", e); + + } + if (e.getCause() != null && e.getCause().getCause() instanceof SignatureValidationException) { + log.warn("Signature verification for metadata" + metadataUrl + " FAILED.", e); + + } + if (e.getCause() != null && e.getCause().getCause() instanceof SchemaValidationException) { + log.warn("Schema validation for metadata " + metadataUrl + " FAILED.", e); + } + + log.warn("Failed to load Metadata file for " + idForLogging + "[ " + e.getMessage() + " ]", + e); + + if (httpMetadataResolver != null) { + log.debug("Destroy failed Metadata provider"); + httpMetadataResolver.destroy(); + + } + + } + + 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"); + + } + +} -- cgit v1.2.3