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