|  | @@ -1,247 +0,0 @@
 | 
	
		
			
				|  |  | -/*
 | 
	
		
			
				|  |  | - * Copyright 2002-2020 the original author or authors.
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Licensed under the Apache License, Version 2.0 (the "License");
 | 
	
		
			
				|  |  | - * you may not use this file except in compliance with the License.
 | 
	
		
			
				|  |  | - * You may obtain a copy of the License at
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - *      https://www.apache.org/licenses/LICENSE-2.0
 | 
	
		
			
				|  |  | - *
 | 
	
		
			
				|  |  | - * Unless required by applicable law or agreed to in writing, software
 | 
	
		
			
				|  |  | - * distributed under the License is distributed on an "AS IS" BASIS,
 | 
	
		
			
				|  |  | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
	
		
			
				|  |  | - * See the License for the specific language governing permissions and
 | 
	
		
			
				|  |  | - * limitations under the License.
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -package org.springframework.security.saml2.provider.service.authentication;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -import java.io.ByteArrayInputStream;
 | 
	
		
			
				|  |  | -import java.nio.charset.Charset;
 | 
	
		
			
				|  |  | -import java.nio.charset.StandardCharsets;
 | 
	
		
			
				|  |  | -import java.util.Collection;
 | 
	
		
			
				|  |  | -import java.util.LinkedHashMap;
 | 
	
		
			
				|  |  | -import java.util.Map;
 | 
	
		
			
				|  |  | -import javax.xml.namespace.QName;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -import net.shibboleth.utilities.java.support.xml.SerializeSupport;
 | 
	
		
			
				|  |  | -import net.shibboleth.utilities.java.support.xml.XMLParserException;
 | 
	
		
			
				|  |  | -import org.opensaml.core.xml.XMLObject;
 | 
	
		
			
				|  |  | -import org.opensaml.core.xml.XMLObjectBuilderFactory;
 | 
	
		
			
				|  |  | -import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 | 
	
		
			
				|  |  | -import org.opensaml.core.xml.io.MarshallerFactory;
 | 
	
		
			
				|  |  | -import org.opensaml.core.xml.io.MarshallingException;
 | 
	
		
			
				|  |  | -import org.opensaml.core.xml.io.UnmarshallerFactory;
 | 
	
		
			
				|  |  | -import org.opensaml.core.xml.io.UnmarshallingException;
 | 
	
		
			
				|  |  | -import org.opensaml.saml.saml2.core.AuthnRequest;
 | 
	
		
			
				|  |  | -import org.opensaml.saml.saml2.encryption.EncryptedElementTypeEncryptedKeyResolver;
 | 
	
		
			
				|  |  | -import org.opensaml.security.SecurityException;
 | 
	
		
			
				|  |  | -import org.opensaml.security.credential.BasicCredential;
 | 
	
		
			
				|  |  | -import org.opensaml.security.credential.Credential;
 | 
	
		
			
				|  |  | -import org.opensaml.security.credential.CredentialSupport;
 | 
	
		
			
				|  |  | -import org.opensaml.security.credential.UsageType;
 | 
	
		
			
				|  |  | -import org.opensaml.security.x509.BasicX509Credential;
 | 
	
		
			
				|  |  | -import org.opensaml.xmlsec.SignatureSigningParameters;
 | 
	
		
			
				|  |  | -import org.opensaml.xmlsec.crypto.XMLSigningUtil;
 | 
	
		
			
				|  |  | -import org.opensaml.xmlsec.encryption.support.ChainingEncryptedKeyResolver;
 | 
	
		
			
				|  |  | -import org.opensaml.xmlsec.encryption.support.EncryptedKeyResolver;
 | 
	
		
			
				|  |  | -import org.opensaml.xmlsec.encryption.support.InlineEncryptedKeyResolver;
 | 
	
		
			
				|  |  | -import org.opensaml.xmlsec.encryption.support.SimpleRetrievalMethodEncryptedKeyResolver;
 | 
	
		
			
				|  |  | -import org.opensaml.xmlsec.signature.support.SignatureConstants;
 | 
	
		
			
				|  |  | -import org.opensaml.xmlsec.signature.support.SignatureException;
 | 
	
		
			
				|  |  | -import org.opensaml.xmlsec.signature.support.SignatureSupport;
 | 
	
		
			
				|  |  | -import org.w3c.dom.Document;
 | 
	
		
			
				|  |  | -import org.w3c.dom.Element;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -import org.springframework.security.saml2.Saml2Exception;
 | 
	
		
			
				|  |  | -import org.springframework.security.saml2.core.OpenSamlInitializationService;
 | 
	
		
			
				|  |  | -import org.springframework.security.saml2.core.Saml2X509Credential;
 | 
	
		
			
				|  |  | -import org.springframework.util.Assert;
 | 
	
		
			
				|  |  | -import org.springframework.web.util.UriUtils;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -import static java.util.Arrays.asList;
 | 
	
		
			
				|  |  | -import static org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport.getParserPool;
 | 
	
		
			
				|  |  | -import static org.springframework.util.StringUtils.hasText;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/**
 | 
	
		
			
				|  |  | - * @since 5.2
 | 
	
		
			
				|  |  | - */
 | 
	
		
			
				|  |  | -final class OpenSamlImplementation {
 | 
	
		
			
				|  |  | -	static {
 | 
	
		
			
				|  |  | -		OpenSamlInitializationService.initialize();
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	private static OpenSamlImplementation instance = new OpenSamlImplementation();
 | 
	
		
			
				|  |  | -	private static XMLObjectBuilderFactory xmlObjectBuilderFactory =
 | 
	
		
			
				|  |  | -			XMLObjectProviderRegistrySupport.getBuilderFactory();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	private final EncryptedKeyResolver encryptedKeyResolver = new ChainingEncryptedKeyResolver(
 | 
	
		
			
				|  |  | -			asList(
 | 
	
		
			
				|  |  | -					new InlineEncryptedKeyResolver(),
 | 
	
		
			
				|  |  | -					new EncryptedElementTypeEncryptedKeyResolver(),
 | 
	
		
			
				|  |  | -					new SimpleRetrievalMethodEncryptedKeyResolver()
 | 
	
		
			
				|  |  | -			)
 | 
	
		
			
				|  |  | -	);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	/*
 | 
	
		
			
				|  |  | -	 * ==============================================================
 | 
	
		
			
				|  |  | -	 * PUBLIC METHODS
 | 
	
		
			
				|  |  | -	 * ==============================================================
 | 
	
		
			
				|  |  | -	 */
 | 
	
		
			
				|  |  | -	static OpenSamlImplementation getInstance() {
 | 
	
		
			
				|  |  | -		return instance;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	EncryptedKeyResolver getEncryptedKeyResolver() {
 | 
	
		
			
				|  |  | -		return this.encryptedKeyResolver;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	<T> T buildSamlObject(QName qName) {
 | 
	
		
			
				|  |  | -		return (T) xmlObjectBuilderFactory.getBuilder(qName).buildObject(qName);
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	XMLObject resolve(String xml) {
 | 
	
		
			
				|  |  | -		return resolve(xml.getBytes(StandardCharsets.UTF_8));
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	String serialize(XMLObject xmlObject) {
 | 
	
		
			
				|  |  | -		final MarshallerFactory marshallerFactory = XMLObjectProviderRegistrySupport.getMarshallerFactory();
 | 
	
		
			
				|  |  | -		try {
 | 
	
		
			
				|  |  | -			Element element = marshallerFactory.getMarshaller(xmlObject).marshall(xmlObject);
 | 
	
		
			
				|  |  | -			return SerializeSupport.nodeToString(element);
 | 
	
		
			
				|  |  | -		} catch (MarshallingException e) {
 | 
	
		
			
				|  |  | -			throw new Saml2Exception(e);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	/**
 | 
	
		
			
				|  |  | -	 * Returns query parameter after creating a Query String signature
 | 
	
		
			
				|  |  | -	 * All return values are unencoded and will need to be encoded prior to sending
 | 
	
		
			
				|  |  | -	 * The methods {@link UriUtils#encode(String, Charset)} and {@link UriUtils#decode(String, Charset)}
 | 
	
		
			
				|  |  | -	 * with the {@link StandardCharsets#ISO_8859_1} character set are used for all URL encoding/decoding.
 | 
	
		
			
				|  |  | -	 * @param signingCredentials - credentials to be used for signature
 | 
	
		
			
				|  |  | -	 * @return a map of unencoded query parameters with the following keys:
 | 
	
		
			
				|  |  | -	 * {@code {SAMLRequest, RelayState (may be null)}, SigAlg, Signature}
 | 
	
		
			
				|  |  | -	 *
 | 
	
		
			
				|  |  | -	 */
 | 
	
		
			
				|  |  | -	Map<String, String> signQueryParameters(
 | 
	
		
			
				|  |  | -			Collection<Saml2X509Credential> signingCredentials,
 | 
	
		
			
				|  |  | -			String samlRequest,
 | 
	
		
			
				|  |  | -			String relayState) {
 | 
	
		
			
				|  |  | -		Assert.notNull(samlRequest, "samlRequest cannot be null");
 | 
	
		
			
				|  |  | -		String algorithmUri = SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256;
 | 
	
		
			
				|  |  | -		StringBuilder queryString = new StringBuilder();
 | 
	
		
			
				|  |  | -		queryString
 | 
	
		
			
				|  |  | -				.append("SAMLRequest")
 | 
	
		
			
				|  |  | -				.append("=")
 | 
	
		
			
				|  |  | -				.append(UriUtils.encode(samlRequest, StandardCharsets.ISO_8859_1))
 | 
	
		
			
				|  |  | -				.append("&");
 | 
	
		
			
				|  |  | -		if (hasText(relayState)) {
 | 
	
		
			
				|  |  | -			queryString
 | 
	
		
			
				|  |  | -					.append("RelayState")
 | 
	
		
			
				|  |  | -					.append("=")
 | 
	
		
			
				|  |  | -					.append(UriUtils.encode(relayState, StandardCharsets.ISO_8859_1))
 | 
	
		
			
				|  |  | -					.append("&");
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		queryString
 | 
	
		
			
				|  |  | -				.append("SigAlg")
 | 
	
		
			
				|  |  | -				.append("=")
 | 
	
		
			
				|  |  | -				.append(UriUtils.encode(algorithmUri, StandardCharsets.ISO_8859_1));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		try {
 | 
	
		
			
				|  |  | -			byte[] rawSignature = XMLSigningUtil.signWithURI(
 | 
	
		
			
				|  |  | -					getSigningCredential(signingCredentials, ""),
 | 
	
		
			
				|  |  | -					algorithmUri,
 | 
	
		
			
				|  |  | -					queryString.toString().getBytes(StandardCharsets.UTF_8)
 | 
	
		
			
				|  |  | -			);
 | 
	
		
			
				|  |  | -			String b64Signature = Saml2Utils.samlEncode(rawSignature);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			Map<String, String> result = new LinkedHashMap<>();
 | 
	
		
			
				|  |  | -			result.put("SAMLRequest", samlRequest);
 | 
	
		
			
				|  |  | -			if (hasText(relayState)) {
 | 
	
		
			
				|  |  | -				result.put("RelayState", relayState);
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			result.put("SigAlg", algorithmUri);
 | 
	
		
			
				|  |  | -			result.put("Signature", b64Signature);
 | 
	
		
			
				|  |  | -			return result;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		catch (SecurityException e) {
 | 
	
		
			
				|  |  | -			throw new Saml2Exception(e);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	/*
 | 
	
		
			
				|  |  | -	 * ==============================================================
 | 
	
		
			
				|  |  | -	 * PRIVATE METHODS
 | 
	
		
			
				|  |  | -	 * ==============================================================
 | 
	
		
			
				|  |  | -	 */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	private XMLObject resolve(byte[] xml) {
 | 
	
		
			
				|  |  | -		XMLObject parsed = parse(xml);
 | 
	
		
			
				|  |  | -		if (parsed != null) {
 | 
	
		
			
				|  |  | -			return parsed;
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		throw new Saml2Exception("Deserialization not supported for given data set");
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	private XMLObject parse(byte[] xml) {
 | 
	
		
			
				|  |  | -		try {
 | 
	
		
			
				|  |  | -			Document document = getParserPool().parse(new ByteArrayInputStream(xml));
 | 
	
		
			
				|  |  | -			Element element = document.getDocumentElement();
 | 
	
		
			
				|  |  | -			return getUnmarshallerFactory().getUnmarshaller(element).unmarshall(element);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		catch (UnmarshallingException | XMLParserException e) {
 | 
	
		
			
				|  |  | -			throw new Saml2Exception(e);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	private UnmarshallerFactory getUnmarshallerFactory() {
 | 
	
		
			
				|  |  | -		return XMLObjectProviderRegistrySupport.getUnmarshallerFactory();
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	private Saml2X509Credential hasSigningCredential(Collection<Saml2X509Credential> credentials) {
 | 
	
		
			
				|  |  | -		for (Saml2X509Credential c : credentials) {
 | 
	
		
			
				|  |  | -			if (c.isSigningCredential()) {
 | 
	
		
			
				|  |  | -				return c;
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		return null;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	private Credential getSigningCredential(Collection<Saml2X509Credential> signingCredential,
 | 
	
		
			
				|  |  | -											String localSpEntityId
 | 
	
		
			
				|  |  | -	) {
 | 
	
		
			
				|  |  | -		Saml2X509Credential credential = hasSigningCredential(signingCredential);
 | 
	
		
			
				|  |  | -		if (credential == null) {
 | 
	
		
			
				|  |  | -			throw new Saml2Exception("no signing credential configured");
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -		BasicCredential cred = getBasicCredential(credential);
 | 
	
		
			
				|  |  | -		cred.setEntityId(localSpEntityId);
 | 
	
		
			
				|  |  | -		cred.setUsageType(UsageType.SIGNING);
 | 
	
		
			
				|  |  | -		return cred;
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	private void signAuthnRequest(AuthnRequest authnRequest, Collection<Saml2X509Credential> signingCredentials) {
 | 
	
		
			
				|  |  | -		SignatureSigningParameters parameters = new SignatureSigningParameters();
 | 
	
		
			
				|  |  | -		Credential credential = getSigningCredential(signingCredentials, authnRequest.getIssuer().getValue());
 | 
	
		
			
				|  |  | -		parameters.setSigningCredential(credential);
 | 
	
		
			
				|  |  | -		parameters.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
 | 
	
		
			
				|  |  | -		parameters.setSignatureReferenceDigestMethod(SignatureConstants.ALGO_ID_DIGEST_SHA256);
 | 
	
		
			
				|  |  | -		parameters.setSignatureCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
 | 
	
		
			
				|  |  | -		try {
 | 
	
		
			
				|  |  | -			SignatureSupport.signObject(authnRequest, parameters);
 | 
	
		
			
				|  |  | -		} catch (MarshallingException | SignatureException | SecurityException e) {
 | 
	
		
			
				|  |  | -			throw new Saml2Exception(e);
 | 
	
		
			
				|  |  | -		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	private BasicX509Credential getBasicCredential(Saml2X509Credential credential) {
 | 
	
		
			
				|  |  | -		return CredentialSupport.getSimpleCredential(
 | 
	
		
			
				|  |  | -				credential.getCertificate(),
 | 
	
		
			
				|  |  | -				credential.getPrivateKey()
 | 
	
		
			
				|  |  | -		);
 | 
	
		
			
				|  |  | -	}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -}
 |