2 * Copyright 2001-2006 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.
18 * MessageSigningRule.cpp
20 * XML Signature checking SecurityPolicyRule
24 #include "exceptions.h"
25 #include "RootObject.h"
26 #include "binding/MessageSigningRule.h"
27 #include "saml1/core/Assertions.h"
28 #include "saml1/core/Protocols.h"
29 #include "saml2/core/Protocols.h"
30 #include "saml2/metadata/Metadata.h"
31 #include "saml2/metadata/MetadataProvider.h"
32 #include "security/TrustEngine.h"
34 #include <xmltooling/util/NDC.h>
35 #include <xmltooling/util/ReplayCache.h>
36 #include <log4cpp/Category.hh>
38 using namespace opensaml::saml2md;
39 using namespace opensaml;
40 using namespace xmltooling;
41 using namespace log4cpp;
45 SecurityPolicyRule* SAML_DLLLOCAL MessageSigningRuleFactory(const DOMElement* const & e)
47 return new MessageSigningRule(e);
51 pair<saml2::Issuer*,const saml2md::RoleDescriptor*> MessageSigningRule::evaluate(
52 const GenericRequest& request,
53 const XMLObject& message,
54 const MetadataProvider* metadataProvider,
56 const opensaml::TrustEngine* trustEngine
59 Category& log=Category::getInstance(SAML_LOGCAT".SecurityPolicyRule.MessageSigning");
60 log.debug("evaluating message signing policy");
62 pair<saml2::Issuer*,const RoleDescriptor*> ret = pair<saml2::Issuer*,const RoleDescriptor*>(NULL,NULL);
64 if (!metadataProvider || !role || !trustEngine) {
65 log.debug("ignoring message, no metadata or trust information supplied");
70 const RootObject& root = dynamic_cast<const RootObject&>(message);
71 if (!root.getSignature()) {
72 log.debug("ignoring unsigned message");
76 log.debug("extracting issuer from message");
77 pair<saml2::Issuer*,const XMLCh*> issuerInfo = getIssuerAndProtocol(message);
79 auto_ptr<saml2::Issuer> issuer(issuerInfo.first);
80 if (!issuerInfo.first || !issuerInfo.second ||
81 (issuer->getFormat() && !XMLString::equals(issuer->getFormat(), saml2::NameIDType::ENTITY))) {
82 log.warn("issuer identity not estabished, or was not an entityID");
86 log.debug("searching metadata for message issuer...");
87 const EntityDescriptor* entity = metadataProvider->getEntityDescriptor(issuer->getName());
89 auto_ptr_char temp(issuer->getName());
90 log.warn("no metadata found, can't establish identity of issuer (%s)", temp.get());
94 log.debug("matched assertion issuer against metadata, searching for applicable role...");
95 const RoleDescriptor* roledesc=entity->getRoleDescriptor(*role, issuerInfo.second);
97 log.warn("unable to find compatible role (%s) in metadata", role->toString().c_str());
101 if (!trustEngine->validate(*(root.getSignature()), *roledesc, metadataProvider->getKeyResolver())) {
102 log.error("unable to verify signature on message with supplied trust engine");
106 if (log.isDebugEnabled()) {
107 auto_ptr_char iname(entity->getEntityID());
108 log.debug("message from (%s), signature verified", iname.get());
111 ret.first = issuer.release();
112 ret.second = roledesc;
116 log.warn("caught a bad_cast while extracting issuer");
121 pair<saml2::Issuer*,const XMLCh*> MessageSigningRule::getIssuerAndProtocol(const XMLObject& message) const
123 // We just let any bad casts throw here.
125 saml2::Issuer* issuer;
127 // Shortcuts some of the casting.
128 const XMLCh* ns = message.getElementQName().getNamespaceURI();
130 if (XMLString::equals(ns, samlconstants::SAML20P_NS) || XMLString::equals(ns, samlconstants::SAML20_NS)) {
131 // 2.0 namespace should be castable to a specialized 2.0 root.
132 const saml2::RootObject& root = dynamic_cast<const saml2::RootObject&>(message);
133 issuer = root.getIssuer();
134 if (issuer && issuer->getName()) {
135 return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS);
138 // No issuer in the message, so we have to try the Response approach.
139 const vector<saml2::Assertion*>& assertions = dynamic_cast<const saml2p::Response&>(message).getAssertions();
140 if (!assertions.empty()) {
141 issuer = assertions.front()->getIssuer();
142 if (issuer && issuer->getName())
143 return make_pair(issuer->cloneIssuer(), samlconstants::SAML20P_NS);
146 else if (XMLString::equals(ns, samlconstants::SAML1P_NS)) {
147 // Should be a samlp:Response, at least in OpenSAML.
148 const vector<saml1::Assertion*>& assertions = dynamic_cast<const saml1p::Response&>(message).getAssertions();
149 if (!assertions.empty()) {
150 const saml1::Assertion* a = assertions.front();
151 if (a->getIssuer()) {
152 issuer = saml2::IssuerBuilder::buildIssuer();
153 issuer->setName(a->getIssuer());
154 pair<bool,int> minor = a->getMinorVersion();
157 (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM
162 else if (XMLString::equals(ns, samlconstants::SAML1_NS)) {
163 // Should be a saml:Assertion.
164 const saml1::Assertion& a = dynamic_cast<const saml1::Assertion&>(message);
166 issuer = saml2::IssuerBuilder::buildIssuer();
167 issuer->setName(a.getIssuer());
168 pair<bool,int> minor = a.getMinorVersion();
171 (minor.first && minor.second==0) ? samlconstants::SAML10_PROTOCOL_ENUM : samlconstants::SAML11_PROTOCOL_ENUM
176 return pair<saml2::Issuer*,const XMLCh*>(NULL,NULL);