Author: anil.saldhana(a)jboss.com
Date: 2009-05-29 16:56:24 -0400 (Fri, 29 May 2009)
New Revision: 543
Added:
identity-federation/trunk/jboss-identity-fed-api/src/test/resources/logging.properties
identity-federation/trunk/jboss-identity-fed-api/src/test/resources/xml/dom/saml-response-2-assertions.xml
Modified:
identity-federation/trunk/jboss-identity-fed-api/src/main/java/org/jboss/identity/federation/api/saml/v2/sig/SAML2Signature.java
identity-federation/trunk/jboss-identity-fed-api/src/test/java/org/jboss/test/identity/federation/api/saml/v2/SignatureValidationUnitTestCase.java
identity-federation/trunk/jboss-identity-fed-api/src/test/java/org/jboss/test/identity/federation/api/util/DocumentUtilUnitTestCase.java
Log:
JBID-121: SAML2Signature API
Modified:
identity-federation/trunk/jboss-identity-fed-api/src/main/java/org/jboss/identity/federation/api/saml/v2/sig/SAML2Signature.java
===================================================================
---
identity-federation/trunk/jboss-identity-fed-api/src/main/java/org/jboss/identity/federation/api/saml/v2/sig/SAML2Signature.java 2009-05-29
20:56:09 UTC (rev 542)
+++
identity-federation/trunk/jboss-identity-fed-api/src/main/java/org/jboss/identity/federation/api/saml/v2/sig/SAML2Signature.java 2009-05-29
20:56:24 UTC (rev 543)
@@ -21,15 +21,30 @@
*/
package org.jboss.identity.federation.api.saml.v2.sig;
+import java.io.IOException;
+import java.security.GeneralSecurityException;
import java.security.KeyPair;
+import javax.xml.bind.JAXBException;
+import javax.xml.crypto.MarshalException;
+import javax.xml.crypto.dsig.DigestMethod;
+import javax.xml.crypto.dsig.SignatureMethod;
+import javax.xml.crypto.dsig.XMLSignatureException;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactoryConfigurationError;
+import javax.xml.xpath.XPathException;
+
import org.jboss.identity.federation.api.saml.v2.request.SAML2Request;
import org.jboss.identity.federation.api.saml.v2.response.SAML2Response;
import org.jboss.identity.federation.api.util.XMLSignatureUtil;
+import org.jboss.identity.federation.core.saml.v2.constants.JBossSAMLURIConstants;
+import org.jboss.identity.federation.core.saml.v2.util.DocumentUtil;
import org.jboss.identity.federation.saml.v2.protocol.RequestAbstractType;
import org.jboss.identity.federation.saml.v2.protocol.ResponseType;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
/**
* Class that deals with SAML2 Signature
@@ -38,27 +53,54 @@
*/
public class SAML2Signature
{
+ private String signatureMethod = SignatureMethod.RSA_SHA1;
+ private String digestMethod = DigestMethod.SHA1;
+
+ public String getSignatureMethod()
+ {
+ return signatureMethod;
+ }
+
+ public void setSignatureMethod(String signatureMethod)
+ {
+ this.signatureMethod = signatureMethod;
+ }
+
+ public String getDigestMethod()
+ {
+ return digestMethod;
+ }
+
+ public void setDigestMethod(String digestMethod)
+ {
+ this.digestMethod = digestMethod;
+ }
+
/**
* Sign an RequestType at the root
* @param request
* @param keypair Key Pair
* @param digestMethod (Example: DigestMethod.SHA1)
* @param signatureMethod (Example: SignatureMethod.DSA_SHA1)
- * @return
- * @throws Exception
+ * @return
+ * @throws ParserConfigurationException
+ * @throws JAXBException
+ * @throws IOException
+ * @throws SAXException
+ * @throws XMLSignatureException
+ * @throws MarshalException
+ * @throws GeneralSecurityException
*/
- public Document sign(RequestAbstractType request, KeyPair keypair,
- String digestMethod, String signatureMethod) throws Exception
+ public Document sign(RequestAbstractType request, KeyPair keypair) throws
SAXException, IOException, JAXBException, ParserConfigurationException,
GeneralSecurityException, MarshalException, XMLSignatureException
{
SAML2Request saml2Request = new SAML2Request();
Document doc = saml2Request.convert(request);
+ doc.normalize();
String referenceURI = "#" + request.getID();
-
- Node root = doc.getDocumentElement();
- return XMLSignatureUtil.sign(doc, root,
- keypair.getPrivate(),
- keypair.getPublic(),
+
+ return XMLSignatureUtil.sign(doc,
+ keypair,
digestMethod, signatureMethod,
referenceURI);
}
@@ -69,22 +111,61 @@
* @param keypair Key Pair
* @param digestMethod (Example: DigestMethod.SHA1)
* @param signatureMethod (Example: SignatureMethod.DSA_SHA1)
- * @return
- * @throws Exception
+ * @return
+ * @throws ParserConfigurationException
+ * @throws JAXBException
+ * @throws XMLSignatureException
+ * @throws MarshalException
+ * @throws GeneralSecurityException
*/
- public Document sign(ResponseType response,KeyPair keypair,
- String digestMethod, String signatureMethod) throws Exception
+ public Document sign(ResponseType response,KeyPair keypair) throws JAXBException,
ParserConfigurationException, GeneralSecurityException, MarshalException,
XMLSignatureException
{
SAML2Response saml2Request = new SAML2Response();
Document doc = saml2Request.convert(response);
+ doc.normalize();
String referenceURI = "#" + response.getID();
- Node root = doc.getDocumentElement();
- return XMLSignatureUtil.sign(doc, root,
- keypair.getPrivate(),
- keypair.getPublic(),
+ return XMLSignatureUtil.sign(doc,
+ keypair,
digestMethod, signatureMethod,
referenceURI);
}
-}
+
+ /**
+ * Sign an assertion whose id value is provided in the response type
+ * @param response
+ * @param idValueOfAssertion
+ * @param keypair
+ * @param referenceURI
+ * @return
+ * @throws ParserConfigurationException
+ * @throws JAXBException
+ * @throws TransformerException
+ * @throws TransformerFactoryConfigurationError
+ * @throws XPathException
+ * @throws XMLSignatureException
+ * @throws MarshalException
+ * @throws GeneralSecurityException
+ */
+ public Document sign(ResponseType response,
+ String idValueOfAssertion,
+ KeyPair keypair,
+ String referenceURI) throws JAXBException, ParserConfigurationException,
XPathException, TransformerFactoryConfigurationError, TransformerException,
GeneralSecurityException, MarshalException, XMLSignatureException
+ {
+ SAML2Response saml2Request = new SAML2Response();
+ Document doc = saml2Request.convert(response);
+
+
+ Node assertionNode = DocumentUtil.getNodeWithAttribute(doc,
+ JBossSAMLURIConstants.ASSERTION_NSURI.get(),
+ "Assertion",
+ "ID",
+ idValueOfAssertion);
+
+ return XMLSignatureUtil.sign(doc, assertionNode,
+ keypair,
+ digestMethod, signatureMethod,
+ referenceURI);
+ }
+}
\ No newline at end of file
Modified:
identity-federation/trunk/jboss-identity-fed-api/src/test/java/org/jboss/test/identity/federation/api/saml/v2/SignatureValidationUnitTestCase.java
===================================================================
---
identity-federation/trunk/jboss-identity-fed-api/src/test/java/org/jboss/test/identity/federation/api/saml/v2/SignatureValidationUnitTestCase.java 2009-05-29
20:56:09 UTC (rev 542)
+++
identity-federation/trunk/jboss-identity-fed-api/src/test/java/org/jboss/test/identity/federation/api/saml/v2/SignatureValidationUnitTestCase.java 2009-05-29
20:56:24 UTC (rev 543)
@@ -21,12 +21,13 @@
*/
package org.jboss.test.identity.federation.api.saml.v2;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import java.io.InputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
-import javax.xml.crypto.dsig.DigestMethod;
import javax.xml.crypto.dsig.SignatureMethod;
import org.jboss.identity.federation.api.saml.v2.common.IDGenerator;
@@ -34,19 +35,18 @@
import org.jboss.identity.federation.api.saml.v2.response.SAML2Response;
import org.jboss.identity.federation.api.saml.v2.sig.SAML2Signature;
import org.jboss.identity.federation.api.util.XMLSignatureUtil;
-import org.jboss.identity.federation.core.saml.v2.constants.JBossSAMLConstants;
import org.jboss.identity.federation.core.saml.v2.constants.JBossSAMLURIConstants;
-import org.jboss.identity.federation.core.saml.v2.factories.SAMLAssertionFactory;
import org.jboss.identity.federation.core.saml.v2.holders.IssuerInfoHolder;
+import org.jboss.identity.federation.core.saml.v2.util.DocumentUtil;
import org.jboss.identity.federation.core.saml.v2.util.SignatureUtil;
import org.jboss.identity.federation.core.saml.v2.util.XMLTimeUtil;
import org.jboss.identity.federation.saml.v2.assertion.AssertionType;
import org.jboss.identity.federation.saml.v2.assertion.AuthnStatementType;
-import org.jboss.identity.federation.saml.v2.assertion.ObjectFactory;
import org.jboss.identity.federation.saml.v2.protocol.AuthnRequestType;
import org.jboss.identity.federation.saml.v2.protocol.ResponseType;
import org.junit.Test;
import org.w3c.dom.Document;
+import org.w3c.dom.Node;
/**
* Signatures related unit test cases
@@ -76,8 +76,11 @@
KeyPair kp = kpg.genKeyPair();
SAML2Signature ss = new SAML2Signature();
- Document signedDoc = ss.sign(authnRequest, kp, DigestMethod.SHA1,
SignatureMethod.DSA_SHA1);
+ ss.setSignatureMethod(SignatureMethod.DSA_SHA1);
+ Document signedDoc = ss.sign(authnRequest, kp);
+ System.out.println(DocumentUtil.getDocumentAsString(signedDoc));
+
//Validate the signature
boolean isValid = XMLSignatureUtil.validate(signedDoc, kp.getPublic());
assertTrue(isValid);
@@ -88,7 +91,7 @@
* @throws Exception
*/
@Test
- public void testSigningAssertionWithSignature() throws Exception
+ public void testSigningResponse() throws Exception
{
IssuerInfoHolder issuerInfo = new IssuerInfoHolder("testIssuer");
String id = IDGenerator.create("ID_");
@@ -101,14 +104,11 @@
AuthnStatementType authnStatement =
response.createAuthnStatement(authnContextDeclRef,
XMLTimeUtil.getIssueInstant());
- ObjectFactory objectFactory = SAMLAssertionFactory.getObjectFactory();
-
- AssertionType assertion = objectFactory.createAssertionType();
+ //Create an assertion
+ AssertionType assertion = response.createAssertion(id, issuerInfo.getIssuer());
assertion.getStatementOrAuthnStatementOrAuthzDecisionStatement().add(authnStatement);
- assertion.setID(id);
- assertion.setVersion(JBossSAMLConstants.VERSION_2_0.get());
- assertion.setIssuer(issuerInfo.getIssuer());
+
KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
KeyPair kp = kpg.genKeyPair();
@@ -116,13 +116,63 @@
ResponseType responseType = response.createResponseType(id, issuerInfo,
assertion);
SAML2Signature ss = new SAML2Signature();
- Document signedDoc = ss.sign(responseType, kp, DigestMethod.SHA1,
SignatureMethod.DSA_SHA1);
+ ss.setSignatureMethod(SignatureMethod.DSA_SHA1);
+ Document signedDoc = ss.sign(responseType, kp);
//Validate the signature
boolean isValid = XMLSignatureUtil.validate(signedDoc, kp.getPublic());
assertTrue(isValid);
}
+ @Test
+ public void testSigningAnAssertionWithinResponse() throws Exception
+ {
+ SAML2Response response = new SAML2Response();
+ String fileName = "xml/dom/saml-response-2-assertions.xml";
+ ClassLoader tcl = Thread.currentThread().getContextClassLoader();
+ InputStream is = tcl.getResourceAsStream(fileName);
+ if(is == null)
+ throw new RuntimeException("InputStream is null");
+
+ ResponseType responseType = response.getResponseType(is);
+
+ Document doc = response.convert(responseType);
+
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
+ KeyPair kp = kpg.genKeyPair();
+
+ //String id = "ID_0be488d8-7089-4892-8aeb-83594c800706";
+ String id = "ID_976d8310-658a-450d-be39-f33c73c8afa6";
+
+ //Get the second assertion
+ Node assert2 = DocumentUtil.getNodeWithAttribute(doc,
+ "urn:oasis:names:tc:SAML:2.0:assertion",
+ "Assertion",
+ "ID", id);
+
+ String referenceURI = "#" + id;
+
+ assertNotNull("Found assertion?", assert2);
+ SAML2Signature ss = new SAML2Signature();
+ Document signedDoc = ss.sign(responseType, id, kp,referenceURI);
+
+ System.out.println(DocumentUtil.getDocumentAsString(signedDoc));
+
+ Node signedNode = DocumentUtil.getNodeWithAttribute(signedDoc,
+ "urn:oasis:names:tc:SAML:2.0:assertion",
+ "Assertion",
+ "ID", id);
+
+ //Let us just validate the signature of the assertion
+ Document validatingDoc = DocumentUtil.createDocument();
+ Node importedSignedNode = validatingDoc.importNode(signedNode, true);
+ validatingDoc.appendChild(importedSignedNode);
+
+ //Validate the signature
+ boolean isValid = XMLSignatureUtil.validate(validatingDoc, kp.getPublic());
+ assertTrue("Signature is valid:", isValid);
+ }
+
/**
* Test signing a string
* @throws Exception
Modified:
identity-federation/trunk/jboss-identity-fed-api/src/test/java/org/jboss/test/identity/federation/api/util/DocumentUtilUnitTestCase.java
===================================================================
---
identity-federation/trunk/jboss-identity-fed-api/src/test/java/org/jboss/test/identity/federation/api/util/DocumentUtilUnitTestCase.java 2009-05-29
20:56:09 UTC (rev 542)
+++
identity-federation/trunk/jboss-identity-fed-api/src/test/java/org/jboss/test/identity/federation/api/util/DocumentUtilUnitTestCase.java 2009-05-29
20:56:24 UTC (rev 543)
@@ -23,14 +23,13 @@
import java.io.InputStream;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-
import junit.framework.TestCase;
-import org.apache.xml.security.utils.EncryptionConstants;
+import org.jboss.identity.federation.core.saml.v2.util.DocumentUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
/**
* Unit Test the DocumentUtil
@@ -39,31 +38,69 @@
*/
public class DocumentUtilUnitTestCase extends TestCase
{
+ String EncryptionSpecNS = "http://www.w3.org/2001/04/xmlenc#";
+ String TAG_ENCRYPTEDDATA = "EncryptedData";
+ String TAG_ENCRYPTEDKEY = "EncryptedKey";
+
public void testReadSAMLEncryptedAssertion() throws Exception
{
- Document encDoc = getDocument();
+ Document encDoc = getDocument("xml/dom/enc-sample.xml");
Element encryptedDataElement =
(Element) encDoc.getElementsByTagNameNS(
- EncryptionConstants.EncryptionSpecNS,
- EncryptionConstants._TAG_ENCRYPTEDDATA).item(0);
+ EncryptionSpecNS,
+ TAG_ENCRYPTEDDATA).item(0);
Element encryptedKeyElement =
(Element) encryptedDataElement.getElementsByTagNameNS(
- EncryptionConstants.EncryptionSpecNS,
- EncryptionConstants._TAG_ENCRYPTEDKEY).item(0);
+ EncryptionSpecNS,
+ TAG_ENCRYPTEDKEY).item(0);
assertNotNull(encryptedDataElement);
assertNotNull(encryptedKeyElement);
- }
+ }
- private Document getDocument() throws Exception
+ /**
+ * The SAML ResponseType has 2 assertions. We get the second one
+ * @throws Exception
+ */
+ public void testReadingAnAssertionFromSAMLResponse() throws Exception
{
- String fileName = "xml/dom/enc-sample.xml";
+ String id = "ID_976d8310-658a-450d-be39-f33c73c8afa6";
+ Document responseDoc =
getDocument("xml/dom/saml-response-2-assertions.xml");
+ DocumentUtil.logNodes(responseDoc);
+ Node n = DocumentUtil.getNodeWithAttribute(responseDoc,
"urn:oasis:names:tc:SAML:2.0:assertion",
+ "Assertion",
+ "ID", id );
+ assertNotNull(n);
+
+ assertTrue("Assertion".equals(n.getNodeName()));
+ NamedNodeMap nnm = n.getAttributes();
+ assertEquals(3, nnm.getLength() );
+ Node att = nnm.getNamedItem("ID");
+ assertEquals(id, att.getNodeValue());
+
+ assertTrue(n.getParentNode() != null);
+ assertTrue(n.getPreviousSibling() != null);
+ assertTrue(n.getNextSibling() != null);
+
+ //Let us get the first assertion
+ Node firstAssertion = DocumentUtil.getNodeWithAttribute(responseDoc,
+ "urn:oasis:names:tc:SAML:2.0:assertion",
+ "Assertion",
+ "ID", "ID_0be488d8-7089-4892-8aeb-83594c800706" );
+ Node prev = firstAssertion.getPreviousSibling();
+ assertTrue(firstAssertion.getParentNode() != null);
+ assertTrue( prev!= null);
+ Node next = firstAssertion.getNextSibling();
+ assertTrue( next != null);
+
+ //We have to check that the extracted node actually exists in the document
+ assertTrue("Extracted Node is in
doc",DocumentUtil.containsNode(responseDoc, firstAssertion));
+ }
+
+ private Document getDocument(String fileName) throws Exception
+ {
InputStream is =
Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
if(is == null)
throw new RuntimeException("InputStream is null");
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(true);
- DocumentBuilder builder = factory.newDocumentBuilder();
- return builder.parse(is);
- }
-
-}
+ return DocumentUtil.getDocument(is);
+ }
+}
\ No newline at end of file
Added:
identity-federation/trunk/jboss-identity-fed-api/src/test/resources/logging.properties
===================================================================
---
identity-federation/trunk/jboss-identity-fed-api/src/test/resources/logging.properties
(rev 0)
+++
identity-federation/trunk/jboss-identity-fed-api/src/test/resources/logging.properties 2009-05-29
20:56:24 UTC (rev 543)
@@ -0,0 +1,21 @@
+# Specify the handlers to create in the root logger
+# (all loggers are children of the root logger)
+# The following creates two handlers
+handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler
+
+# Set the default logging level for the root logger
+.level = ALL
+
+# Set the default logging level for new ConsoleHandler instances
+java.util.logging.ConsoleHandler.level = ALL
+
+# Set the default logging level for new FileHandler instances
+java.util.logging.FileHandler.level = ALL
+
+# Set the default formatter for new ConsoleHandler instances
+java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
+java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
+
+# Set the default logging level for the logger named org.jboss
+org.jcp.xml.dsig.internal.level = FINER
+com.sun.org.apache.xml.internal.security.level = FINER
Added:
identity-federation/trunk/jboss-identity-fed-api/src/test/resources/xml/dom/saml-response-2-assertions.xml
===================================================================
---
identity-federation/trunk/jboss-identity-fed-api/src/test/resources/xml/dom/saml-response-2-assertions.xml
(rev 0)
+++
identity-federation/trunk/jboss-identity-fed-api/src/test/resources/xml/dom/saml-response-2-assertions.xml 2009-05-29
20:56:24 UTC (rev 543)
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"
standalone="yes"?>
+<ns3:Response xmlns="urn:oasis:names:tc:SAML:2.0:assertion"
+
xmlns:ns2="http://www.w3.org/2000/09/xmldsig#"
xmlns:ns3="urn:oasis:names:tc:SAML:2.0:protocol"
+
xmlns:ns4="http://www.w3.org/2001/04/xmlenc#"
IssueInstant="2009-05-26T14:06:26.362-05:00"
+ Version="2.0" ID="ID_1164e0fc-576d-4797-b11c-3d049520f566">
+ <Issuer>testIssuer</Issuer>
+ <ns3:Status>
+ <ns3:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
+ </ns3:Status>
+ <Assertion IssueInstant="2009-05-26T14:06:26.362-05:00"
+ ID="ID_0be488d8-7089-4892-8aeb-83594c800706" Version="2.0">
+ <Issuer>testIssuer</Issuer>
+ <AuthnStatement AuthnInstant="2009-05-26T14:06:26.359-05:00">
+ <AuthnContext>
+ <AuthnContextDeclRef>
+ urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
+ </AuthnContextDeclRef>
+ </AuthnContext>
+ </AuthnStatement>
+ </Assertion>
+ <Assertion IssueInstant="2009-05-26T14:06:26.363-05:00"
+ ID="ID_976d8310-658a-450d-be39-f33c73c8afa6" Version="2.0">
+ <Issuer>testIssuer</Issuer>
+ <AuthnStatement AuthnInstant="2009-05-26T14:06:26.359-05:00">
+ <AuthnContext>
+ <AuthnContextDeclRef>
+ urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
+ </AuthnContextDeclRef>
+ </AuthnContext>
+ </AuthnStatement>
+ </Assertion>
+</ns3:Response>
\ No newline at end of file