Revamped binding classes with security policy layer.
authorScott Cantor <cantor.2@osu.edu>
Fri, 3 Nov 2006 05:10:46 +0000 (05:10 +0000)
committerScott Cantor <cantor.2@osu.edu>
Fri, 3 Nov 2006 05:10:46 +0000 (05:10 +0000)
53 files changed:
saml/Makefile.am
saml/RootObject.h [new file with mode: 0644]
saml/SAMLConfig.cpp
saml/SAMLConfig.h
saml/binding/GenericRequest.h [new file with mode: 0644]
saml/binding/GenericResponse.h [new file with mode: 0644]
saml/binding/HTTPRequest.h [new file with mode: 0644]
saml/binding/HTTPResponse.h [new file with mode: 0644]
saml/binding/MessageDecoder.h
saml/binding/MessageEncoder.h
saml/binding/MessageFlowRule.h [new file with mode: 0644]
saml/binding/MessageSigningRule.h [new file with mode: 0644]
saml/binding/SecurityPolicy.h [new file with mode: 0644]
saml/binding/SecurityPolicyRule.h [new file with mode: 0644]
saml/binding/impl/MessageFlowRule.cpp [new file with mode: 0644]
saml/binding/impl/MessageSigningRule.cpp [new file with mode: 0644]
saml/binding/impl/SecurityPolicy.cpp [new file with mode: 0644]
saml/saml.vcproj
saml/saml1/binding/SAML1ArtifactDecoder.h
saml/saml1/binding/SAML1ArtifactEncoder.h
saml/saml1/binding/SAML1POSTDecoder.h
saml/saml1/binding/SAML1POSTEncoder.h
saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp
saml/saml1/binding/impl/SAML1ArtifactEncoder.cpp
saml/saml1/binding/impl/SAML1POSTDecoder.cpp
saml/saml1/binding/impl/SAML1POSTEncoder.cpp
saml/saml1/core/Assertions.h
saml/saml1/core/Protocols.h
saml/saml1/core/impl/AssertionsImpl.cpp
saml/saml1/core/impl/ProtocolsImpl.cpp
saml/saml2/binding/SAML2ArtifactDecoder.h
saml/saml2/binding/SAML2ArtifactEncoder.h
saml/saml2/binding/SAML2POSTDecoder.h
saml/saml2/binding/SAML2POSTEncoder.h
saml/saml2/binding/SAML2Redirect.h [new file with mode: 0644]
saml/saml2/binding/SAML2RedirectDecoder.h [new file with mode: 0644]
saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp
saml/saml2/binding/impl/SAML2ArtifactEncoder.cpp
saml/saml2/binding/impl/SAML2POSTDecoder.cpp
saml/saml2/binding/impl/SAML2POSTEncoder.cpp
saml/saml2/binding/impl/SAML2Redirect.cpp [new file with mode: 0644]
saml/saml2/binding/impl/SAML2RedirectDecoder.cpp [new file with mode: 0644]
saml/saml2/core/Assertions.h
saml/saml2/core/Protocols.h
saml/saml2/metadata/Metadata.h
saml/signature/SignableObject.h
saml/util/SAMLConstants.cpp
saml/util/SAMLConstants.h
samltest/binding.h
samltest/saml1/binding/SAML1ArtifactTest.h
samltest/saml1/binding/SAML1POSTTest.h
samltest/saml2/binding/SAML2ArtifactTest.h
samltest/saml2/binding/SAML2POSTTest.h

index 636ffac..ae7c2d1 100644 (file)
@@ -28,13 +28,22 @@ libsamlinclude_HEADERS = \
        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 = \
@@ -95,7 +104,10 @@ libsaml_la_SOURCES = \
        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 \
diff --git a/saml/RootObject.h b/saml/RootObject.h
new file mode 100644 (file)
index 0000000..5ce98ec
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *  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__ */
index 709850e..ef24319 100644 (file)
@@ -125,6 +125,7 @@ bool SAMLInternalConfig::init(bool initXMLTooling)
     registerTrustEngines();
     registerMessageEncoders();
     registerMessageDecoders();
+    registerSecurityPolicyRules();
     
     m_urlEncoder = new URLEncoder();
 
@@ -142,6 +143,7 @@ void SAMLInternalConfig::term(bool termXMLTooling)
     MessageDecoderManager.deregisterFactories();
     MessageEncoderManager.deregisterFactories();
     TrustEngineManager.deregisterFactories();
+    SecurityPolicyRuleManager.deregisterFactories();
     SAMLArtifactManager.deregisterFactories();
     MetadataFilterManager.deregisterFactories();
     MetadataProviderManager.deregisterFactories();
index 566c2d1..b6f620a 100644 (file)
@@ -40,6 +40,7 @@ namespace opensaml {
     class SAML_API MessageEncoder;
     class SAML_API MessageDecoder;
     class SAML_API SAMLArtifact;
+    class SAML_API SecurityPolicyRule;
     class SAML_API TrustEngine;
     class SAML_API URLEncoder;
 
@@ -164,34 +165,25 @@ namespace opensaml {
          */
         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:
diff --git a/saml/binding/GenericRequest.h b/saml/binding/GenericRequest.h
new file mode 100644 (file)
index 0000000..0acfd4d
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ *  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__ */
diff --git a/saml/binding/GenericResponse.h b/saml/binding/GenericResponse.h
new file mode 100644 (file)
index 0000000..f955e5c
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *  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__ */
diff --git a/saml/binding/HTTPRequest.h b/saml/binding/HTTPRequest.h
new file mode 100644 (file)
index 0000000..2c34a83
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  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__ */
diff --git a/saml/binding/HTTPResponse.h b/saml/binding/HTTPResponse.h
new file mode 100644 (file)
index 0000000..e77e17d
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  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__ */
index 70a4768..ef69d61 100644 (file)
@@ -23,8 +23,8 @@
 #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 {
@@ -43,7 +43,7 @@ namespace opensaml {
         class SAML_API IDPSSODescriptor;
         class SAML_API RoleDescriptor;
         class SAML_API SSODescriptorType;
-    }
+    };
 
     /**
      * Interface to SAML protocol binding message decoders.
@@ -55,90 +55,6 @@ namespace opensaml {
         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
@@ -173,36 +89,36 @@ namespace opensaml {
             
             /**
              * 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;
         };
 
@@ -233,35 +149,23 @@ namespace opensaml {
         }
 
         /**
-         * 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:
index 536acf4..9e611ff 100644 (file)
 #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>
@@ -48,59 +46,6 @@ namespace opensaml {
         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
@@ -146,7 +91,7 @@ namespace opensaml {
         }
         
         /**
-         * 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.
          * 
@@ -157,7 +102,7 @@ namespace opensaml {
          * <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
@@ -166,7 +111,7 @@ namespace opensaml {
          * @param sigAlgorithm      optional signature algorithm identifier
          */
         virtual long encode(
-            HTTPResponse& httpResponse,
+            GenericResponse& genericResponse,
             xmltooling::XMLObject* xmlObject,
             const char* destination,
             const char* recipientID=NULL,
diff --git a/saml/binding/MessageFlowRule.h b/saml/binding/MessageFlowRule.h
new file mode 100644 (file)
index 0000000..97c9797
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  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;
+    };
+    
+};
diff --git a/saml/binding/MessageSigningRule.h b/saml/binding/MessageSigningRule.h
new file mode 100644 (file)
index 0000000..1fa0581
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *  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;
+    };
+    
+};
diff --git a/saml/binding/SecurityPolicy.h b/saml/binding/SecurityPolicy.h
new file mode 100644 (file)
index 0000000..67259ca
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *  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__ */
diff --git a/saml/binding/SecurityPolicyRule.h b/saml/binding/SecurityPolicyRule.h
new file mode 100644 (file)
index 0000000..f547251
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ *  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__ */
diff --git a/saml/binding/impl/MessageFlowRule.cpp b/saml/binding/impl/MessageFlowRule.cpp
new file mode 100644 (file)
index 0000000..0e8cea3
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ *  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()));
+        }
+    }
+}
diff --git a/saml/binding/impl/MessageSigningRule.cpp b/saml/binding/impl/MessageSigningRule.cpp
new file mode 100644 (file)
index 0000000..6b9eedf
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ *  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);
+}
diff --git a/saml/binding/impl/SecurityPolicy.cpp b/saml/binding/impl/SecurityPolicy.cpp
new file mode 100644 (file)
index 0000000..0b30af3
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ *  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;
+}
index 3f2c224..6a44790 100644 (file)
                                                        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
index 141a83e..c1e384b 100644 (file)
@@ -38,12 +38,8 @@ namespace opensaml {
             
             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;
         };                
 
index 15f0ed1..a4d4718 100644 (file)
@@ -36,7 +36,7 @@ namespace opensaml {
             virtual ~SAML1ArtifactEncoder();
             
             long encode(
-                HTTPResponse& httpResponse,
+                GenericResponse& genericResponse,
                 xmltooling::XMLObject* xmlObject,
                 const char* destination,
                 const char* recipientID=NULL,
index 2236239..9ed3334 100644 (file)
@@ -38,12 +38,8 @@ namespace opensaml {
             
             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;
         };                
 
index 4ab47bf..1496aff 100644 (file)
@@ -36,7 +36,7 @@ namespace opensaml {
             virtual ~SAML1POSTEncoder();
             
             long encode(
-                HTTPResponse& httpResponse,
+                GenericResponse& genericResponse,
                 xmltooling::XMLObject* xmlObject,
                 const char* destination,
                 const char* recipientID=NULL,
index 72ce569..83cd7ba 100644 (file)
 
 #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>
@@ -34,9 +34,7 @@
 
 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;
@@ -56,12 +54,8 @@ SAML1ArtifactDecoder::~SAML1ArtifactDecoder() {}
 
 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
@@ -70,16 +64,21 @@ Response* SAML1ArtifactDecoder::decode(
     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;
@@ -111,10 +110,8 @@ Response* SAML1ArtifactDecoder::decode(
         }
     }
     
-    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)",
@@ -130,11 +127,11 @@ Response* SAML1ArtifactDecoder::decode(
     }
     
     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
@@ -142,33 +139,17 @@ Response* SAML1ArtifactDecoder::decode(
     
     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;
     }
 }
index b747201..7252831 100644 (file)
@@ -23,6 +23,7 @@
 #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"
@@ -53,7 +54,7 @@ SAML1ArtifactEncoder::SAML1ArtifactEncoder(const DOMElement* e) {}
 SAML1ArtifactEncoder::~SAML1ArtifactEncoder() {}
 
 long SAML1ArtifactEncoder::encode(
-    HTTPResponse& httpResponse,
+    GenericResponse& genericResponse,
     XMLObject* xmlObject,
     const char* destination,
     const char* recipientID,
@@ -66,8 +67,11 @@ long SAML1ArtifactEncoder::encode(
     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);
@@ -98,5 +102,5 @@ long SAML1ArtifactEncoder::encode(
     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());
 }
index ebdb2a4..33ac05f 100644 (file)
 
 #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;
@@ -58,12 +56,8 @@ SAML1POSTDecoder::~SAML1POSTDecoder() {}
 
 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
@@ -72,10 +66,15 @@ Response* SAML1POSTDecoder::decode(
     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;
@@ -100,14 +99,13 @@ Response* SAML1POSTDecoder::decode(
     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.");
@@ -117,98 +115,33 @@ Response* SAML1POSTDecoder::decode(
             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
     }
 
index ccc5510..ce99ce1 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "internal.h"
 #include "exceptions.h"
+#include "binding/HTTPResponse.h"
 #include "saml1/binding/SAML1POSTEncoder.h"
 #include "saml1/core/Protocols.h"
 
@@ -64,7 +65,7 @@ SAML1POSTEncoder::SAML1POSTEncoder(const DOMElement* e)
 SAML1POSTEncoder::~SAML1POSTEncoder() {}
 
 long SAML1POSTEncoder::encode(
-    HTTPResponse& httpResponse,
+    GenericResponse& genericResponse,
     XMLObject* xmlObject,
     const char* destination,
     const char* recipientID,
@@ -77,8 +78,11 @@ long SAML1POSTEncoder::encode(
     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);
@@ -137,7 +141,8 @@ long SAML1POSTEncoder::encode(
     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;
index b4cf753..0da3ecf 100644 (file)
@@ -23,7 +23,7 @@
 #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>
@@ -217,11 +217,11 @@ namespace opensaml {
             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);
@@ -229,7 +229,7 @@ namespace opensaml {
             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;
index 074edea..2201d09 100644 (file)
@@ -23,7 +23,7 @@
 #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>
@@ -91,12 +91,12 @@ namespace opensaml {
             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;
@@ -142,13 +142,13 @@ namespace opensaml {
             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;
index 6d6bb1c..a8127ab 100644 (file)
@@ -1014,6 +1014,9 @@ namespace opensaml {
                 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);
index a823253..550367c 100644 (file)
@@ -361,6 +361,9 @@ namespace opensaml {
                 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);
     
@@ -680,6 +683,9 @@ namespace opensaml {
                 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);
index 9c3cd96..bf297c0 100644 (file)
@@ -41,16 +41,9 @@ namespace opensaml {
             
             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;
         };                
 
     };
index 01057f8..d3f5f3d 100644 (file)
@@ -36,7 +36,7 @@ namespace opensaml {
             virtual ~SAML2ArtifactEncoder();
             
             long encode(
-                HTTPResponse& httpResponse,
+                GenericResponse& genericResponse,
                 xmltooling::XMLObject* xmlObject,
                 const char* destination,
                 const char* recipientID=NULL,
index 31c2f6a..00edb7a 100644 (file)
  */
 
 #include <saml/binding/MessageDecoder.h>
+#include <saml/saml2/core/Assertions.h>
 
 namespace opensaml {
+    
     namespace saml2p {
 
         /**
@@ -34,14 +36,10 @@ namespace opensaml {
             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;
         };                
 
index 3f325e4..4417849 100644 (file)
@@ -36,7 +36,7 @@ namespace opensaml {
             virtual ~SAML2POSTEncoder();
             
             long encode(
-                HTTPResponse& httpResponse,
+                GenericResponse& genericResponse,
                 xmltooling::XMLObject* xmlObject,
                 const char* destination,
                 const char* recipientID=NULL,
diff --git a/saml/saml2/binding/SAML2Redirect.h b/saml/saml2/binding/SAML2Redirect.h
new file mode 100644 (file)
index 0000000..d6b8400
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ *  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);
+        
+    };
+};
diff --git a/saml/saml2/binding/SAML2RedirectDecoder.h b/saml/saml2/binding/SAML2RedirectDecoder.h
new file mode 100644 (file)
index 0000000..f0ced2b
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  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;
+        };                
+
+    };
+};
index 846254a..1cd434e 100644 (file)
 
 #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>
@@ -38,7 +38,6 @@ 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;
@@ -58,12 +57,8 @@ SAML2ArtifactDecoder::~SAML2ArtifactDecoder() {}
 
 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
@@ -72,23 +67,28 @@ XMLObject* SAML2ArtifactDecoder::decode(
     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);
@@ -112,10 +112,8 @@ XMLObject* SAML2ArtifactDecoder::decode(
         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)",
@@ -130,103 +128,31 @@ XMLObject* SAML2ArtifactDecoder::decode(
     }
     
     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;
-}
-
index 048eeb7..2ce48a3 100644 (file)
@@ -23,6 +23,7 @@
 #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"
@@ -64,7 +65,7 @@ SAML2ArtifactEncoder::SAML2ArtifactEncoder(const DOMElement* e)
 SAML2ArtifactEncoder::~SAML2ArtifactEncoder() {}
 
 long SAML2ArtifactEncoder::encode(
-    HTTPResponse& httpResponse,
+    GenericResponse& genericResponse,
     xmltooling::XMLObject* xmlObject,
     const char* destination,
     const char* recipientID,
@@ -77,8 +78,11 @@ long SAML2ArtifactEncoder::encode(
     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.");
     
@@ -135,7 +139,7 @@ long SAML2ArtifactEncoder::encode(
         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. 
@@ -153,6 +157,7 @@ long SAML2ArtifactEncoder::encode(
             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);
     }
 }
index 2258304..a7f1cda 100644 (file)
 
 #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;
@@ -56,14 +54,10 @@ SAML2POSTDecoder::SAML2POSTDecoder(const DOMElement* e) {}
 
 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
@@ -72,14 +66,19 @@ XMLObject* SAML2POSTDecoder::decode(
     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
@@ -101,40 +100,27 @@ XMLObject* SAML2POSTDecoder::decode(
     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.");
         }
@@ -143,88 +129,44 @@ XMLObject* SAML2POSTDecoder::decode(
             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;
 }
index 9a4e7df..ec73691 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "internal.h"
 #include "exceptions.h"
+#include "binding/HTTPResponse.h"
 #include "saml2/binding/SAML2POSTEncoder.h"
 #include "saml2/core/Protocols.h"
 
@@ -64,7 +65,7 @@ SAML2POSTEncoder::SAML2POSTEncoder(const DOMElement* e)
 SAML2POSTEncoder::~SAML2POSTEncoder() {}
 
 long SAML2POSTEncoder::encode(
-    HTTPResponse& httpResponse,
+    GenericResponse& genericResponse,
     XMLObject* xmlObject,
     const char* destination,
     const char* recipientID,
@@ -77,8 +78,11 @@ long SAML2POSTEncoder::encode(
     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.");
     
@@ -143,7 +147,8 @@ long SAML2POSTEncoder::encode(
         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;
diff --git a/saml/saml2/binding/impl/SAML2Redirect.cpp b/saml/saml2/binding/impl/SAML2Redirect.cpp
new file mode 100644 (file)
index 0000000..b90a89b
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *  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;
+}
diff --git a/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp b/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp
new file mode 100644 (file)
index 0000000..6afb59a
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ *  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();
+}
index e4cd74a..ae5018d 100644 (file)
@@ -23,7 +23,7 @@
 #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>
@@ -79,7 +79,7 @@ namespace opensaml {
         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;
@@ -306,12 +306,29 @@ namespace opensaml {
             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);
index 440032f..c93c758 100644 (file)
@@ -50,14 +50,14 @@ namespace opensaml {
             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[];
@@ -140,19 +140,17 @@ namespace opensaml {
             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;
@@ -174,7 +172,6 @@ namespace opensaml {
             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[];
 
index ee6863b..457afc2 100644 (file)
@@ -163,7 +163,7 @@ namespace opensaml {
             /** 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);
@@ -322,7 +322,7 @@ namespace opensaml {
                 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);
@@ -334,7 +334,7 @@ namespace opensaml {
                 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);
@@ -372,7 +372,7 @@ namespace opensaml {
                 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);
index a1d6521..1e0119b 100644 (file)
@@ -48,6 +48,13 @@ namespace opensaml {
             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() {}
     };
index 7c790d9..f5a4db4 100644 (file)
@@ -186,3 +186,5 @@ const char samlconstants::SAML20_BINDING_HTTP_ARTIFACT[] = "urn:oasis:names:tc:S
 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
index 17eade2..1fc82ff 100644 (file)
@@ -137,6 +137,9 @@ namespace samlconstants {
 
     /** 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__ */
index 15aa249..fdd0ce7 100644 (file)
-/*
- *  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,"&lt;",4)) {
-                    decoded+='<'; ch+=4;
-                }
-                else if (!strncmp(ch,"&gt;",4)) {
-                    decoded+='>'; ch+=4;
-                }
-                else if (!strncmp(ch,"&quot;",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,"&lt;",4)) {\r
+                    decoded+='<'; ch+=4;\r
+                }\r
+                else if (!strncmp(ch,"&gt;",4)) {\r
+                    decoded+='>'; ch+=4;\r
+                }\r
+                else if (!strncmp(ch,"&quot;",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
index cfa8a2c..e5ebe30 100644 (file)
@@ -1,30 +1,30 @@
-/*
- *  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
@@ -36,81 +36,75 @@ namespace {
         }\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
@@ -129,39 +123,36 @@ public:
         \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
index f84bf8a..e485a76 100644 (file)
@@ -31,69 +31,11 @@ public:
         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());
@@ -104,7 +46,7 @@ public:
                 );
             janitor.release();
 
-            // Freshen timestamp and clear ID.
+            // Freshen timestamp and ID.
             toSend->setIssueInstant(time(NULL));
             toSend->setResponseID(NULL);
     
@@ -122,36 +64,27 @@ public:
                     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());
index 958e5ed..a6e4449 100644 (file)
-/*
- *  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
index 6245b6e..7d6ec3e 100644 (file)
@@ -31,69 +31,11 @@ public:
         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());
@@ -104,7 +46,7 @@ public:
                 );
             janitor.release();
 
-            // Freshen timestamp and clear ID.
+            // Freshen timestamp and ID.
             toSend->setIssueInstant(time(NULL));
             toSend->setID(NULL);
     
@@ -122,36 +64,27 @@ public:
                     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());