From 19a320b1a8d5c733503a4b1aa842865d59b25d24 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Fri, 20 Apr 2007 19:51:04 +0000 Subject: [PATCH] Multi-line svn commit, see body. Encrypted assertion test. SAML-specific encryption key resolver needs to call base class. --- .cdtproject | 3 +- saml/encryption/EncryptedKeyResolver.cpp | 4 + saml/saml2/core/impl/Assertions.cpp | 3 - samltest/Makefile.am | 1 + samltest/data/binding/example-metadata.xml | 5 +- samltest/encryption/EncryptedAssertionTest.cpp | 27 +++++ samltest/encryption/EncryptedAssertionTest.h | 148 +++++++++++++++++++++++++ samltest/samltest.vcproj | 34 ++++++ 8 files changed, 219 insertions(+), 6 deletions(-) create mode 100644 samltest/encryption/EncryptedAssertionTest.cpp create mode 100644 samltest/encryption/EncryptedAssertionTest.h diff --git a/.cdtproject b/.cdtproject index 5bc0b69..7053798 100644 --- a/.cdtproject +++ b/.cdtproject @@ -73,7 +73,7 @@ - + @@ -90,6 +90,7 @@ + diff --git a/saml/encryption/EncryptedKeyResolver.cpp b/saml/encryption/EncryptedKeyResolver.cpp index 8831717..449a753 100644 --- a/saml/encryption/EncryptedKeyResolver.cpp +++ b/saml/encryption/EncryptedKeyResolver.cpp @@ -29,6 +29,10 @@ using namespace std; const EncryptedKey* opensaml::EncryptedKeyResolver::resolveKey(const EncryptedData& encryptedData, const XMLCh* recipient) const { + const EncryptedKey* base = xmlencryption::EncryptedKeyResolver::resolveKey(encryptedData, recipient); + if (base) + return base; + const vector& keys=m_ref.getEncryptedKeys(); for (vector::const_iterator i=keys.begin(); i!=keys.end(); i++) { if (XMLString::equals(recipient,(*i)->getRecipient())) diff --git a/saml/saml2/core/impl/Assertions.cpp b/saml/saml2/core/impl/Assertions.cpp index 585723a..dbbc6e3 100644 --- a/saml/saml2/core/impl/Assertions.cpp +++ b/saml/saml2/core/impl/Assertions.cpp @@ -79,9 +79,6 @@ void EncryptedElementType::encrypt( const XMLCh* algorithm ) { - if (recipients.size()==1) - return encrypt(xmlObject, *recipients.front().first, *recipients.front().second, compact, algorithm); - // With multiple recipients, we have to generate an encryption key and then multicast it, // so we need to split the encryption and key wrapping steps. if (!algorithm || !*algorithm) diff --git a/samltest/Makefile.am b/samltest/Makefile.am index 932a2c5..706d38b 100644 --- a/samltest/Makefile.am +++ b/samltest/Makefile.am @@ -14,6 +14,7 @@ samltest_h = \ SAMLArtifactType0002Test.h \ SAMLArtifactType0004Test.h \ ArtifactMapTest.h \ + encryption/EncryptedAssertionTest.h \ signature/SAML1AssertionTest.h \ signature/SAML1RequestTest.h \ signature/SAML1ResponseTest.h \ diff --git a/samltest/data/binding/example-metadata.xml b/samltest/data/binding/example-metadata.xml index f4e82f8..1a3f5f3 100644 --- a/samltest/data/binding/example-metadata.xml +++ b/samltest/data/binding/example-metadata.xml @@ -6,7 +6,7 @@ - + @@ -31,8 +31,9 @@ - + + sp.example.org MIICjzCCAfigAwIBAgIJAKk8t1hYcMkhMA0GCSqGSIb3DQEBBAUAMDoxCzAJBgNV diff --git a/samltest/encryption/EncryptedAssertionTest.cpp b/samltest/encryption/EncryptedAssertionTest.cpp new file mode 100644 index 0000000..c835ff6 --- /dev/null +++ b/samltest/encryption/EncryptedAssertionTest.cpp @@ -0,0 +1,27 @@ +/* Generated file, do not edit */ + +#ifndef CXXTEST_RUNNING +#define CXXTEST_RUNNING +#endif + +#define _CXXTEST_HAVE_STD +#define _CXXTEST_HAVE_EH +#define _CXXTEST_ABORT_TEST_ON_FAIL +#include +#include +#include +#include + +#include "c:\cvs\cpp-opensaml2\samltest\encryption\EncryptedAssertionTest.h" + +static EncryptedAssertionTest suite_EncryptedAssertionTest; + +static CxxTest::List Tests_EncryptedAssertionTest = { 0, 0 }; +CxxTest::StaticSuiteDescription suiteDescription_EncryptedAssertionTest( "c:\\cvs\\cpp-opensaml2\\samltest\\encryption\\EncryptedAssertionTest.h", 30, "EncryptedAssertionTest", suite_EncryptedAssertionTest, Tests_EncryptedAssertionTest ); + +static class TestDescription_EncryptedAssertionTest_testEncryptedAssertion : public CxxTest::RealTestDescription { +public: + TestDescription_EncryptedAssertionTest_testEncryptedAssertion() : CxxTest::RealTestDescription( Tests_EncryptedAssertionTest, suiteDescription_EncryptedAssertionTest, 59, "testEncryptedAssertion" ) {} + void runTest() { suite_EncryptedAssertionTest.testEncryptedAssertion(); } +} testDescription_EncryptedAssertionTest_testEncryptedAssertion; + diff --git a/samltest/encryption/EncryptedAssertionTest.h b/samltest/encryption/EncryptedAssertionTest.h new file mode 100644 index 0000000..70eb860 --- /dev/null +++ b/samltest/encryption/EncryptedAssertionTest.h @@ -0,0 +1,148 @@ +/* + * Copyright 2001-2007 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 "signature/SAMLSignatureTestBase.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace opensaml::saml2md; +using namespace opensaml::saml2; + +class EncryptedAssertionTest : public CxxTest::TestSuite, public SAMLSignatureTestBase { + MetadataProvider* m_metadata; +public: + void setUp() { + childElementsFile = data_path + "signature/SAML2Assertion.xml"; + SAMLSignatureTestBase::setUp(); + + string config = data_path + "binding/ExampleMetadataProvider.xml"; + ifstream in(config.c_str()); + DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in); + XercesJanitor janitor(doc); + + auto_ptr_XMLCh path("path"); + string s = data_path + "binding/example-metadata.xml"; + auto_ptr_XMLCh file(s.c_str()); + doc->getDocumentElement()->setAttributeNS(NULL,path.get(),file.get()); + + m_metadata = opensaml::SAMLConfig::getConfig().MetadataProviderManager.newPlugin( + XML_METADATA_PROVIDER,doc->getDocumentElement() + ); + m_metadata->init(); + } + + void tearDown() { + delete m_metadata; + m_metadata=NULL; + SAMLSignatureTestBase::tearDown(); + } + + void testEncryptedAssertion() { + 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"); + + Issuer* is=IssuerBuilder::buildIssuer(); + is->setName(issuer.get()); + + NameID* n=NameIDBuilder::buildNameID(); + n->setName(nameid.get()); + Subject* subject=SubjectBuilder::buildSubject(); + subject->setNameID(n); + + AuthnStatement* statement=AuthnStatementBuilder::buildAuthnStatement(); + statement->setAuthnInstant(issueInstant.get()); + + AuthnContext* ac=AuthnContextBuilder::buildAuthnContext(); + AuthnContextClassRef* acc=AuthnContextClassRefBuilder::buildAuthnContextClassRef(); + acc->setReference(method.get()); + ac->setAuthnContextClassRef(acc); + statement->setAuthnContext(ac); + + auto_ptr assertion(AssertionBuilder::buildAssertion()); + assertion->setID(id.get()); + assertion->setIssueInstant(issueInstant.get()); + assertion->setIssuer(is); + assertion->setSubject(subject); + assertion->getAuthnStatements().push_back(statement); + + // Append a Signature. + Signature* sig=SignatureBuilder::buildSignature(); + assertion->setSignature(sig); + + // Sign while marshalling. + vector sigs(1,sig); + CredentialCriteria cc; + cc.setUsage(CredentialCriteria::SIGNING_CREDENTIAL); + Locker locker(m_resolver); + const Credential* cred = m_resolver->resolve(&cc); + TSM_ASSERT("Retrieved credential was null", cred!=NULL); + + DOMElement* rootElement = NULL; + try { + rootElement=assertion->marshall((DOMDocument*)NULL,&sigs,cred); + } + catch (XMLToolingException& e) { + TS_TRACE(e.what()); + throw; + } + + // Now encrypt this puppy to the SP role in the example metadata. + auto_ptr encrypted(EncryptedAssertionBuilder::buildEncryptedAssertion()); + Locker mlocker(m_metadata); + const EntityDescriptor* sp = m_metadata->getEntityDescriptor("https://sp.example.org/"); + TSM_ASSERT("No metadata for recipient.", sp!=NULL); + const SPSSODescriptor* sprole = sp->getSPSSODescriptor(samlconstants::SAML20P_NS); + TSM_ASSERT("No SP role for recipient.", sprole!=NULL); + MetadataCredentialCriteria mcc(*sprole); + vector< pair > recipients(1, make_pair(m_metadata, &mcc)); + encrypted->encrypt(*assertion.get(), recipients); + + // Roundtrip it. + string buf; + XMLHelper::serialize(encrypted->marshall(), buf); + //TS_TRACE(buf.c_str()); + istringstream in(buf); + DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in); + const XMLObjectBuilder* b = XMLObjectBuilder::getBuilder(doc->getDocumentElement()); + + // Unpack, then decypt with our key. + auto_ptr encrypted2(dynamic_cast(b->buildFromDocument(doc))); + auto_ptr assertion2(dynamic_cast(encrypted2->decrypt(*m_resolver, sp->getEntityID()))); + assertEquals("Unmarshalled assertion does not match", expectedChildElementsDOM, assertion2.get(), false); + + // And check the signature. + try { + opensaml::SignatureProfileValidator spv; + SignatureValidator sv(cred); + spv.validate(dynamic_cast(assertion2.get())->getSignature()); + sv.validate(dynamic_cast(assertion2.get())->getSignature()); + } + catch (XMLToolingException& e) { + TS_TRACE(e.what()); + throw; + } + } + +}; diff --git a/samltest/samltest.vcproj b/samltest/samltest.vcproj index 0eeb2b0..543520e 100644 --- a/samltest/samltest.vcproj +++ b/samltest/samltest.vcproj @@ -561,6 +561,14 @@ > + + + + + + + + + + + + + +