2 * Copyright 2001-2010 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 "ServiceProvider.h"
26 #include "binding/SOAPClient.h"
27 #include "security/SecurityPolicy.h"
29 #include <saml/exceptions.h>
30 #include <saml/saml2/metadata/Metadata.h>
31 #include <saml/saml2/metadata/MetadataCredentialCriteria.h>
32 #include <saml/signature/ContentReference.h>
33 #include <xmltooling/security/Credential.h>
34 #include <xmltooling/signature/Signature.h>
35 #include <xmltooling/soap/SOAP.h>
36 #include <xmltooling/soap/HTTPSOAPTransport.h>
37 #include <xmltooling/util/NDC.h>
39 using namespace shibsp;
40 using namespace opensaml::saml2md;
41 using namespace xmlsignature;
42 using namespace xmltooling;
45 SOAPClient::SOAPClient(SecurityPolicy& policy)
46 : opensaml::SOAPClient(policy), m_app(policy.getApplication()), m_relyingParty(nullptr), m_credResolver(nullptr)
50 SOAPClient::~SOAPClient()
53 m_credResolver->unlock();
56 void SOAPClient::send(const soap11::Envelope& env, const char* from, MetadataCredentialCriteria& to, const char* endpoint)
58 // Check for message signing requirements.
59 m_relyingParty = m_app.getRelyingParty(dynamic_cast<const EntityDescriptor*>(to.getRole().getParent()));
60 pair<bool,const char*> flag = m_relyingParty->getString("signing");
61 if (flag.first && (!strcmp(flag.second, "true") || !strcmp(flag.second, "back"))) {
62 m_credResolver=m_app.getCredentialResolver();
64 m_credResolver->lock();
65 // Fill in criteria to use.
66 to.setUsage(Credential::SIGNING_CREDENTIAL);
67 pair<bool,const char*> keyName = m_relyingParty->getString("keyName");
69 to.getKeyNames().insert(keyName.second);
70 pair<bool,const XMLCh*> sigalg = m_relyingParty->getXMLString("signingAlg");
72 to.setXMLAlgorithm(sigalg.second);
73 const Credential* cred = m_credResolver->resolve(&to);
74 // Reset criteria back.
75 to.setKeyAlgorithm(nullptr);
77 to.getKeyNames().clear();
81 const vector<XMLObject*>& bodies=const_cast<const soap11::Body*>(env.getBody())->getUnknownXMLObjects();
82 if (!bodies.empty()) {
83 opensaml::SignableObject* msg = dynamic_cast<opensaml::SignableObject*>(bodies.front());
86 Signature* sig = SignatureBuilder::buildSignature();
87 msg->setSignature(sig);
89 sig->setSignatureAlgorithm(sigalg.second);
90 sigalg = m_relyingParty->getXMLString("digestAlg");
92 dynamic_cast<opensaml::ContentReference*>(sig->getContentReference())->setDigestAlgorithm(sigalg.second);
94 // Sign it. The marshalling step in the base class should be a no-op.
95 vector<Signature*> sigs(1,sig);
96 env.marshall((DOMDocument*)nullptr,&sigs,cred);
101 Category::getInstance(SHIBSP_LOGCAT".SOAPClient").error("no signing credential supplied, leaving unsigned.");
105 Category::getInstance(SHIBSP_LOGCAT".SOAPClient").error("no CredentialResolver available, leaving unsigned.");
109 opensaml::SOAPClient::send(env, from, to, endpoint);
112 void SOAPClient::prepareTransport(SOAPTransport& transport)
115 xmltooling::NDC("prepareTransport");
117 Category& log=Category::getInstance(SHIBSP_LOGCAT".SOAPClient");
118 log.debug("prepping SOAP transport for use by application (%s)", m_app.getId());
120 pair<bool,bool> flag = m_relyingParty->getBool("requireConfidentiality");
121 if ((!flag.first || flag.second) && !transport.isConfidential())
122 throw opensaml::BindingException("Transport confidentiality required, but not available.");
124 setValidating(getPolicy().getValidating());
125 flag = m_relyingParty->getBool("requireTransportAuth");
126 forceTransportAuthentication(!flag.first || flag.second);
128 opensaml::SOAPClient::prepareTransport(transport);
130 pair<bool,const char*> authType=m_relyingParty->getString("authType");
131 if (!authType.first || !strcmp(authType.second,"TLS")) {
132 if (!m_credResolver) {
133 m_credResolver = m_app.getCredentialResolver();
135 m_credResolver->lock();
137 if (m_credResolver) {
138 m_criteria->setUsage(Credential::TLS_CREDENTIAL);
139 authType = m_relyingParty->getString("keyName");
141 m_criteria->getKeyNames().insert(authType.second);
142 const Credential* cred = m_credResolver->resolve(m_criteria);
143 m_criteria->getKeyNames().clear();
145 if (!transport.setCredential(cred))
146 log.error("failed to load Credential into SOAPTransport");
149 log.error("no TLS credential supplied");
153 log.error("no CredentialResolver available for TLS");
157 SOAPTransport::transport_auth_t type=SOAPTransport::transport_auth_none;
158 pair<bool,const char*> username=m_relyingParty->getString("authUsername");
159 pair<bool,const char*> password=m_relyingParty->getString("authPassword");
160 if (!username.first || !password.first)
161 log.error("transport authType (%s) specified but authUsername or authPassword was missing", authType.second);
162 else if (!strcmp(authType.second,"basic"))
163 type = SOAPTransport::transport_auth_basic;
164 else if (!strcmp(authType.second,"digest"))
165 type = SOAPTransport::transport_auth_digest;
166 else if (!strcmp(authType.second,"ntlm"))
167 type = SOAPTransport::transport_auth_ntlm;
168 else if (!strcmp(authType.second,"gss"))
169 type = SOAPTransport::transport_auth_gss;
170 else if (strcmp(authType.second,"none"))
171 log.error("unknown authType (%s) specified for RelyingParty", authType.second);
172 if (type > SOAPTransport::transport_auth_none) {
173 if (transport.setAuth(type,username.second,password.second))
174 log.debug("configured for transport authentication (method=%s, username=%s)", authType.second, username.second);
176 log.error("failed to configure transport authentication (method=%s)", authType.second);
180 pair<bool,unsigned int> timeout = m_relyingParty->getUnsignedInt("connectTimeout");
181 transport.setConnectTimeout(timeout.first ? timeout.second : 10);
182 timeout = m_relyingParty->getUnsignedInt("timeout");
183 transport.setTimeout(timeout.first ? timeout.second : 20);
184 m_app.getServiceProvider().setTransportOptions(transport);
186 HTTPSOAPTransport* http = dynamic_cast<HTTPSOAPTransport*>(&transport);
188 flag = m_relyingParty->getBool("chunkedEncoding");
189 http->useChunkedEncoding(flag.first && flag.second);
190 http->setRequestHeader(PACKAGE_NAME, PACKAGE_VERSION);
194 void SOAPClient::reset()
196 m_relyingParty = nullptr;
198 m_credResolver->unlock();
199 m_credResolver = nullptr;
200 opensaml::SOAPClient::reset();