From d41afe91ee59daf6b5f5037cecac52900fe2ccb2 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 31 Jan 2020 20:41:54 +0100 Subject: a lot of more OpenSAML3 refactoring staff This version is also NOT stable! --- .../metadata/AbstractChainingMetadataProvider.java | 253 +++++++++------------ .../pvp2/impl/metadata/MetadataFilterChain.java | 76 ------- .../pvp2/impl/metadata/SimpleMetadataProvider.java | 231 ------------------- .../pvp2/impl/metadata/SimpleMetadataResolver.java | 243 ++++++++++++++++++++ 4 files changed, 348 insertions(+), 455 deletions(-) delete mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/MetadataFilterChain.java delete mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataProvider.java create mode 100644 eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataResolver.java (limited to 'eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata') 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 4a9bb89a..ec59b1df 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 @@ -21,48 +21,59 @@ package at.gv.egiz.eaaf.modules.pvp2.impl.metadata; import java.io.IOException; import java.security.cert.CertificateException; -import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; 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.naming.ConfigurationException; import javax.xml.namespace.QName; -import org.apache.commons.lang3.StringUtils; -import org.opensaml.saml2.metadata.EntitiesDescriptor; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.RoleDescriptor; -import org.opensaml.saml2.metadata.provider.ChainingMetadataProvider; -import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; -import org.opensaml.saml2.metadata.provider.MetadataFilter; -import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.saml2.metadata.provider.MetadataProviderException; -import org.opensaml.saml2.metadata.provider.ObservableMetadataProvider; -import org.opensaml.xml.XMLObject; -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.IPvpMetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IRefreshableMetadataProvider; -public abstract class AbstractChainingMetadataProvider extends SimpleMetadataProvider - implements ObservableMetadataProvider, IGarbageCollectorProcessing, - IRefreshableMetadataProvider, IDestroyableObject, IPvpMetadataProvider { +import org.apache.commons.lang3.StringUtils; +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 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); - private MetadataProvider internalProvider = null; + @Nonnull @NonnullElements private final List internalResolvers; private static Object mutex = new Object(); private Timer timer = null; + /** + * Build a chaining metadata resolver that requires valid metadata. + * + */ public AbstractChainingMetadataProvider() { - internalProvider = new ChainingMetadataProvider(); + internalResolvers = Collections.synchronizedList(Collections.emptyList()); } @@ -102,30 +113,34 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro } + + @Override - public synchronized boolean refreshMetadataProvider(final String entityID) { + public synchronized boolean refreshMetadataProvider(final String entityId) { try { // check if metadata provider is already loaded try { - if (internalProvider.getEntityDescriptor(entityID) != null) { + if (resolveEntityDescripor(entityId) != null) { return true; + } - } catch (final MetadataProviderException e) { - log.debug("Metadata for EntityId: {} is not valid. Starting refresh ... ", entityID); + } catch (final ResolverException e) { + log.debug("Metadata for EntityId: {} is not valid. Starting refresh ... ", entityId); } // reload metadata provider - final String metadataUrl = getMetadataUrl(entityID); + final String metadataUrl = getMetadataUrl(entityId); if (StringUtils.isNotEmpty(metadataUrl)) { - final Map actuallyLoadedProviders = - getAllActuallyLoadedProviders(); + final Map actuallyLoadedResolver = + getAllActuallyLoadedResolvers(); // check if MetadataProvider is actually loaded - if (actuallyLoadedProviders.containsKey(metadataUrl)) { - actuallyLoadedProviders.get(metadataUrl).refresh(); - log.info("SAML2 metadata for service provider: " + entityID + " is refreshed."); + final MetadataResolver loadedResover = actuallyLoadedResolver.get(metadataUrl); + if (loadedResover instanceof RefreshableMetadataResolver) { + ((RefreshableMetadataResolver)loadedResover).refresh(); + log.info("SAML2 metadata for service provider: " + entityId + " is refreshed."); return true; } else { @@ -134,32 +149,20 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro timer = new Timer(true); } - final ChainingMetadataProvider chainProvider = - (ChainingMetadataProvider) internalProvider; - chainProvider.addMetadataProvider(createNewMetadataProvider(entityID)); + internalResolvers.add(createNewMetadataProvider(metadataUrl)); - emitChangeEvent(); - log.info("SAML2 metadata for service provider: " + entityID + " is added."); + log.info("SAML2 metadata for service provider: " + entityId + " is added."); return true; } } else { log.debug( - "Can not refresh SAML2 metadata: NO SAML2 metadata URL for SP with Id: " + entityID); + "Can not refresh SAML2 metadata: NO SAML2 metadata URL for SP with Id: " + entityId); } - } catch (final MetadataProviderException e) { - log.warn("Refresh SAML2 metadata for service provider: " + entityID + " FAILED.", e); - - } catch (final IOException e) { - log.warn("Refresh SAML2 metadata for service provider: " + entityID + " FAILED.", e); - - } catch (final EaafConfigurationException e) { - log.warn("Refresh SAML2 metadata for service provider: " + entityID + " FAILED.", e); - - } catch (final CertificateException e) { - log.warn("Refresh SAML2 metadata for service provider: " + entityID + " FAILED.", e); + } catch (final IOException | ResolverException | EaafConfigurationException | CertificateException e) { + log.warn("Refresh SAML2 metadata for service provider: " + entityId + " FAILED.", e); } @@ -172,55 +175,20 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro * */ public void internalDestroy() { - if (internalProvider != null && internalProvider instanceof ChainingMetadataProvider) { - log.info("Destrorying PVP-Authentication MetaDataProvider."); - final ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider; - - final List providers = chainProvider.getProviders(); - for (final MetadataProvider provider : providers) { - if (provider instanceof HTTPMetadataProvider) { - final HTTPMetadataProvider httpprovider = (HTTPMetadataProvider) provider; - log.debug("Destroy HTTPMetadataProvider +" + httpprovider.getMetadataURI()); - httpprovider.destroy(); + log.info("Destroying chained metadata resolvers ..."); - } else { - log.warn("MetadataProvider can not be destroyed."); - } + for (final MetadataResolver resolver : internalResolvers) { + destroyMetadataResolver(resolver); } - internalProvider = new ChainingMetadataProvider(); + internalResolvers.clear(); if (timer != null) { timer.cancel(); } - } else { - log.warn( - "ReInitalize MOAMetaDataProvider is not possible! MOA-ID Instance has to be restarted manualy"); - } } - /* - * (non-Javadoc) - * - * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider# - * requireValidMetadata() - */ - @Override - public boolean requireValidMetadata() { - return internalProvider.requireValidMetadata(); - } - - /* - * (non-Javadoc) - * - * @see at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IEAAFMetadataProvider# - * setRequireValidMetadata (boolean) - */ - @Override - public void setRequireValidMetadata(final boolean requireValidMetadata) { - internalProvider.setRequireValidMetadata(requireValidMetadata); - } /* * (non-Javadoc) @@ -359,18 +327,6 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro return result; } - /* - * (non-Javadoc) - * - * @see - * org.opensaml.saml2.metadata.provider.ObservableMetadataProvider#getObservers( - * ) - */ - @Override - public List getObservers() { - return ((ChainingMetadataProvider) internalProvider).getObservers(); - } - /** * Get the URL to metadata for a specific entityID. * @@ -384,13 +340,13 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro * Creates a new implementation specific SAML2 metadata provider. * * @param entityId EntityId - * @return MetadataProvider + * @return MetadataResolver * @throws EaafConfigurationException In case of an error * @throws IOException In case of an error * @throws CertificateException In case of an error * @throws ConfigurationException In case of an error */ - protected abstract MetadataProvider createNewMetadataProvider(String entityId) + protected abstract MetadataResolver createNewMetadataProvider(String entityId) throws EaafConfigurationException, IOException, CertificateException; /** @@ -398,33 +354,25 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro * * @throws EaafConfigurationException In case of an error */ + @Nonnull protected abstract List getAllMetadataUrlsFromConfiguration() throws EaafConfigurationException; - protected void emitChangeEvent() { - if (getObservers() == null || getObservers().size() == 0) { - return; - } - - final List tempObserverList = new ArrayList<>(getObservers()); - for (final ObservableMetadataProvider.Observer observer : tempObserverList) { - if (observer != null) { - observer.onEvent(this); - } - } - } - private Map getAllActuallyLoadedProviders() { - final Map loadedproviders = + private Map getAllActuallyLoadedResolvers() { + final Map loadedproviders = new HashMap<>(); - final ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider; // make a Map of all actually loaded HTTPMetadataProvider - final List providers = chainProvider.getProviders(); - for (final MetadataProvider provider : providers) { - if (provider instanceof HTTPMetadataProvider) { - final HTTPMetadataProvider httpprovider = (HTTPMetadataProvider) provider; - loadedproviders.put(httpprovider.getMetadataURI(), httpprovider); + for (final MetadataResolver resolver : internalResolvers) { + if (resolver instanceof IdentifiedComponent) { + loadedproviders.put(((IdentifiedComponent) resolver).getId(), resolver); + + } else { + final String uuid = UUID.randomUUID().toString(); + loadedproviders.put(uuid, resolver); + log.debug("MetadatenResolver is not of type: {}. Mark it with id: {}", + IdentifiedComponent.class.getSimpleName(), uuid); } } @@ -433,19 +381,17 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro } private void addAndRemoveMetadataProvider() throws EaafConfigurationException { - if (internalProvider != null && internalProvider instanceof ChainingMetadataProvider) { - log.info("Reload MOAMetaDataProvider."); + log.info("EAAF chaining metadata resolver starting internal managment task .... "); /* * OpenSAML ChainingMetadataProvider can not remove a MetadataProvider * (UnsupportedOperationException) The ChainingMetadataProvider use internal a * unmodifiableList to hold all registrated MetadataProviders. */ - final Map providersinuse = new HashMap<>(); - final ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider; + final Map providersinuse = new HashMap<>(); // get all actually loaded metadata providers - final Map loadedproviders = getAllActuallyLoadedProviders(); + final Map loadedproviders = getAllActuallyLoadedResolvers(); /* * TODO: maybe add metadata provider destroy after timeout. But could be a @@ -460,7 +406,6 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro // compare actually loaded Providers with configured SAML2 SPs final List allMetadataUrls = getAllMetadataUrlsFromConfiguration(); - if (allMetadataUrls != null) { final Iterator metadataUrlInterator = allMetadataUrls.iterator(); while (metadataUrlInterator.hasNext()) { final String metadataurl = metadataUrlInterator.next(); @@ -477,15 +422,15 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro } } - } + // remove all actually loaded MetadataProviders with are not in ConfigurationDB // any more - final Collection notusedproviders = loadedproviders.values(); - for (final HTTPMetadataProvider provider : notusedproviders) { - final String metadataurl = provider.getMetadataURI(); - try { - provider.destroy(); + final Collection notusedproviders = loadedproviders.values(); + for (final MetadataResolver resolver : notusedproviders) { + log.info("Remove not used MetadataProvider with MetadataURL " + resolver.getId()); + destroyMetadataResolver(resolver); + internalResolvers.remove(resolver); /* * OpenSAML ChainingMetadataProvider can not remove a MetadataProvider @@ -493,31 +438,43 @@ public abstract class AbstractChainingMetadataProvider extends SimpleMetadataPro * unmodifiableList to hold all registrated MetadataProviders. */ // chainProvider.removeMetadataProvider(provider); - log.info("Remove not used MetadataProvider with MetadataURL " + metadataurl); - } catch (final Throwable e) { - log.error("HTTPMetadataProvider with URL " + metadataurl - + " can not be removed from the list of actually loaded Providers.", e); - - } } + } + + private EntityDescriptor resolveEntityDescripor(String entityId) throws ResolverException { + final CriteriaSet criteria = new CriteriaSet(); + criteria.add(new EntityIdCriterion(entityId)); + for (final MetadataResolver resolver : internalResolvers) { try { - chainProvider.setProviders(new ArrayList<>(providersinuse.values())); - emitChangeEvent(); + final EntityDescriptor descriptors = resolver.resolveSingle(criteria); + if (descriptors != null) { + return descriptors; + } - } catch (final MetadataProviderException e) { - log.warn( - "ReInitalize AbstractMetaDataProvider is not possible! Service has to be restarted manualy", - e); + } catch (final ResolverException e) { + continue; } - } else { - log.warn( - "ReInitalize AbstractMetaDataProvider is not possible! Service has to be restarted manualy"); } + return null; + + } + + private void destroyMetadataResolver(MetadataResolver resolver) { + if (resolver instanceof AbstractMetadataResolver) { + final AbstractMetadataResolver httpprovider = (AbstractMetadataResolver) resolver; + log.debug("Destroy metadata resolver with id: {}", httpprovider.getId()); + httpprovider.destroy(); + + } else { + log.warn("Metadata resolver: {} can not be destroyed. Reason: unsupported type: {}", + resolver.getId(), resolver.getClass().getName()); + + } } } diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/MetadataFilterChain.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/MetadataFilterChain.java deleted file mode 100644 index ebc057df..00000000 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/MetadataFilterChain.java +++ /dev/null @@ -1,76 +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.metadata; - -import java.util.ArrayList; -import java.util.List; - -import org.opensaml.saml2.metadata.provider.FilterException; -import org.opensaml.saml2.metadata.provider.MetadataFilter; -import org.opensaml.xml.XMLObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Metadata filter-chain implementation. - * - * @author tlenz - * - */ -public class MetadataFilterChain implements MetadataFilter { - private static final Logger log = LoggerFactory.getLogger(MetadataFilterChain.class); - - private final List filters = new ArrayList<>(); - - /** - * Return all actually used Metadata filters. - * - * @return List of Metadata filters - */ - public List getFilters() { - return filters; - } - - /** - * Add a new Metadata filter to filterchain. - * - * @param filter add a metadata filter - */ - public void addFilter(final MetadataFilter filter) { - filters.add(filter); - } - - /* - * (non-Javadoc) - * - * @see - * org.opensaml.saml2.metadata.provider.MetadataFilter#doFilter(org.opensaml.xml - * .XMLObject) - */ - @Override - public void doFilter(final XMLObject arg0) throws FilterException { - for (final MetadataFilter filter : filters) { - log.trace("Use EAAFMetadataFilter " + filter.getClass().getName()); - filter.doFilter(arg0); - } - - } - -} diff --git a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataProvider.java b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataProvider.java deleted file mode 100644 index d63950cb..00000000 --- a/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataProvider.java +++ /dev/null @@ -1,231 +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.metadata; - -import java.io.File; -import java.net.MalformedURLException; -import java.util.Timer; - -import javax.net.ssl.SSLHandshakeException; - -import org.apache.commons.httpclient.HttpClient; -import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider; -import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; -import org.opensaml.saml2.metadata.provider.MetadataFilter; -import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.xml.parse.ParserPool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; - -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; - -/** - * Simple SAML2 metadata provider. - * - * @author tlenz - * - */ -public abstract class SimpleMetadataProvider implements MetadataProvider { - private static final Logger log = LoggerFactory.getLogger(SimpleMetadataProvider.class); - - 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; - - /** - * 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 timer {@link Timer} which is used to schedule metadata - * refresh operations - * @param httpClient Apache commons 3.x http client - * - * @return SAML2 Metadata Provider, or null if the metadata provider can not - * initialized - */ - protected MetadataProvider createNewSimpleMetadataProvider(final String metadataLocation, - final MetadataFilter filter, final String idForLogging, final Timer timer, - final ParserPool pool, final HttpClient httpClient) { - if (metadataLocation.startsWith(URI_PREFIX_HTTP) - || metadataLocation.startsWith(URI_PREFIX_HTTPS)) { - if (httpClient != null) { - return 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 { - String absoluteMetadataLocation; - try { - 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, - pool); - } else { - log.warn( - "SAML2 metadata file: " + absoluteMetadataLocation + " not found or not exist"); - return null; - } - - } - - } catch (final MalformedURLException e) { - log.warn("SAML2 metadata URL is invalid: " + metadataLocation, e); - - } - - } - - 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 - */ - private MetadataProvider createNewFileSystemMetaDataProvider(final File metadataFile, - final MetadataFilter filter, final String idForLogging, final Timer timer, - final ParserPool pool) { - FilesystemMetadataProvider fileSystemProvider = null; - try { - fileSystemProvider = new FilesystemMetadataProvider(timer, metadataFile); - fileSystemProvider.setParserPool(pool); - fileSystemProvider.setRequireValidMetadata(true); - fileSystemProvider.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes - fileSystemProvider.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours - // httpProvider.setRefreshDelayFactor(0.1F); - - fileSystemProvider.setMetadataFilter(filter); - fileSystemProvider.initialize(); - - fileSystemProvider.setRequireValidMetadata(true); - - return fileSystemProvider; - - } catch (final Exception e) { - log.warn("Failed to load Metadata file for " + idForLogging + "[ " + "File: " - + metadataFile.getAbsolutePath() + " Msg: " + e.getMessage() + " ]", e); - - log.warn("Can not initialize SAML2 metadata provider from filesystem: " - + metadataFile.getAbsolutePath() + " Reason: " + e.getMessage(), e); - - if (fileSystemProvider != null) { - fileSystemProvider.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 MetadataProvider createNewHttpMetaDataProvider(final String metadataUrl, - final MetadataFilter filter, final String idForLogging, final Timer timer, - final ParserPool pool, final HttpClient httpClient) { - HTTPMetadataProvider httpProvider = null; - try { - httpProvider = new HTTPMetadataProvider(timer, httpClient, metadataUrl); - httpProvider.setParserPool(pool); - httpProvider.setRequireValidMetadata(true); - httpProvider.setMinRefreshDelay(1000 * 60 * 15); // 15 minutes - httpProvider.setMaxRefreshDelay(1000 * 60 * 60 * 24); // 24 hours - // httpProvider.setRefreshDelayFactor(0.1F); - - httpProvider.setMetadataFilter(filter); - httpProvider.initialize(); - - httpProvider.setRequireValidMetadata(true); - - return httpProvider; - - } 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 (httpProvider != null) { - log.debug("Destroy failed Metadata provider"); - httpProvider.destroy(); - } - - // if (timer != null) { - // log.debug("Destroy Timer."); - // timer.cancel(); - // } - - } - - return null; - } - -} 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/SimpleMetadataResolver.java new file mode 100644 index 00000000..35ad3f97 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_core/src/main/java/at/gv/egiz/eaaf/modules/pvp2/impl/metadata/SimpleMetadataResolver.java @@ -0,0 +1,243 @@ +/* + * 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.util.Timer; + +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.saml.metadata.resolver.filter.MetadataFilter; +import org.opensaml.saml.metadata.resolver.impl.FilesystemMetadataResolver; +import org.opensaml.saml.metadata.resolver.impl.HTTPMetadataResolver; +import org.springframework.beans.factory.annotation.Autowired; + +import lombok.extern.slf4j.Slf4j; +import net.shibboleth.utilities.java.support.xml.ParserPool; + +/** + * Simple SAML2 metadata provider. + * + * @author tlenz + * + */ +@Slf4j +public abstract class SimpleMetadataResolver implements MetadataResolver { + 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()); + + } + + + + /** + * 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 timer {@link Timer} which is used to schedule metadata + * refresh operations + * @param httpClient Apache commons 3.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) { + if (metadataLocation.startsWith(URI_PREFIX_HTTP) + || metadataLocation.startsWith(URI_PREFIX_HTTPS)) { + if (httpClient != null) { + return 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 { + String absoluteMetadataLocation; + try { + 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, + pool); + } else { + log.warn( + "SAML2 metadata file: " + absoluteMetadataLocation + " not found or not exist"); + return null; + } + + } + + } catch (final MalformedURLException e) { + log.warn("SAML2 metadata URL is invalid: " + metadataLocation, e); + + } + + } + + 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 + */ + private MetadataResolver createNewFileSystemMetaDataProvider(final File metadataFile, + final MetadataFilter filter, final String idForLogging, final Timer timer, + final ParserPool pool) { + FilesystemMetadataResolver fileSystemResolver = null; + try { + fileSystemResolver = new FilesystemMetadataResolver(timer, metadataFile); + fileSystemResolver.setParserPool(pool); + 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.setRequireValidMetadata(true); + + return fileSystemResolver; + + } catch (final Exception e) { + log.warn("Failed to load Metadata file for " + idForLogging + "[ " + "File: " + + metadataFile.getAbsolutePath() + " Msg: " + e.getMessage() + " ]", e); + + log.warn("Can not initialize SAML2 metadata provider from filesystem: " + + metadataFile.getAbsolutePath() + " 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 MetadataResolver 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; + } + +} -- cgit v1.2.3