diff --git a/build.gradle b/build.gradle index 22226687a..e90f62900 100644 --- a/build.gradle +++ b/build.gradle @@ -15,14 +15,14 @@ def coreProjects = subprojects.findAll { !it.name.contains("sample") } configure(allprojects) { project -> group = "org.springframework.security.extensions" - ext.slf4jVersion = "1.7.25" - ext.springVersion = "4.3.14.RELEASE" - ext.springSecurityVersion = "4.2.4.RELEASE" - ext.bcprovVersion = "1.60" - ext.bcpkixVersion = "1.60" + ext.slf4jVersion = "1.7.29" + ext.springVersion = "4.3.25.RELEASE" + ext.springSecurityVersion = "4.2.13.RELEASE" + ext.bcprovVersion = "1.64" + ext.bcpkixVersion = "1.64" ext.openSamlVersion = "2.6.6" ext.openSamlXmlSec = "1.5.8" - ext.esapiVersion = "2.1.0.1" + ext.esapiVersion = "2.2.0.0" ext.xalanVersion = "2.7.2" ext.xmlApisVersion = "1.4.01" ext.gradleScriptDir = "${rootProject.projectDir}/gradle" diff --git a/core/src/main/java/org/springframework/security/saml/metadata/MetadataManager.java b/core/src/main/java/org/springframework/security/saml/metadata/MetadataManager.java index b18883e2b..1f61d1609 100644 --- a/core/src/main/java/org/springframework/security/saml/metadata/MetadataManager.java +++ b/core/src/main/java/org/springframework/security/saml/metadata/MetadataManager.java @@ -14,18 +14,6 @@ */ package org.springframework.security.saml.metadata; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.locks.ReentrantReadWriteLock; - import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.metadata.EntitiesDescriptor; import org.opensaml.saml2.metadata.EntityDescriptor; @@ -62,6 +50,19 @@ import org.springframework.security.saml.util.SAMLUtil; import org.springframework.util.Assert; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.locks.ReentrantReadWriteLock; + /** * Class offers extra services on top of the underlying chaining MetadataProviders. Manager keeps track of all available * identity and service providers configured inside the chained metadata providers. Exactly one service provider can @@ -80,46 +81,46 @@ public class MetadataManager extends ChainingMetadataProvider implements Extende protected final Logger log = LoggerFactory.getLogger(MetadataManager.class); // Lock for the instance - private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + protected final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); // Lock for the refresh mechanism - private final ReentrantReadWriteLock refreshLock = new ReentrantReadWriteLock(); + protected final ReentrantReadWriteLock refreshLock = new ReentrantReadWriteLock(); - private String hostedSPName; + protected String hostedSPName; - private String defaultIDP; + protected String defaultIDP; - private ExtendedMetadata defaultExtendedMetadata; + protected ExtendedMetadata defaultExtendedMetadata; // Timer used to refresh the metadata upon changes - private Timer timer; + protected Timer timer; // Internal of metadata refresh checking in ms - private long refreshCheckInterval = 10000l; + protected long refreshCheckInterval = 10000l; // Flag indicating whether metadata needs to be reloaded - private boolean refreshRequired = true; + protected boolean refreshRequired = true; // Storage for cryptographic data used to verify metadata signatures protected KeyManager keyManager; // All providers which were added, not all may be active - private List availableProviders; + protected List availableProviders; /** * Set of IDP names available in the system. */ - private Set idpName; + protected Set idpName; /** * Set of SP names available in the system. */ - private Set spName; + protected Set spName; /** * All valid aliases. */ - private Set aliasSet; + protected Set aliasSet; /** * Creates new metadata manager, automatically registers itself for notifications from metadata changes and calls @@ -258,18 +259,18 @@ public void refreshMetadata() { try { - log.debug("Refreshing metadata provider {}", provider.toString()); + log.debug("Refreshing metadata provider {}", provider); initializeProviderFilters(provider); initializeProvider(provider); initializeProviderData(provider); // Make provider available for queries super.addMetadataProvider(provider); - log.debug("Metadata provider was initialized {}", provider.toString()); + log.debug("Metadata provider was initialized {}", provider); } catch (MetadataProviderException e) { - log.error("Initialization of metadata provider " + provider + " failed, provider will be ignored", e); + log.error("Initialization of metadata provider {} failed, provider will be ignored", provider, e); } @@ -551,19 +552,12 @@ protected void initializeProviderFilters(ExtendedMetadataDelegate provider) thro log.debug("Created new trust manager for metadata provider {}", provider); - // Combine any existing filters with the signature verification MetadataFilter currentFilter = provider.getMetadataFilter(); if (currentFilter != null) { - if (currentFilter instanceof MetadataFilterChain) { - log.debug("Adding signature filter into existing chain"); - MetadataFilterChain chain = (MetadataFilterChain) currentFilter; - chain.getFilters().add(filter); - } else { - log.debug("Combining signature filter with the existing in a new chain"); - MetadataFilterChain chain = new MetadataFilterChain(); - chain.getFilters().add(currentFilter); - chain.getFilters().add(filter); - } + log.debug("Adding signature filter before existing filters"); + MetadataFilterChain chain = new MetadataFilterChain(); + chain.setFilters(Arrays.asList(filter, currentFilter)); + provider.setMetadataFilter(chain); } else { log.debug("Adding signature filter"); provider.setMetadataFilter(filter); @@ -640,11 +634,13 @@ protected PKIXValidationInformationResolver getPKIXResolver(MetadataProvider pro // Resolve allowed certificates to build the anchors List certificates = new LinkedList(); + Set trustedSubjectDns = new HashSet(); for (String key : trustedKeys) { log.debug("Adding PKIX trust anchor {} for metadata verification of provider {}", key, provider); X509Certificate certificate = keyManager.getCertificate(key); if (certificate != null) { certificates.add(certificate); + trustedSubjectDns.add( certificate.getSubjectDN().getName() ); } else { log.warn("Cannot construct PKIX trust anchor for key with alias {} for provider {}, key isn't included in the keystore", key, provider); } @@ -652,7 +648,7 @@ protected PKIXValidationInformationResolver getPKIXResolver(MetadataProvider pro List info = new LinkedList(); info.add(new BasicPKIXValidationInformation(certificates, null, 4)); - return new StaticPKIXValidationInformationResolver(info, trustedNames) { + return new StaticPKIXValidationInformationResolver(info, trustedNames != null ? trustedNames : trustedSubjectDns) { @Override public Set resolveTrustedNames(CriteriaSet criteriaSet) throws SecurityException, UnsupportedOperationException { @@ -704,7 +700,7 @@ protected List parseProvider(MetadataProvider provider) throws MetadataP */ private void addDescriptors(List result, EntitiesDescriptor descriptors) throws MetadataProviderException { - log.debug("Found metadata EntitiesDescriptor with ID", descriptors.getID()); + log.debug("Found metadata EntitiesDescriptor with ID {}", descriptors.getID()); if (descriptors.getEntitiesDescriptors() != null) { for (EntitiesDescriptor descriptor : descriptors.getEntitiesDescriptors()) { diff --git a/core/src/main/java/org/springframework/security/saml/trust/httpclient/TLSProtocolSocketFactory.java b/core/src/main/java/org/springframework/security/saml/trust/httpclient/TLSProtocolSocketFactory.java index c5ed5aa1f..fc7b2d193 100644 --- a/core/src/main/java/org/springframework/security/saml/trust/httpclient/TLSProtocolSocketFactory.java +++ b/core/src/main/java/org/springframework/security/saml/trust/httpclient/TLSProtocolSocketFactory.java @@ -26,10 +26,7 @@ import java.net.InetAddress; import java.net.Socket; import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Set; +import java.util.*; /** * Socket factory can be used with HTTP Client for creation of SSL/TLS sockets. Implementation uses internal KeyManager @@ -136,14 +133,17 @@ protected PKIXValidationInformationResolver getPKIXResolver() { // Resolve allowed certificates to build the anchors List certificates = new ArrayList(trustedKeys.size()); + Set subjectDNs = new HashSet(trustedKeys.size()); for (String key : trustedKeys) { log.debug("Adding PKIX trust anchor {} for SSL/TLS verification {}", key); - certificates.add(keyManager.getCertificate(key)); + X509Certificate cert = keyManager.getCertificate(key); + certificates.add(cert); + subjectDNs.add(cert.getSubjectDN().getName()); } List info = new LinkedList(); info.add(new BasicPKIXValidationInformation(certificates, null, 4)); - return new StaticPKIXValidationInformationResolver(info, null); + return new StaticPKIXValidationInformationResolver(info, subjectDNs); } diff --git a/core/src/test/java/org/springframework/security/saml/metadata/MetadataManagerWithTLSConfigurer.java b/core/src/test/java/org/springframework/security/saml/metadata/MetadataManagerWithTLSConfigurer.java new file mode 100644 index 000000000..61463897b --- /dev/null +++ b/core/src/test/java/org/springframework/security/saml/metadata/MetadataManagerWithTLSConfigurer.java @@ -0,0 +1,53 @@ +package org.springframework.security.saml.metadata; + +import org.junit.Before; +import org.junit.Test; +import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider; +import org.opensaml.xml.parse.ParserPool; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.security.saml.key.KeyManager; + +import java.io.File; + +import static junit.framework.Assert.assertNotNull; + +public class MetadataManagerWithTLSConfigurer { + + ApplicationContext context; + KeyManager keyManager; + MetadataManager manager; + ParserPool pool; + + @Before + public void initialize() throws Exception { + String resName = "/" + getClass().getName().replace('.', '/') + ".xml"; + context = new ClassPathXmlApplicationContext(resName); + keyManager = context.getBean("keyManager", KeyManager.class); + manager = context.getBean("metadata", MetadataManager.class); + pool = context.getBean("parserPool", ParserPool.class); + } + + @Test + public void testExplicitKeyStore() throws Exception { + ExtendedMetadataDelegate provider = getMetadata("classpath:testSP_signed_ca2_chain.xml"); + provider.setMetadataRequireSignature(true); + provider.setMetadataTrustCheck(true); + provider.setForceMetadataRevocationCheck(true); + + manager.addMetadataProvider(provider); + manager.refreshMetadata(); + + assertNotNull(manager.getEntityDescriptor("test_ca2")); + + } + + protected ExtendedMetadataDelegate getMetadata(String fileName) throws Exception { + File file = context.getResource(fileName).getFile(); + FilesystemMetadataProvider innerProvider = new FilesystemMetadataProvider(file); + innerProvider.setParserPool(pool); + return new ExtendedMetadataDelegate(innerProvider); + } + + +} diff --git a/core/src/test/resources/org/springframework/security/saml/metadata/MetadataManagerWithTLSConfigurer.xml b/core/src/test/resources/org/springframework/security/saml/metadata/MetadataManagerWithTLSConfigurer.xml new file mode 100644 index 000000000..9b90fc20e --- /dev/null +++ b/core/src/test/resources/org/springframework/security/saml/metadata/MetadataManagerWithTLSConfigurer.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gradle.properties b/gradle.properties index 9ae90dd46..2c666534f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ -version=1.0.10.BUILD-SNAPSHOT +version=1.0.11.BUILD-SNAPSHOT maxParallelForks=1