2 * Copyright 2001-2005 Internet2
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * shib-target.h -- top-level header file for the SHIB Common Target Library
20 * Created by: Derek Atkins <derek@ihtfp.com>
28 #include <saml/saml.h>
29 #include <shib/shib.h>
30 #include <shib/shib-threads.h>
33 # ifndef SHIBTARGET_EXPORTS
34 # define SHIBTARGET_EXPORTS __declspec(dllimport)
36 # define SHIB_SCHEMAS "/opt/shibboleth-sp/share/xml/shibboleth"
37 # define SHIB_CONFIG "/opt/shibboleth-sp/etc/shibboleth/shibboleth.xml"
39 # include <shib-target/shib-paths.h>
40 # define SHIBTARGET_EXPORTS
43 #include <shib-target/ddf.h>
45 namespace shibtarget {
47 DECLARE_SAML_EXCEPTION(SHIBTARGET_EXPORTS,ListenerException,SAMLException);
48 DECLARE_SAML_EXCEPTION(SHIBTARGET_EXPORTS,ConfigurationException,SAMLException);
50 // Abstract APIs for access to configuration information
53 * Interface to a generic set of typed properties or a DOM container of additional
56 struct SHIBTARGET_EXPORTS IPropertySet
58 virtual std::pair<bool,bool> getBool(const char* name, const char* ns=NULL) const=0;
59 virtual std::pair<bool,const char*> getString(const char* name, const char* ns=NULL) const=0;
60 virtual std::pair<bool,const XMLCh*> getXMLString(const char* name, const char* ns=NULL) const=0;
61 virtual std::pair<bool,unsigned int> getUnsignedInt(const char* name, const char* ns=NULL) const=0;
62 virtual std::pair<bool,int> getInt(const char* name, const char* ns=NULL) const=0;
63 virtual const IPropertySet* getPropertySet(const char* name, const char* ns="urn:mace:shibboleth:target:config:1.0") const=0;
64 virtual const DOMElement* getElement() const=0;
65 virtual ~IPropertySet() {}
68 // Forward declaration
69 class SHIBTARGET_EXPORTS ShibTarget;
72 * Interface to a protocol handler
74 * Protocol handlers perform system functions such as processing SAML protocol
75 * messages to create and logout sessions or creating protocol requests.
77 struct SHIBTARGET_EXPORTS IHandler : public virtual saml::IPlugIn
79 IHandler() : m_props(NULL) {}
80 virtual ~IHandler() {}
81 virtual const IPropertySet* getProperties() const { return m_props; }
82 virtual void setProperties(const IPropertySet* properties) { m_props=properties; }
83 virtual std::pair<bool,void*> run(ShibTarget* st, bool isHandler=true) const=0;
85 const IPropertySet* m_props;
89 * Interface to Shibboleth Applications, which exposes most of the functionality
90 * required to process web requests or security protocol messages for resources
91 * associated with them.
93 * Applications are implementation-specific, but generally correspond to collections
94 * of resources related to one another in logical ways, such as a virtual host or
95 * a Java servlet context. Most complex configuration data is associated with an
96 * Application. Implementations should always expose an application named "default"
99 struct SHIBTARGET_EXPORTS IApplication : public virtual IPropertySet,
100 public virtual shibboleth::ShibBrowserProfile::ITokenValidator
102 virtual const char* getId() const=0;
103 virtual const char* getHash() const=0;
105 virtual saml::Iterator<saml::SAMLAttributeDesignator*> getAttributeDesignators() const=0;
106 virtual saml::Iterator<shibboleth::IAAP*> getAAPProviders() const=0;
107 virtual saml::Iterator<shibboleth::IMetadata*> getMetadataProviders() const=0;
108 virtual saml::Iterator<shibboleth::ITrust*> getTrustProviders() const=0;
109 virtual saml::Iterator<const XMLCh*> getAudiences() const=0;
110 virtual const IPropertySet* getCredentialUse(const shibboleth::IEntityDescriptor* provider) const=0;
112 // caller is borrowing object, must use within scope of config lock
113 virtual const saml::SAMLBrowserProfile* getBrowserProfile() const=0;
114 virtual const saml::SAMLBinding* getBinding(const XMLCh* binding) const=0;
116 // caller is given ownership of object, must use and delete within scope of config lock
117 virtual saml::SAMLBrowserProfile::ArtifactMapper* getArtifactMapper() const=0;
119 // general token validation based on conditions, signatures, etc.
120 virtual void validateToken(
121 saml::SAMLAssertion* token,
123 const shibboleth::IRoleDescriptor* role=NULL,
124 const saml::Iterator<shibboleth::ITrust*>& trusts=EMPTY(shibboleth::ITrust*)
127 // Used to locate a default or designated session initiator for automatic sessions
128 virtual const IHandler* getDefaultSessionInitiator() const=0;
129 virtual const IHandler* getSessionInitiatorById(const char* id) const=0;
131 // Used by session initiators to get endpoint to forward to IdP/WAYF
132 virtual const IHandler* getDefaultAssertionConsumerService() const=0;
133 virtual const IHandler* getAssertionConsumerServiceByIndex(unsigned short index) const=0;
134 virtual saml::Iterator<const IHandler*> getAssertionConsumerServicesByBinding(const XMLCh* binding) const=0;
136 // Used by dispatcher to locate the handler(s) for a request
137 virtual saml::Iterator<const IHandler*> getHandlers(const char* path) const=0;
139 virtual ~IApplication() {}
143 * OpenSAML binding hook
145 * Instead of wrapping the binding to deal with mutual authentication, we
146 * just use the HTTP hook functionality offered by OpenSAML. The hook will
147 * register "itself" as a globalCtx pointer with the SAML binding and the caller
148 * will declare and pass the embedded struct as callCtx for use by the hook.
150 class ShibHTTPHook : virtual public saml::SAMLSOAPHTTPBinding::HTTPHook
153 ShibHTTPHook(const saml::Iterator<shibboleth::ITrust*>& trusts, const saml::Iterator<shibboleth::ICredentials*>& creds)
154 : m_trusts(trusts), m_creds(creds) {}
155 virtual ~ShibHTTPHook() {}
157 // Only hook we need here is for outgoing connection to server.
158 virtual bool outgoing(saml::HTTPClient* conn, void* globalCtx=NULL, void* callCtx=NULL);
160 // Client declares a context object and pass as callCtx to send() method.
161 class ShibHTTPHookCallContext {
163 ShibHTTPHookCallContext(const IPropertySet* credUse, const shibboleth::IRoleDescriptor* role)
164 : m_credUse(credUse), m_role(role), m_hook(NULL), m_authenticated(false) {}
165 const ShibHTTPHook* getHook() {return m_hook;}
166 const IPropertySet* getCredentialUse() {return m_credUse;}
167 const shibboleth::IRoleDescriptor* getRoleDescriptor() {return m_role;}
168 bool isAuthenticated() const {return m_authenticated;}
169 void setAuthenticated() {m_authenticated=true;}
172 const IPropertySet* m_credUse;
173 const shibboleth::IRoleDescriptor* m_role;
174 ShibHTTPHook* m_hook;
175 bool m_authenticated;
176 friend class ShibHTTPHook;
179 const saml::Iterator<shibboleth::ITrust*>& getTrustProviders() const {return m_trusts;}
180 const saml::Iterator<shibboleth::ICredentials*>& getCredentialProviders() const {return m_creds;}
182 saml::Iterator<shibboleth::ITrust*> m_trusts;
183 saml::Iterator<shibboleth::ICredentials*> m_creds;
187 * Interface to a cached user session.
189 * Cache entries provide implementations with access to the raw SAML information they
190 * need to publish or provide access to the data for applications to use. All creation
191 * or access to entries is through the ISessionCache interface, and callers must unlock
192 * the entry when finished using it, rather than explicitly freeing them.
194 struct SHIBTARGET_EXPORTS ISessionCacheEntry : public virtual saml::ILockable
196 virtual const char* getClientAddress() const=0;
197 virtual const char* getProviderId() const=0;
198 virtual std::pair<const char*,const saml::SAMLSubject*> getSubject(bool xml=true, bool obj=false) const=0;
199 virtual const char* getAuthnContext() const=0;
200 virtual std::pair<const char*,const saml::SAMLResponse*> getTokens(bool xml=true, bool obj=false) const=0;
201 virtual std::pair<const char*,const saml::SAMLResponse*> getFilteredTokens(bool xml=true, bool obj=false) const=0;
202 virtual ~ISessionCacheEntry() {}
206 * Interface to a sink for session cache events.
208 * All caches support registration of a backing store that can be informed
209 * of significant events in the lifecycle of a cache entry.
211 struct SHIBTARGET_EXPORTS ISessionCacheStore
213 virtual HRESULT onCreate(
215 const IApplication* application,
216 const ISessionCacheEntry* entry,
221 virtual HRESULT onRead(
223 std::string& applicationId,
224 std::string& clientAddress,
225 std::string& providerId,
226 std::string& subject,
227 std::string& authnContext,
234 virtual HRESULT onRead(const char* key, time_t& accessed)=0;
235 virtual HRESULT onRead(const char* key, std::string& tokens)=0;
236 virtual HRESULT onUpdate(const char* key, const char* tokens=NULL, time_t lastAccess=0)=0;
237 virtual HRESULT onDelete(const char* key)=0;
238 virtual ~ISessionCacheStore() {}
242 * Interface to the session cache.
244 * The session cache abstracts a persistent (meaning across requests) cache of
245 * instances of the ISessionCacheEntry interface. Creation of new entries and entry
246 * lookup are confined to this interface to enable implementations to flexibly
247 * remote and/or optimize calls by implementing custom versions of the
248 * ISessionCacheEntry interface as required.
250 struct SHIBTARGET_EXPORTS ISessionCache : public virtual saml::IPlugIn
252 virtual std::string insert(
253 const IApplication* application,
254 const shibboleth::IEntityDescriptor* source,
255 const char* client_addr,
256 const saml::SAMLSubject* subject,
257 const char* authnContext,
258 const saml::SAMLResponse* tokens
260 virtual ISessionCacheEntry* find(
261 const char* key, const IApplication* application, const char* client_addr
264 const char* key, const IApplication* application, const char* client_addr
267 virtual bool setBackingStore(ISessionCacheStore* store)=0;
268 virtual ~ISessionCache() {}
272 * Interface to a remoted service
274 * Plugins that support remoted messages delivered by the IListener runtime
275 * support this interface and register themselves with the runtime to receive
276 * particular messages.
278 struct SHIBTARGET_EXPORTS IRemoted : public virtual saml::IPlugIn
280 virtual DDF receive(const DDF& in)=0;
281 virtual ~IRemoted() {}
285 * Interface to the remoting engine
287 * A listener supports the remoting of DDF objects, which are dynamic data trees
288 * that interface implementations can use to remote themselves by calling an
289 * out-of-process peer implementation with arbitrary data to carry out tasks
290 * on the implementation's behalf that require isolation from the dynamic process
291 * fluctuations that web servers are prone to. The ability to pass arbitrary data
292 * trees across the boundary allows arbitrary separation of duty between the
293 * in-process and out-of-process "halves". The implementation is responsible
294 * for marshalling and transmitting messages, as well as managing connections
295 * and communication errors.
297 class SHIBTARGET_EXPORTS IListener : public virtual IRemoted
300 virtual DDF send(const DDF& in)=0;
301 virtual DDF receive(const DDF& in);
302 virtual ~IListener() {}
304 // Remoted classes register and unregister for messages using these methods.
305 // Registration returns any existing listeners, allowing message hooking.
306 virtual IRemoted* regListener(const char* address, IRemoted* listener);
307 virtual bool unregListener(const char* address, IRemoted* current, IRemoted* restore=NULL);
308 virtual IRemoted* lookup(const char* address) const;
310 // OutOfProcess servers can implement server-side transport handling by
311 // calling the run method and supplying a flag to monitor for shutdown.
312 virtual bool run(bool* shutdown)=0;
315 std::map<std::string,IRemoted*> m_listenerMap;
319 * Interface to an access control plugin
321 * Access control plugins return authorization decisions based on the intersection
322 * of the resource request and the active session. They can be implemented through
323 * cross-platform or platform-specific mechanisms.
325 struct SHIBTARGET_EXPORTS IAccessControl : public virtual saml::ILockable, public virtual saml::IPlugIn
327 virtual bool authorized(ShibTarget* st, ISessionCacheEntry* entry) const=0;
328 virtual ~IAccessControl() {}
332 * Interface to a request mapping plugin
334 * Request mapping plugins return configuration settings that apply to resource requests.
335 * They can be implemented through cross-platform or platform-specific mechanisms.
337 struct SHIBTARGET_EXPORTS IRequestMapper : public virtual saml::ILockable, public virtual saml::IPlugIn
339 typedef std::pair<const IPropertySet*,IAccessControl*> Settings;
340 virtual Settings getSettings(ShibTarget* st) const=0;
341 virtual ~IRequestMapper() {}
344 struct SHIBTARGET_EXPORTS IConfig : public virtual saml::ILockable, public virtual IPropertySet, public virtual saml::IPlugIn
346 // loads initial configuration
347 virtual void init()=0;
349 virtual IListener* getListener() const=0;
350 virtual ISessionCache* getSessionCache() const=0;
351 virtual saml::IReplayCache* getReplayCache() const=0;
352 virtual IRequestMapper* getRequestMapper() const=0;
353 virtual const IApplication* getApplication(const char* applicationId) const=0;
354 virtual saml::Iterator<shibboleth::ICredentials*> getCredentialsProviders() const=0;
355 virtual ~IConfig() {}
358 class SHIBTARGET_EXPORTS ShibTargetConfig
361 ShibTargetConfig() : m_ini(NULL), m_features(0) {}
362 virtual ~ShibTargetConfig() {}
364 virtual bool init(const char* schemadir) = 0;
365 virtual bool load(const char* config) = 0;
366 virtual void shutdown() = 0;
380 void setFeatures(long enabled) {m_features = enabled;}
381 bool isEnabled(components_t feature) {return (m_features & feature)>0;}
382 virtual IConfig* getINI() const {return m_ini;}
384 static ShibTargetConfig& getConfig();
390 unsigned long m_features;
393 // Helper class for SAML 2.0 Common Domain Cookie operations
394 class CommonDomainCookie
397 CommonDomainCookie(const char* cookie);
398 ~CommonDomainCookie() {}
399 saml::Iterator<std::string> get() {return m_list;}
400 const char* set(const char* providerId);
401 static const char CDCName[];
403 std::string m_encoded;
404 std::vector<std::string> m_list;
408 class ShibTargetPriv;
409 class SHIBTARGET_EXPORTS ShibTarget {
411 ShibTarget(const IApplication* app);
412 virtual ~ShibTarget(void);
414 // These are defined here so the subclass does not need to specifically
415 // depend on log4cpp. We could use log4cpp::Priority::PriorityLevel
416 // but this is just as easy, IMHO. It's just a case statement in the
417 // implementation to handle the event level.
426 // Note: subclasses MUST implement ALL of these virtual methods
429 // Send a message to the Webserver log
430 virtual void log(ShibLogLevel level, const std::string &msg)=0;
432 void log(ShibLogLevel level, const char* msg) {
437 // Get/Set a cookie for this request
438 virtual std::string getCookies() const=0;
439 virtual void setCookie(const std::string& name, const std::string& value)=0;
440 virtual const char* getCookie(const std::string& name) const;
441 void setCookie(const char* name, const char* value) {
442 std::string ns = name;
443 std::string vs = value;
446 void setCookie(const char* name, const std::string& value) {
447 std::string ns = name;
448 setCookie(ns, value);
451 // Get any URL-encoded arguments or the raw POST body from the server
452 virtual const char* getQueryString() const=0;
453 virtual const char* getRequestBody() const=0;
454 virtual const char* getRequestParameter(const char* param, size_t index=0) const;
456 // Clear a header, set a header
457 // These APIs are used for exporting the Assertions into the
458 // Headers. It will clear some well-known headers first to make
459 // sure none remain. Then it will process the set of assertions
460 // and export them via setHeader().
461 virtual void clearHeader(const std::string& name)=0;
462 virtual void setHeader(const std::string& name, const std::string& value)=0;
463 virtual std::string getHeader(const std::string& name)=0;
464 virtual void setRemoteUser(const std::string& user)=0;
465 virtual std::string getRemoteUser()=0;
467 void clearHeader(const char* n) {
471 void setHeader(const char* n, const char* v) {
476 void setHeader(const std::string& n, const char* v) {
480 void setHeader(const char* n, const std::string& v) {
484 std::string getHeader(const char* n) {
488 void setRemoteUser(const char* n) {
493 // We're done. Finish up. Send specific result content or a redirect.
494 // If there are no headers supplied assume the content-type is text/html
495 typedef std::pair<std::string, std::string> header_t;
496 virtual void* sendPage(
497 const std::string& msg,
499 const std::string& content_type = "text/html",
500 const saml::Iterator<header_t>& headers = EMPTY(header_t)
502 void* sendPage(const char* msg) {
506 virtual void* sendRedirect(const std::string& url)=0;
508 // These next two APIs are used to obtain the module-specific "OK"
509 // and "Decline" results. OK means "we believe that this request
510 // should be accepted". Declined means "we believe that this is
511 // not a shibbolized request so we have no comment".
513 virtual void* returnDecline();
514 virtual void* returnOK();
517 // Note: Subclasses need not implement anything below this line
520 // These functions implement the server-agnostic shibboleth engine
521 // The web server modules implement a subclass and then call into
522 // these methods once they instantiate their request object.
525 // these APIs will always return the result of sendPage(), sendRedirect(),
526 // returnDecline(), or returnOK() in the void* portion of the return code.
527 // Exactly what those values are is module- (subclass-) implementation
528 // specific. The 'bool' part of the return value declares whether the
529 // void* is valid or not. If the bool is true then the void* is valid.
530 // If the bool is false then the API did not call any callback, the void*
531 // is not valid, and the caller should continue processing (the API Call
532 // finished successfully).
534 // The handleProfile argument declares whether doCheckAuthN() should
535 // automatically call doHandlePOST() when it encounters a request for
536 // the ShireURL; if false it will call returnOK() instead.
538 std::pair<bool,void*> doCheckAuthN(bool handler = false);
539 std::pair<bool,void*> doHandler();
540 std::pair<bool,void*> doCheckAuthZ();
541 std::pair<bool,void*> doExportAssertions(bool requireSession = true);
543 // Basic request access in case any plugins need the info
544 virtual const IConfig* getConfig() const;
545 virtual const IApplication* getApplication() const;
546 const char* getRequestMethod() const {return m_method.c_str();}
547 const char* getProtocol() const {return m_protocol.c_str();}
548 const char* getHostname() const {return m_hostname.c_str();}
549 int getPort() const {return m_port;}
550 const char* getRequestURI() const {return m_uri.c_str();}
551 const char* getContentType() const {return m_content_type.c_str();}
552 const char* getRemoteAddr() const {return m_remote_addr.c_str();}
553 const char* getRequestURL() const {return m_url.c_str();}
555 // Advanced methods useful to profile handlers implemented outside core
557 // Get per-application session and state cookie name and properties
558 virtual std::pair<std::string,const char*> getCookieNameProps(const char* prefix) const;
560 // Determine the effective handler URL based on the resource URL
561 virtual std::string getHandlerURL(const char* resource) const;
563 static void url_decode(char* s);
564 static std::string url_encode(const char* s);
571 // Initialize the request from the parsed URL
572 // protocol == http, https, etc
573 // hostname == server name
574 // port == server port
575 // uri == resource path
576 // method == GET, POST, etc.
578 const char* protocol,
579 const char* hostname,
582 const char* content_type,
583 const char* remote_addr,
587 std::string m_url, m_method, m_protocol, m_hostname, m_uri, m_content_type, m_remote_addr;
591 mutable ShibTargetPriv* m_priv;
592 friend class ShibTargetPriv;
595 struct SHIBTARGET_EXPORTS XML
597 static const XMLCh SHIBTARGET_NS[];
598 static const XMLCh SHIBTARGET_SCHEMA_ID[];
599 static const XMLCh SAML2ASSERT_NS[];
600 static const XMLCh SAML2ASSERT_SCHEMA_ID[];
601 static const XMLCh SAML2META_NS[];
602 static const XMLCh SAML2META_SCHEMA_ID[];
603 static const XMLCh XMLENC_NS[];
604 static const XMLCh XMLENC_SCHEMA_ID[];
606 // Session cache implementations
607 static const char MemorySessionCacheType[];
608 static const char MySQLSessionCacheType[];
610 // Replay cache implementations
611 static const char MySQLReplayCacheType[];
613 // Request mapping/settings implementations
614 static const char XMLRequestMapType[]; // portable XML-based map
615 static const char NativeRequestMapType[]; // Native web server command override of XML-based map
616 static const char LegacyRequestMapType[]; // older designation of XML map, hijacked by web server
618 // Access control implementations
619 static const char htAccessControlType[]; // Apache-specific .htaccess authz module
620 static const char XMLAccessControlType[]; // Proprietary but portable XML authz syntax
622 // Listener implementations
623 static const char TCPListenerType[]; // ONC RPC via TCP socket
624 static const char UnixListenerType[]; // ONC RPC via domain socker
625 static const char MemoryListenerType[]; // "faked" in-process marshalling
627 struct SHIBTARGET_EXPORTS Literals
629 static const XMLCh AAPProvider[];
630 static const XMLCh AccessControl[];
631 static const XMLCh AccessControlProvider[];
632 static const XMLCh acl[];
633 static const XMLCh AND[];
634 static const XMLCh applicationId[];
635 static const XMLCh Application[];
636 static const XMLCh Applications[];
637 static const XMLCh AssertionConsumerService[];
638 static const XMLCh AttributeFactory[];
639 static const XMLCh config[];
640 static const XMLCh CredentialsProvider[];
641 static const XMLCh CredentialUse[];
642 static const XMLCh DiagnosticService[];
643 static const XMLCh echo[];
644 static const XMLCh Extensions[];
645 static const XMLCh fatal[];
646 static const XMLCh FederationProvider[];
647 static const XMLCh Global[];
648 static const XMLCh Host[];
649 static const XMLCh htaccess[];
650 static const XMLCh Implementation[];
651 static const XMLCh index[];
652 static const XMLCh InProcess[];
653 static const XMLCh isDefault[];
654 static const XMLCh Library[];
655 static const XMLCh Listener[];
656 static const XMLCh Local[];
657 static const XMLCh log[];
658 static const XMLCh logger[];
659 static const XMLCh MemorySessionCache[];
660 static const XMLCh MetadataProvider[];
661 static const XMLCh MySQLReplayCache[];
662 static const XMLCh MySQLSessionCache[];
663 static const XMLCh name[];
664 static const XMLCh Name[];
665 static const XMLCh NOT[];
666 static const XMLCh OR[];
667 static const XMLCh OutOfProcess[];
668 static const XMLCh Path[];
669 static const XMLCh path[];
670 static const XMLCh RelyingParty[];
671 static const XMLCh ReplayCache[];
672 static const XMLCh RequestMap[];
673 static const XMLCh RequestMapProvider[];
674 static const XMLCh require[];
675 static const XMLCh Rule[];
676 static const XMLCh SessionCache[];
677 static const XMLCh SessionInitiator[];
678 static const XMLCh SHAR[];
679 static const XMLCh ShibbolethTargetConfig[];
680 static const XMLCh SHIRE[];
681 static const XMLCh Signing[];
682 static const XMLCh SingleLogoutService[];
683 static const XMLCh SPConfig[];
684 static const XMLCh TCPListener[];
685 static const XMLCh TLS[];
686 static const XMLCh TrustProvider[];
687 static const XMLCh type[];
688 static const XMLCh UnixListener[];
693 #endif /* SHIB_TARGET_H */