Extended MLP to support arbitrary tag subbing from XML config
[shibboleth/cpp-sp.git] / shib-target / shib-mlp.cpp
1 /*
2  * The Shibboleth License, Version 1.
3  * Copyright (c) 2002
4  * University Corporation for Advanced Internet Development, Inc.
5  * All rights reserved
6  *
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * Redistributions of source code must retain the above copyright notice, this
12  * list of conditions and the following disclaimer.
13  *
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.
22  *
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
28  *
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.
33  *
34  *
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.
48  */
49
50 /*
51  * shib-mlp.cpp -- The ShibTarget Markup Language processor
52  *
53  * Created by:  Derek Atkins <derek@ihtfp.com>
54  *
55  * $Id$
56  */
57
58 #include "internal.h"
59
60 #include <sstream>
61 #include <ctype.h>
62 #include <xercesc/util/XercesDefs.hpp>
63 #include <log4cpp/Category.hh>
64
65 using namespace std;
66 using namespace log4cpp;
67 using namespace saml;
68 using namespace shibboleth;
69 using namespace shibtarget;
70
71 class shibtarget::ShibMLPPriv {
72 public:
73   ShibMLPPriv();
74   ~ShibMLPPriv() {}
75   log4cpp::Category *log;
76 };  
77
78 ShibMLPPriv::ShibMLPPriv() : log(&(log4cpp::Category::getInstance("shibtarget.ShibMLP"))) {}
79
80 static void trimspace (string& s)
81 {
82   int end = s.size() - 1, start = 0;
83
84   // Trim stuff on right.
85   while (end > 0 && !isgraph(s[end])) end--;
86
87   // Trim stuff on left.
88   while (start < end && !isgraph(s[start])) start++;
89
90   // Modify the string.
91   s = s.substr(start, end - start + 1);
92 }
93
94 ShibMLP::ShibMLP()
95 {
96   m_priv = new ShibMLPPriv ();
97
98   // Create a timestamp
99   time_t now = time(NULL);
100   insert("now", ctime(&now));
101 }
102
103 ShibMLP::~ShibMLP ()
104 {
105   delete m_priv;
106 }
107
108 const char* ShibMLP::run(const string& is, const IPropertySet* props)
109 {
110   const char* line = is.c_str();
111   const char* lastpos = line;
112   const char* thispos;
113
114   m_generated.erase();
115   m_priv->log->info("Processing string");
116
117   //
118   // Search for SHIBMLP tags.  These are of the form:
119   //    <shibmlp key />
120   // Note that there MUST be white-space after "<shibmlp" but
121   // there does not need to be white space between the key and
122   // the close-tag.
123   //
124   while ((thispos = strstr(lastpos, "<")) != NULL) {
125     // save the string up to this token
126     m_generated += is.substr(lastpos-line, thispos-lastpos);
127
128     // Make sure this token matches our token.
129     if (strnicmp (thispos, "<shibmlp ", 9)) {
130       m_generated += "<";
131       lastpos = thispos + 1;
132       continue;
133     }
134
135     // Save this position off.
136     lastpos = thispos + 9;      // strlen("<shibmlp ")
137
138     // search for the end-tag
139     if ((thispos = strstr(lastpos, "/>")) != NULL) {
140       string key = is.substr(lastpos-line, thispos-lastpos);
141       trimspace(key);
142
143       m_priv->log->debug("found key: \"%s\"", key.c_str());
144
145       map<string,string>::const_iterator i=m_map.find(key);
146       if (i != m_map.end()) {
147         m_generated += i->second;
148         m_priv->log->debug("key maps to \"%s\"", i->second.c_str());
149       }
150       else {
151         pair<bool,const char*> p=props ? props->getString(key.c_str()) : pair<bool,const char*>(false,NULL);
152         if (p.first) {
153             m_generated += p.second;
154             m_priv->log->debug("property maps to \"%s\"", p.second);
155         }
156         else {
157             static string s1 = "<!-- Unknown SHIBMLP key: ";
158             static string s2 = "/>";
159             m_generated += s1 + key + s2;
160             m_priv->log->debug("key unknown");
161         }
162       }
163
164       lastpos = thispos + 2;    // strlen("/>")
165     }
166   }
167   m_generated += is.substr(lastpos-line);
168
169   return m_generated.c_str();
170 }
171
172 const char* ShibMLP::run(istream& is, const IPropertySet* props)
173 {
174   static string eol = "\r\n";
175   string str, line;
176
177   m_priv->log->info("processing stream");
178
179   while (getline(is, line))
180     str += line + eol;
181
182   return run(str,props);
183 }
184
185 void ShibMLP::insert (RPCError& e)
186 {
187     insert ("errorType", e.getType() ? e.getType() : "Unknown Type");
188     insert ("errorText", e.getText() ? e.getText() : "No Message");
189     insert ("errorDesc", e.getDesc() ? e.getDesc() : "No Description");
190     insert ("originErrorURL", e.getErrorURL() ? e.getErrorURL() : "No Error URL");
191     insert ("originContactName", e.getContactName() ? e.getContactName() : "No Contact Name");
192     insert ("originContactEmail", e.getContactEmail() ? e.getContactEmail() : "No Contact Email");
193 }
194
195 void ShibMLP::insert (const std::string& key, const std::string& value)
196 {
197   m_priv->log->debug("inserting %s -> %s", key.c_str(), value.c_str());
198   m_map[key] = value;
199 }