Consolidated exception and status handling into a single class.
[shibboleth/sp.git] / shib-target / ArtifactMapper.cpp
1 /* 
2  * The Shibboleth License, Version 1. 
3  * Copyright (c) 2002 
4  * University Corporation for Advanced Internet Development, Inc. 
5  * All rights reserved
6  * 
7  * 
8  * Redistribution and use in source and binary forms, with or without 
9  * modification, are permitted provided that the following conditions are met:
10  * 
11  * Redistributions of source code must retain the above copyright notice, this 
12  * list of conditions and the following disclaimer.
13  * 
14  * Redistributions in binary form must reproduce the above copyright notice, 
15  * this list of conditions and the following disclaimer in the documentation 
16  * and/or other materials provided with the distribution, if any, must include 
17  * the following acknowledgment: "This product includes software developed by 
18  * the University Corporation for Advanced Internet Development 
19  * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement 
20  * may appear in the software itself, if and wherever such third-party 
21  * acknowledgments normally appear.
22  * 
23  * Neither the name of Shibboleth nor the names of its contributors, nor 
24  * Internet2, nor the University Corporation for Advanced Internet Development, 
25  * Inc., nor UCAID may be used to endorse or promote products derived from this 
26  * software without specific prior written permission. For written permission, 
27  * please contact shibboleth@shibboleth.org
28  * 
29  * Products derived from this software may not be called Shibboleth, Internet2, 
30  * UCAID, or the University Corporation for Advanced Internet Development, nor 
31  * may Shibboleth appear in their name, without prior written permission of the 
32  * University Corporation for Advanced Internet Development.
33  * 
34  * 
35  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
36  * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
37  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
38  * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK 
39  * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE. 
40  * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY 
41  * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT, 
42  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
43  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
47  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49
50 /* ArtifactMapper.cpp - a ShibTarget-aware SAML artifact->binding mapper
51
52    Scott Cantor
53    2/20/05
54
55    $History:$
56 */
57
58 #include "internal.h"
59
60 #include <log4cpp/Category.hh>
61
62 using namespace std;
63 using namespace log4cpp;
64 using namespace saml;
65 using namespace shibboleth;
66 using namespace shibtarget;
67
68 SAMLBrowserProfile::ArtifactMapper::ArtifactMapperResponse STArtifactMapper::map(const SAMLArtifact* artifact)
69 {
70     Category& log=Category::getInstance("shibtarget.ArtifactMapper");
71     
72     // First do a search for the issuer.
73     const IEntityDescriptor* entity=m_metadata.lookup(artifact);
74     if (!entity) {
75         log.error(
76             "metadata lookup failed, unable to determine issuer of artifact (0x%s)",
77             SAMLArtifact::toHex(artifact->getBytes()).c_str()
78             );
79         throw MetadataException("ArtifactMapper::map() metadata lookup failed, unable to determine artifact issuer");
80     }
81     
82     SAMLBrowserProfile::ArtifactMapper::ArtifactMapperResponse amr;
83     auto_ptr_char issuer(entity->getId());
84     log.info("lookup succeeded, artifact issued by (%s)", issuer.get());
85     amr.source=issuer.get();
86     
87     const IPropertySet* credUse=m_app->getCredentialUse(entity);
88
89     // Depends on type of artifact.
90     const SAMLArtifactType0001* type1=dynamic_cast<const SAMLArtifactType0001*>(artifact);
91     if (type1) {
92         // With type 01, any endpoint will do. Try SAML 1.1 first.
93         const IIDPSSODescriptor* idp=entity->getIDPSSODescriptor(saml::XML::SAML11_PROTOCOL_ENUM);
94         if (idp) {
95             const IEndpointManager* mgr=idp->getArtifactResolutionServiceManager();
96             Iterator<const IEndpoint*> eps=mgr ? mgr->getEndpoints() : EMPTY(const IEndpoint*);
97             while (eps.hasNext()) {
98                 const IEndpoint* ep=eps.next();
99                 amr.binding = m_app->getBinding(ep->getBinding());
100                 if (amr.binding) {
101                     auto_ptr_char loc(ep->getLocation());
102                     amr.endpoint = loc.get();
103                     amr.callCtx = new ShibHTTPHook::ShibHTTPHookCallContext(credUse ? credUse->getString("TLS").second : NULL,idp);
104                     return amr;
105                 }
106             }
107         }
108         
109         // No compatible 1.1 binding, try 1.0...
110         idp=entity->getIDPSSODescriptor(saml::XML::SAML10_PROTOCOL_ENUM);
111         if (idp) {
112             const IEndpointManager* mgr=idp->getArtifactResolutionServiceManager();
113             Iterator<const IEndpoint*> eps=mgr ? mgr->getEndpoints() : EMPTY(const IEndpoint*);
114             while (eps.hasNext()) {
115                 const IEndpoint* ep=eps.next();
116                 amr.binding = m_app->getBinding(ep->getBinding());
117                 if (amr.binding) {
118                     auto_ptr_char loc(ep->getLocation());
119                     amr.endpoint = loc.get();
120                     amr.callCtx = new ShibHTTPHook::ShibHTTPHookCallContext(credUse ? credUse->getString("TLS").second : NULL,idp);
121                     return amr;
122                 }
123             }
124         }
125     }
126     else {
127         const SAMLArtifactType0002* type2=dynamic_cast<const SAMLArtifactType0002*>(artifact);
128         if (type2) {
129             // With type 02, we have to find the matching location. Try SAML 1.1 first.
130             const IIDPSSODescriptor* idp=entity->getIDPSSODescriptor(saml::XML::SAML11_PROTOCOL_ENUM);
131             if (idp) {
132                 const IEndpointManager* mgr=idp->getArtifactResolutionServiceManager();
133                 Iterator<const IEndpoint*> eps=mgr ? mgr->getEndpoints() : EMPTY(const IEndpoint*);
134                 while (eps.hasNext()) {
135                     const IEndpoint* ep=eps.next();
136                     auto_ptr_char loc(ep->getLocation());
137                     if (!strcmp(loc.get(),type2->getSourceLocation())) {
138                         amr.binding = m_app->getBinding(ep->getBinding());
139                         if (amr.binding) {
140                             amr.endpoint = loc.get();
141                             amr.callCtx = new ShibHTTPHook::ShibHTTPHookCallContext(credUse ? credUse->getString("TLS").second : NULL,idp);
142                             return amr;
143                         }
144                     }
145                 }
146             }
147
148             // No match for 1.1, try 1.0...
149             idp=entity->getIDPSSODescriptor(saml::XML::SAML10_PROTOCOL_ENUM);
150             if (idp) {
151                 const IEndpointManager* mgr=idp->getArtifactResolutionServiceManager();
152                 Iterator<const IEndpoint*> eps=mgr ? mgr->getEndpoints() : EMPTY(const IEndpoint*);
153                 while (eps.hasNext()) {
154                     const IEndpoint* ep=eps.next();
155                     auto_ptr_char loc(ep->getLocation());
156                     if (!strcmp(loc.get(),type2->getSourceLocation())) {
157                         amr.binding = m_app->getBinding(ep->getBinding());
158                         if (amr.binding) {
159                             amr.endpoint = loc.get();
160                             amr.callCtx = new ShibHTTPHook::ShibHTTPHookCallContext(credUse ? credUse->getString("TLS").second : NULL,idp);
161                             return amr;
162                         }
163                     }
164                 }
165             }
166         }
167         else {
168             log.error("unrecognized artifact type (0x%s)", SAMLArtifact::toHex(artifact->getTypeCode()).c_str());
169             throw UnsupportedExtensionException(
170                 string("ArtifactMapper::map() unrecognized artifact type (0x") + SAMLArtifact::toHex(artifact->getTypeCode()) + ")"
171                 );
172         }
173     }
174     
175     log.error("unable to locate acceptable binding endpoint to resolve artifact");
176     MetadataException ex("Unable to locate acceptable binding endpoint to resolve artifact.");
177     annotateException(ex,entity,false);
178     throw ex;
179 }