Some API refactoring
[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 #else
72 # include <shib-target/shib-paths.h>
73 # define SHIBTARGET_EXPORTS
74 #endif
75
76 #include <shib-target/shibrpc.h>
77
78 namespace shibtarget {
79   
80     DECLARE_SAML_EXCEPTION(SHIBTARGET_EXPORTS,ListenerException,SAMLException);
81     DECLARE_SAML_EXCEPTION(SHIBTARGET_EXPORTS,ConfigurationException,SAMLException);
82
83     // Abstract APIs for access to configuration information
84     
85     struct SHIBTARGET_EXPORTS IPropertySet
86     {
87         virtual std::pair<bool,bool> getBool(const char* name, const char* ns=NULL) const=0;
88         virtual std::pair<bool,const char*> getString(const char* name, const char* ns=NULL) const=0;
89         virtual std::pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const=0;
90         virtual std::pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const=0;
91         virtual std::pair<bool,int> getInt(const char* name, const char* ns=NULL) const=0;
92         virtual const IPropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:target:config:1.0") const=0;
93         virtual const DOMElement* getElement() const=0;
94         virtual ~IPropertySet() {}
95     };
96
97     struct SHIBTARGET_EXPORTS IListener : public virtual saml::IPlugIn
98     {
99 #ifdef WIN32
100         typedef SOCKET ShibSocket;
101 #else
102         typedef int ShibSocket;
103 #endif
104         virtual bool create(ShibSocket& s) const=0;
105         virtual bool bind(ShibSocket& s, bool force=false) const=0;
106         virtual bool connect(ShibSocket& s) const=0;
107         virtual bool close(ShibSocket& s) const=0;
108         virtual bool accept(ShibSocket& listener, ShibSocket& s) const=0;
109         virtual CLIENT* getClientHandle(ShibSocket& s, u_long program, u_long version) const=0;
110         virtual ~IListener() {}
111     };
112
113     class SHIBTARGET_EXPORTS ShibTarget;
114     struct SHIBTARGET_EXPORTS IAccessControl : public virtual saml::ILockable, public virtual saml::IPlugIn
115     {
116         virtual bool authorized(
117             const char* providerId,
118             const saml::SAMLAuthenticationStatement* authn,
119             const saml::SAMLResponse* attrs,
120             ShibTarget* st
121             ) const=0;
122         virtual ~IAccessControl() {}
123     };
124
125     struct SHIBTARGET_EXPORTS IRequestMapper : public virtual saml::ILockable, public virtual saml::IPlugIn
126     {
127         typedef std::pair<const IPropertySet*,IAccessControl*> Settings;
128         virtual Settings getSettingsFromURL(const char* url, ShibTarget* st) const=0;
129         virtual Settings getSettingsFromParsedURL(
130             const char* scheme, const char* hostname, unsigned int port, const char* path, ShibTarget* st
131             ) const=0;
132         virtual ~IRequestMapper() {}
133     };
134     
135     struct SHIBTARGET_EXPORTS IApplication : public virtual IPropertySet
136     {
137         virtual const char* getId() const=0;
138         virtual const char* getHash() const=0;
139         
140         virtual saml::Iterator<saml::SAMLAttributeDesignator*> getAttributeDesignators() const=0;
141         virtual saml::Iterator<shibboleth::IAAP*> getAAPProviders() const=0;
142         virtual saml::Iterator<shibboleth::IMetadata*> getMetadataProviders() const=0;
143         virtual saml::Iterator<shibboleth::ITrust*> getTrustProviders() const=0;
144         virtual saml::Iterator<const XMLCh*> getAudiences() const=0;
145         virtual const IPropertySet* getCredentialUse(const shibboleth::IEntityDescriptor* provider) const=0;
146
147         // caller is borrowing object, must use within scope of config lock
148         virtual const saml::SAMLBrowserProfile* getBrowserProfile() const=0;
149         virtual const saml::SAMLBinding* getBinding(const XMLCh* binding) const=0;
150
151         // caller is given ownership of object, must use and delete within scope of config lock
152         virtual saml::SAMLBrowserProfile::ArtifactMapper* getArtifactMapper() const=0;
153
154         // Used to locate a default or designated session initiator for automatic sessions
155         virtual const IPropertySet* getDefaultSessionInitiator() const=0;
156         virtual const IPropertySet* getSessionInitiatorById(const char* id) const=0;
157         
158         // Used by session initiators to get endpoint to forward to IdP/WAYF
159         virtual const IPropertySet* getDefaultAssertionConsumerService() const=0;
160         virtual const IPropertySet* getAssertionConsumerServiceByIndex(unsigned short index) const=0;
161         
162         // Used by dispatcher to locate a handler for a Shibboleth request
163         virtual const IPropertySet* getHandler(const char* path) const=0;
164
165         virtual ~IApplication() {}
166     };
167
168     struct SHIBTARGET_EXPORTS ISessionCacheEntry : public virtual saml::ILockable
169     {
170         virtual bool isValid(time_t lifetime, time_t timeout) const=0;
171         virtual const char* getClientAddress() const=0;
172         virtual ShibProfile getProfile() const=0;
173         virtual const char* getProviderId() const=0;
174         virtual const saml::SAMLAuthenticationStatement* getAuthnStatement() const=0;
175         struct SHIBTARGET_EXPORTS CachedResponse {
176             CachedResponse(const saml::SAMLResponse* unfiltered, const saml::SAMLResponse* filtered) {
177                 this->unfiltered=unfiltered;
178                 this->filtered=filtered;
179             }
180             bool empty() {return unfiltered==NULL;}
181             const saml::SAMLResponse* unfiltered;
182             const saml::SAMLResponse* filtered;
183         };
184         virtual CachedResponse getResponse()=0;
185         virtual ~ISessionCacheEntry() {}
186     };
187
188     struct SHIBTARGET_EXPORTS ISessionCache : public virtual saml::IPlugIn
189     {
190         virtual void thread_init()=0;
191         virtual void thread_end()=0;
192         virtual std::string generateKey() const=0;
193         virtual void insert(
194             const char* key,
195             const IApplication* application,
196             const char* client_addr,
197             ShibProfile profile,
198             const char* providerId,
199             saml::SAMLAuthenticationStatement* s,
200             saml::SAMLResponse* r=NULL,
201             const shibboleth::IRoleDescriptor* source=NULL,
202             time_t created=0,
203             time_t accessed=0
204             )=0;
205         virtual ISessionCacheEntry* find(const char* key, const IApplication* application)=0;
206         virtual void remove(const char* key)=0;
207         virtual ~ISessionCache() {}
208     };
209
210     struct SHIBTARGET_EXPORTS IConfig : public virtual saml::ILockable, public virtual IPropertySet, public virtual saml::IPlugIn
211     {
212         virtual const IListener* getListener() const=0;
213         virtual ISessionCache* getSessionCache() const=0;
214         virtual saml::IReplayCache* getReplayCache() const=0;
215         virtual IRequestMapper* getRequestMapper() const=0;
216         virtual const IApplication* getApplication(const char* applicationId) const=0;
217         virtual saml::Iterator<shibboleth::ICredentials*> getCredentialsProviders() const=0;
218         virtual ~IConfig() {}
219     };
220
221     class SHIBTARGET_EXPORTS ShibTargetConfig
222     {
223     public:
224         ShibTargetConfig() : m_ini(NULL), m_features(0) {}
225         virtual ~ShibTargetConfig() {}
226         
227         virtual bool init(const char* schemadir) = 0;
228         virtual bool load(const char* config) = 0;
229         virtual void shutdown() = 0;
230
231         enum components_t {
232             Listener = 1,
233             Caching = 2,
234             Metadata = 4,
235             Trust = 8,
236             Credentials = 16,
237             AAP = 32,
238             RequestMapper = 64,
239             GlobalExtensions = 128,
240             LocalExtensions = 256,
241             Logging = 512
242         };
243         void setFeatures(long enabled) {m_features = enabled;}
244         bool isEnabled(components_t feature) {return (m_features & feature)>0;}
245         virtual IConfig* getINI() const {return m_ini;}
246
247         static const XMLCh SHIBTARGET_NS[];
248         static ShibTargetConfig& getConfig();
249
250     protected:
251         IConfig* m_ini;
252         
253     private:
254         unsigned long m_features;
255     };
256
257   class HTAccessInfo {
258   public:
259     HTAccessInfo() {}
260     ~HTAccessInfo() {
261       for (int k = 0; k < elements.size(); k++)
262         delete elements[k];
263       elements.resize(0);
264     }
265
266     struct RequireLine {
267       bool use_line;
268       std::vector<std::string> tokens;
269     };
270     std::vector<RequireLine*> elements;
271     bool requireAll;
272   };
273
274   class HTGroupTable {
275   public:
276     virtual ~HTGroupTable() {}
277     virtual bool lookup(const char *entry) = 0;
278   protected:
279     HTGroupTable() {}
280   };
281
282   class ShibTargetPriv;
283   class SHIBTARGET_EXPORTS ShibTarget {
284   public:
285     ShibTarget(const IApplication *app);
286     virtual ~ShibTarget(void);
287
288     // These are defined here so the subclass does not need to specifically
289     // depend on log4cpp.  We could use log4cpp::Priority::PriorityLevel
290     // but this is just as easy, IMHO.  It's just a case statement in the
291     // implementation to handle the event level.
292     enum ShibLogLevel {
293       LogLevelDebug,
294       LogLevelInfo,
295       LogLevelWarn,
296       LogLevelError
297     };
298
299     //
300     // Note: subclasses MUST implement ALL of these virtual methods
301     //
302     
303     // Send a message to the Webserver log
304     virtual void log(ShibLogLevel level, const std::string &msg)=0;
305
306     void log(ShibLogLevel level, const char *msg) {
307       std::string s = msg;
308       log(level, s);
309     }
310
311     // Get/Set a cookie for this request
312     virtual std::string getCookies() const=0;
313     virtual void setCookie(const std::string &name, const std::string &value)=0;
314     void setCookie(const char *name, const char *value) {
315       std::string ns = name;
316       std::string vs = value;
317       setCookie(ns, vs);
318     }
319     void setCookie(const char *name, const std::string &value) {
320       std::string ns = name;
321       setCookie(ns, value);
322     }
323
324
325     // Get the request's GET arguments or POST data from the server
326     virtual std::string getArgs(void)=0;
327     virtual std::string getPostData(void)=0;
328
329     // Clear a header, set a header
330     // These APIs are used for exporting the Assertions into the
331     // Headers.  It will clear some well-known headers first to make
332     // sure none remain.  Then it will process the set of assertions
333     // and export them via setHeader().
334     virtual void clearHeader(const std::string &name)=0;
335     virtual void setHeader(const std::string &name, const std::string &value)=0;
336     virtual std::string getHeader(const std::string &name)=0;
337     virtual void setRemoteUser(const std::string &user)=0;
338     virtual std::string getRemoteUser(void)=0;
339
340     void clearHeader(const char *n) {
341       std::string s = n;
342       clearHeader(s);
343     }
344     void setHeader(const char *n, const char *v) {
345       std::string ns = n;
346       std::string vs = v;
347       setHeader(ns, vs);
348     }
349     void setHeader(const std::string &n, const char *v) {
350       std::string vs = v;
351       setHeader(n, vs);
352     }
353     void setHeader(const char *n, const std::string &v) {
354       std::string ns = n;
355       setHeader(ns, v);
356     }
357     std::string getHeader(const char *n) {
358       std::string s = n;
359       return getHeader(s);
360     }
361     void setRemoteUser(const char *n) {
362       std::string s = n;
363       setRemoteUser(s);
364     }
365
366     // returns the "auth type"..  if this string is not "shibboleth" then
367     // the request will be denied.  Any kind of "override" should be handled
368     // by the subclass before returning this value.  Note that the default
369     // implementation always returns "shibboleth".
370     virtual std::string getAuthType(void);
371
372     // Note: we still need to define exactly what kind of data in contained
373     // in the HTAccessInfo -- perhaps we can stub it out so non-htaccess
374     // systems have something they can plug in?
375     virtual HTAccessInfo* getAccessInfo(void);
376     virtual HTGroupTable* getGroupTable(std::string &user);
377
378     // We're done.  Finish up.  Send specific result content or a redirect.
379     // If there are no headers supplied assume the content-type is text/html
380     typedef std::pair<std::string, std::string> header_t;
381     virtual void* sendPage(
382         const std::string& msg,
383         int code = 200,
384         const std::string& content_type = "text/html",
385         const saml::Iterator<header_t>& headers = EMPTY(header_t)
386         )=0;
387     void* sendPage(const char *msg) {
388       std::string m = msg;
389       return sendPage(m);
390     }
391     virtual void* sendRedirect(const std::string& url)=0;
392     
393     // These next two APIs are used to obtain the module-specific "OK"
394     // and "Decline" results.  OK means "we believe that this request
395     // should be accepted".  Declined means "we believe that this is
396     // not a shibbolized request so we have no comment".
397
398     virtual void* returnDecline(void);
399     virtual void* returnOK(void);
400
401     //
402     // Note:  Subclasses need not implement anything below this line
403     //
404
405     // These functions implement the server-agnostic shibboleth engine
406     // The web server modules implement a subclass and then call into 
407     // these methods once they instantiate their request object.
408     // 
409     // Return value:
410     //   these APIs will always return the result of sendPage(), sendRedirect(),
411     //   returnDecline(), or returnOK() in the void* portion of the return code.
412     //   Exactly what those values are is module- (subclass-) implementation
413     //   specific.  The 'bool' part of the return value declares whether the
414     //   void* is valid or not.  If the bool is true then the void* is valid.
415     //   If the bool is false then the API did not call any callback, the void*
416     //   is not valid, and the caller should continue processing (the API Call
417     //   finished successfully).
418     //
419     //   The arguments are all overrides..  The requireSession and
420     //   exportAssertion values passed in here are only used if the
421     //   settings resource is negative.
422     //
423     //   The handleProfile argument declares whether doCheckAuthN() should
424     //   automatically call doHandlePOST() when it encounters a request for
425     //   the ShireURL;  if false it will call returnOK() instead.
426     //
427     std::pair<bool,void*> doCheckAuthN(bool requireSession = false, bool handler = false);
428     std::pair<bool,void*> doHandler();
429     std::pair<bool,void*> doCheckAuthZ();
430     std::pair<bool,void*> doExportAssertions(bool exportAssertion = false);
431
432     // Currently wraps remoted interface.
433     // TODO: Move this functionality behind IListener
434     void sessionNew(
435         int supported_profiles,
436         const std::string& recipient,
437         const char* packet,
438         const char* ip,
439         std::string& target,
440         std::string& cookie,
441         std::string& provider_id
442         ) const;
443
444     void sessionGet(
445         const char* cookie,
446         const char* ip,
447         ShibProfile& profile,
448         std::string& provider_id,
449         saml::SAMLAuthenticationStatement** auth_statement=NULL,
450         saml::SAMLResponse** attr_response_pre=NULL,
451         saml::SAMLResponse** attr_response_post=NULL
452         ) const;
453
454     void sessionEnd(const char* cookie) const;
455
456     // Basic request access in case any plugins need the info
457     const char* getRequestMethod() const {return m_method.c_str();}
458     const char* getProtocol() const {return m_protocol.c_str();}
459     const char* getHostname() const {return m_hostname.c_str();}
460     int getPort() const {return m_port;}
461     const char* getRequestURI() const {return m_uri.c_str();}
462     const char* getContentType() const {return m_content_type.c_str();}
463     const char* getRemoteAddr() const {return m_remote_addr.c_str();}
464     const char* getRequestURL() const {return m_url.c_str();}
465
466   protected:
467     ShibTarget();
468
469     // Internal APIs
470
471     // Initialize the request from the parsed URL
472     // protocol == http, https, etc
473     // hostname == server name
474     // port == server port
475     // uri == resource path
476     // method == GET, POST, etc.
477     void init(
478         const char* protocol,
479         const char* hostname,
480         int port,
481         const char* uri,
482         const char* content_type,
483         const char* remote_addr,
484         const char* method
485         );
486
487     std::string m_url, m_method, m_protocol, m_hostname, m_uri, m_content_type, m_remote_addr;
488     int m_port;
489
490   private:
491     mutable ShibTargetPriv* m_priv;
492     friend class ShibTargetPriv;
493   };
494 }
495
496 #endif /* SHIB_TARGET_H */