2 * The Shibboleth License, Version 1.
4 * University Corporation for Advanced Internet Development, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
14 * Redistributions in binary form must reproduce the above copyright notice,
15 * this list of conditions and the following disclaimer in the documentation
16 * and/or other materials provided with the distribution, if any, must include
17 * the following acknowledgment: "This product includes software developed by
18 * the University Corporation for Advanced Internet Development
19 * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
20 * may appear in the software itself, if and wherever such third-party
21 * acknowledgments normally appear.
23 * Neither the name of Shibboleth nor the names of its contributors, nor
24 * Internet2, nor the University Corporation for Advanced Internet Development,
25 * Inc., nor UCAID may be used to endorse or promote products derived from this
26 * software without specific prior written permission. For written permission,
27 * please contact shibboleth@shibboleth.org
29 * Products derived from this software may not be called Shibboleth, Internet2,
30 * UCAID, or the University Corporation for Advanced Internet Development, nor
31 * may Shibboleth appear in their name, without prior written permission of the
32 * University Corporation for Advanced Internet Development.
35 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
36 * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
38 * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
39 * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
40 * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
41 * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
42 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
51 * shib-mlp.cpp -- The ShibTarget Markup Language processor
53 * Created by: Derek Atkins <derek@ihtfp.com>
62 #include <xercesc/util/XercesDefs.hpp>
63 #include <log4cpp/Category.hh>
66 using namespace log4cpp;
68 using namespace shibboleth;
69 using namespace shibtarget;
71 class shibtarget::ShibMLPPriv {
75 log4cpp::Category *log;
78 ShibMLPPriv::ShibMLPPriv() : log(&(log4cpp::Category::getInstance("shibtarget.ShibMLP"))) {}
80 static void trimspace (string& s)
82 int end = s.size() - 1, start = 0;
84 // Trim stuff on right.
85 while (end > 0 && !isgraph(s[end])) end--;
87 // Trim stuff on left.
88 while (start < end && !isgraph(s[start])) start++;
91 s = s.substr(start, end - start + 1);
96 m_priv = new ShibMLPPriv ();
104 const char* ShibMLP::run(const string& is, const IPropertySet* props, std::string* output)
106 // Create a timestamp
107 time_t now = time(NULL);
108 insert("now", ctime(&now));
112 const char* line = is.c_str();
113 const char* lastpos = line;
116 m_priv->log->debug("Processing string");
119 // Search for SHIBMLP tags. These are of the form:
121 // <shibmlpif key> stuff </shibmlpif>
122 // <shibmlpifnot key> stuff </shibmlpifnot>
123 // Note that there MUST be white-space after "<shibmlp" but
124 // there does not need to be white space between the key and
127 while ((thispos = strchr(lastpos, '<')) != NULL) {
128 // save the string up to this token
129 *output += is.substr(lastpos-line, thispos-lastpos);
131 // Make sure this token matches our tokens.
132 #ifdef HAVE_STRCASECMP
133 if (!strncasecmp(thispos, "<shibmlp ", 9))
135 if (!strnicmp(thispos, "<shibmlp ", 9))
138 // Save this position off.
139 lastpos = thispos + 9; // strlen("<shibmlp ")
141 // search for the end-tag
142 if ((thispos = strstr(lastpos, "/>")) != NULL) {
143 string key = is.substr(lastpos-line, thispos-lastpos);
146 map<string,string>::const_iterator i=m_map.find(key);
147 if (i != m_map.end()) {
148 *output += i->second;
151 pair<bool,const char*> p=props ? props->getString(key.c_str()) : pair<bool,const char*>(false,NULL);
156 static const char* s1 = "<!-- Unknown SHIBMLP key: ";
157 static const char* s2 = "/>";
162 lastpos = thispos + 2; // strlen("/>")
165 #ifdef HAVE_STRCASECMP
166 else if (!strncasecmp(thispos, "<shibmlpif ", 11))
168 else if (!strnicmp(thispos, "<shibmlpif ", 11))
171 // Save this position off.
172 lastpos = thispos + 11; // strlen("<shibmlpif ")
174 // search for the end of this tag
175 if ((thispos = strchr(lastpos, '>')) != NULL) {
176 string key = is.substr(lastpos-line, thispos-lastpos);
179 map<string,string>::const_iterator i=m_map.find(key);
180 if (i != m_map.end() && !i->second.empty()) {
184 pair<bool,const char*> p=props ? props->getString(key.c_str()) : pair<bool,const char*>(false,NULL);
189 lastpos = thispos + 1; // strlen(">")
191 // Search for the closing tag.
192 const char* frontpos=lastpos;
193 while ((thispos = strstr(lastpos, "</")) != NULL) {
194 #ifdef HAVE_STRCASECMP
195 if (!strncasecmp(thispos, "</shibmlpif>", 12))
197 if (!strnicmp(thispos, "</shibmlpif>", 12))
200 // We found our terminator. Process the string in between.
202 run(is.substr(frontpos-line, thispos-frontpos),props,&segment);
205 lastpos = thispos + 12; // strlen("</shibmlpif>")
210 lastpos = thispos + 2;
215 #ifdef HAVE_STRCASECMP
216 else if (!strncasecmp(thispos, "<shibmlpifnot ", 14))
218 else if (!strnicmp(thispos, "<shibmlpifnot ", 14))
221 // Save this position off.
222 lastpos = thispos + 14; // strlen("<shibmlpifnot ")
224 // search for the end of this tag
225 if ((thispos = strchr(lastpos, '>')) != NULL) {
226 string key = is.substr(lastpos-line, thispos-lastpos);
229 map<string,string>::const_iterator i=m_map.find(key);
230 if (i != m_map.end() && !i->second.empty()) {
234 pair<bool,const char*> p=props ? props->getString(key.c_str()) : pair<bool,const char*>(false,NULL);
239 lastpos = thispos + 1; // strlen(">")
241 // Search for the closing tag.
242 const char* frontpos=lastpos;
243 while ((thispos = strstr(lastpos, "</")) != NULL) {
244 #ifdef HAVE_STRCASECMP
245 if (!strncasecmp(thispos, "</shibmlpifnot>", 15))
247 if (!strnicmp(thispos, "</shibmlpifnot>", 15))
250 // We found our terminator. Process the string in between.
252 run(is.substr(frontpos-line, thispos-frontpos),props,&segment);
255 lastpos = thispos + 15; // strlen("</shibmlpifnot>")
260 lastpos = thispos + 2;
268 lastpos = thispos + 1;
271 *output += is.substr(lastpos-line);
273 return output->c_str();
276 const char* ShibMLP::run(istream& is, const IPropertySet* props, std::string* output)
278 static string eol = "\r\n";
281 m_priv->log->debug("processing stream");
283 while (getline(is, line))
286 return run(str,props,output);
289 void ShibMLP::insert(SAMLException& e)
291 insert("errorType", e.classname());
292 if (typeid(e)==typeid(ContentTypeException))
293 insert("errorText", "A problem was detected with your identity provider's software configuration.");
295 insert("errorText", e.getMessage() ? e.getMessage() : "No Message");
296 if (e.getProperty("errorURL"))
297 insert("originErrorURL", e.getProperty("errorURL"));
298 if (e.getProperty("contactName"))
299 insert("originContactName", e.getProperty("contactName"));
300 if (e.getProperty("contactEmail"))
301 insert("originContactEmail", e.getProperty("contactEmail"));
304 void ShibMLP::insert (const std::string& key, const std::string& value)
306 m_priv->log->debug("inserting %s -> %s", key.c_str(), value.c_str());