2 * Copyright 2001-2007 Internet2
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
18 * SimpleAttributeResolver.cpp
\r
20 * AttributeResolver based on a simple mapping of SAML information.
\r
23 #include "internal.h"
\r
24 #include "Application.h"
\r
25 #include "SessionCache.h"
\r
26 #include "attribute/AttributeDecoder.h"
\r
27 #include "attribute/resolver/AttributeResolver.h"
\r
28 #include "attribute/resolver/ResolutionContext.h"
\r
29 #include "binding/SOAPClient.h"
\r
30 #include "util/SPConstants.h"
\r
33 #include <log4cpp/Category.hh>
\r
34 #include <saml/binding/SecurityPolicy.h>
\r
35 #include <saml/saml1/binding/SAML1SOAPClient.h>
\r
36 #include <saml/saml1/core/Assertions.h>
\r
37 #include <saml/saml1/core/Protocols.h>
\r
38 #include <saml/saml2/binding/SAML2SOAPClient.h>
\r
39 #include <saml/saml2/core/Protocols.h>
\r
40 #include <saml/saml2/metadata/Metadata.h>
\r
41 #include <saml/saml2/metadata/MetadataProvider.h>
\r
42 #include <xmltooling/util/NDC.h>
\r
43 #include <xmltooling/util/ReloadableXMLFile.h>
\r
44 #include <xmltooling/util/XMLHelper.h>
\r
45 #include <xercesc/util/XMLUniDefs.hpp>
\r
47 using namespace shibsp;
\r
48 using namespace opensaml::saml1;
\r
49 using namespace opensaml::saml1p;
\r
50 using namespace opensaml::saml2;
\r
51 using namespace opensaml::saml2p;
\r
52 using namespace opensaml::saml2md;
\r
53 using namespace opensaml;
\r
54 using namespace xmltooling;
\r
55 using namespace log4cpp;
\r
56 using namespace std;
\r
60 class SHIBSP_DLLLOCAL SimpleContext : public ResolutionContext
\r
63 SimpleContext(const Application& application, const Session& session)
\r
64 : m_app(application), m_session(&session), m_metadata(NULL), m_entity(NULL),
\r
65 m_nameid(session.getNameID()), m_token(NULL) {
\r
69 const Application& application,
\r
70 const char* client_addr,
\r
71 const EntityDescriptor* issuer,
\r
72 const NameID& nameid,
\r
73 const opensaml::RootObject* ssoToken=NULL
\r
74 ) : m_app(application), m_session(NULL), m_entity(issuer), m_nameid(nameid), m_token(ssoToken) {
\r
76 m_client_addr = client_addr;
\r
81 m_metadata->unlock();
\r
82 for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<shibsp::Attribute>());
\r
83 for_each(m_assertions.begin(), m_assertions.end(), xmltooling::cleanup<opensaml::RootObject>());
\r
86 const Application& getApplication() const {
\r
89 const char* getClientAddress() const {
\r
90 return m_session ? m_session->getClientAddress() : m_client_addr.c_str();
\r
92 const EntityDescriptor* getEntityDescriptor() const {
\r
95 if (m_session && m_session->getEntityID()) {
\r
96 m_metadata = m_app.getMetadataProvider();
\r
99 return m_entity = m_metadata->getEntityDescriptor(m_session->getEntityID());
\r
104 const NameID& getNameID() const {
\r
107 const opensaml::RootObject* getSSOToken() const {
\r
111 const vector<const char*>& ids = m_session->getAssertionIDs();
\r
113 return m_token = m_session->getAssertion(ids.front());
\r
117 const Session* getSession() const {
\r
120 vector<shibsp::Attribute*>& getResolvedAttributes() {
\r
121 return m_attributes;
\r
123 vector<opensaml::RootObject*>& getResolvedAssertions() {
\r
124 return m_assertions;
\r
128 const Application& m_app;
\r
129 const Session* m_session;
\r
130 string m_client_addr;
\r
131 mutable MetadataProvider* m_metadata;
\r
132 mutable const EntityDescriptor* m_entity;
\r
133 const NameID& m_nameid;
\r
134 mutable const opensaml::RootObject* m_token;
\r
135 vector<shibsp::Attribute*> m_attributes;
\r
136 vector<opensaml::RootObject*> m_assertions;
\r
139 #if defined (_MSC_VER)
\r
140 #pragma warning( push )
\r
141 #pragma warning( disable : 4250 )
\r
144 class SimpleResolverImpl
\r
147 SimpleResolverImpl(const DOMElement* e);
\r
148 ~SimpleResolverImpl() {
\r
149 for_each(m_decoderMap.begin(), m_decoderMap.end(), cleanup_pair<string,AttributeDecoder>());
\r
151 m_document->release();
\r
154 void setDocument(DOMDocument* doc) {
\r
159 ResolutionContext& ctx, const opensaml::saml1::Assertion* token, const vector<const char*>* attributes=NULL
\r
162 ResolutionContext& ctx, const opensaml::saml2::Assertion* token, const vector<const char*>* attributes=NULL
\r
165 ResolutionContext& ctx, const opensaml::saml1::Assertion* token, const vector<const char*>* attributes=NULL
\r
168 ResolutionContext& ctx, const opensaml::saml2::Assertion* token, const vector<const char*>* attributes=NULL
\r
172 DOMDocument* m_document;
\r
174 map<string,AttributeDecoder*> m_decoderMap;
\r
175 #ifdef HAVE_GOOD_STL
\r
176 map< pair<xstring,xstring>,pair<const AttributeDecoder*,string> > m_attrMap;
\r
178 map< pair<string,string>,pair<const AttributeDecoder*,string> > m_attrMap;
\r
182 class SimpleResolver : public AttributeResolver, public ReloadableXMLFile
\r
185 SimpleResolver(const DOMElement* e) : ReloadableXMLFile(e), m_impl(NULL) {
\r
188 ~SimpleResolver() {
\r
192 ResolutionContext* createResolutionContext(
\r
193 const Application& application,
\r
194 const char* client_addr,
\r
195 const EntityDescriptor* issuer,
\r
196 const NameID& nameid,
\r
197 const opensaml::RootObject* ssoToken=NULL
\r
199 return new SimpleContext(application,client_addr,issuer,nameid,ssoToken);
\r
202 ResolutionContext* createResolutionContext(const Application& application, const Session& session) const {
\r
203 return new SimpleContext(application,session);
\r
206 void resolveAttributes(ResolutionContext& ctx, const vector<const char*>* attributes=NULL) const;
\r
209 pair<bool,DOMElement*> load();
\r
210 SimpleResolverImpl* m_impl;
\r
213 #if defined (_MSC_VER)
\r
214 #pragma warning( pop )
\r
217 AttributeResolver* SHIBSP_DLLLOCAL SimpleAttributeResolverFactory(const DOMElement* const & e)
\r
219 return new SimpleResolver(e);
\r
222 static const XMLCh SIMPLE_NS[] = {
\r
223 chLatin_u, chLatin_r, chLatin_n, chColon, chLatin_m, chLatin_a, chLatin_c, chLatin_e, chColon,
\r
224 chLatin_s, chLatin_h, chLatin_i, chLatin_b, chLatin_b, chLatin_o, chLatin_l, chLatin_e, chLatin_t, chLatin_h, chColon,
\r
225 chDigit_2, chPeriod, chDigit_0, chColon,
\r
226 chLatin_r, chLatin_e, chLatin_s, chLatin_o, chLatin_l, chLatin_v, chLatin_e, chLatin_r, chColon,
\r
227 chLatin_s, chLatin_i, chLatin_m, chLatin_p, chLatin_l, chLatin_e, chNull
\r
229 static const XMLCh _AttributeResolver[] = UNICODE_LITERAL_17(A,t,t,r,i,b,u,t,e,R,e,s,o,l,v,e,r);
\r
230 static const XMLCh allowQuery[] = UNICODE_LITERAL_10(a,l,l,o,w,Q,u,e,r,y);
\r
231 static const XMLCh decoderType[] = UNICODE_LITERAL_11(d,e,c,o,d,e,r,T,y,p,e);
\r
234 SimpleResolverImpl::SimpleResolverImpl(const DOMElement* e) : m_document(NULL), m_allowQuery(true)
\r
237 xmltooling::NDC ndc("SimpleResolverImpl");
\r
239 Category& log=Category::getInstance(SHIBSP_LOGCAT".AttributeResolver");
\r
241 if (!XMLHelper::isNodeNamed(e, SIMPLE_NS, _AttributeResolver))
\r
242 throw ConfigurationException("Simple resolver requires resolver:AttributeResolver at root of configuration.");
\r
244 const XMLCh* flag = e->getAttributeNS(NULL,allowQuery);
\r
245 if (flag && (*flag==chLatin_f || *flag==chDigit_0)) {
\r
246 log.info("SAML attribute queries disabled");
\r
247 m_allowQuery = false;
\r
250 e = XMLHelper::getFirstChildElement(e, samlconstants::SAML20_NS, opensaml::saml2::Attribute::LOCAL_NAME);
\r
252 // Check for missing Name.
\r
253 const XMLCh* name = e->getAttributeNS(NULL, opensaml::saml2::Attribute::NAME_ATTRIB_NAME);
\r
254 if (!name || !*name) {
\r
255 log.warn("skipping saml:Attribute declared with no Name");
\r
256 e = XMLHelper::getNextSiblingElement(e, samlconstants::SAML20_NS, opensaml::saml2::Attribute::LOCAL_NAME);
\r
260 auto_ptr_char id(e->getAttributeNS(NULL, opensaml::saml2::Attribute::FRIENDLYNAME_ATTRIB_NAME));
\r
261 if (!id.get() || !*id.get()) {
\r
262 log.warn("skipping saml:Attribute declared with no FriendlyName");
\r
263 e = XMLHelper::getNextSiblingElement(e, samlconstants::SAML20_NS, opensaml::saml2::Attribute::LOCAL_NAME);
\r
267 auto_ptr_char d(e->getAttributeNS(SIMPLE_NS, decoderType));
\r
268 const char* dtype = d.get();
\r
269 if (!dtype || !*dtype)
\r
270 dtype = SIMPLE_ATTRIBUTE_DECODER;
\r
271 AttributeDecoder*& decoder = m_decoderMap[dtype];
\r
274 decoder = SPConfig::getConfig().AttributeDecoderManager.newPlugin(dtype, NULL);
\r
276 catch (exception& ex) {
\r
277 log.error("error building AttributeDecoder: %s", ex.what());
\r
278 e = XMLHelper::getNextSiblingElement(e, samlconstants::SAML20_NS, opensaml::saml2::Attribute::LOCAL_NAME);
\r
283 // Empty NameFormat implies the usual Shib URI naming defaults.
\r
284 const XMLCh* format = e->getAttributeNS(NULL, opensaml::saml2::Attribute::NAMEFORMAT_ATTRIB_NAME);
\r
285 if (!format || XMLString::equals(format, shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI) ||
\r
286 XMLString::equals(format, opensaml::saml2::Attribute::URI_REFERENCE))
\r
287 format = &chNull; // ignore default Format/Namespace values
\r
289 // Fetch/create the map entry and see if it's a duplicate rule.
\r
290 #ifdef HAVE_GOOD_STL
\r
291 pair<const AttributeDecoder*,string>& decl = m_attrMap[make_pair(name,format)];
\r
293 auto_ptr_char n(name);
\r
294 auto_ptr_char f(format);
\r
295 pair<const AttributeDecoder*,string>& decl = m_attrMap[make_pair(n.get(),f.get())];
\r
298 log.warn("skipping duplicate saml:Attribute declaration (same Name and NameFormat)");
\r
299 e = XMLHelper::getNextSiblingElement(e, samlconstants::SAML20_NS, opensaml::saml2::Attribute::LOCAL_NAME);
\r
303 if (log.isDebugEnabled()) {
\r
304 #ifdef HAVE_GOOD_STL
\r
305 auto_ptr_char n(name);
\r
306 auto_ptr_char f(format);
\r
308 log.debug("creating declaration for (Name=%s) %s%s)", n.get(), *f.get() ? "(Format/Namespace=" : "", f.get());
\r
311 decl.first = decoder;
\r
312 decl.second = id.get();
\r
314 e = XMLHelper::getNextSiblingElement(e, samlconstants::SAML20_NS, opensaml::saml2::Attribute::LOCAL_NAME);
\r
318 void SimpleResolverImpl::resolve(
\r
319 ResolutionContext& ctx, const opensaml::saml1::Assertion* token, const vector<const char*>* attributes
\r
324 for(vector<const char*>::const_iterator i=attributes->begin(); i!=attributes->end(); ++i)
\r
327 vector<shibsp::Attribute*>& resolved = ctx.getResolvedAttributes();
\r
329 #ifdef HAVE_GOOD_STL
\r
330 map< pair<xstring,xstring>,pair<const AttributeDecoder*,string> >::const_iterator rule;
\r
332 map< pair<string,string>,pair<const AttributeDecoder*,string> >::const_iterator rule;
\r
335 // Check the NameID based on the format.
\r
337 const XMLCh* format = ctx.getNameID().getFormat();
\r
339 format = NameID::UNSPECIFIED;
\r
340 #ifdef HAVE_GOOD_STL
\r
341 if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {
\r
343 auto_ptr_char temp(format);
\r
344 if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {
\r
346 if (aset.empty() || aset.count(rule->second.second))
\r
347 resolved.push_back(rule->second.first->decode(rule->second.second.c_str(), &ctx.getNameID()));
\r
351 const vector<opensaml::saml1::AttributeStatement*>& statements = token->getAttributeStatements();
\r
352 for (vector<opensaml::saml1::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s) {
\r
353 const vector<opensaml::saml1::Attribute*>& attrs = const_cast<const opensaml::saml1::AttributeStatement*>(*s)->getAttributes();
\r
354 for (vector<opensaml::saml1::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a) {
\r
355 name = (*a)->getAttributeName();
\r
356 format = (*a)->getAttributeNamespace();
\r
357 if (!name || !*name)
\r
361 #ifdef HAVE_GOOD_STL
\r
362 if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) {
\r
364 auto_ptr_char temp1(name);
\r
365 auto_ptr_char temp2(format);
\r
366 if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {
\r
368 if (aset.empty() || aset.count(rule->second.second))
\r
369 resolved.push_back(rule->second.first->decode(rule->second.second.c_str(), *a));
\r
375 void SimpleResolverImpl::resolve(
\r
376 ResolutionContext& ctx, const opensaml::saml2::Assertion* token, const vector<const char*>* attributes
\r
381 for(vector<const char*>::const_iterator i=attributes->begin(); i!=attributes->end(); ++i)
\r
384 vector<shibsp::Attribute*>& resolved = ctx.getResolvedAttributes();
\r
386 #ifdef HAVE_GOOD_STL
\r
387 map< pair<xstring,xstring>,pair<const AttributeDecoder*,string> >::const_iterator rule;
\r
389 map< pair<string,string>,pair<const AttributeDecoder*,string> >::const_iterator rule;
\r
392 // Check the NameID based on the format.
\r
394 const XMLCh* format = ctx.getNameID().getFormat();
\r
396 format = NameID::UNSPECIFIED;
\r
397 #ifdef HAVE_GOOD_STL
\r
398 if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {
\r
400 auto_ptr_char temp(format);
\r
401 if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {
\r
403 if (aset.empty() || aset.count(rule->second.second))
\r
404 resolved.push_back(rule->second.first->decode(rule->second.second.c_str(), &ctx.getNameID()));
\r
408 const vector<opensaml::saml2::AttributeStatement*>& statements = token->getAttributeStatements();
\r
409 for (vector<opensaml::saml2::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s) {
\r
410 const vector<opensaml::saml2::Attribute*>& attrs = const_cast<const opensaml::saml2::AttributeStatement*>(*s)->getAttributes();
\r
411 for (vector<opensaml::saml2::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a) {
\r
412 name = (*a)->getName();
\r
413 format = (*a)->getNameFormat();
\r
414 if (!name || !*name)
\r
418 #ifdef HAVE_GOOD_STL
\r
419 if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) {
\r
421 auto_ptr_char temp1(name);
\r
422 auto_ptr_char temp2(format);
\r
423 if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {
\r
425 if (aset.empty() || aset.count(rule->second.second))
\r
426 resolved.push_back(rule->second.first->decode(rule->second.second.c_str(), *a));
\r
432 void SimpleResolverImpl::query(ResolutionContext& ctx, const opensaml::saml1::Assertion* token, const vector<const char*>* attributes) const
\r
438 xmltooling::NDC ndc("query");
\r
440 Category& log=Category::getInstance(SHIBSP_LOGCAT".AttributeResolver");
\r
442 const EntityDescriptor* entity = ctx.getEntityDescriptor();
\r
444 log.debug("no issuer information available, skipping query");
\r
447 const AttributeAuthorityDescriptor* AA =
\r
448 entity->getAttributeAuthorityDescriptor(
\r
449 token->getMinorVersion().second==1 ? samlconstants::SAML11_PROTOCOL_ENUM : samlconstants::SAML10_PROTOCOL_ENUM
\r
452 log.debug("no SAML 1.%d AttributeAuthority role found in metadata", token->getMinorVersion().second);
\r
456 SecurityPolicy policy;
\r
457 shibsp::SOAPClient soaper(ctx.getApplication(),policy);
\r
459 auto_ptr_XMLCh binding(samlconstants::SAML1_BINDING_SOAP);
\r
460 opensaml::saml1p::Response* response=NULL;
\r
461 const vector<AttributeService*>& endpoints=AA->getAttributeServices();
\r
462 for (vector<AttributeService*>::const_iterator ep=endpoints.begin(); !response && ep!=endpoints.end(); ++ep) {
\r
464 if (!XMLString::equals((*ep)->getBinding(),binding.get()))
\r
466 auto_ptr_char loc((*ep)->getLocation());
\r
467 auto_ptr_XMLCh issuer(ctx.getApplication().getString("providerId").second);
\r
468 opensaml::saml1::Subject* subject = opensaml::saml1::SubjectBuilder::buildSubject();
\r
469 subject->setNameIdentifier(token->getAuthenticationStatements().front()->getSubject()->getNameIdentifier()->cloneNameIdentifier());
\r
470 opensaml::saml1p::AttributeQuery* query = opensaml::saml1p::AttributeQueryBuilder::buildAttributeQuery();
\r
471 query->setSubject(subject);
\r
472 Request* request = RequestBuilder::buildRequest();
\r
473 request->setAttributeQuery(query);
\r
474 query->setResource(issuer.get());
\r
475 request->setMinorVersion(token->getMinorVersion().second);
\r
476 SAML1SOAPClient client(soaper);
\r
477 client.sendSAML(request, *AA, loc.get());
\r
478 response = client.receiveSAML();
\r
480 catch (exception& ex) {
\r
481 log.error("exception making SAML query: %s", ex.what());
\r
487 log.error("unable to successfully query for attributes");
\r
491 time_t now = time(NULL);
\r
492 const Validator* tokval = ctx.getApplication().getTokenValidator(now, AA);
\r
493 const vector<opensaml::saml1::Assertion*>& assertions = const_cast<const opensaml::saml1p::Response*>(response)->getAssertions();
\r
494 if (assertions.size()==1) {
\r
495 auto_ptr<opensaml::saml1p::Response> wrapper(response);
\r
496 opensaml::saml1::Assertion* newtoken = assertions.front();
\r
497 if (!XMLString::equals(policy.getIssuer() ? policy.getIssuer()->getName() : NULL, newtoken->getIssuer())) {
\r
498 log.error("assertion issued by someone other than AA, rejecting it");
\r
502 tokval->validate(newtoken);
\r
504 catch (exception& ex) {
\r
505 log.error("assertion failed validation check: %s", ex.what());
\r
507 newtoken->detach();
\r
509 ctx.getResolvedAssertions().push_back(newtoken);
\r
510 resolve(ctx, newtoken, attributes);
\r
513 auto_ptr<opensaml::saml1p::Response> wrapper(response);
\r
514 for (vector<opensaml::saml1::Assertion*>::const_iterator a = assertions.begin(); a!=assertions.end(); ++a) {
\r
515 if (!XMLString::equals(policy.getIssuer() ? policy.getIssuer()->getName() : NULL, (*a)->getIssuer())) {
\r
516 log.error("assertion issued by someone other than AA, rejecting it");
\r
520 tokval->validate(*a);
\r
522 catch (exception& ex) {
\r
523 log.error("assertion failed validation check: %s", ex.what());
\r
525 resolve(ctx, *a, attributes);
\r
526 ctx.getResolvedAssertions().push_back((*a)->cloneAssertion());
\r
531 void SimpleResolverImpl::query(ResolutionContext& ctx, const opensaml::saml2::Assertion* token, const vector<const char*>* attributes) const
\r
537 xmltooling::NDC ndc("query");
\r
539 Category& log=Category::getInstance(SHIBSP_LOGCAT".AttributeResolver");
\r
541 const EntityDescriptor* entity = ctx.getEntityDescriptor();
\r
543 log.debug("no issuer information available, skipping query");
\r
546 const AttributeAuthorityDescriptor* AA = entity->getAttributeAuthorityDescriptor(samlconstants::SAML20P_NS);
\r
548 log.debug("no SAML 2 AttributeAuthority role found in metadata");
\r
552 SecurityPolicy policy;
\r
553 shibsp::SOAPClient soaper(ctx.getApplication(),policy);
\r
555 auto_ptr_XMLCh binding(samlconstants::SAML20_BINDING_SOAP);
\r
556 opensaml::saml2p::StatusResponseType* srt=NULL;
\r
557 const vector<AttributeService*>& endpoints=AA->getAttributeServices();
\r
558 for (vector<AttributeService*>::const_iterator ep=endpoints.begin(); !srt && ep!=endpoints.end(); ++ep) {
\r
560 if (!XMLString::equals((*ep)->getBinding(),binding.get()))
\r
562 auto_ptr_char loc((*ep)->getLocation());
\r
563 auto_ptr_XMLCh issuer(ctx.getApplication().getString("providerId").second);
\r
564 opensaml::saml2::Subject* subject = opensaml::saml2::SubjectBuilder::buildSubject();
\r
565 subject->setNameID(token->getSubject()->getNameID()->cloneNameID());
\r
566 opensaml::saml2p::AttributeQuery* query = opensaml::saml2p::AttributeQueryBuilder::buildAttributeQuery();
\r
567 query->setSubject(subject);
\r
568 Issuer* iss = IssuerBuilder::buildIssuer();
\r
569 query->setIssuer(iss);
\r
570 iss->setName(issuer.get());
\r
571 SAML2SOAPClient client(soaper);
\r
572 client.sendSAML(query, *AA, loc.get());
\r
573 srt = client.receiveSAML();
\r
575 catch (exception& ex) {
\r
576 log.error("exception making SAML query: %s", ex.what());
\r
582 log.error("unable to successfully query for attributes");
\r
585 opensaml::saml2p::Response* response = dynamic_cast<opensaml::saml2p::Response*>(srt);
\r
588 log.error("message was not a samlp:Response");
\r
592 time_t now = time(NULL);
\r
593 const Validator* tokval = ctx.getApplication().getTokenValidator(now, AA);
\r
594 const vector<opensaml::saml2::Assertion*>& assertions = const_cast<const opensaml::saml2p::Response*>(response)->getAssertions();
\r
595 if (assertions.size()==1) {
\r
596 auto_ptr<opensaml::saml2p::Response> wrapper(response);
\r
597 opensaml::saml2::Assertion* newtoken = assertions.front();
\r
598 if (!XMLString::equals(policy.getIssuer() ? policy.getIssuer()->getName() : NULL, newtoken->getIssuer() ? newtoken->getIssuer()->getName() : NULL)) {
\r
599 log.error("assertion issued by someone other than AA, rejecting it");
\r
603 tokval->validate(newtoken);
\r
605 catch (exception& ex) {
\r
606 log.error("assertion failed validation check: %s", ex.what());
\r
608 newtoken->detach();
\r
610 ctx.getResolvedAssertions().push_back(newtoken);
\r
611 resolve(ctx, newtoken, attributes);
\r
614 auto_ptr<opensaml::saml2p::Response> wrapper(response);
\r
615 for (vector<opensaml::saml2::Assertion*>::const_iterator a = assertions.begin(); a!=assertions.end(); ++a) {
\r
616 if (!XMLString::equals(policy.getIssuer() ? policy.getIssuer()->getName() : NULL, (*a)->getIssuer() ? (*a)->getIssuer()->getName() : NULL)) {
\r
617 log.error("assertion issued by someone other than AA, rejecting it");
\r
621 tokval->validate(*a);
\r
623 catch (exception& ex) {
\r
624 log.error("assertion failed validation check: %s", ex.what());
\r
626 resolve(ctx, *a, attributes);
\r
627 ctx.getResolvedAssertions().push_back((*a)->cloneAssertion());
\r
632 void SimpleResolver::resolveAttributes(ResolutionContext& ctx, const vector<const char*>* attributes) const
\r
635 xmltooling::NDC ndc("resolveAttributes");
\r
637 Category& log=Category::getInstance(SHIBSP_LOGCAT".AttributeResolver");
\r
639 log.debug("examining incoming SSO token");
\r
641 const opensaml::RootObject* token = ctx.getSSOToken();
\r
643 log.warn("no SSO token supplied to resolver, returning nothing");
\r
646 const opensaml::saml2::Assertion* token2 = dynamic_cast<const opensaml::saml2::Assertion*>(token);
\r
648 if (!token2->getAttributeStatements().empty()) {
\r
649 log.debug("found SAML 2 SSO token with an AttributeStatement");
\r
650 return m_impl->resolve(ctx, token2, attributes);
\r
652 return m_impl->query(ctx, token2, attributes);
\r
655 const opensaml::saml1::Assertion* token1 = dynamic_cast<const opensaml::saml1::Assertion*>(token);
\r
657 if (!token1->getAttributeStatements().empty()) {
\r
658 log.debug("found SAML 1 SSO token with an AttributeStatement");
\r
659 return m_impl->resolve(ctx, token1, attributes);
\r
661 return m_impl->query(ctx, token1, attributes);
\r
664 log.warn("unrecognized token type, returning nothing");
\r
667 pair<bool,DOMElement*> SimpleResolver::load()
\r
669 // Load from source using base class.
\r
670 pair<bool,DOMElement*> raw = ReloadableXMLFile::load();
\r
672 // If we own it, wrap it.
\r
673 XercesJanitor<DOMDocument> docjanitor(raw.first ? raw.second->getOwnerDocument() : NULL);
\r
675 SimpleResolverImpl* impl = new SimpleResolverImpl(raw.second);
\r
677 // If we held the document, transfer it to the impl. If we didn't, it's a no-op.
\r
678 impl->setDocument(docjanitor.release());
\r
683 return make_pair(false,(DOMElement*)NULL);
\r