All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.onelogin.saml2.settings.Metadata Maven / Gradle / Ivy

There is a newer version: 2.9.0
Show newest version
package com.onelogin.saml2.settings;

import java.net.URL;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.xpath.XPathExpressionException;

import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.security.PrivateKey;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.apache.xml.security.exceptions.XMLSecurityException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;

import com.onelogin.saml2.model.Contact;
import com.onelogin.saml2.model.Organization;
import com.onelogin.saml2.model.AttributeConsumingService;
import com.onelogin.saml2.model.RequestedAttribute;
import com.onelogin.saml2.util.Constants;
import com.onelogin.saml2.util.Util;

/**
 * Metadata class of OneLogin's Java Toolkit.
 *
 * A class that contains methods related to the metadata of the SP
 */
public class Metadata {
	/**
     * Private property to construct a logger for this class.
     */
	private static final Logger LOGGER = LoggerFactory.getLogger(Metadata.class);
	
	// Constants
	private static final int N_DAYS_VALID_UNTIL = 2;
	private static final int SECONDS_CACHED = 604800; // 1 week

	/**
     * AttributeConsumingService 
     */
	private AttributeConsumingService attributeConsumingService = null;
	
	/**
     * Generated metadata in string format
     */
	private final String metadataString;

	/**
     * validUntilTime of the metadata. How long the metadata is valid
     */
	private final Calendar validUntilTime;

	/**
     * cacheDuration of the metadata. Duration of the cache in seconds
     */
	private final Integer cacheDuration;

	/**
	 * Constructs the Metadata object.
	 * 
	 * @param settings
	 * 				Saml2Settings object. Setting data  
	 * @param validUntilTime 
	 * 				Metadata's valid time 
	 * @param cacheDuration
	 * 				Duration of the cache in seconds
	 * @param attributeConsumingService
	 * 				AttributeConsumingService of service provider
	 * 
	 * @throws CertificateEncodingException 
	 */
	public Metadata(Saml2Settings settings, Calendar validUntilTime, Integer cacheDuration, AttributeConsumingService attributeConsumingService) throws CertificateEncodingException {
		if (validUntilTime == null) {
			this.validUntilTime = Calendar.getInstance();
			this.validUntilTime.add(Calendar.DAY_OF_YEAR, N_DAYS_VALID_UNTIL);
		} else {
			this.validUntilTime = validUntilTime;
		}
		
		this.attributeConsumingService = attributeConsumingService;

		if (cacheDuration == null) {
			this.cacheDuration = SECONDS_CACHED;
		} else {
			this.cacheDuration = cacheDuration;
		}

		StrSubstitutor substitutor = generateSubstitutor(settings);
		String unsignedMetadataString = substitutor.replace(getMetadataTemplate());

    	LOGGER.debug("metadata --> " + unsignedMetadataString);
    	metadataString = unsignedMetadataString;
	}

	/**
	 * Constructs the Metadata object.
	 * 
	 * @param settings
	 * 				Saml2Settings object. Setting data  
	 * @param validUntilTime 
	 * 				Metadata's valid time 
	 * @param cacheDuration
	 * 				Duration of the cache in seconds
	 * 
	 * @throws CertificateEncodingException 
	 */
	public Metadata(Saml2Settings settings, Calendar validUntilTime, Integer cacheDuration) throws CertificateEncodingException {
		this(settings, validUntilTime, cacheDuration, null);
	}
		
	/**
	 * Constructs the Metadata object.
	 *
	 * @param settings
	 * 				Saml2Settings object. Setting data  
	 *
	 * @throws CertificateEncodingException 
	 */
	public Metadata(Saml2Settings settings) throws CertificateEncodingException {
		this(settings, null, null);
	}
	
	/**
	 * Substitutes metadata variables within a string by values.
	 *
	 * @param settings
	 * 				Saml2Settings object. Setting data
	 * 
	 * @return the StrSubstitutor object of the metadata 
	 */ 
	private StrSubstitutor generateSubstitutor(Saml2Settings settings) throws CertificateEncodingException {

		Map valueMap = new HashMap();
		Boolean wantsEncrypted = settings.getWantAssertionsEncrypted() || settings.getWantNameIdEncrypted(); 
		
		valueMap.put("id", Util.generateUniqueID(settings.getUniqueIDPrefix()));
		valueMap.put("validUntilTime", Util.formatDateTime(validUntilTime.getTimeInMillis()));
		valueMap.put("cacheDuration", String.valueOf(cacheDuration));
		valueMap.put("spEntityId", settings.getSpEntityId());
		valueMap.put("strAuthnsign", String.valueOf(settings.getAuthnRequestsSigned()));
		valueMap.put("strWsign", String.valueOf(settings.getWantAssertionsSigned()));
		valueMap.put("spNameIDFormat", settings.getSpNameIDFormat());
		valueMap.put("spAssertionConsumerServiceBinding", settings.getSpAssertionConsumerServiceBinding());
		valueMap.put("spAssertionConsumerServiceUrl", settings.getSpAssertionConsumerServiceUrl().toString());
		valueMap.put("sls", toSLSXml(settings.getSpSingleLogoutServiceUrl(), settings.getSpSingleLogoutServiceBinding()));

		valueMap.put("strAttributeConsumingService", getAttributeConsumingServiceXml());
		
		valueMap.put("strKeyDescriptor", toX509KeyDescriptorsXML(settings.getSPcert(), wantsEncrypted));
		valueMap.put("strContacts", toContactsXml(settings.getContacts()));
		valueMap.put("strOrganization", toOrganizationXml(settings.getOrganization()));

		return new StrSubstitutor(valueMap);
	}

	/**
	 * @return the metadata's template
	 */
	private static StringBuilder getMetadataTemplate() {

		StringBuilder template = new StringBuilder();
		template.append("");
		template.append("");
		template.append("");
		template.append("${strKeyDescriptor}");
		template.append("${sls}${spNameIDFormat}");
		template.append("");
		template.append("${strAttributeConsumingService}");
		template.append("${strOrganization}${strContacts}");
		template.append("");

		return template;
	}

	/**
	 * Generates the AttributeConsumingService section of the metadata's template
	 *
	 *
	 * @return the AttributeConsumingService section of the metadata's template
	 */
	private String getAttributeConsumingServiceXml() {
		StringBuilder attributeConsumingServiceXML = new StringBuilder();
		if (attributeConsumingService != null) {
			String serviceName = attributeConsumingService.getServiceName();
			String serviceDescription = attributeConsumingService.getServiceDescription();
			List requestedAttributes = attributeConsumingService.getRequestedAttributes();

			attributeConsumingServiceXML.append("");
			if (serviceName != null && !serviceName.isEmpty()) {
				attributeConsumingServiceXML.append("" + serviceName + "");
			}
			if (serviceDescription != null && !serviceDescription.isEmpty()) {
				attributeConsumingServiceXML.append("" + serviceDescription + "");
			}
			if (requestedAttributes != null && !requestedAttributes.isEmpty()) {
				for (RequestedAttribute requestedAttribute : requestedAttributes) {
					String name = requestedAttribute.getName();
					String friendlyName = requestedAttribute.getFriendlyName();
					String nameFormat = requestedAttribute.getNameFormat();
					Boolean isRequired = requestedAttribute.isRequired();
					List attrValues = requestedAttribute.getAttributeValues() ;

					String contentStr = "" + attrValue + "";
						}
						attributeConsumingServiceXML.append(contentStr + "");
					} else {
						attributeConsumingServiceXML.append(contentStr + " />");
					}
				}
			}
			attributeConsumingServiceXML.append("");
		}
		
		return attributeConsumingServiceXML.toString();
	}
	
	/**
	 * Generates the contact section of the metadata's template
	 *
	 * @param contacts
	 * 				List of contact objects
	 *
	 * @return the contact section of the metadata's template
	 */
	private String toContactsXml(List contacts) {
		StringBuilder contactsXml = new StringBuilder();

		for (Contact contact : contacts) {
			contactsXml.append("");
			contactsXml.append("" + contact.getGivenName() + "");
			contactsXml.append("" + contact.getEmailAddress() + "");
			contactsXml.append("");
		}

		return contactsXml.toString();
	}

	/**
	 * Generates the organization section of the metadata's template
	 *
	 * @param organization
	 * 				organization object
	 *  @return the organization section of the metadata's template
	 */
	private String toOrganizationXml(Organization organization) {
		String orgXml = "";

		if (organization != null) {
			String lang = organization.getOrgLangAttribute();
			orgXml = "" + organization.getOrgName()
					+ ""
					+ organization.getOrgDisplayName() + "" + organization.getOrgUrl() + "";
		}
		return orgXml;
	}

	/**
	 * Generates the KeyDescriptor section of the metadata's template
	 * 
	 * @param cert
	 * 				the public cert that will be used by the SP to sign and encrypt
	 * @param wantsEncrypted
	 * 				Whether to include the KeyDescriptor for encryption
	 *
	 * @return the KeyDescriptor section of the metadata's template
	 */
	private String toX509KeyDescriptorsXML(X509Certificate cert, Boolean wantsEncrypted) throws CertificateEncodingException {
		StringBuilder keyDescriptorXml = new StringBuilder();

		if (cert != null) {
			Base64 encoder = new Base64(64);
			byte[] encodedCert = cert.getEncoded();
			String certString = new String(encoder.encode(encodedCert));

			keyDescriptorXml.append("");
			keyDescriptorXml.append("");
			keyDescriptorXml.append("");
			keyDescriptorXml.append(""+certString+"");
			keyDescriptorXml.append("");
			keyDescriptorXml.append("");
			keyDescriptorXml.append("");

			if (wantsEncrypted) {
				keyDescriptorXml.append("");
				keyDescriptorXml.append("");
				keyDescriptorXml.append("");
				keyDescriptorXml.append(""+certString+"");
				keyDescriptorXml.append("");
				keyDescriptorXml.append("");
				keyDescriptorXml.append("");
			}
		}

		return keyDescriptorXml.toString();
	}

	/**
	 * Generates the KeyDescriptor section of the metadata's template
	 * 
	 * @param cert
	 * 				the public cert that will be used by the SP to sign and encrypt
	 *
	 * @return the KeyDescriptor section of the metadata's template
	 */
	private String toX509KeyDescriptorsXML(X509Certificate cert) throws CertificateEncodingException {
		return toX509KeyDescriptorsXML(cert, true);
	}
	
	/**
	 * @return the md:SingleLogoutService section of the metadata's template
	 */
	private String toSLSXml(URL spSingleLogoutServiceUrl, String spSingleLogoutServiceBinding) {
		StringBuilder slsXml = new StringBuilder();
		
		if (spSingleLogoutServiceUrl != null) {
			slsXml.append("");
		}
		return slsXml.toString();
	}

	/**
	 * @return the metadata
	 */
	public final String getMetadataString() {
		return metadataString;
	}

    /**
     * Signs the metadata with the key/cert provided
     *
     * @param metadata
     * 				SAML Metadata XML
     * @param key
     *       		Private Key
     * @param cert
     *      		x509 Public certificate
     * @param signAlgorithm
	 * 				Signature Algorithm
     *
     * @return string Signed Metadata
     * @throws XMLSecurityException
     * @throws XPathExpressionException
     */
    public static String signMetadata(String metadata, PrivateKey key, X509Certificate cert, String signAlgorithm) throws XPathExpressionException, XMLSecurityException
    {
        return signMetadata(metadata, key, cert, signAlgorithm, Constants.SHA1);
    }

    /**
     * Signs the metadata with the key/cert provided
     *
     * @param metadata
     * 				SAML Metadata XML
     * @param key
     *       		Private Key
     * @param cert
     *      		x509 Public certificate
     * @param signAlgorithm
	 * 				Signature Algorithm
     * @param digestAlgorithm
	 * 				Digest Algorithm
     *
     * @return string Signed Metadata
     * @throws XMLSecurityException
     * @throws XPathExpressionException
     */
    public static String signMetadata(String metadata, PrivateKey key, X509Certificate cert, String signAlgorithm, String digestAlgorithm) throws XPathExpressionException, XMLSecurityException
    {
        Document metadataDoc = Util.loadXML(metadata);
        String signedMetadata = Util.addSign(metadataDoc, key, cert, signAlgorithm, digestAlgorithm);
        LOGGER.debug("Signed metadata --> " + signedMetadata);
        return signedMetadata;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy