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