我正在尝试使用OpenSAML和ComponentSpace作为SP实现IDP发起的SSO。SP被配置为接受带有加密断言的SAMLResponse。
我能够加密断言,但SP要求我在EncryptedData中的KeyInfo中包含X509证书。
是否可以使用OpenSAML?如果是,你能告诉我如何做到这一点吗?
SP期望:
<saml:EncryptedAssertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
<EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<X509Data>
<X509Certificate>......</X509Certificate>
</X509Data>
</KeyInfo>
<CipherData>
<CipherValue>......</CipherValue>
</CipherData>
</EncryptedKey>
</KeyInfo>
<CipherData>
<CipherValue>......</CipherValue>
</CipherData>
</EncryptedData>
我能生成的:
<EncryptedAssertion>
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Type="http://www.w3.org/2001/04/xmlenc#Element">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
<dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#">
<xenc:EncryptedKey>
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
<xenc:CipherData>
<xenc:CipherValue>......</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedKey>
</dsig:KeyInfo>
<xenc:CipherData>
<xenc:CipherValue>......</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
</EncryptedAssertion>
查看http://ideone.com/p4Bhy9中的signSamlResponseObject2()方法。
public void signSamlResponseObject2() {
try {
String keyStoreFileName = "/WEB-INF/classes/saml-data/keystore.jks";
InputStream fis = getServletContext().getResource(keyStoreFileName)
.openStream();
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(fis, "abc123456*".toCharArray());
fis.close();
// Get Private Key Entry From keystore
KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry) ks
.getEntry("zohosso", new KeyStore.PasswordProtection(
"abc123456*".toCharArray()));
PrivateKey privKey = pkEntry.getPrivateKey();
PublicKey pubKey = ks.getCertificate("zohosso").getPublicKey();
X509Certificate cert = (X509Certificate) ks
.getCertificate("zohosso");
/*
* // Getting x509 Certificate from the keystore directly.
*
* KeyStore.TrustedCertificateEntry certEntry =
* (KeyStore.TrustedCertificateEntry) ks .getEntry("zohosso", new
* KeyStore.PasswordProtection( "abc123456*".toCharArray()));
*
* X509Certificate cert = (X509Certificate)
* certEntry.getTrustedCertificate();
*/
// Create a DOM XMLSignatureFactory that will be used to generate
// the
// enveloped signature.
// String providerName =
// System.getProperty("jsr105Provider",JSR_105_PROVIDER);
XMLSignatureFactory sigFactory = XMLSignatureFactory
.getInstance("DOM");
// Create a Reference to the enveloped document (we are
// signing the whole document, so a URI of "" signifies that) and
// also specify the SHA1 digest algorithm and the ENVELOPED
// Transform.
List envelopedTransform = Collections.singletonList(sigFactory
.newTransform(Transform.ENVELOPED,
(TransformParameterSpec) null));
Reference ref = sigFactory.newReference("",
sigFactory.newDigestMethod(DigestMethod.SHA1, null),
envelopedTransform, null, null);
SignatureMethod signatureMethod = sigFactory.newSignatureMethod(
SignatureMethod.DSA_SHA1, null);
CanonicalizationMethod canonicalizationMethod = sigFactory
.newCanonicalizationMethod(
CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
(C14NMethodParameterSpec) null);
// Create the SignedInfo
SignedInfo signedInfo = sigFactory.newSignedInfo(
canonicalizationMethod, signatureMethod,
Collections.singletonList(ref));
// Create a KeyValue containing the DSA PublicKey
KeyInfoFactory keyInfoFactory = sigFactory.getKeyInfoFactory();
KeyValue keyValuePair = keyInfoFactory.newKeyValue(pubKey);
// Creating the x509 certificate data from Certificate object ( cert )
List x509 = new ArrayList();
x509.add(cert);
X509Data x509Data = keyInfoFactory.newX509Data(x509);
// Create a KeyInfo and add the KeyValue to it
// keyInfoItems.add(Collections.singletonList(keyValuePair));
// Adding the certificate data and the key value pair to the keyInfo
List keyInfoItems = new ArrayList();
keyInfoItems.add(x509Data);
keyInfoItems.add(keyValuePair);
KeyInfo keyInfo = keyInfoFactory.newKeyInfo(keyInfoItems);
// Building the org.jdom.Document object from the samlResponse
// string
// ------------------------------------------------------------------
SAXBuilder builder = new SAXBuilder();
org.jdom.Document doc = builder.build(new ByteArrayInputStream(
strResponseXML.getBytes()));
// ------------------------------------------------------------------
// Convert the rootElement extracted from the doc to w3cElement
// ------------------------------------------------------------------
org.jdom.Element docRootElement = doc.getRootElement();
doc = docRootElement.getDocument();
XMLOutputter xmlOutputter = new XMLOutputter();
StringWriter elemStrWriter = new StringWriter();
xmlOutputter.output(doc, elemStrWriter);
byte[] xmlBytes = elemStrWriter.toString().getBytes();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
org.w3c.dom.Element w3cElement = dbf.newDocumentBuilder()
.parse(new ByteArrayInputStream(xmlBytes))
.getDocumentElement();
// --------------------------------------------------------------------
// Create a DOMSignContext and specify the DSA PrivateKey and
// location of the resulting XMLSignature's parent element
DOMSignContext dsc = new DOMSignContext(privKey, w3cElement);
// compute the correct location to insert the signature xml
// (location is important because the SAML xsd's enforce sequence on
// signed
// info.)
org.w3c.dom.Node xmlSigInsertionPoint = null;
String JSR_105_PROVIDER = "org.jcp.xml.dsig.internal.dom.XMLDSigRI";
String SAML_PROTOCOL_NS_URI_V20 = "urn:oasis:names:tc:SAML:2.0:protocol";
org.w3c.dom.NodeList nodeList = w3cElement.getElementsByTagNameNS(
SAML_PROTOCOL_NS_URI_V20, "Extensions");
if (nodeList.getLength() != 0) {
xmlSigInsertionPoint = nodeList.item(nodeList.getLength() - 1);
} else {
nodeList = w3cElement.getElementsByTagNameNS(
SAML_PROTOCOL_NS_URI_V20, "Status");
xmlSigInsertionPoint = nodeList.item(nodeList.getLength() - 1);
}
dsc.setNextSibling(xmlSigInsertionPoint);
// Marshal, generate (and sign) the enveloped signature
XMLSignature signature = sigFactory.newXMLSignature(signedInfo,
keyInfo);
signature.sign(dsc);
// Create the root dom element from the w3cElement using DOMBuilder
DOMBuilder domBuilder = new DOMBuilder();
org.jdom.Element signedElement = domBuilder.build(w3cElement);
doc.setRootElement((org.jdom.Element) signedElement.detach());
xmlOutputter = new XMLOutputter();
strFinalResponse = xmlOutputter.outputString(doc);
System.out.println("The signed SAML Response is : "
+ strFinalResponse);
} catch (Exception e) {
System.out
.println("Exception while attempting to sign the SAML Response.");
e.printStackTrace();
}
}