VS10 solution files, convert from NULL macro to nullptr.
[shibboleth/sp.git] / shibsp / handler / impl / SessionHandler.cpp
1 /*
2  *  Copyright 2001-2010 Internet2
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /**
18  * SessionHandler.cpp
19  *
20  * Handler for dumping information about an active session.
21  */
22
23 #include "internal.h"
24 #include "Application.h"
25 #include "exceptions.h"
26 #include "ServiceProvider.h"
27 #include "SessionCache.h"
28 #include "SPRequest.h"
29 #include "attribute/Attribute.h"
30 #include "handler/AbstractHandler.h"
31
32 #include <ctime>
33
34 using namespace shibsp;
35 using namespace xmltooling;
36 using namespace std;
37
38 namespace shibsp {
39
40 #if defined (_MSC_VER)
41     #pragma warning( push )
42     #pragma warning( disable : 4250 )
43 #endif
44
45     class SHIBSP_DLLLOCAL Blocker : public DOMNodeFilter
46     {
47     public:
48 #ifdef SHIBSP_XERCESC_SHORT_ACCEPTNODE
49         short
50 #else
51         FilterAction
52 #endif
53         acceptNode(const DOMNode* node) const {
54             return FILTER_REJECT;
55         }
56     };
57
58     static SHIBSP_DLLLOCAL Blocker g_Blocker;
59
60     class SHIBSP_API SessionHandler : public AbstractHandler
61     {
62     public:
63         SessionHandler(const DOMElement* e, const char* appId);
64         virtual ~SessionHandler() {}
65
66         pair<bool,long> run(SPRequest& request, bool isHandler=true) const;
67
68     private:
69         bool m_values;
70         set<string> m_acl;
71     };
72
73 #if defined (_MSC_VER)
74     #pragma warning( pop )
75 #endif
76
77     Handler* SHIBSP_DLLLOCAL SessionHandlerFactory(const pair<const DOMElement*,const char*>& p)
78     {
79         return new SessionHandler(p.first, p.second);
80     }
81
82 };
83
84 SessionHandler::SessionHandler(const DOMElement* e, const char* appId)
85     : AbstractHandler(e, Category::getInstance(SHIBSP_LOGCAT".SessionHandler"), &g_Blocker), m_values(false)
86 {
87     pair<bool,const char*> acl = getString("acl");
88     if (acl.first) {
89         string aclbuf=acl.second;
90         int j = 0;
91         for (unsigned int i=0;  i < aclbuf.length();  i++) {
92             if (aclbuf.at(i)==' ') {
93                 m_acl.insert(aclbuf.substr(j, i-j));
94                 j = i+1;
95             }
96         }
97         m_acl.insert(aclbuf.substr(j, aclbuf.length()-j));
98     }
99
100     pair<bool,bool> flag = getBool("showAttributeValues");
101     if (flag.first)
102         m_values = flag.second;
103 }
104
105 pair<bool,long> SessionHandler::run(SPRequest& request, bool isHandler) const
106 {
107     if (!m_acl.empty() && m_acl.count(request.getRemoteAddr()) == 0) {
108         m_log.error("session handler request blocked from invalid address (%s)", request.getRemoteAddr().c_str());
109         istringstream msg("Session Handler Blocked");
110         return make_pair(true,request.sendResponse(msg, HTTPResponse::XMLTOOLING_HTTP_STATUS_FORBIDDEN));
111     }
112
113     stringstream s;
114     s << "<html><head><title>Session Summary</title></head><body><pre>" << endl;
115
116     Session* session = nullptr;
117     try {
118         session = request.getSession();
119         if (!session) {
120             s << "A valid session was not found.</pre></body></html>" << endl;
121             request.setContentType("text/html");
122             request.setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT");
123             request.setResponseHeader("Cache-Control","private,no-store,no-cache");
124             return make_pair(true, request.sendResponse(s));
125         }
126     }
127     catch (exception& ex) {
128         s << "Exception while retrieving active session:" << endl
129             << '\t' << ex.what() << "</pre></body></html>" << endl;
130         request.setContentType("text/html");
131         request.setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT");
132         request.setResponseHeader("Cache-Control","private,no-store,no-cache");
133         return make_pair(true, request.sendResponse(s));
134     }
135
136     s << "<u>Miscellaneous</u>" << endl;
137
138     s << "<strong>Client Address:</strong> " << (session->getClientAddress() ? session->getClientAddress() : "(none)") << endl;
139     s << "<strong>Identity Provider:</strong> " << (session->getEntityID() ? session->getEntityID() : "(none)") << endl;
140     s << "<strong>SSO Protocol:</strong> " << (session->getProtocol() ? session->getProtocol() : "(none)") << endl;
141     s << "<strong>Authentication Time:</strong> " << (session->getAuthnInstant() ? session->getAuthnInstant() : "(none)") << endl;
142     s << "<strong>Authentication Context Class:</strong> " << (session->getAuthnContextClassRef() ? session->getAuthnContextClassRef() : "(none)") << endl;
143     s << "<strong>Authentication Context Decl:</strong> " << (session->getAuthnContextDeclRef() ? session->getAuthnContextDeclRef() : "(none)") << endl;
144     s << "<strong>Session Expiration (barring inactivity):</strong> ";
145     if (session->getExpiration())
146         s << ((session->getExpiration() - time(nullptr)) / 60) << " minute(s)" << endl;
147     else
148         s << "Infinite" << endl;
149
150     s << endl << "<u>Attributes</u>" << endl;
151
152     string key;
153     vector<string>::size_type count=0;
154     const multimap<string,const Attribute*>& attributes = session->getIndexedAttributes();
155     for (multimap<string,const Attribute*>::const_iterator a = attributes.begin(); a != attributes.end(); ++a) {
156         if (a->first != key) {
157             if (a != attributes.begin()) {
158                 if (m_values)
159                     s << endl;
160                 else {
161                     s << count << " value(s)" << endl;
162                     count = 0;
163                 }
164             }
165             s << "<strong>" << a->first << "</strong>: ";
166         }
167
168         if (m_values) {
169             const vector<string>& vals = a->second->getSerializedValues();
170             for (vector<string>::const_iterator v = vals.begin(); v!=vals.end(); ++v) {
171                 if (v != vals.begin() || a->first == key)
172                     s << ';';
173                 string::size_type pos = v->find_first_of(';',string::size_type(0));
174                 if (pos!=string::npos) {
175                     string value(*v);
176                     for (; pos != string::npos; pos = value.find_first_of(';',pos)) {
177                         value.insert(pos, "\\");
178                         pos += 2;
179                     }
180                     s << value;
181                 }
182                 else {
183                     s << *v;
184                 }
185             }
186         }
187         else {
188             count += a->second->getSerializedValues().size();
189         }
190     }
191
192     if (!m_values && !attributes.empty())
193         s << count << " value(s)" << endl;
194
195     s << "</pre></body></html>";
196     request.setContentType("text/html; charset=UTF-8");
197     request.setResponseHeader("Expires","01-Jan-1997 12:00:00 GMT");
198     request.setResponseHeader("Cache-Control","private,no-store,no-cache");
199     return make_pair(true, request.sendResponse(s));
200 }