Remove state mgr (overkill for now), implement local relay state option
[shibboleth/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   //******************************************************************************
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::IEntityDescriptor* provider);
92     explicit ShibTargetException(ShibRpcStatus code, const char* msg, const shibboleth::IRoleDescriptor* 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 saml::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 saml::ILockable, public virtual saml::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 saml::ILockable, public virtual saml::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 IPropertySet* getCredentialUse(const shibboleth::IEntityDescriptor* provider) const=0;
196
197         // caller is borrowing object, must use within scope of config lock
198         virtual const saml::SAMLBrowserProfile* getBrowserProfile() const=0;
199         virtual const saml::SAMLBinding* getBinding(const XMLCh* binding) const=0;
200
201         // caller is given ownership of object, must use and delete within scope of config lock
202         virtual saml::SAMLBrowserProfile::ArtifactMapper* getArtifactMapper() const=0;
203
204         virtual ~IApplication() {}
205     };
206
207     struct SHIBTARGET_EXPORTS ISessionCacheEntry : public virtual saml::ILockable
208     {
209         virtual bool isValid(time_t lifetime, time_t timeout) const=0;
210         virtual const char* getClientAddress() const=0;
211         virtual ShibProfile getProfile() const=0;
212         virtual const char* getProviderId() const=0;
213         virtual const saml::SAMLAuthenticationStatement* getAuthnStatement() const=0;
214         struct SHIBTARGET_EXPORTS CachedResponse {
215             CachedResponse(const saml::SAMLResponse* unfiltered, const saml::SAMLResponse* filtered) {
216                 this->unfiltered=unfiltered;
217                 this->filtered=filtered;
218             }
219             bool empty() {return unfiltered==NULL;}
220             const saml::SAMLResponse* unfiltered;
221             const saml::SAMLResponse* filtered;
222         };
223         virtual CachedResponse getResponse()=0;
224         virtual ~ISessionCacheEntry() {}
225     };
226
227     struct SHIBTARGET_EXPORTS ISessionCache : public virtual saml::IPlugIn
228     {
229         virtual void thread_init()=0;
230         virtual void thread_end()=0;
231         virtual std::string generateKey() const=0;
232         virtual void insert(
233             const char* key,
234             const IApplication* application,
235             const char* client_addr,
236             ShibProfile profile,
237             const char* providerId,
238             saml::SAMLAuthenticationStatement* s,
239             saml::SAMLResponse* r=NULL,
240             const shibboleth::IRoleDescriptor* source=NULL,
241             time_t created=0,
242             time_t accessed=0
243             )=0;
244         virtual ISessionCacheEntry* find(const char* key, const IApplication* application)=0;
245         virtual void remove(const char* key)=0;
246         virtual ~ISessionCache() {}
247     };
248
249     struct SHIBTARGET_EXPORTS IConfig : public virtual saml::ILockable, public virtual IPropertySet, public virtual saml::IPlugIn
250     {
251         virtual const IListener* getListener() const=0;
252         virtual ISessionCache* getSessionCache() const=0;
253         virtual saml::IReplayCache* getReplayCache() const=0;
254         virtual IRequestMapper* getRequestMapper() const=0;
255         virtual const IApplication* getApplication(const char* applicationId) const=0;
256         virtual saml::Iterator<shibboleth::ICredentials*> getCredentialsProviders() const=0;
257         virtual ~IConfig() {}
258     };
259
260     class SHIBTARGET_EXPORTS ShibTargetConfig
261     {
262     public:
263         ShibTargetConfig() : m_ini(NULL), m_features(0) {}
264         virtual ~ShibTargetConfig() {}
265
266         virtual bool init(const char* schemadir, 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 const XMLCh SHIBTARGET_NS[];
286         static ShibTargetConfig& getConfig();
287
288     protected:
289         IConfig* m_ini;
290         
291     private:
292         unsigned long m_features;
293     };
294
295     class ShibMLPPriv;
296     class SHIBTARGET_EXPORTS ShibMLP {
297     public:
298         ShibMLP();
299         ~ShibMLP();
300
301         void insert (const std::string& key, const std::string& value);
302         void insert (const std::string& key, const char* value) {
303           std::string v = value;
304           insert (key, v);
305         }
306         void insert (const char* key, const std::string& value) {
307           std::string k = key;
308           insert (k, value);
309         }
310         void insert (const char* key, const char* value) {
311           std::string k = key, v = value;
312           insert(k,v);
313         }
314         void insert (RPCError& e);
315
316         void clear () { m_map.clear(); }
317
318         const char* run (std::istream& s, const IPropertySet* props=NULL, std::string* output=NULL);
319         const char* run (const std::string& input, const IPropertySet* props=NULL, std::string* output=NULL);
320         const char* run (const char* input, const IPropertySet* props=NULL, std::string* output=NULL) {
321             std::string i = input;
322             return run(i,props,output);
323         }
324
325     private:
326         ShibMLPPriv *m_priv;
327         std::map<std::string,std::string> m_map;
328         std::string m_generated;
329     };
330
331   //******************************************************************************
332   //
333   // This is the interface you're looking for.
334   //
335
336   class HTAccessInfo {
337   public:
338     class RequireLine {
339     public:
340       bool use_line;
341       std::vector<std::string> tokens;
342     };
343
344     HTAccessInfo() {}
345     ~HTAccessInfo() {
346       for (int k = 0; k < elements.size(); k++)
347         delete elements[k];
348       elements.resize(0);
349     }
350
351     std::vector<RequireLine*> elements;
352     bool requireAll;
353   };
354
355   class HTGroupTable {
356   public:
357     virtual ~HTGroupTable() {}
358     virtual bool lookup(const char *entry) = 0;
359   protected:
360     HTGroupTable() {}
361   };
362
363   // This usurps the existing SHIRE and RM apis into a single class.
364   class ShibTargetPriv;
365   class SHIBTARGET_EXPORTS ShibTarget {
366   public:
367     ShibTarget(const IApplication *app);
368     virtual ~ShibTarget(void);
369
370     // These are defined here so the subclass does not need to specifically
371     // depend on log4cpp.  We could use log4cpp::Priority::PriorityLevel
372     // but this is just as easy, IMHO.  It's just a case statement in the
373     // implementation to handle the event level.
374     enum ShibLogLevel {
375       LogLevelDebug,
376       LogLevelInfo,
377       LogLevelWarn,
378       LogLevelError
379     };
380
381     //
382     // Note: subclasses MUST implement ALL of these virtual methods
383     //
384
385     // Send a message to the Webserver log
386     virtual void log(ShibLogLevel level, const std::string &msg)=0;
387
388     void log(ShibLogLevel level, const char *msg) {
389       std::string s = msg;
390       log(level, s);
391     }
392
393     // Get/Set a cookie for this connection
394     virtual std::string getCookies(void)=0;
395     virtual void setCookie(const std::string &name, const std::string &value)=0;
396
397     void setCookie(const char *name, const char *value) {
398       std::string ns = name;
399       std::string vs = value;
400       setCookie(ns, vs);
401     }
402     void setCookie(const char *name, const std::string &value) {
403       std::string ns = name;
404       setCookie(ns, value);
405     }
406
407
408     // Get the request's GET arguments or POST data from the server
409     virtual std::string getArgs(void)=0;
410     virtual std::string getPostData(void)=0;
411
412     // Clear a header, set a header
413     // These APIs are used for exporting the Assertions into the
414     // Headers.  It will clear some well-known headers first to make
415     // sure none remain.  Then it will process the set of assertions
416     // and export them via setHeader().
417     virtual void clearHeader(const std::string &name)=0;
418     virtual void setHeader(const std::string &name, const std::string &value)=0;
419     virtual std::string getHeader(const std::string &name)=0;
420     virtual void setRemoteUser(const std::string &user)=0;
421     virtual std::string getRemoteUser(void)=0;
422
423     void clearHeader(const char *n) {
424       std::string s = n;
425       clearHeader(s);
426     }
427     void setHeader(const char *n, const char *v) {
428       std::string ns = n;
429       std::string vs = v;
430       setHeader(ns, vs);
431     }
432     void setHeader(const std::string &n, const char *v) {
433       std::string vs = v;
434       setHeader(n, vs);
435     }
436     void setHeader(const char *n, const std::string &v) {
437       std::string ns = n;
438       setHeader(ns, v);
439     }
440     std::string getHeader(const char *n) {
441       std::string s = n;
442       return getHeader(s);
443     }
444     void setRemoteUser(const char *n) {
445       std::string s = n;
446       setRemoteUser(s);
447     }
448
449     // returns the "auth type"..  if this string is not "shibboleth" then
450     // the request will be denied.  Any kind of "override" should be handled
451     // by the subclass before returning this value.  Note that the default
452     // implementation always returns "shibboleth".
453     virtual std::string getAuthType(void);
454
455     // Note: we still need to define exactly what kind of data in contained
456     // in the HTAccessInfo -- perhaps we can stub it out so non-htaccess
457     // systems have something they can plug in?
458     virtual HTAccessInfo* getAccessInfo(void);
459     virtual HTGroupTable* getGroupTable(std::string &user);
460
461     // We're done.  Finish up.  Send either a result (error?) page or a redirect.
462     // If there are no headers supplied assume the content-type == text/html
463     typedef std::pair<std::string, std::string> header_t;
464     virtual void* sendPage(
465                            const std::string &msg,
466                            const std::string content_type = "text/html",
467                            const saml::Iterator<header_t>& headers = EMPTY(header_t),
468                            int code = 200
469                            )=0;
470     void* sendPage(const char *msg) {
471       std::string m = msg;
472       return sendPage(m);
473     }
474
475     virtual void* sendRedirect(const std::string url)=0;
476
477     // These next two APIs are used to obtain the module-specific "OK"
478     // and "Decline" results.  OK means "we believe that this request
479     // should be accepted".  Declined means "we believe that this is
480     // not a shibbolized request so we have no comment".
481
482     virtual void* returnDecline(void);
483     virtual void* returnOK(void);
484
485     //
486     // Note:  Subclasses need not implement anything below this line
487     //
488
489     // These functions implement the server-agnostic shibboleth engine
490     // The web server modules implement a subclass and then call into 
491     // these methods once they instantiate their request object.
492     // 
493     // Return value:
494     //   these APIs will always return the result of sendPage(), sendRedirect(),
495     //   returnDecline(), or returnOK() in the void* portion of the return code.
496     //   Exactly what those values are is module- (subclass-) implementation
497     //   specific.  The 'bool' part of the return value declares whether the
498     //   void* is valid or not.  If the bool is true then the void* is valid.
499     //   If the bool is false then the API did not call any callback, the void*
500     //   is not valid, and the caller should continue processing (the API Call
501     //   finished successfully).
502     //
503     //   The arguments are all overrides..  The requireSession and
504     //   exportAssertion values passed in here are only used if the
505     //   settings resource is negative.
506     //
507     //   The handleProfile argument declares whether doCheckAuthN() should
508     //   automatically call doHandlePOST() when it encounters a request for
509     //   the ShireURL;  if false it will call returnOK() instead.
510     //
511     std::pair<bool,void*> doCheckAuthN(bool requireSession = false, bool handleProfile = false);
512     std::pair<bool,void*> doHandleProfile();
513     std::pair<bool,void*> doCheckAuthZ();
514     std::pair<bool,void*> doExportAssertions(bool exportAssertion = false);
515
516     //**************************************************************************
517     // These APIs are for backwards-compatibility.  Hopefully they can
518     // eventually go away.
519
520     // SHIRE APIs
521
522     // Get the session cookie name and properties for the application
523     std::pair<const char*,const char*> getCookieNameProps() const;
524         
525     // Find the default assertion consumer service for the resource
526     const char* getShireURL(const char* resource) const;
527         
528     // Generate a Shib 1.x AuthnRequest redirect URL for the resource
529     std::string getAuthnRequest(const char* resource);
530         
531     // Process a lazy session setup request and turn it into an AuthnRequest
532     std::string getLazyAuthnRequest(const char* query_string);
533         
534   protected:
535     ShibTarget();
536
537     // Currently wraps remoted interface.
538     // TODO: Move this functionality behind ISessionCache
539     RPCError* sessionNew(
540         int supported_profiles,
541         const char* packet,
542         const char* ip,
543         std::string& cookie,
544         std::string& target
545         ) const;
546
547     RPCError* sessionGet(
548         const char* cookie,
549         const char* ip,
550         ShibProfile& profile,
551         std::string& provider_id,
552         saml::SAMLAuthenticationStatement** auth_statement=NULL,
553         saml::SAMLResponse** attr_response_pre=NULL,
554         saml::SAMLResponse** attr_response_post=NULL
555         ) const;
556
557     // Initialize the request from the parsed URL
558     // protocol == http, https, etc
559     // hostname == server name
560     // port == server port
561     // uri == resource path
562     // method == GET, POST, etc.
563     void init(ShibTargetConfig *config,
564               std::string protocol, std::string hostname, int port,
565               std::string uri, std::string content_type, std::string remote_host,
566               std::string method);
567
568   private:
569     mutable ShibTargetPriv *m_priv;
570   };
571 }
572
573 #endif /* SHIB_TARGET_H */