2 * Copyright 2001-2007 Internet2
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 * Specialized SOAPClient for SP environment.
24 #include "Application.h"
25 #include "exceptions.h"
26 #include "ServiceProvider.h"
27 #include "binding/SOAPClient.h"
29 #include <log4cpp/Category.hh>
30 #include <saml/saml2/metadata/Metadata.h>
31 #include <xmltooling/soap/SOAP.h>
32 #include <xmltooling/soap/HTTPSOAPTransport.h>
33 #include <xmltooling/util/NDC.h>
35 using namespace shibsp;
36 using namespace opensaml::saml2md;
37 using namespace xmlsignature;
38 using namespace xmltooling;
39 using namespace log4cpp;
42 SOAPClient::SOAPClient(SecurityPolicy& policy)
43 : opensaml::SOAPClient(policy), m_app(policy.getApplication()), m_settings(NULL), m_relyingParty(NULL), m_credResolver(NULL)
45 m_settings = m_app.getServiceProvider().getPolicySettings(m_app.getString("policyId").second);
46 pair<bool,bool> validate = m_settings->getBool("validate");
47 policy.setValidating(validate.first && validate.second);
48 setValidating(validate.first && validate.second);
51 void SOAPClient::send(const soap11::Envelope& env, MetadataCredentialCriteria& peer, const char* endpoint)
53 // Check for message signing requirements.
54 m_relyingParty = m_app.getRelyingParty(dynamic_cast<const EntityDescriptor*>(peer.getRole().getParent()));
55 pair<bool,bool> flag = m_relyingParty->getBool("signRequests");
56 if (flag.first && flag.second) {
57 m_credResolver=m_app.getCredentialResolver();
59 m_credResolver->lock();
60 // Fill in criteria to use.
61 peer.setUsage(CredentialCriteria::SIGNING_CREDENTIAL);
62 pair<bool,const char*> keyName = m_relyingParty->getString("keyName");
64 peer.getKeyNames().insert(keyName.second);
65 pair<bool,const XMLCh*> sigalg = m_relyingParty->getXMLString("signatureAlg");
67 peer.setXMLAlgorithm(sigalg.second);
68 const Credential* cred = m_credResolver->resolve(&peer);
69 // Reset criteria back.
70 peer.setKeyAlgorithm(NULL);
75 const vector<XMLObject*>& bodies=const_cast<const soap11::Body*>(env.getBody())->getUnknownXMLObjects();
76 if (!bodies.empty()) {
77 opensaml::SignableObject* msg = dynamic_cast<opensaml::SignableObject*>(bodies.front());
80 Signature* sig = SignatureBuilder::buildSignature();
81 msg->setSignature(sig);
83 sig->setSignatureAlgorithm(sigalg.second);
84 sigalg = m_relyingParty->getXMLString("digestAlg");
86 dynamic_cast<opensaml::ContentReference*>(sig->getContentReference())->setDigestAlgorithm(sigalg.second);
88 // Sign it. The marshalling step in the base class should be a no-op.
89 vector<Signature*> sigs(1,sig);
90 env.marshall((DOMDocument*)NULL,&sigs,cred);
95 Category::getInstance(SHIBSP_LOGCAT".SOAPClient").error("no signing credential supplied, leaving unsigned.");
99 Category::getInstance(SHIBSP_LOGCAT".SOAPClient").error("no CredentialResolver available, leaving unsigned.");
103 opensaml::SOAPClient::send(env, peer, endpoint);
106 void SOAPClient::prepareTransport(SOAPTransport& transport)
109 xmltooling::NDC("prepareTransport");
111 Category& log=Category::getInstance(SHIBSP_LOGCAT".SOAPClient");
112 log.debug("prepping SOAP transport for use by application (%s)", m_app.getId());
114 pair<bool,bool> flag = m_settings->getBool("requireConfidentiality");
115 if ((!flag.first || flag.second) && !transport.isConfidential())
116 throw opensaml::BindingException("Transport confidentiality required, but not available.");
118 flag = m_settings->getBool("validate");
119 setValidating(flag.first && flag.second);
120 flag = m_settings->getBool("requireTransportAuth");
121 forceTransportAuthentication(!flag.first || flag.second);
123 opensaml::SOAPClient::prepareTransport(transport);
125 pair<bool,const char*> authType=m_relyingParty->getString("authType");
126 if (!authType.first || !strcmp(authType.second,"TLS")) {
127 if (!m_credResolver) {
128 m_credResolver = m_app.getCredentialResolver();
130 m_credResolver->lock();
132 if (m_credResolver) {
133 m_criteria->setUsage(CredentialCriteria::TLS_CREDENTIAL);
134 authType = m_relyingParty->getString("keyName");
136 m_criteria->getKeyNames().insert(authType.second);
137 const Credential* cred = m_credResolver->resolve(m_criteria);
139 if (!transport.setCredential(cred))
140 log.error("failed to load Credential into SOAPTransport");
143 log.error("no TLS credential supplied");
147 log.error("no CredentialResolver available for TLS");
151 SOAPTransport::transport_auth_t type=SOAPTransport::transport_auth_none;
152 pair<bool,const char*> username=m_relyingParty->getString("authUsername");
153 pair<bool,const char*> password=m_relyingParty->getString("authPassword");
154 if (!username.first || !password.first)
155 log.error("transport authType (%s) specified but authUsername or authPassword was missing", authType.second);
156 else if (!strcmp(authType.second,"basic"))
157 type = SOAPTransport::transport_auth_basic;
158 else if (!strcmp(authType.second,"digest"))
159 type = SOAPTransport::transport_auth_digest;
160 else if (!strcmp(authType.second,"ntlm"))
161 type = SOAPTransport::transport_auth_ntlm;
162 else if (!strcmp(authType.second,"gss"))
163 type = SOAPTransport::transport_auth_gss;
165 log.error("unknown authType (%s) specified for RelyingParty", authType.second);
166 if (type > SOAPTransport::transport_auth_none) {
167 if (transport.setAuth(type,username.second,password.second))
168 log.debug("configured for transport authentication (method=%s, username=%s)", authType.second, username.second);
170 log.error("failed to configure transport authentication (method=%s)", authType.second);
174 transport.setConnectTimeout(m_settings->getUnsignedInt("connectTimeout").second);
175 transport.setTimeout(m_settings->getUnsignedInt("timeout").second);
177 HTTPSOAPTransport* http = dynamic_cast<HTTPSOAPTransport*>(&transport);
179 flag = m_settings->getBool("chunkedEncoding");
180 http->useChunkedEncoding(!flag.first || flag.second);
181 http->setRequestHeader("Shibboleth", PACKAGE_VERSION);
185 void SOAPClient::reset()
187 m_relyingParty = NULL;
189 m_credResolver->unlock();
190 m_credResolver = NULL;
191 opensaml::SOAPClient::reset();