2 * Copyright 2001-2005 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * shib-mlp.cpp -- The ShibTarget Markup Language processor
20 * Created by: Derek Atkins <derek@ihtfp.com>
30 #include <xercesc/util/XercesDefs.hpp>
34 using namespace shibboleth;
35 using namespace shibtarget;
37 void ShibMLP::html_encode(string& os, const char* start)
39 while (start && *start) {
41 case '<': os += "<"; break;
42 case '>': os += ">"; break;
43 case '"': os += """; break;
44 case '#': os += "#"; break;
45 case '%': os += "%"; break;
46 case '&': os += "&"; break;
47 case '\'': os += "'"; break;
48 case '(': os += "("; break;
49 case ')': os += ")"; break;
50 case ':': os += ":"; break;
51 case '[': os += "["; break;
52 case '\\': os += "\"; break;
53 case ']': os += "]"; break;
54 case '`': os += "`"; break;
55 case '{': os += "{"; break;
56 case '}': os += "}"; break;
57 default: os += *start;
63 static void trimspace (string& s)
65 int end = s.size() - 1, start = 0;
67 // Trim stuff on right.
68 while (end > 0 && !isgraph(s[end])) end--;
70 // Trim stuff on left.
71 while (start < end && !isgraph(s[start])) start++;
74 s = s.substr(start, end - start + 1);
77 const char* ShibMLP::run(const string& is, const IPropertySet* props, std::string* output)
80 time_t now = time(NULL);
81 #if defined(HAVE_CTIME_R_2)
83 insert("now", ctime_r(&now,timebuf));
84 #elif defined(HAVE_CTIME_R_3)
86 insert("now", ctime_r(&now,timebuf,sizeof(timebuf)));
88 insert("now", ctime(&now));
93 const char* line = is.c_str();
94 const char* lastpos = line;
98 // Search for SHIBMLP tags. These are of the form:
100 // <shibmlpif key> stuff </shibmlpif>
101 // <shibmlpifnot key> stuff </shibmlpifnot>
102 // Note that there MUST be white-space after "<shibmlp" but
103 // there does not need to be white space between the key and
106 while ((thispos = strchr(lastpos, '<')) != NULL) {
107 // save the string up to this token
108 *output += is.substr(lastpos-line, thispos-lastpos);
110 // Make sure this token matches our tokens.
111 #ifdef HAVE_STRCASECMP
112 if (!strncasecmp(thispos, "<shibmlp ", 9))
114 if (!strnicmp(thispos, "<shibmlp ", 9))
117 // Save this position off.
118 lastpos = thispos + 9; // strlen("<shibmlp ")
120 // search for the end-tag
121 if ((thispos = strstr(lastpos, "/>")) != NULL) {
122 string key = is.substr(lastpos-line, thispos-lastpos);
125 map<string,string>::const_iterator i=m_map.find(key);
126 if (i != m_map.end()) {
127 html_encode(*output,i->second.c_str());
130 pair<bool,const char*> p=props ? props->getString(key.c_str()) : pair<bool,const char*>(false,NULL);
132 html_encode(*output,p.second);
135 static const char* s1 = "<!-- Unknown SHIBMLP key: ";
136 static const char* s2 = "/>";
141 lastpos = thispos + 2; // strlen("/>")
144 #ifdef HAVE_STRCASECMP
145 else if (!strncasecmp(thispos, "<shibmlpif ", 11))
147 else if (!strnicmp(thispos, "<shibmlpif ", 11))
150 // Save this position off.
151 lastpos = thispos + 11; // strlen("<shibmlpif ")
153 // search for the end of this tag
154 if ((thispos = strchr(lastpos, '>')) != NULL) {
155 string key = is.substr(lastpos-line, thispos-lastpos);
158 map<string,string>::const_iterator i=m_map.find(key);
159 if (i != m_map.end() && !i->second.empty()) {
163 pair<bool,const char*> p=props ? props->getString(key.c_str()) : pair<bool,const char*>(false,NULL);
168 lastpos = thispos + 1; // strlen(">")
170 // Search for the closing tag.
171 const char* frontpos=lastpos;
172 while ((thispos = strstr(lastpos, "</")) != NULL) {
173 #ifdef HAVE_STRCASECMP
174 if (!strncasecmp(thispos, "</shibmlpif>", 12))
176 if (!strnicmp(thispos, "</shibmlpif>", 12))
179 // We found our terminator. Process the string in between.
181 run(is.substr(frontpos-line, thispos-frontpos),props,&segment);
184 lastpos = thispos + 12; // strlen("</shibmlpif>")
189 lastpos = thispos + 2;
194 #ifdef HAVE_STRCASECMP
195 else if (!strncasecmp(thispos, "<shibmlpifnot ", 14))
197 else if (!strnicmp(thispos, "<shibmlpifnot ", 14))
200 // Save this position off.
201 lastpos = thispos + 14; // strlen("<shibmlpifnot ")
203 // search for the end of this tag
204 if ((thispos = strchr(lastpos, '>')) != NULL) {
205 string key = is.substr(lastpos-line, thispos-lastpos);
208 map<string,string>::const_iterator i=m_map.find(key);
209 if (i != m_map.end() && !i->second.empty()) {
213 pair<bool,const char*> p=props ? props->getString(key.c_str()) : pair<bool,const char*>(false,NULL);
218 lastpos = thispos + 1; // strlen(">")
220 // Search for the closing tag.
221 const char* frontpos=lastpos;
222 while ((thispos = strstr(lastpos, "</")) != NULL) {
223 #ifdef HAVE_STRCASECMP
224 if (!strncasecmp(thispos, "</shibmlpifnot>", 15))
226 if (!strnicmp(thispos, "</shibmlpifnot>", 15))
229 // We found our terminator. Process the string in between.
231 run(is.substr(frontpos-line, thispos-frontpos),props,&segment);
234 lastpos = thispos + 15; // strlen("</shibmlpifnot>")
239 lastpos = thispos + 2;
247 lastpos = thispos + 1;
250 *output += is.substr(lastpos-line);
252 return output->c_str();
255 const char* ShibMLP::run(istream& is, const IPropertySet* props, std::string* output)
257 static string eol = "\r\n";
260 while (getline(is, line))
263 return run(str,props,output);
266 void ShibMLP::insert(SAMLException& e)
268 insert("errorType", e.classname());
269 if (typeid(e)==typeid(ContentTypeException))
270 insert("errorText", "A problem was detected with your identity provider's software configuration.");
272 insert("errorText", e.getMessage() ? e.getMessage() : "No Message");
273 if (e.getProperty("errorURL"))
274 insert("originErrorURL", e.getProperty("errorURL"));
275 if (e.getProperty("contactName"))
276 insert("originContactName", e.getProperty("contactName"));
277 const char* email=e.getProperty("contactEmail");
279 if (!strncmp(email,"mailto:",7) && strlen(email)>7)
280 insert("originContactEmail", email+7);
282 insert("originContactEmail", email);