/* * Copyright 2014 Federal Chancellery Austria * MOA-ID has been developed in a cooperation between BRZ, the Federal * Chancellery Austria - ICT staff unit, and Graz University of Technology. * * Licensed under the EUPL, Version 1.1 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: * http://www.osor.eu/eupl/ * * 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.egovernment.moa.id.auth.modules.eIDAScentralAuth.utils; import java.net.MalformedURLException; import java.util.List; import java.util.Timer; import javax.xml.namespace.QName; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.MOAHttpClient; import org.apache.commons.httpclient.params.HttpClientParams; 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.xml.XMLObject; import org.opensaml.xml.parse.BasicParserPool; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import at.gv.egiz.eaaf.core.api.IDestroyableObject; import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.MetadataFilterChain; import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.SimpleMetadataProvider; import at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata.SchemaValidationFilter; import at.gv.egovernment.moa.id.auth.modules.eIDAScentralAuth.EidasCentralAuthConstants; import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; import at.gv.egovernment.moa.id.commons.ex.MOAHttpProtocolSocketFactoryException; import at.gv.egovernment.moa.id.commons.utils.MOAHttpProtocolSocketFactory; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; import at.gv.egovernment.moa.id.protocols.pvp2x.verification.metadata.MOASPMetadataSignatureFilter; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; /** * @author tlenz * */ @Service("EidasCentralAuthMetadataProvider") public class EidasCentralAuthMetadataProvider extends SimpleMetadataProvider implements IDestroyableObject { @Autowired(required=true) AuthConfiguration moaAuthConfig; private ChainingMetadataProvider metadataProvider = new ChainingMetadataProvider(); private Timer timer = null; public EidasCentralAuthMetadataProvider() { metadataProvider.setRequireValidMetadata(true); } public void addMetadataWithMetadataURL(String metadataURL) throws MetadataProviderException { internalInitialize(metadataURL); } public void destroy() { fullyDestroy(); } /* (non-Javadoc) * @see org.opensaml.saml2.metadata.provider.MetadataProvider#requireValidMetadata() */ @Override public boolean requireValidMetadata() { return metadataProvider.requireValidMetadata(); } /* (non-Javadoc) * @see org.opensaml.saml2.metadata.provider.MetadataProvider#setRequireValidMetadata(boolean) */ @Override public void setRequireValidMetadata(boolean requireValidMetadata) { metadataProvider.setRequireValidMetadata(requireValidMetadata); } /* (non-Javadoc) * @see org.opensaml.saml2.metadata.provider.MetadataProvider#getMetadataFilter() */ @Override public MetadataFilter getMetadataFilter() { return metadataProvider.getMetadataFilter(); } /* (non-Javadoc) * @see org.opensaml.saml2.metadata.provider.MetadataProvider#setMetadataFilter(org.opensaml.saml2.metadata.provider.MetadataFilter) */ @Override public void setMetadataFilter(MetadataFilter newFilter) throws MetadataProviderException { Logger.fatal("Set Metadata Filter is not implemented her!"); } /* (non-Javadoc) * @see org.opensaml.saml2.metadata.provider.MetadataProvider#getMetadata() */ @Override public XMLObject getMetadata() throws MetadataProviderException { return metadataProvider.getMetadata(); } /* (non-Javadoc) * @see org.opensaml.saml2.metadata.provider.MetadataProvider#getEntitiesDescriptor(java.lang.String) */ @Override public EntitiesDescriptor getEntitiesDescriptor(String name) throws MetadataProviderException { return metadataProvider.getEntitiesDescriptor(name); } /* (non-Javadoc) * @see org.opensaml.saml2.metadata.provider.MetadataProvider#getEntityDescriptor(java.lang.String) */ @Override public EntityDescriptor getEntityDescriptor(String entityID) throws MetadataProviderException { try { //search if metadata is already loaded EntityDescriptor entityDesc = metadataProvider.getEntityDescriptor(entityID); if (entityDesc != null) return entityDesc; else Logger.info("No ms-specific eIDAS node: " + entityID + " Starting refresh process ..."); } catch (MetadataProviderException e) { Logger.info("Access ms-specific eIDAS node: " + entityID + " FAILED. Reason:" + e.getMessage() + " Starting refresh process ..."); } //(re)initialize ms-specific eIDAS node internalInitialize(entityID); //search again after reload (re)initialization try { EntityDescriptor entityDesc = metadataProvider.getEntityDescriptor(entityID); if (entityDesc == null) { Logger.error("MS-specific eIDAS node Client ERROR: No EntityID with "+ entityID); throw new MetadataProviderException("No EntityID with "+ entityID); } return entityDesc; } catch (MetadataProviderException e) { Logger.error("MS-specific eIDAS node Client ERROR: Metadata extraction FAILED.", e); throw new MetadataProviderException("Metadata extraction FAILED", e); } } /* (non-Javadoc) * @see org.opensaml.saml2.metadata.provider.MetadataProvider#getRole(java.lang.String, javax.xml.namespace.QName) */ @Override public List getRole(String entityID, QName roleName) throws MetadataProviderException { try { //search if metadata is already loaded List role = metadataProvider.getRole(entityID, roleName); if (role != null) return role; else Logger.info("No ms-specific eIDAS node: " + entityID + " Starting refresh process ..."); } catch (MetadataProviderException e) { Logger.info("Access ms-specific eIDAS node: " + entityID + " FAILED. Reason:" + e.getMessage() + " Starting refresh process ..."); } //(re)initialize ms-specific eIDAS node internalInitialize(entityID); //search again after reload (re)initialization return metadataProvider.getRole(entityID, roleName); } /* (non-Javadoc) * @see org.opensaml.saml2.metadata.provider.MetadataProvider#getRole(java.lang.String, javax.xml.namespace.QName, java.lang.String) */ @Override public RoleDescriptor getRole(String entityID, QName roleName, String supportedProtocol) throws MetadataProviderException { try { //search if metadata is already loaded RoleDescriptor role = metadataProvider.getRole(entityID, roleName, supportedProtocol); if (role != null) return role; else Logger.info("No ms-specific eIDAS node: " + entityID + " Starting refresh process ..."); } catch (MetadataProviderException e) { Logger.info("Access ms-specific eIDAS node: " + entityID + " FAILED. Reason:" + e.getMessage() + " Starting refresh process ..."); } //(re)initialize ms-specific eIDAS node internalInitialize(entityID); //search again after reload (re)initialization return metadataProvider.getRole(entityID, roleName, supportedProtocol); } private synchronized void internalInitialize(String metdataURL) throws MetadataProviderException { //check if metadata with EntityID already exists in chaining metadata provider boolean addNewMetadata = true; try { addNewMetadata = (metadataProvider.getEntityDescriptor(metdataURL) == null); } catch (MetadataProviderException e) {} //switch between metadata refresh and add new metadata if (addNewMetadata) { //Metadata provider seems not loaded --> Add new metadata provider Logger.info("Initialize PVP MetadataProvider:" + metdataURL + " to connect ms-specific eIDAS node"); String trustProfileID = authConfig.getBasicConfiguration(EidasCentralAuthConstants.CONFIG_PROPS_NODE_TRUSTPROFILEID); if (MiscUtil.isEmpty(trustProfileID)) { Logger.error("Create ms-specific eIDAS node Client FAILED: No trustProfileID to verify PVP metadata." ); throw new MetadataProviderException("No trustProfileID to verify PVP metadata."); } //initialize Timer if it is null if (timer == null) timer = new Timer(true); //create metadata validation filter chain MetadataFilterChain filter = new MetadataFilterChain(); filter.addFilter(new SchemaValidationFilter(true)); filter.addFilter(new MOASPMetadataSignatureFilter(trustProfileID)); MetadataProvider idpMetadataProvider = createNewSimpleMetadataProvider(metdataURL, filter, EidasCentralAuthConstants.MODULE_NAME_FOR_LOGGING, timer, new BasicParserPool(), createHttpClient(metdataURL)); if (idpMetadataProvider == null) { Logger.error("Create ms-specific eIDAS node Client FAILED."); throw new MetadataProviderException("Can not initialize 'ms-specific eIDAS node' metadata provider."); } idpMetadataProvider.setRequireValidMetadata(true); metadataProvider.addMetadataProvider(idpMetadataProvider); } else { //Metadata provider seems already loaded --> start refresh process List loadedProvider = metadataProvider.getProviders(); for (MetadataProvider el : loadedProvider) { if (el instanceof HTTPMetadataProvider) { HTTPMetadataProvider prov = (HTTPMetadataProvider)el; if (prov.getMetadataURI().equals(metdataURL)) prov.refresh(); } else Logger.warn("'ms-specific eIDAS node' Metadata provider is not of Type 'HTTPMetadataProvider'! Something is suspect!!!!"); } } } /* (non-Javadoc) * @see at.gv.egovernment.moa.id.auth.IDestroyableObject#fullyDestroy() */ @Override public void fullyDestroy() { Logger.info("Destroy 'ms-specific eIDAS node' PVP metadata pool ... "); if (metadataProvider != null) { metadataProvider.destroy(); } if (timer != null) timer.cancel(); } private HttpClient createHttpClient(String metadataURL) { MOAHttpClient httpClient = new MOAHttpClient(); HttpClientParams httpClientParams = new HttpClientParams(); httpClientParams.setSoTimeout(AuthConfiguration.CONFIG_PROPS_METADATA_SOCKED_TIMEOUT); httpClient.setParams(httpClientParams); if (metadataURL.startsWith("https:")) { try { //FIX: change hostname validation default flag to true when httpClient is updated to > 4.4 MOAHttpProtocolSocketFactory protoSocketFactory = new MOAHttpProtocolSocketFactory( PVPConstants.SSLSOCKETFACTORYNAME, moaAuthConfig.getBasicMOAIDConfigurationBoolean( AuthConfiguration.PROP_KEY_SSL_USE_JVM_TRUSTSTORE, false), moaAuthConfig.getTrustedCACertificates(), null, AuthConfiguration.DEFAULT_X509_CHAININGMODE, moaAuthConfig.isTrustmanagerrevoationchecking(), moaAuthConfig.getRevocationMethodOrder(), moaAuthConfig.getBasicMOAIDConfigurationBoolean( AuthConfiguration.PROP_KEY_SSL_HOSTNAME_VALIDATION, false)); httpClient.setCustomSSLTrustStore(metadataURL, protoSocketFactory); } catch (MOAHttpProtocolSocketFactoryException | MalformedURLException e) { Logger.warn("MOA SSL-TrustStore can not initialized. Use default Java TrustStore.", e); } } return httpClient; } }