Move the 'SHIRE' d'tor into the class definition.
[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/etc/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   //******************************************************************************
81   // You probably don't care about much below this line
82   // unless you are using the lower-layer APIs provided by
83   // the shib target library.  Go to the end of the file to
84   // find the ShibTarget class -- you probably wnat to use that.
85   //
86
87   class SHIBTARGET_EXPORTS ShibTargetException : public std::exception
88   {
89   public:
90     explicit ShibTargetException() : m_code(SHIBRPC_OK) {}
91     explicit ShibTargetException(ShibRpcStatus code, const char* msg, const shibboleth::IProvider* provider);
92     explicit ShibTargetException(ShibRpcStatus code, const char* msg, const shibboleth::IProviderRole* role=NULL);
93     
94     virtual ~ShibTargetException() throw () {}
95     virtual ShibRpcStatus which() const throw () { return m_code; }
96     virtual const char* what() const throw () { return m_msg.c_str(); }
97     virtual const char* syswho() const throw() { return m_providerId.c_str(); }
98     virtual const char* where() const throw () { return m_errorURL.c_str(); }
99     virtual const char* who() const throw () { return m_contact.c_str(); }
100     virtual const char* how() const throw () { return m_email.c_str(); }
101
102   private:
103     ShibRpcStatus m_code;
104     std::string m_msg;
105     std::string m_providerId;
106     std::string m_errorURL;
107     std::string m_contact;
108     std::string m_email;
109   };
110
111   class RPCErrorPriv;
112   class SHIBTARGET_EXPORTS RPCError
113   {
114   public:
115     RPCError();
116     RPCError(ShibRpcError* e);
117     RPCError(int s, const char* st);
118     RPCError(ShibTargetException &exp);
119     ~RPCError();
120
121     bool isError();
122     bool isRetryable();
123
124     // Return a set of strings that correspond to the error properties
125     const char* getType();
126     const char* getText();
127     const char* getDesc();
128     const char* getProviderId();
129     const char* getErrorURL();
130     const char* getContactName();
131     const char* getContactEmail();
132     int getCode();
133
134   private:
135     RPCErrorPriv* m_priv;
136   };
137
138     // Abstract APIs for access to configuration information
139     
140     struct SHIBTARGET_EXPORTS IPropertySet
141     {
142         virtual std::pair<bool,bool> getBool(const char* name, const char* ns=NULL) const=0;
143         virtual std::pair<bool,const char*> getString(const char* name, const char* ns=NULL) const=0;
144         virtual std::pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const=0;
145         virtual std::pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const=0;
146         virtual std::pair<bool,int> getInt(const char* name, const char* ns=NULL) const=0;
147         virtual const IPropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:target:config:1.0") const=0;
148         virtual const DOMElement* getElement() const=0;
149         virtual ~IPropertySet() {}
150     };
151
152     struct SHIBTARGET_EXPORTS IListener : public virtual shibboleth::IPlugIn
153     {
154 #ifdef WIN32
155         typedef SOCKET ShibSocket;
156 #else
157         typedef int ShibSocket;
158 #endif
159         virtual bool create(ShibSocket& s) const=0;
160         virtual bool bind(ShibSocket& s, bool force=false) const=0;
161         virtual bool connect(ShibSocket& s) const=0;
162         virtual bool close(ShibSocket& s) const=0;
163         virtual bool accept(ShibSocket& listener, ShibSocket& s) const=0;
164         virtual CLIENT* getClientHandle(ShibSocket& s, u_long program, u_long version) const=0;
165         virtual ~IListener() {}
166     };
167
168     struct SHIBTARGET_EXPORTS IAccessControl : public virtual shibboleth::ILockable, public virtual shibboleth::IPlugIn
169     {
170         virtual bool authorized(
171             const saml::SAMLAuthenticationStatement& authn, const saml::Iterator<saml::SAMLAssertion*>& attrs
172             ) const=0;
173         virtual ~IAccessControl() {}
174     };
175
176     struct SHIBTARGET_EXPORTS IRequestMapper : public virtual shibboleth::ILockable, public virtual shibboleth::IPlugIn
177     {
178         typedef std::pair<const IPropertySet*,IAccessControl*> Settings;
179         virtual Settings getSettingsFromURL(const char* url) const=0;
180         virtual Settings getSettingsFromParsedURL(
181             const char* scheme, const char* hostname, unsigned int port, const char* path=NULL
182             ) const=0;
183         virtual ~IRequestMapper() {}
184     };
185     
186     struct SHIBTARGET_EXPORTS IApplication : public virtual IPropertySet
187     {
188         virtual const char* getId() const=0;
189         virtual saml::Iterator<saml::SAMLAttributeDesignator*> getAttributeDesignators() const=0;
190         virtual saml::Iterator<shibboleth::IAAP*> getAAPProviders() const=0;
191         virtual saml::Iterator<shibboleth::IMetadata*> getMetadataProviders() const=0;
192         virtual saml::Iterator<shibboleth::ITrust*> getTrustProviders() const=0;
193         virtual saml::Iterator<shibboleth::IRevocation*> getRevocationProviders() const=0;
194         virtual saml::Iterator<const XMLCh*> getAudiences() const=0;
195         virtual const char* getTLSCred(const shibboleth::IProvider* provider) const=0;
196         virtual const char* getSigningCred(const shibboleth::IProvider* provider) const=0;
197         virtual ~IApplication() {}
198     };
199
200         struct SHIBTARGET_EXPORTS ISessionCacheEntry : public virtual shibboleth::ILockable
201     {
202         virtual bool isValid(time_t lifetime, time_t timeout) const=0;
203         virtual const char* getClientAddress() const=0;
204         virtual const char* getSerializedStatement() const=0;
205         virtual const saml::SAMLAuthenticationStatement* getStatement() const=0;
206         virtual void preFetch(int prefetch_window)=0;
207         virtual saml::Iterator<saml::SAMLAssertion*> getAssertions()=0;
208         virtual ~ISessionCacheEntry() {}
209     };
210
211     struct SHIBTARGET_EXPORTS ISessionCache : public virtual shibboleth::IPlugIn
212     {
213         virtual void thread_init()=0;
214         virtual void thread_end()=0;
215         virtual std::string generateKey() const=0;
216         virtual void insert(
217             const char* key,
218             const IApplication* application,
219             saml::SAMLAuthenticationStatement *s,
220             const char* client_addr,
221             saml::SAMLResponse* r=NULL
222             )=0;
223         virtual ISessionCacheEntry* find(const char* key, const IApplication* application)=0;
224         virtual void remove(const char* key)=0;
225         virtual ~ISessionCache() {}
226     };
227
228     struct SHIBTARGET_EXPORTS IConfig : public virtual shibboleth::ILockable, public virtual IPropertySet, public virtual shibboleth::IPlugIn
229     {
230         virtual const IListener* getListener() const=0;
231         virtual ISessionCache* getSessionCache() const=0;
232         virtual IRequestMapper* getRequestMapper() const=0;
233         virtual const IApplication* getApplication(const char* applicationId) const=0;
234         virtual saml::Iterator<shibboleth::ICredentials*> getCredentialsProviders() const=0;
235         virtual ~IConfig() {}
236     };
237
238     class SHIBTARGET_EXPORTS ShibTargetConfig
239     {
240     public:
241         ShibTargetConfig() : m_ini(NULL), m_features(0) {}
242         virtual ~ShibTargetConfig() {}
243
244         virtual bool init(const char* schemadir, const char* config) = 0;
245         virtual void shutdown() = 0;
246
247         enum components_t {
248             Listener = 1,
249             SessionCache = 2,
250             Metadata = 4,
251             Trust = 8,
252             Credentials = 16,
253             AAP = 32,
254             RequestMapper = 64,
255             SHARExtensions = 128,
256             SHIREExtensions = 256,
257             Logging = 512
258         };
259         void setFeatures(long enabled) {m_features = enabled;}
260         bool isEnabled(components_t feature) {return (m_features & feature)>0;}
261         virtual IConfig* getINI() const {return m_ini;}
262
263         static const XMLCh SHIBTARGET_NS[];
264         static ShibTargetConfig& getConfig();
265
266     protected:
267         IConfig* m_ini;
268         
269     private:
270         unsigned long m_features;
271     };
272
273     class SHIBTARGET_EXPORTS RM
274     {
275     public:
276         RM(const IApplication* app) : m_app(app) {}
277         ~RM() {}
278     
279         RPCError* getAssertions(
280             const char* cookie,
281             const char* ip,
282             std::vector<saml::SAMLAssertion*>& assertions,
283             saml::SAMLAuthenticationStatement **statement = NULL
284             );
285         static void serialize(saml::SAMLAssertion &assertion, std::string &result);
286     
287     private:
288         const IApplication* m_app;
289     };
290
291     class ShibMLPPriv;
292     class SHIBTARGET_EXPORTS ShibMLP {
293     public:
294         ShibMLP();
295         ~ShibMLP();
296
297         void insert (const std::string& key, const std::string& value);
298         void insert (const std::string& key, const char* value) {
299           std::string v = value;
300           insert (key, v);
301         }
302         void insert (const char* key, const std::string& value) {
303           std::string k = key;
304           insert (k, value);
305         }
306         void insert (const char* key, const char* value) {
307           std::string k = key, v = value;
308           insert(k,v);
309         }
310         void insert (RPCError& e);
311
312         void clear () { m_map.clear(); }
313
314         const char* run (std::istream& s, const IPropertySet* props=NULL, std::string* output=NULL);
315         const char* run (const std::string& input, const IPropertySet* props=NULL, std::string* output=NULL);
316         const char* run (const char* input, const IPropertySet* props=NULL, std::string* output=NULL) {
317             std::string i = input;
318             return run(i,props,output);
319         }
320
321     private:
322         ShibMLPPriv *m_priv;
323         std::map<std::string,std::string> m_map;
324         std::string m_generated;
325     };
326
327   //******************************************************************************
328   //
329   // This is the interface you're looking for.
330   //
331
332   // This usurps the existing SHIRE and RM apis into a single class.
333   class ShibTargetPriv;
334   class SHIBTARGET_EXPORTS ShibTarget {
335   public:
336     ShibTarget(const IApplication *app);
337     virtual ~ShibTarget(void);
338
339     // These are defined here so the subclass does not need to specifically
340     // depend on log4cpp.  We could use log4cpp::Priority::PriorityLevel
341     // but this is just as easy, IMHO.  It's just a case statement in the
342     // implementation to handle the event level.
343     enum ShibLogLevel {
344       LogLevelDebug,
345       LogLevelInfo,
346       LogLevelWarn,
347       LogLevelError
348     };
349
350     //
351     // Note: subclasses MUST implement ALL of these virtual methods
352     //
353
354     // Send a message to the Webserver log
355     virtual void log(ShibLogLevel level, std::string &msg);
356
357     void log(ShibLogLevel level, const char *msg) {
358       std::string s = msg;
359       log(level, s);
360     }
361
362     // Get/Set a cookie for this connection
363     virtual std::string getCookies(void);
364     virtual void setCookie(std::string &name, std::string &value);
365
366     void setCookie(const char *name, const char *value) {
367       std::string ns = name;
368       std::string vs = value;
369       setCookie(ns, vs);
370     }
371
372     // Get the request's POST data from the server
373     virtual std::string getPostData(void);
374
375     // Not sure if I need these, but I might for something like Apache
376     // in order to "fix" the auth type in the case of basicHijack.  In
377     // particular we need to maintain some state between the different
378     // APIs to know whether or not to proceed with shib processing.
379     virtual std::string getAuthType(void);
380     virtual void setAuthType(std::string);
381
382     void setAuthType(const char *type) {
383       std::string s = type;
384       setAuthType(s);
385     }
386
387     virtual std::pair<bool,bool> getRequireSession(IRequestMapper::Settings &settings);
388
389     // Note: we still need to define exactly what kind of data in contained
390     // in the HTAccessInfo -- perhaps we can stub it out so non-htaccess
391     // systems have something they can plug in?
392     //virtual HTAccessInfo& getAccessInfo(void);
393
394     // We're done.  Finish up.  Send either a result (error?) page or a redirect.
395     virtual void* sendPage(
396                            std::string &msg,
397                            std::pair<std::string, std::string> headers[] = NULL,
398                            int code = 200
399                            );
400     virtual void* sendRedirect(std::string url);
401
402     // These next two APIs are used to obtain the module-specific "OK"
403     // and "Decline" results.  OK means "we believe that this request
404     // should be accepted".  Declined means "we believe that this is
405     // not a shibbolized request so we have no comment".
406
407     virtual void* returnDecline(void);
408     virtual void* returnOK(void);
409
410     //
411     // Note:  Subclasses need not implement anything below this line
412     //
413
414     // These functions implement the server-agnostic shibboleth engine
415     // The web server modules implement a subclass and then call into 
416     // these methods once they instantiate their request object.
417     // 
418     // Return value:
419     //   these APIs will always return the result of sendPage(), sendRedirect(),
420     //   returnDecline(), or returnOK().  Exactly what those values are
421     //   is module- (subclass-) implementation specific.
422     //
423     void* doCheckAuthN(void);
424     void* doHandlePOST(void);
425     void* doCheckAuthZ(void);
426
427     // SHIRE APIs
428
429     // Get the session cookie name and properties for the application
430     std::pair<const char*,const char*> getCookieNameProps() const;
431         
432     // Find the default assertion consumer service for the resource
433     const char* getShireURL(const char* resource) const;
434         
435     // Generate a Shib 1.x AuthnRequest redirect URL for the resource
436     const char* getAuthnRequest(const char* resource) const;
437         
438     // Process a lazy session setup request and turn it into an AuthnRequest
439     const char* getLazyAuthnRequest(const char* query_string) const;
440         
441     // Process a POST profile submission, and return (SAMLResponse,TARGET) pair.
442     std::pair<const char*,const char*>
443       getFormSubmission(const char* post, unsigned int len) const;
444         
445     RPCError* sessionCreate(
446                             const char* response,
447                             const char* ip,
448                             std::string &cookie
449                             ) const;
450     RPCError* sessionIsValid(const char* session_id, const char* ip) const;
451
452     // RM APIS
453
454     RPCError* getAssertions(
455                             const char* cookie,
456                             const char* ip,
457                             std::vector<saml::SAMLAssertion*>& assertions,
458                             saml::SAMLAuthenticationStatement **statement = NULL
459                             ) const;
460     static void serialize(saml::SAMLAssertion &assertion, std::string &result);
461
462
463   protected:
464     ShibTarget(void);
465
466     // Initialize the request from the parsed URL
467     void init(ShibTargetConfig *config,
468               std::string protocol, std::string hostname, int port,
469               std::string uri, std::string content_type, std::string remote_host,
470               int total_bytes);
471
472   private:
473     mutable ShibTargetPriv *m_priv;
474   };
475
476   //******************************************************************************
477   // You probably don't care about much below this line
478   // unless you are using the lower-layer APIs provided by
479   // the shib target library.
480
481     class SHIBTARGET_EXPORTS SHIRE
482     {
483     public:
484         SHIRE(const IApplication* app) { m_st = new ShibTarget(app); }
485         ~SHIRE() { delete m_st; }
486         
487         // Get the session cookie name and properties for the application
488         std::pair<const char*,const char*> getCookieNameProps() const
489           { return m_st->getCookieNameProps(); }
490         
491         // Find the default assertion consumer service for the resource
492         const char* getShireURL(const char* resource) const
493           { return m_st->getShireURL(resource); }
494         
495         // Generate a Shib 1.x AuthnRequest redirect URL for the resource
496         const char* getAuthnRequest(const char* resource) const
497           { return m_st->getAuthnRequest(resource); }
498         
499         // Process a lazy session setup request and turn it into an AuthnRequest
500         const char* getLazyAuthnRequest(const char* query_string) const
501           { return m_st->getLazyAuthnRequest(query_string); }
502         
503         // Process a POST profile submission, and return (SAMLResponse,TARGET) pair.
504         std::pair<const char*,const char*> getFormSubmission(const char* post, unsigned int len) const
505           { return m_st->getFormSubmission(post, len); }
506         
507         RPCError* sessionCreate(const char* response, const char* ip, std::string &cookie) const
508           { return m_st->sessionCreate(response, ip, cookie); }
509         RPCError* sessionIsValid(const char* session_id, const char* ip) const
510           { return sessionIsValid(session_id, ip); }
511     
512     private:
513         ShibTarget *m_st;
514         //const IApplication* m_app;
515         //mutable std::string m_cookieName;
516         //mutable std::string m_shireURL;
517         //mutable std::string m_authnRequest;
518         //mutable CgiParse* m_parser;
519     };
520
521 }
522
523 #endif /* SHIB_TARGET_H */