001/* 002 * oauth2-oidc-sdk 003 * 004 * Copyright 2012-2016, Connect2id Ltd and contributors. 005 * 006 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use 007 * this file except in compliance with the License. You may obtain a copy of the 008 * License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software distributed 013 * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 014 * CONDITIONS OF ANY KIND, either express or implied. See the License for the 015 * specific language governing permissions and limitations under the License. 016 */ 017 018package com.nimbusds.oauth2.sdk.assertions.saml2; 019 020 021import com.nimbusds.oauth2.sdk.SerializeException; 022import net.jcip.annotations.ThreadSafe; 023import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport; 024import org.opensaml.core.xml.io.MarshallingException; 025import org.opensaml.saml.saml2.core.Assertion; 026import org.opensaml.security.credential.BasicCredential; 027import org.opensaml.security.credential.Credential; 028import org.opensaml.security.credential.UsageType; 029import org.opensaml.xmlsec.signature.Signature; 030import org.opensaml.xmlsec.signature.support.SignatureConstants; 031import org.opensaml.xmlsec.signature.support.SignatureException; 032import org.opensaml.xmlsec.signature.support.Signer; 033import org.w3c.dom.Element; 034 035import java.security.interfaces.RSAPrivateKey; 036import java.security.interfaces.RSAPublicKey; 037 038import static com.nimbusds.oauth2.sdk.assertions.saml2.SAML2Utils.buildSAMLObject; 039import static net.shibboleth.utilities.java.support.xml.SerializeSupport.nodeToString; 040 041 042/** 043 * Static SAML 2.0 bearer assertion factory. 044 * 045 * <p>Related specifications: 046 * 047 * <ul> 048 * <li>Assertion Framework for OAuth 2.0 Client Authentication and 049 * Authorization Grants (RFC 7521) 050 * <li>Security Assertion Markup Language (SAML) 2.0 Profile for OAuth 2.0 051 * Client Authentication and Authorization Grants (RFC 7522) 052 * </ul> 053 */ 054@ThreadSafe 055public class SAML2AssertionFactory { 056 057 058 /** 059 * Creates a new SAML 2.0 assertion. 060 * 061 * @param details The SAML 2.0 bearer assertion details. Must not 062 * be {@code null}. 063 * @param xmlDsigAlg The XML digital signature algorithm. Must not be 064 * {@code null}. 065 * @param credential The appropriate credentials to facilitate signing 066 * of the assertion. 067 * 068 * @return The SAML 2.0 bearer assertion. 069 * 070 * @throws SerializeException If serialisation or signing failed. 071 */ 072 public static Assertion create(final SAML2AssertionDetails details, 073 final String xmlDsigAlg, 074 final Credential credential) { 075 076 Assertion a = details.toSAML2Assertion(); 077 078 // Create signature element 079 Signature signature = buildSAMLObject(Signature.class); 080 signature.setSigningCredential(credential); 081 signature.setSignatureAlgorithm(xmlDsigAlg); 082 signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); 083 084 a.setSignature(signature); 085 086 try { 087 // Marshall and sign 088 XMLObjectProviderRegistrySupport 089 .getMarshallerFactory() 090 .getMarshaller(a) 091 .marshall(a); 092 Signer.signObject(signature); 093 } catch (MarshallingException | SignatureException e) { 094 throw new SerializeException(e.getMessage(), e); 095 } 096 097 return a; 098 } 099 100 101 /** 102 * Creates a new SAML 2.0 assertion as an XML element. 103 * 104 * @param details The SAML 2.0 bearer assertion details. Must not 105 * be {@code null}. 106 * @param xmlDsigAlg The XML digital signature algorithm. Must not be 107 * {@code null}. 108 * @param credential The appropriate credentials to facilitate signing 109 * of the assertion. 110 * 111 * @return The SAML 2.0 bearer assertion as an XML element. 112 * 113 * @throws SerializeException If serialisation or signing failed. 114 */ 115 public static Element createAsElement(final SAML2AssertionDetails details, 116 final String xmlDsigAlg, 117 final Credential credential) { 118 119 Assertion a = create(details, xmlDsigAlg, credential); 120 try { 121 return XMLObjectProviderRegistrySupport 122 .getMarshallerFactory() 123 .getMarshaller(a) 124 .marshall(a); 125 } catch (MarshallingException e) { 126 throw new SerializeException(e.getMessage(), e); 127 } 128 } 129 130 131 /** 132 * Creates a new SAML 2.0 assertion as an XML string. 133 * 134 * @param details The SAML 2.0 bearer assertion details. Must not 135 * be {@code null}. 136 * @param xmlDsigAlg The XML digital signature algorithm. Must not be 137 * {@code null}. 138 * @param credential The appropriate credentials to facilitate signing 139 * of the assertion. 140 * 141 * @return The SAML 2.0 bearer assertion as an XML string. Note that 142 * an XML declaration is not present in the output string. 143 * 144 * @throws SerializeException If serialisation or signing failed. 145 */ 146 public static String createAsString(final SAML2AssertionDetails details, 147 final String xmlDsigAlg, 148 final Credential credential) { 149 150 Element a = createAsElement(details, xmlDsigAlg, credential); 151 String xml = nodeToString(a); 152 153 // Strip XML doc declaration 154 final String header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; 155 if (xml.startsWith(header)) { 156 xml = xml.substring(header.length()); 157 } 158 159 return xml; 160 } 161 162 163 /** 164 * Creates a new SAML 2.0 assertion as an XML string, signed with the 165 * RSA-SHA256 XML digital signature algorithm (mandatory to implement). 166 * 167 * @param details The SAML 2.0 bearer assertion details. Must not 168 * be {@code null}. 169 * @param rsaPublicKey The public RSA key. Must not be {@code null}. 170 * @param rsaPrivateKey The private RSA key to sign the assertion. Must 171 * not be {@code null}. 172 * 173 * @return The SAML 2.0 bearer assertion as an XML string. Note that 174 * an XML declaration is not present in the output string. 175 * 176 * @throws SerializeException If serialisation or signing failed. 177 */ 178 public static String createAsString(final SAML2AssertionDetails details, 179 final RSAPublicKey rsaPublicKey, 180 final RSAPrivateKey rsaPrivateKey) { 181 182 BasicCredential credential = new BasicCredential(rsaPublicKey, rsaPrivateKey); 183 credential.setUsageType(UsageType.SIGNING); 184 return createAsString(details, SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256, credential); 185 } 186 187 188 /** 189 * Prevents public instantiation. 190 */ 191 private SAML2AssertionFactory() {} 192}