Refactored signature handling.
[shibboleth/cpp-opensaml.git] / samltest / signature / SAML1AssertionTest.h
1 /*\r
2  *  Copyright 2001-2005 Internet2\r
3  * \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 #include "internal.h"\r
18 #include <saml/saml1/core/Assertions.h>\r
19 #include <saml/signature/SignatureProfileValidator.h>\r
20 \r
21 #include <xmltooling/signature/Signature.h>\r
22 \r
23 #include <fstream>\r
24 #include <openssl/pem.h>\r
25 #include <xercesc/util/XMLUniDefs.hpp>\r
26 #include <xsec/enc/XSECKeyInfoResolverDefault.hpp>\r
27 #include <xsec/enc/OpenSSL/OpenSSLCryptoX509.hpp>\r
28 #include <xsec/enc/OpenSSL/OpenSSLCryptoKeyRSA.hpp>\r
29 #include <xsec/enc/XSECCryptoException.hpp>\r
30 #include <xsec/framework/XSECException.hpp>\r
31 \r
32 using namespace opensaml::saml1;\r
33 using namespace xmlsignature;\r
34 \r
35 class TestValidator : public Validator\r
36 {\r
37 public:\r
38     TestValidator() {}\r
39     virtual ~TestValidator() {}\r
40 \r
41     Validator* clone() const {\r
42         return new TestValidator();\r
43     }\r
44 \r
45     void validate(const XMLObject* xmlObject) const {\r
46         DSIGSignature* sig=dynamic_cast<const Signature*>(xmlObject)->getXMLSignature();\r
47         if (!sig)\r
48             throw SignatureException("Only a marshalled Signature object can be verified.");\r
49         XSECKeyInfoResolverDefault resolver;\r
50         sig->setKeyInfoResolver(&resolver); // It will clone the resolver for us.\r
51         try {\r
52             if (!sig->verify())\r
53                 throw SignatureException("Signature did not verify.");\r
54         }\r
55         catch(XSECException& e) {\r
56             auto_ptr_char temp(e.getMsg());\r
57             throw SignatureException(string("Caught an XMLSecurity exception verifying signature: ") + temp.get());\r
58         }\r
59         catch(XSECCryptoException& e) {\r
60             throw SignatureException(string("Caught an XMLSecurity exception verifying signature: ") + e.getMsg());\r
61         }\r
62     }\r
63 };\r
64 \r
65 class _addcert : public std::binary_function<X509Data*,XSECCryptoX509*,void> {\r
66 public:\r
67     void operator()(X509Data* bag, XSECCryptoX509* cert) const {\r
68         safeBuffer& buf=cert->getDEREncodingSB();\r
69         X509Certificate* x=X509CertificateBuilder::buildX509Certificate();\r
70         x->setValue(buf.sbStrToXMLCh());\r
71         bag->getX509Certificates().push_back(x);\r
72     }\r
73 };\r
74 \r
75 class SAML1AssertionTest : public CxxTest::TestSuite, public SAMLObjectBaseTestCase {\r
76     XSECCryptoKey* m_key;\r
77     vector<XSECCryptoX509*> m_certs;\r
78 public:\r
79     void setUp() {\r
80         childElementsFile  = data_path + "signature/SAML1Assertion.xml";\r
81         SAMLObjectBaseTestCase::setUp();\r
82         string keypath=data_path + "key.pem";\r
83         BIO* in=BIO_new(BIO_s_file_internal());\r
84         if (in && BIO_read_filename(in,keypath.c_str())>0) {\r
85             EVP_PKEY* pkey=PEM_read_bio_PrivateKey(in, NULL, NULL, NULL);\r
86             if (pkey) {\r
87                 m_key=new OpenSSLCryptoKeyRSA(pkey);\r
88                 EVP_PKEY_free(pkey);\r
89             }\r
90         }\r
91         if (in) BIO_free(in);\r
92         TS_ASSERT(m_key!=NULL);\r
93 \r
94         string certpath=data_path + "cert.pem";\r
95         in=BIO_new(BIO_s_file_internal());\r
96         if (in && BIO_read_filename(in,certpath.c_str())>0) {\r
97             X509* x=NULL;\r
98             while (x=PEM_read_bio_X509(in,NULL,NULL,NULL)) {\r
99                 m_certs.push_back(new OpenSSLCryptoX509(x));\r
100                 X509_free(x);\r
101             }\r
102         }\r
103         if (in) BIO_free(in);\r
104         TS_ASSERT(m_certs.size()>0);\r
105     }\r
106 \r
107     void tearDown() {\r
108         SAMLObjectBaseTestCase::tearDown();\r
109         delete m_key;\r
110         for_each(m_certs.begin(),m_certs.end(),xmltooling::cleanup<XSECCryptoX509>());\r
111     }\r
112 \r
113     void testSignature() {\r
114         auto_ptr_XMLCh issuer("issuer");\r
115         auto_ptr_XMLCh issueInstant("1970-01-02T01:01:02.100Z");\r
116         auto_ptr_XMLCh id("ident");\r
117         auto_ptr_XMLCh method("method");\r
118         auto_ptr_XMLCh nameid("John Doe");\r
119         \r
120         NameIdentifier* n=NameIdentifierBuilder::buildNameIdentifier();\r
121         n->setName(nameid.get());        \r
122         Subject* subject=SubjectBuilder::buildSubject();\r
123         subject->setNameIdentifier(n);\r
124 \r
125         AuthenticationStatement* statement=AuthenticationStatementBuilder::buildAuthenticationStatement();\r
126         statement->setAuthenticationInstant(issueInstant.get());\r
127         statement->setAuthenticationMethod(method.get());\r
128         statement->setSubject(subject);\r
129         \r
130         auto_ptr<Assertion> assertion(AssertionBuilder::buildAssertion());\r
131         assertion->setAssertionID(id.get());\r
132         assertion->setIssueInstant(issueInstant.get());\r
133         assertion->setIssuer(issuer.get());\r
134         assertion->getAuthenticationStatements().push_back(statement);\r
135 \r
136         // Append a Signature.\r
137         Signature* sig=SignatureBuilder::buildSignature();\r
138         assertion->setSignature(sig);\r
139         sig->setSigningKey(m_key->clone());\r
140 \r
141         // Build KeyInfo.\r
142         KeyInfo* keyInfo=KeyInfoBuilder::buildKeyInfo();\r
143         X509Data* x509Data=X509DataBuilder::buildX509Data();\r
144         keyInfo->getX509Datas().push_back(x509Data);\r
145         for_each(m_certs.begin(),m_certs.end(),bind1st(_addcert(),x509Data));\r
146         sig->setKeyInfo(keyInfo);\r
147 \r
148         // Sign while marshalling.\r
149         vector<Signature*> sigs(1,sig);\r
150         DOMElement* rootElement = NULL;\r
151         try {\r
152             rootElement=assertion->marshall((DOMDocument*)NULL,&sigs);\r
153         }\r
154         catch (XMLToolingException& e) {\r
155             TS_TRACE(e.what());\r
156             throw;\r
157         }\r
158         \r
159         string buf;\r
160         XMLHelper::serialize(rootElement, buf);\r
161         istringstream in(buf);\r
162         DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);\r
163         const XMLObjectBuilder* b = XMLObjectBuilder::getBuilder(doc->getDocumentElement());\r
164         \r
165         assertEquals(expectedChildElementsDOM, b->buildFromDocument(doc));\r
166         \r
167         try {\r
168             assertion->getSignature()->registerValidator(new SignatureProfileValidator());\r
169             assertion->getSignature()->registerValidator(new TestValidator());\r
170             assertion->getSignature()->validate(true);\r
171         }\r
172         catch (XMLToolingException& e) {\r
173             TS_TRACE(e.what());\r
174             throw;\r
175         }\r
176     }\r
177 \r
178 };\r