Reworked profile handlers outside of core library.
[shibboleth/cpp-sp.git] / shib-target / shib-target.h
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-target.h -- top-level header file for the SHIB Common Target Library
52  *
53  * Created by:  Derek Atkins <derek@ihtfp.com>
54  *
55  * $Id$
56  */
57
58 #ifndef SHIB_TARGET_H
59 #define SHIB_TARGET_H
60
61 #include <saml/saml.h>
62 #include <shib/shib.h>
63 #include <shib/shib-threads.h>
64
65 #ifdef WIN32
66 # ifndef SHIBTARGET_EXPORTS
67 #  define SHIBTARGET_EXPORTS __declspec(dllimport)
68 # endif
69 # define SHIB_SCHEMAS "/opt/shibboleth/share/xml/shibboleth"
70 # define SHIB_CONFIG "/opt/shibboleth/etc/shibboleth/shibboleth.xml"
71 # include <winsock.h>
72 #else
73 # include <shib-target/shib-paths.h>
74 # define SHIBTARGET_EXPORTS
75 #endif
76
77
78 namespace shibtarget {
79   
80     DECLARE_SAML_EXCEPTION(SHIBTARGET_EXPORTS,ListenerException,SAMLException);
81     DECLARE_SAML_EXCEPTION(SHIBTARGET_EXPORTS,ConfigurationException,SAMLException);
82
83     enum ShibProfile {
84       PROFILE_UNSPECIFIED = 0,
85       SAML10_POST = 1,
86       SAML10_ARTIFACT = 2,
87       SAML11_POST = 4,
88       SAML11_ARTIFACT = 8,
89       SAML20_SSO = 16
90     };
91
92     // Abstract APIs for access to configuration information
93     
94     struct SHIBTARGET_EXPORTS IPropertySet
95     {
96         virtual std::pair<bool,bool> getBool(const char* name, const char* ns=NULL) const=0;
97         virtual std::pair<bool,const char*> getString(const char* name, const char* ns=NULL) const=0;
98         virtual std::pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const=0;
99         virtual std::pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const=0;
100         virtual std::pair<bool,int> getInt(const char* name, const char* ns=NULL) const=0;
101         virtual const IPropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:target:config:1.0") const=0;
102         virtual const DOMElement* getElement() const=0;
103         virtual ~IPropertySet() {}
104     };
105
106     struct SHIBTARGET_EXPORTS IApplication : public virtual IPropertySet
107     {
108         virtual const char* getId() const=0;
109         virtual const char* getHash() const=0;
110         
111         virtual saml::Iterator<saml::SAMLAttributeDesignator*> getAttributeDesignators() const=0;
112         virtual saml::Iterator<shibboleth::IAAP*> getAAPProviders() const=0;
113         virtual saml::Iterator<shibboleth::IMetadata*> getMetadataProviders() const=0;
114         virtual saml::Iterator<shibboleth::ITrust*> getTrustProviders() const=0;
115         virtual saml::Iterator<const XMLCh*> getAudiences() const=0;
116         virtual const IPropertySet* getCredentialUse(const shibboleth::IEntityDescriptor* provider) const=0;
117
118         // caller is borrowing object, must use within scope of config lock
119         virtual const saml::SAMLBrowserProfile* getBrowserProfile() const=0;
120         virtual const saml::SAMLBinding* getBinding(const XMLCh* binding) const=0;
121
122         // caller is given ownership of object, must use and delete within scope of config lock
123         virtual saml::SAMLBrowserProfile::ArtifactMapper* getArtifactMapper() const=0;
124
125         // Used to locate a default or designated session initiator for automatic sessions
126         virtual const IPropertySet* getDefaultSessionInitiator() const=0;
127         virtual const IPropertySet* getSessionInitiatorById(const char* id) const=0;
128         
129         // Used by session initiators to get endpoint to forward to IdP/WAYF
130         virtual const IPropertySet* getDefaultAssertionConsumerService() const=0;
131         virtual const IPropertySet* getAssertionConsumerServiceByIndex(unsigned short index) const=0;
132         
133         // Used by dispatcher to locate the handler configuration for a Shibboleth request
134         virtual const IPropertySet* getHandlerConfig(const char* path) const=0;
135
136         virtual ~IApplication() {}
137     };
138
139     struct SHIBTARGET_EXPORTS ISessionCacheEntry : public virtual saml::ILockable
140     {
141         virtual bool isValid(time_t lifetime, time_t timeout) const=0;
142         virtual const char* getClientAddress() const=0;
143         virtual ShibProfile getProfile() const=0;
144         virtual const char* getProviderId() const=0;
145         virtual const saml::SAMLAuthenticationStatement* getAuthnStatement() const=0;
146         struct SHIBTARGET_EXPORTS CachedResponse {
147             CachedResponse(const saml::SAMLResponse* unfiltered, const saml::SAMLResponse* filtered) {
148                 this->unfiltered=unfiltered;
149                 this->filtered=filtered;
150             }
151             bool empty() {return unfiltered==NULL;}
152             const saml::SAMLResponse* unfiltered;
153             const saml::SAMLResponse* filtered;
154         };
155         virtual CachedResponse getResponse()=0;
156         virtual ~ISessionCacheEntry() {}
157     };
158
159     struct SHIBTARGET_EXPORTS ISessionCache : public virtual saml::IPlugIn
160     {
161         virtual void thread_init()=0;
162         virtual void thread_end()=0;
163         virtual std::string generateKey() const=0;
164         virtual void insert(
165             const char* key,
166             const IApplication* application,
167             const char* client_addr,
168             ShibProfile profile,
169             const char* providerId,
170             saml::SAMLAuthenticationStatement* s,
171             saml::SAMLResponse* r=NULL,
172             const shibboleth::IRoleDescriptor* source=NULL,
173             time_t created=0,
174             time_t accessed=0
175             )=0;
176         virtual ISessionCacheEntry* find(const char* key, const IApplication* application)=0;
177         virtual void remove(const char* key)=0;
178         virtual ~ISessionCache() {}
179     };
180
181     struct SHIBTARGET_EXPORTS IListener : public virtual saml::IPlugIn
182     {
183         // The socket APIs should really be somewhere else, but compatibility
184         // with older configuration files dictates that the Listener handles
185         // both client and server socket handling. We can fix this for 2.0...?
186 #ifdef WIN32
187         typedef SOCKET ShibSocket;
188 #else
189         typedef int ShibSocket;
190 #endif
191         virtual bool create(ShibSocket& s) const=0;
192         virtual bool bind(ShibSocket& s, bool force=false) const=0;
193         virtual bool connect(ShibSocket& s) const=0;
194         virtual bool close(ShibSocket& s) const=0;
195         virtual bool accept(ShibSocket& listener, ShibSocket& s) const=0;
196
197         // The "real" Listener API abstracts the primitive operations that make up
198         // the meat of the SP's job. Right now, that's session create/read/delete.
199         virtual void sessionNew(
200             const IApplication* application,
201             int supported_profiles,
202             const char* recipient,
203             const char* packet,
204             const char* ip,
205             std::string& target,
206             std::string& cookie,
207             std::string& provider_id
208             ) const=0;
209     
210         virtual void sessionGet(
211             const IApplication* application,
212             const char* cookie,
213             const char* ip,
214             ISessionCacheEntry** pentry
215             ) const=0;
216     
217         virtual void sessionEnd(
218             const IApplication* application,
219             const char* cookie
220             ) const=0;
221             
222         virtual void ping(int& i) const=0;
223         
224         virtual ~IListener() {}
225     };
226
227     class SHIBTARGET_EXPORTS ShibTarget;
228
229     struct SHIBTARGET_EXPORTS IAccessControl : public virtual saml::ILockable, public virtual saml::IPlugIn
230     {
231         virtual bool authorized(ShibTarget* st, ISessionCacheEntry* entry) const=0;
232         virtual ~IAccessControl() {}
233     };
234
235     struct SHIBTARGET_EXPORTS IRequestMapper : public virtual saml::ILockable, public virtual saml::IPlugIn
236     {
237         typedef std::pair<const IPropertySet*,IAccessControl*> Settings;
238         virtual Settings getSettings(ShibTarget* st) const=0;
239         virtual ~IRequestMapper() {}
240     };
241     
242     struct SHIBTARGET_EXPORTS IHandler : public virtual saml::IPlugIn
243     {
244         virtual std::pair<bool,void*> run(ShibTarget* st, const IPropertySet* config, bool isHandler=true)=0;
245         virtual ~IHandler() {}
246     };
247     
248     struct SHIBTARGET_EXPORTS IConfig : public virtual saml::ILockable, public virtual IPropertySet, public virtual saml::IPlugIn
249     {
250         virtual const IListener* getListener() const=0;
251         virtual ISessionCache* getSessionCache() const=0;
252         virtual saml::IReplayCache* getReplayCache() const=0;
253         virtual IRequestMapper* getRequestMapper() const=0;
254         virtual const IApplication* getApplication(const char* applicationId) const=0;
255         virtual saml::Iterator<shibboleth::ICredentials*> getCredentialsProviders() const=0;
256         virtual ~IConfig() {}
257     };
258
259     class SHIBTARGET_EXPORTS ShibTargetConfig
260     {
261     public:
262         ShibTargetConfig() : m_ini(NULL), m_features(0) {}
263         virtual ~ShibTargetConfig() {}
264         
265         virtual bool init(const char* schemadir) = 0;
266         virtual bool load(const char* config) = 0;
267         virtual void shutdown() = 0;
268
269         enum components_t {
270             Listener = 1,
271             Caching = 2,
272             Metadata = 4,
273             Trust = 8,
274             Credentials = 16,
275             AAP = 32,
276             RequestMapper = 64,
277             GlobalExtensions = 128,
278             LocalExtensions = 256,
279             Logging = 512
280         };
281         void setFeatures(long enabled) {m_features = enabled;}
282         bool isEnabled(components_t feature) {return (m_features & feature)>0;}
283         virtual IConfig* getINI() const {return m_ini;}
284
285         static ShibTargetConfig& getConfig();
286
287     protected:
288         IConfig* m_ini;
289         
290     private:
291         unsigned long m_features;
292     };
293
294   class ShibTargetPriv;
295   class SHIBTARGET_EXPORTS ShibTarget {
296   public:
297     ShibTarget(const IApplication *app);
298     virtual ~ShibTarget(void);
299
300     // These are defined here so the subclass does not need to specifically
301     // depend on log4cpp.  We could use log4cpp::Priority::PriorityLevel
302     // but this is just as easy, IMHO.  It's just a case statement in the
303     // implementation to handle the event level.
304     enum ShibLogLevel {
305       LogLevelDebug,
306       LogLevelInfo,
307       LogLevelWarn,
308       LogLevelError
309     };
310
311     //
312     // Note: subclasses MUST implement ALL of these virtual methods
313     //
314     
315     // Send a message to the Webserver log
316     virtual void log(ShibLogLevel level, const std::string &msg)=0;
317
318     void log(ShibLogLevel level, const char *msg) {
319       std::string s = msg;
320       log(level, s);
321     }
322
323     // Get/Set a cookie for this request
324     virtual std::string getCookies() const=0;
325     virtual void setCookie(const std::string &name, const std::string &value)=0;
326     virtual const char* getCookie(const std::string& name) const;
327     void setCookie(const char *name, const char *value) {
328       std::string ns = name;
329       std::string vs = value;
330       setCookie(ns, vs);
331     }
332     void setCookie(const char *name, const std::string &value) {
333       std::string ns = name;
334       setCookie(ns, value);
335     }
336
337
338     // Get the request's GET arguments or POST data from the server
339     virtual std::string getArgs(void)=0;
340     virtual std::string getPostData(void)=0;
341
342     // Clear a header, set a header
343     // These APIs are used for exporting the Assertions into the
344     // Headers.  It will clear some well-known headers first to make
345     // sure none remain.  Then it will process the set of assertions
346     // and export them via setHeader().
347     virtual void clearHeader(const std::string &name)=0;
348     virtual void setHeader(const std::string &name, const std::string &value)=0;
349     virtual std::string getHeader(const std::string &name)=0;
350     virtual void setRemoteUser(const std::string &user)=0;
351     virtual std::string getRemoteUser(void)=0;
352
353     void clearHeader(const char *n) {
354       std::string s = n;
355       clearHeader(s);
356     }
357     void setHeader(const char *n, const char *v) {
358       std::string ns = n;
359       std::string vs = v;
360       setHeader(ns, vs);
361     }
362     void setHeader(const std::string &n, const char *v) {
363       std::string vs = v;
364       setHeader(n, vs);
365     }
366     void setHeader(const char *n, const std::string &v) {
367       std::string ns = n;
368       setHeader(ns, v);
369     }
370     std::string getHeader(const char *n) {
371       std::string s = n;
372       return getHeader(s);
373     }
374     void setRemoteUser(const char *n) {
375       std::string s = n;
376       setRemoteUser(s);
377     }
378
379     // We're done.  Finish up.  Send specific result content or a redirect.
380     // If there are no headers supplied assume the content-type is text/html
381     typedef std::pair<std::string, std::string> header_t;
382     virtual void* sendPage(
383         const std::string& msg,
384         int code = 200,
385         const std::string& content_type = "text/html",
386         const saml::Iterator<header_t>& headers = EMPTY(header_t)
387         )=0;
388     void* sendPage(const char *msg) {
389       std::string m = msg;
390       return sendPage(m);
391     }
392     virtual void* sendRedirect(const std::string& url)=0;
393     
394     // These next two APIs are used to obtain the module-specific "OK"
395     // and "Decline" results.  OK means "we believe that this request
396     // should be accepted".  Declined means "we believe that this is
397     // not a shibbolized request so we have no comment".
398
399     virtual void* returnDecline(void);
400     virtual void* returnOK(void);
401
402     //
403     // Note:  Subclasses need not implement anything below this line
404     //
405
406     // These functions implement the server-agnostic shibboleth engine
407     // The web server modules implement a subclass and then call into 
408     // these methods once they instantiate their request object.
409     // 
410     // Return value:
411     //   these APIs will always return the result of sendPage(), sendRedirect(),
412     //   returnDecline(), or returnOK() in the void* portion of the return code.
413     //   Exactly what those values are is module- (subclass-) implementation
414     //   specific.  The 'bool' part of the return value declares whether the
415     //   void* is valid or not.  If the bool is true then the void* is valid.
416     //   If the bool is false then the API did not call any callback, the void*
417     //   is not valid, and the caller should continue processing (the API Call
418     //   finished successfully).
419     //
420     //   The handleProfile argument declares whether doCheckAuthN() should
421     //   automatically call doHandlePOST() when it encounters a request for
422     //   the ShireURL;  if false it will call returnOK() instead.
423     //
424     std::pair<bool,void*> doCheckAuthN(bool handler = false);
425     std::pair<bool,void*> doHandler();
426     std::pair<bool,void*> doCheckAuthZ();
427     std::pair<bool,void*> doExportAssertions();
428
429     // Basic request access in case any plugins need the info
430     virtual const IConfig* getConfig() const;
431     virtual const IApplication* getApplication() const;
432     const char* getRequestMethod() const {return m_method.c_str();}
433     const char* getProtocol() const {return m_protocol.c_str();}
434     const char* getHostname() const {return m_hostname.c_str();}
435     int getPort() const {return m_port;}
436     const char* getRequestURI() const {return m_uri.c_str();}
437     const char* getContentType() const {return m_content_type.c_str();}
438     const char* getRemoteAddr() const {return m_remote_addr.c_str();}
439     const char* getRequestURL() const {return m_url.c_str();}
440     
441     // Advanced methods useful to profile handlers implemented outside core
442     
443     // Get per-application session and state cookie name and properties
444     virtual std::pair<std::string,const char*> getCookieNameProps(const char* prefix) const;
445     
446     // Determine the effective handler URL based on the resource URL
447     virtual std::string getHandlerURL(const char* resource) const;
448
449   protected:
450     ShibTarget();
451
452     // Internal APIs
453
454     // Initialize the request from the parsed URL
455     // protocol == http, https, etc
456     // hostname == server name
457     // port == server port
458     // uri == resource path
459     // method == GET, POST, etc.
460     void init(
461         const char* protocol,
462         const char* hostname,
463         int port,
464         const char* uri,
465         const char* content_type,
466         const char* remote_addr,
467         const char* method
468         );
469
470     std::string m_url, m_method, m_protocol, m_hostname, m_uri, m_content_type, m_remote_addr;
471     int m_port;
472
473   private:
474     mutable ShibTargetPriv* m_priv;
475     friend class ShibTargetPriv;
476   };
477
478     struct SHIBTARGET_EXPORTS XML
479     {
480         static const XMLCh SHIBTARGET_NS[];
481         static const XMLCh SHIBTARGET_SCHEMA_ID[];
482         static const XMLCh SAML2ASSERT_NS[];
483         static const XMLCh SAML2ASSERT_SCHEMA_ID[];
484         static const XMLCh SAML2META_NS[];
485         static const XMLCh SAML2META_SCHEMA_ID[];
486         static const XMLCh XMLENC_NS[];
487         static const XMLCh XMLENC_SCHEMA_ID[];
488     
489         // Session cache implementations
490         static const char MemorySessionCacheType[];
491         static const char MySQLSessionCacheType[];
492         
493         // Replay cache implementations
494         static const char MySQLReplayCacheType[];
495         
496         // Request mapping/settings implementations
497         static const char XMLRequestMapType[];      // portable XML-based map
498         static const char NativeRequestMapType[];   // Native web server command override of XML-based map
499         static const char LegacyRequestMapType[];   // older designation of XML map, hijacked by web server
500         
501         // Access control implementations
502         static const char htAccessControlType[];    // Apache-specific .htaccess authz module
503         static const char XMLAccessControlType[];   // Proprietary but portable XML authz syntax
504
505         // Listener implementations
506         static const char TCPListenerType[];        // ONC RPC via TCP socket
507         static const char UnixListenerType[];       // ONC RPC via domain socker
508         static const char MemoryListenerType[];     // "faked" in-process marshalling
509     
510         struct SHIBTARGET_EXPORTS Literals
511         {
512             static const XMLCh AAPProvider[];
513             static const XMLCh AccessControl[];
514             static const XMLCh AccessControlProvider[];
515             static const XMLCh acl[];
516             static const XMLCh AND[];
517             static const XMLCh applicationId[];
518             static const XMLCh Application[];
519             static const XMLCh Applications[];
520             static const XMLCh AssertionConsumerService[];
521             static const XMLCh AttributeFactory[];
522             static const XMLCh config[];
523             static const XMLCh CredentialsProvider[];
524             static const XMLCh CredentialUse[];
525             static const XMLCh DiagnosticService[];
526             static const XMLCh echo[];
527             static const XMLCh Extensions[];
528             static const XMLCh fatal[];
529             static const XMLCh FederationProvider[];
530             static const XMLCh Global[];
531             static const XMLCh Host[];
532             static const XMLCh htaccess[];
533             static const XMLCh Implementation[];
534             static const XMLCh index[];
535             static const XMLCh isDefault[];
536             static const XMLCh Library[];
537             static const XMLCh Listener[];
538             static const XMLCh Local[];
539             static const XMLCh log[];
540             static const XMLCh logger[];
541             static const XMLCh MemorySessionCache[];
542             static const XMLCh MetadataProvider[];
543             static const XMLCh MySQLReplayCache[];
544             static const XMLCh MySQLSessionCache[];
545             static const XMLCh name[];
546             static const XMLCh Name[];
547             static const XMLCh NOT[];
548             static const XMLCh OR[];
549             static const XMLCh Path[];
550             static const XMLCh path[];
551             static const XMLCh RelyingParty[];
552             static const XMLCh ReplayCache[];
553             static const XMLCh RequestMap[];
554             static const XMLCh RequestMapProvider[];
555             static const XMLCh require[];
556             static const XMLCh Rule[];
557             static const XMLCh SessionCache[];
558             static const XMLCh SessionInitiator[];
559             static const XMLCh SHAR[];
560             static const XMLCh ShibbolethTargetConfig[];
561             static const XMLCh SHIRE[];
562             static const XMLCh Signing[];
563             static const XMLCh SingleLogoutService[];
564             static const XMLCh SPConfig[];
565             static const XMLCh TCPListener[];
566             static const XMLCh TLS[];
567             static const XMLCh TrustProvider[];
568             static const XMLCh type[];
569             static const XMLCh UnixListener[];
570         };
571     };
572 }
573
574 #endif /* SHIB_TARGET_H */