base.h \
exceptions.h \
version.h \
+ RootObject.h \
SAMLConfig.h
samlbindinclude_HEADERS = \
binding/ArtifactMap.h \
+ binding/GenericRequest.h \
+ binding/GenericResponse.h \
+ binding/HTTPRequest.h \
+ binding/HTTPResponse.h \
binding/MessageDecoder.h \
binding/MessageEncoder.h \
+ binding/MessageFlowRule.h \
+ binding/MessageSigningRule.h \
binding/SAMLArtifact.h \
+ binding/SecurityPolicy.h \
+ binding/SecurityPolicyRule.h \
binding/URLEncoder.h
encinclude_HEADERS = \
binding/impl/ArtifactMap.cpp \
binding/impl/MessageDecoder.cpp \
binding/impl/MessageEncoder.cpp \
+ binding/impl/MessageFlowRule.cpp \
+ binding/impl/MessageSigningRule.cpp \
binding/impl/SAMLArtifact.cpp \
+ binding/impl/SecurityPolicy.cpp \
binding/impl/URLEncoder.cpp \
saml1/core/impl/AssertionsImpl.cpp \
saml1/core/impl/AssertionsSchemaValidators.cpp \
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/RootObject.h
+ *
+ * Base class for SAML objects at the root of core schemas
+ */
+
+#ifndef __saml_root_h__
+#define __saml_root_h__
+
+#include <saml/signature/SignableObject.h>
+#include <xmltooling/util/DateTime.h>
+
+namespace opensaml {
+
+ /**
+ * Base class for SAML objects at the root of core schemas.
+ * Root objects are signable, and have message identifiers and timestamps.
+ */
+ class SAML_API RootObject : public virtual SignableObject
+ {
+ public:
+ virtual ~RootObject() {}
+
+ /**
+ * Returns the unique SAML ID of the object.
+ *
+ * @return the unique SAML ID
+ */
+ virtual const XMLCh* getID() const=0;
+
+ /**
+ * Returns the timestamp of the object
+ *
+ * @return the timestamp
+ */
+ virtual const xmltooling::DateTime* getIssueInstant() const=0;
+
+ /**
+ * Returns the timestamp of the object as an epoch
+ *
+ * @return the timestamp
+ */
+ virtual time_t getIssueInstantEpoch() const=0;
+
+ protected:
+ RootObject() {}
+ };
+
+};
+
+#endif /* __saml_root_h__ */
registerTrustEngines();
registerMessageEncoders();
registerMessageDecoders();
+ registerSecurityPolicyRules();
m_urlEncoder = new URLEncoder();
MessageDecoderManager.deregisterFactories();
MessageEncoderManager.deregisterFactories();
TrustEngineManager.deregisterFactories();
+ SecurityPolicyRuleManager.deregisterFactories();
SAMLArtifactManager.deregisterFactories();
MetadataFilterManager.deregisterFactories();
MetadataProviderManager.deregisterFactories();
class SAML_API MessageEncoder;
class SAML_API MessageDecoder;
class SAML_API SAMLArtifact;
+ class SAML_API SecurityPolicyRule;
class SAML_API TrustEngine;
class SAML_API URLEncoder;
*/
virtual std::string hashSHA1(const char* s, bool toHex=false)=0;
- /**
- * Manages factories for MessageDecoder plugins.
- */
+ /** Manages factories for MessageDecoder plugins. */
xmltooling::PluginManager<MessageDecoder,const DOMElement*> MessageDecoderManager;
- /**
- * Manages factories for MessageEncoder plugins.
- */
+ /** Manages factories for MessageEncoder plugins. */
xmltooling::PluginManager<MessageEncoder,const DOMElement*> MessageEncoderManager;
- /**
- * Manages factories for SAMLArtifact plugins.
- */
+ /** Manages factories for SAMLArtifact plugins. */
xmltooling::PluginManager<SAMLArtifact,const char*> SAMLArtifactManager;
- /**
- * Manages factories for TrustEngine plugins.
- */
+ /** Manages factories for SecurityPolicyRule plugins. */
+ xmltooling::PluginManager<SecurityPolicyRule,const DOMElement*> SecurityPolicyRuleManager;
+
+ /** Manages factories for TrustEngine plugins. */
xmltooling::PluginManager<TrustEngine,const DOMElement*> TrustEngineManager;
- /**
- * Manages factories for MetadataProvider plugins.
- */
+ /** Manages factories for MetadataProvider plugins. */
xmltooling::PluginManager<saml2md::MetadataProvider,const DOMElement*> MetadataProviderManager;
- /**
- * Manages factories for MetadataFilter plugins.
- */
+ /** Manages factories for MetadataFilter plugins. */
xmltooling::PluginManager<saml2md::MetadataFilter,const DOMElement*> MetadataFilterManager;
protected:
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/binding/GenericRequest.h
+ *
+ * Interface to generic protocol requests that transport SAML messages.
+ */
+
+#ifndef __saml_genreq_h__
+#define __saml_genreq_h__
+
+#include <saml/base.h>
+#include <string>
+#include <vector>
+#include <xsec/enc/XSECCryptoX509.hpp>
+
+namespace opensaml {
+
+ /**
+ * Interface to caller-supplied shim for accessing generic transport
+ * request context.
+ *
+ * <p>This interface need not be threadsafe.
+ */
+ class SAML_API GenericRequest {
+ MAKE_NONCOPYABLE(GenericRequest);
+ protected:
+ GenericRequest() {}
+ public:
+ virtual ~GenericRequest() {}
+
+ /**
+ * Returns the URL scheme of the request (http, https, ftp, ldap, etc.)
+ *
+ * @return the URL scheme
+ */
+ virtual const char* getScheme() const=0;
+
+ /**
+ * Returns true iff the request is over a confidential channel.
+ *
+ * @return confidential channel indicator
+ */
+ virtual bool isSecure() const=0;
+
+ /**
+ * Returns the MIME type of the request, if known.
+ *
+ * @return the MIME type, or an empty string
+ */
+ virtual std::string getContentType() const=0;
+
+ /**
+ * Returns the length of the request body, if known.
+ *
+ * @return the content length, or -1 if unknown
+ */
+ virtual long getContentLength() const=0;
+
+ /**
+ * Returns the raw request body.
+ *
+ * @return the request body, or NULL
+ */
+ virtual const char* getRequestBody() const=0;
+
+ /**
+ * Returns a decoded named parameter value from the request.
+ * If a parameter has multiple values, only one will be returned.
+ *
+ * @param name the name of the parameter to return
+ * @return a single parameter value or NULL
+ */
+ virtual const char* getParameter(const char* name) const=0;
+
+ /**
+ * Returns all of the decoded values of a named parameter from the request.
+ * All values found will be returned.
+ *
+ * @param name the name of the parameter to return
+ * @param values a vector in which to return pointers to the decoded values
+ * @return the number of values returned
+ */
+ virtual std::vector<const char*>::size_type getParameters(
+ const char* name, std::vector<const char*>& values
+ ) const=0;
+
+ /**
+ * Returns the transport-authenticated identity associated with the request,
+ * if authentication is solely handled by the transport.
+ *
+ * @return the authenticated username or an empty string
+ */
+ virtual std::string getRemoteUser() const=0;
+
+ /**
+ * Returns the IP address of the client.
+ *
+ * @return the client's IP address
+ */
+ virtual std::string getRemoteAddr() const=0;
+
+ /**
+ * Returns the chain of certificates sent by the client.
+ * They are not guaranteed to be valid according to any particular definition.
+ *
+ * @return the client's certificate chain
+ */
+ virtual const std::vector<XSECCryptoX509*>& getClientCertificates() const=0;
+ };
+};
+
+#endif /* __saml_genreq_h__ */
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/binding/GenericResponse.h
+ *
+ * Interface to generic protocol responses that transport SAML messages.
+ */
+
+#ifndef __saml_genres_h__
+#define __saml_genres_h__
+
+#include <saml/base.h>
+#include <iostream>
+
+namespace opensaml {
+
+ /**
+ * Interface to caller-supplied shim for accessing generic transport
+ * request context.
+ *
+ * <p>This interface need not be threadsafe.
+ */
+ class SAML_API GenericResponse {
+ MAKE_NONCOPYABLE(GenericResponse);
+ protected:
+ GenericResponse() {}
+ public:
+ virtual ~GenericResponse() {}
+
+ /**
+ * Sets or clears the MIME type of the response.
+ *
+ * @param type the MIME type, or NULL to clear
+ */
+ virtual void setContentType(const char* type=NULL)=0;
+
+ /**
+ * Sends a completed response to the client.
+ *
+ * @param inputStream reference to source of response data
+ * @param status transport-specific status to return
+ * @return a result code to return from the calling MessageEncoder
+ */
+ virtual long sendResponse(std::istream& inputStream, long status)=0;
+ };
+};
+
+#endif /* __saml_genres_h__ */
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/binding/HTTPRequest.h
+ *
+ * Interface to HTTP requests
+ */
+
+#ifndef __saml_httpreq_h__
+#define __saml_httpreq_h__
+
+#include <saml/binding/GenericRequest.h>
+
+namespace opensaml {
+
+ /**
+ * Interface to caller-supplied shim for accessing HTTP request context.
+ *
+ * <p>To supply information from the surrounding web server environment,
+ * a shim must be supplied in the form of this interface to adapt the
+ * library to different proprietary server APIs.
+ *
+ * <p>This interface need not be threadsafe.
+ */
+ class SAML_API HTTPRequest : public GenericRequest {
+ MAKE_NONCOPYABLE(HTTPRequest);
+ protected:
+ HTTPRequest() {}
+ public:
+ virtual ~HTTPRequest() {}
+
+ /**
+ * Returns the HTTP method of the request (GET, POST, etc.)
+ *
+ * @return the HTTP method
+ */
+ virtual const char* getMethod() const=0;
+
+ /**
+ * Returns the complete request URL, including scheme, host, port.
+ *
+ * @return the request URL
+ */
+ virtual const char* getRequestURL() const=0;
+
+ /**
+ * Returns the HTTP query string appened to the request. The query
+ * string is returned without any decoding applied, everything found
+ * after the ? delimiter.
+ *
+ * @return the query string
+ */
+ virtual const char* getQueryString() const=0;
+
+ /**
+ * Returns a request header value.
+ *
+ * @param name the name of the header to return
+ * @return the header's value, or an empty string
+ */
+ virtual std::string getHeader(const char* name) const=0;
+ };
+};
+
+#endif /* __saml_httpreq_h__ */
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/binding/HTTPResponse.h
+ *
+ * Interface to HTTP requests
+ */
+
+#ifndef __saml_httpres_h__
+#define __saml_httpres_h__
+
+#include <saml/binding/GenericResponse.h>
+
+namespace opensaml {
+
+ /**
+ * Interface to caller-supplied shim for issuing an HTTP response.
+ *
+ * <p>To supply information to the surrounding web server environment,
+ * a shim must be supplied in the form of this interface to adapt the
+ * library to different proprietary server APIs.
+ *
+ * <p>This interface need not be threadsafe.
+ */
+ class SAML_API HTTPResponse : public GenericResponse {
+ MAKE_NONCOPYABLE(HTTPResponse);
+ protected:
+ HTTPResponse() {}
+ public:
+ virtual ~HTTPResponse() {}
+
+ /**
+ * Sets or clears a response header.
+ *
+ * @param name header name
+ * @param value value to set, or NULL to clear
+ */
+ virtual void setHeader(const char* name, const char* value)=0;
+
+ /**
+ * Sets a client cookie.
+ *
+ * @param name cookie name
+ * @param value value to set, or NULL to clear
+ */
+ virtual void setCookie(const char* name, const char* value)=0;
+
+ /**
+ * Redirect the client to the specified URL and complete the response.
+ * Any headers previously set will be sent ahead of the redirect.
+ *
+ * @param url location to redirect client
+ * @return a result code to return from the calling MessageEncoder
+ */
+ virtual long sendRedirect(const char* url)=0;
+
+ /** Some common HTTP status codes. */
+ enum status_t {
+ SAML_HTTP_STATUS_OK = 200,
+ SAML_HTTP_STATUS_MOVED = 302
+ };
+ };
+};
+
+#endif /* __saml_httpres_h__ */
#ifndef __saml_decoder_h__
#define __saml_decoder_h__
-#include <saml/base.h>
-
+#include <saml/binding/GenericRequest.h>
+#include <saml/binding/SecurityPolicy.h>
#include <xmltooling/XMLObject.h>
namespace opensaml {
class SAML_API IDPSSODescriptor;
class SAML_API RoleDescriptor;
class SAML_API SSODescriptorType;
- }
+ };
/**
* Interface to SAML protocol binding message decoders.
virtual ~MessageDecoder() {}
/**
- * Interface to caller-supplied shim for accessing HTTP request context.
- *
- * <p>To supply information from the surrounding web server environment,
- * a shim must be supplied in the form of this interface to adapt the
- * library to different proprietary server APIs.
- *
- * <p>This interface need not be threadsafe.
- */
- class SAML_API HTTPRequest {
- MAKE_NONCOPYABLE(HTTPRequest);
- protected:
- HTTPRequest() {}
- public:
- virtual ~HTTPRequest() {}
-
- /**
- * Returns the HTTP method of the request (GET, POST, etc.)
- *
- * @return the HTTP method
- */
- virtual const char* getMethod() const=0;
-
- /**
- * Returns the complete request URL, including scheme, host, port.
- *
- * @return the request URL
- */
- virtual const char* getRequestURL() const=0;
-
- /**
- * Returns the HTTP query string appened to the request. The query
- * string is returned without any decoding applied, everything found
- * after the ? delimiter.
- *
- * @return the query string
- */
- virtual const char* getQueryString() const=0;
-
- /**
- * Returns the raw HTTP request body. Used to access the body
- * of a POST that is not in URL-encoded form.
- *
- * @return the request body, or NULL
- */
- virtual const char* getRequestBody() const=0;
-
- /**
- * Returns a decoded named parameter value from the query string or form body.
- * If a parameter has multiple values, only one will be returned.
- *
- * @param name the name of the parameter to return
- * @return a single parameter value or NULL
- */
- virtual const char* getParameter(const char* name) const=0;
-
- /**
- * Returns all of the decoded values of a named parameter from the query string
- * or form body. All values found will be returned.
- *
- * @param name the name of the parameter to return
- * @param values a vector in which to return pointers to the decoded values
- * @return the number of values returned
- */
- virtual std::vector<const char*>::size_type getParameters(
- const char* name, std::vector<const char*>& values
- ) const=0;
-
- /**
- * Returns the authenticated identity associated with the request
- *
- * @return the authenticated username or an empty string
- */
- virtual std::string getRemoteUser() const=0;
-
- /**
- * Returns a request header value.
- *
- * @param name the name of the header to return
- * @return the header's value, or an empty string
- */
- virtual std::string getHeader(const char* name) const=0;
- };
-
- /**
* Interface to caller-supplied artifact resolution mechanism.
*
* Resolving artifacts requires internally performing a SOAP-based
/**
* Resolves one or more SAML 1.x artifacts into a response containing a set of
- * resolved Assertions. The caller is responsible for the resulting Response.
+ * resolved Assertions. The caller is responsible for the resulting Response.
+ * The supplied SecurityPolicy is used to access caller-supplied infrastructure
+ * and to pass back the result of authenticating the resolution process.
*
- * @param securityMech will be set to identifier of security mechanism that authenticated the resolution
* @param artifacts one or more SAML 1.x artifacts
* @param idpDescriptor reference to IdP role of artifact issuer
- * @param trustEngine optional pointer to X509TrustEngine supplied to MessageDecoder
+ * @param policy reference to policy containing rules, MetadataProvider, TrustEngine, etc.
* @return the corresponding SAML Assertions wrapped in a Response.
*/
virtual saml1p::Response* resolve(
- const XMLCh*& securityMech,
const std::vector<SAMLArtifact*>& artifacts,
const saml2md::IDPSSODescriptor& idpDescriptor,
- const X509TrustEngine* trustEngine=NULL
+ SecurityPolicy& policy
) const=0;
/**
* Resolves a SAML 2.0 artifact into the corresponding SAML protocol message.
* The caller is responsible for the resulting ArtifactResponse message.
+ * The supplied SecurityPolicy is used to access caller-supplied infrastructure
+ * and to pass back the result of authenticating the resolution process.
*
- * @param securityMech will be set to identifier of security mechanism that authenticated the resolution
* @param artifact reference to a SAML 2.0 artifact
* @param ssoDescriptor reference to SSO role of artifact issuer (may be SP or IdP)
- * @param trustEngine optional pointer to X509TrustEngine supplied to MessageDecoder
+ * @param policy reference to policy containing rules, MetadataProvider, TrustEngine, etc.
* @return the corresponding SAML protocol message or NULL
*/
virtual saml2p::ArtifactResponse* resolve(
- const XMLCh*& securityMech,
const saml2p::SAML2Artifact& artifact,
const saml2md::SSODescriptorType& ssoDescriptor,
- const X509TrustEngine* trustEngine=NULL
+ SecurityPolicy& policy
) const=0;
};
}
/**
- * Decodes an HTTP request into a SAML protocol message, and returns related
- * information about the issuer of the message and whether it can be trusted.
- * If the HTTP request does not contain the information necessary to decode
- * the request, a NULL will be returned. Errors during the decoding process
- * will be raised as exceptions.
+ * Decodes a transport request into a SAML protocol message, and evaluates it
+ * against a supplied SecurityPolicy. If the transport request does not contain
+ * the information necessary to decode the request, NULL will be returned.
+ * Errors during the decoding process will be raised as exceptions.
*
* <p>Artifact-based bindings require an ArtifactResolver be set to
* turn an artifact into the corresponding message.
*
- * <p>In some cases, a message may be returned but not authenticated. The caller
- * should examine the issuerTrusted output value to establish this.
- *
* @param relayState will be set to RelayState/TARGET value accompanying message
- * @param issuer will be set to role descriptor of issuing party, if known
- * @param securityMech will be set to identifier of security mechanism that authenticates the message
- * @param httpRequest reference to interface for accessing HTTP message to decode
- * @param metadataProvider optional MetadataProvider instance to authenticate the message
- * @param role optional, identifies the role (generally IdP or SP) of the peer who issued the message
- * @param trustEngine optional TrustEngine to authenticate the message
+ * @param genericRequest reference to interface for accessing transport request to decode
+ * @param policy reference to policy containing rules, MetadataProvider, TrustEngine, etc.
* @return the decoded message, or NULL if the decoder did not recognize the request content
*/
virtual xmltooling::XMLObject* decode(
std::string& relayState,
- const saml2md::RoleDescriptor*& issuer,
- const XMLCh*& securityMech,
- const HTTPRequest& httpRequest,
- const saml2md::MetadataProvider* metadataProvider=NULL,
- const xmltooling::QName* role=NULL,
- const TrustEngine* trustEngine=NULL
+ const GenericRequest& genericRequest,
+ SecurityPolicy& policy
) const=0;
protected:
#ifndef __saml_encoder_h__
#define __saml_encoder_h__
-#include <saml/base.h>
+#include <saml/binding/GenericResponse.h>
-#include <map>
-#include <string>
#include <istream>
#include <xmltooling/XMLObject.h>
#include <xmltooling/signature/CredentialResolver.h>
virtual ~MessageEncoder() {}
/**
- * Interface to caller-supplied shim for issuing an HTTP response.
- *
- * <p>To supply information to the surrounding web server environment,
- * a shim must be supplied in the form of this interface to adapt the
- * library to different proprietary server APIs.
- *
- * <p>This interface need not be threadsafe.
- */
- class SAML_API HTTPResponse {
- MAKE_NONCOPYABLE(HTTPResponse);
- protected:
- HTTPResponse() {}
- public:
- virtual ~HTTPResponse() {}
-
- /**
- * Sets or clears a response header.
- *
- * @param name header name
- * @param value value to set, or NULL to clear
- */
- virtual void setHeader(const char* name, const char* value)=0;
-
- /**
- * Sets a client cookie.
- *
- * @param name cookie name
- * @param value value to set, or NULL to clear
- */
- virtual void setCookie(const char* name, const char* value)=0;
-
- /**
- * Redirect the client to the specified URL and complete the response.
- * Any headers previously set will be sent ahead of the redirect.
- *
- * @param url location to redirect client
- * @return a result code to return from the calling MessageEncoder
- */
- virtual long sendRedirect(const char* url)=0;
-
- /**
- * Sends a completed response to the client. Any headers previously set
- * will be sent ahead of the data.
- *
- * @param inputStream reference to source of response data
- * @param status HTTP status code to return
- * @param contentType Content-Type header to return
- * @return a result code to return from the calling MessageEncoder
- */
- virtual long sendResponse(std::istream& inputStream, int status = 200, const char* contentType = "text/html")=0;
- };
-
- /**
* Interface to caller-supplied artifact generation mechanism.
*
* Generating an artifact for storage and retrieval requires knowledge of
}
/**
- * Encodes an XML object/message into a binding-specific HTTP response.
+ * Encodes an XML object/message into a binding- and transport-specific response.
* The XML content cannot have a parent object, and any existing references to
* the content will be invalidated if the encode method returns successfully.
*
* <p>Artifact-based bindings require an ArtifactGenerator be set to
* produce an artifact suitable for the intended recipient.
*
- * @param httpResponse reference to interface for sending encoded response to client
+ * @param genericResponse reference to interface for sending transport response
* @param xmlObject XML message to encode
* @param destination destination URL for message
* @param recipientID optional entityID of message recipient
* @param sigAlgorithm optional signature algorithm identifier
*/
virtual long encode(
- HTTPResponse& httpResponse,
+ GenericResponse& genericResponse,
xmltooling::XMLObject* xmlObject,
const char* destination,
const char* recipientID=NULL,
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/binding/MessageFlowRule.h
+ *
+ * SAML replay and freshness checking SecurityPolicyRule
+ */
+
+#include <saml/binding/SecurityPolicyRule.h>
+
+
+namespace opensaml {
+ /**
+ * SAML replay and freshness checking SecurityPolicyRule
+ *
+ * Subclasses can provide support for additional message types
+ * by overriding the main method and then calling the check method.
+ */
+ class SAML_API MessageFlowRule : public SecurityPolicyRule
+ {
+ public:
+ MessageFlowRule(const DOMElement* e);
+ virtual ~MessageFlowRule() {}
+
+ std::pair<saml2::Issuer*,const saml2md::RoleDescriptor*> evaluate(
+ const GenericRequest& request,
+ const xmltooling::XMLObject& message,
+ const saml2md::MetadataProvider* metadataProvider,
+ const xmltooling::QName* role,
+ const TrustEngine* trustEngine
+ ) const;
+
+ protected:
+ /**
+ * Performs the check.
+ *
+ * @param id message identifier
+ * @param issueInstant timestamp of protocol message
+ *
+ * @exception BindingException raised if a check fails
+ */
+ void check(const XMLCh* id, time_t issueInstant) const;
+
+ private:
+ bool m_checkReplay;
+ time_t m_expires;
+ };
+
+};
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/binding/MessageSigningRule.h
+ *
+ * XML Signature checking SecurityPolicyRule
+ */
+
+#include <saml/binding/SecurityPolicyRule.h>
+
+
+namespace opensaml {
+ /**
+ * XML Signature checking SecurityPolicyRule
+ *
+ * Subclasses can provide support for additional message types
+ * by overriding the issuer derivation method.
+ */
+ class SAML_API MessageSigningRule : public SecurityPolicyRule
+ {
+ public:
+ MessageSigningRule(const DOMElement* e) {}
+ virtual ~MessageSigningRule() {}
+
+ std::pair<saml2::Issuer*,const saml2md::RoleDescriptor*> evaluate(
+ const GenericRequest& request,
+ const xmltooling::XMLObject& message,
+ const saml2md::MetadataProvider* metadataProvider,
+ const xmltooling::QName* role,
+ const TrustEngine* trustEngine
+ ) const;
+
+ protected:
+ /**
+ * Examines the message and/or its contents and extracts the issuer's claimed
+ * identity along with a protocol identifier. The two together can be used to
+ * locate metadata to use in validating the signature. Conventions may be needed
+ * to properly encode non-SAML2 issuer information into a compatible form.
+ *
+ * <p>The caller is responsible for freeing the Issuer object.
+ *
+ * @param message message to examine
+ * @return a pair consisting of a SAML 2.0 Issuer object and a protocol constant.
+ */
+ virtual std::pair<saml2::Issuer*,const XMLCh*> getIssuerAndProtocol(const xmltooling::XMLObject& message) const;
+ };
+
+};
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/binding/SecurityPolicy.h
+ *
+ * Overall policy used to verify the security of an incoming message.
+ */
+
+#ifndef __saml_secpol_h__
+#define __saml_secpol_h__
+
+#include <saml/binding/SecurityPolicyRule.h>
+#include <vector>
+
+#if defined (_MSC_VER)
+ #pragma warning( push )
+ #pragma warning( disable : 4250 4251 )
+#endif
+
+namespace opensaml {
+
+ namespace saml2md {
+ class SAML_API MetadataProvider;
+ };
+
+ /**
+ * A policy used to verify the security of an incoming message.
+ *
+ * <p>Its security mechanisms may be used to examine the transport layer
+ * (e.g client certificates and HTTP basic auth passwords) or to check the
+ * payload of a request to ensure it meets certain criteria (e.g. valid
+ * digital signature, freshness, replay).
+ *
+ * <p>Policy objects can be reused, but are not thread-safe.
+ */
+ class SAML_API SecurityPolicy
+ {
+ MAKE_NONCOPYABLE(SecurityPolicy);
+ public:
+ /**
+ * Constructor for policy.
+ *
+ * @param rules reference to array of policy rules to use
+ * @param metadataProvider locked MetadataProvider instance
+ * @param role identifies the role (generally IdP or SP) of the policy peer
+ * @param trustEngine TrustEngine to authenticate policy peer
+ */
+ SecurityPolicy(
+ const std::vector<const SecurityPolicyRule*>& rules,
+ const saml2md::MetadataProvider* metadataProvider=NULL,
+ const xmltooling::QName* role=NULL,
+ const TrustEngine* trustEngine=NULL
+ ) : m_issuer(NULL), m_issuerRole(NULL), m_rules(rules), m_metadata(metadataProvider),
+ m_role(role ? *role : xmltooling::QName()), m_trust(trustEngine) {
+ }
+ virtual ~SecurityPolicy();
+
+ /**
+ * Returns the locked MetadataProvider supplied to the policy.
+ *
+ * @return the supplied MetadataProvider or NULL
+ */
+ const saml2md::MetadataProvider* getMetadataProvider() const {
+ return m_metadata;
+ }
+
+ /**
+ * Returns the peer role element/type supplied to the policy.
+ *
+ * @return the peer role element/type, or an empty QName
+ */
+ const xmltooling::QName* getRole() const {
+ return &m_role;
+ }
+
+ /**
+ * Returns the TrustEngine supplied to the policy.
+ *
+ * @return the supplied TrustEngine or NULL
+ */
+ const TrustEngine* getTrustEngine() const {
+ return m_trust;
+ }
+
+ /**
+ * Evaluates the rule against the given request and message,
+ * possibly populating issuer information in the policy object.
+ *
+ * @param request the protocol request
+ * @param message the incoming message
+ * @return the identity of the message issuer, in one or more of two forms, or NULL
+ *
+ * @throws BindingException thrown if the request/message do not meet the requirements of this rule
+ */
+ void evaluate(const GenericRequest& request, const xmltooling::XMLObject& message);
+
+ /**
+ * Gets the issuer of the message as determined by the registered policies.
+ *
+ * @return issuer of the message as determined by the registered policies
+ */
+ const saml2::Issuer* getIssuer() const {
+ return m_issuer;
+ }
+
+ /**
+ * Gets the metadata for the role the issuer is operating in.
+ *
+ * @return metadata for the role the issuer is operating in
+ */
+ const saml2md::RoleDescriptor* getIssuerMetadata() const {
+ return m_issuerRole;
+ }
+
+ /**
+ * Sets the issuer of the message as determined by external factors.
+ * The policy object takes ownership of the Issuer object.
+ *
+ * @param issuer issuer of the message
+ */
+ void setIssuer(saml2::Issuer* issuer);
+
+ /**
+ * Sets the metadata for the role the issuer is operating in.
+ *
+ * @param issuerRole metadata for the role the issuer is operating in
+ */
+ void setIssuerMetadata(const saml2md::RoleDescriptor* issuerRole);
+
+ protected:
+ /**
+ * Returns true iff the two operands "match". Applications can override this method to
+ * support non-standard issuer matching for complex policies.
+ *
+ * <p>The default implementation does a basic comparison of the XML content, treating
+ * an unsupplied Format as "entityID".
+ *
+ * @param issuer1 the first Issuer to match
+ * @param issuer2 the second Issuer to match
+ * @return true iff the operands match
+ */
+ virtual bool issuerMatches(const saml2::Issuer* issuer1, const saml2::Issuer* issuer2) const;
+
+ private:
+ saml2::Issuer* m_issuer;
+ const saml2md::RoleDescriptor* m_issuerRole;
+
+ std::vector<const SecurityPolicyRule*> m_rules;
+ const saml2md::MetadataProvider* m_metadata;
+ xmltooling::QName m_role;
+ const TrustEngine* m_trust;
+ };
+
+};
+
+#if defined (_MSC_VER)
+ #pragma warning( pop )
+#endif
+
+#endif /* __saml_secpol_h__ */
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/binding/SecurityPolicyRule.h
+ *
+ * Policy rules that secure and authenticate bindings.
+ */
+
+#ifndef __saml_secrule_h__
+#define __saml_secrule_h__
+
+#include <saml/binding/GenericRequest.h>
+#include <xmltooling/XMLObject.h>
+
+namespace opensaml {
+ class SAML_API TrustEngine;
+
+ namespace saml2 {
+ class SAML_API Issuer;
+ };
+ namespace saml2md {
+ class SAML_API RoleDescriptor;
+ };
+
+ /**
+ * A rule that a protocol request and message must meet in order to be valid and secure.
+ *
+ * <p>Rules must be stateless and thread-safe across evaluations. Evaluation should not
+ * result in an exception if the request/message properties do not apply to the rule
+ * (e.g. particular security mechanisms that are not present).
+ */
+ class SAML_API SecurityPolicyRule
+ {
+ MAKE_NONCOPYABLE(SecurityPolicyRule);
+ protected:
+ SecurityPolicyRule() {}
+ public:
+ virtual ~SecurityPolicyRule() {}
+
+ /**
+ * Evaluates the rule against the given request and message. If an Issuer is
+ * returned, the caller is responsible for freeing the Issuer object.
+ *
+ * @param request the protocol request
+ * @param message the incoming message
+ * @param metadataProvider locked MetadataProvider instance to authenticate the message
+ * @param role identifies the role (generally IdP or SP) of the peer who issued the message
+ * @param trustEngine TrustEngine to authenticate the message
+ * @return the identity of the message issuer, in two forms, or NULL
+ *
+ * @throws BindingException thrown if the request/message do not meet the requirements of this rule
+ */
+ virtual std::pair<saml2::Issuer*,const saml2md::RoleDescriptor*> evaluate(
+ const GenericRequest& request,
+ const xmltooling::XMLObject& message,
+ const saml2md::MetadataProvider* metadataProvider,
+ const xmltooling::QName* role,
+ const TrustEngine* trustEngine
+ ) const=0;
+ };
+
+ /**
+ * Registers SecurityPolicyRule plugins into the runtime.
+ */
+ void SAML_API registerSecurityPolicyRules();
+
+ /**
+ * SecurityPolicyRule for replay detection and freshness checking.
+ *
+ * <p>A ReplayCache instance must be available from the runtime, unless
+ * a "checkReplay" XML attribute is set to "0" or "false" when instantiating
+ * the policy.
+ *
+ * <p>Messages must have been issued in the past, but no more than 60 seconds ago,
+ * or up to a number of seconds set by an "expires" XML attribute when
+ * instantiating the policy.
+ */
+ #define MESSAGEFLOW_POLICY_RULE "org.opensaml.binding.MessageFlowRule"
+
+ /**
+ * SecurityPolicyRule for protocol message signing.
+ *
+ * Allows the message issuer to be authenticated using an XML or binding-specific
+ * digital signature over the message. The transport layer is not considered.
+ */
+ #define MESSAGESIGNING_POLICY_RULE "org.opensaml.binding.MessageSigningRule"
+};
+
+#endif /* __saml_secrule_h__ */
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * MessageFlowRule.cpp
+ *
+ * SAML replay and freshness checking SecurityPolicyRule
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "RootObject.h"
+#include "binding/MessageFlowRule.h"
+
+#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/ReplayCache.h>
+#include <log4cpp/Category.hh>
+
+using namespace opensaml;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace opensaml {
+ SecurityPolicyRule* SAML_DLLLOCAL MessageFlowRuleFactory(const DOMElement* const & e)
+ {
+ return new MessageFlowRule(e);
+ }
+};
+
+static const XMLCh checkReplay[] = UNICODE_LITERAL_11(c,h,e,c,k,R,e,p,l,a,y);
+static const XMLCh expires[] = UNICODE_LITERAL_7(e,x,p,i,r,e,s);
+
+MessageFlowRule::MessageFlowRule(const DOMElement* e)
+ : m_checkReplay(true), m_expires(XMLToolingConfig::getConfig().clock_skew_secs)
+{
+ if (e) {
+ const XMLCh* attr = e->getAttributeNS(NULL, checkReplay);
+ if (attr && (*attr==chLatin_f || *attr==chDigit_0))
+ m_checkReplay = false;
+ attr = e->getAttributeNS(NULL, expires);
+ if (attr)
+ m_expires = XMLString::parseInt(attr);
+ }
+}
+
+pair<saml2::Issuer*,const saml2md::RoleDescriptor*> MessageFlowRule::evaluate(
+ const GenericRequest& request,
+ const XMLObject& message,
+ const saml2md::MetadataProvider* metadataProvider,
+ const QName* role,
+ const opensaml::TrustEngine* trustEngine
+ ) const
+{
+ try {
+ const RootObject& obj = dynamic_cast<const RootObject&>(message);
+ check(obj.getID(), obj.getIssueInstantEpoch());
+ }
+ catch (bad_cast&) {
+ throw BindingException("Message was not of a recognized SAML root type.");
+ }
+ return pair<saml2::Issuer*,const saml2md::RoleDescriptor*>(NULL,NULL);
+}
+
+void MessageFlowRule::check(const XMLCh* id, time_t issueInstant) const
+{
+ Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.MessageFlow");
+ log.debug("evaluating message flow policy (replay checking %s, expiration %lu)", m_checkReplay ? "on" : "off", m_expires);
+
+ time_t skew = XMLToolingConfig::getConfig().clock_skew_secs;
+ time_t now = time(NULL);
+ if (issueInstant > now + skew) {
+ log.error("rejected not-yet-valid message, timestamp (%lu), now (%lu)", issueInstant, now + skew);
+ throw BindingException("Message rejected, was issued in the future.");
+ }
+ else if (issueInstant < now - skew - m_expires) {
+ log.error("rejected expired message, timestamp (%lu), oldest allowed (%lu)", issueInstant, now - skew - m_expires);
+ throw BindingException("Message expired, was issued too long ago.");
+ }
+
+ // Check replay.
+ if (m_checkReplay) {
+ ReplayCache* replayCache = XMLToolingConfig::getConfig().getReplayCache();
+ if (!replayCache)
+ throw BindingException("No ReplayCache instance available.");
+ else if (!id)
+ throw BindingException("Message did not contain an identifier.");
+ auto_ptr_char temp(id);
+ if (!replayCache->check("SAML", temp.get(), issueInstant + skew + m_expires)) {
+ log.error("replay detected of message ID (%s)", temp.get());
+ throw BindingException("Rejecting replayed message ID ($1).", params(1,temp.get()));
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * MessageSigningRule.cpp
+ *
+ * XML Signature checking SecurityPolicyRule
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "RootObject.h"
+#include "binding/MessageSigningRule.h"
+#include "saml1/core/Assertions.h"
+#include "saml1/core/Protocols.h"
+#include "saml2/core/Protocols.h"
+#include "saml2/metadata/Metadata.h"
+#include "saml2/metadata/MetadataProvider.h"
+#include "security/TrustEngine.h"
+
+#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/ReplayCache.h>
+#include <log4cpp/Category.hh>
+
+using namespace opensaml::saml2md;
+using namespace opensaml;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace opensaml {
+ SecurityPolicyRule* SAML_DLLLOCAL MessageSigningRuleFactory(const DOMElement* const & e)
+ {
+ return new MessageSigningRule(e);
+ }
+};
+
+pair<saml2::Issuer*,const saml2md::RoleDescriptor*> MessageSigningRule::evaluate(
+ const GenericRequest& request,
+ const XMLObject& message,
+ const MetadataProvider* metadataProvider,
+ const QName* role,
+ const opensaml::TrustEngine* trustEngine
+ ) const
+{
+ Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.MessageSigning");
+ log.debug("evaluating message signing policy");
+
+ pair<saml2::Issuer*,const RoleDescriptor*> ret = pair<saml2::Issuer*,const RoleDescriptor*>(NULL,NULL);
+
+ if (!metadataProvider || !role || !trustEngine) {
+ log.debug("ignoring message, no metadata or trust information supplied");
+ return ret;
+ }
+
+ try {
+ const RootObject& root = dynamic_cast<const RootObject&>(message);
+ if (!root.getSignature()) {
+ log.debug("ignoring unsigned message");
+ return ret;
+ }
+
+ log.debug("extracting issuer from message");
+ pair<saml2::Issuer*,const XMLCh*> issuerInfo = getIssuerAndProtocol(message);
+
+ auto_ptr<saml2::Issuer> issuer(issuerInfo.first);
+ if (!issuerInfo.first || !issuerInfo.second ||
+ (issuer->getFormat() && !XMLString::equals(issuer->getFormat(), saml2::NameIDType::ENTITY))) {
+ log.warn("issuer identity not estabished, or was not an entityID");
+ return ret;
+ }
+
+ log.debug("searching metadata for message issuer...");
+ const EntityDescriptor* entity = metadataProvider->getEntityDescriptor(issuer->getName());
+ if (!entity) {
+ auto_ptr_char temp(issuer->getName());
+ log.warn("no metadata found, can't establish identity of issuer (%s)", temp.get());
+ return ret;
+ }
+
+ log.debug("matched assertion issuer against metadata, searching for applicable role...");
+ const RoleDescriptor* roledesc=entity->getRoleDescriptor(*role, issuerInfo.second);
+ if (!roledesc) {
+ log.warn("unable to find compatible role (%s) in metadata", role->toString().c_str());
+ return ret;
+ }
+
+ if (!trustEngine->validate(*(root.getSignature()), *roledesc, metadataProvider->getKeyResolver())) {
+ log.error("unable to verify signature on message with supplied trust engine");
+ return ret;
+ }
+
+ if (log.isDebugEnabled()) {
+ auto_ptr_char iname(entity->getEntityID());
+ log.debug("message from (%s), signature verified", iname.get());
+ }
+
+ ret.first = issuer.release();
+ ret.second = roledesc;
+ }
+ catch (bad_cast&) {
+ // Just trap it.
+ log.warn("caught a bad_cast while extracting issuer");
+ }
+ return ret;
+}
+
+pair<saml2::Issuer*,const XMLCh*> MessageSigningRule::getIssuerAndProtocol(const XMLObject& message) const
+{
+ // We just let any bad casts throw here.
+
+ saml2::Issuer* issuer;
+
+ // Shortcuts some of the casting.
+ const XMLCh* ns = message.getElementQName().getNamespaceURI();
+ if (ns) {
+ if (XMLString::equals(ns, samlconstants::SAML20P_NS) || XMLString::equals(ns, samlconstants::SAML20_NS)) {
+ // 2.0 namespace should be castable to a specialized 2.0 root.
+ const saml2::RootObject& root = dynamic_cast<const saml2::RootObject&>(message);
+ issuer = root.getIssuer();
+ if (issuer && issuer->getName()) {
+ return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS);
+ }
+
+ // No issuer in the message, so we have to try the Response approach.
+ const vector<saml2::Assertion*>& assertions = dynamic_cast<const saml2p::Response&>(message).getAssertions();
+ if (!assertions.empty()) {
+ issuer = assertions.front()->getIssuer();
+ if (issuer && issuer->getName())
+ return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS);
+ }
+ }
+ else if (XMLString::equals(ns, samlconstants::SAML1P_NS)) {
+ // Should be a samlp:Response, at least in OpenSAML.
+ const vector<saml1::Assertion*>& assertions = dynamic_cast<const saml1p::Response&>(message).getAssertions();
+ if (!assertions.empty()) {
+ const saml1::Assertion* a = assertions.front();
+ if (a->getIssuer()) {
+ issuer = saml2::IssuerBuilder::buildIssuer();
+ issuer->setName(a->getIssuer());
+ pair<bool,int> minor = a->getMinorVersion();
+ return make_pair(
+ issuer,
+ (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM
+ );
+ }
+ }
+ }
+ else if (XMLString::equals(ns, samlconstants::SAML1_NS)) {
+ // Should be a saml:Assertion.
+ const saml1::Assertion& a = dynamic_cast<const saml1::Assertion&>(message);
+ if (a.getIssuer()) {
+ issuer = saml2::IssuerBuilder::buildIssuer();
+ issuer->setName(a.getIssuer());
+ pair<bool,int> minor = a.getMinorVersion();
+ return make_pair(
+ issuer,
+ (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM
+ );
+ }
+ }
+ }
+ return pair<saml2::Issuer*,const XMLCh*>(NULL,NULL);
+}
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * SecurityPolicy.cpp
+ *
+ * Overall policy used to verify the security of an incoming message.
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "binding/SecurityPolicy.h"
+#include "saml2/core/Assertions.h"
+
+using namespace opensaml::saml2md;
+using namespace opensaml::saml2;
+using namespace opensaml;
+using namespace xmltooling;
+using namespace std;
+
+namespace opensaml {
+ SAML_DLLLOCAL PluginManager<SecurityPolicyRule,const DOMElement*>::Factory MessageFlowRuleFactory;
+ SAML_DLLLOCAL PluginManager<SecurityPolicyRule,const DOMElement*>::Factory MessageSigningRuleFactory;
+};
+
+void SAML_API opensaml::registerSecurityPolicyRules()
+{
+ SAMLConfig& conf=SAMLConfig::getConfig();
+ conf.SecurityPolicyRuleManager.registerFactory(MESSAGEFLOW_POLICY_RULE, MessageFlowRuleFactory);
+ conf.SecurityPolicyRuleManager.registerFactory(MESSAGESIGNING_POLICY_RULE, MessageSigningRuleFactory);
+}
+
+SecurityPolicy::~SecurityPolicy()
+{
+ delete m_issuer;
+}
+
+void SecurityPolicy::evaluate(const GenericRequest& request, const XMLObject& message)
+{
+ for (vector<const SecurityPolicyRule*>::const_iterator i=m_rules.begin(); i!=m_rules.end(); ++i) {
+
+ // Run the rule...
+ pair<Issuer*,const RoleDescriptor*> ident = (*i)->evaluate(request,message,m_metadata,&m_role,m_trust);
+
+ // Make sure returned issuer doesn't conflict.
+
+ if (ident.first) {
+ if (!issuerMatches(ident.first, m_issuer)) {
+ delete ident.first;
+ throw BindingException("Policy rules returned differing Issuers.");
+ }
+ delete m_issuer;
+ m_issuer=ident.first;
+ }
+
+ if (ident.second) {
+ if (m_issuerRole && ident.second!=m_issuerRole)
+ throw BindingException("Policy rules returned differing issuer RoleDescriptors.");
+ m_issuerRole=ident.second;
+ }
+ }
+}
+
+void SecurityPolicy::setIssuer(saml2::Issuer* issuer)
+{
+ if (!issuerMatches(issuer, m_issuer)) {
+ delete issuer;
+ throw BindingException("Externally provided Issuer conflicts with policy results.");
+ }
+
+ delete m_issuer;
+ m_issuer=issuer;
+}
+
+void SecurityPolicy::setIssuerMetadata(const saml2md::RoleDescriptor* issuerRole)
+{
+ if (issuerRole && m_issuerRole && issuerRole!=m_issuerRole)
+ throw BindingException("Externally provided RoleDescriptor conflicts with policy results.");
+ m_issuerRole=issuerRole;
+}
+
+bool SecurityPolicy::issuerMatches(const Issuer* issuer1, const Issuer* issuer2) const
+{
+ // NULL matches anything for the purposes of this interface.
+ if (!issuer1 || !issuer2)
+ return true;
+
+ const XMLCh* op1=issuer1->getName();
+ const XMLCh* op2=issuer2->getName();
+ if (!op1 || !op2 || !XMLString::equals(op1,op2))
+ return false;
+
+ op1=issuer1->getFormat();
+ op2=issuer2->getFormat();
+ if (!XMLString::equals(op1 ? op1 : NameIDType::ENTITY, op2 ? op2 : NameIDType::ENTITY))
+ return false;
+
+ op1=issuer1->getNameQualifier();
+ op2=issuer2->getNameQualifier();
+ if (!XMLString::equals(op1 ? op1 : &chNull, op2 ? op2 : &chNull))
+ return false;
+
+ op1=issuer1->getSPNameQualifier();
+ op2=issuer2->getSPNameQualifier();
+ if (!XMLString::equals(op1 ? op1 : &chNull, op2 ? op2 : &chNull))
+ return false;
+
+ return true;
+}
RelativePath=".\saml2\binding\impl\SAML2POSTEncoder.cpp"\r
>\r
</File>\r
+ <File\r
+ RelativePath=".\saml2\binding\impl\SAML2Redirect.cpp"\r
+ >\r
+ </File>\r
</Filter>\r
</Filter>\r
</Filter>\r
>\r
</File>\r
<File\r
+ RelativePath=".\binding\impl\MessageFlowRule.cpp"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\binding\impl\MessageSigningRule.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\binding\impl\SAMLArtifact.cpp"\r
>\r
</File>\r
<File\r
+ RelativePath=".\binding\impl\SecurityPolicy.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\binding\impl\URLEncoder.cpp"\r
>\r
</File>\r
</Filter>\r
</Filter>\r
+ <Filter\r
+ Name="zlib"\r
+ >\r
+ <File\r
+ RelativePath=".\zlib\adler32.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\zlib\crc32.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\zlib\inffast.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\zlib\inflate.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\zlib\inftrees.c"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\zlib\zutil.c"\r
+ >\r
+ </File>\r
+ </Filter>\r
</Filter>\r
<Filter\r
Name="Header Files"\r
>\r
</File>\r
<File\r
+ RelativePath=".\RootObject.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\SAMLConfig.h"\r
>\r
</File>\r
RelativePath=".\saml2\binding\SAML2POSTEncoder.h"\r
>\r
</File>\r
+ <File\r
+ RelativePath=".\saml2\binding\SAML2Redirect.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\saml2\binding\SAML2RedirectDecoder.h"\r
+ >\r
+ </File>\r
</Filter>\r
</Filter>\r
<Filter\r
>\r
</File>\r
<File\r
+ RelativePath=".\binding\GenericRequest.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\binding\GenericResponse.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\binding\HTTPRequest.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\binding\HTTPResponse.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\binding\MessageDecoder.h"\r
>\r
</File>\r
>\r
</File>\r
<File\r
+ RelativePath=".\binding\MessageFlowRule.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\binding\MessageSigningRule.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\binding\SAMLArtifact.h"\r
>\r
</File>\r
<File\r
+ RelativePath=".\binding\SecurityPolicy.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\binding\SecurityPolicyRule.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\binding\URLEncoder.h"\r
>\r
</File>\r
</Filter>\r
+ <Filter\r
+ Name="zlib"\r
+ >\r
+ <File\r
+ RelativePath=".\zlib\crc32.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\zlib\inffast.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\zlib\inffixed.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\zlib\inflate.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\zlib\inftrees.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\zlib\zconf.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\zlib\zlib.h"\r
+ >\r
+ </File>\r
+ <File\r
+ RelativePath=".\zlib\zutil.h"\r
+ >\r
+ </File>\r
+ </Filter>\r
</Filter>\r
<Filter\r
Name="Resource Files"\r
Response* decode(
std::string& relayState,
- const saml2md::RoleDescriptor*& issuer,
- const XMLCh*& securityMech,
- const HTTPRequest& httpRequest,
- const saml2md::MetadataProvider* metadataProvider=NULL,
- const xmltooling::QName* role=NULL,
- const TrustEngine* trustEngine=NULL
+ const GenericRequest& genericRequest,
+ SecurityPolicy& policy
) const;
};
virtual ~SAML1ArtifactEncoder();
long encode(
- HTTPResponse& httpResponse,
+ GenericResponse& genericResponse,
xmltooling::XMLObject* xmlObject,
const char* destination,
const char* recipientID=NULL,
Response* decode(
std::string& relayState,
- const saml2md::RoleDescriptor*& issuer,
- const XMLCh*& securityMech,
- const HTTPRequest& httpRequest,
- const saml2md::MetadataProvider* metadataProvider=NULL,
- const xmltooling::QName* role=NULL,
- const TrustEngine* trustEngine=NULL
+ const GenericRequest& genericRequest,
+ SecurityPolicy& policy
) const;
};
virtual ~SAML1POSTEncoder();
long encode(
- HTTPResponse& httpResponse,
+ GenericResponse& genericResponse,
xmltooling::XMLObject* xmlObject,
const char* destination,
const char* recipientID=NULL,
#include "internal.h"
#include "exceptions.h"
+#include "binding/HTTPRequest.h"
#include "saml/binding/SAMLArtifact.h"
#include "saml1/binding/SAML1ArtifactDecoder.h"
#include "saml2/metadata/Metadata.h"
#include "saml2/metadata/MetadataProvider.h"
-#include "security/X509TrustEngine.h"
#include <log4cpp/Category.hh>
#include <xmltooling/util/NDC.h>
using namespace opensaml::saml2md;
using namespace opensaml::saml1p;
-using namespace opensaml::saml1;
using namespace opensaml;
-using namespace xmlsignature;
using namespace xmltooling;
using namespace log4cpp;
using namespace std;
Response* SAML1ArtifactDecoder::decode(
string& relayState,
- const RoleDescriptor*& issuer,
- const XMLCh*& securityMech,
- const HTTPRequest& httpRequest,
- const MetadataProvider* metadataProvider,
- const QName* role,
- const opensaml::TrustEngine* trustEngine
+ const GenericRequest& genericRequest,
+ SecurityPolicy& policy
) const
{
#ifdef _DEBUG
Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML1Artifact");
log.debug("validating input");
- if (strcmp(httpRequest.getMethod(),"GET"))
+ const HTTPRequest* httpRequest=dynamic_cast<const HTTPRequest*>(&genericRequest);
+ if (!httpRequest) {
+ log.error("unable to cast request to HTTPRequest type");
+ return NULL;
+ }
+ if (strcmp(httpRequest->getMethod(),"GET"))
return NULL;
vector<const char*> SAMLart;
- const char* TARGET = httpRequest.getParameter("TARGET");
- if (httpRequest.getParameters("SAMLart", SAMLart)==0 || !TARGET)
+ const char* TARGET = httpRequest->getParameter("TARGET");
+ if (httpRequest->getParameters("SAMLart", SAMLart)==0 || !TARGET)
return NULL;
relayState = TARGET;
- if (!m_artifactResolver || !metadataProvider)
- throw BindingException("Artifact binding requires ArtifactResolver and MetadataProvider implementations be supplied.");
+ if (!m_artifactResolver || !policy.getMetadataProvider() || !policy.getRole())
+ throw BindingException("Artifact profile requires ArtifactResolver and MetadataProvider implementations be supplied.");
// Import the artifacts.
vector<SAMLArtifact*> artifacts;
}
}
- issuer = NULL;
- securityMech = false;
log.debug("attempting to determine source of artifact(s)...");
- const EntityDescriptor* provider=metadataProvider->getEntityDescriptor(artifacts.front());
+ const EntityDescriptor* provider=policy.getMetadataProvider()->getEntityDescriptor(artifacts.front());
if (!provider) {
log.error(
"metadata lookup failed, unable to determine issuer of artifact (0x%s)",
}
log.debug("attempting to find artifact issuing role...");
- issuer=provider->getRoleDescriptor(*role, samlconstants::SAML11_PROTOCOL_ENUM);
- if (!issuer)
- issuer=provider->getRoleDescriptor(*role, samlconstants::SAML10_PROTOCOL_ENUM);
- if (!issuer || !dynamic_cast<const IDPSSODescriptor*>(issuer)) {
- log.error("unable to find compatible SAML role (%s) in metadata", role->toString().c_str());
+ const RoleDescriptor* roledesc=provider->getRoleDescriptor(*(policy.getRole()), samlconstants::SAML11_PROTOCOL_ENUM);
+ if (!roledesc)
+ roledesc=provider->getRoleDescriptor(*(policy.getRole()), samlconstants::SAML10_PROTOCOL_ENUM);
+ if (!roledesc || !dynamic_cast<const IDPSSODescriptor*>(roledesc)) {
+ log.error("unable to find compatible SAML role (%s) in metadata", policy.getRole()->toString().c_str());
for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
BindingException ex("Unable to find compatible metadata role for artifact issuer.");
annotateException(&ex,provider); // throws it
try {
auto_ptr<Response> response(
- m_artifactResolver->resolve(
- securityMech,
- artifacts,
- dynamic_cast<const IDPSSODescriptor&>(*issuer),
- dynamic_cast<const X509TrustEngine*>(trustEngine)
- )
+ m_artifactResolver->resolve(artifacts, dynamic_cast<const IDPSSODescriptor&>(*roledesc), policy)
);
- if (trustEngine && response->getSignature()) {
- if (!trustEngine->validate(*(response->getSignature()), *issuer, metadataProvider->getKeyResolver())) {
- log.error("unable to verify signature on message with supplied trust engine");
- throw BindingException("Message signature failed verification.");
- }
- else if (!securityMech) {
- securityMech = samlconstants::SAML1P_NS;
- }
- }
- else if (!securityMech) {
- log.warn("unable to authenticate the message, leaving untrusted");
- }
+ policy.evaluate(genericRequest, *(response.get()));
for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
return response.release();
}
catch (XMLToolingException& ex) {
for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
- annotateException(&ex,issuer,false);
+ annotateException(&ex,roledesc,false);
throw;
}
}
#include "internal.h"
#include "exceptions.h"
#include "binding/ArtifactMap.h"
+#include "binding/HTTPResponse.h"
#include "binding/SAMLArtifact.h"
#include "binding/URLEncoder.h"
#include "saml1/binding/SAML1ArtifactEncoder.h"
SAML1ArtifactEncoder::~SAML1ArtifactEncoder() {}
long SAML1ArtifactEncoder::encode(
- HTTPResponse& httpResponse,
+ GenericResponse& genericResponse,
XMLObject* xmlObject,
const char* destination,
const char* recipientID,
xmltooling::NDC ndc("encode");
#endif
Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML1Artifact");
+
log.debug("validating input");
-
+ HTTPResponse* httpResponse=dynamic_cast<HTTPResponse*>(&genericResponse);
+ if (!httpResponse)
+ throw BindingException("Unable to cast response interface to HTTPResponse type.");
if (xmlObject->getParent())
throw BindingException("Cannot encode XML content with parent.");
Assertion* assertion = dynamic_cast<Assertion*>(xmlObject);
URLEncoder* escaper = SAMLConfig::getConfig().getURLEncoder();
loc = loc + "SAMLart=" + escaper->encode(artifact->encode().c_str()) + "&TARGET=" + escaper->encode(relayState);
log.debug("message encoded, sending redirect to client");
- return httpResponse.sendRedirect(loc.c_str());
+ return httpResponse->sendRedirect(loc.c_str());
}
#include "internal.h"
#include "exceptions.h"
+#include "binding/HTTPRequest.h"
#include "saml1/core/Assertions.h"
#include "saml1/binding/SAML1POSTDecoder.h"
#include "saml2/metadata/Metadata.h"
#include "saml2/metadata/MetadataProvider.h"
-#include "security/X509TrustEngine.h"
#include <log4cpp/Category.hh>
#include <xercesc/util/Base64.hpp>
#include <xmltooling/util/NDC.h>
-#include <xmltooling/util/ReplayCache.h>
#include <xmltooling/validation/ValidatorSuite.h>
using namespace opensaml::saml2md;
using namespace opensaml::saml1p;
using namespace opensaml::saml1;
using namespace opensaml;
-using namespace xmlsignature;
using namespace xmltooling;
using namespace log4cpp;
using namespace std;
Response* SAML1POSTDecoder::decode(
string& relayState,
- const RoleDescriptor*& issuer,
- const XMLCh*& securityMech,
- const HTTPRequest& httpRequest,
- const MetadataProvider* metadataProvider,
- const QName* role,
- const opensaml::TrustEngine* trustEngine
+ const GenericRequest& genericRequest,
+ SecurityPolicy& policy
) const
{
#ifdef _DEBUG
Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML1POST");
log.debug("validating input");
- if (strcmp(httpRequest.getMethod(),"POST"))
+ const HTTPRequest* httpRequest=dynamic_cast<const HTTPRequest*>(&genericRequest);
+ if (!httpRequest) {
+ log.error("unable to cast request to HTTPRequest type");
return NULL;
- const char* samlResponse = httpRequest.getParameter("SAMLResponse");
- const char* TARGET = httpRequest.getParameter("TARGET");
+ }
+ if (strcmp(httpRequest->getMethod(),"POST"))
+ return NULL;
+ const char* samlResponse = httpRequest->getParameter("SAMLResponse");
+ const char* TARGET = httpRequest->getParameter("TARGET");
if (!samlResponse || !TARGET)
return NULL;
relayState = TARGET;
if (!response)
throw BindingException("Decoded message was not a SAML 1.x Response.");
- const EntityDescriptor* provider=NULL;
try {
if (!m_validate)
SchemaValidators.validate(xmlObject.get());
// Check recipient URL.
auto_ptr_char recipient(response->getRecipient());
- const char* recipient2 = httpRequest.getRequestURL();
+ const char* recipient2 = httpRequest->getRequestURL();
if (!recipient.get() || !*(recipient.get())) {
log.error("response missing Recipient attribute");
throw BindingException("SAML response did not contain Recipient attribute identifying intended destination.");
throw BindingException("SAML message delivered with POST to incorrect server URL.");
}
- // Check freshness.
- time_t now = time(NULL);
- if (response->getIssueInstant()->getEpoch() < now-(2*XMLToolingConfig::getConfig().clock_skew_secs))
- throw BindingException("Detected expired POST profile response.");
-
- // Check replay.
- ReplayCache* replayCache = XMLToolingConfig::getConfig().getReplayCache();
- if (replayCache) {
- auto_ptr_char id(response->getResponseID());
- if (!replayCache->check("SAML1POST", id.get(), response->getIssueInstant()->getEpoch() + (2*XMLToolingConfig::getConfig().clock_skew_secs))) {
- log.error("replay detected of response ID (%s)", id.get());
- throw BindingException("Rejecting replayed response ID ($1).", params(1,id.get()));
- }
- }
- else
- log.warn("replay cache was not provided, this is a serious security risk!");
-
- /* For SAML 1, the issuer can only be established from any assertions in the message.
- * Generally, errors aren't delivered like this, so there should be one.
- * The Issuer attribute is matched against metadata, and then trust checking can be
- * applied.
- */
- issuer = NULL;
- securityMech = NULL;
- log.debug("attempting to establish issuer and integrity of message...");
- const vector<Assertion*>& assertions=const_cast<const Response*>(response)->getAssertions();
- if (!assertions.empty()) {
- log.debug("searching metadata for assertion issuer...");
- provider=metadataProvider ? metadataProvider->getEntityDescriptor(assertions.front()->getIssuer()) : NULL;
- if (provider) {
- log.debug("matched assertion issuer against metadata, searching for applicable role...");
- pair<bool,int> minor = response->getMinorVersion();
- issuer=provider->getRoleDescriptor(
- *role,
- (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM
- );
- if (issuer) {
- if (trustEngine && response->getSignature()) {
- if (trustEngine->validate(*(response->getSignature()), *issuer, metadataProvider->getKeyResolver())) {
- securityMech = samlconstants::SAML1P_NS;
- }
- else {
- log.error("unable to verify signature on message with supplied trust engine");
- throw BindingException("Message signature failed verification.");
- }
- }
- else {
- log.warn("unable to authenticate the message, leaving untrusted");
- }
- }
- else {
- log.warn(
- "unable to find compatible SAML 1.%d role (%s) in metadata",
- (minor.first && minor.second==0) ? 0 : 1,
- role->toString().c_str()
- );
- }
- if (log.isDebugEnabled()) {
- auto_ptr_char iname(assertions.front()->getIssuer());
- log.debug("message from (%s), integrity %sverified", iname.get(), securityMech ? "" : "NOT ");
- }
- }
- else {
- auto_ptr_char temp(assertions.front()->getIssuer());
- log.warn("no metadata found, can't establish identity of issuer (%s)", temp.get());
- }
- }
- else {
- log.warn("no assertions found, can't establish identity of issuer");
- }
+ // Run through the policy.
+ policy.evaluate(genericRequest, *response);
}
catch (XMLToolingException& ex) {
+ // This is just to maximize the likelihood of attaching a source to the message for support purposes.
+ if (policy.getIssuerMetadata())
+ annotateException(&ex,policy.getIssuerMetadata()); // throws it
+
// Check for an Issuer.
- if (!provider) {
- const vector<Assertion*>& assertions=const_cast<const Response*>(response)->getAssertions();
- if (!assertions.empty() || !metadataProvider ||
- !(provider=metadataProvider->getEntityDescriptor(assertions.front()->getIssuer(), false))) {
- // Just record it.
- auto_ptr_char iname(assertions.front()->getIssuer());
- if (iname.get())
- ex.addProperty("entityID", iname.get());
- throw;
- }
+ const EntityDescriptor* provider=NULL;
+ const vector<Assertion*>& assertions=const_cast<const Response*>(response)->getAssertions();
+ if (!assertions.empty() || !policy.getMetadataProvider() ||
+ !(provider=policy.getMetadataProvider()->getEntityDescriptor(assertions.front()->getIssuer(), false))) {
+ // Just record it.
+ auto_ptr_char iname(assertions.front()->getIssuer());
+ if (iname.get())
+ ex.addProperty("entityID", iname.get());
+ throw;
}
- if (!issuer) {
+ if (policy.getRole()) {
pair<bool,int> minor = response->getMinorVersion();
- issuer=provider->getRoleDescriptor(
- *role,
+ const RoleDescriptor* roledesc=provider->getRoleDescriptor(
+ *(policy.getRole()),
(minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM
);
+ if (roledesc) annotateException(&ex,roledesc); // throws it
}
- if (issuer) annotateException(&ex,issuer); // throws it
annotateException(&ex,provider); // throws it
}
#include "internal.h"
#include "exceptions.h"
+#include "binding/HTTPResponse.h"
#include "saml1/binding/SAML1POSTEncoder.h"
#include "saml1/core/Protocols.h"
SAML1POSTEncoder::~SAML1POSTEncoder() {}
long SAML1POSTEncoder::encode(
- HTTPResponse& httpResponse,
+ GenericResponse& genericResponse,
XMLObject* xmlObject,
const char* destination,
const char* recipientID,
xmltooling::NDC ndc("encode");
#endif
Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML1POST");
+
log.debug("validating input");
-
+ HTTPResponse* httpResponse=dynamic_cast<HTTPResponse*>(&genericResponse);
+ if (!httpResponse)
+ throw BindingException("Unable to cast response interface to HTTPResponse type.");
if (xmlObject->getParent())
throw BindingException("Cannot encode XML content with parent.");
Response* response = dynamic_cast<Response*>(xmlObject);
params["TARGET"] = relayState;
stringstream s;
engine->run(infile, s, params);
- long ret = httpResponse.sendResponse(s);
+ httpResponse->setContentType("text/html");
+ long ret = httpResponse->sendResponse(s, HTTPResponse::SAML_HTTP_STATUS_OK);
// Cleanup by destroying XML.
delete xmlObject;
#ifndef __saml1_assertions_h__
#define __saml1_assertions_h__
-#include <saml/signature/SignableObject.h>
+#include <saml/RootObject.h>
#include <saml/util/SAMLConstants.h>
#include <xmltooling/AttributeExtensibleXMLObject.h>
static const XMLCh TYPE_NAME[];
END_XMLOBJECT;
- BEGIN_XMLOBJECT(SAML_API,Assertion,SignableObject,SAML 1.x Assertion element);
+ BEGIN_XMLOBJECT(SAML_API,Assertion,RootObject,SAML 1.x Assertion element);
DECL_INTEGER_ATTRIB(MinorVersion,MINORVERSION);
DECL_STRING_ATTRIB(AssertionID,ASSERTIONID);
DECL_STRING_ATTRIB(Issuer,ISSUER);
- DECL_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
+ DECL_INHERITED_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
DECL_TYPED_CHILD(Conditions);
DECL_TYPED_CHILD(Advice);
DECL_TYPED_CHILDREN(Statement);
DECL_TYPED_CHILDREN(AuthenticationStatement);
DECL_TYPED_CHILDREN(AttributeStatement);
DECL_TYPED_CHILDREN(AuthorizationDecisionStatement);
- DECL_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
+ DECL_INHERITED_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
/** AssertionType local name */
static const XMLCh TYPE_NAME[];
END_XMLOBJECT;
#ifndef __saml1_protocols_h__
#define __saml1_protocols_h__
-#include <saml/signature/SignableObject.h>
+#include <saml/RootObject.h>
#include <saml/util/SAMLConstants.h>
#include <xmltooling/AttributeExtensibleXMLObject.h>
static const XMLCh TYPE_NAME[];
END_XMLOBJECT;
- BEGIN_XMLOBJECT(SAML_API,RequestAbstractType,SignableObject,SAML 1.x RequestAbstractType base type);
+ BEGIN_XMLOBJECT(SAML_API,RequestAbstractType,RootObject,SAML 1.x RequestAbstractType base type);
DECL_INTEGER_ATTRIB(MinorVersion,MINORVERSION);
DECL_STRING_ATTRIB(RequestID,REQUESTID);
- DECL_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
+ DECL_INHERITED_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
DECL_TYPED_CHILDREN(RespondWith);
- DECL_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
+ DECL_INHERITED_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
/** RequestAbstractType local name */
static const XMLCh TYPE_NAME[];
END_XMLOBJECT;
static const XMLCh TYPE_NAME[];
END_XMLOBJECT;
- BEGIN_XMLOBJECT(SAML_API,ResponseAbstractType,SignableObject,SAML 1.x ResponseAbstractType base type);
+ BEGIN_XMLOBJECT(SAML_API,ResponseAbstractType,RootObject,SAML 1.x ResponseAbstractType base type);
DECL_INTEGER_ATTRIB(MinorVersion,MINORVERSION);
DECL_STRING_ATTRIB(ResponseID,RESPONSEID);
DECL_STRING_ATTRIB(InResponseTo,INRESPONSETO);
- DECL_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
+ DECL_INHERITED_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
DECL_STRING_ATTRIB(Recipient,RECIPIENT);
- DECL_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
+ DECL_INHERITED_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
/** ResponseAbstractType local name */
static const XMLCh TYPE_NAME[];
END_XMLOBJECT;
pair<bool,int> v = getMinorVersion();
return (!v.first || v.second > 0) ? m_AssertionID : NULL;
}
+ const XMLCh* getID() const {
+ return getAssertionID();
+ }
IMPL_STRING_ATTRIB(Issuer);
IMPL_DATETIME_ATTRIB(IssueInstant,0);
IMPL_TYPED_CHILD(Conditions);
pair<bool,int> v = getMinorVersion();
return (!v.first || v.second > 0) ? m_RequestID : NULL;
}
+ const XMLCh* getID() const {
+ return getRequestID();
+ }
IMPL_DATETIME_ATTRIB(IssueInstant,0);
IMPL_TYPED_CHILDREN(RespondWith,m_pos_Signature);
pair<bool,int> v = getMinorVersion();
return (!v.first || v.second > 0) ? m_ResponseID : NULL;
}
+ const XMLCh* getID() const {
+ return getResponseID();
+ }
IMPL_STRING_ATTRIB(InResponseTo);
IMPL_DATETIME_ATTRIB(IssueInstant,0);
IMPL_STRING_ATTRIB(Recipient);
xmltooling::XMLObject* decode(
std::string& relayState,
- const saml2md::RoleDescriptor*& issuer,
- const XMLCh*& securityMech,
- const HTTPRequest& httpRequest,
- const saml2md::MetadataProvider* metadataProvider=NULL,
- const xmltooling::QName* role=NULL,
- const TrustEngine* trustEngine=NULL
+ const GenericRequest& genericRequest,
+ SecurityPolicy& policy
) const;
-
- protected:
- bool issuerMatches(const saml2::Issuer* messageIssuer, const XMLCh* expectedIssuer) const;
};
};
virtual ~SAML2ArtifactEncoder();
long encode(
- HTTPResponse& httpResponse,
+ GenericResponse& genericResponse,
xmltooling::XMLObject* xmlObject,
const char* destination,
const char* recipientID=NULL,
*/
#include <saml/binding/MessageDecoder.h>
+#include <saml/saml2/core/Assertions.h>
namespace opensaml {
+
namespace saml2p {
/**
SAML2POSTDecoder(const DOMElement* e);
virtual ~SAML2POSTDecoder();
- xmltooling::XMLObject* decode(
+ saml2::RootObject* decode(
std::string& relayState,
- const saml2md::RoleDescriptor*& issuer,
- const XMLCh*& securityMech,
- const HTTPRequest& httpRequest,
- const saml2md::MetadataProvider* metadataProvider=NULL,
- const xmltooling::QName* role=NULL,
- const TrustEngine* trustEngine=NULL
+ const GenericRequest& genericRequest,
+ SecurityPolicy& policy
) const;
};
virtual ~SAML2POSTEncoder();
long encode(
- HTTPResponse& httpResponse,
+ GenericResponse& genericResponse,
xmltooling::XMLObject* xmlObject,
const char* destination,
const char* recipientID=NULL,
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/saml2/binding/SAML2Redirect.h
+ *
+ * SAML 2.0 HTTP Redirect compression functionality
+ */
+
+#include <saml/base.h>
+#include <iostream>
+
+namespace opensaml {
+ namespace saml2p {
+
+ unsigned int inflate(char* in, unsigned int inlen, std::ostream& out);
+
+ };
+};
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/saml2/binding/SAML2RedirectDecoder.h
+ *
+ * SAML 2.0 HTTP Redirect binding message decoder
+ */
+
+#include <saml/binding/MessageDecoder.h>
+
+namespace opensaml {
+ namespace saml2p {
+
+ /**
+ * SAML 2.0 HTTP Redirect binding message decoder
+ */
+ class SAML_API SAML2RedirectDecoder : public MessageDecoder
+ {
+ public:
+ SAML2RedirectDecoder(const DOMElement* e);
+ virtual ~SAML2RedirectDecoder();
+
+ xmltooling::XMLObject* decode(
+ std::string& relayState,
+ const GenericRequest& genericRequest,
+ SecurityPolicy& policy
+ ) const;
+ };
+
+ };
+};
#include "internal.h"
#include "exceptions.h"
+#include "binding/HTTPRequest.h"
#include "saml/binding/SAMLArtifact.h"
+#include "saml2/binding/SAML2Artifact.h"
+#include "saml2/binding/SAML2ArtifactDecoder.h"
#include "saml2/core/Protocols.h"
#include "saml2/metadata/Metadata.h"
#include "saml2/metadata/MetadataProvider.h"
-#include "saml2/binding/SAML2Artifact.h"
-#include "saml2/binding/SAML2ArtifactDecoder.h"
-#include "security/X509TrustEngine.h"
#include <log4cpp/Category.hh>
#include <xmltooling/util/NDC.h>
using namespace opensaml::saml2p;
using namespace opensaml::saml2;
using namespace opensaml;
-using namespace xmlsignature;
using namespace xmltooling;
using namespace log4cpp;
using namespace std;
XMLObject* SAML2ArtifactDecoder::decode(
string& relayState,
- const RoleDescriptor*& issuer,
- const XMLCh*& securityMech,
- const HTTPRequest& httpRequest,
- const MetadataProvider* metadataProvider,
- const QName* role,
- const opensaml::TrustEngine* trustEngine
+ const GenericRequest& genericRequest,
+ SecurityPolicy& policy
) const
{
#ifdef _DEBUG
Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML2Artifact");
log.debug("validating input");
- const char* SAMLart = httpRequest.getParameter("SAMLart");
+ const HTTPRequest* httpRequest=dynamic_cast<const HTTPRequest*>(&genericRequest);
+ if (!httpRequest) {
+ log.error("unable to cast request to HTTPRequest type");
+ return NULL;
+ }
+ const char* SAMLart = httpRequest->getParameter("SAMLart");
if (!SAMLart)
return NULL;
- const char* state = httpRequest.getParameter("RelayState");
+ const char* state = httpRequest->getParameter("RelayState");
if (state)
relayState = state;
- if (!m_artifactResolver || !metadataProvider)
+ if (!m_artifactResolver || !policy.getMetadataProvider() || !policy.getRole())
throw BindingException("Artifact binding requires ArtifactResolver and MetadataProvider implementations be supplied.");
// Import the artifact.
SAMLArtifact* artifact=NULL;
- ReplayCache* replayCache = XMLToolingConfig::getConfig().getReplayCache();
try {
log.debug("processing encoded artifact (%s)", SAMLart);
// Check replay.
+ ReplayCache* replayCache = XMLToolingConfig::getConfig().getReplayCache();
if (replayCache) {
if (!replayCache->check("SAML2Artifact", SAMLart, time(NULL) + (2*XMLToolingConfig::getConfig().clock_skew_secs))) {
log.error("replay detected of artifact (%s)", SAMLart);
delete artifact;
}
- issuer = NULL;
- securityMech = NULL;
log.debug("attempting to determine source of artifact...");
- const EntityDescriptor* provider=metadataProvider->getEntityDescriptor(artifact);
+ const EntityDescriptor* provider=policy.getMetadataProvider()->getEntityDescriptor(artifact);
if (!provider) {
log.error(
"metadata lookup failed, unable to determine issuer of artifact (0x%s)",
}
log.debug("attempting to find artifact issuing role...");
- issuer=provider->getRoleDescriptor(*role, samlconstants::SAML20P_NS);
- if (!issuer || !dynamic_cast<const SSODescriptorType*>(issuer)) {
- log.error("unable to find compatible SAML role (%s) in metadata", role->toString().c_str());
+ const RoleDescriptor* roledesc=provider->getRoleDescriptor(*(policy.getRole()), samlconstants::SAML20P_NS);
+ if (!roledesc || !dynamic_cast<const SSODescriptorType*>(roledesc)) {
+ log.error("unable to find compatible SAML role (%s) in metadata", policy.getRole()->toString().c_str());
BindingException ex("Unable to find compatible metadata role for artifact issuer.");
annotateException(&ex,provider); // throws it
}
try {
auto_ptr<ArtifactResponse> response(
- m_artifactResolver->resolve(
- securityMech,
- *(artifact2.get()),
- dynamic_cast<const SSODescriptorType&>(*issuer),
- dynamic_cast<const X509TrustEngine*>(trustEngine)
- )
+ m_artifactResolver->resolve(*(artifact2.get()), dynamic_cast<const SSODescriptorType&>(*roledesc), policy)
);
- // Check Issuer of outer message.
- if (!issuerMatches(response->getIssuer(), provider->getEntityID())) {
- log.error("issuer of ArtifactResponse did not match source of artifact");
- throw BindingException("Issuer of ArtifactResponse did not match source of artifact.");
- }
+ policy.evaluate(genericRequest, *(response.get()));
- // Extract payload and check that Issuer.
+ // Extract payload and check that message.
XMLObject* payload = response->getPayload();
- RequestAbstractType* req = NULL;
- StatusResponseType* res = dynamic_cast<StatusResponseType*>(payload);
- if (!res)
- req = dynamic_cast<RequestAbstractType*>(payload);
- if (!res && !req)
- throw BindingException("ArtifactResponse payload was not a recognized SAML 2.0 protocol message.");
-
- if (!issuerMatches(res ? res->getIssuer() : req->getIssuer(), provider->getEntityID())) {
- log.error("issuer of ArtifactResponse payload did not match source of artifact");
- throw BindingException("Issuer of ArtifactResponse payload did not match source of artifact.");
- }
-
- // Check payload freshness.
- time_t now = time(NULL);
- if ((res ? res->getIssueInstant() : req->getIssueInstant())->getEpoch() < now-(2*XMLToolingConfig::getConfig().clock_skew_secs))
- throw BindingException("Detected expired ArtifactResponse payload.");
+ policy.evaluate(genericRequest, *payload);
- // Check replay.
- if (replayCache) {
- auto_ptr_char mid(res ? res->getID() : req->getID());
- if (!replayCache->check("SAML2ArtifactPayload", mid.get(), now + (2*XMLToolingConfig::getConfig().clock_skew_secs))) {
- log.error("replay detected of ArtifactResponse payload message ID (%s)", mid.get());
- throw BindingException("Rejecting replayed ArtifactResponse payload ($1).", params(1,mid.get()));
- }
- }
-
- // Check signatures.
- if (trustEngine) {
- if (response->getSignature()) {
- if (!trustEngine->validate(*(response->getSignature()), *issuer, metadataProvider->getKeyResolver())) {
- log.error("unable to verify signature on ArtifactResponse message with supplied trust engine");
- throw BindingException("Message signature failed verification.");
- }
- else if (!securityMech) {
- securityMech = samlconstants::SAML20P_NS;
- }
- }
- Signature* sig = (res ? res->getSignature() : req->getSignature());
- if (sig) {
- if (!trustEngine->validate(*sig, *issuer, metadataProvider->getKeyResolver())) {
- log.error("unable to verify signature on ArtifactResponse payload with supplied trust engine");
- throw BindingException("Message signature failed verification.");
- }
- else if (!securityMech) {
- securityMech = samlconstants::SAML20P_NS;
- }
- }
- }
-
- if (!securityMech) {
- log.warn("unable to authenticate ArtifactResponse message or payload, leaving untrusted");
- }
-
// Return the payload only.
response.release();
payload->detach();
return payload;
}
catch (XMLToolingException& ex) {
- annotateException(&ex,issuer,false);
+ annotateException(&ex,roledesc,false);
throw;
}
}
-
-bool SAML2ArtifactDecoder::issuerMatches(const Issuer* messageIssuer, const XMLCh* expectedIssuer) const
-{
- if (messageIssuer && messageIssuer->getName()) {
- if (messageIssuer->getFormat() && !XMLString::equals(messageIssuer->getFormat(), NameIDType::ENTITY))
- return false;
- else if (!XMLString::equals(expectedIssuer, messageIssuer->getName()))
- return false;
- }
- return true;
-}
-
#include "internal.h"
#include "exceptions.h"
#include "binding/ArtifactMap.h"
+#include "binding/HTTPResponse.h"
#include "binding/URLEncoder.h"
#include "saml2/binding/SAML2Artifact.h"
#include "saml2/binding/SAML2ArtifactEncoder.h"
SAML2ArtifactEncoder::~SAML2ArtifactEncoder() {}
long SAML2ArtifactEncoder::encode(
- HTTPResponse& httpResponse,
+ GenericResponse& genericResponse,
xmltooling::XMLObject* xmlObject,
const char* destination,
const char* recipientID,
xmltooling::NDC ndc("encode");
#endif
Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML2Artifact");
+
log.debug("validating input");
-
+ HTTPResponse* httpResponse=dynamic_cast<HTTPResponse*>(&genericResponse);
+ if (!httpResponse)
+ throw BindingException("Unable to cast response interface to HTTPResponse type.");
if (relayState && strlen(relayState)>80)
throw BindingException("RelayState cannot exceed 80 bytes in length.");
if (relayState)
loc = loc + "&RelayState=" + escaper->encode(relayState);
log.debug("message encoded, sending redirect to client");
- return httpResponse.sendRedirect(loc.c_str());
+ return httpResponse->sendRedirect(loc.c_str());
}
else {
// Push message into template and send result to client.
params["RelayState"] = relayState;
stringstream s;
engine->run(infile, s, params);
- return httpResponse.sendResponse(s);
+ httpResponse->setContentType("text/html");
+ return httpResponse->sendResponse(s, HTTPResponse::SAML_HTTP_STATUS_OK);
}
}
#include "internal.h"
#include "exceptions.h"
+#include "binding/HTTPRequest.h"
#include "saml2/binding/SAML2POSTDecoder.h"
#include "saml2/core/Protocols.h"
#include "saml2/metadata/Metadata.h"
#include "saml2/metadata/MetadataProvider.h"
-#include "security/X509TrustEngine.h"
#include <log4cpp/Category.hh>
#include <xercesc/util/Base64.hpp>
#include <xmltooling/util/NDC.h>
-#include <xmltooling/util/ReplayCache.h>
#include <xmltooling/validation/ValidatorSuite.h>
using namespace opensaml::saml2md;
using namespace opensaml::saml2p;
using namespace opensaml::saml2;
using namespace opensaml;
-using namespace xmlsignature;
using namespace xmltooling;
using namespace log4cpp;
using namespace std;
SAML2POSTDecoder::~SAML2POSTDecoder() {}
-XMLObject* SAML2POSTDecoder::decode(
- string& relayState,
- const RoleDescriptor*& issuer,
- const XMLCh*& securityMech,
- const HTTPRequest& httpRequest,
- const MetadataProvider* metadataProvider,
- const QName* role,
- const opensaml::TrustEngine* trustEngine
+saml2::RootObject* SAML2POSTDecoder::decode(
+ std::string& relayState,
+ const GenericRequest& genericRequest,
+ SecurityPolicy& policy
) const
{
#ifdef _DEBUG
Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML2POST");
log.debug("validating input");
- if (strcmp(httpRequest.getMethod(),"POST"))
+ const HTTPRequest* httpRequest=dynamic_cast<const HTTPRequest*>(&genericRequest);
+ if (!httpRequest) {
+ log.error("unable to cast request to HTTPRequest type");
return NULL;
- const char* msg = httpRequest.getParameter("SAMLResponse");
+ }
+ if (strcmp(httpRequest->getMethod(),"POST"))
+ return NULL;
+ const char* msg = httpRequest->getParameter("SAMLResponse");
if (!msg)
- msg = httpRequest.getParameter("SAMLRequest");
+ msg = httpRequest->getParameter("SAMLRequest");
if (!msg)
return NULL;
- const char* state = httpRequest.getParameter("RelayState");
+ const char* state = httpRequest->getParameter("RelayState");
if (state)
relayState = state;
else
auto_ptr<XMLObject> xmlObject(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true));
janitor.release();
+ saml2::RootObject* root = NULL;
StatusResponseType* response = NULL;
RequestAbstractType* request = dynamic_cast<RequestAbstractType*>(xmlObject.get());
if (!request) {
response = dynamic_cast<StatusResponseType*>(xmlObject.get());
if (!response)
throw BindingException("XML content for SAML 2.0 HTTP-POST Decoder must be a SAML 2.0 protocol message.");
+ root = static_cast<saml2::RootObject*>(response);
}
-
- /* For SAML 2, the issuer can be established either from the message, or in some profiles
- * it's possible to omit it and defer to assertions in a Response.
- * The Issuer is later matched against metadata, and then trust checking can be applied.
- */
- const Issuer* claimedIssuer = request ? request->getIssuer() : response->getIssuer();
- if (!claimedIssuer) {
- // Check assertion option. I cannot resist the variable name, for the sake of google.
- const Response* assbag = dynamic_cast<const Response*>(response);
- if (assbag) {
- const vector<Assertion*>& assertions=assbag->getAssertions();
- if (!assertions.empty())
- claimedIssuer = assertions.front()->getIssuer();
- }
+ else {
+ root = static_cast<saml2::RootObject*>(request);
}
-
- const EntityDescriptor* provider=NULL;
+
try {
if (!m_validate)
SchemaValidators.validate(xmlObject.get());
- Signature* signature = request ? request->getSignature() : response->getSignature();
-
// Check destination URL.
auto_ptr_char dest(request ? request->getDestination() : response->getDestination());
- const char* dest2 = httpRequest.getRequestURL();
- if (signature && !dest.get() || !*(dest.get())) {
+ const char* dest2 = httpRequest->getRequestURL();
+ if (root->getSignature() && !dest.get() || !*(dest.get())) {
log.error("signed SAML message missing Destination attribute");
throw BindingException("Signed SAML message missing Destination attribute identifying intended destination.");
}
throw BindingException("SAML message delivered with POST to incorrect server URL.");
}
- // Check freshness.
- time_t now = time(NULL);
- if ((request ? request->getIssueInstant()->getEpoch() : response->getIssueInstant()->getEpoch())
- < now-(2*XMLToolingConfig::getConfig().clock_skew_secs))
- throw BindingException("Detected expired POST binding message.");
-
- // Check replay.
- ReplayCache* replayCache = XMLToolingConfig::getConfig().getReplayCache();
- if (replayCache) {
- auto_ptr_char id(xmlObject->getXMLID());
- if (!replayCache->check("SAML2POST", id.get(), response->getIssueInstant()->getEpoch() + (2*XMLToolingConfig::getConfig().clock_skew_secs))) {
- log.error("replay detected of response ID (%s)", id.get());
- throw BindingException("Rejecting replayed response ID ($1).", params(1,id.get()));
- }
- }
- else
- log.warn("replay cache was not provided, this is a serious security risk!");
-
- issuer = NULL;
- securityMech = false;
- log.debug("attempting to establish issuer and integrity of message...");
-
- // If we can't identify the issuer, we're done, since we can't lookup or verify anything.
- if (!claimedIssuer || !claimedIssuer->getName()) {
- log.warn("unable to establish identity of message issuer");
- return xmlObject.release();
- }
- else if (claimedIssuer->getFormat() && !XMLString::equals(claimedIssuer->getFormat(), NameIDType::ENTITY)) {
- auto_ptr_char iformat(claimedIssuer->getFormat());
- log.warn("message issuer was in an unsupported format (%s)", iformat.get());
- return xmlObject.release();
- }
-
- log.debug("searching metadata for assertion issuer...");
- provider=metadataProvider ? metadataProvider->getEntityDescriptor(claimedIssuer->getName()) : NULL;
- if (provider) {
- log.debug("matched assertion issuer against metadata, searching for applicable role...");
- issuer=provider->getRoleDescriptor(*role, samlconstants::SAML20P_NS);
- if (issuer) {
- if (trustEngine && signature) {
- if (!trustEngine->validate(*signature, *issuer, metadataProvider->getKeyResolver())) {
- log.error("unable to verify signature on message with supplied trust engine");
- throw BindingException("Message signature failed verification.");
- }
- else {
- securityMech = samlconstants::SAML20P_NS;
- }
- }
- else {
- log.warn("unable to authenticate the message, leaving untrusted");
- }
- }
- else {
- log.warn("unable to find compatible SAML 2.0 role (%s) in metadata", role->toString().c_str());
- }
- if (log.isDebugEnabled()) {
- auto_ptr_char iname(provider->getEntityID());
- log.debug("message from (%s), integrity %sverified", iname.get(), securityMech ? "" : "NOT ");
- }
- }
- else {
- auto_ptr_char temp(claimedIssuer->getName());
- log.warn("no metadata found, can't establish identity of issuer (%s)", temp.get());
- }
+ // Run through the policy.
+ policy.evaluate(genericRequest, *response);
}
catch (XMLToolingException& ex) {
- if (!provider) {
- if (!claimedIssuer || !claimedIssuer->getName())
- throw;
- if (!metadataProvider || !(provider=metadataProvider->getEntityDescriptor(claimedIssuer->getName(), false))) {
- // Just record it.
- auto_ptr_char iname(claimedIssuer->getName());
- if (iname.get())
- ex.addProperty("entityID", iname.get());
- throw;
+ // This is just to maximize the likelihood of attaching a source to the message for support purposes.
+ if (policy.getIssuerMetadata())
+ annotateException(&ex,policy.getIssuerMetadata()); // throws it
+
+ const Issuer* claimedIssuer = root->getIssuer();
+ if (!claimedIssuer) {
+ // Check for assertions.
+ const Response* assbag = dynamic_cast<Response*>(response);
+ if (assbag) {
+ const vector<Assertion*>& assertions=assbag->getAssertions();
+ if (!assertions.empty())
+ claimedIssuer = assertions.front()->getIssuer();
}
}
- if (!issuer)
- issuer=provider->getRoleDescriptor(*role, samlconstants::SAML20P_NS);
- if (issuer) annotateException(&ex,issuer); // throws it
+
+ if (!claimedIssuer || !claimedIssuer->getName())
+ throw;
+ const EntityDescriptor* provider=NULL;
+ if (!policy.getMetadataProvider() ||
+ !(provider=policy.getMetadataProvider()->getEntityDescriptor(claimedIssuer->getName(), false))) {
+ // Just record it.
+ auto_ptr_char iname(claimedIssuer->getName());
+ if (iname.get())
+ ex.addProperty("entityID", iname.get());
+ throw;
+ }
+
+ if (policy.getRole()) {
+ const RoleDescriptor* roledesc=provider->getRoleDescriptor(*(policy.getRole()), samlconstants::SAML20P_NS);
+ if (roledesc) annotateException(&ex,roledesc); // throws it
+ }
annotateException(&ex,provider); // throws it
}
- return xmlObject.release();
+ xmlObject.release();
+ return root;
}
#include "internal.h"
#include "exceptions.h"
+#include "binding/HTTPResponse.h"
#include "saml2/binding/SAML2POSTEncoder.h"
#include "saml2/core/Protocols.h"
SAML2POSTEncoder::~SAML2POSTEncoder() {}
long SAML2POSTEncoder::encode(
- HTTPResponse& httpResponse,
+ GenericResponse& genericResponse,
XMLObject* xmlObject,
const char* destination,
const char* recipientID,
xmltooling::NDC ndc("encode");
#endif
Category& log = Category::getInstance(SAML_LOGCAT".MessageEncoder.SAML2POST");
+
log.debug("validating input");
-
+ HTTPResponse* httpResponse=dynamic_cast<HTTPResponse*>(&genericResponse);
+ if (!httpResponse)
+ throw BindingException("Unable to cast response interface to HTTPResponse type.");
if (xmlObject->getParent())
throw BindingException("Cannot encode XML content with parent.");
params["RelayState"] = relayState;
stringstream s;
engine->run(infile, s, params);
- long ret = httpResponse.sendResponse(s);
+ httpResponse->setContentType("text/html");
+ long ret = httpResponse->sendResponse(s, HTTPResponse::SAML_HTTP_STATUS_OK);
// Cleanup by destroying XML.
delete xmlObject;
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/saml2/binding/SAML2Redirect.h
+ *
+ * SAML 2.0 HTTP Redirect compression functionality
+ */
+
+#include "internal.h"
+#include "saml2/binding/SAML2Redirect.h"
+#include "zlib/zlib.h"
+
+#include <log4cpp/Category.hh>
+#include <xmltooling/util/NDC.h>
+
+using namespace log4cpp;
+using namespace std;
+
+namespace {
+ extern "C" {
+ voidpf saml_zalloc(void* opaque, uInt items, uInt size)
+ {
+ return malloc(items*size);
+ }
+
+ void saml_zfree(void* opaque, voidpf addr)
+ {
+ free(addr);
+ }
+ };
+};
+
+unsigned int opensaml::saml2p::inflate(char* in, unsigned int in_len, ostream& out)
+{
+#ifdef _DEBUG
+ xmltooling::NDC ndc("inflate");
+#endif
+ Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML2Redirect.zlib");
+
+ z_stream z;
+ memset(&z, 0, sizeof(z_stream));
+
+ z.zalloc = saml_zalloc;
+ z.zfree = saml_zfree;
+ z.opaque = NULL;
+ z.next_in = (Bytef*)in;
+ z.avail_in = in_len;
+
+ int dlen = in_len << 3; /* guess inflated size: orig_size * 8 */
+ Byte* buf = new Byte[dlen];
+ memset(buf, 0, dlen);
+ z.next_out = buf;
+ z.avail_out = dlen;
+
+ int ret = inflateInit2(&z, -15);
+ if (ret != Z_OK) {
+ log.error("zlib inflateInit failed with error code (%d)", ret);
+ delete[] buf;
+ return 0;
+ }
+
+ int iter = 30;
+ while (--iter) { /* Make sure we can never be caught in infinite loop */
+ ret = inflate(&z, Z_SYNC_FLUSH);
+ switch (ret) {
+ case Z_STREAM_END:
+ goto done;
+
+ case Z_OK: /* avail_out should be 0 now. Time to dump the buffer. */
+ ret = z.next_out - buf;
+ z.next_out = buf;
+ while (ret--)
+ out << *(z.next_out++);
+ memset(buf, 0, dlen);
+ z.next_out = buf;
+ z.avail_out = dlen;
+ break;
+
+ default:
+ delete[] buf;
+ inflateEnd(&z);
+ log.error("zlib inflate failed with error code (%d)", ret);
+ return 0;
+ }
+ }
+done:
+ delete[] buf;
+ int out_len = z.total_out;
+ inflateEnd(&z);
+ return out_len;
+}
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * SAML2RedirectDecoder.cpp
+ *
+ * SAML 2.0 HTTP Redirect binding message encoder
+ */
+
+#include "internal.h"
+#include "exceptions.h"
+#include "saml2/binding/SAML2Redirect.h"
+#include "saml2/binding/SAML2RedirectDecoder.h"
+#include "saml2/core/Protocols.h"
+#include "saml2/metadata/Metadata.h"
+#include "saml2/metadata/MetadataProvider.h"
+#include "security/X509TrustEngine.h"
+
+#include <log4cpp/Category.hh>
+#include <xercesc/util/Base64.hpp>
+#include <xmltooling/util/NDC.h>
+#include <xmltooling/util/ReplayCache.h>
+#include <xmltooling/validation/ValidatorSuite.h>
+
+using namespace opensaml::saml2md;
+using namespace opensaml::saml2p;
+using namespace opensaml::saml2;
+using namespace opensaml;
+using namespace xmlsignature;
+using namespace xmltooling;
+using namespace log4cpp;
+using namespace std;
+
+namespace opensaml {
+ namespace saml2p {
+ MessageDecoder* SAML_DLLLOCAL SAML2RedirectDecoderFactory(const DOMElement* const & e)
+ {
+ return new SAML2RedirectDecoder(e);
+ }
+ };
+};
+
+SAML2RedirectDecoder::SAML2RedirectDecoder(const DOMElement* e) {}
+
+SAML2RedirectDecoder::~SAML2RedirectDecoder() {}
+
+XMLObject* SAML2RedirectDecoder::decode(
+ string& relayState,
+ const RoleDescriptor*& issuer,
+ const XMLCh*& securityMech,
+ const HTTPRequest& httpRequest,
+ const MetadataProvider* metadataProvider,
+ const QName* role,
+ const opensaml::TrustEngine* trustEngine
+ ) const
+{
+#ifdef _DEBUG
+ xmltooling::NDC ndc("decode");
+#endif
+ Category& log = Category::getInstance(SAML_LOGCAT".MessageDecoder.SAML2Redirect");
+
+ log.debug("validating input");
+ if (strcmp(httpRequest.getMethod(),"GET"))
+ return NULL;
+ const char* msg = httpRequest.getParameter("SAMLResponse");
+ if (!msg)
+ msg = httpRequest.getParameter("SAMLRequest");
+ if (!msg)
+ return NULL;
+ const char* state = httpRequest.getParameter("RelayState");
+ if (state)
+ relayState = state;
+ else
+ relayState.erase();
+ state = httpRequest.getParameter("SAMLEncoding");
+ if (state && strcmp(state,samlconstants::SAML20_BINDING_URL_ENCODING_DEFLATE)) {
+ log.warn("SAMLEncoding (%s) was not recognized", state);
+ return NULL;
+ }
+
+ // Decode the compressed message into SAML. First we base64-decode it.
+ unsigned int x;
+ XMLByte* decoded=Base64::decode(reinterpret_cast<const XMLByte*>(msg),&x);
+ if (!decoded)
+ throw BindingException("Unable to decode base64 in Redirect binding message.");
+
+ // Now we have to inflate it.
+ stringstream str;
+ if (inflate((char*)decoded, x, str)==0) {
+ XMLString::release(&decoded);
+ throw BindingException("Unable to inflate Redirect binding message.");
+ }
+
+ XMLString::release(&decoded);
+
+ // Parse and bind the document into an XMLObject.
+ DOMDocument* doc = (m_validate ? XMLToolingConfig::getConfig().getValidatingParser()
+ : XMLToolingConfig::getConfig().getParser()).parse(str);
+ XercesJanitor<DOMDocument> janitor(doc);
+ auto_ptr<XMLObject> xmlObject(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(), true));
+ janitor.release();
+
+ StatusResponseType* response = NULL;
+ RequestAbstractType* request = dynamic_cast<RequestAbstractType*>(xmlObject.get());
+ if (!request) {
+ response = dynamic_cast<StatusResponseType*>(xmlObject.get());
+ if (!response)
+ throw BindingException("XML content for SAML 2.0 HTTP-Redirect Decoder must be a SAML 2.0 protocol message.");
+ }
+
+ /* For SAML 2, the issuer can be established either from the message, or in some profiles
+ * it's possible to omit it and defer to assertions in a Response.
+ * The Issuer is later matched against metadata, and then trust checking can be applied.
+ */
+ const Issuer* claimedIssuer = request ? request->getIssuer() : response->getIssuer();
+ if (!claimedIssuer) {
+ // Check assertion option. I cannot resist the variable name, for the sake of google.
+ const Response* assbag = dynamic_cast<const Response*>(response);
+ if (assbag) {
+ const vector<Assertion*>& assertions=assbag->getAssertions();
+ if (!assertions.empty())
+ claimedIssuer = assertions.front()->getIssuer();
+ }
+ }
+
+ const EntityDescriptor* provider=NULL;
+ try {
+ if (!m_validate)
+ SchemaValidators.validate(xmlObject.get());
+
+ // Check destination URL.
+ auto_ptr_char dest(request ? request->getDestination() : response->getDestination());
+ const char* dest2 = httpRequest.getRequestURL();
+ if (!dest.get() || !*(dest.get())) {
+ log.error("signed SAML message missing Destination attribute");
+ throw BindingException("Signed SAML message missing Destination attribute identifying intended destination.");
+ }
+ else if (dest.get() && (!dest2 || !*dest2 || strcmp(dest.get(),dest2))) {
+ log.error("Redirect targeted at (%s), but delivered to (%s)", dest.get(), dest2 ? dest2 : "none");
+ throw BindingException("SAML message delivered with Redirect to incorrect server URL.");
+ }
+
+ // Check freshness.
+ time_t now = time(NULL);
+ if ((request ? request->getIssueInstant()->getEpoch() : response->getIssueInstant()->getEpoch())
+ < now-(2*XMLToolingConfig::getConfig().clock_skew_secs))
+ throw BindingException("Detected expired Redirect binding message.");
+
+ // Check replay.
+ ReplayCache* replayCache = XMLToolingConfig::getConfig().getReplayCache();
+ if (replayCache) {
+ auto_ptr_char id(xmlObject->getXMLID());
+ if (!replayCache->check("SAML2Redirect", id.get(), response->getIssueInstant()->getEpoch() + (2*XMLToolingConfig::getConfig().clock_skew_secs))) {
+ log.error("replay detected of message ID (%s)", id.get());
+ throw BindingException("Rejecting replayed message ID ($1).", params(1,id.get()));
+ }
+ }
+ else
+ log.warn("replay cache was not provided, this is a serious security risk!");
+
+ issuer = NULL;
+ securityMech = false;
+ log.debug("attempting to establish issuer and integrity of message...");
+
+ // If we can't identify the issuer, we're done, since we can't lookup or verify anything.
+ if (!claimedIssuer || !claimedIssuer->getName()) {
+ log.warn("unable to establish identity of message issuer");
+ return xmlObject.release();
+ }
+ else if (claimedIssuer->getFormat() && !XMLString::equals(claimedIssuer->getFormat(), NameIDType::ENTITY)) {
+ auto_ptr_char iformat(claimedIssuer->getFormat());
+ log.warn("message issuer was in an unsupported format (%s)", iformat.get());
+ return xmlObject.release();
+ }
+
+ log.debug("searching metadata for assertion issuer...");
+ provider=metadataProvider ? metadataProvider->getEntityDescriptor(claimedIssuer->getName()) : NULL;
+ if (provider) {
+ log.debug("matched assertion issuer against metadata, searching for applicable role...");
+ issuer=provider->getRoleDescriptor(*role, samlconstants::SAML20P_NS);
+ if (issuer) {
+ /*
+ if (trustEngine && signature) {
+ if (!trustEngine->validate(*signature, *issuer, metadataProvider->getKeyResolver())) {
+ log.error("unable to verify signature on message with supplied trust engine");
+ throw BindingException("Message signature failed verification.");
+ }
+ else {
+ securityMech = samlconstants::SAML20P_NS;
+ }
+ }
+ else {
+ log.warn("unable to authenticate the message, leaving untrusted");
+ }
+ */
+ }
+ else {
+ log.warn("unable to find compatible SAML 2.0 role (%s) in metadata", role->toString().c_str());
+ }
+ if (log.isDebugEnabled()) {
+ auto_ptr_char iname(provider->getEntityID());
+ log.debug("message from (%s), integrity %sverified", iname.get(), securityMech ? "" : "NOT ");
+ }
+ }
+ else {
+ auto_ptr_char temp(claimedIssuer->getName());
+ log.warn("no metadata found, can't establish identity of issuer (%s)", temp.get());
+ }
+ }
+ catch (XMLToolingException& ex) {
+ if (!provider) {
+ if (!claimedIssuer || !claimedIssuer->getName())
+ throw;
+ if (!metadataProvider || !(provider=metadataProvider->getEntityDescriptor(claimedIssuer->getName(), false))) {
+ // Just record it.
+ auto_ptr_char iname(claimedIssuer->getName());
+ if (iname.get())
+ ex.addProperty("entityID", iname.get());
+ throw;
+ }
+ }
+ if (!issuer)
+ issuer=provider->getRoleDescriptor(*role, samlconstants::SAML20P_NS);
+ if (issuer) annotateException(&ex,issuer); // throws it
+ annotateException(&ex,provider); // throws it
+ }
+
+ return xmlObject.release();
+}
#ifndef __saml2_assertions_h__
#define __saml2_assertions_h__
-#include <saml/signature/SignableObject.h>
+#include <saml/RootObject.h>
#include <saml/util/SAMLConstants.h>
#include <xmltooling/AttributeExtensibleXMLObject.h>
BEGIN_XMLOBJECT(SAML_API,EncryptedID,EncryptedElementType,SAML 2.0 EncryptedID element);
END_XMLOBJECT;
- BEGIN_XMLOBJECT(SAML_API,BaseID,xmltooling::XMLObject,SAML 2.0 BaseIDAbstractType abstract type);
+ BEGIN_XMLOBJECT(SAML_API,BaseID,xmltooling::XMLObject,SAML 2.0 BaseID abstract element);
DECL_STRING_ATTRIB(NameQualifier,NAMEQUALIFIER);
DECL_STRING_ATTRIB(SPNameQualifier,SPNAMEQUALIFIER);
END_XMLOBJECT;
static const XMLCh TYPE_NAME[];
END_XMLOBJECT;
- BEGIN_XMLOBJECT(SAML_API,Assertion,SignableObject,SAML 2.0 Assertion element);
- DECL_STRING_ATTRIB(Version,VER);
- DECL_STRING_ATTRIB(ID,ID);
- DECL_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
- DECL_TYPED_CHILD(Issuer);
- DECL_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
+ /**
+ * SAML 2.0 assertion or protocol message.
+ */
+ class SAML_API RootObject : virtual public opensaml::RootObject
+ {
+ protected:
+ RootObject() {}
+ public:
+ virtual ~RootObject() {}
+
+ /** Gets the Version attribute. */
+ virtual const XMLCh* getVersion() const=0;
+
+ /** Gets the Issuer. */
+ virtual Issuer* getIssuer() const=0;
+ };
+
+ BEGIN_XMLOBJECT(SAML_API,Assertion,saml2::RootObject,SAML 2.0 Assertion element);
+ DECL_INHERITED_STRING_ATTRIB(Version,VER);
+ DECL_INHERITED_STRING_ATTRIB(ID,ID);
+ DECL_INHERITED_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
+ DECL_INHERITED_TYPED_CHILD(Issuer);
+ DECL_INHERITED_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
DECL_TYPED_CHILD(Subject);
DECL_TYPED_CHILD(Conditions);
DECL_TYPED_CHILD(Advice);
static const XMLCh TYPE_NAME[];
END_XMLOBJECT;
- BEGIN_XMLOBJECT(SAML_API,RequestAbstractType,SignableObject,SAML 2.0 RequestAbstractType base type);
- DECL_STRING_ATTRIB(ID,ID);
- DECL_STRING_ATTRIB(Version,VER);
- DECL_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
+ BEGIN_XMLOBJECT(SAML_API,RequestAbstractType,saml2::RootObject,SAML 2.0 RequestAbstractType base type);
+ DECL_INHERITED_STRING_ATTRIB(ID,ID);
+ DECL_INHERITED_STRING_ATTRIB(Version,VER);
+ DECL_INHERITED_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
DECL_STRING_ATTRIB(Destination,DESTINATION);
DECL_STRING_ATTRIB(Consent,CONSENT);
- DECL_TYPED_FOREIGN_CHILD(Issuer,saml2);
- DECL_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
+ DECL_INHERITED_TYPED_FOREIGN_CHILD(Issuer,saml2);
+ DECL_INHERITED_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
DECL_TYPED_CHILD(Extensions);
/** RequestAbstractType local name */
static const XMLCh TYPE_NAME[];
static const XMLCh TYPE_NAME[];
END_XMLOBJECT;
- BEGIN_XMLOBJECT(SAML_API,StatusResponseType,SignableObject,SAML 2.0 StatusResponseType base type);
- DECL_STRING_ATTRIB(ID,ID);
+ BEGIN_XMLOBJECT(SAML_API,StatusResponseType,saml2::RootObject,SAML 2.0 StatusResponseType base type);
+ DECL_INHERITED_STRING_ATTRIB(ID,ID);
DECL_STRING_ATTRIB(InResponseTo,INRESPONSETO);
- DECL_STRING_ATTRIB(Version,VER);
- DECL_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
+ DECL_INHERITED_STRING_ATTRIB(Version,VER);
+ DECL_INHERITED_DATETIME_ATTRIB(IssueInstant,ISSUEINSTANT);
DECL_STRING_ATTRIB(Destination,DESTINATION);
DECL_STRING_ATTRIB(Consent,CONSENT);
-
- DECL_TYPED_FOREIGN_CHILD(Issuer,saml2);
- DECL_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
+ DECL_INHERITED_TYPED_FOREIGN_CHILD(Issuer,saml2);
+ DECL_INHERITED_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
DECL_TYPED_CHILD(Extensions);
DECL_TYPED_CHILD(Status);
-
/** StatusResponseType local name */
static const XMLCh TYPE_NAME[];
END_XMLOBJECT;
DECL_STRING_ATTRIB(Comparison,COMPARISON);
DECL_TYPED_FOREIGN_CHILDREN(AuthnContextClassRef,saml2);
DECL_TYPED_FOREIGN_CHILDREN(AuthnContextDeclRef,saml2);
-
/** RequestedAuthnContextType local name */
static const XMLCh TYPE_NAME[];
/** Searches the ProtocolSupportEnumeration attribute for the indicated protocol. */
virtual bool hasSupport(const XMLCh* protocol) const=0;
DECL_STRING_ATTRIB(ErrorURL,ERRORURL);
- DECL_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
+ DECL_INHERITED_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
DECL_TYPED_CHILD(Extensions);
DECL_TYPED_CHILDREN(KeyDescriptor);
DECL_TYPED_CHILD(Organization);
CacheableSAMLObject,TimeBoundSAMLObject,SAML 2.0 AffiliationDescriptor element);
DECL_STRING_ATTRIB(ID,ID);
DECL_STRING_ATTRIB(AffiliationOwnerID,AFFILIATIONOWNERID);
- DECL_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
+ DECL_INHERITED_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
DECL_TYPED_CHILD(Extensions);
DECL_TYPED_CHILDREN(AffiliateMember);
DECL_TYPED_CHILDREN(KeyDescriptor);
CacheableSAMLObject,TimeBoundSAMLObject,SAML 2.0 EntityDescriptor element);
DECL_STRING_ATTRIB(ID,ID);
DECL_STRING_ATTRIB(EntityID,ENTITYID);
- DECL_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
+ DECL_INHERITED_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
DECL_TYPED_CHILD(Extensions);
DECL_TYPED_CHILD(AffiliationDescriptor);
DECL_TYPED_CHILDREN(RoleDescriptor);
TimeBoundSAMLObject,SAML 2.0 EntitiesDescriptor element);
DECL_STRING_ATTRIB(ID,ID);
DECL_STRING_ATTRIB(Name,NAME);
- DECL_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
+ DECL_INHERITED_TYPED_FOREIGN_CHILD(Signature,xmlsignature);
DECL_TYPED_CHILD(Extensions);
DECL_TYPED_CHILDREN(EntityDescriptor);
DECL_TYPED_CHILDREN(EntitiesDescriptor);
return new ContentReference(*this);
}
+ /**
+ * Returns the enveloped Signature from the object.
+ *
+ * @return the enveloped Signature, or NULL
+ */
+ virtual xmlsignature::Signature* getSignature() const=0;
+
protected:
SignableObject() {}
};
const char samlconstants::SAML20_BINDING_HTTP_POST[] = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST";
const char samlconstants::SAML20_BINDING_HTTP_REDIRECT[] = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect";
+
+const char samlconstants::SAML20_BINDING_URL_ENCODING_DEFLATE[] = "urn:oasis:names:tc:SAML:2.0:bindings:URL-Encoding:DEFLATE";
\ No newline at end of file
/** SAML 2.0 HTTP-Redirect binding ("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect") */
extern SAML_API const char SAML20_BINDING_HTTP_REDIRECT[];
+
+ /** SAML 2.0 HTTP-Redirect DEFLATE URL encoding ("urn:oasis:names:tc:SAML:2.0:bindings:URL-Encoding:DEFLATE") */
+ extern SAML_API const char SAML20_BINDING_URL_ENCODING_DEFLATE[];
};
#endif /* __saml_xmlconstants_h__ */
-/*
- * Copyright 2001-2006 Internet2
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "internal.h"
-
-#include <saml/SAMLConfig.h>
-#include <saml/binding/MessageDecoder.h>
-#include <saml/binding/MessageEncoder.h>
-#include <saml/binding/URLEncoder.h>
-#include <saml/saml2/metadata/MetadataProvider.h>
-#include <saml/security/X509TrustEngine.h>
-
-using namespace saml2md;
-using namespace xmlsignature;
-
-class SAMLBindingBaseTestCase : public MessageDecoder::HTTPRequest, public MessageEncoder::HTTPResponse
-{
-protected:
- CredentialResolver* m_creds;
- MetadataProvider* m_metadata;
- opensaml::X509TrustEngine* m_trust;
- map<string,string> m_fields;
- map<string,string> m_headers;
- string m_method,m_url;
-
-public:
- void setUp() {
- m_creds=NULL;
- m_metadata=NULL;
- m_trust=NULL;
- m_fields.clear();
- m_headers.clear();
- m_method.erase();
- m_url.erase();
-
- try {
- string config = data_path + "binding/ExampleMetadataProvider.xml";
- ifstream in(config.c_str());
- DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);
- XercesJanitor<DOMDocument> janitor(doc);
-
- auto_ptr_XMLCh path("path");
- string s = data_path + "binding/example-metadata.xml";
- auto_ptr_XMLCh file(s.c_str());
- doc->getDocumentElement()->setAttributeNS(NULL,path.get(),file.get());
-
- m_metadata = SAMLConfig::getConfig().MetadataProviderManager.newPlugin(
- FILESYSTEM_METADATA_PROVIDER,doc->getDocumentElement()
- );
- m_metadata->init();
-
- config = data_path + "FilesystemCredentialResolver.xml";
- ifstream in2(config.c_str());
- DOMDocument* doc2=XMLToolingConfig::getConfig().getParser().parse(in2);
- XercesJanitor<DOMDocument> janitor2(doc2);
- m_creds = XMLToolingConfig::getConfig().CredentialResolverManager.newPlugin(
- FILESYSTEM_CREDENTIAL_RESOLVER,doc2->getDocumentElement()
- );
-
- m_trust = dynamic_cast<X509TrustEngine*>(
- SAMLConfig::getConfig().TrustEngineManager.newPlugin(EXPLICIT_KEY_SAMLTRUSTENGINE, NULL)
- );
- }
- catch (XMLToolingException& ex) {
- TS_TRACE(ex.what());
- tearDown();
- throw;
- }
-
- }
-
- void tearDown() {
- delete m_creds;
- delete m_metadata;
- delete m_trust;
- m_creds=NULL;
- m_metadata=NULL;
- m_trust=NULL;
- m_fields.clear();
- m_headers.clear();
- m_method.erase();
- m_url.erase();
- }
-
- // HTTPRequest methods
-
- const char* getMethod() const {
- return m_method.c_str();
- }
-
- const char* getRequestURL() const {
- return m_url.c_str();
- }
-
- const char* getRequestBody() const {
- return NULL;
- }
-
- const char* getQueryString() const {
- return NULL;
- }
-
- string getRemoteUser() const {
- return "";
- }
-
- string getHeader(const char* name) const {
- map<string,string>::const_iterator i=m_headers.find(name);
- return i==m_headers.end() ? "" : i->second;
- }
-
- const char* getParameter(const char* name) const {
- map<string,string>::const_iterator i=m_fields.find(name);
- return i==m_fields.end() ? NULL : i->second.c_str();
- }
-
- vector<const char*>::size_type getParameters(const char* name, vector<const char*>& values) const {
- values.clear();
- map<string,string>::const_iterator i=m_fields.find(name);
- if (i!=m_fields.end())
- values.push_back(i->second.c_str());
- return values.size();
- }
-
- // HTTPResponse methods
-
- void setHeader(const char* name, const char* value) {
- m_headers[name] = value ? value : "";
- }
-
- void setCookie(const char* name, const char* value) {
- m_headers["Set-Cookie"] = string(name) + "=" + (value ? value : "");
- }
-
- // The amount of error checking missing from this is incredible, but as long
- // as the test data isn't unexpected or malformed, it should work.
-
- long sendRedirect(const char* url) {
- m_method = "GET";
- char* dup = strdup(url);
- char* pch = strchr(dup,'?');
- if (pch) {
- *pch++=0;
- char* name=pch;
- while (name && *name) {
- pch=strchr(pch,'=');
- *pch++=0;
- char* value=pch;
- pch=strchr(pch,'&');
- if (pch)
- *pch++=0;
- SAMLConfig::getConfig().getURLEncoder()->decode(value);
- m_fields[name] = value;
- name = pch;
- }
- }
- m_url = dup;
- free(dup);
- return m_fields.size();
- }
-
- string html_decode(const string& s) const {
- string decoded;
- const char* ch=s.c_str();
- while (*ch) {
- if (*ch=='&') {
- if (!strncmp(ch,"<",4)) {
- decoded+='<'; ch+=4;
- }
- else if (!strncmp(ch,">",4)) {
- decoded+='>'; ch+=4;
- }
- else if (!strncmp(ch,""",6)) {
- decoded+='"'; ch+=6;
- }
- else if (*++ch=='#') {
- decoded+=(char)atoi(++ch);
- ch=strchr(ch,';')+1;
- }
- }
- else {
- decoded+=*ch++;
- }
- }
- return decoded;
- }
-
- long sendResponse(std::istream& inputStream, int status = 200, const char* contentType = "text/html") {
- m_method="POST";
- string page,line;
- while (getline(inputStream,line))
- page += line + '\n';
-
- const char* pch=strstr(page.c_str(),"action=\"");
- pch+=strlen("action=\"");
- m_url = html_decode(page.substr(pch-page.c_str(),strchr(pch,'"')-pch));
-
- while (pch=strstr(pch,"<input type=\"hidden\" name=\"")) {
- pch+=strlen("<input type=\"hidden\" name=\"");
- string name = page.substr(pch-page.c_str(),strchr(pch,'"')-pch);
- pch=strstr(pch,"value=\"");
- pch+=strlen("value=\"");
- m_fields[name] = html_decode(page.substr(pch-page.c_str(),strchr(pch,'"')-pch));
- }
- return m_fields.size();
- }
-};
+/*\r
+ * Copyright 2001-2006 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include "internal.h"\r
+\r
+#include <saml/SAMLConfig.h>\r
+#include <saml/binding/HTTPRequest.h>\r
+#include <saml/binding/HTTPResponse.h>\r
+#include <saml/binding/MessageDecoder.h>\r
+#include <saml/binding/MessageEncoder.h>\r
+#include <saml/binding/URLEncoder.h>\r
+#include <saml/saml2/metadata/MetadataProvider.h>\r
+#include <saml/security/TrustEngine.h>\r
+\r
+using namespace saml2md;\r
+using namespace xmlsignature;\r
+\r
+class SAMLBindingBaseTestCase : public HTTPRequest, public HTTPResponse\r
+{\r
+protected:\r
+ CredentialResolver* m_creds; \r
+ MetadataProvider* m_metadata;\r
+ opensaml::TrustEngine* m_trust;\r
+ map<string,string> m_fields;\r
+ map<string,string> m_headers;\r
+ string m_method,m_url;\r
+ vector<XSECCryptoX509*> m_clientCerts;\r
+ vector<const SecurityPolicyRule*> m_rules;\r
+\r
+public:\r
+ void setUp() {\r
+ m_creds=NULL;\r
+ m_metadata=NULL;\r
+ m_trust=NULL;\r
+ m_fields.clear();\r
+ m_headers.clear();\r
+ m_method.erase();\r
+ m_url.erase();\r
+\r
+ try {\r
+ string config = data_path + "binding/ExampleMetadataProvider.xml";\r
+ ifstream in(config.c_str());\r
+ DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);\r
+ XercesJanitor<DOMDocument> janitor(doc);\r
+ \r
+ auto_ptr_XMLCh path("path");\r
+ string s = data_path + "binding/example-metadata.xml";\r
+ auto_ptr_XMLCh file(s.c_str());\r
+ doc->getDocumentElement()->setAttributeNS(NULL,path.get(),file.get());\r
+ \r
+ m_metadata = SAMLConfig::getConfig().MetadataProviderManager.newPlugin(\r
+ FILESYSTEM_METADATA_PROVIDER,doc->getDocumentElement()\r
+ );\r
+ m_metadata->init();\r
+\r
+ config = data_path + "FilesystemCredentialResolver.xml";\r
+ ifstream in2(config.c_str());\r
+ DOMDocument* doc2=XMLToolingConfig::getConfig().getParser().parse(in2);\r
+ XercesJanitor<DOMDocument> janitor2(doc2);\r
+ m_creds = XMLToolingConfig::getConfig().CredentialResolverManager.newPlugin(\r
+ FILESYSTEM_CREDENTIAL_RESOLVER,doc2->getDocumentElement()\r
+ );\r
+ \r
+ m_trust = SAMLConfig::getConfig().TrustEngineManager.newPlugin(EXPLICIT_KEY_SAMLTRUSTENGINE, NULL);\r
+\r
+ m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(MESSAGEFLOW_POLICY_RULE,NULL));\r
+ m_rules.push_back(SAMLConfig::getConfig().SecurityPolicyRuleManager.newPlugin(MESSAGESIGNING_POLICY_RULE,NULL));\r
+ }\r
+ catch (XMLToolingException& ex) {\r
+ TS_TRACE(ex.what());\r
+ tearDown();\r
+ throw;\r
+ }\r
+\r
+ }\r
+ \r
+ void tearDown() {\r
+ for_each(m_rules.begin(), m_rules.end(), xmltooling::cleanup<SecurityPolicyRule>());\r
+ delete m_creds;\r
+ delete m_metadata;\r
+ delete m_trust;\r
+ m_creds=NULL;\r
+ m_metadata=NULL;\r
+ m_trust=NULL;\r
+ m_fields.clear();\r
+ m_headers.clear();\r
+ m_method.erase();\r
+ m_url.erase();\r
+ }\r
+\r
+ // HTTPRequest methods\r
+\r
+ const char* getMethod() const {\r
+ return m_method.c_str();\r
+ }\r
+\r
+ const char* getScheme() const {\r
+ return "https";\r
+ }\r
+\r
+ bool isSecure() const {\r
+ return true;\r
+ }\r
+\r
+ string getContentType() const {\r
+ return "application/x-www-form-urlencoded";\r
+ }\r
+\r
+ long getContentLength() const {\r
+ return -1;\r
+ }\r
+\r
+ const char* getRequestURL() const {\r
+ return m_url.c_str();\r
+ }\r
+ \r
+ const char* getRequestBody() const {\r
+ return NULL;\r
+ }\r
+ \r
+ const char* getQueryString() const {\r
+ return NULL;\r
+ }\r
+ \r
+ string getRemoteUser() const {\r
+ return "";\r
+ }\r
+\r
+ string getRemoteAddr() const {\r
+ return "127.0.0.1";\r
+ }\r
+\r
+ const std::vector<XSECCryptoX509*>& getClientCertificates() const {\r
+ return m_clientCerts;\r
+ }\r
+\r
+ string getHeader(const char* name) const {\r
+ map<string,string>::const_iterator i=m_headers.find(name);\r
+ return i==m_headers.end() ? "" : i->second;\r
+ }\r
+ \r
+ const char* getParameter(const char* name) const {\r
+ map<string,string>::const_iterator i=m_fields.find(name);\r
+ return i==m_fields.end() ? NULL : i->second.c_str();\r
+ }\r
+\r
+ vector<const char*>::size_type getParameters(const char* name, vector<const char*>& values) const {\r
+ values.clear();\r
+ map<string,string>::const_iterator i=m_fields.find(name);\r
+ if (i!=m_fields.end())\r
+ values.push_back(i->second.c_str());\r
+ return values.size();\r
+ }\r
+ \r
+ // HTTPResponse methods\r
+ \r
+ void setHeader(const char* name, const char* value) {\r
+ m_headers[name] = value ? value : "";\r
+ }\r
+\r
+ void setContentType(const char* type) {\r
+ setHeader("Content-Type", type);\r
+ }\r
+ \r
+ void setCookie(const char* name, const char* value) {\r
+ m_headers["Set-Cookie"] = string(name) + "=" + (value ? value : "");\r
+ }\r
+ \r
+ // The amount of error checking missing from this is incredible, but as long\r
+ // as the test data isn't unexpected or malformed, it should work.\r
+ \r
+ long sendRedirect(const char* url) {\r
+ m_method = "GET";\r
+ char* dup = strdup(url);\r
+ char* pch = strchr(dup,'?');\r
+ if (pch) {\r
+ *pch++=0;\r
+ char* name=pch;\r
+ while (name && *name) {\r
+ pch=strchr(pch,'=');\r
+ *pch++=0;\r
+ char* value=pch;\r
+ pch=strchr(pch,'&');\r
+ if (pch)\r
+ *pch++=0;\r
+ SAMLConfig::getConfig().getURLEncoder()->decode(value);\r
+ m_fields[name] = value;\r
+ name = pch; \r
+ }\r
+ }\r
+ m_url = dup;\r
+ free(dup);\r
+ return m_fields.size();\r
+ }\r
+ \r
+ string html_decode(const string& s) const {\r
+ string decoded;\r
+ const char* ch=s.c_str();\r
+ while (*ch) {\r
+ if (*ch=='&') {\r
+ if (!strncmp(ch,"<",4)) {\r
+ decoded+='<'; ch+=4;\r
+ }\r
+ else if (!strncmp(ch,">",4)) {\r
+ decoded+='>'; ch+=4;\r
+ }\r
+ else if (!strncmp(ch,""",6)) {\r
+ decoded+='"'; ch+=6;\r
+ }\r
+ else if (*++ch=='#') {\r
+ decoded+=(char)atoi(++ch);\r
+ ch=strchr(ch,';')+1;\r
+ }\r
+ }\r
+ else {\r
+ decoded+=*ch++;\r
+ }\r
+ }\r
+ return decoded;\r
+ }\r
+ \r
+ long sendResponse(std::istream& inputStream, long status) {\r
+ m_method="POST";\r
+ string page,line;\r
+ while (getline(inputStream,line))\r
+ page += line + '\n';\r
+ \r
+ const char* pch=strstr(page.c_str(),"action=\"");\r
+ pch+=strlen("action=\"");\r
+ m_url = html_decode(page.substr(pch-page.c_str(),strchr(pch,'"')-pch));\r
+\r
+ while (pch=strstr(pch,"<input type=\"hidden\" name=\"")) {\r
+ pch+=strlen("<input type=\"hidden\" name=\"");\r
+ string name = page.substr(pch-page.c_str(),strchr(pch,'"')-pch);\r
+ pch=strstr(pch,"value=\"");\r
+ pch+=strlen("value=\"");\r
+ m_fields[name] = html_decode(page.substr(pch-page.c_str(),strchr(pch,'"')-pch));\r
+ }\r
+ return m_fields.size();\r
+ }\r
+};\r
-/*
- * Copyright 2001-2005 Internet2
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "binding.h"
-
-#include <saml/binding/ArtifactMap.h>
-#include <saml/saml1/core/Assertions.h>
-#include <saml/saml1/core/Protocols.h>
-#include <saml/saml1/binding/SAMLArtifactType0001.h>
-#include <xmltooling/validation/ValidatorSuite.h>
-
-using namespace opensaml::saml1p;
-using namespace opensaml::saml1;
-
+/*\r
+ * Copyright 2001-2005 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include "binding.h"\r
+\r
+#include <saml/binding/ArtifactMap.h>\r
+#include <saml/saml1/core/Assertions.h>\r
+#include <saml/saml1/core/Protocols.h>\r
+#include <saml/saml1/binding/SAMLArtifactType0001.h>\r
+#include <xmltooling/validation/ValidatorSuite.h>\r
+\r
+using namespace opensaml::saml1p;\r
+using namespace opensaml::saml1;\r
+\r
namespace {\r
class SAML_DLLLOCAL _addcert : public binary_function<X509Data*,XSECCryptoX509*,void> {\r
public:\r
}\r
};\r
};\r
-
-class SAML1ArtifactTest : public CxxTest::TestSuite,
- public SAMLBindingBaseTestCase, public MessageEncoder::ArtifactGenerator, public MessageDecoder::ArtifactResolver {
-public:
- void setUp() {
- SAMLBindingBaseTestCase::setUp();
- }
-
- void tearDown() {
- SAMLBindingBaseTestCase::tearDown();
- }
-
- void testSAML1Artifact() {
- try {
- // Read message to use from file.
- string path = data_path + "saml1/binding/SAML1Assertion.xml";
- ifstream in(path.c_str());
- DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);
- XercesJanitor<DOMDocument> janitor(doc);
- auto_ptr<Assertion> toSend(
- dynamic_cast<Assertion*>(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(),true))
- );
- janitor.release();
-
- // Encode message.
- auto_ptr<MessageEncoder> encoder(
- SAMLConfig::getConfig().MessageEncoderManager.newPlugin(samlconstants::SAML1_PROFILE_BROWSER_ARTIFACT, NULL)
- );
- encoder->setArtifactGenerator(this);
- encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/Artifact","https://sp.example.org/","state",m_creds);
- toSend.release();
-
- // Decode message.
- string relayState;
- const RoleDescriptor* issuer=NULL;
- const XMLCh* securityMech=NULL;
- QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
- auto_ptr<MessageDecoder> decoder(
- SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML1_PROFILE_BROWSER_ARTIFACT, NULL)
- );
- decoder->setArtifactResolver(this);
- Locker locker(m_metadata);
- auto_ptr<Response> response(
- dynamic_cast<Response*>(
- decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust)
- )
- );
-
- // Test the results.
- TSM_ASSERT_EQUALS("TARGET was not the expected result.", relayState, "state");
- TSM_ASSERT("SAML Response not decoded successfully.", response.get());
- TSM_ASSERT("Message was not verified.", issuer && securityMech && securityMech==samlconstants::SAML1P_NS);
- auto_ptr_char entityID(dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID());
- TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));
- TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);
-
- // Trigger a replay.
- TSM_ASSERT_THROWS("Did not catch the replay.",
- decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust),
- BindingException);
- }
- catch (XMLToolingException& ex) {
- TS_TRACE(ex.what());
- throw;
- }
- }
-
- SAMLArtifact* generateSAML1Artifact(const char* relyingParty) const {
- return new SAMLArtifactType0001(SAMLConfig::getConfig().hashSHA1("https://idp.example.org/"));
- }
-
- saml2p::SAML2Artifact* generateSAML2Artifact(const char* relyingParty) const {
- throw BindingException("Not implemented.");
- }
-
+\r
+class SAML1ArtifactTest : public CxxTest::TestSuite,\r
+ public SAMLBindingBaseTestCase, public MessageEncoder::ArtifactGenerator, public MessageDecoder::ArtifactResolver {\r
+public:\r
+ void setUp() {\r
+ SAMLBindingBaseTestCase::setUp();\r
+ }\r
+\r
+ void tearDown() {\r
+ SAMLBindingBaseTestCase::tearDown();\r
+ }\r
+\r
+ void testSAML1Artifact() {\r
+ try {\r
+ QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);\r
+ SecurityPolicy policy(m_rules, m_metadata, &idprole, m_trust);\r
+\r
+ // Read message to use from file.\r
+ string path = data_path + "saml1/binding/SAML1Assertion.xml";\r
+ ifstream in(path.c_str());\r
+ DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);\r
+ XercesJanitor<DOMDocument> janitor(doc);\r
+ auto_ptr<Assertion> toSend(\r
+ dynamic_cast<Assertion*>(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(),true))\r
+ );\r
+ janitor.release();\r
+\r
+ // Encode message.\r
+ auto_ptr<MessageEncoder> encoder(\r
+ SAMLConfig::getConfig().MessageEncoderManager.newPlugin(samlconstants::SAML1_PROFILE_BROWSER_ARTIFACT, NULL)\r
+ );\r
+ encoder->setArtifactGenerator(this);\r
+ encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/Artifact","https://sp.example.org/","state",m_creds);\r
+ toSend.release();\r
+ \r
+ // Decode message.\r
+ string relayState;\r
+ auto_ptr<MessageDecoder> decoder(\r
+ SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML1_PROFILE_BROWSER_ARTIFACT, NULL)\r
+ );\r
+ decoder->setArtifactResolver(this);\r
+ Locker locker(m_metadata);\r
+ auto_ptr<Response> response(dynamic_cast<Response*>(decoder->decode(relayState,*this,policy)));\r
+ \r
+ // Test the results.\r
+ TSM_ASSERT_EQUALS("TARGET was not the expected result.", relayState, "state");\r
+ TSM_ASSERT("SAML Response not decoded successfully.", response.get());\r
+ TSM_ASSERT("Message was not verified.", policy.getIssuer()!=NULL);\r
+ auto_ptr_char entityID(policy.getIssuer()->getName());\r
+ TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));\r
+ TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);\r
+\r
+ // Trigger a replay.\r
+ TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException);\r
+ }\r
+ catch (XMLToolingException& ex) {\r
+ TS_TRACE(ex.what());\r
+ throw;\r
+ }\r
+ }\r
+\r
+ SAMLArtifact* generateSAML1Artifact(const char* relyingParty) const {\r
+ return new SAMLArtifactType0001(SAMLConfig::getConfig().hashSHA1("https://idp.example.org/"));\r
+ }\r
+ \r
+ saml2p::SAML2Artifact* generateSAML2Artifact(const char* relyingParty) const {\r
+ throw BindingException("Not implemented.");\r
+ }\r
+ \r
Signature* buildSignature(const CredentialResolver* credResolver) const\r
{\r
// Build a Signature.\r
\r
return sig;\r
}\r
-
- Response* resolve(
- const XMLCh*& securityMech,
- const vector<SAMLArtifact*>& artifacts,
- const IDPSSODescriptor& idpDescriptor,
- const X509TrustEngine* trustEngine=NULL
- ) const {
- TSM_ASSERT_EQUALS("Too many artifacts.", artifacts.size(), 1);
- XMLObject* xmlObject =
- SAMLConfig::getConfig().getArtifactMap()->retrieveContent(artifacts.front(), "https://sp.example.org/");
- Assertion* assertion = dynamic_cast<Assertion*>(xmlObject);
- TSM_ASSERT("Not an assertion.", assertion!=NULL);
- auto_ptr<Response> response(ResponseBuilder::buildResponse());
- response->getAssertions().push_back(assertion);
- Status* status = StatusBuilder::buildStatus();
- response->setStatus(status);
- StatusCode* sc = StatusCodeBuilder::buildStatusCode();
- status->setStatusCode(sc);
- sc->setValue(&StatusCode::SUCCESS);
- response->setSignature(buildSignature(m_creds));
- vector<Signature*> sigs(1,response->getSignature());
- response->marshall((DOMDocument*)NULL,&sigs);
- SchemaValidators.validate(response.get());
- securityMech = NULL;
- return response.release();
- }
-
- saml2p::ArtifactResponse* resolve(
- const XMLCh*& securityMech,
- const saml2p::SAML2Artifact& artifact,
- const SSODescriptorType& ssoDescriptor,
- const X509TrustEngine* trustEngine=NULL
- ) const {
- throw BindingException("Not implemented.");
- }
-};
+\r
+ Response* resolve(\r
+ const vector<SAMLArtifact*>& artifacts,\r
+ const IDPSSODescriptor& idpDescriptor,\r
+ SecurityPolicy& policy\r
+ ) const {\r
+ TSM_ASSERT_EQUALS("Too many artifacts.", artifacts.size(), 1);\r
+ XMLObject* xmlObject =\r
+ SAMLConfig::getConfig().getArtifactMap()->retrieveContent(artifacts.front(), "https://sp.example.org/");\r
+ Assertion* assertion = dynamic_cast<Assertion*>(xmlObject);\r
+ TSM_ASSERT("Not an assertion.", assertion!=NULL);\r
+ auto_ptr<Response> response(ResponseBuilder::buildResponse());\r
+ response->getAssertions().push_back(assertion);\r
+ Status* status = StatusBuilder::buildStatus();\r
+ response->setStatus(status);\r
+ StatusCode* sc = StatusCodeBuilder::buildStatusCode();\r
+ status->setStatusCode(sc);\r
+ sc->setValue(&StatusCode::SUCCESS);\r
+ response->setSignature(buildSignature(m_creds));\r
+ vector<Signature*> sigs(1,response->getSignature());\r
+ response->marshall((DOMDocument*)NULL,&sigs);\r
+ SchemaValidators.validate(response.get());\r
+ return response.release();\r
+ }\r
+\r
+ saml2p::ArtifactResponse* resolve(\r
+ const saml2p::SAML2Artifact& artifact,\r
+ const SSODescriptorType& ssoDescriptor,\r
+ SecurityPolicy& policy\r
+ ) const {\r
+ throw BindingException("Not implemented.");\r
+ }\r
+};\r
SAMLBindingBaseTestCase::tearDown();
}
- void testSAML1POSTTrusted() {
+ void testSAML1POST() {
try {
- // Read message to use from file.
- string path = data_path + "saml1/binding/SAML1Response.xml";
- ifstream in(path.c_str());
- DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);
- XercesJanitor<DOMDocument> janitor(doc);
- auto_ptr<Response> toSend(
- dynamic_cast<Response*>(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(),true))
- );
- janitor.release();
-
- // Freshen timestamp.
- toSend->setIssueInstant(time(NULL));
-
- // Encode message.
- auto_ptr_XMLCh lit1("MessageEncoder");
- auto_ptr_XMLCh lit2("template");
- path = data_path + "binding/template.html";
- auto_ptr_XMLCh lit3(path.c_str());
- DOMDocument* encoder_config = XMLToolingConfig::getConfig().getParser().newDocument();
- XercesJanitor<DOMDocument> janitor2(encoder_config);
- encoder_config->appendChild(encoder_config->createElementNS(NULL,lit1.get()));
- encoder_config->getDocumentElement()->setAttributeNS(NULL,lit2.get(),lit3.get());
- auto_ptr<MessageEncoder> encoder(
- SAMLConfig::getConfig().MessageEncoderManager.newPlugin(
- samlconstants::SAML1_PROFILE_BROWSER_POST, encoder_config->getDocumentElement()
- )
- );
- encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/POST","https://sp.example.org/","state",m_creds);
- toSend.release();
-
- // Decode message.
- string relayState;
- const RoleDescriptor* issuer=NULL;
- const XMLCh* securityMech=NULL;
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
- auto_ptr<MessageDecoder> decoder(
- SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML1_PROFILE_BROWSER_POST, NULL)
- );
- Locker locker(m_metadata);
- auto_ptr<Response> response(
- dynamic_cast<Response*>(
- decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust)
- )
- );
-
- // Test the results.
- TSM_ASSERT_EQUALS("TARGET was not the expected result.", relayState, "state");
- TSM_ASSERT("SAML Response not decoded successfully.", response.get());
- TSM_ASSERT("Message was not verified.", issuer && securityMech && securityMech==samlconstants::SAML1P_NS);
- auto_ptr_char entityID(dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID());
- TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));
- TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);
- }
- catch (XMLToolingException& ex) {
- TS_TRACE(ex.what());
- throw;
- }
- }
+ SecurityPolicy policy(m_rules, m_metadata, &idprole, m_trust);
- void testSAML1POSTUntrusted() {
- try {
// Read message to use from file.
string path = data_path + "saml1/binding/SAML1Response.xml";
ifstream in(path.c_str());
);
janitor.release();
- // Freshen timestamp and clear ID.
+ // Freshen timestamp and ID.
toSend->setIssueInstant(time(NULL));
toSend->setResponseID(NULL);
samlconstants::SAML1_PROFILE_BROWSER_POST, encoder_config->getDocumentElement()
)
);
- encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/POST","https://sp.example.org/","state");
+ encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/POST","https://sp.example.org/","state",m_creds);
toSend.release();
// Decode message.
string relayState;
- const RoleDescriptor* issuer=NULL;
- const XMLCh* securityMech=NULL;
- QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
auto_ptr<MessageDecoder> decoder(
SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML1_PROFILE_BROWSER_POST, NULL)
);
Locker locker(m_metadata);
- auto_ptr<Response> response(
- dynamic_cast<Response*>(
- decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole)
- )
- );
+ auto_ptr<Response> response(dynamic_cast<Response*>(decoder->decode(relayState,*this,policy)));
// Test the results.
TSM_ASSERT_EQUALS("TARGET was not the expected result.", relayState, "state");
TSM_ASSERT("SAML Response not decoded successfully.", response.get());
- TSM_ASSERT("Message was verified.", issuer && !securityMech);
- auto_ptr_char entityID(dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID());
+ TSM_ASSERT("Message was not verified.", policy.getIssuer()!=NULL);
+ auto_ptr_char entityID(policy.getIssuer()->getName());
TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));
TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);
// Trigger a replay.
- TSM_ASSERT_THROWS("Did not catch the replay.",
- decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust),
- BindingException);
+ TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException);
}
catch (XMLToolingException& ex) {
TS_TRACE(ex.what());
-/*
- * Copyright 2001-2005 Internet2
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "binding.h"
-
-#include <saml/binding/ArtifactMap.h>
-#include <saml/saml2/core/Protocols.h>
-#include <saml/saml2/binding/SAML2ArtifactType0004.h>
-#include <xmltooling/validation/ValidatorSuite.h>
-
-using namespace opensaml::saml2p;
-using namespace opensaml::saml2;
-
-class SAML2ArtifactTest : public CxxTest::TestSuite,
- public SAMLBindingBaseTestCase, public MessageEncoder::ArtifactGenerator, public MessageDecoder::ArtifactResolver {
-public:
- void setUp() {
- SAMLBindingBaseTestCase::setUp();
- }
-
- void tearDown() {
- SAMLBindingBaseTestCase::tearDown();
- }
-
- void testSAML2Artifact() {
- try {
- // Read message to use from file.
- string path = data_path + "saml2/binding/SAML2Response.xml";
- ifstream in(path.c_str());
- DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);
- XercesJanitor<DOMDocument> janitor(doc);
- auto_ptr<Response> toSend(
- dynamic_cast<Response*>(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(),true))
- );
- janitor.release();
-
- // Freshen timestamp.
- toSend->setIssueInstant(time(NULL));
-
- // Encode message.
- auto_ptr<MessageEncoder> encoder(
- SAMLConfig::getConfig().MessageEncoderManager.newPlugin(samlconstants::SAML20_BINDING_HTTP_ARTIFACT, NULL)
- );
- encoder->setArtifactGenerator(this);
- encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/Artifact","https://sp.example.org/","state",m_creds);
- toSend.release();
-
- // Decode message.
- string relayState;
- const RoleDescriptor* issuer=NULL;
- const XMLCh* securityMech=NULL;
- QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
- auto_ptr<MessageDecoder> decoder(
- SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML20_BINDING_HTTP_ARTIFACT, NULL)
- );
- decoder->setArtifactResolver(this);
- Locker locker(m_metadata);
- auto_ptr<Response> response(
- dynamic_cast<Response*>(
- decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust)
- )
- );
-
- // Test the results.
- TSM_ASSERT_EQUALS("RelayState was not the expected result.", relayState, "state");
- TSM_ASSERT("SAML Response not decoded successfully.", response.get());
- TSM_ASSERT("Message was not verified.", issuer && securityMech && securityMech==samlconstants::SAML20P_NS);
- auto_ptr_char entityID(dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID());
- TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));
- TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);
-
- // Trigger a replay.
- TSM_ASSERT_THROWS("Did not catch the replay.",
- decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust),
- BindingException);
- }
- catch (XMLToolingException& ex) {
- TS_TRACE(ex.what());
- throw;
- }
- }
-
- SAMLArtifact* generateSAML1Artifact(const char* relyingParty) const {
- throw BindingException("Not implemented.");
- }
-
- saml2p::SAML2Artifact* generateSAML2Artifact(const char* relyingParty) const {
- return new SAML2ArtifactType0004(SAMLConfig::getConfig().hashSHA1("https://idp.example.org/"),1);
- }
-
- saml1p::Response* resolve(
- const XMLCh*& securityMech,
- const vector<SAMLArtifact*>& artifacts,
- const IDPSSODescriptor& idpDescriptor,
- const X509TrustEngine* trustEngine=NULL
- ) const {
- throw BindingException("Not implemented.");
- }
-
- ArtifactResponse* resolve(
- const XMLCh*& securityMech,
- const SAML2Artifact& artifact,
- const SSODescriptorType& ssoDescriptor,
- const X509TrustEngine* trustEngine=NULL
- ) const {
- XMLObject* xmlObject =
- SAMLConfig::getConfig().getArtifactMap()->retrieveContent(&artifact, "https://sp.example.org/");
- Response* payload = dynamic_cast<Response*>(xmlObject);
- TSM_ASSERT("Not a response.", payload!=NULL);
- auto_ptr<ArtifactResponse> response(ArtifactResponseBuilder::buildArtifactResponse());
- response->setPayload(payload);
- Status* status = StatusBuilder::buildStatus();
- response->setStatus(status);
- StatusCode* sc = StatusCodeBuilder::buildStatusCode();
- status->setStatusCode(sc);
- sc->setValue(StatusCode::SUCCESS);
- response->marshall();
- SchemaValidators.validate(response.get());
- securityMech = NULL;
- return response.release();
- }
-};
+/*\r
+ * Copyright 2001-2005 Internet2\r
+ * \r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+#include "binding.h"\r
+\r
+#include <saml/binding/ArtifactMap.h>\r
+#include <saml/saml2/core/Protocols.h>\r
+#include <saml/saml2/binding/SAML2ArtifactType0004.h>\r
+#include <xmltooling/validation/ValidatorSuite.h>\r
+\r
+using namespace opensaml::saml2p;\r
+using namespace opensaml::saml2;\r
+\r
+class SAML2ArtifactTest : public CxxTest::TestSuite,\r
+ public SAMLBindingBaseTestCase, public MessageEncoder::ArtifactGenerator, public MessageDecoder::ArtifactResolver {\r
+public:\r
+ void setUp() {\r
+ SAMLBindingBaseTestCase::setUp();\r
+ }\r
+\r
+ void tearDown() {\r
+ SAMLBindingBaseTestCase::tearDown();\r
+ }\r
+\r
+ void testSAML2Artifact() {\r
+ try {\r
+ QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);\r
+ SecurityPolicy policy(m_rules, m_metadata, &idprole, m_trust);\r
+\r
+ // Read message to use from file.\r
+ string path = data_path + "saml2/binding/SAML2Response.xml";\r
+ ifstream in(path.c_str());\r
+ DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);\r
+ XercesJanitor<DOMDocument> janitor(doc);\r
+ auto_ptr<Response> toSend(\r
+ dynamic_cast<Response*>(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(),true))\r
+ );\r
+ janitor.release();\r
+\r
+ // Freshen timestamp.\r
+ toSend->setIssueInstant(time(NULL));\r
+\r
+ // Encode message.\r
+ auto_ptr<MessageEncoder> encoder(\r
+ SAMLConfig::getConfig().MessageEncoderManager.newPlugin(samlconstants::SAML20_BINDING_HTTP_ARTIFACT, NULL)\r
+ );\r
+ encoder->setArtifactGenerator(this);\r
+ encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/Artifact","https://sp.example.org/","state",m_creds);\r
+ toSend.release();\r
+ \r
+ // Decode message.\r
+ string relayState;\r
+ auto_ptr<MessageDecoder> decoder(\r
+ SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML20_BINDING_HTTP_ARTIFACT, NULL)\r
+ );\r
+ decoder->setArtifactResolver(this);\r
+ Locker locker(m_metadata);\r
+ auto_ptr<Response> response(dynamic_cast<Response*>(decoder->decode(relayState,*this,policy)));\r
+ \r
+ // Test the results.\r
+ TSM_ASSERT_EQUALS("RelayState was not the expected result.", relayState, "state");\r
+ TSM_ASSERT("SAML Response not decoded successfully.", response.get());\r
+ TSM_ASSERT("Message was not verified.", policy.getIssuer()!=NULL);\r
+ auto_ptr_char entityID(policy.getIssuer()->getName());\r
+ TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));\r
+ TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);\r
+\r
+ // Trigger a replay.\r
+ TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException);\r
+ }\r
+ catch (XMLToolingException& ex) {\r
+ TS_TRACE(ex.what());\r
+ throw;\r
+ }\r
+ }\r
+ \r
+ SAMLArtifact* generateSAML1Artifact(const char* relyingParty) const {\r
+ throw BindingException("Not implemented.");\r
+ }\r
+ \r
+ saml2p::SAML2Artifact* generateSAML2Artifact(const char* relyingParty) const {\r
+ return new SAML2ArtifactType0004(SAMLConfig::getConfig().hashSHA1("https://idp.example.org/"),1);\r
+ }\r
+ \r
+ saml1p::Response* resolve(\r
+ const vector<SAMLArtifact*>& artifacts,\r
+ const IDPSSODescriptor& idpDescriptor,\r
+ SecurityPolicy& policy\r
+ ) const {\r
+ throw BindingException("Not implemented.");\r
+ }\r
+\r
+ ArtifactResponse* resolve(\r
+ const SAML2Artifact& artifact,\r
+ const SSODescriptorType& ssoDescriptor,\r
+ SecurityPolicy& policy\r
+ ) const {\r
+ XMLObject* xmlObject =\r
+ SAMLConfig::getConfig().getArtifactMap()->retrieveContent(&artifact, "https://sp.example.org/");\r
+ Response* payload = dynamic_cast<Response*>(xmlObject);\r
+ TSM_ASSERT("Not a response.", payload!=NULL);\r
+ auto_ptr<ArtifactResponse> response(ArtifactResponseBuilder::buildArtifactResponse());\r
+ response->setPayload(payload);\r
+ Status* status = StatusBuilder::buildStatus();\r
+ response->setStatus(status);\r
+ StatusCode* sc = StatusCodeBuilder::buildStatusCode();\r
+ status->setStatusCode(sc);\r
+ sc->setValue(StatusCode::SUCCESS);\r
+ response->marshall();\r
+ SchemaValidators.validate(response.get());\r
+ return response.release();\r
+ }\r
+};\r
SAMLBindingBaseTestCase::tearDown();
}
- void testSAML2POSTTrusted() {
+ void testSAML2POST() {
try {
- // Read message to use from file.
- string path = data_path + "saml2/binding/SAML2Response.xml";
- ifstream in(path.c_str());
- DOMDocument* doc=XMLToolingConfig::getConfig().getParser().parse(in);
- XercesJanitor<DOMDocument> janitor(doc);
- auto_ptr<Response> toSend(
- dynamic_cast<Response*>(XMLObjectBuilder::buildOneFromElement(doc->getDocumentElement(),true))
- );
- janitor.release();
-
- // Freshen timestamp.
- toSend->setIssueInstant(time(NULL));
-
- // Encode message.
- auto_ptr_XMLCh lit1("MessageEncoder");
- auto_ptr_XMLCh lit2("template");
- path = data_path + "binding/template.html";
- auto_ptr_XMLCh lit3(path.c_str());
- DOMDocument* encoder_config = XMLToolingConfig::getConfig().getParser().newDocument();
- XercesJanitor<DOMDocument> janitor2(encoder_config);
- encoder_config->appendChild(encoder_config->createElementNS(NULL,lit1.get()));
- encoder_config->getDocumentElement()->setAttributeNS(NULL,lit2.get(),lit3.get());
- auto_ptr<MessageEncoder> encoder(
- SAMLConfig::getConfig().MessageEncoderManager.newPlugin(
- samlconstants::SAML20_BINDING_HTTP_POST, encoder_config->getDocumentElement()
- )
- );
- encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/POST","https://sp.example.org/","state",m_creds);
- toSend.release();
-
- // Decode message.
- string relayState;
- const RoleDescriptor* issuer=NULL;
- const XMLCh* securityMech=NULL;
QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
- auto_ptr<MessageDecoder> decoder(
- SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML20_BINDING_HTTP_POST, NULL)
- );
- Locker locker(m_metadata);
- auto_ptr<Response> response(
- dynamic_cast<Response*>(
- decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust)
- )
- );
-
- // Test the results.
- TSM_ASSERT_EQUALS("RelayState was not the expected result.", relayState, "state");
- TSM_ASSERT("SAML Response not decoded successfully.", response.get());
- TSM_ASSERT("Message was not verified.", issuer && securityMech && securityMech==samlconstants::SAML20P_NS);
- auto_ptr_char entityID(dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID());
- TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));
- TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);
- }
- catch (XMLToolingException& ex) {
- TS_TRACE(ex.what());
- throw;
- }
- }
+ SecurityPolicy policy(m_rules, m_metadata, &idprole, m_trust);
- void testSAML2POSTUntrusted() {
- try {
// Read message to use from file.
string path = data_path + "saml2/binding/SAML2Response.xml";
ifstream in(path.c_str());
);
janitor.release();
- // Freshen timestamp and clear ID.
+ // Freshen timestamp and ID.
toSend->setIssueInstant(time(NULL));
toSend->setID(NULL);
samlconstants::SAML20_BINDING_HTTP_POST, encoder_config->getDocumentElement()
)
);
- encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/POST","https://sp.example.org/","state");
+ encoder->encode(*this,toSend.get(),"https://sp.example.org/SAML/POST","https://sp.example.org/","state",m_creds);
toSend.release();
// Decode message.
string relayState;
- const RoleDescriptor* issuer=NULL;
- const XMLCh* securityMech=NULL;
- QName idprole(samlconstants::SAML20MD_NS, IDPSSODescriptor::LOCAL_NAME);
auto_ptr<MessageDecoder> decoder(
SAMLConfig::getConfig().MessageDecoderManager.newPlugin(samlconstants::SAML20_BINDING_HTTP_POST, NULL)
);
Locker locker(m_metadata);
- auto_ptr<Response> response(
- dynamic_cast<Response*>(
- decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole)
- )
- );
+ auto_ptr<Response> response(dynamic_cast<Response*>(decoder->decode(relayState,*this,policy)));
// Test the results.
TSM_ASSERT_EQUALS("RelayState was not the expected result.", relayState, "state");
TSM_ASSERT("SAML Response not decoded successfully.", response.get());
- TSM_ASSERT("Message was verified.", issuer && !securityMech);
- auto_ptr_char entityID(dynamic_cast<const EntityDescriptor*>(issuer->getParent())->getEntityID());
+ TSM_ASSERT("Message was not verified.", policy.getIssuer()!=NULL);
+ auto_ptr_char entityID(policy.getIssuer()->getName());
TSM_ASSERT("Issuer was not expected.", !strcmp(entityID.get(),"https://idp.example.org/"));
TSM_ASSERT_EQUALS("Assertion count was not correct.", response->getAssertions().size(), 1);
// Trigger a replay.
- TSM_ASSERT_THROWS("Did not catch the replay.",
- decoder->decode(relayState,issuer,securityMech,*this,m_metadata,&idprole,m_trust),
- BindingException);
+ TSM_ASSERT_THROWS("Did not catch the replay.", decoder->decode(relayState,*this,policy), BindingException);
}
catch (XMLToolingException& ex) {
TS_TRACE(ex.what());