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"
40 # include <shib-target/shib-paths.h>
41 # define SHIBTARGET_EXPORTS
45 namespace shibtarget {
47 DECLARE_SAML_EXCEPTION(SHIBTARGET_EXPORTS,ListenerException,SAMLException);
48 DECLARE_SAML_EXCEPTION(SHIBTARGET_EXPORTS,ConfigurationException,SAMLException);
51 PROFILE_UNSPECIFIED = 0,
59 // Abstract APIs for access to configuration information
61 struct SHIBTARGET_EXPORTS IPropertySet
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() {}
73 struct SHIBTARGET_EXPORTS IApplication : public virtual IPropertySet
75 virtual const char* getId() const=0;
76 virtual const char* getHash() const=0;
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;
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;
89 // caller is given ownership of object, must use and delete within scope of config lock
90 virtual saml::SAMLBrowserProfile::ArtifactMapper* getArtifactMapper() const=0;
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;
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;
100 // Used by dispatcher to locate the handler configuration for a Shibboleth request
101 virtual const IPropertySet* getHandlerConfig(const char* path) const=0;
103 virtual ~IApplication() {}
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
113 ShibHTTPHook(const saml::Iterator<shibboleth::ITrust*>& trusts, const saml::Iterator<shibboleth::ICredentials*>& creds)
114 : m_trusts(trusts), m_creds(creds) {}
115 virtual ~ShibHTTPHook() {}
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);
120 // Client declares a context object and pass as callCtx to send() method.
121 class ShibHTTPHookCallContext {
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;}
132 const IPropertySet* m_credUse;
133 const shibboleth::IRoleDescriptor* m_role;
134 ShibHTTPHook* m_hook;
135 bool m_authenticated;
136 friend class ShibHTTPHook;
139 const saml::Iterator<shibboleth::ITrust*>& getTrustProviders() const {return m_trusts;}
140 const saml::Iterator<shibboleth::ICredentials*>& getCredentialProviders() const {return m_creds;}
142 saml::Iterator<shibboleth::ITrust*> m_trusts;
143 saml::Iterator<shibboleth::ICredentials*> m_creds;
146 struct SHIBTARGET_EXPORTS ISessionCacheEntry : public virtual saml::ILockable
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;
159 const char* unfiltered;
160 const char* filtered;
162 struct SHIBTARGET_EXPORTS CachedResponseSAML {
163 CachedResponseSAML(const saml::SAMLResponse* unfiltered, const saml::SAMLResponse* filtered) {
164 this->unfiltered=unfiltered;
165 this->filtered=filtered;
167 const saml::SAMLResponse* unfiltered;
168 const saml::SAMLResponse* filtered;
170 virtual CachedResponseXML getResponseXML()=0;
171 virtual CachedResponseSAML getResponseSAML()=0;
172 virtual ~ISessionCacheEntry() {}
175 struct SHIBTARGET_EXPORTS ISessionCache : public virtual saml::IPlugIn
177 virtual void thread_init()=0;
178 virtual void thread_end()=0;
179 virtual std::string generateKey() const=0;
182 const IApplication* application,
183 const char* client_addr,
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
193 virtual ISessionCacheEntry* find(const char* key, const IApplication* application)=0;
194 virtual void remove(const char* key)=0;
195 virtual ~ISessionCache() {}
198 struct SHIBTARGET_EXPORTS IListener : public virtual saml::IPlugIn
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...?
204 typedef SOCKET ShibSocket;
206 typedef int ShibSocket;
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;
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,
224 std::string& provider_id
227 virtual void sessionGet(
228 const IApplication* application,
231 ISessionCacheEntry** pentry
234 virtual void sessionEnd(
235 const IApplication* application,
239 virtual void ping(int& i) const=0;
241 virtual ~IListener() {}
244 class SHIBTARGET_EXPORTS ShibTarget;
246 struct SHIBTARGET_EXPORTS IAccessControl : public virtual saml::ILockable, public virtual saml::IPlugIn
248 virtual bool authorized(ShibTarget* st, ISessionCacheEntry* entry) const=0;
249 virtual ~IAccessControl() {}
252 struct SHIBTARGET_EXPORTS IRequestMapper : public virtual saml::ILockable, public virtual saml::IPlugIn
254 typedef std::pair<const IPropertySet*,IAccessControl*> Settings;
255 virtual Settings getSettings(ShibTarget* st) const=0;
256 virtual ~IRequestMapper() {}
259 struct SHIBTARGET_EXPORTS IHandler : public virtual saml::IPlugIn
261 virtual std::pair<bool,void*> run(ShibTarget* st, const IPropertySet* config, bool isHandler=true)=0;
262 virtual ~IHandler() {}
265 struct SHIBTARGET_EXPORTS IConfig : public virtual saml::ILockable, public virtual IPropertySet, public virtual saml::IPlugIn
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() {}
276 class SHIBTARGET_EXPORTS ShibTargetConfig
279 ShibTargetConfig() : m_ini(NULL), m_features(0) {}
280 virtual ~ShibTargetConfig() {}
282 virtual bool init(const char* schemadir) = 0;
283 virtual bool load(const char* config) = 0;
284 virtual void shutdown() = 0;
294 GlobalExtensions = 128,
295 LocalExtensions = 256,
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;}
302 static ShibTargetConfig& getConfig();
308 unsigned long m_features;
311 class ShibTargetPriv;
312 class SHIBTARGET_EXPORTS ShibTarget {
314 ShibTarget(const IApplication *app);
315 virtual ~ShibTarget(void);
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.
329 // Note: subclasses MUST implement ALL of these virtual methods
332 // Send a message to the Webserver log
333 virtual void log(ShibLogLevel level, const std::string &msg)=0;
335 void log(ShibLogLevel level, const char *msg) {
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;
349 void setCookie(const char *name, const std::string &value) {
350 std::string ns = name;
351 setCookie(ns, value);
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;
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;
370 void clearHeader(const char *n) {
374 void setHeader(const char *n, const char *v) {
379 void setHeader(const std::string &n, const char *v) {
383 void setHeader(const char *n, const std::string &v) {
387 std::string getHeader(const char *n) {
391 void setRemoteUser(const char *n) {
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,
402 const std::string& content_type = "text/html",
403 const saml::Iterator<header_t>& headers = EMPTY(header_t)
405 void* sendPage(const char *msg) {
409 virtual void* sendRedirect(const std::string& url)=0;
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".
416 virtual void* returnDecline(void);
417 virtual void* returnOK(void);
420 // Note: Subclasses need not implement anything below this line
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.
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).
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.
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);
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();}
458 // Advanced methods useful to profile handlers implemented outside core
460 // Get per-application session and state cookie name and properties
461 virtual std::pair<std::string,const char*> getCookieNameProps(const char* prefix) const;
463 // Determine the effective handler URL based on the resource URL
464 virtual std::string getHandlerURL(const char* resource) const;
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.
478 const char* protocol,
479 const char* hostname,
482 const char* content_type,
483 const char* remote_addr,
487 std::string m_url, m_method, m_protocol, m_hostname, m_uri, m_content_type, m_remote_addr;
491 mutable ShibTargetPriv* m_priv;
492 friend class ShibTargetPriv;
495 struct SHIBTARGET_EXPORTS XML
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[];
506 // Session cache implementations
507 static const char MemorySessionCacheType[];
508 static const char MySQLSessionCacheType[];
510 // Replay cache implementations
511 static const char MySQLReplayCacheType[];
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
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
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
527 struct SHIBTARGET_EXPORTS Literals
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[];
591 #endif /* SHIB_TARGET_H */