From 750aa26530f9e8993eae37cd9e68e25497be66b5 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Thu, 23 Nov 2006 04:22:59 +0000 Subject: [PATCH] Allow message-only policy rules, basic SAML SOAP client. --- saml/Makefile.am | 2 + saml/binding/ClientCertAuthRule.h | 2 +- saml/binding/MessageFlowRule.h | 2 +- saml/binding/SOAPClient.h | 95 ++++++++++++++++++++++++ saml/binding/SecurityPolicy.h | 9 +-- saml/binding/SecurityPolicyRule.h | 4 +- saml/binding/SimpleSigningRule.h | 2 +- saml/binding/XMLSigningRule.h | 2 +- saml/binding/impl/ClientCertAuthRule.cpp | 10 ++- saml/binding/impl/MessageFlowRule.cpp | 2 +- saml/binding/impl/SOAPClient.cpp | 76 +++++++++++++++++++ saml/binding/impl/SecurityPolicy.cpp | 4 +- saml/binding/impl/SimpleSigningRule.cpp | 25 ++++--- saml/binding/impl/XMLSigningRule.cpp | 2 +- saml/saml.vcproj | 8 ++ saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp | 2 +- saml/saml1/binding/impl/SAML1POSTDecoder.cpp | 2 +- saml/saml1/binding/impl/SAML1SOAPDecoder.cpp | 4 +- saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp | 4 +- saml/saml2/binding/impl/SAML2POSTDecoder.cpp | 5 +- saml/saml2/binding/impl/SAML2RedirectDecoder.cpp | 5 +- saml/saml2/binding/impl/SAML2SOAPDecoder.cpp | 4 +- 22 files changed, 229 insertions(+), 42 deletions(-) create mode 100644 saml/binding/SOAPClient.h create mode 100644 saml/binding/impl/SOAPClient.cpp diff --git a/saml/Makefile.am b/saml/Makefile.am index 5a7e285..a779fe7 100644 --- a/saml/Makefile.am +++ b/saml/Makefile.am @@ -45,6 +45,7 @@ samlbindinclude_HEADERS = \ binding/SecurityPolicy.h \ binding/SecurityPolicyRule.h \ binding/SimpleSigningRule.h \ + binding/SOAPClient.h \ binding/URLEncoder.h \ binding/XMLSigningRule.h @@ -112,6 +113,7 @@ libsaml_la_SOURCES = \ binding/impl/SAMLArtifact.cpp \ binding/impl/SecurityPolicy.cpp \ binding/impl/SimpleSigningRule.cpp \ + binding/impl/SOAPClient.cpp \ binding/impl/URLEncoder.cpp \ binding/impl/XMLSigningRule.cpp \ saml1/core/impl/AssertionsImpl.cpp \ diff --git a/saml/binding/ClientCertAuthRule.h b/saml/binding/ClientCertAuthRule.h index 0b90bd7..edd9b99 100644 --- a/saml/binding/ClientCertAuthRule.h +++ b/saml/binding/ClientCertAuthRule.h @@ -34,8 +34,8 @@ namespace opensaml { virtual ~ClientCertAuthRule() {} std::pair evaluate( - const GenericRequest& request, const xmltooling::XMLObject& message, + const GenericRequest* request, const saml2md::MetadataProvider* metadataProvider, const xmltooling::QName* role, const xmltooling::TrustEngine* trustEngine diff --git a/saml/binding/MessageFlowRule.h b/saml/binding/MessageFlowRule.h index 9e261c5..885b82a 100644 --- a/saml/binding/MessageFlowRule.h +++ b/saml/binding/MessageFlowRule.h @@ -37,8 +37,8 @@ namespace opensaml { virtual ~MessageFlowRule() {} std::pair evaluate( - const GenericRequest& request, const xmltooling::XMLObject& message, + const GenericRequest* request, const saml2md::MetadataProvider* metadataProvider, const xmltooling::QName* role, const xmltooling::TrustEngine* trustEngine diff --git a/saml/binding/SOAPClient.h b/saml/binding/SOAPClient.h new file mode 100644 index 0000000..fcc89bd --- /dev/null +++ b/saml/binding/SOAPClient.h @@ -0,0 +1,95 @@ +/* + * 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/SOAPClient.h + * + * Specialized SOAPClient for SAML SOAP bindings. + */ + +#ifndef __saml_soap11client_h__ +#define __saml_soap11client_h__ + +#include +#include + +namespace opensaml { + + /** + * Specialized SOAPClient for SAML SOAP bindings. + */ + class SAML_API SOAPClient : soap11::SOAPClient + { + public: + /** + * Creates a SOAP client instance with a particular SecurityPolicy. + * + * @param policy reference to SecurityPolicy to apply + */ + SOAPClient(SecurityPolicy& policy) : m_policy(policy), m_force(true) {} + + virtual ~SOAPClient() {} + + /** + * Controls whether to force transport/peer authentication via an X509TrustEngine. + * + *

Only makes sense if an X509TrustEngine is supplied by the SecurityPolicy. + * + * @param force true iff the client should refuse to communicate without this protection + */ + void forceTransportAuthentication(bool force=true) { + m_force = force; + } + + /** + * Override prepares the SecurityPolicy by clearing Issuer identity, in case the policy + * is reused. + * + * @param env SOAP envelope to send + * @param peer peer to send message to, expressed in TrustEngine terms + * @param endpoint URL of endpoint to recieve message + */ + void send(const soap11::Envelope* env, const xmltooling::KeyInfoSource& peer, const char* endpoint); + + /** + * Override applies SecurityPolicy to envelope before returning it. + * + * @return response envelope after SecurityPolicy has been applied + */ + soap11::Envelope* receive(); + + protected: + /** + * Override prepares transport by assigning an X509TrustEngine to it, if one is + * attached to the policy. + * + * @param transport reference to transport layer + */ + void prepareTransport(const xmltooling::SOAPTransport& transport); + + /** Reference to security policy to apply. */ + SecurityPolicy& m_policy; + + /** Flag controlling whether transport/peer authn is mandatory. */ + bool m_force; + + private: + const saml2md::RoleDescriptor* m_peer; + }; + +}; + +#endif /* __saml_soap11client_h__ */ diff --git a/saml/binding/SecurityPolicy.h b/saml/binding/SecurityPolicy.h index 8994179..96fdffe 100644 --- a/saml/binding/SecurityPolicy.h +++ b/saml/binding/SecurityPolicy.h @@ -151,16 +151,15 @@ namespace opensaml { } /** - * Evaluates the rule against the given request and message, + * Evaluates the policy 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 + * @param request the protocol request * - * @throws BindingException thrown if the request/message do not meet the requirements of this rule + * @throws BindingException thrown if the request/message do not meet the requirements of this policy */ - void evaluate(const GenericRequest& request, const xmltooling::XMLObject& message); + void evaluate(const xmltooling::XMLObject& message, const GenericRequest* request=NULL); /** * Gets the issuer of the message as determined by the registered policies. diff --git a/saml/binding/SecurityPolicyRule.h b/saml/binding/SecurityPolicyRule.h index 517d4b4..ed31d7c 100644 --- a/saml/binding/SecurityPolicyRule.h +++ b/saml/binding/SecurityPolicyRule.h @@ -55,8 +55,8 @@ namespace opensaml { * 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 request the protocol request * @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 @@ -66,8 +66,8 @@ namespace opensaml { * @throws BindingException thrown if the request/message do not meet the requirements of this rule */ virtual std::pair evaluate( - const GenericRequest& request, const xmltooling::XMLObject& message, + const GenericRequest* request, const saml2md::MetadataProvider* metadataProvider, const xmltooling::QName* role, const xmltooling::TrustEngine* trustEngine diff --git a/saml/binding/SimpleSigningRule.h b/saml/binding/SimpleSigningRule.h index 0219d9c..bceac07 100644 --- a/saml/binding/SimpleSigningRule.h +++ b/saml/binding/SimpleSigningRule.h @@ -38,8 +38,8 @@ namespace opensaml { virtual ~SimpleSigningRule() {} std::pair evaluate( - const GenericRequest& request, const xmltooling::XMLObject& message, + const GenericRequest* request, const saml2md::MetadataProvider* metadataProvider, const xmltooling::QName* role, const xmltooling::TrustEngine* trustEngine diff --git a/saml/binding/XMLSigningRule.h b/saml/binding/XMLSigningRule.h index ed499db..d2c3580 100644 --- a/saml/binding/XMLSigningRule.h +++ b/saml/binding/XMLSigningRule.h @@ -37,8 +37,8 @@ namespace opensaml { virtual ~XMLSigningRule() {} std::pair evaluate( - const GenericRequest& request, const xmltooling::XMLObject& message, + const GenericRequest* request, const saml2md::MetadataProvider* metadataProvider, const xmltooling::QName* role, const xmltooling::TrustEngine* trustEngine diff --git a/saml/binding/impl/ClientCertAuthRule.cpp b/saml/binding/impl/ClientCertAuthRule.cpp index 307a1d7..f13e25e 100644 --- a/saml/binding/impl/ClientCertAuthRule.cpp +++ b/saml/binding/impl/ClientCertAuthRule.cpp @@ -45,8 +45,8 @@ namespace opensaml { }; pair ClientCertAuthRule::evaluate( - const GenericRequest& request, const XMLObject& message, + const GenericRequest* request, const MetadataProvider* metadataProvider, const QName* role, const TrustEngine* trustEngine @@ -55,7 +55,11 @@ pair ClientCertAuthRule::evaluate( Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.ClientCertAuth"); log.debug("evaluating client certificate authentication policy"); - pair ret = pair(NULL,NULL); + pair ret = pair(NULL,NULL); + if (!request) { + log.debug("ignoring message, no protocol request available"); + return ret; + } const X509TrustEngine* x509trust; if (!metadataProvider || !role || !(x509trust=dynamic_cast(trustEngine))) { @@ -63,7 +67,7 @@ pair ClientCertAuthRule::evaluate( return ret; } - const std::vector& chain = request.getClientCertificates(); + const std::vector& chain = request->getClientCertificates(); if (chain.empty()) { log.debug("ignoring message, no client certificates in request"); return ret; diff --git a/saml/binding/impl/MessageFlowRule.cpp b/saml/binding/impl/MessageFlowRule.cpp index 9db7c4e..f7412c2 100644 --- a/saml/binding/impl/MessageFlowRule.cpp +++ b/saml/binding/impl/MessageFlowRule.cpp @@ -59,8 +59,8 @@ MessageFlowRule::MessageFlowRule(const DOMElement* e) } pair MessageFlowRule::evaluate( - const GenericRequest& request, const XMLObject& message, + const GenericRequest* request, const saml2md::MetadataProvider* metadataProvider, const QName* role, const TrustEngine* trustEngine diff --git a/saml/binding/impl/SOAPClient.cpp b/saml/binding/impl/SOAPClient.cpp new file mode 100644 index 0000000..45693dc --- /dev/null +++ b/saml/binding/impl/SOAPClient.cpp @@ -0,0 +1,76 @@ +/* + * 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. + */ + +/** + * SOAPClient.cpp + * + * Implements SOAP 1.1 messaging over a transport. + */ + +#include "internal.h" +#include "exceptions.h" +#include "binding/SOAPClient.h" +#include "saml2/metadata/Metadata.h" +#include "saml2/metadata/MetadataProvider.h" + +#include +#include + +using namespace opensaml::saml2; +using namespace opensaml::saml2md; +using namespace opensaml; +using namespace xmltooling; +using namespace std; + +void SOAPClient::send(const soap11::Envelope* env, const KeyInfoSource& peer, const char* endpoint) +{ + // Clear policy. + m_policy.setIssuer(NULL); + m_policy.setIssuerMetadata(NULL); + + m_peer = dynamic_cast(&peer); + + soap11::SOAPClient::send(env, peer, endpoint); +} + +void SOAPClient::prepareTransport(const xmltooling::SOAPTransport& transport) +{ + const X509TrustEngine* engine = dynamic_cast(m_policy.getTrustEngine()); + if (engine) { + const MetadataProvider* metadata = m_policy.getMetadataProvider(); + if (!transport.setTrustEngine(engine, m_force, metadata ? metadata->getKeyResolver() : NULL)) + throw BindingException("Unable to install X509TrustEngine into SOAPTransport."); + } +} + +soap11::Envelope* SOAPClient::receive() +{ + auto_ptr env(soap11::SOAPClient::receive()); + if (env.get()) { + if (m_peer && m_transport->isSecure()) { + // Set issuer based on peer identity. + EntityDescriptor* parent = dynamic_cast(m_peer->getParent()); + if (parent) { + Issuer* issuer = IssuerBuilder::buildIssuer(); + issuer->setName(parent->getEntityID()); + m_policy.setIssuer(issuer); + m_policy.setIssuerMetadata(m_peer); + } + } + m_policy.evaluate(*(env.get())); + } + return env.release(); +} diff --git a/saml/binding/impl/SecurityPolicy.cpp b/saml/binding/impl/SecurityPolicy.cpp index b2157ce..350057e 100644 --- a/saml/binding/impl/SecurityPolicy.cpp +++ b/saml/binding/impl/SecurityPolicy.cpp @@ -58,12 +58,12 @@ SecurityPolicy::~SecurityPolicy() delete m_issuer; } -void SecurityPolicy::evaluate(const GenericRequest& request, const XMLObject& message) +void SecurityPolicy::evaluate(const XMLObject& message, const GenericRequest* request) { for (vector::const_iterator i=m_rules.begin(); i!=m_rules.end(); ++i) { // Run the rule... - pair ident = (*i)->evaluate(request,message,m_metadata,&m_role,m_trust); + pair ident = (*i)->evaluate(message,request,m_metadata,&m_role,m_trust); // Make sure returned issuer doesn't conflict. diff --git a/saml/binding/impl/SimpleSigningRule.cpp b/saml/binding/impl/SimpleSigningRule.cpp index 3a09638..7f1ea7f 100644 --- a/saml/binding/impl/SimpleSigningRule.cpp +++ b/saml/binding/impl/SimpleSigningRule.cpp @@ -68,8 +68,8 @@ namespace opensaml { pair SimpleSigningRule::evaluate( - const GenericRequest& request, const XMLObject& message, + const GenericRequest* request, const MetadataProvider* metadataProvider, const QName* role, const TrustEngine* trustEngine @@ -80,18 +80,24 @@ pair SimpleSigningRule::evaluate( pair ret = pair(NULL,NULL); + const HTTPRequest* httpRequest = dynamic_cast(request); + if (!request || !httpRequest) { + log.debug("ignoring message, no HTTP protocol request available"); + return ret; + } + if (!metadataProvider || !role || !trustEngine) { log.debug("ignoring message, no metadata supplied"); return ret; } - const char* signature = request.getParameter("Signature"); + const char* signature = request->getParameter("Signature"); if (!signature) { log.debug("ignoring unsigned message"); return ret; } - const char* sigAlgorithm = request.getParameter("SigAlg"); + const char* sigAlgorithm = request->getParameter("SigAlg"); if (!sigAlgorithm) { log.error("SigAlg parameter not found, no way to verify the signature"); return ret; @@ -125,12 +131,11 @@ pair SimpleSigningRule::evaluate( string input; const char* pch; - const HTTPRequest& httpRequest = dynamic_cast(request); - if (!strcmp(httpRequest.getMethod(), "GET")) { + if (!strcmp(httpRequest->getMethod(), "GET")) { // We have to construct a string containing the signature input by accessing the // request directly. We can't use the decoded parameters because we need the raw // data and URL-encoding isn't canonical. - pch = httpRequest.getQueryString(); + pch = httpRequest->getQueryString(); if (!appendParameter(input, pch, "SAMLRequest=")) appendParameter(input, pch, "SAMLResponse="); appendParameter(input, pch, "RelayState="); @@ -139,14 +144,14 @@ pair SimpleSigningRule::evaluate( else { // With POST, the input string is concatenated from the decoded form controls. // GET should be this way too, but I messed up the spec, sorry. - pch = httpRequest.getParameter("SAMLRequest"); + pch = httpRequest->getParameter("SAMLRequest"); if (pch) input = string("SAMLRequest=") + pch; else { - pch = httpRequest.getParameter("SAMLResponse"); + pch = httpRequest->getParameter("SAMLResponse"); input = string("SAMLResponse=") + pch; } - pch = httpRequest.getParameter("RelayState"); + pch = httpRequest->getParameter("RelayState"); if (pch) input = input + "&RelayState=" + pch; input = input + "&SigAlg=" + sigAlgorithm; @@ -154,7 +159,7 @@ pair SimpleSigningRule::evaluate( // Check for KeyInfo, but defensively (we might be able to run without it). KeyInfo* keyInfo=NULL; - pch = request.getParameter("KeyInfo"); + pch = request->getParameter("KeyInfo"); if (pch) { try { istringstream kstrm(pch); diff --git a/saml/binding/impl/XMLSigningRule.cpp b/saml/binding/impl/XMLSigningRule.cpp index 6cc736d..56c2250 100644 --- a/saml/binding/impl/XMLSigningRule.cpp +++ b/saml/binding/impl/XMLSigningRule.cpp @@ -48,8 +48,8 @@ namespace opensaml { }; pair XMLSigningRule::evaluate( - const GenericRequest& request, const XMLObject& message, + const GenericRequest* request, const MetadataProvider* metadataProvider, const QName* role, const TrustEngine* trustEngine diff --git a/saml/saml.vcproj b/saml/saml.vcproj index 8f121e1..4682f2b 100644 --- a/saml/saml.vcproj +++ b/saml/saml.vcproj @@ -486,6 +486,10 @@ > + + @@ -801,6 +805,10 @@ > + + diff --git a/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp b/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp index 0f467f0..bc0f0e6 100644 --- a/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp +++ b/saml/saml1/binding/impl/SAML1ArtifactDecoder.cpp @@ -140,7 +140,7 @@ XMLObject* SAML1ArtifactDecoder::decode( m_artifactResolver->resolve(artifacts, dynamic_cast(*roledesc), policy) ); - policy.evaluate(genericRequest, *(response.get())); + policy.evaluate(*(response.get()), &genericRequest); for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup()); return response.release(); diff --git a/saml/saml1/binding/impl/SAML1POSTDecoder.cpp b/saml/saml1/binding/impl/SAML1POSTDecoder.cpp index f3018ef..fd3258a 100644 --- a/saml/saml1/binding/impl/SAML1POSTDecoder.cpp +++ b/saml/saml1/binding/impl/SAML1POSTDecoder.cpp @@ -114,7 +114,7 @@ XMLObject* SAML1POSTDecoder::decode( } // Run through the policy. - policy.evaluate(genericRequest, *response); + policy.evaluate(*response, &genericRequest); } catch (XMLToolingException& ex) { // This is just to maximize the likelihood of attaching a source to the message for support purposes. diff --git a/saml/saml1/binding/impl/SAML1SOAPDecoder.cpp b/saml/saml1/binding/impl/SAML1SOAPDecoder.cpp index ffd191f..10fd72f 100644 --- a/saml/saml1/binding/impl/SAML1SOAPDecoder.cpp +++ b/saml/saml1/binding/impl/SAML1SOAPDecoder.cpp @@ -91,8 +91,8 @@ XMLObject* SAML1SOAPDecoder::decode( Request* request = dynamic_cast(body->getXMLObjects().front()); if (request) { // Run through the policy at two layers. - policy.evaluate(genericRequest, *env); - policy.evaluate(genericRequest, *request); + policy.evaluate(*env, &genericRequest); + policy.evaluate(*request, &genericRequest); xmlObject.release(); body->detach(); // frees Envelope request->detach(); // frees Body diff --git a/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp b/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp index 48fcceb..c309162 100644 --- a/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2ArtifactDecoder.cpp @@ -138,11 +138,11 @@ XMLObject* SAML2ArtifactDecoder::decode( m_artifactResolver->resolve(*(artifact2.get()), dynamic_cast(*roledesc), policy) ); - policy.evaluate(genericRequest, *(response.get())); + policy.evaluate(*(response.get()), &genericRequest); // Extract payload and check that message. XMLObject* payload = response->getPayload(); - policy.evaluate(genericRequest, *payload); + policy.evaluate(*payload, &genericRequest); // Return the payload only. response.release(); diff --git a/saml/saml2/binding/impl/SAML2POSTDecoder.cpp b/saml/saml2/binding/impl/SAML2POSTDecoder.cpp index ebb2ec2..8b953e3 100644 --- a/saml/saml2/binding/impl/SAML2POSTDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2POSTDecoder.cpp @@ -128,7 +128,7 @@ XMLObject* SAML2POSTDecoder::decode( } // Run through the policy. - policy.evaluate(genericRequest, *root); + policy.evaluate(*root, &genericRequest); } catch (XMLToolingException& ex) { // This is just to maximize the likelihood of attaching a source to the message for support purposes. @@ -165,6 +165,5 @@ XMLObject* SAML2POSTDecoder::decode( annotateException(&ex,provider); // throws it } - xmlObject.release(); - return root; + return xmlObject.release(); } diff --git a/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp b/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp index 5c1dc39..d2abd41 100644 --- a/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2RedirectDecoder.cpp @@ -143,7 +143,7 @@ XMLObject* SAML2RedirectDecoder::decode( } // Run through the policy. - policy.evaluate(genericRequest, *root); + policy.evaluate(*root, &genericRequest); } catch (XMLToolingException& ex) { // This is just to maximize the likelihood of attaching a source to the message for support purposes. @@ -170,6 +170,5 @@ XMLObject* SAML2RedirectDecoder::decode( annotateException(&ex,provider); // throws it } - xmlObject.release(); - return root; + return xmlObject.release(); } diff --git a/saml/saml2/binding/impl/SAML2SOAPDecoder.cpp b/saml/saml2/binding/impl/SAML2SOAPDecoder.cpp index 8ff3738..092e7f4 100644 --- a/saml/saml2/binding/impl/SAML2SOAPDecoder.cpp +++ b/saml/saml2/binding/impl/SAML2SOAPDecoder.cpp @@ -91,8 +91,8 @@ XMLObject* SAML2SOAPDecoder::decode( RequestAbstractType* request = dynamic_cast(body->getXMLObjects().front()); if (request) { // Run through the policy at two layers. - policy.evaluate(genericRequest, *env); - policy.evaluate(genericRequest, *request); + policy.evaluate(*env, &genericRequest); + policy.evaluate(*request, &genericRequest); xmlObject.release(); body->detach(); // frees Envelope request->detach(); // frees Body -- 2.1.4