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 java.security.interfaces.RSAPrivateKey; 022 023import com.nimbusds.oauth2.sdk.SerializeException; 024import net.jcip.annotations.ThreadSafe; 025import org.opensaml.Configuration; 026import org.opensaml.saml2.core.Assertion; 027import org.opensaml.saml2.core.impl.AssertionMarshaller; 028import org.opensaml.xml.io.MarshallerFactory; 029import org.opensaml.xml.io.MarshallingException; 030import org.opensaml.xml.security.credential.BasicCredential; 031import org.opensaml.xml.security.credential.Credential; 032import org.opensaml.xml.security.credential.UsageType; 033import org.opensaml.xml.signature.Signature; 034import org.opensaml.xml.signature.SignatureConstants; 035import org.opensaml.xml.signature.SignatureException; 036import org.opensaml.xml.signature.Signer; 037import org.opensaml.xml.util.XMLHelper; 038import org.w3c.dom.Element; 039 040 041/** 042 * Static SAML 2.0 bearer assertion factory. 043 * 044 * <p>Related specifications: 045 * 046 * <ul> 047 * <li>Assertion Framework for OAuth 2.0 Client Authentication and 048 * Authorization Grants (RFC 7521). 049 * <li>Security Assertion Markup Language (SAML) 2.0 Profile for OAuth 2.0 050 * Client Authentication and Authorization Grants (RFC 7522). 051 * </ul> 052 */ 053@ThreadSafe 054public class SAML2AssertionFactory { 055 056 057 /** 058 * Creates a new SAML 2.0 assertion. 059 * 060 * @param details The SAML 2.0 bearer assertion details. Must not 061 * be {@code null}. 062 * @param xmlDsigAlg The XML digital signature algorithm. Must not be 063 * {@code null}. 064 * @param credential The appropriate credentials to facilitate signing 065 * of the assertion. 066 * 067 * @return The SAML 2.0 bearer assertion. 068 * 069 * @throws SerializeException If serialisation or signing failed. 070 */ 071 public static Assertion create(final SAML2AssertionDetails details, 072 final String xmlDsigAlg, 073 final Credential credential) { 074 075 Assertion a = details.toSAML2Assertion(); 076 077 // Create signature element 078 Signature signature = (Signature) Configuration.getBuilderFactory() 079 .getBuilder(Signature.DEFAULT_ELEMENT_NAME) 080 .buildObject(Signature.DEFAULT_ELEMENT_NAME); 081 082 signature.setSigningCredential(credential); 083 signature.setSignatureAlgorithm(xmlDsigAlg); 084 signature.setCanonicalizationAlgorithm(SignatureConstants.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); 085 086 a.setSignature(signature); 087 088 MarshallerFactory marshallerFactory = Configuration.getMarshallerFactory(); 089 090 try { 091 // Perform actual signing 092 marshallerFactory.getMarshaller(a).marshall(a); 093 Signer.signObject(signature); 094 } catch (MarshallingException | SignatureException e) { 095 throw new SerializeException(e.getMessage(), e); 096 } 097 098 return a; 099 } 100 101 102 /** 103 * Creates a new SAML 2.0 assertion as an XML element. 104 * 105 * @param details The SAML 2.0 bearer assertion details. Must not 106 * be {@code null}. 107 * @param xmlDsigAlg The XML digital signature algorithm. Must not be 108 * {@code null}. 109 * @param credential The appropriate credentials to facilitate signing 110 * of the assertion. 111 * 112 * @return The SAML 2.0 bearer assertion as an XML element. 113 * 114 * @throws SerializeException If serialisation or signing failed. 115 */ 116 public static Element createAsElement(final SAML2AssertionDetails details, 117 final String xmlDsigAlg, 118 final Credential credential) { 119 120 Assertion a = create(details, xmlDsigAlg, credential); 121 AssertionMarshaller assertionMarshaller = new AssertionMarshaller(); 122 try { 123 return assertionMarshaller.marshall(a); 124 } catch (MarshallingException e) { 125 throw new SerializeException(e.getMessage(), e); 126 } 127 } 128 129 130 /** 131 * Creates a new SAML 2.0 assertion as an XML string. 132 * 133 * @param details The SAML 2.0 bearer assertion details. Must not 134 * be {@code null}. 135 * @param xmlDsigAlg The XML digital signature algorithm. Must not be 136 * {@code null}. 137 * @param credential The appropriate credentials to facilitate signing 138 * of the assertion. 139 * 140 * @return The SAML 2.0 bearer assertion as an XML string. Note that 141 * an XML declaration is not present in the output string. 142 * 143 * @throws SerializeException If serialisation or signing failed. 144 */ 145 public static String createAsString(final SAML2AssertionDetails details, 146 final String xmlDsigAlg, 147 final Credential credential) { 148 149 Element a = createAsElement(details, xmlDsigAlg, credential); 150 String xml = XMLHelper.nodeToString(a); 151 // Strip XML doc declaration 152 final String header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; 153 return xml.substring(header.length()); 154 } 155 156 157 /** 158 * Creates a new SAML 2.0 assertion as an XML string, signed with the 159 * RSA-SHA256 XML digital signature algorithm (mandatory to implement). 160 * 161 * @param details The SAML 2.0 bearer assertion details. Must not 162 * be {@code null}. 163 * @param rsaPrivateKey The private RSA key to sign the assertion. Must 164 * not be {@code null}. 165 * 166 * @return The SAML 2.0 bearer assertion as an XML string. Note that 167 * an XML declaration is not present in the output string. 168 * 169 * @throws SerializeException If serialisation or signing failed. 170 */ 171 public static String createAsString(final SAML2AssertionDetails details, 172 final RSAPrivateKey rsaPrivateKey) { 173 174 BasicCredential credential = new BasicCredential(); 175 credential.setPrivateKey(rsaPrivateKey); 176 credential.setUsageType(UsageType.SIGNING); 177 return createAsString(details, SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256, credential); 178 } 179 180 181 /** 182 * Prevents public instantiation. 183 */ 184 private SAML2AssertionFactory() {} 185}