From: Scott Cantor Date: Sun, 14 May 2006 03:35:30 +0000 (+0000) Subject: SAML Signature subclasses and test. X-Git-Tag: 2.0-alpha1~255 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fcpp-opensaml.git;a=commitdiff_plain;h=2c235cac370df082dd2f1462a06fcf6148b6b319 SAML Signature subclasses and test. --- diff --git a/.cdtproject b/.cdtproject index 419cc0d..c59f390 100644 --- a/.cdtproject +++ b/.cdtproject @@ -58,7 +58,7 @@ - + @@ -66,8 +66,10 @@ - + + + diff --git a/saml/Makefile.am b/saml/Makefile.am index 139d5fb..460c788 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -14,6 +14,10 @@ libsamlinclude_HEADERS = \ version.h \ SAMLConfig.h +siginclude_HEADERS = \ + signature/SigningContext.h \ + signature/VerifyingContext.h + utilinclude_HEADERS = \ util/SAMLConstants.h @@ -27,6 +31,8 @@ libsaml_la_SOURCES = \ SAMLConfig.cpp \ saml1/core/impl/AssertionsImpl.cpp \ saml1/core/impl/AssertionsSchemaValidators.cpp \ + signature/SigningContext.cpp \ + signature/VerifyingContext.cpp \ util/SAMLConstants.cpp # this is different from the project version diff --git a/saml/saml.vcproj b/saml/saml.vcproj index d9fe07c..a6e42e7 100644 --- a/saml/saml.vcproj +++ b/saml/saml.vcproj @@ -213,6 +213,18 @@ + + + + + + + + + + + + getSubjectStatements().empty() && ptr->getStatements().empty()) throw ValidationException("Assertion must have at least one statement."); + if (ptr->getMinorVersion()==0 && ptr->getConditions() && !ptr->getConditions()->getDoNotCacheConditions().empty()) + throw ValidationException("SAML 1.0 assertions cannot contain DoNotCacheCondition elements."); END_XMLOBJECTVALIDATOR; class SAML_DLLLOCAL checkWildcardNS { diff --git a/saml/signature/SigningContext.cpp b/saml/signature/SigningContext.cpp new file mode 100644 index 0000000..445147e --- /dev/null +++ b/saml/signature/SigningContext.cpp @@ -0,0 +1,61 @@ +/* + * Copyright 2001-2006 Internet2 + * + * 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 + * + * http://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. + */ + +/** + * SigningContext.cpp + * + * SAML-specific signature construction + */ + +#include "internal.h" +#include "signature/SigningContext.h" + +#include +#include +#include + +using namespace opensaml; +using namespace std; + +class _addprefix : public binary_function { +public: + void operator()(DSIGTransformC14n* t, const string& s) const { + if (s.empty()) + t->addInclusiveNamespace("#default"); + else + t->addInclusiveNamespace(s.c_str()); + } +}; + +void SigningContext::createSignature(DSIGSignature* sig) const +{ + DSIGReference* ref=NULL; + XMLCh* buf=new XMLCh[XMLString::stringLen(m_id) + 2]; + buf[0]=chPound; + buf[1]=chNull; + XMLString::catString(buf,m_id); + try { + ref=sig->createReference(buf); + delete[] buf; + } + catch(...) { + delete[] buf; + throw; + } + ref->appendEnvelopedSignatureTransform(); + DSIGTransformC14n* c14n=ref->appendCanonicalizationTransform(CANON_C14NE_NOC); + for_each(m_prefixes.begin(), m_prefixes.end(), bind1st(_addprefix(),c14n)); +} diff --git a/saml/signature/SigningContext.h b/saml/signature/SigningContext.h new file mode 100644 index 0000000..bdd1cbe --- /dev/null +++ b/saml/signature/SigningContext.h @@ -0,0 +1,137 @@ +/* + * Copyright 2001-2006 Internet2 + * + * 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 + * + * http://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. + */ + +/** + * @file SigningContext.h + * + * SAML-specific signature construction + */ + +#ifndef __saml_signctx_h__ +#define __saml_signctx_h__ + +#include +#include + +namespace opensaml { + + /** + * Singleton object that manages library startup/shutdown.configuration. + */ + class SAML_API SigningContext : public virtual xmlsignature::SigningContext + { + public: + /** + * Constructor. + * + * @param id identifier of object being signed + * @param key signing key to use, will be freed by context + * @param certs a certificate chain to embed, or NULL + */ + SigningContext(const XMLCh* id, XSECCryptoKey* key, const std::vector* certs=NULL) + : m_id(id), m_key(key), m_certs(certs), m_keyInfo(NULL) { + } + + /** + * Constructor. + * + * @param id identifier of object being signed + * @param key signing key to use, will be freed by context + * @param keyInfo a complete KeyInfo object to attach, will be freed by context + */ + SigningContext(const XMLCh* id, XSECCryptoKey* key, xmlsignature::KeyInfo* keyInfo) + : m_id(id), m_key(key), m_certs(NULL), m_keyInfo(keyInfo) { + } + + virtual ~SigningContext() { + delete m_key; + delete m_keyInfo; + } + + /** + * Given a "blank" native signature, asks the context to define the + * appropriate signature transforms, references, etc. + * This method MAY attach ds:KeyInfo information, or a set of X.509 + * certificates can be returned from the SigningContext::getX509Certificates() + * method instead. + * + * @param sig native signature interface + */ + virtual void createSignature(DSIGSignature* sig) const; + + /** + * Gets a reference to a collection of certificates to append to + * the ds:KeyInfo element in a ds:X509Data chain. + * The certificate corresponding to the signing key SHOULD be + * first, followed by any additional intermediates to append. + * + * @return an immutable collection of certificates to embed + */ + virtual const std::vector* getX509Certificates() const { + return m_certs; + } + + /** + * Gets a KeyInfo structure to embed. + * Ownership of the object MUST be transferred to the caller. + * This method will only be called if no certificates are returned from + * the getX509Certificates() method. + * + * @return pointer to a KeyInfo structure, will be freed by caller + */ + virtual xmlsignature::KeyInfo* getKeyInfo() const { + xmlsignature::KeyInfo* ret=m_keyInfo; + m_keyInfo=NULL; + return ret; + } + + /** + * Gets the signing key to use. + * Must be compatible with the intended signature algorithm. Ownership of the key + * MUST be transferred to the caller. + * + * @return pointer to a signing key, will be freed by caller + */ + virtual XSECCryptoKey* getSigningKey() const { + XSECCryptoKey* ret=m_key; + m_key=NULL; + return ret; + } + + void addInclusivePrefix(const char* prefix) { + m_prefixes.push_back(prefix); + } + + protected: + /** Identifier of object to sign. */ + const XMLCh* m_id; + + /** Signing key. */ + mutable XSECCryptoKey* m_key; + + /** Optional pointer to certificate chain to embed. */ + const std::vector* m_certs; + + /** Optional pointer to KeyInfo to embed. */ + mutable xmlsignature::KeyInfo* m_keyInfo; + + /** Inclusive prefixes. */ + std::vector m_prefixes; + }; + +}; + +#endif /* __saml_signctx_h__ */ diff --git a/saml/signature/VerifyingContext.cpp b/saml/signature/VerifyingContext.cpp new file mode 100644 index 0000000..def1f98 --- /dev/null +++ b/saml/signature/VerifyingContext.cpp @@ -0,0 +1,62 @@ +/* + * Copyright 2001-2006 Internet2 + * + * 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 + * + * http://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. + */ + +/** + * VerifyingContext.cpp + * + * SAML-specific signature verification + */ + +#include "internal.h" +#include "signature/VerifyingContext.h" + +#include + +#include +#include +#include +#include + +using namespace opensaml; +using namespace std; + +void VerifyingContext::verifySignature(DSIGSignature* sig) const +{ + bool valid=false; + + DSIGReferenceList* refs=sig->getReferenceList(); + if (refs && refs->getSize()==1) { + DSIGReference* ref=refs->item(0); + if (ref) { + const XMLCh* URI=ref->getURI(); + if (URI==NULL || *URI==0 || (*URI==chPound && !XMLString::compareString(URI+1,m_id))) { + DSIGTransformList* tlist=ref->getTransforms(); + for (unsigned int i=0; tlist && igetSize(); i++) { + if (tlist->item(i)->getTransformType()==TRANSFORM_ENVELOPED_SIGNATURE) + valid=true; + else if (tlist->item(i)->getTransformType()!=TRANSFORM_EXC_C14N && + tlist->item(i)->getTransformType()!=TRANSFORM_C14N) { + valid=false; + break; + } + } + } + } + } + + if (!valid) + throw xmlsignature::SignatureException("Invalid signature profile for SAML object."); +} diff --git a/saml/signature/VerifyingContext.h b/saml/signature/VerifyingContext.h new file mode 100644 index 0000000..77d730d --- /dev/null +++ b/saml/signature/VerifyingContext.h @@ -0,0 +1,63 @@ +/* + * Copyright 2001-2006 Internet2 + * + * 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 + * + * http://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. + */ + +/** + * @file VerifyingContext.h + * + * SAML-specific signature verification + */ + +#ifndef __saml_verctx_h__ +#define __saml_verctx_h__ + +#include +#include + +namespace opensaml { + + /** + * Singleton object that manages library startup/shutdown.configuration. + */ + class SAML_API VerifyingContext : public virtual xmlsignature::VerifyingContext + { + public: + /** + * Constructor. + * + * @param id identifier of object being verified + */ + VerifyingContext(const XMLCh* id) : m_id(id) {} + + virtual ~VerifyingContext() {} + + /** + * Given a native signature, asks the context to verify the signature + * in accordance with the relying party's requirements. + * + * @param sig native signature object + * + * @throws SignatureException raised if signature is invalid + */ + virtual void verifySignature(DSIGSignature* sig) const; + + protected: + /** Identifier of object to verify. */ + const XMLCh* m_id; + }; + +}; + +#endif /* __saml_verctx_h__ */ diff --git a/samltest/Makefile.am b/samltest/Makefile.am index d45c891..ba32aaa 100644 --- a/samltest/Makefile.am +++ b/samltest/Makefile.am @@ -9,7 +9,16 @@ endif samltest_h = \ samltest.h \ - saml1/core/impl/ActionTest.h + saml1/core/impl/ActionTest.h \ + saml1/core/impl/AdviceTest.h \ + saml1/core/impl/AssertionIDReferenceTest.h \ + saml1/core/impl/AssertionTest.h \ + saml1/core/impl/AttributeDesignatorTest.h \ + saml1/core/impl/AttributeStatementTest.h \ + saml1/core/impl/AttributeTest.h \ + saml1/core/impl/AudienceRestrictionConditionTest.h \ + saml1/core/impl/AudienceTest.h \ + saml1/core/impl/AuthenticationStatementTest.h noinst_HEADERS = \ internal.h diff --git a/samltest/saml1/core/impl/AudienceRestrictionConditionTest.h b/samltest/saml1/core/impl/AudienceRestrictionConditionTest.h new file mode 100644 index 0000000..afacde3 --- /dev/null +++ b/samltest/saml1/core/impl/AudienceRestrictionConditionTest.h @@ -0,0 +1,56 @@ +/* + * Copyright 2001-2006 Internet2 + * + * 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 + * + * http://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. + */ + +#include "internal.h" +#include + +using namespace opensaml::saml1; + +class AudienceRestrictionConditionTest : public CxxTest::TestSuite, public SAMLObjectBaseTestCase { +public: + void setUp() { + singleElementFile = data_path + "saml1/core/impl/singleAudienceRestrictionCondition.xml"; + childElementsFile = data_path + "saml1/core/impl/AudienceRestrictionConditionWithChildren.xml"; + SAMLObjectBaseTestCase::setUp(); + } + + void tearDown() { + SAMLObjectBaseTestCase::tearDown(); + } + + void testSingleElementUnmarshall() { + auto_ptr xo(unmarshallElement(singleElementFile)); + AudienceRestrictionCondition& a = dynamic_cast(*xo.get()); + TSM_ASSERT_EQUALS("Count of child Audience elements !=0", 0, a.getAudiences().size()); + } + + void testChildElementsUnmarshall() { + auto_ptr xo(unmarshallElement(childElementsFile)); + AudienceRestrictionCondition& a = dynamic_cast(*xo.get()); + TSM_ASSERT_EQUALS("Count of child Audience elements", 2, a.getAudiences().size()); + } + + void testSingleElementMarshall() { + assertEquals(expectedDOM, AudienceRestrictionConditionBuilder::buildAudienceRestrictionCondition()); + } + + void testChildElementsMarshall(){ + AudienceRestrictionCondition* a=AudienceRestrictionConditionBuilder::buildAudienceRestrictionCondition(); + a->getAudiences().push_back(AudienceBuilder::buildAudience()); + a->getAudiences().push_back(AudienceBuilder::buildAudience()); + assertEquals(expectedChildElementsDOM, a); + } +}; diff --git a/samltest/saml1/core/impl/AudienceTest.h b/samltest/saml1/core/impl/AudienceTest.h new file mode 100644 index 0000000..aa281c2 --- /dev/null +++ b/samltest/saml1/core/impl/AudienceTest.h @@ -0,0 +1,60 @@ +/* + * Copyright 2001-2006 Internet2 + * + * 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 + * + * http://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. + */ + +#include "internal.h" +#include + +using namespace opensaml::saml1; + +class AudienceTest : public CxxTest::TestSuite, public SAMLObjectBaseTestCase { + XMLCh* expectedUri; + +public: + void setUp() { + expectedUri=XMLString::transcode("urn:oasis:names:tc:SAML:1.0:assertion"); + singleElementFile = data_path + "saml1/core/impl/singleAudience.xml"; + singleElementOptionalAttributesFile = data_path + "saml1/core/impl/singleAudienceAttributes.xml"; + SAMLObjectBaseTestCase::setUp(); + } + + void tearDown() { + XMLString::release(&expectedUri); + SAMLObjectBaseTestCase::tearDown(); + } + + void testSingleElementUnmarshall() { + auto_ptr xo(unmarshallElement(singleElementFile)); + Audience& a = dynamic_cast(*xo.get()); + TSM_ASSERT("Uri is non-null", a.getUri()==NULL); + } + + void testSingleElementOptionalAttributesUnmarshall() { + auto_ptr xo(unmarshallElement(singleElementOptionalAttributesFile)); + Audience& a = dynamic_cast(*xo.get()); + TSM_ASSERT_SAME_DATA("Uri", expectedUri, a.getUri(), XMLString::stringLen(expectedUri)); + } + + void testSingleElementMarshall() { + assertEquals(expectedDOM, AudienceBuilder::buildAudience()); + } + + void testSingleElementOptionalAttributesMarshall() { + Audience* a=AudienceBuilder::buildAudience(); + a->setUri(expectedUri); + assertEquals(expectedOptionalAttributesDOM, a); + } + +}; diff --git a/samltest/saml1/core/impl/AuthenticationStatementTest.h b/samltest/saml1/core/impl/AuthenticationStatementTest.h new file mode 100644 index 0000000..26e583d --- /dev/null +++ b/samltest/saml1/core/impl/AuthenticationStatementTest.h @@ -0,0 +1,93 @@ +/* + * Copyright 2001-2006 Internet2 + * + * 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 + * + * http://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. + */ + +#include "internal.h" +#include + +using namespace opensaml::saml1; + +class AuthenticationStatementTest : public CxxTest::TestSuite, public SAMLObjectBaseTestCase { + XMLCh* expectedAuthenticationMethod; + XMLCh* expectedAuthenticationInstant; + +public: + void setUp() { + expectedAuthenticationInstant=XMLString::transcode("1970-01-02T01:01:02.123Z"); + expectedAuthenticationMethod=XMLString::transcode("trustme"); + singleElementFile = data_path + "saml1/core/impl/singleAuthenticationStatement.xml"; + singleElementOptionalAttributesFile = data_path + "saml1/core/impl/singleAuthenticationStatementAttributes.xml"; + childElementsFile = data_path + "saml1/core/impl/AuthenticationStatementWithChildren.xml"; + SAMLObjectBaseTestCase::setUp(); + } + + void tearDown() { + XMLString::release(&expectedAuthenticationInstant); + XMLString::release(&expectedAuthenticationMethod); + SAMLObjectBaseTestCase::tearDown(); + } + + void testSingleElementUnmarshall() { + auto_ptr xo(unmarshallElement(singleElementFile)); + AuthenticationStatement& as = dynamic_cast(*xo.get()); + TSM_ASSERT("AuthenticationMethod attribute present", as.getAuthenticationMethod()==NULL); + TSM_ASSERT("AuthenticationInstant attribute present", as.getAuthenticationInstant()==NULL); + + TSM_ASSERT("Subject element", as.getSubject()==NULL); + TSM_ASSERT("SubjectLocality element", as.getSubjectLocality()==NULL); + TSM_ASSERT_EQUALS("AuthorityBinding element count", 0, as.getAuthorityBindings().size()); + } + + void testSingleElementOptionalAttributesUnmarshall() { + auto_ptr xo(unmarshallElement(singleElementOptionalAttributesFile)); + AuthenticationStatement& as = dynamic_cast(*xo.get()); + + TSM_ASSERT_SAME_DATA("AuthenticationMethod attribute", expectedAuthenticationMethod, as.getAuthenticationMethod(), XMLString::stringLen(expectedAuthenticationMethod)); + TSM_ASSERT_SAME_DATA("AuthenticationInstant attribute", expectedAuthenticationInstant, as.getAuthenticationInstant()->getRawData(), XMLString::stringLen(expectedAuthenticationInstant)); + } + + void testChildElementsUnmarshall() { + auto_ptr xo(unmarshallElement(childElementsFile)); + AuthenticationStatement& as = dynamic_cast(*xo.get()); + + TSM_ASSERT("Subject element", as.getSubject()!=NULL); + TSM_ASSERT("SubjectLocality element", as.getSubjectLocality()!=NULL); + + TSM_ASSERT_EQUALS("AuthorityBinding element count", 2, as.getAuthorityBindings().size()); + as.getAuthorityBindings().erase(as.getAuthorityBindings().begin()); + TSM_ASSERT_EQUALS("AuthorityBinding element count", 1, as.getAuthorityBindings().size()); + } + + void testSingleElementMarshall() { + assertEquals(expectedDOM, AuthenticationStatementBuilder::buildAuthenticationStatement()); + } + + void testSingleElementOptionalAttributesMarshall() { + AuthenticationStatement* as=AuthenticationStatementBuilder::buildAuthenticationStatement(); + as->setAuthenticationInstant(expectedAuthenticationInstant); + as->setAuthenticationMethod(expectedAuthenticationMethod); + assertEquals(expectedOptionalAttributesDOM, as); + } + + void testChildElementsMarshall() { + AuthenticationStatement* as=AuthenticationStatementBuilder::buildAuthenticationStatement(); + as->setSubject(SubjectBuilder::buildSubject()); + as->setSubjectLocality(SubjectLocalityBuilder::buildSubjectLocality()); + as->getAuthorityBindings().push_back(AuthorityBindingBuilder::buildAuthorityBinding()); + as->getAuthorityBindings().push_back(AuthorityBindingBuilder::buildAuthorityBinding()); + assertEquals(expectedChildElementsDOM, as); + } + +}; diff --git a/samltest/samltest.vcproj b/samltest/samltest.vcproj index c6f5e45..a9df5f2 100644 --- a/samltest/samltest.vcproj +++ b/samltest/samltest.vcproj @@ -61,7 +61,7 @@ /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +#include +#include + +using namespace opensaml::saml1; + +#include +#include +#include +#include +#include +#include +#include + +class TestContext : public VerifyingContext +{ + SigningContext* m_signing; + vector m_certs; +public: + TestContext(const XMLCh* uri) : VerifyingContext(uri), m_signing(NULL) { + OpenSSLCryptoKeyRSA* key=NULL; + string keypath=data_path + "key.pem"; + BIO* in=BIO_new(BIO_s_file_internal()); + if (in && BIO_read_filename(in,keypath.c_str())>0) { + EVP_PKEY* pkey=PEM_read_bio_PrivateKey(in, NULL, NULL, NULL); + if (pkey) { + key=new OpenSSLCryptoKeyRSA(pkey); + EVP_PKEY_free(pkey); + } + } + if (in) BIO_free(in); + TS_ASSERT(key!=NULL); + + string certpath=data_path + "cert.pem"; + in=BIO_new(BIO_s_file_internal()); + if (in && BIO_read_filename(in,certpath.c_str())>0) { + X509* x=NULL; + while (x=PEM_read_bio_X509(in,NULL,NULL,NULL)) { + m_certs.push_back(new OpenSSLCryptoX509(x)); + X509_free(x); + } + } + if (in) BIO_free(in); + TS_ASSERT(m_certs.size()>0); + m_signing=new SigningContext(uri, key, &m_certs); + } + + virtual ~TestContext() { + delete m_signing; + for_each(m_certs.begin(),m_certs.end(),xmltooling::cleanup()); + } + + SigningContext* getSigningContext() { return m_signing; } + + void verifySignature(DSIGSignature* sig) const { + VerifyingContext::verifySignature(sig); + sig->setSigningKey(NULL); + XSECKeyInfoResolverDefault resolver; + sig->setKeyInfoResolver(&resolver); + sig->verify(); + } +}; + +class SAML1AssertionTest : public CxxTest::TestSuite, public SAMLObjectBaseTestCase { +public: + void setUp() { + childElementsFile = data_path + "signature/SAML1Assertion.xml"; + SAMLObjectBaseTestCase::setUp(); + } + + void tearDown() { + SAMLObjectBaseTestCase::tearDown(); + } + + void testSignature() { + auto_ptr_XMLCh issuer("issuer"); + auto_ptr_XMLCh issueInstant("1970-01-02T01:01:02.100Z"); + auto_ptr_XMLCh id("ident"); + auto_ptr_XMLCh method("method"); + auto_ptr_XMLCh nameid("John Doe"); + + NameIdentifier* n=NameIdentifierBuilder::buildNameIdentifier(); + n->setName(nameid.get()); + Subject* subject=SubjectBuilder::buildSubject(); + subject->setNameIdentifier(n); + + AuthenticationStatement* statement=AuthenticationStatementBuilder::buildAuthenticationStatement(); + statement->setAuthenticationInstant(issueInstant.get()); + statement->setAuthenticationMethod(method.get()); + statement->setSubject(subject); + + auto_ptr assertion(AssertionBuilder::buildAssertion()); + assertion->setAssertionID(id.get()); + assertion->setIssueInstant(issueInstant.get()); + assertion->setIssuer(issuer.get()); + assertion->getAuthenticationStatements().push_back(statement); + + // Append a Signature. + xmlsignature::Signature* sig=xmlsignature::SignatureBuilder::newSignature(); + assertion->setSignature(sig); + + // Signing context for the assertion. + TestContext tc(id.get()); + MarshallingContext mctx(sig,tc.getSigningContext()); + DOMElement* rootElement = assertion->marshall((DOMDocument*)NULL,&mctx); + + string buf; + XMLHelper::serialize(rootElement, buf); + istringstream in(buf); + DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in); + const XMLObjectBuilder* b = XMLObjectBuilder::getBuilder(doc->getDocumentElement()); + + assertEquals(expectedChildElementsDOM, b->buildFromDocument(doc)); + + try { + assertion->getSignature()->verify(tc); + } + catch (xmlsignature::SignatureException& e) { + TS_TRACE(e.what()); + throw; + } + } + +};