bf5c6733e41c4bca33b56fa75c1d037bff9c234f
[shibboleth/cpp-opensaml.git] / saml / saml1 / binding / impl / SAML1MessageDecoder.cpp
1 /**
2  * Licensed to the University Corporation for Advanced Internet
3  * Development, Inc. (UCAID) under one or more contributor license
4  * agreements. See the NOTICE file distributed with this work for
5  * additional information regarding copyright ownership.
6  *
7  * UCAID licenses this file to you under the Apache License,
8  * Version 2.0 (the "License"); you may not use this file except
9  * in compliance with the License. You may obtain a copy of the
10  * License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
17  * either express or implied. See the License for the specific
18  * language governing permissions and limitations under the License.
19  */
20
21 /**
22  * SAML1MessageDecoder.cpp
23  *
24  * Base class for SAML 1.x MessageDecoders.
25  */
26
27 #include "internal.h"
28 #include "binding/SecurityPolicy.h"
29 #include "saml1/binding/SAML1MessageDecoder.h"
30 #include "saml1/core/Assertions.h"
31 #include "saml1/core/Protocols.h"
32 #include "saml2/metadata/Metadata.h"
33 #include "saml2/metadata/MetadataProvider.h"
34
35 #include <xmltooling/logging.h>
36
37 using namespace opensaml::saml2md;
38 using namespace opensaml::saml1p;
39 using namespace opensaml::saml1;
40 using namespace opensaml;
41 using namespace xmltooling::logging;
42 using namespace xmltooling;
43 using namespace std;
44
45 SAML1MessageDecoder::SAML1MessageDecoder()
46 {
47 }
48
49 SAML1MessageDecoder::~SAML1MessageDecoder()
50 {
51 }
52
53 const XMLCh* SAML1MessageDecoder::getProtocolFamily() const
54 {
55     return samlconstants::SAML11_PROTOCOL_ENUM;
56 }
57
58 void SAML1MessageDecoder::extractMessageDetails(
59     const XMLObject& message, const GenericRequest& req, const XMLCh* protocol, SecurityPolicy& policy
60     ) const
61 {
62     // Only handle SAML 1.x protocol messages.
63     const xmltooling::QName& q = message.getElementQName();
64     if (!XMLString::equals(q.getNamespaceURI(), samlconstants::SAML1P_NS))
65         return;
66
67     Category& log = Category::getInstance(SAML_LOGCAT ".MessageDecoder.SAML1");
68
69     const Request* request=nullptr;
70     const Response* response=nullptr;
71     if (XMLString::equals(q.getLocalPart(), Request::LOCAL_NAME))
72         request = dynamic_cast<const Request*>(&message);
73     if (!request && XMLString::equals(q.getLocalPart(), Response::LOCAL_NAME))
74         response = dynamic_cast<const Response*>(&message);
75
76     if (!request && !response) {
77         log.warn("decoder cannot extract details from non-SAML 1.x protocol message");
78         return;
79     }
80
81     const RootObject* root = request ? static_cast<const RootObject*>(request) : static_cast<const RootObject*>(response);
82
83     // Extract message details.
84     policy.setMessageID(root->getID());
85     policy.setIssueInstant(root->getIssueInstantEpoch());
86
87     if (request) {
88         log.warn("issuer identity not extracted, only responses with assertions carry issuer information in standard SAML 1.x");
89         return;
90     }
91
92     log.debug("extracting issuer from SAML 1.x Response");
93     const vector<saml1::Assertion*>& assertions = response->getAssertions();
94     if (assertions.empty()) {
95         log.warn("issuer identity not extracted from response (no assertions were present)");
96         return;
97     }
98
99     const XMLCh* issuer = assertions.front()->getIssuer();
100     policy.setIssuer(issuer);
101     if (log.isDebugEnabled()) {
102         auto_ptr_char iname(issuer);
103         log.debug("response from (%s)", iname.get());
104     }
105
106     if (policy.getIssuerMetadata()) {
107         log.debug("metadata for issuer already set, leaving in place");
108         return;
109     }
110
111     if (policy.getMetadataProvider() && policy.getRole()) {
112         log.debug("searching metadata for response issuer...");
113         MetadataProvider::Criteria& mc = policy.getMetadataProviderCriteria();
114         mc.entityID_unicode = issuer;
115         mc.role = policy.getRole();
116         mc.protocol = protocol;
117         pair<const EntityDescriptor*,const RoleDescriptor*> entity = policy.getMetadataProvider()->getEntityDescriptor(mc);
118
119         if (!entity.first) {
120             auto_ptr_char iname(issuer);
121             log.warn("no metadata found, can't establish identity of issuer (%s)", iname.get());
122             return;
123         }
124         else if (!entity.second) {
125             log.warn("unable to find compatible role (%s) in metadata", policy.getRole()->toString().c_str());
126             return;
127         }
128         policy.setIssuerMetadata(entity.second);
129     }
130 }