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