\r
#include "internal.h"\r
#include "Application.h"\r
+#include "ServiceProvider.h"\r
#include "SessionCache.h"\r
#include "attribute/AttributeDecoder.h"\r
#include "attribute/resolver/AttributeResolver.h"\r
#include <saml/saml1/binding/SAML1SOAPClient.h>\r
#include <saml/saml1/core/Assertions.h>\r
#include <saml/saml1/core/Protocols.h>\r
+#include <saml/saml1/profile/AssertionValidator.h>\r
#include <saml/saml2/binding/SAML2SOAPClient.h>\r
#include <saml/saml2/core/Protocols.h>\r
#include <saml/saml2/metadata/Metadata.h>\r
#include <saml/saml2/metadata/MetadataProvider.h>\r
+#include <saml/saml2/profile/AssertionValidator.h>\r
#include <xmltooling/util/NDC.h>\r
#include <xmltooling/util/ReloadableXMLFile.h>\r
#include <xmltooling/util/XMLHelper.h>\r
{\r
public:\r
SimpleContext(const Application& application, const Session& session)\r
- : m_app(application), m_session(&session), m_metadata(NULL), m_entity(NULL),\r
- m_nameid(session.getNameID()), m_token(NULL) {\r
+ : m_app(application), m_session(&session), m_client_addr(NULL), m_metadata(NULL), m_entity(NULL),\r
+ m_nameid(session.getNameID()), m_tokens(NULL) {\r
}\r
\r
SimpleContext(\r
const Application& application,\r
const char* client_addr,\r
const EntityDescriptor* issuer,\r
- const NameID& nameid,\r
- const opensaml::RootObject* ssoToken=NULL\r
- ) : m_app(application), m_session(NULL), m_entity(issuer), m_nameid(nameid), m_token(ssoToken) {\r
- if (client_addr)\r
- m_client_addr = client_addr;\r
+ const NameID* nameid,\r
+ const vector<const opensaml::Assertion*>* tokens=NULL\r
+ ) : m_app(application), m_session(NULL), m_client_addr(client_addr), m_metadata(NULL), m_entity(issuer),\r
+ m_nameid(nameid), m_tokens(tokens) {\r
}\r
\r
~SimpleContext() {\r
if (m_metadata)\r
m_metadata->unlock();\r
for_each(m_attributes.begin(), m_attributes.end(), xmltooling::cleanup<shibsp::Attribute>());\r
- for_each(m_assertions.begin(), m_assertions.end(), xmltooling::cleanup<opensaml::RootObject>());\r
+ for_each(m_assertions.begin(), m_assertions.end(), xmltooling::cleanup<opensaml::Assertion>());\r
}\r
\r
const Application& getApplication() const {\r
return m_app;\r
}\r
const char* getClientAddress() const {\r
- return m_session ? m_session->getClientAddress() : m_client_addr.c_str();\r
+ return m_session ? m_session->getClientAddress() : m_client_addr;\r
}\r
const EntityDescriptor* getEntityDescriptor() const {\r
if (m_entity)\r
}\r
return NULL;\r
}\r
- const NameID& getNameID() const {\r
+ const NameID* getNameID() const {\r
return m_nameid;\r
}\r
- const opensaml::RootObject* getSSOToken() const {\r
- if (m_token)\r
- return m_token;\r
- if (m_session) {\r
- const vector<const char*>& ids = m_session->getAssertionIDs();\r
- if (!ids.empty())\r
- return m_token = m_session->getAssertion(ids.front());\r
- }\r
- return NULL;\r
+ const vector<const opensaml::Assertion*>* getTokens() const {\r
+ return m_tokens;\r
}\r
const Session* getSession() const {\r
return m_session;\r
vector<shibsp::Attribute*>& getResolvedAttributes() {\r
return m_attributes;\r
}\r
- vector<opensaml::RootObject*>& getResolvedAssertions() {\r
+ vector<opensaml::Assertion*>& getResolvedAssertions() {\r
return m_assertions;\r
}\r
\r
private:\r
const Application& m_app;\r
const Session* m_session;\r
- string m_client_addr;\r
+ const char* m_client_addr;\r
mutable MetadataProvider* m_metadata;\r
mutable const EntityDescriptor* m_entity;\r
- const NameID& m_nameid;\r
- mutable const opensaml::RootObject* m_token;\r
+ const NameID* m_nameid;\r
+ const vector<const opensaml::Assertion*>* m_tokens;\r
vector<shibsp::Attribute*> m_attributes;\r
- vector<opensaml::RootObject*> m_assertions;\r
+ vector<opensaml::Assertion*> m_assertions;\r
};\r
\r
#if defined (_MSC_VER)\r
}\r
\r
void query(\r
- ResolutionContext& ctx, const opensaml::saml1::Assertion* token, const vector<const char*>* attributes=NULL\r
+ ResolutionContext& ctx, const NameIdentifier& nameid, const set<string>* attributes=NULL\r
) const;\r
void query(\r
- ResolutionContext& ctx, const opensaml::saml2::Assertion* token, const vector<const char*>* attributes=NULL\r
+ ResolutionContext& ctx, const NameID& nameid, const set<string>* attributes=NULL\r
) const;\r
void resolve(\r
- ResolutionContext& ctx, const opensaml::saml1::Assertion* token, const vector<const char*>* attributes=NULL\r
+ ResolutionContext& ctx, const saml1::Assertion* token, const set<string>* attributes=NULL\r
) const;\r
void resolve(\r
- ResolutionContext& ctx, const opensaml::saml2::Assertion* token, const vector<const char*>* attributes=NULL\r
+ ResolutionContext& ctx, const saml2::Assertion* token, const set<string>* attributes=NULL\r
) const;\r
\r
+ bool m_allowQuery;\r
+\r
private:\r
+ void populateQuery(saml1p::AttributeQuery& query, const string& id) const;\r
+ void populateQuery(saml2p::AttributeQuery& query, const string& id) const;\r
+\r
DOMDocument* m_document;\r
- bool m_allowQuery;\r
map<string,AttributeDecoder*> m_decoderMap;\r
#ifdef HAVE_GOOD_STL\r
- map< pair<xstring,xstring>,pair<const AttributeDecoder*,string> > m_attrMap;\r
+ typedef map< pair<xstring,xstring>,pair<const AttributeDecoder*,string> > attrmap_t;\r
#else\r
- map< pair<string,string>,pair<const AttributeDecoder*,string> > m_attrMap;\r
+ typedef map< pair<string,string>,pair<const AttributeDecoder*,string> > attrmap_t;\r
#endif\r
+ attrmap_t m_attrMap;\r
};\r
\r
class SimpleResolver : public AttributeResolver, public ReloadableXMLFile\r
const Application& application,\r
const char* client_addr,\r
const EntityDescriptor* issuer,\r
- const NameID& nameid,\r
- const opensaml::RootObject* ssoToken=NULL\r
+ const NameID* nameid,\r
+ const vector<const opensaml::Assertion*>* tokens=NULL\r
) const {\r
- return new SimpleContext(application,client_addr,issuer,nameid,ssoToken);\r
+ return new SimpleContext(application,client_addr,issuer,nameid,tokens);\r
}\r
\r
ResolutionContext* createResolutionContext(const Application& application, const Session& session) const {\r
return new SimpleContext(application,session);\r
}\r
\r
- void resolveAttributes(ResolutionContext& ctx, const vector<const char*>* attributes=NULL) const;\r
+ void resolveAttributes(ResolutionContext& ctx, const set<string>* attributes=NULL) const;\r
\r
protected:\r
pair<bool,DOMElement*> load();\r
child = XMLHelper::getNextSiblingElement(child, SIMPLE_NS, _AttributeDecoder);\r
}\r
\r
- child = XMLHelper::getFirstChildElement(e, samlconstants::SAML20_NS, opensaml::saml2::Attribute::LOCAL_NAME);\r
+ child = XMLHelper::getFirstChildElement(e, samlconstants::SAML20_NS, saml2::Attribute::LOCAL_NAME);\r
while (child) {\r
// Check for missing Name.\r
- const XMLCh* name = child->getAttributeNS(NULL, opensaml::saml2::Attribute::NAME_ATTRIB_NAME);\r
+ const XMLCh* name = child->getAttributeNS(NULL, saml2::Attribute::NAME_ATTRIB_NAME);\r
if (!name || !*name) {\r
log.warn("skipping saml:Attribute declared with no Name");\r
- child = XMLHelper::getNextSiblingElement(child, samlconstants::SAML20_NS, opensaml::saml2::Attribute::LOCAL_NAME);\r
+ child = XMLHelper::getNextSiblingElement(child, samlconstants::SAML20_NS, saml2::Attribute::LOCAL_NAME);\r
continue;\r
}\r
\r
const AttributeDecoder* decoder=NULL;\r
- auto_ptr_char id(child->getAttributeNS(NULL, opensaml::saml2::Attribute::FRIENDLYNAME_ATTRIB_NAME));\r
+ auto_ptr_char id(child->getAttributeNS(NULL, saml2::Attribute::FRIENDLYNAME_ATTRIB_NAME));\r
auto_ptr_char d(child->getAttributeNS(SIMPLE_NS, decoderId));\r
if (!id.get() || !*id.get() || !d.get() || !*d.get() || !(decoder=m_decoderMap[d.get()])) {\r
log.warn("skipping saml:Attribute declared with no FriendlyName or resolvable AttributeDecoder");\r
- child = XMLHelper::getNextSiblingElement(child, samlconstants::SAML20_NS, opensaml::saml2::Attribute::LOCAL_NAME);\r
+ child = XMLHelper::getNextSiblingElement(child, samlconstants::SAML20_NS, saml2::Attribute::LOCAL_NAME);\r
continue;\r
}\r
\r
// Empty NameFormat implies the usual Shib URI naming defaults.\r
- const XMLCh* format = child->getAttributeNS(NULL, opensaml::saml2::Attribute::NAMEFORMAT_ATTRIB_NAME);\r
+ const XMLCh* format = child->getAttributeNS(NULL, saml2::Attribute::NAMEFORMAT_ATTRIB_NAME);\r
if (!format || XMLString::equals(format, shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI) ||\r
- XMLString::equals(format, opensaml::saml2::Attribute::URI_REFERENCE))\r
+ XMLString::equals(format, saml2::Attribute::URI_REFERENCE))\r
format = &chNull; // ignore default Format/Namespace values\r
\r
// Fetch/create the map entry and see if it's a duplicate rule.\r
#endif\r
if (decl.first) {\r
log.warn("skipping duplicate saml:Attribute declaration (same Name and NameFormat)");\r
- child = XMLHelper::getNextSiblingElement(child, samlconstants::SAML20_NS, opensaml::saml2::Attribute::LOCAL_NAME);\r
+ child = XMLHelper::getNextSiblingElement(child, samlconstants::SAML20_NS, saml2::Attribute::LOCAL_NAME);\r
continue;\r
}\r
\r
- if (log.isDebugEnabled()) {\r
+ if (log.isInfoEnabled()) {\r
#ifdef HAVE_GOOD_STL\r
auto_ptr_char n(name);\r
auto_ptr_char f(format);\r
#endif\r
- log.debug("creating declaration for Attribute %s%s%s", n.get(), *f.get() ? ", Format/Namespace:" : "", f.get());\r
+ log.info("creating declaration for Attribute %s%s%s", n.get(), *f.get() ? ", Format/Namespace:" : "", f.get());\r
}\r
\r
decl.first = decoder;\r
decl.second = id.get();\r
\r
- child = XMLHelper::getNextSiblingElement(child, samlconstants::SAML20_NS, opensaml::saml2::Attribute::LOCAL_NAME);\r
+ child = XMLHelper::getNextSiblingElement(child, samlconstants::SAML20_NS, saml2::Attribute::LOCAL_NAME);\r
}\r
}\r
\r
void SimpleResolverImpl::resolve(\r
- ResolutionContext& ctx, const opensaml::saml1::Assertion* token, const vector<const char*>* attributes\r
+ ResolutionContext& ctx, const saml1::Assertion* token, const set<string>* attributes\r
) const\r
{\r
- set<string> aset;\r
- if (attributes)\r
- for(vector<const char*>::const_iterator i=attributes->begin(); i!=attributes->end(); ++i)\r
- aset.insert(*i);\r
-\r
vector<shibsp::Attribute*>& resolved = ctx.getResolvedAttributes();\r
\r
auto_ptr_char assertingParty(ctx.getEntityDescriptor() ? ctx.getEntityDescriptor()->getEntityID() : NULL);\r
map< pair<string,string>,pair<const AttributeDecoder*,string> >::const_iterator rule;\r
#endif\r
\r
- // Check the NameID based on the format.\r
const XMLCh* name;\r
- const XMLCh* format = ctx.getNameID().getFormat();\r
- if (!format) {\r
- format = NameID::UNSPECIFIED;\r
+ const XMLCh* format;\r
+ \r
+ // Check the NameID based on the format.\r
+ if (ctx.getNameID()) {\r
+ format = ctx.getNameID()->getFormat();\r
+ if (!format || !*format)\r
+ format = NameID::UNSPECIFIED;\r
#ifdef HAVE_GOOD_STL\r
if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {\r
#else\r
auto_ptr_char temp(format);\r
if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {\r
#endif\r
- if (aset.empty() || aset.count(rule->second.second)) {\r
+ if (!attributes || attributes->count(rule->second.second)) {\r
resolved.push_back(\r
rule->second.first->decode(\r
- rule->second.second.c_str(), &ctx.getNameID(), assertingParty.get(), relyingParty\r
+ rule->second.second.c_str(), ctx.getNameID(), assertingParty.get(), relyingParty\r
)\r
);\r
}\r
}\r
}\r
\r
- const vector<opensaml::saml1::AttributeStatement*>& statements = token->getAttributeStatements();\r
- for (vector<opensaml::saml1::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s) {\r
- const vector<opensaml::saml1::Attribute*>& attrs = const_cast<const opensaml::saml1::AttributeStatement*>(*s)->getAttributes();\r
- for (vector<opensaml::saml1::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a) {\r
+ const vector<saml1::AttributeStatement*>& statements = token->getAttributeStatements();\r
+ for (vector<saml1::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s) {\r
+ const vector<saml1::Attribute*>& attrs = const_cast<const saml1::AttributeStatement*>(*s)->getAttributes();\r
+ for (vector<saml1::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a) {\r
name = (*a)->getAttributeName();\r
format = (*a)->getAttributeNamespace();\r
if (!name || !*name)\r
continue;\r
- if (!format)\r
+ if (!format || XMLString::equals(format, shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI))\r
format = &chNull;\r
#ifdef HAVE_GOOD_STL\r
if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) {\r
auto_ptr_char temp2(format);\r
if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {\r
#endif\r
- if (aset.empty() || aset.count(rule->second.second)) {\r
+ if (!attributes || attributes->count(rule->second.second)) {\r
resolved.push_back(\r
rule->second.first->decode(rule->second.second.c_str(), *a, assertingParty.get(), relyingParty)\r
);\r
}\r
\r
void SimpleResolverImpl::resolve(\r
- ResolutionContext& ctx, const opensaml::saml2::Assertion* token, const vector<const char*>* attributes\r
+ ResolutionContext& ctx, const saml2::Assertion* token, const set<string>* attributes\r
) const\r
{\r
- set<string> aset;\r
- if (attributes)\r
- for(vector<const char*>::const_iterator i=attributes->begin(); i!=attributes->end(); ++i)\r
- aset.insert(*i);\r
-\r
vector<shibsp::Attribute*>& resolved = ctx.getResolvedAttributes();\r
\r
auto_ptr_char assertingParty(ctx.getEntityDescriptor() ? ctx.getEntityDescriptor()->getEntityID() : NULL);\r
map< pair<string,string>,pair<const AttributeDecoder*,string> >::const_iterator rule;\r
#endif\r
\r
- // Check the NameID based on the format.\r
const XMLCh* name;\r
- const XMLCh* format = ctx.getNameID().getFormat();\r
- if (!format) {\r
- format = NameID::UNSPECIFIED;\r
+ const XMLCh* format;\r
+ \r
+ // Check the NameID based on the format.\r
+ if (ctx.getNameID()) {\r
+ format = ctx.getNameID()->getFormat();\r
+ if (!format || !*format)\r
+ format = NameID::UNSPECIFIED;\r
#ifdef HAVE_GOOD_STL\r
if ((rule=m_attrMap.find(make_pair(format,xstring()))) != m_attrMap.end()) {\r
#else\r
auto_ptr_char temp(format);\r
if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {\r
#endif\r
- if (aset.empty() || aset.count(rule->second.second)) {\r
+ if (!attributes || attributes->count(rule->second.second)) {\r
resolved.push_back(\r
rule->second.first->decode(\r
- rule->second.second.c_str(), &ctx.getNameID(), assertingParty.get(), relyingParty\r
+ rule->second.second.c_str(), ctx.getNameID(), assertingParty.get(), relyingParty\r
)\r
);\r
}\r
}\r
}\r
\r
- const vector<opensaml::saml2::AttributeStatement*>& statements = token->getAttributeStatements();\r
- for (vector<opensaml::saml2::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s) {\r
- const vector<opensaml::saml2::Attribute*>& attrs = const_cast<const opensaml::saml2::AttributeStatement*>(*s)->getAttributes();\r
- for (vector<opensaml::saml2::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a) {\r
+ const vector<saml2::AttributeStatement*>& statements = token->getAttributeStatements();\r
+ for (vector<saml2::AttributeStatement*>::const_iterator s = statements.begin(); s!=statements.end(); ++s) {\r
+ const vector<saml2::Attribute*>& attrs = const_cast<const saml2::AttributeStatement*>(*s)->getAttributes();\r
+ for (vector<saml2::Attribute*>::const_iterator a = attrs.begin(); a!=attrs.end(); ++a) {\r
name = (*a)->getName();\r
format = (*a)->getNameFormat();\r
if (!name || !*name)\r
continue;\r
- if (!format)\r
+ if (!format || !*format)\r
+ format = saml2::Attribute::UNSPECIFIED;\r
+ else if (XMLString::equals(format, saml2::Attribute::URI_REFERENCE))\r
format = &chNull;\r
#ifdef HAVE_GOOD_STL\r
if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) {\r
auto_ptr_char temp2(format);\r
if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {\r
#endif\r
- if (aset.empty() || aset.count(rule->second.second)) {\r
+ if (!attributes || attributes->count(rule->second.second)) {\r
resolved.push_back(\r
rule->second.first->decode(rule->second.second.c_str(), *a, assertingParty.get(), relyingParty)\r
);\r
}\r
}\r
}\r
+\r
+ const vector<saml2::EncryptedAttribute*>& encattrs = const_cast<const saml2::AttributeStatement*>(*s)->getEncryptedAttributes();\r
+ if (!encattrs.empty()) {\r
+ const XMLCh* recipient = ctx.getApplication().getXMLString("providerId").second;\r
+ CredentialResolver* cr = ctx.getApplication().getCredentialResolver();\r
+ if (!cr) {\r
+ Category::getInstance(SHIBSP_LOGCAT".AttributeResolver").warn(\r
+ "found encrypted attributes, but no CredentialResolver was available"\r
+ );\r
+ return;\r
+ }\r
+\r
+ // We look up credentials based on the peer who did the encrypting.\r
+ CredentialCriteria cc;\r
+ cc.setPeerName(assertingParty.get());\r
+\r
+ Locker credlocker(cr);\r
+ for (vector<saml2::EncryptedAttribute*>::const_iterator ea = encattrs.begin(); ea!=encattrs.end(); ++ea) {\r
+ auto_ptr<XMLObject> decrypted((*ea)->decrypt(*cr, recipient, &cc));\r
+ const saml2::Attribute* decattr = dynamic_cast<const saml2::Attribute*>(decrypted.get());\r
+ name = decattr->getName();\r
+ format = decattr->getNameFormat();\r
+ if (!name || !*name)\r
+ continue;\r
+ if (!format || !*format)\r
+ format = saml2::Attribute::UNSPECIFIED;\r
+ else if (XMLString::equals(format, saml2::Attribute::URI_REFERENCE))\r
+ format = &chNull;\r
+#ifdef HAVE_GOOD_STL\r
+ if ((rule=m_attrMap.find(make_pair(name,format))) != m_attrMap.end()) {\r
+#else\r
+ auto_ptr_char temp1(name);\r
+ auto_ptr_char temp2(format);\r
+ if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {\r
+#endif\r
+ if (!attributes || attributes->count(rule->second.second)) {\r
+ resolved.push_back(\r
+ rule->second.first->decode(rule->second.second.c_str(), decattr, assertingParty.get(), relyingParty)\r
+ );\r
+ }\r
+ }\r
+ }\r
+ }\r
}\r
}\r
\r
-void SimpleResolverImpl::query(ResolutionContext& ctx, const opensaml::saml1::Assertion* token, const vector<const char*>* attributes) const\r
+void SimpleResolverImpl::query(ResolutionContext& ctx, const NameIdentifier& nameid, const set<string>* attributes) const\r
{\r
- if (!m_allowQuery)\r
- return;\r
-\r
#ifdef _DEBUG\r
xmltooling::NDC ndc("query");\r
#endif\r
log.debug("no issuer information available, skipping query");\r
return;\r
}\r
- const AttributeAuthorityDescriptor* AA =\r
- entity->getAttributeAuthorityDescriptor(\r
- token->getMinorVersion().second==1 ? samlconstants::SAML11_PROTOCOL_ENUM : samlconstants::SAML10_PROTOCOL_ENUM\r
- );\r
+\r
+ int version = 1;\r
+ const AttributeAuthorityDescriptor* AA = entity->getAttributeAuthorityDescriptor(samlconstants::SAML11_PROTOCOL_ENUM);\r
if (!AA) {\r
- log.debug("no SAML 1.%d AttributeAuthority role found in metadata", token->getMinorVersion().second);\r
+ AA = entity->getAttributeAuthorityDescriptor(samlconstants::SAML10_PROTOCOL_ENUM);\r
+ version = 0;\r
+ }\r
+ if (!AA) {\r
+ log.info("no SAML 1.x AttributeAuthority role found in metadata");\r
return;\r
}\r
\r
SecurityPolicy policy;\r
+ MetadataCredentialCriteria mcc(*AA);\r
shibsp::SOAPClient soaper(ctx.getApplication(),policy);\r
+ const PropertySet* policySettings = ctx.getApplication().getServiceProvider().getPolicySettings(ctx.getApplication().getString("policyId").second);\r
+ pair<bool,bool> signedAssertions = policySettings->getBool("signedAssertions");\r
\r
auto_ptr_XMLCh binding(samlconstants::SAML1_BINDING_SOAP);\r
- opensaml::saml1p::Response* response=NULL;\r
+ saml1p::Response* response=NULL;\r
const vector<AttributeService*>& endpoints=AA->getAttributeServices();\r
for (vector<AttributeService*>::const_iterator ep=endpoints.begin(); !response && ep!=endpoints.end(); ++ep) {\r
try {\r
continue;\r
auto_ptr_char loc((*ep)->getLocation());\r
auto_ptr_XMLCh issuer(ctx.getApplication().getString("providerId").second);\r
- opensaml::saml1::Subject* subject = opensaml::saml1::SubjectBuilder::buildSubject();\r
- subject->setNameIdentifier(token->getAuthenticationStatements().front()->getSubject()->getNameIdentifier()->cloneNameIdentifier());\r
- opensaml::saml1p::AttributeQuery* query = opensaml::saml1p::AttributeQueryBuilder::buildAttributeQuery();\r
+ saml1::Subject* subject = saml1::SubjectBuilder::buildSubject();\r
+ subject->setNameIdentifier(nameid.cloneNameIdentifier());\r
+ saml1p::AttributeQuery* query = saml1p::AttributeQueryBuilder::buildAttributeQuery();\r
query->setSubject(subject);\r
Request* request = RequestBuilder::buildRequest();\r
request->setAttributeQuery(query);\r
query->setResource(issuer.get());\r
- request->setMinorVersion(token->getMinorVersion().second);\r
+ request->setMinorVersion(version);\r
+ if (attributes) {\r
+ for (set<string>::const_iterator a = attributes->begin(); a!=attributes->end(); ++a)\r
+ populateQuery(*query, *a);\r
+ }\r
+\r
SAML1SOAPClient client(soaper);\r
- client.sendSAML(request, *AA, loc.get());\r
+ client.sendSAML(request, mcc, loc.get());\r
response = client.receiveSAML();\r
}\r
catch (exception& ex) {\r
return;\r
}\r
\r
- time_t now = time(NULL);\r
- const Validator* tokval = ctx.getApplication().getTokenValidator(now, AA);\r
- const vector<opensaml::saml1::Assertion*>& assertions = const_cast<const opensaml::saml1p::Response*>(response)->getAssertions();\r
- if (assertions.size()==1) {\r
- auto_ptr<opensaml::saml1p::Response> wrapper(response);\r
- opensaml::saml1::Assertion* newtoken = assertions.front();\r
- if (!XMLString::equals(policy.getIssuer() ? policy.getIssuer()->getName() : NULL, newtoken->getIssuer())) {\r
- log.error("assertion issued by someone other than AA, rejecting it");\r
- return;\r
- }\r
- try {\r
- tokval->validate(newtoken);\r
- }\r
- catch (exception& ex) {\r
- log.error("assertion failed validation check: %s", ex.what());\r
- }\r
- newtoken->detach();\r
- wrapper.release();\r
- ctx.getResolvedAssertions().push_back(newtoken);\r
- resolve(ctx, newtoken, attributes);\r
+ const vector<saml1::Assertion*>& assertions = const_cast<const saml1p::Response*>(response)->getAssertions();\r
+ if (assertions.size()>1)\r
+ log.warn("simple resolver only supports one assertion in the query response");\r
+\r
+ auto_ptr<saml1p::Response> wrapper(response);\r
+ saml1::Assertion* newtoken = assertions.front();\r
+\r
+ if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {\r
+ log.error("assertion unsigned, rejecting it based on signedAssertions policy");\r
+ return;\r
}\r
- else {\r
- auto_ptr<opensaml::saml1p::Response> wrapper(response);\r
- for (vector<opensaml::saml1::Assertion*>::const_iterator a = assertions.begin(); a!=assertions.end(); ++a) {\r
- if (!XMLString::equals(policy.getIssuer() ? policy.getIssuer()->getName() : NULL, (*a)->getIssuer())) {\r
- log.error("assertion issued by someone other than AA, rejecting it");\r
- continue;\r
- }\r
- try {\r
- tokval->validate(*a);\r
- }\r
- catch (exception& ex) {\r
- log.error("assertion failed validation check: %s", ex.what());\r
+\r
+ try {\r
+ policy.evaluate(*newtoken);\r
+ if (!policy.isSecure())\r
+ throw SecurityPolicyException("Security of SAML 1.x query result not established.");\r
+ saml1::AssertionValidator tokval(ctx.getApplication().getAudiences(), time(NULL));\r
+ tokval.validateAssertion(*newtoken);\r
+ }\r
+ catch (exception& ex) {\r
+ log.error("assertion failed policy/validation: %s", ex.what());\r
+ }\r
+ newtoken->detach();\r
+ wrapper.release();\r
+ ctx.getResolvedAssertions().push_back(newtoken);\r
+ resolve(ctx, newtoken, attributes);\r
+}\r
+\r
+void SimpleResolverImpl::populateQuery(saml1p::AttributeQuery& query, const string& id) const\r
+{\r
+ for (attrmap_t::const_iterator i = m_attrMap.begin(); i!=m_attrMap.end(); ++i) {\r
+ if (i->second.second == id) {\r
+ AttributeDesignator* a = AttributeDesignatorBuilder::buildAttributeDesignator();\r
+#ifdef HAVE_GOOD_STL\r
+ a->setAttributeName(i->first.first.c_str());\r
+ a->setAttributeNamespace(i->first.second.empty() ? shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI : i->first.second.c_str());\r
+#else\r
+ auto_ptr_XMLCh n(i->first.first.c_str());\r
+ a->setAttributeName(n.get());\r
+ if (i->first.second.empty())\r
+ a->setAttributeNamespace(shibspconstants::SHIB1_ATTRIBUTE_NAMESPACE_URI);\r
+ else {\r
+ auto_ptr_XMLCh ns(i->first.second.c_str());\r
+ a->setAttributeNamespace(ns.get());\r
}\r
- resolve(ctx, *a, attributes);\r
- ctx.getResolvedAssertions().push_back((*a)->cloneAssertion());\r
+#endif\r
+ query.getAttributeDesignators().push_back(a);\r
}\r
}\r
}\r
\r
-void SimpleResolverImpl::query(ResolutionContext& ctx, const opensaml::saml2::Assertion* token, const vector<const char*>* attributes) const\r
+void SimpleResolverImpl::query(ResolutionContext& ctx, const NameID& nameid, const set<string>* attributes) const\r
{\r
- if (!m_allowQuery)\r
- return;\r
-\r
#ifdef _DEBUG\r
xmltooling::NDC ndc("query");\r
#endif\r
}\r
const AttributeAuthorityDescriptor* AA = entity->getAttributeAuthorityDescriptor(samlconstants::SAML20P_NS);\r
if (!AA) {\r
- log.debug("no SAML 2 AttributeAuthority role found in metadata");\r
+ log.info("no SAML 2 AttributeAuthority role found in metadata");\r
return;\r
}\r
\r
SecurityPolicy policy;\r
+ MetadataCredentialCriteria mcc(*AA);\r
shibsp::SOAPClient soaper(ctx.getApplication(),policy);\r
+ const PropertySet* policySettings = ctx.getApplication().getServiceProvider().getPolicySettings(ctx.getApplication().getString("policyId").second);\r
+ pair<bool,bool> signedAssertions = policySettings->getBool("signedAssertions");\r
\r
auto_ptr_XMLCh binding(samlconstants::SAML20_BINDING_SOAP);\r
- opensaml::saml2p::StatusResponseType* srt=NULL;\r
+ saml2p::StatusResponseType* srt=NULL;\r
const vector<AttributeService*>& endpoints=AA->getAttributeServices();\r
for (vector<AttributeService*>::const_iterator ep=endpoints.begin(); !srt && ep!=endpoints.end(); ++ep) {\r
try {\r
continue;\r
auto_ptr_char loc((*ep)->getLocation());\r
auto_ptr_XMLCh issuer(ctx.getApplication().getString("providerId").second);\r
- opensaml::saml2::Subject* subject = opensaml::saml2::SubjectBuilder::buildSubject();\r
- subject->setNameID(token->getSubject()->getNameID()->cloneNameID());\r
- opensaml::saml2p::AttributeQuery* query = opensaml::saml2p::AttributeQueryBuilder::buildAttributeQuery();\r
+ saml2::Subject* subject = saml2::SubjectBuilder::buildSubject();\r
+ subject->setNameID(nameid.cloneNameID());\r
+ saml2p::AttributeQuery* query = saml2p::AttributeQueryBuilder::buildAttributeQuery();\r
query->setSubject(subject);\r
Issuer* iss = IssuerBuilder::buildIssuer();\r
query->setIssuer(iss);\r
iss->setName(issuer.get());\r
+ if (attributes) {\r
+ for (set<string>::const_iterator a = attributes->begin(); a!=attributes->end(); ++a)\r
+ populateQuery(*query, *a);\r
+ }\r
+\r
SAML2SOAPClient client(soaper);\r
- client.sendSAML(query, *AA, loc.get());\r
+ client.sendSAML(query, mcc, loc.get());\r
srt = client.receiveSAML();\r
}\r
catch (exception& ex) {\r
log.error("unable to successfully query for attributes");\r
return;\r
}\r
- opensaml::saml2p::Response* response = dynamic_cast<opensaml::saml2p::Response*>(srt);\r
+ saml2p::Response* response = dynamic_cast<saml2p::Response*>(srt);\r
if (!response) {\r
delete srt;\r
log.error("message was not a samlp:Response");\r
return;\r
}\r
\r
- time_t now = time(NULL);\r
- const Validator* tokval = ctx.getApplication().getTokenValidator(now, AA);\r
- const vector<opensaml::saml2::Assertion*>& assertions = const_cast<const opensaml::saml2p::Response*>(response)->getAssertions();\r
- if (assertions.size()==1) {\r
- auto_ptr<opensaml::saml2p::Response> wrapper(response);\r
- opensaml::saml2::Assertion* newtoken = assertions.front();\r
- if (!XMLString::equals(policy.getIssuer() ? policy.getIssuer()->getName() : NULL, newtoken->getIssuer() ? newtoken->getIssuer()->getName() : NULL)) {\r
- log.error("assertion issued by someone other than AA, rejecting it");\r
- return;\r
- }\r
- try {\r
- tokval->validate(newtoken);\r
- }\r
- catch (exception& ex) {\r
- log.error("assertion failed validation check: %s", ex.what());\r
- }\r
- newtoken->detach();\r
- wrapper.release();\r
- ctx.getResolvedAssertions().push_back(newtoken);\r
- resolve(ctx, newtoken, attributes);\r
+ const vector<saml2::Assertion*>& assertions = const_cast<const saml2p::Response*>(response)->getAssertions();\r
+ if (assertions.size()>1)\r
+ log.warn("simple resolver only supports one assertion in the query response");\r
+\r
+ auto_ptr<saml2p::Response> wrapper(response);\r
+ saml2::Assertion* newtoken = assertions.front();\r
+\r
+ if (!newtoken->getSignature() && signedAssertions.first && signedAssertions.second) {\r
+ log.error("assertion unsigned, rejecting it based on signedAssertions policy");\r
+ return;\r
}\r
- else {\r
- auto_ptr<opensaml::saml2p::Response> wrapper(response);\r
- for (vector<opensaml::saml2::Assertion*>::const_iterator a = assertions.begin(); a!=assertions.end(); ++a) {\r
- if (!XMLString::equals(policy.getIssuer() ? policy.getIssuer()->getName() : NULL, (*a)->getIssuer() ? (*a)->getIssuer()->getName() : NULL)) {\r
- log.error("assertion issued by someone other than AA, rejecting it");\r
- return;\r
- }\r
- try {\r
- tokval->validate(*a);\r
- }\r
- catch (exception& ex) {\r
- log.error("assertion failed validation check: %s", ex.what());\r
+\r
+ try {\r
+ policy.evaluate(*newtoken);\r
+ if (!policy.isSecure())\r
+ throw SecurityPolicyException("Security of SAML 2.0 query result not established.");\r
+ saml2::AssertionValidator tokval(ctx.getApplication().getAudiences(), time(NULL));\r
+ tokval.validateAssertion(*newtoken);\r
+ }\r
+ catch (exception& ex) {\r
+ log.error("assertion failed policy/validation: %s", ex.what());\r
+ }\r
+ newtoken->detach();\r
+ wrapper.release();\r
+ ctx.getResolvedAssertions().push_back(newtoken);\r
+ resolve(ctx, newtoken, attributes);\r
+}\r
+\r
+void SimpleResolverImpl::populateQuery(saml2p::AttributeQuery& query, const string& id) const\r
+{\r
+ for (attrmap_t::const_iterator i = m_attrMap.begin(); i!=m_attrMap.end(); ++i) {\r
+ if (i->second.second == id) {\r
+ saml2::Attribute* a = saml2::AttributeBuilder::buildAttribute();\r
+#ifdef HAVE_GOOD_STL\r
+ a->setName(i->first.first.c_str());\r
+ a->setNameFormat(i->first.second.empty() ? saml2::Attribute::URI_REFERENCE : i->first.second.c_str());\r
+#else\r
+ auto_ptr_XMLCh n(i->first.first.c_str());\r
+ a->setName(n.get());\r
+ if (i->first.second.empty())\r
+ a->setNameFormat(saml2::Attribute::URI_REFERENCE);\r
+ else {\r
+ auto_ptr_XMLCh ns(i->first.second.c_str());\r
+ a->setNameFormat(ns.get());\r
}\r
- resolve(ctx, *a, attributes);\r
- ctx.getResolvedAssertions().push_back((*a)->cloneAssertion());\r
+#endif\r
+ query.getAttributes().push_back(a);\r
}\r
}\r
}\r
\r
-void SimpleResolver::resolveAttributes(ResolutionContext& ctx, const vector<const char*>* attributes) const\r
+void SimpleResolver::resolveAttributes(ResolutionContext& ctx, const set<string>* attributes) const\r
{\r
#ifdef _DEBUG\r
xmltooling::NDC ndc("resolveAttributes");\r
#endif\r
Category& log=Category::getInstance(SHIBSP_LOGCAT".AttributeResolver");\r
\r
- log.debug("examining incoming SSO token");\r
-\r
- const opensaml::RootObject* token = ctx.getSSOToken();\r
- if (!token) {\r
- log.warn("no SSO token supplied to resolver, returning nothing");\r
- return;\r
- }\r
- const opensaml::saml2::Assertion* token2 = dynamic_cast<const opensaml::saml2::Assertion*>(token);\r
- if (token2) {\r
- if (!token2->getAttributeStatements().empty()) {\r
- log.debug("found SAML 2 SSO token with an AttributeStatement");\r
- return m_impl->resolve(ctx, token2, attributes);\r
+ log.debug("examining tokens to resolve");\r
+\r
+ bool query = m_impl->m_allowQuery;\r
+ const saml1::Assertion* token1;\r
+ const saml2::Assertion* token2;\r
+ if (ctx.getTokens()) {\r
+ for (vector<const opensaml::Assertion*>::const_iterator t = ctx.getTokens()->begin(); t!=ctx.getTokens()->end(); ++t) {\r
+ token2 = dynamic_cast<const saml2::Assertion*>(*t);\r
+ if (token2 && !token2->getAttributeStatements().empty()) {\r
+ log.debug("resolving SAML 2 token with an AttributeStatement");\r
+ m_impl->resolve(ctx, token2, attributes);\r
+ query = false;\r
+ }\r
+ else {\r
+ token1 = dynamic_cast<const saml1::Assertion*>(*t);\r
+ if (token1 && !token1->getAttributeStatements().empty()) {\r
+ log.debug("resolving SAML 1 token with an AttributeStatement");\r
+ m_impl->resolve(ctx, token1, attributes);\r
+ query = false;\r
+ }\r
+ }\r
}\r
- return m_impl->query(ctx, token2, attributes);\r
}\r
\r
- const opensaml::saml1::Assertion* token1 = dynamic_cast<const opensaml::saml1::Assertion*>(token);\r
- if (token1) {\r
- if (!token1->getAttributeStatements().empty()) {\r
- log.debug("found SAML 1 SSO token with an AttributeStatement");\r
- return m_impl->resolve(ctx, token1, attributes);\r
+ if (query) {\r
+ if (token1 && !token1->getAuthenticationStatements().empty()) {\r
+ const AuthenticationStatement* statement = token1->getAuthenticationStatements().front();\r
+ if (statement && statement->getSubject() && statement->getSubject()->getNameIdentifier()) {\r
+ log.debug("attempting SAML 1.x attribute query");\r
+ return m_impl->query(ctx, *(statement->getSubject()->getNameIdentifier()), attributes);\r
+ }\r
}\r
- return m_impl->query(ctx, token1, attributes);\r
+ else if (token2 && ctx.getNameID()) {\r
+ log.debug("attempting SAML 2.0 attribute query");\r
+ return m_impl->query(ctx, *ctx.getNameID(), attributes);\r
+ }\r
+ log.warn("can't attempt attribute query, no identifier in assertion subject");\r
}\r
-\r
- log.warn("unrecognized token type, returning nothing");\r
}\r
\r
pair<bool,DOMElement*> SimpleResolver::load()\r