Skip to content

Commit

Permalink
Refactor saml idp/sp configuration
Browse files Browse the repository at this point in the history
[#157525402] https://www.pivotaltracker.com/story/show/157525402

Signed-off-by: Bruce Ricard <bruce.ricard@gmail.com>
  • Loading branch information
DennisDenuto authored and bruce-ricard committed May 17, 2018
1 parent 63dcbc8 commit 8197f29
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 359 deletions.
@@ -0,0 +1,20 @@
package org.cloudfoundry.identity.uaa.impl.config;

import org.cloudfoundry.identity.uaa.util.UaaHttpRequestUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

@Bean
public RestTemplate nonTrustingRestTemplate() {
return new RestTemplate(UaaHttpRequestUtils.createRequestFactory(false, 30_000));
}

@Bean
public RestTemplate trustingRestTemplate() {
return new RestTemplate(UaaHttpRequestUtils.createRequestFactory(true, 30_000));
}
}
Expand Up @@ -13,57 +13,46 @@

package org.cloudfoundry.identity.uaa.provider.saml;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.SimpleHttpConnectionManager;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.cloudfoundry.identity.uaa.cache.UrlContentCache;
import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider;
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
import org.springframework.web.client.RestTemplate;

import java.util.Timer;
import java.net.URI;
import java.net.URISyntaxException;

/**
* This class works around the problem described in <a href="http://issues.apache.org/jira/browse/HTTPCLIENT-646">http://issues.apache.org/jira/browse/HTTPCLIENT-646</a> when a socket factory is set
* on the OpenSAML
* {@link HTTPMetadataProvider#setSocketFactory(ProtocolSocketFactory)} all
* subsequent GET Methods should be executed using a relative URL, otherwise the
* HttpClient
* resets the underlying socket factory.
*
*
*/
public class FixedHttpMetaDataProvider extends HTTPMetadataProvider {
public class FixedHttpMetaDataProvider {

private RestTemplate template;
private RestTemplate trustingRestTemplate;
private RestTemplate nonTrustingRestTemplate;
private UrlContentCache cache;

public static FixedHttpMetaDataProvider buildProvider(Timer backgroundTaskTimer,
HttpClientParams params,
String metadataURL,
RestTemplate template,
UrlContentCache cache) throws MetadataProviderException {
SimpleHttpConnectionManager connectionManager = new SimpleHttpConnectionManager(true);
connectionManager.getParams().setDefaults(params);
HttpClient client = new HttpClient(connectionManager);
return new FixedHttpMetaDataProvider(backgroundTaskTimer, client, metadataURL, template, cache);

public byte[] fetchMetadata(String metadataURL, boolean isSkipSSLValidation) throws MetadataProviderException, URISyntaxException {
validateMetadataURL(metadataURL);

if (isSkipSSLValidation) {
return cache.getUrlContent(metadataURL, trustingRestTemplate);
}
return cache.getUrlContent(metadataURL, nonTrustingRestTemplate);
}

private FixedHttpMetaDataProvider(Timer backgroundTaskTimer,
HttpClient client,
String metadataURL,
RestTemplate template,
UrlContentCache cache) throws MetadataProviderException {
super(backgroundTaskTimer, client, metadataURL);
this.template = template;
this.cache = cache;
private void validateMetadataURL(String metadataURL) throws MetadataProviderException {
try {
new URI(metadataURL);
} catch (URISyntaxException e) {
throw new MetadataProviderException("Illegal URL syntax", e);
}
}

@Override
public byte[] fetchMetadata() throws MetadataProviderException {
return cache.getUrlContent(getMetadataURI(), template);
public void setTrustingRestTemplate(RestTemplate trustingRestTemplate) {
this.trustingRestTemplate = trustingRestTemplate;
}

public void setNonTrustingRestTemplate(RestTemplate nonTrustingRestTemplate) {
this.nonTrustingRestTemplate = nonTrustingRestTemplate;
}

public void setCache(UrlContentCache cache) {
this.cache = cache;
}
}

This file was deleted.

Expand Up @@ -12,16 +12,11 @@
*******************************************************************************/
package org.cloudfoundry.identity.uaa.provider.saml;

import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.utils.URIBuilder;
import org.cloudfoundry.identity.uaa.cache.UrlContentCache;
import org.cloudfoundry.identity.uaa.constants.OriginKeys;
import org.cloudfoundry.identity.uaa.provider.IdentityProvider;
import org.cloudfoundry.identity.uaa.provider.IdentityProviderProvisioning;
import org.cloudfoundry.identity.uaa.provider.SamlIdentityProviderDefinition;
import org.cloudfoundry.identity.uaa.util.UaaHttpRequestUtils;
import org.cloudfoundry.identity.uaa.zone.IdentityZone;
import org.cloudfoundry.identity.uaa.zone.IdentityZoneHolder;
import org.opensaml.saml2.metadata.provider.MetadataProviderException;
Expand All @@ -30,50 +25,21 @@
import org.springframework.security.saml.metadata.ExtendedMetadata;
import org.springframework.security.saml.metadata.ExtendedMetadataDelegate;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import static org.springframework.util.StringUtils.hasText;

public class SamlIdentityProviderConfigurator implements InitializingBean {
public static final int CONFIGURE_URL_DEFAULT_TIMEOUT = 30_000;
private static Log logger = LogFactory.getLog(SamlIdentityProviderConfigurator.class);
private HttpClientParams clientParams;
private BasicParserPool parserPool;
private IdentityProviderProvisioning providerProvisioning;
private UrlContentCache contentCache;
private MetadataFetcher metadataFetcher;

private Timer dummyTimer = new Timer() {
@Override public void cancel() { super.cancel(); }
@Override public int purge() {return 0; }
@Override public void schedule(TimerTask task, long delay) {}
@Override public void schedule(TimerTask task, long delay, long period) {}
@Override public void schedule(TimerTask task, Date firstTime, long period) {}
@Override public void schedule(TimerTask task, Date time) {}
@Override public void scheduleAtFixedRate(TimerTask task, long delay, long period) {}
@Override public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) {}
};
private FixedHttpMetaDataProvider fixedHttpMetaDataProvider;

public SamlIdentityProviderConfigurator() {
dummyTimer.cancel();
}

public UrlContentCache getContentCache() {
return contentCache;
}

public SamlIdentityProviderConfigurator setContentCache(UrlContentCache contentCache) {
this.contentCache = contentCache;
return this;
}

public List<SamlIdentityProviderDefinition> getIdentityProviderDefinitions() {
Expand All @@ -82,7 +48,7 @@ public List<SamlIdentityProviderDefinition> getIdentityProviderDefinitions() {

public List<SamlIdentityProviderDefinition> getIdentityProviderDefinitionsForZone(IdentityZone zone) {
List<SamlIdentityProviderDefinition> result = new LinkedList<>();
for (IdentityProvider provider: providerProvisioning.retrieveActive(zone.getId())) {
for (IdentityProvider provider : providerProvisioning.retrieveActive(zone.getId())) {
if (OriginKeys.SAML.equals(provider.getType())) {
result.add((SamlIdentityProviderDefinition) provider.getConfig());
}
Expand All @@ -106,12 +72,13 @@ public List<SamlIdentityProviderDefinition> getIdentityProviderDefinitions(List<

/**
* adds or replaces a SAML identity proviider
*
* @param providerDefinition - the provider to be added
* @throws MetadataProviderException if the system fails to fetch meta data for this provider
*/
public synchronized void validateSamlIdentityProviderDefinition(SamlIdentityProviderDefinition providerDefinition) throws MetadataProviderException {
ExtendedMetadataDelegate added, deleted=null;
if (providerDefinition==null) {
ExtendedMetadataDelegate added, deleted = null;
if (providerDefinition == null) {
throw new NullPointerException();
}
if (!hasText(providerDefinition.getIdpEntityAlias())) {
Expand All @@ -122,45 +89,25 @@ public synchronized void validateSamlIdentityProviderDefinition(SamlIdentityProv
}
SamlIdentityProviderDefinition clone = providerDefinition.clone();
added = getExtendedMetadataDelegate(clone);
String entityIDToBeAdded = ((ConfigMetadataProvider)added.getDelegate()).getEntityID();
String entityIDToBeAdded = ((ConfigMetadataProvider) added.getDelegate()).getEntityID();
if (!StringUtils.hasText(entityIDToBeAdded)) {
throw new MetadataProviderException("Emtpy entityID for SAML provider with zoneId:"+providerDefinition.getZoneId()+" and origin:"+providerDefinition.getIdpEntityAlias());
throw new MetadataProviderException("Emtpy entityID for SAML provider with zoneId:" + providerDefinition.getZoneId() + " and origin:" + providerDefinition.getIdpEntityAlias());
}

boolean entityIDexists = false;

for (SamlIdentityProviderDefinition existing : getIdentityProviderDefinitions()) {
ConfigMetadataProvider existingProvider = (ConfigMetadataProvider)getExtendedMetadataDelegate(existing).getDelegate();
ConfigMetadataProvider existingProvider = (ConfigMetadataProvider) getExtendedMetadataDelegate(existing).getDelegate();
if (entityIDToBeAdded.equals(existingProvider.getEntityID()) &&
!(existing.getUniqueAlias().equals(clone.getUniqueAlias()))) {
!(existing.getUniqueAlias().equals(clone.getUniqueAlias()))) {
entityIDexists = true;
break;
}
}

if (entityIDexists) {
throw new MetadataProviderException("Duplicate entity ID:"+entityIDToBeAdded);
}
}

public synchronized ExtendedMetadataDelegate removeIdentityProviderDefinition(SamlIdentityProviderDefinition providerDefinition) {
return null;
}

public List<ExtendedMetadataDelegate> getSamlIdentityProviders() {
return getSamlIdentityProviders(null);
}

public List<ExtendedMetadataDelegate> getSamlIdentityProviders(IdentityZone zone) {
List<ExtendedMetadataDelegate> result = new LinkedList<>();
for (SamlIdentityProviderDefinition def : getIdentityProviderDefinitionsForZone(zone)) {
try {
result.add(getExtendedMetadataDelegate(def));
} catch (MetadataProviderException e) {
throw new RuntimeException(e);
}
throw new MetadataProviderException("Duplicate entity ID:" + entityIDToBeAdded);
}
return result;
}

public ExtendedMetadataDelegate getExtendedMetadataDelegateFromCache(SamlIdentityProviderDefinition def) throws MetadataProviderException {
Expand All @@ -175,7 +122,7 @@ public ExtendedMetadataDelegate getExtendedMetadataDelegate(SamlIdentityProvider
break;
}
case URL: {
metadata = configureURLMetadata(def, CONFIGURE_URL_DEFAULT_TIMEOUT);
metadata = configureURLMetadata(def);
break;
}
default: {
Expand All @@ -197,19 +144,6 @@ protected ExtendedMetadataDelegate configureXMLMetadata(SamlIdentityProviderDefi
return delegate;
}

protected FixedHttpMetaDataProvider getFixedHttpMetaDataProvider(SamlIdentityProviderDefinition def,
Timer dummyTimer,
int timeout) throws ClassNotFoundException, MetadataProviderException, URISyntaxException, InstantiationException, IllegalAccessException {
ExtendedMetadata extendedMetadata = new ExtendedMetadata();
extendedMetadata.setAlias(def.getIdpEntityAlias());
RestTemplate template = new RestTemplate(UaaHttpRequestUtils.createRequestFactory(def.isSkipSslValidation(), timeout));
FixedHttpMetaDataProvider fixedHttpMetaDataProvider =
FixedHttpMetaDataProvider.buildProvider(dummyTimer, getClientParams(),
adjustURIForPort(def.getMetaDataLocation()),
template,
this.contentCache);
return fixedHttpMetaDataProvider;
}

protected String adjustURIForPort(String uri) throws URISyntaxException {
URI metadataURI = new URI(uri);
Expand All @@ -226,23 +160,17 @@ protected String adjustURIForPort(String uri) throws URISyntaxException {
return uri;
}

protected ExtendedMetadataDelegate configureURLMetadata(SamlIdentityProviderDefinition def, int timeoutInMs) throws MetadataProviderException {
protected ExtendedMetadataDelegate configureURLMetadata(SamlIdentityProviderDefinition def) throws MetadataProviderException {
try {
def = def.clone();
ExtendedMetadata extendedMetadata = new ExtendedMetadata();
extendedMetadata.setAlias(def.getIdpEntityAlias());
FixedHttpMetaDataProvider fixedHttpMetaDataProvider = getFixedHttpMetaDataProvider(def, dummyTimer, timeoutInMs);
byte[] metadata = metadataFetcher.fetch(fixedHttpMetaDataProvider);
String adjustedMetatadataURIForPort = adjustURIForPort(def.getMetaDataLocation());

byte[] metadata = fixedHttpMetaDataProvider.fetchMetadata(adjustedMetatadataURIForPort, def.isSkipSslValidation());

def.setMetaDataLocation(new String(metadata, StandardCharsets.UTF_8));
return configureXMLMetadata(def);
} catch (URISyntaxException e) {
throw new MetadataProviderException("Invalid socket factory(invalid URI):"+def.getMetaDataLocation(), e);
} catch (ClassNotFoundException e) {
throw new MetadataProviderException("Invalid socket factory:"+def.getSocketFactoryClassName(), e);
} catch (InstantiationException e) {
throw new MetadataProviderException("Invalid socket factory:"+def.getSocketFactoryClassName(), e);
} catch (IllegalAccessException e) {
throw new MetadataProviderException("Invalid socket factory:"+def.getSocketFactoryClassName(), e);
throw new MetadataProviderException("Invalid socket factory(invalid URI):" + def.getMetaDataLocation(), e);
}
}

Expand All @@ -254,13 +182,6 @@ public void setIdentityProviderProvisioning(IdentityProviderProvisioning provide
this.providerProvisioning = providerProvisioning;
}

public HttpClientParams getClientParams() {
return clientParams;
}

public void setClientParams(HttpClientParams clientParams) {
this.clientParams = clientParams;
}

public BasicParserPool getParserPool() {
return parserPool;
Expand All @@ -274,7 +195,7 @@ public void setParserPool(BasicParserPool parserPool) {
public void afterPropertiesSet() throws Exception {
}

public void setMetadataFetcher(MetadataFetcher metadataFetcher) {
this.metadataFetcher = metadataFetcher;
public void setFixedHttpMetaDataProvider(FixedHttpMetaDataProvider fixedHttpMetaDataProvider) {
this.fixedHttpMetaDataProvider = fixedHttpMetaDataProvider;
}
}

0 comments on commit 8197f29

Please sign in to comment.