binding/SecurityPolicy.h \
binding/SecurityPolicyRule.h \
binding/SimpleSigningRule.h \
+ binding/SOAPClient.h \
binding/URLEncoder.h \
binding/XMLSigningRule.h
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 \
virtual ~ClientCertAuthRule() {}
std::pair<saml2::Issuer*,const saml2md::RoleDescriptor*> evaluate(
- const GenericRequest& request,
const xmltooling::XMLObject& message,
+ const GenericRequest* request,
const saml2md::MetadataProvider* metadataProvider,
const xmltooling::QName* role,
const xmltooling::TrustEngine* trustEngine
virtual ~MessageFlowRule() {}
std::pair<saml2::Issuer*,const saml2md::RoleDescriptor*> evaluate(
- const GenericRequest& request,
const xmltooling::XMLObject& message,
+ const GenericRequest* request,
const saml2md::MetadataProvider* metadataProvider,
const xmltooling::QName* role,
const xmltooling::TrustEngine* trustEngine
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file saml/binding/SOAPClient.h
+ *
+ * Specialized SOAPClient for SAML SOAP bindings.
+ */
+
+#ifndef __saml_soap11client_h__
+#define __saml_soap11client_h__
+
+#include <saml/binding/SecurityPolicy.h>
+#include <xmltooling/soap/SOAPClient.h>
+
+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.
+ *
+ * <p>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__ */
}
/**
- * 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.
* 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
* @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 GenericRequest* request,
const saml2md::MetadataProvider* metadataProvider,
const xmltooling::QName* role,
const xmltooling::TrustEngine* trustEngine
virtual ~SimpleSigningRule() {}
std::pair<saml2::Issuer*,const saml2md::RoleDescriptor*> evaluate(
- const GenericRequest& request,
const xmltooling::XMLObject& message,
+ const GenericRequest* request,
const saml2md::MetadataProvider* metadataProvider,
const xmltooling::QName* role,
const xmltooling::TrustEngine* trustEngine
virtual ~XMLSigningRule() {}
std::pair<saml2::Issuer*,const saml2md::RoleDescriptor*> evaluate(
- const GenericRequest& request,
const xmltooling::XMLObject& message,
+ const GenericRequest* request,
const saml2md::MetadataProvider* metadataProvider,
const xmltooling::QName* role,
const xmltooling::TrustEngine* trustEngine
};
pair<saml2::Issuer*,const RoleDescriptor*> ClientCertAuthRule::evaluate(
- const GenericRequest& request,
const XMLObject& message,
+ const GenericRequest* request,
const MetadataProvider* metadataProvider,
const QName* role,
const TrustEngine* trustEngine
Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.ClientCertAuth");
log.debug("evaluating client certificate authentication policy");
- pair<saml2::Issuer*,const RoleDescriptor*> ret = pair<saml2::Issuer*,const RoleDescriptor*>(NULL,NULL);
+ pair<saml2::Issuer*,const RoleDescriptor*> ret = pair<saml2::Issuer*,const RoleDescriptor*>(NULL,NULL);
+ if (!request) {
+ log.debug("ignoring message, no protocol request available");
+ return ret;
+ }
const X509TrustEngine* x509trust;
if (!metadataProvider || !role || !(x509trust=dynamic_cast<const X509TrustEngine*>(trustEngine))) {
return ret;
}
- const std::vector<XSECCryptoX509*>& chain = request.getClientCertificates();
+ const std::vector<XSECCryptoX509*>& chain = request->getClientCertificates();
if (chain.empty()) {
log.debug("ignoring message, no client certificates in request");
return ret;
}
pair<saml2::Issuer*,const saml2md::RoleDescriptor*> MessageFlowRule::evaluate(
- const GenericRequest& request,
const XMLObject& message,
+ const GenericRequest* request,
const saml2md::MetadataProvider* metadataProvider,
const QName* role,
const TrustEngine* trustEngine
--- /dev/null
+/*
+ * Copyright 2001-2006 Internet2
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * 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 <xmltooling/security/X509TrustEngine.h>
+#include <xmltooling/soap/SOAP.h>
+
+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<const RoleDescriptor*>(&peer);
+
+ soap11::SOAPClient::send(env, peer, endpoint);
+}
+
+void SOAPClient::prepareTransport(const xmltooling::SOAPTransport& transport)
+{
+ const X509TrustEngine* engine = dynamic_cast<const X509TrustEngine*>(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<soap11::Envelope> env(soap11::SOAPClient::receive());
+ if (env.get()) {
+ if (m_peer && m_transport->isSecure()) {
+ // Set issuer based on peer identity.
+ EntityDescriptor* parent = dynamic_cast<EntityDescriptor*>(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();
+}
delete m_issuer;
}
-void SecurityPolicy::evaluate(const GenericRequest& request, const XMLObject& message)
+void SecurityPolicy::evaluate(const XMLObject& message, const GenericRequest* request)
{
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);
+ pair<Issuer*,const RoleDescriptor*> ident = (*i)->evaluate(message,request,m_metadata,&m_role,m_trust);
// Make sure returned issuer doesn't conflict.
pair<saml2::Issuer*,const RoleDescriptor*> SimpleSigningRule::evaluate(
- const GenericRequest& request,
const XMLObject& message,
+ const GenericRequest* request,
const MetadataProvider* metadataProvider,
const QName* role,
const TrustEngine* trustEngine
pair<saml2::Issuer*,const RoleDescriptor*> ret = pair<saml2::Issuer*,const RoleDescriptor*>(NULL,NULL);
+ const HTTPRequest* httpRequest = dynamic_cast<const HTTPRequest*>(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;
string input;
const char* pch;
- const HTTPRequest& httpRequest = dynamic_cast<const HTTPRequest&>(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=");
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;
// 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);
};
pair<saml2::Issuer*,const RoleDescriptor*> XMLSigningRule::evaluate(
- const GenericRequest& request,
const XMLObject& message,
+ const GenericRequest* request,
const MetadataProvider* metadataProvider,
const QName* role,
const TrustEngine* trustEngine
>\r
</File>\r
<File\r
+ RelativePath=".\binding\impl\SOAPClient.cpp"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\binding\impl\URLEncoder.cpp"\r
>\r
</File>\r
>\r
</File>\r
<File\r
+ RelativePath=".\binding\SOAPClient.h"\r
+ >\r
+ </File>\r
+ <File\r
RelativePath=".\binding\URLEncoder.h"\r
>\r
</File>\r
m_artifactResolver->resolve(artifacts, dynamic_cast<const IDPSSODescriptor&>(*roledesc), policy)
);
- policy.evaluate(genericRequest, *(response.get()));
+ policy.evaluate(*(response.get()), &genericRequest);
for_each(artifacts.begin(), artifacts.end(), xmltooling::cleanup<SAMLArtifact>());
return response.release();
}
// 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.
Request* request = dynamic_cast<Request*>(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
m_artifactResolver->resolve(*(artifact2.get()), dynamic_cast<const SSODescriptorType&>(*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();
}
// 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.
annotateException(&ex,provider); // throws it
}
- xmlObject.release();
- return root;
+ return xmlObject.release();
}
}
// 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.
annotateException(&ex,provider); // throws it
}
- xmlObject.release();
- return root;
+ return xmlObject.release();
}
RequestAbstractType* request = dynamic_cast<RequestAbstractType*>(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