2 * Copyright 2001-2005 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.
17 /* ArtifactMapper.cpp - a ShibTarget-aware SAML artifact->binding mapper
28 using namespace log4cpp;
30 using namespace shibboleth;
31 using namespace shibtarget;
33 SAMLResponse* STArtifactMapper::resolve(SAMLRequest* request)
35 Category& log=Category::getInstance("shibtarget.ArtifactMapper");
37 // First do a search for the issuer.
38 SAMLArtifact* artifact=request->getArtifacts().next();
39 Metadata m(m_app->getMetadataProviders());
40 const IEntityDescriptor* entity=m.lookup(artifact);
43 "metadata lookup failed, unable to determine issuer of artifact (0x%s)",
44 SAMLArtifact::toHex(artifact->getBytes()).c_str()
46 throw MetadataException("Metadata lookup failed, unable to determine artifact issuer");
49 auto_ptr_char issuer(entity->getId());
50 log.info("lookup succeeded, artifact issued by (%s)", issuer.get());
53 const IPropertySet* credUse=m_app->getCredentialUse(entity);
54 pair<bool,bool> signRequest=credUse ? credUse->getBool("signRequest") : make_pair(false,false);
55 pair<bool,const char*> signatureAlg=credUse ? credUse->getString("signatureAlg") : pair<bool,const char*>(false,NULL);
56 if (!signatureAlg.first)
57 signatureAlg.second=URI_ID_RSA_SHA1;
58 pair<bool,const char*> digestAlg=credUse ? credUse->getString("digestAlg") : pair<bool,const char*>(false,NULL);
60 digestAlg.second=URI_ID_SHA1;
61 pair<bool,bool> signedResponse=credUse ? credUse->getBool("signedResponse") : make_pair(false,false);
62 pair<bool,const char*> signingCred=credUse ? credUse->getString("Signing") : pair<bool,const char*>(false,NULL);
63 if (signRequest.first && signRequest.second && signingCred.first) {
64 if (request->getMinorVersion()==1) {
65 Credentials creds(ShibTargetConfig::getConfig().getINI()->getCredentialsProviders());
66 const ICredResolver* cr=creds.lookup(signingCred.second);
68 request->sign(cr->getKey(),cr->getCertificates(),signatureAlg.second,digestAlg.second);
70 log.error("unable to sign artifact request, specified credential (%s) was not found",signingCred.second);
73 log.error("unable to sign SAML 1.0 artifact request, only SAML 1.1 defines signing adequately");
76 SAMLResponse* response = NULL;
77 bool authenticated = false;
78 static const XMLCh https[] = {chLatin_h, chLatin_t, chLatin_t, chLatin_p, chLatin_s, chColon, chNull};
80 // Depends on type of artifact.
81 const SAMLArtifactType0001* type1=dynamic_cast<const SAMLArtifactType0001*>(artifact);
83 // With type 01, any endpoint will do.
84 const IIDPSSODescriptor* idp=entity->getIDPSSODescriptor(
85 request->getMinorVersion()==1 ? saml::XML::SAML11_PROTOCOL_ENUM : saml::XML::SAML10_PROTOCOL_ENUM
88 ShibHTTPHook::ShibHTTPHookCallContext callCtx(credUse,idp);
89 const IEndpointManager* mgr=idp->getArtifactResolutionServiceManager();
90 Iterator<const IEndpoint*> eps=mgr ? mgr->getEndpoints() : EMPTY(const IEndpoint*);
91 while (!response && eps.hasNext()) {
92 const IEndpoint* ep=eps.next();
93 const SAMLBinding* binding = m_app->getBinding(ep->getBinding());
95 auto_ptr_char prot(ep->getBinding());
96 log.warn("skipping binding on unsupported protocol (%s)", prot.get());
100 response = binding->send(ep->getLocation(),*request,&callCtx);
101 if (log.isDebugEnabled())
102 log.debugStream() << "SAML response from artifact request:\n" << *response << CategoryStream::ENDLINE;
104 if (!response->getAssertions().hasNext()) {
106 throw FatalProfileException("No SAML assertions returned in response to artifact profile request.");
108 authenticated = callCtx.isAuthenticated() && !XMLString::compareNString(ep->getLocation(),https,6);
110 catch (SAMLException& ex) {
111 annotateException(&ex,idp); // rethrows it
117 const SAMLArtifactType0002* type2=dynamic_cast<const SAMLArtifactType0002*>(artifact);
119 // With type 02, we have to find the matching location.
120 const IIDPSSODescriptor* idp=entity->getIDPSSODescriptor(
121 request->getMinorVersion()==1 ? saml::XML::SAML11_PROTOCOL_ENUM : saml::XML::SAML10_PROTOCOL_ENUM
124 ShibHTTPHook::ShibHTTPHookCallContext callCtx(credUse,idp);
125 const IEndpointManager* mgr=idp->getArtifactResolutionServiceManager();
126 Iterator<const IEndpoint*> eps=mgr ? mgr->getEndpoints() : EMPTY(const IEndpoint*);
127 while (eps.hasNext()) {
128 const IEndpoint* ep=eps.next();
129 auto_ptr_char loc(ep->getLocation());
130 if (strcmp(loc.get(),type2->getSourceLocation()))
132 const SAMLBinding* binding = m_app->getBinding(ep->getBinding());
134 auto_ptr_char prot(ep->getBinding());
135 log.warn("skipping binding on unsupported protocol (%s)", prot.get());
139 response = binding->send(ep->getLocation(),*request,&callCtx);
140 if (log.isDebugEnabled())
141 log.debugStream() << "SAML response from artifact request:\n" << *response << CategoryStream::ENDLINE;
143 if (!response->getAssertions().hasNext()) {
145 throw FatalProfileException("No SAML assertions returned in response to artifact profile request.");
147 authenticated = callCtx.isAuthenticated() && !XMLString::compareNString(ep->getLocation(),https,6);
149 catch (SAMLException& ex) {
150 annotateException(&ex,idp); // rethrows it
156 log.error("unrecognized artifact type (0x%s)", SAMLArtifact::toHex(artifact->getTypeCode()).c_str());
157 throw UnsupportedExtensionException(
158 string("Received unrecognized artifact type (0x") + SAMLArtifact::toHex(artifact->getTypeCode()) + ")"
164 log.error("unable to locate acceptable binding/endpoint to resolve artifact");
165 MetadataException ex("Unable to locate acceptable binding/endpoint to resolve artifact.");
166 annotateException(&ex,entity); // throws it
168 else if (!response->isSigned()) {
169 if (!authenticated || (signedResponse.first && signedResponse.second)) {
170 log.error("unsigned response obtained, but it must be signed.");
171 TrustException ex("Unable to obtain a signed response from artifact request.");
172 annotateException(&ex,entity); // throws it