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