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>
29 #include <xercesc/util/XercesDefs.hpp>
30 #include <log4cpp/Category.hh>
33 using namespace log4cpp;
35 using namespace shibboleth;
36 using namespace shibtarget;
38 class shibtarget::ShibMLPPriv {
42 log4cpp::Category *log;
45 ShibMLPPriv::ShibMLPPriv() : log(&(log4cpp::Category::getInstance("shibtarget.ShibMLP"))) {}
47 static void trimspace (string& s)
49 int end = s.size() - 1, start = 0;
51 // Trim stuff on right.
52 while (end > 0 && !isgraph(s[end])) end--;
54 // Trim stuff on left.
55 while (start < end && !isgraph(s[start])) start++;
58 s = s.substr(start, end - start + 1);
63 m_priv = new ShibMLPPriv ();
71 const char* ShibMLP::run(const string& is, const IPropertySet* props, std::string* output)
74 time_t now = time(NULL);
75 insert("now", ctime(&now));
79 const char* line = is.c_str();
80 const char* lastpos = line;
83 m_priv->log->debug("Processing string");
86 // Search for SHIBMLP tags. These are of the form:
88 // <shibmlpif key> stuff </shibmlpif>
89 // <shibmlpifnot key> stuff </shibmlpifnot>
90 // Note that there MUST be white-space after "<shibmlp" but
91 // there does not need to be white space between the key and
94 while ((thispos = strchr(lastpos, '<')) != NULL) {
95 // save the string up to this token
96 *output += is.substr(lastpos-line, thispos-lastpos);
98 // Make sure this token matches our tokens.
99 #ifdef HAVE_STRCASECMP
100 if (!strncasecmp(thispos, "<shibmlp ", 9))
102 if (!strnicmp(thispos, "<shibmlp ", 9))
105 // Save this position off.
106 lastpos = thispos + 9; // strlen("<shibmlp ")
108 // search for the end-tag
109 if ((thispos = strstr(lastpos, "/>")) != NULL) {
110 string key = is.substr(lastpos-line, thispos-lastpos);
113 map<string,string>::const_iterator i=m_map.find(key);
114 if (i != m_map.end()) {
115 *output += i->second;
118 pair<bool,const char*> p=props ? props->getString(key.c_str()) : pair<bool,const char*>(false,NULL);
123 static const char* s1 = "<!-- Unknown SHIBMLP key: ";
124 static const char* s2 = "/>";
129 lastpos = thispos + 2; // strlen("/>")
132 #ifdef HAVE_STRCASECMP
133 else if (!strncasecmp(thispos, "<shibmlpif ", 11))
135 else if (!strnicmp(thispos, "<shibmlpif ", 11))
138 // Save this position off.
139 lastpos = thispos + 11; // strlen("<shibmlpif ")
141 // search for the end of this tag
142 if ((thispos = strchr(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() && !i->second.empty()) {
151 pair<bool,const char*> p=props ? props->getString(key.c_str()) : pair<bool,const char*>(false,NULL);
156 lastpos = thispos + 1; // strlen(">")
158 // Search for the closing tag.
159 const char* frontpos=lastpos;
160 while ((thispos = strstr(lastpos, "</")) != NULL) {
161 #ifdef HAVE_STRCASECMP
162 if (!strncasecmp(thispos, "</shibmlpif>", 12))
164 if (!strnicmp(thispos, "</shibmlpif>", 12))
167 // We found our terminator. Process the string in between.
169 run(is.substr(frontpos-line, thispos-frontpos),props,&segment);
172 lastpos = thispos + 12; // strlen("</shibmlpif>")
177 lastpos = thispos + 2;
182 #ifdef HAVE_STRCASECMP
183 else if (!strncasecmp(thispos, "<shibmlpifnot ", 14))
185 else if (!strnicmp(thispos, "<shibmlpifnot ", 14))
188 // Save this position off.
189 lastpos = thispos + 14; // strlen("<shibmlpifnot ")
191 // search for the end of this tag
192 if ((thispos = strchr(lastpos, '>')) != NULL) {
193 string key = is.substr(lastpos-line, thispos-lastpos);
196 map<string,string>::const_iterator i=m_map.find(key);
197 if (i != m_map.end() && !i->second.empty()) {
201 pair<bool,const char*> p=props ? props->getString(key.c_str()) : pair<bool,const char*>(false,NULL);
206 lastpos = thispos + 1; // strlen(">")
208 // Search for the closing tag.
209 const char* frontpos=lastpos;
210 while ((thispos = strstr(lastpos, "</")) != NULL) {
211 #ifdef HAVE_STRCASECMP
212 if (!strncasecmp(thispos, "</shibmlpifnot>", 15))
214 if (!strnicmp(thispos, "</shibmlpifnot>", 15))
217 // We found our terminator. Process the string in between.
219 run(is.substr(frontpos-line, thispos-frontpos),props,&segment);
222 lastpos = thispos + 15; // strlen("</shibmlpifnot>")
227 lastpos = thispos + 2;
235 lastpos = thispos + 1;
238 *output += is.substr(lastpos-line);
240 return output->c_str();
243 const char* ShibMLP::run(istream& is, const IPropertySet* props, std::string* output)
245 static string eol = "\r\n";
248 m_priv->log->debug("processing stream");
250 while (getline(is, line))
253 return run(str,props,output);
256 void ShibMLP::insert(SAMLException& e)
258 insert("errorType", e.classname());
259 if (typeid(e)==typeid(ContentTypeException))
260 insert("errorText", "A problem was detected with your identity provider's software configuration.");
262 insert("errorText", e.getMessage() ? e.getMessage() : "No Message");
263 if (e.getProperty("errorURL"))
264 insert("originErrorURL", e.getProperty("errorURL"));
265 if (e.getProperty("contactName"))
266 insert("originContactName", e.getProperty("contactName"));
267 const char* email=e.getProperty("contactEmail");
269 if (!strncmp(email,"mailto:",7) && strlen(email)>7)
270 insert("originContactEmail", email+7);
272 insert("originContactEmail", email);
276 void ShibMLP::insert (const std::string& key, const std::string& value)
278 m_priv->log->debug("inserting %s -> %s", key.c_str(), value.c_str());