/*******************************************************************************
* Cloud Foundry
* Copyright (c) [2009-2016] Pivotal Software, Inc. All Rights Reserved.
*
* This product is licensed to you under the Apache License, Version 2.0 (the "License").
* You may not use this product except in compliance with the License.
*
* This product includes a number of subcomponents with
* separate copyright notices and license terms. Your use of these
* subcomponents is subject to the terms and conditions of the
* subcomponent's license, as noted in the LICENSE file.
*******************************************************************************/
package org.cloudfoundry.identity.uaa.provider.saml.idp;
import org.opensaml.Configuration;
import org.opensaml.common.SAMLObjectBuilder;
import org.opensaml.common.SAMLRuntimeException;
import org.opensaml.common.xml.SAMLConstants;
import org.opensaml.saml2.common.Extensions;
import org.opensaml.saml2.common.impl.ExtensionsBuilder;
import org.opensaml.saml2.core.AuthnRequest;
import org.opensaml.saml2.core.NameIDType;
import org.opensaml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml2.metadata.IDPSSODescriptor;
import org.opensaml.saml2.metadata.KeyDescriptor;
import org.opensaml.saml2.metadata.NameIDFormat;
import org.opensaml.saml2.metadata.SingleLogoutService;
import org.opensaml.saml2.metadata.SingleSignOnService;
import org.opensaml.samlext.idpdisco.DiscoveryResponse;
import org.opensaml.util.URLBuilder;
import org.opensaml.xml.XMLObjectBuilderFactory;
import org.opensaml.xml.security.SecurityHelper;
import org.opensaml.xml.security.credential.Credential;
import org.opensaml.xml.security.credential.UsageType;
import org.opensaml.xml.security.keyinfo.KeyInfoGenerator;
import org.opensaml.xml.signature.KeyInfo;
import org.opensaml.xml.util.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.saml.SAMLDiscovery;
import org.springframework.security.saml.SAMLEntryPoint;
import org.springframework.security.saml.SAMLLogoutProcessingFilter;
import org.springframework.security.saml.SAMLProcessingFilter;
import org.springframework.security.saml.SAMLWebSSOHoKProcessingFilter;
import org.springframework.security.saml.key.KeyManager;
import org.springframework.security.saml.metadata.ExtendedMetadata;
import org.springframework.security.saml.util.SAMLUtil;
import javax.xml.namespace.QName;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;
/**
* The class is responsible for generating the metadata that describes the identity provider in the current deployment
* environment. All the URLs in the metadata derive from information provided by the ServletContext.
*
* This code for this class is based on org.springframework.security.saml.metadata.MetadataGenerator.
*/
public class IdpMetadataGenerator {
private String id;
private String entityId;
private String entityBaseURL;
private boolean wantAuthnRequestSigned = true;
/**
* Index of the assertion consumer endpoint marked as default.
*/
private int assertionConsumerIndex = 0;
/**
* Extended metadata with details on metadata generation.
*/
private IdpExtendedMetadata extendedMetadata;
// List of case-insensitive alias terms
private static TreeMap<String, String> aliases = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
static {
aliases.put(SAMLConstants.SAML2_POST_BINDING_URI, SAMLConstants.SAML2_POST_BINDING_URI);
aliases.put("post", SAMLConstants.SAML2_POST_BINDING_URI);
aliases.put("http-post", SAMLConstants.SAML2_POST_BINDING_URI);
aliases.put(SAMLConstants.SAML2_PAOS_BINDING_URI, SAMLConstants.SAML2_PAOS_BINDING_URI);
aliases.put("paos", SAMLConstants.SAML2_PAOS_BINDING_URI);
aliases.put(SAMLConstants.SAML2_ARTIFACT_BINDING_URI, SAMLConstants.SAML2_ARTIFACT_BINDING_URI);
aliases.put("artifact", SAMLConstants.SAML2_ARTIFACT_BINDING_URI);
aliases.put("http-artifact", SAMLConstants.SAML2_ARTIFACT_BINDING_URI);
aliases.put(SAMLConstants.SAML2_REDIRECT_BINDING_URI, SAMLConstants.SAML2_REDIRECT_BINDING_URI);
aliases.put("redirect", SAMLConstants.SAML2_REDIRECT_BINDING_URI);
aliases.put("http-redirect", SAMLConstants.SAML2_REDIRECT_BINDING_URI);
aliases.put(SAMLConstants.SAML2_SOAP11_BINDING_URI, SAMLConstants.SAML2_SOAP11_BINDING_URI);
aliases.put("soap", SAMLConstants.SAML2_SOAP11_BINDING_URI);
aliases.put(NameIDType.EMAIL, NameIDType.EMAIL);
aliases.put("email", NameIDType.EMAIL);
aliases.put(NameIDType.TRANSIENT, NameIDType.TRANSIENT);
aliases.put("transient", NameIDType.TRANSIENT);
aliases.put(NameIDType.PERSISTENT, NameIDType.PERSISTENT);
aliases.put("persistent", NameIDType.PERSISTENT);
aliases.put(NameIDType.UNSPECIFIED, NameIDType.UNSPECIFIED);
aliases.put("unspecified", NameIDType.UNSPECIFIED);
aliases.put(NameIDType.X509_SUBJECT, NameIDType.X509_SUBJECT);
aliases.put("x509_subject", NameIDType.X509_SUBJECT);
}
/**
* Bindings for single sign-on
*/
private Collection<String> bindingsSSO = Arrays.asList("post", "artifact");
/**
* Bindings for single sign-on holder of key
*/
private Collection<String> bindingsHoKSSO = Collections.emptyList();
/**
* Bindings for single logout
*/
private Collection<String> bindingsSLO = Collections.emptyList();
/**
* Flag indicates whether to include extension with discovery endpoints in metadata.
*/
private boolean includeDiscoveryExtension;
/**
* NameIDs to be included in generated metadata.
*/
private Collection<String> nameID = null;
/**
* Default set of NameIDs included in metadata.
*/
public static final Collection<String> defaultNameID = Arrays.asList(NameIDType.EMAIL, NameIDType.TRANSIENT,
NameIDType.PERSISTENT, NameIDType.UNSPECIFIED, NameIDType.X509_SUBJECT);
protected XMLObjectBuilderFactory builderFactory;
/**
* Source of certificates.
*/
protected KeyManager keyManager;
/**
* Filters for loading of paths.
*/
protected SAMLProcessingFilter samlWebSSOFilter;
protected SAMLWebSSOHoKProcessingFilter samlWebSSOHoKFilter;
protected SAMLLogoutProcessingFilter samlLogoutProcessingFilter;
protected SAMLEntryPoint samlEntryPoint;
protected SAMLDiscovery samlDiscovery;
/**
* Class logger.
*/
protected final static Logger log = LoggerFactory.getLogger(IdpMetadataGenerator.class);
/**
* Default constructor.
*/
public IdpMetadataGenerator() {
this.builderFactory = Configuration.getBuilderFactory();
}
public EntityDescriptor generateMetadata() {
boolean wantAuthnRequestSigned = isWantAuthnRequestSigned();
Collection<String> includedNameID = getNameID();
String entityId = getEntityId();
String entityBaseURL = getEntityBaseURL();
String entityAlias = getEntityAlias();
validateRequiredAttributes(entityId, entityBaseURL);
if (id == null) {
// Use entityID cleaned as NCName for ID in case no value is provided
id = SAMLUtil.getNCNameString(entityId);
}
@SuppressWarnings("unchecked")
SAMLObjectBuilder<EntityDescriptor> builder = (SAMLObjectBuilder<EntityDescriptor>) builderFactory
.getBuilder(EntityDescriptor.DEFAULT_ELEMENT_NAME);
EntityDescriptor descriptor = builder.buildObject();
if (id != null) {
descriptor.setID(id);
}
descriptor.setEntityID(entityId);
IDPSSODescriptor ssoDescriptor = buildIDPSSODescriptor(entityBaseURL, entityAlias, wantAuthnRequestSigned,
includedNameID);
if (ssoDescriptor != null) {
descriptor.getRoleDescriptors().add(ssoDescriptor);
}
return descriptor;
}
protected void validateRequiredAttributes(String entityId, String entityBaseURL) {
if (entityId == null || entityBaseURL == null) {
throw new RuntimeException("Required attributes entityId or entityBaseURL weren't set");
}
}
protected KeyInfo getServerKeyInfo(String alias) {
Credential serverCredential = keyManager.getCredential(alias);
if (serverCredential == null) {
throw new RuntimeException("Key for alias " + alias + " not found");
} else if (serverCredential.getPrivateKey() == null) {
throw new RuntimeException("Key with alias " + alias + " doesn't have a private key");
}
return generateKeyInfoForCredential(serverCredential);
}
/**
* Generates extended metadata. Default extendedMetadata object is cloned if present and used for defaults. The
* following properties are always overriden from the properties of this bean: discoveryUrl, discoveryResponseUrl,
* signingKey, encryptionKey, entityAlias and tlsKey. Property local of the generated metadata is always set to
* true.
*
* @return generated extended metadata
*/
public IdpExtendedMetadata generateExtendedMetadata() {
IdpExtendedMetadata metadata;
if (extendedMetadata != null) {
metadata = extendedMetadata.clone();
} else {
metadata = new IdpExtendedMetadata();
}
String entityBaseURL = getEntityBaseURL();
String entityAlias = getEntityAlias();
if (isIncludeDiscovery()) {
metadata.setIdpDiscoveryURL(getDiscoveryURL(entityBaseURL, entityAlias));
metadata.setIdpDiscoveryResponseURL(getDiscoveryResponseURL(entityBaseURL, entityAlias));
} else {
metadata.setIdpDiscoveryURL(null);
metadata.setIdpDiscoveryResponseURL(null);
}
metadata.setLocal(true);
metadata.setAssertionTimeToLiveSeconds(getAssertionTimeToLiveSeconds());
metadata.setAssertionsSigned(isAssertionsSigned());
return metadata;
}
protected KeyInfo generateKeyInfoForCredential(Credential credential) {
try {
String keyInfoGeneratorName = org.springframework.security.saml.SAMLConstants.SAML_METADATA_KEY_INFO_GENERATOR;
if (extendedMetadata != null && extendedMetadata.getKeyInfoGeneratorName() != null) {
keyInfoGeneratorName = extendedMetadata.getKeyInfoGeneratorName();
}
KeyInfoGenerator keyInfoGenerator = SecurityHelper.getKeyInfoGenerator(credential, null,
keyInfoGeneratorName);
return keyInfoGenerator.generate(credential);
} catch (org.opensaml.xml.security.SecurityException e) {
log.error("Can't obtain key from the keystore or generate key info for credential: " + credential, e);
throw new SAMLRuntimeException("Can't obtain key from keystore or generate key info", e);
}
}
protected IDPSSODescriptor buildIDPSSODescriptor(String entityBaseURL, String entityAlias,
boolean wantAuthnRequestSigned, Collection<String> includedNameID) {
@SuppressWarnings("unchecked")
SAMLObjectBuilder<IDPSSODescriptor> builder = (SAMLObjectBuilder<IDPSSODescriptor>) builderFactory
.getBuilder(IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
IDPSSODescriptor idpDescriptor = builder.buildObject();
idpDescriptor.setWantAuthnRequestsSigned(wantAuthnRequestSigned);
idpDescriptor.addSupportedProtocol(SAMLConstants.SAML20P_NS);
// Name ID
idpDescriptor.getNameIDFormats().addAll(getNameIDFormat(includedNameID));
// Resolve alases
Collection<String> bindingsSSO = mapAliases(getBindingsSSO());
Collection<String> bindingsSLO = mapAliases(getBindingsSLO());
// Assertion consumer MUST NOT be used with HTTP Redirect, Profiles 424, same applies to HoK profile
for (String binding : bindingsSSO) {
if (binding.equals(SAMLConstants.SAML2_ARTIFACT_BINDING_URI)) {
idpDescriptor.getSingleSignOnServices().add(getSingleSignOnService(entityBaseURL, entityAlias,
getSAMLWebSSOProcessingFilterPath(), SAMLConstants.SAML2_ARTIFACT_BINDING_URI));
}
if (binding.equals(SAMLConstants.SAML2_POST_BINDING_URI)) {
idpDescriptor.getSingleSignOnServices().add(getSingleSignOnService(entityBaseURL, entityAlias,
getSAMLWebSSOProcessingFilterPath(), SAMLConstants.SAML2_POST_BINDING_URI));
}
if (binding.equals(SAMLConstants.SAML2_PAOS_BINDING_URI)) {
idpDescriptor.getSingleSignOnServices().add(getSingleSignOnService(entityBaseURL, entityAlias,
getSAMLWebSSOProcessingFilterPath(), SAMLConstants.SAML2_PAOS_BINDING_URI));
}
}
for (String binding : bindingsSLO) {
if (binding.equals(SAMLConstants.SAML2_POST_BINDING_URI)) {
idpDescriptor.getSingleLogoutServices()
.add(getSingleLogoutService(entityBaseURL, entityAlias, SAMLConstants.SAML2_POST_BINDING_URI));
}
if (binding.equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)) {
idpDescriptor.getSingleLogoutServices().add(
getSingleLogoutService(entityBaseURL, entityAlias, SAMLConstants.SAML2_REDIRECT_BINDING_URI));
}
if (binding.equals(SAMLConstants.SAML2_SOAP11_BINDING_URI)) {
idpDescriptor.getSingleLogoutServices().add(
getSingleLogoutService(entityBaseURL, entityAlias, SAMLConstants.SAML2_SOAP11_BINDING_URI));
}
}
// Build extensions
Extensions extensions = buildExtensions(entityBaseURL, entityAlias);
if (extensions != null) {
idpDescriptor.setExtensions(extensions);
}
// Populate key aliases
String signingKey = getSigningKey();
String encryptionKey = getEncryptionKey();
String tlsKey = getTLSKey();
// Generate key info
if (signingKey != null) {
idpDescriptor.getKeyDescriptors().add(getKeyDescriptor(UsageType.SIGNING, getServerKeyInfo(signingKey)));
} else {
log.info(
"Generating metadata without signing key, KeyStore doesn't contain any default private key, or the signingKey specified in ExtendedMetadata cannot be found");
}
if (encryptionKey != null) {
idpDescriptor.getKeyDescriptors()
.add(getKeyDescriptor(UsageType.ENCRYPTION, getServerKeyInfo(encryptionKey)));
} else {
log.info(
"Generating metadata without encryption key, KeyStore doesn't contain any default private key, or the encryptionKey specified in ExtendedMetadata cannot be found");
}
// Include TLS key with unspecified usage in case it differs from the singing and encryption keys
if (tlsKey != null && !(tlsKey.equals(encryptionKey)) && !(tlsKey.equals(signingKey))) {
idpDescriptor.getKeyDescriptors().add(getKeyDescriptor(UsageType.UNSPECIFIED, getServerKeyInfo(tlsKey)));
}
return idpDescriptor;
}
/**
* Method iterates all values in the input, for each tries to resolve correct alias. When alias value is found, it
* is entered into the return collection, otherwise warning is logged. Values are returned in order of input with
* all duplicities removed.
*
* @param values
* input collection
* @return result with resolved aliases
*/
protected Collection<String> mapAliases(Collection<String> values) {
LinkedHashSet<String> result = new LinkedHashSet<String>();
for (String value : values) {
String alias = aliases.get(value);
if (alias != null) {
result.add(alias);
} else {
log.warn("Unsupported value " + value + " found");
}
}
return result;
}
protected Extensions buildExtensions(String entityBaseURL, String entityAlias) {
boolean include = false;
Extensions extensions = new ExtensionsBuilder().buildObject();
// Add discovery
if (isIncludeDiscoveryExtension()) {
DiscoveryResponse discoveryService = getDiscoveryService(entityBaseURL, entityAlias);
extensions.getUnknownXMLObjects().add(discoveryService);
include = true;
}
if (include) {
return extensions;
} else {
return null;
}
}
protected KeyDescriptor getKeyDescriptor(UsageType type, KeyInfo key) {
@SuppressWarnings("unchecked")
SAMLObjectBuilder<KeyDescriptor> builder = (SAMLObjectBuilder<KeyDescriptor>) Configuration.getBuilderFactory()
.getBuilder(KeyDescriptor.DEFAULT_ELEMENT_NAME);
KeyDescriptor descriptor = builder.buildObject();
descriptor.setUse(type);
descriptor.setKeyInfo(key);
return descriptor;
}
protected Collection<NameIDFormat> getNameIDFormat(Collection<String> includedNameID) {
// Resolve alases
includedNameID = mapAliases(includedNameID);
Collection<NameIDFormat> formats = new LinkedList<NameIDFormat>();
@SuppressWarnings("unchecked")
SAMLObjectBuilder<NameIDFormat> builder = (SAMLObjectBuilder<NameIDFormat>) builderFactory
.getBuilder(NameIDFormat.DEFAULT_ELEMENT_NAME);
// Populate nameIDs
for (String nameIDValue : includedNameID) {
if (nameIDValue.equals(NameIDType.EMAIL)) {
NameIDFormat nameID = builder.buildObject();
nameID.setFormat(NameIDType.EMAIL);
formats.add(nameID);
}
if (nameIDValue.equals(NameIDType.TRANSIENT)) {
NameIDFormat nameID = builder.buildObject();
nameID.setFormat(NameIDType.TRANSIENT);
formats.add(nameID);
}
if (nameIDValue.equals(NameIDType.PERSISTENT)) {
NameIDFormat nameID = builder.buildObject();
nameID.setFormat(NameIDType.PERSISTENT);
formats.add(nameID);
}
if (nameIDValue.equals(NameIDType.UNSPECIFIED)) {
NameIDFormat nameID = builder.buildObject();
nameID.setFormat(NameIDType.UNSPECIFIED);
formats.add(nameID);
}
if (nameIDValue.equals(NameIDType.X509_SUBJECT)) {
NameIDFormat nameID = builder.buildObject();
nameID.setFormat(NameIDType.X509_SUBJECT);
formats.add(nameID);
}
}
return formats;
}
protected SingleSignOnService getSingleSignOnService(String entityBaseURL, String entityAlias, String filterURL,
String binding) {
@SuppressWarnings("unchecked")
SAMLObjectBuilder<SingleSignOnService> builder = (SAMLObjectBuilder<SingleSignOnService>) builderFactory
.getBuilder(SingleSignOnService.DEFAULT_ELEMENT_NAME);
SingleSignOnService sso = builder.buildObject();
sso.setLocation(getServerURL(entityBaseURL, entityAlias, filterURL));
sso.setBinding(binding);
return sso;
}
protected SingleSignOnService getHoKSingleSignOnService(String entityBaseURL, String entityAlias, String filterURL,
String binding) {
SingleSignOnService hokSso = getSingleSignOnService(entityBaseURL, entityAlias, filterURL,
org.springframework.security.saml.SAMLConstants.SAML2_HOK_WEBSSO_PROFILE_URI);
QName consumerName = new QName(org.springframework.security.saml.SAMLConstants.SAML2_HOK_WEBSSO_PROFILE_URI,
AuthnRequest.PROTOCOL_BINDING_ATTRIB_NAME, "hoksso");
hokSso.getUnknownAttributes().put(consumerName, binding);
return hokSso;
}
protected DiscoveryResponse getDiscoveryService(String entityBaseURL, String entityAlias) {
@SuppressWarnings("unchecked")
SAMLObjectBuilder<DiscoveryResponse> builder = (SAMLObjectBuilder<DiscoveryResponse>) builderFactory
.getBuilder(DiscoveryResponse.DEFAULT_ELEMENT_NAME);
DiscoveryResponse discovery = builder.buildObject(DiscoveryResponse.DEFAULT_ELEMENT_NAME);
discovery.setBinding(DiscoveryResponse.IDP_DISCO_NS);
discovery.setLocation(getDiscoveryResponseURL(entityBaseURL, entityAlias));
return discovery;
}
protected SingleLogoutService getSingleLogoutService(String entityBaseURL, String entityAlias, String binding) {
@SuppressWarnings("unchecked")
SAMLObjectBuilder<SingleLogoutService> builder = (SAMLObjectBuilder<SingleLogoutService>) builderFactory
.getBuilder(SingleLogoutService.DEFAULT_ELEMENT_NAME);
SingleLogoutService logoutService = builder.buildObject();
logoutService.setLocation(getServerURL(entityBaseURL, entityAlias, getSAMLLogoutFilterPath()));
logoutService.setBinding(binding);
return logoutService;
}
/**
* Creates URL at which the local server is capable of accepting incoming SAML messages.
*
* @param entityBaseURL
* entity ID
* @param processingURL
* local context at which processing filter is waiting
* @return URL of local server
*/
private String getServerURL(String entityBaseURL, String entityAlias, String processingURL) {
return getServerURL(entityBaseURL, entityAlias, processingURL, null);
}
/**
* Creates URL at which the local server is capable of accepting incoming SAML messages.
*
* @param entityBaseURL
* entity ID
* @param processingURL
* local context at which processing filter is waiting
* @param parameters
* key - value pairs to be included as query part of the generated url, can be null
* @return URL of local server
*/
private String getServerURL(String entityBaseURL, String entityAlias, String processingURL,
Map<String, String> parameters) {
StringBuilder result = new StringBuilder();
result.append(entityBaseURL);
if (!processingURL.startsWith("/")) {
result.append("/");
}
result.append(processingURL);
if (entityAlias != null) {
if (!processingURL.endsWith("/")) {
result.append("/");
}
result.append("alias/");
result.append(entityAlias);
}
String resultString = result.toString();
if (parameters == null || parameters.size() == 0) {
return resultString;
} else {
// Add parameters
URLBuilder returnUrlBuilder = new URLBuilder(resultString);
for (Map.Entry<String, String> entry : parameters.entrySet()) {
returnUrlBuilder.getQueryParams().add(new Pair<String, String>(entry.getKey(), entry.getValue()));
}
return returnUrlBuilder.buildURL();
}
}
private String getSAMLWebSSOProcessingFilterPath() {
if (samlWebSSOFilter != null) {
return samlWebSSOFilter.getFilterProcessesUrl();
} else {
return SAMLProcessingFilter.FILTER_URL;
}
}
private String getSAMLEntryPointPath() {
if (samlEntryPoint != null) {
return samlEntryPoint.getFilterProcessesUrl();
} else {
return SAMLEntryPoint.FILTER_URL;
}
}
private String getSAMLDiscoveryPath() {
if (samlDiscovery != null) {
return samlDiscovery.getFilterProcessesUrl();
} else {
return SAMLDiscovery.FILTER_URL;
}
}
private String getSAMLLogoutFilterPath() {
if (samlLogoutProcessingFilter != null) {
return samlLogoutProcessingFilter.getFilterProcessesUrl();
} else {
return SAMLLogoutProcessingFilter.FILTER_URL;
}
}
@Autowired(required = false)
@Qualifier("samlWebSSOProcessingFilter")
public void setSamlWebSSOFilter(SAMLProcessingFilter samlWebSSOFilter) {
this.samlWebSSOFilter = samlWebSSOFilter;
}
@Autowired(required = false)
@Qualifier("samlWebSSOHoKProcessingFilter")
public void setSamlWebSSOHoKFilter(SAMLWebSSOHoKProcessingFilter samlWebSSOHoKFilter) {
this.samlWebSSOHoKFilter = samlWebSSOHoKFilter;
}
@Autowired(required = false)
public void setSamlLogoutProcessingFilter(SAMLLogoutProcessingFilter samlLogoutProcessingFilter) {
this.samlLogoutProcessingFilter = samlLogoutProcessingFilter;
}
@Autowired(required = false)
public void setSamlEntryPoint(SAMLEntryPoint samlEntryPoint) {
this.samlEntryPoint = samlEntryPoint;
}
public boolean isWantAuthnRequestSigned() {
return wantAuthnRequestSigned;
}
public void setWantAuthnRequestSigned(boolean wantAuthnRequestSigned) {
this.wantAuthnRequestSigned = wantAuthnRequestSigned;
}
public Collection<String> getNameID() {
return nameID == null ? defaultNameID : nameID;
}
public void setNameID(Collection<String> nameID) {
this.nameID = nameID;
}
public String getEntityBaseURL() {
return entityBaseURL;
}
public void setEntityBaseURL(String entityBaseURL) {
this.entityBaseURL = entityBaseURL;
}
@Autowired
public void setKeyManager(KeyManager keyManager) {
this.keyManager = keyManager;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
public void setEntityId(String entityId) {
this.entityId = entityId;
}
public String getEntityId() {
return entityId;
}
public Collection<String> getBindingsSSO() {
return bindingsSSO;
}
/**
* List of bindings to be included in the generated metadata for Web Single Sign-On. Ordering of bindings affects
* inclusion in the generated metadata.
*
* Supported values are: "artifact" (or "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"), "post" (or
* "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST") and "paos" (or "urn:oasis:names:tc:SAML:2.0:bindings:PAOS").
*
* The following bindings are included by default: "artifact", "post"
*
* @param bindingsSSO
* bindings for web single sign-on
*/
public void setBindingsSSO(Collection<String> bindingsSSO) {
if (bindingsSSO == null) {
this.bindingsSSO = Collections.emptyList();
} else {
this.bindingsSSO = bindingsSSO;
}
}
public Collection<String> getBindingsSLO() {
return bindingsSLO;
}
/**
* List of bindings to be included in the generated metadata for Single Logout. Ordering of bindings affects
* inclusion in the generated metadata.
*
* Supported values are: "post" (or "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST") and "redirect" (or
* "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect").
*
* The following bindings are included by default: "post", "redirect"
*
* @param bindingsSLO
* bindings for single logout
*/
public void setBindingsSLO(Collection<String> bindingsSLO) {
if (bindingsSLO == null) {
this.bindingsSLO = Collections.emptyList();
} else {
this.bindingsSLO = bindingsSLO;
}
}
public Collection<String> getBindingsHoKSSO() {
return bindingsHoKSSO;
}
/**
* List of bindings to be included in the generated metadata for Web Single Sign-On Holder of Key. Ordering of
* bindings affects inclusion in the generated metadata.
*
* Supported values are: "artifact" (or "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact") and "post" (or
* "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST").
*
* By default there are no included bindings for the profile.
*
* @param bindingsHoKSSO
* bindings for web single sign-on holder-of-key
*/
public void setBindingsHoKSSO(Collection<String> bindingsHoKSSO) {
if (bindingsHoKSSO == null) {
this.bindingsHoKSSO = Collections.emptyList();
} else {
this.bindingsHoKSSO = bindingsHoKSSO;
}
}
public boolean isIncludeDiscoveryExtension() {
return includeDiscoveryExtension;
}
/**
* When true discovery profile extension metadata pointing to the default SAMLEntryPoint will be generated and
* stored in the generated metadata document.
*
* @param includeDiscoveryExtension
* flag indicating whether IDP discovery should be enabled
*/
public void setIncludeDiscoveryExtension(boolean includeDiscoveryExtension) {
this.includeDiscoveryExtension = includeDiscoveryExtension;
}
public int getAssertionConsumerIndex() {
return assertionConsumerIndex;
}
/**
* Generated assertion consumer service with the index equaling set value will be marked as default. Use negative
* value to skip the default attribute altogether.
*
* @param assertionConsumerIndex
* assertion consumer index of service to mark as default
*/
public void setAssertionConsumerIndex(int assertionConsumerIndex) {
this.assertionConsumerIndex = assertionConsumerIndex;
}
/**
* True when IDP discovery is enabled either on local property includeDiscovery or property idpDiscoveryEnabled in
* the extended metadata.
*
* @return true when discovery is enabled
*/
protected boolean isIncludeDiscovery() {
return extendedMetadata != null && extendedMetadata.isIdpDiscoveryEnabled();
}
/**
* Provides set discovery request url or generates a default when none was provided. Primarily value set on
* extenedMetadata property idpDiscoveryURL is used, when empty local property customDiscoveryURL is used, when
* empty URL is automatically generated.
*
* @param entityBaseURL
* base URL for generation of endpoints
* @param entityAlias
* alias of entity, or null when there's no alias required
* @return URL to use for IDP discovery request
*/
protected String getDiscoveryURL(String entityBaseURL, String entityAlias) {
if (extendedMetadata != null && extendedMetadata.getIdpDiscoveryURL() != null
&& extendedMetadata.getIdpDiscoveryURL().length() > 0) {
return extendedMetadata.getIdpDiscoveryURL();
} else {
return getServerURL(entityBaseURL, entityAlias, getSAMLDiscoveryPath());
}
}
/**
* Provides set discovery response url or generates a default when none was provided. Primarily value set on
* extenedMetadata property idpDiscoveryResponseURL is used, when empty local property customDiscoveryResponseURL
* is used, when empty URL is automatically generated.
*
* @param entityBaseURL
* base URL for generation of endpoints
* @param entityAlias
* alias of entity, or null when there's no alias required
* @return URL to use for IDP discovery response
*/
protected String getDiscoveryResponseURL(String entityBaseURL, String entityAlias) {
if (extendedMetadata != null && extendedMetadata.getIdpDiscoveryResponseURL() != null
&& extendedMetadata.getIdpDiscoveryResponseURL().length() > 0) {
return extendedMetadata.getIdpDiscoveryResponseURL();
} else {
Map<String, String> params = new HashMap<String, String>();
params.put(SAMLEntryPoint.DISCOVERY_RESPONSE_PARAMETER, "true");
return getServerURL(entityBaseURL, entityAlias, getSAMLEntryPointPath(), params);
}
}
/**
* Provides key used for signing from extended metadata. Uses default key when key is not specified.
*
* @return signing key
*/
protected String getSigningKey() {
if (extendedMetadata != null && extendedMetadata.getSigningKey() != null) {
return extendedMetadata.getSigningKey();
} else {
return keyManager.getDefaultCredentialName();
}
}
/**
* Provides key used for encryption from extended metadata. Uses default when key is not specified.
*
* @return encryption key
*/
protected String getEncryptionKey() {
if (extendedMetadata != null && extendedMetadata.getEncryptionKey() != null) {
return extendedMetadata.getEncryptionKey();
} else {
return keyManager.getDefaultCredentialName();
}
}
/**
* Provides key used for SSL/TLS from extended metadata. Uses null when key is not specified.
*
* @return tls key
*/
protected String getTLSKey() {
if (extendedMetadata != null && extendedMetadata.getTlsKey() != null) {
return extendedMetadata.getTlsKey();
} else {
return null;
}
}
/**
* Provides entity alias from extended metadata, or null when metadata isn't specified or contains null.
*
* @return entity alias
*/
protected String getEntityAlias() {
if (extendedMetadata != null) {
return extendedMetadata.getAlias();
} else {
return null;
}
}
public boolean isAssertionsSigned() {
if (extendedMetadata != null) {
return extendedMetadata.isAssertionsSigned();
} else {
return true;
}
}
public int getAssertionTimeToLiveSeconds() {
if (extendedMetadata != null) {
return extendedMetadata.getAssertionTimeToLiveSeconds();
} else {
return 600;
}
}
/**
* Extended metadata which contains details on configuration of the generated service provider metadata.
*
* @return extended metadata
*/
public ExtendedMetadata getExtendedMetadata() {
return extendedMetadata;
}
/**
* Default value for generation of extended metadata. Value is cloned upon each request to generate new
* ExtendedMetadata object.
*
* @param extendedMetadata
* default extended metadata or null
*/
public void setExtendedMetadata(IdpExtendedMetadata extendedMetadata) {
this.extendedMetadata = extendedMetadata;
}
}