Merged trust engines back into a unified version, made metadata roles a "KeyInfoSource".
[shibboleth/cpp-opensaml.git] / samltest / binding.h
1 /*\r
2  *  Copyright 2001-2006 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 \r
19 #include <saml/SAMLConfig.h>\r
20 #include <saml/binding/HTTPRequest.h>\r
21 #include <saml/binding/HTTPResponse.h>\r
22 #include <saml/binding/MessageDecoder.h>\r
23 #include <saml/binding/MessageEncoder.h>\r
24 #include <saml/binding/URLEncoder.h>\r
25 #include <saml/saml2/metadata/Metadata.h>\r
26 #include <saml/saml2/metadata/MetadataProvider.h>\r
27 #include <xmltooling/security/TrustEngine.h>\r
28 \r
29 using namespace opensaml::saml2md;\r
30 using namespace xmlsignature;\r
31 \r
32 class SAMLBindingBaseTestCase : public HTTPRequest, public HTTPResponse\r
33 {\r
34 protected:\r
35     CredentialResolver* m_creds; \r
36     MetadataProvider* m_metadata;\r
37     TrustEngine* m_trust;\r
38     map<string,string> m_fields;\r
39     map<string,string> m_headers;\r
40     string m_method,m_url,m_query;\r
41     vector<XSECCryptoX509*> m_clientCerts;\r
42     vector<const SecurityPolicyRule*> m_rules;\r
43 \r
44 public:\r
45     void setUp() {\r
46         m_creds=NULL;\r
47         m_metadata=NULL;\r
48         m_trust=NULL;\r
49         m_fields.clear();\r
50         m_headers.clear();\r
51         m_method.erase();\r
52         m_url.erase();\r
53         m_query.erase();\r
54 \r
55         try {\r
56             string config = data_path + "binding/ExampleMetadataProvider.xml";\r
57             ifstream in(config.c_str());\r
58             DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);\r
59             XercesJanitor<DOMDocument> janitor(doc);\r
60     \r
61             auto_ptr_XMLCh path("path");\r
62             string s = data_path + "binding/example-metadata.xml";\r
63             auto_ptr_XMLCh file(s.c_str());\r
64             doc->getDocumentElement()->setAttributeNS(NULL,path.get(),file.get());\r
65     \r
66             m_metadata = SAMLConfig::getConfig().MetadataProviderManager.newPlugin(\r
67                 FILESYSTEM_METADATA_PROVIDER,doc->getDocumentElement()\r
68                 );\r
69             m_metadata->init();\r
70 \r
71             config = data_path + "FilesystemCredentialResolver.xml";\r
72             ifstream in2(config.c_str());\r
73             DOMDocument* doc2=XMLToolingConfig::getConfig().getParser().parse(in2);\r
74             XercesJanitor<DOMDocument> janitor2(doc2);\r
75             m_creds = XMLToolingConfig::getConfig().CredentialResolverManager.newPlugin(\r
76                 FILESYSTEM_CREDENTIAL_RESOLVER,doc2->getDocumentElement()\r
77                 );\r
78                 \r
79             m_trust = XMLToolingConfig::getConfig().TrustEngineManager.newPlugin(EXPLICIT_KEY_TRUSTENGINE, NULL);\r
80 \r
81             m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(MESSAGEFLOW_POLICY_RULE,NULL));\r
82             m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(SIMPLESIGNING_POLICY_RULE,NULL));\r
83             m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(XMLSIGNING_POLICY_RULE,NULL));\r
84         }\r
85         catch (XMLToolingException& ex) {\r
86             TS_TRACE(ex.what());\r
87             tearDown();\r
88             throw;\r
89         }\r
90 \r
91     }\r
92     \r
93     void tearDown() {\r
94         for_each(m_rules.begin(), m_rules.end(), xmltooling::cleanup<SecurityPolicyRule>());\r
95         m_rules.clear();\r
96         delete m_creds;\r
97         delete m_metadata;\r
98         delete m_trust;\r
99         m_creds=NULL;\r
100         m_metadata=NULL;\r
101         m_trust=NULL;\r
102         m_fields.clear();\r
103         m_headers.clear();\r
104         m_method.erase();\r
105         m_url.erase();\r
106         m_query.erase();\r
107     }\r
108 \r
109     // HTTPRequest methods\r
110 \r
111     const char* getMethod() const {\r
112         return m_method.c_str();\r
113     }\r
114 \r
115     const char* getScheme() const {\r
116         return "https";\r
117     }\r
118 \r
119     bool isSecure() const {\r
120         return true;\r
121     }\r
122 \r
123     string getContentType() const {\r
124         return "application/x-www-form-urlencoded";\r
125     }\r
126 \r
127     long getContentLength() const {\r
128         return -1;\r
129     }\r
130 \r
131     const char* getRequestURL() const {\r
132         return m_url.c_str();\r
133     }\r
134     \r
135     const char* getRequestBody() const {\r
136         return NULL;\r
137     }\r
138     \r
139     const char* getQueryString() const {\r
140         return m_query.c_str();\r
141     }\r
142     \r
143     string getRemoteUser() const {\r
144         return "";\r
145     }\r
146 \r
147     string getRemoteAddr() const {\r
148         return "127.0.0.1";\r
149     }\r
150 \r
151     const std::vector<XSECCryptoX509*>& getClientCertificates() const {\r
152         return m_clientCerts;\r
153     }\r
154 \r
155     string getHeader(const char* name) const {\r
156         map<string,string>::const_iterator i=m_headers.find(name);\r
157         return i==m_headers.end() ? "" : i->second;\r
158     }\r
159     \r
160     const char* getParameter(const char* name) const {\r
161         map<string,string>::const_iterator i=m_fields.find(name);\r
162         return i==m_fields.end() ? NULL : i->second.c_str();\r
163     }\r
164 \r
165     vector<const char*>::size_type getParameters(const char* name, vector<const char*>& values) const {\r
166         values.clear();\r
167         map<string,string>::const_iterator i=m_fields.find(name);\r
168         if (i!=m_fields.end())\r
169             values.push_back(i->second.c_str());\r
170         return values.size();\r
171     }\r
172     \r
173     // HTTPResponse methods\r
174     \r
175     void setHeader(const char* name, const char* value) {\r
176         m_headers[name] = value ? value : "";\r
177     }\r
178 \r
179     void setContentType(const char* type) {\r
180         setHeader("Content-Type", type);\r
181     }\r
182     \r
183     void setCookie(const char* name, const char* value) {\r
184         m_headers["Set-Cookie"] = string(name) + "=" + (value ? value : "");\r
185     }\r
186     \r
187     // The amount of error checking missing from this is incredible, but as long\r
188     // as the test data isn't unexpected or malformed, it should work.\r
189     \r
190     long sendRedirect(const char* url) {\r
191         m_method = "GET";\r
192         char* dup = strdup(url);\r
193         char* pch = strchr(dup,'?');\r
194         if (pch) {\r
195             *pch++=0;\r
196             m_query = pch;\r
197             char* name=pch;\r
198             while (name && *name) {\r
199                 pch=strchr(pch,'=');\r
200                 *pch++=0;\r
201                 char* value=pch;\r
202                 pch=strchr(pch,'&');\r
203                 if (pch)\r
204                     *pch++=0;\r
205                 SAMLConfig::getConfig().getURLEncoder()->decode(value);\r
206                 m_fields[name] = value;\r
207                 name = pch; \r
208             }\r
209         }\r
210         m_url = dup;\r
211         free(dup);\r
212         return m_fields.size();\r
213     }\r
214     \r
215     string html_decode(const string& s) const {\r
216         string decoded;\r
217         const char* ch=s.c_str();\r
218         while (*ch) {\r
219             if (*ch=='&') {\r
220                 if (!strncmp(ch,"&lt;",4)) {\r
221                     decoded+='<'; ch+=4;\r
222                 }\r
223                 else if (!strncmp(ch,"&gt;",4)) {\r
224                     decoded+='>'; ch+=4;\r
225                 }\r
226                 else if (!strncmp(ch,"&quot;",6)) {\r
227                     decoded+='"'; ch+=6;\r
228                 }\r
229                 else if (*++ch=='#') {\r
230                     decoded+=(char)atoi(++ch);\r
231                     ch=strchr(ch,';')+1;\r
232                 }\r
233             }\r
234             else {\r
235                 decoded+=*ch++;\r
236             }\r
237         }\r
238         return decoded;\r
239     }\r
240     \r
241     long sendResponse(std::istream& inputStream) {\r
242         return sendResponse(inputStream, HTTPResponse::SAML_HTTP_STATUS_OK);\r
243     }\r
244 \r
245     long sendError(std::istream& inputStream) {\r
246         return sendResponse(inputStream, HTTPResponse::SAML_HTTP_STATUS_ERROR);\r
247     }\r
248 \r
249     long sendResponse(std::istream& inputStream, long status) {\r
250         m_method="POST";\r
251         string page,line;\r
252         while (getline(inputStream,line))\r
253             page += line + '\n';\r
254             \r
255         const char* pch=strstr(page.c_str(),"action=\"");\r
256         pch+=strlen("action=\"");\r
257         m_url = html_decode(page.substr(pch-page.c_str(),strchr(pch,'"')-pch));\r
258 \r
259         while (pch=strstr(pch,"<input type=\"hidden\" name=\"")) {\r
260             pch+=strlen("<input type=\"hidden\" name=\"");\r
261             string name = page.substr(pch-page.c_str(),strchr(pch,'"')-pch);\r
262             pch=strstr(pch,"value=\"");\r
263             pch+=strlen("value=\"");\r
264             m_fields[name] = html_decode(page.substr(pch-page.c_str(),strchr(pch,'"')-pch));\r
265         }\r
266         return m_fields.size();\r
267     }\r
268 };\r