<minLength value="1"/>
</restriction>
</simpleType>
+
+ <simpleType name="listOfStrings">
+ <list itemType="am:string"/>
+ </simpleType>
<element name="Attributes">
<annotation>
<documentation>The internal attribute ID to which this SAML attribute maps.</documentation>
</annotation>
</attribute>
+ <attribute name="aliases" type="am:listOfStrings">
+ <annotation>
+ <documentation>Optional aliases for the internal attribute to which this SAML attribute maps.</documentation>
+ </annotation>
+ </attribute>
<attribute name="name" type="am:string" use="required">
<annotation>
<documentation>The SAML 1 AttributeName or SAML 2 Name of the attribute.</documentation>
/**
* Constructor
*
- * @param id Attribute identifier
+ * @param ids array with primary identifier in first position, followed by any aliases
*/
- Attribute(const char* id) : m_id(id ? id : ""), m_caseSensitive(true) {
+ Attribute(const std::vector<std::string>& ids) : m_id(ids), m_caseSensitive(true) {
}
/**
Attribute(DDF& in) : m_caseSensitive(in["case_insensitive"].isnull()) {
const char* id = in.first().name();
if (id && *id)
- m_id = id;
+ m_id.push_back(id);
else
throw AttributeException("No id found in marshalled attribute content.");
+ DDF aliases = in["aliases"];
+ if (aliases.islist()) {
+ DDF alias = aliases.first();
+ while (alias.isstring()) {
+ m_id.push_back(alias.string());
+ alias = aliases.next();
+ }
+ }
}
-
/**
* Maintains a copy of serialized attribute values, when possible.
*
/**
* Returns the Attribute identifier.
*
- * @return Attribute identifier
+ * @return the Attribute identifier
*/
const char* getId() const {
- return m_id.c_str();
+ return m_id.front().c_str();
+ }
+
+ /**
+ * Returns all of the effective names for the Attribute.
+ *
+ * @return immutable array of identifiers, with the primary ID in the first position
+ */
+ const std::vector<std::string>& getAliases() const {
+ return m_id;
}
/**
*/
virtual DDF marshall() const {
DDF ddf(NULL);
- ddf.structure().addmember(m_id.c_str()).list();
+ ddf.structure().addmember(m_id.front().c_str()).list();
if (!m_caseSensitive)
ddf.addmember("case_insensitive");
+ if (m_id.size() > 1) {
+ DDF alias;
+ DDF aliases = ddf.addmember("aliases").list();
+ for (std::vector<std::string>::const_iterator a = m_id.begin() + 1; a != m_id.end(); ++a) {
+ alias = DDF(NULL).string(a->c_str());
+ aliases.add(alias);
+ }
+ }
return ddf;
}
private:
static std::map<std::string,AttributeFactory*> m_factoryMap;
- std::string m_id;
+ std::vector<std::string> m_id;
bool m_caseSensitive;
};
/**
* Decodes an XMLObject into a resolved Attribute.
*
- * @param id ID of resolved attribute
+ * @param ids array containing primary identifier in first position, followed by any aliases
* @param xmlObject XMLObject to decode
* @param assertingParty name of the party asserting the attribute
* @param relyingParty name of the party relying on the attribute
* @return a resolved Attribute, or NULL
*/
virtual Attribute* decode(
- const char* id, const xmltooling::XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL
+ const std::vector<std::string>& ids,
+ const xmltooling::XMLObject* xmlObject,
+ const char* assertingParty=NULL,
+ const char* relyingParty=NULL
) const=0;
};
{
public:
/**
- * Constructor
+ * Constructor.
*
- * @param id Attribute identifier
+ * @param ids array with primary identifier in first position, followed by any aliases
*/
- NameIDAttribute(const char* id, const char* formatter=DEFAULT_NAMEID_FORMATTER)
- : Attribute(id), m_formatter(formatter) {
+ NameIDAttribute(const std::vector<std::string>& ids, const char* formatter=DEFAULT_NAMEID_FORMATTER)
+ : Attribute(ids), m_formatter(formatter) {
}
/**
~NameIDAttributeDecoder() {}\r
\r
shibsp::Attribute* decode(\r
- const char* id, const XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL\r
+ const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL\r
) const;\r
\r
private:\r
};\r
\r
shibsp::Attribute* NameIDAttributeDecoder::decode(\r
- const char* id, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty\r
+ const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty\r
) const\r
{\r
auto_ptr<NameIDAttribute> nameid(\r
- new NameIDAttribute(id, (m_formatter.get() && *m_formatter.get()) ? m_formatter.get() : DEFAULT_NAMEID_FORMATTER)\r
+ new NameIDAttribute(ids, (m_formatter.get() && *m_formatter.get()) ? m_formatter.get() : DEFAULT_NAMEID_FORMATTER)\r
);\r
nameid->setCaseSensitive(m_caseSensitive);\r
vector<NameIDAttribute::Value>& dest = nameid->getValues();\r
stop = values.end();\r
if (log.isDebugEnabled()) {\r
auto_ptr_char n(saml2attr->getName());\r
- log.debug("decoding NameIDAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)", id, n.get() ? n.get() : "unnamed", values.size());\r
+ log.debug(\r
+ "decoding NameIDAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)",\r
+ ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()\r
+ );\r
}\r
}\r
else {\r
stop = values.end();\r
if (log.isDebugEnabled()) {\r
auto_ptr_char n(saml1attr->getAttributeName());\r
- log.debug("decoding NameIDAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)", id, n.get() ? n.get() : "unnamed", values.size());\r
+ log.debug(\r
+ "decoding NameIDAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)",\r
+ ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()\r
+ );\r
}\r
}\r
else {\r
if (saml2name) {\r
if (log.isDebugEnabled()) {\r
auto_ptr_char f(saml2name->getFormat());\r
- log.debug("decoding NameIDAttribute (%s) from SAML 2 NameID with Format (%s)", id, f.get() ? f.get() : "unspecified");\r
+ log.debug("decoding NameIDAttribute (%s) from SAML 2 NameID with Format (%s)", ids.front().c_str(), f.get() ? f.get() : "unspecified");\r
}\r
extract(saml2name, dest);\r
}\r
if (saml1name) {\r
if (log.isDebugEnabled()) {\r
auto_ptr_char f(saml1name->getFormat());\r
- log.debug("decoding NameIDAttribute (%s) from SAML 1 NameIdentifier with Format (%s)", id, f.get() ? f.get() : "unspecified");\r
+ log.debug(\r
+ "decoding NameIDAttribute (%s) from SAML 1 NameIdentifier with Format (%s)",\r
+ ids.front().c_str(), f.get() ? f.get() : "unspecified"\r
+ );\r
}\r
extract(saml1name, dest);\r
}\r
{
public:
/**
- * Constructor
+ * Constructor.
*
- * @param id Attribute identifier
+ * @param ids array with primary identifier in first position, followed by any aliases
* @param delimeter value/scope delimeter when serializing
*/
- ScopedAttribute(const char* id, char delimeter='@') : Attribute(id), m_delimeter(delimeter) {}
+ ScopedAttribute(const std::vector<std::string>& ids, char delimeter='@')
+ : Attribute(ids), m_delimeter(delimeter) {
+ }
/**
* Constructs based on a remoted ScopedAttribute.
~ScopedAttributeDecoder() {}\r
\r
shibsp::Attribute* decode(\r
- const char* id, const XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL\r
+ const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL\r
) const;\r
\r
private:\r
};\r
\r
shibsp::Attribute* ScopedAttributeDecoder::decode(\r
- const char* id, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty\r
+ const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty\r
) const\r
{\r
char* val;\r
char* scope;\r
const XMLCh* xmlscope;\r
QName scopeqname(NULL,Scope);\r
- auto_ptr<ScopedAttribute> scoped(new ScopedAttribute(id,m_delimeter));\r
+ auto_ptr<ScopedAttribute> scoped(new ScopedAttribute(ids, m_delimeter));\r
scoped->setCaseSensitive(m_caseSensitive);\r
vector< pair<string,string> >& dest = scoped->getValues();\r
vector<XMLObject*>::const_iterator v,stop;\r
stop = values.end();\r
if (log.isDebugEnabled()) {\r
auto_ptr_char n(saml2attr->getName());\r
- log.debug("decoding ScopedAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)", id, n.get() ? n.get() : "unnamed", values.size());\r
+ log.debug(\r
+ "decoding ScopedAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)",\r
+ ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()\r
+ );\r
}\r
}\r
else {\r
stop = values.end();\r
if (log.isDebugEnabled()) {\r
auto_ptr_char n(saml1attr->getAttributeName());\r
- log.debug("decoding ScopedAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)", id, n.get() ? n.get() : "unnamed", values.size());\r
+ log.debug(\r
+ "decoding ScopedAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)",\r
+ ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()\r
+ );\r
}\r
}\r
else {\r
if (saml2name) {\r
if (log.isDebugEnabled()) {\r
auto_ptr_char f(saml2name->getFormat());\r
- log.debug("decoding ScopedAttribute (%s) from SAML 2 NameID with Format (%s)", id, f.get() ? f.get() : "unspecified");\r
+ log.debug("decoding ScopedAttribute (%s) from SAML 2 NameID with Format (%s)", ids.front().c_str(), f.get() ? f.get() : "unspecified");\r
}\r
val = toUTF8(saml2name->getName());\r
}\r
if (saml1name) {\r
if (log.isDebugEnabled()) {\r
auto_ptr_char f(saml1name->getFormat());\r
- log.debug("decoding ScopedAttribute (%s) from SAML 1 NameIdentifier with Format (%s)", id, f.get() ? f.get() : "unspecified");\r
+ log.debug(\r
+ "decoding ScopedAttribute (%s) from SAML 1 NameIdentifier with Format (%s)",\r
+ ids.front().c_str(), f.get() ? f.get() : "unspecified"\r
+ );\r
}\r
val = toUTF8(saml1name->getName());\r
}\r
{
public:
/**
- * Constructor
+ * Constructor.
*
- * @param id Attribute identifier
+ * @param ids array with primary identifier in first position, followed by any aliases
*/
- SimpleAttribute(const char* id) : Attribute(id) {}
+ SimpleAttribute(const std::vector<std::string>& ids) : Attribute(ids) {}
/**
* Constructs based on a remoted SimpleAttribute.
~StringAttributeDecoder() {}\r
\r
shibsp::Attribute* decode(\r
- const char* id, const XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL\r
+ const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty=NULL, const char* relyingParty=NULL\r
) const;\r
};\r
\r
};\r
\r
shibsp::Attribute* StringAttributeDecoder::decode(\r
- const char* id, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty\r
+ const vector<string>& ids, const XMLObject* xmlObject, const char* assertingParty, const char* relyingParty\r
) const\r
{\r
char* val;\r
- auto_ptr<SimpleAttribute> simple(new SimpleAttribute(id));\r
+ auto_ptr<SimpleAttribute> simple(new SimpleAttribute(ids));\r
simple->setCaseSensitive(m_caseSensitive);\r
vector<string>& dest = simple->getValues();\r
vector<XMLObject*>::const_iterator v,stop;\r
stop = values.end();\r
if (log.isDebugEnabled()) {\r
auto_ptr_char n(saml2attr->getName());\r
- log.debug("decoding SimpleAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)", id, n.get() ? n.get() : "unnamed", values.size());\r
+ log.debug(\r
+ "decoding SimpleAttribute (%s) from SAML 2 Attribute (%s) with %lu value(s)",\r
+ ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()\r
+ );\r
}\r
}\r
else {\r
stop = values.end();\r
if (log.isDebugEnabled()) {\r
auto_ptr_char n(saml1attr->getAttributeName());\r
- log.debug("decoding SimpleAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)", id, n.get() ? n.get() : "unnamed", values.size());\r
+ log.debug(\r
+ "decoding SimpleAttribute (%s) from SAML 1 Attribute (%s) with %lu value(s)",\r
+ ids.front().c_str(), n.get() ? n.get() : "unnamed", values.size()\r
+ );\r
}\r
}\r
else {\r
if (saml2name) {\r
if (log.isDebugEnabled()) {\r
auto_ptr_char f(saml2name->getFormat());\r
- log.debug("decoding SimpleAttribute (%s) from SAML 2 NameID with Format (%s)", id, f.get() ? f.get() : "unspecified");\r
+ log.debug("decoding SimpleAttribute (%s) from SAML 2 NameID with Format (%s)", ids.front().c_str(), f.get() ? f.get() : "unspecified");\r
}\r
val = toUTF8(saml2name->getName());\r
}\r
if (saml1name) {\r
if (log.isDebugEnabled()) {\r
auto_ptr_char f(saml1name->getFormat());\r
- log.debug("decoding SimpleAttribute (%s) from SAML 1 NameIdentifier with Format (%s)", id, f.get() ? f.get() : "unspecified");\r
+ log.debug(\r
+ "decoding SimpleAttribute (%s) from SAML 1 NameIdentifier with Format (%s)",\r
+ ids.front().c_str(), f.get() ? f.get() : "unspecified"\r
+ );\r
}\r
val = toUTF8(saml1name->getName());\r
}\r
Category& m_log;
DOMDocument* m_document;
#ifdef HAVE_GOOD_STL
- typedef map< pair<xstring,xstring>,pair<AttributeDecoder*,string> > attrmap_t;
+ typedef map< pair<xstring,xstring>,pair< AttributeDecoder*,vector<string> > > attrmap_t;
#else
- typedef map< pair<string,string>,pair<AttributeDecoder*,string> > attrmap_t;
+ typedef map< pair<string,string>,pair< AttributeDecoder*,vector<string> > > attrmap_t;
#endif
attrmap_t m_attrMap;
vector<string> m_attributeIds;
static const XMLCh _AttributeDecoder[] = UNICODE_LITERAL_16(A,t,t,r,i,b,u,t,e,D,e,c,o,d,e,r);
static const XMLCh Attributes[] = UNICODE_LITERAL_10(A,t,t,r,i,b,u,t,e,s);
static const XMLCh _id[] = UNICODE_LITERAL_2(i,d);
+ static const XMLCh _aliases[] = UNICODE_LITERAL_7(a,l,i,a,s,e,s);
static const XMLCh _name[] = UNICODE_LITERAL_4(n,a,m,e);
static const XMLCh nameFormat[] = UNICODE_LITERAL_10(n,a,m,e,F,o,r,m,a,t);
};
// Fetch/create the map entry and see if it's a duplicate rule.
#ifdef HAVE_GOOD_STL
- pair<AttributeDecoder*,string>& decl = m_attrMap[make_pair(name,format)];
+ pair< AttributeDecoder*,vector<string> >& decl = m_attrMap[make_pair(name,format)];
#else
auto_ptr_char n(name);
auto_ptr_char f(format);
- pair<AttributeDecoder*,string>& decl = m_attrMap[make_pair(n.get(),f.get())];
+ pair< AttributeDecoder*,vector<string> >& decl = m_attrMap[make_pair(n.get(),f.get())];
#endif
if (decl.first) {
m_log.warn("skipping duplicate Attribute mapping (same name and nameFormat)");
}
decl.first = decoder;
- decl.second = id.get();
+ decl.second.push_back(id.get());
m_attributeIds.push_back(id.get());
+
+ name = child->getAttributeNS(NULL, _aliases);
+ if (name && *name) {
+ auto_ptr_char aliases(name);
+ char* pos;
+ char* start = const_cast<char*>(aliases.get());
+ while (start && *start) {
+ while (*start && isspace(*start))
+ start++;
+ if (!*start)
+ break;
+ pos = strchr(start,' ');
+ if (pos)
+ *pos=0;
+ if (strcmp(start, "REMOTE_USER")) {
+ decl.second.push_back(start);
+ m_attributeIds.push_back(start);
+ }
+ else {
+ m_log.warn("skipping alias, REMOTE_USER is a reserved name");
+ }
+ start = pos ? pos+1 : NULL;
+ }
+ }
child = XMLHelper::getNextSiblingElement(child, shibspconstants::SHIB2ATTRIBUTEMAP_NS, saml1::Attribute::LOCAL_NAME);
}
) const
{
#ifdef HAVE_GOOD_STL
- map< pair<xstring,xstring>,pair<AttributeDecoder*,string> >::const_iterator rule;
+ map< pair<xstring,xstring>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
#else
- map< pair<string,string>,pair<AttributeDecoder*,string> >::const_iterator rule;
+ map< pair<string,string>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
#endif
const XMLCh* format = nameid.getFormat();
auto_ptr_char temp(format);
if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {
#endif
- Attribute* a = rule->second.first->decode(rule->second.second.c_str(), &nameid, assertingParty, application.getString("entityID").second);
+ Attribute* a = rule->second.first->decode(rule->second.second, &nameid, assertingParty, application.getString("entityID").second);
if (a)
attributes.push_back(a);
}
) const
{
#ifdef HAVE_GOOD_STL
- map< pair<xstring,xstring>,pair<AttributeDecoder*,string> >::const_iterator rule;
+ map< pair<xstring,xstring>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
#else
- map< pair<string,string>,pair<AttributeDecoder*,string> >::const_iterator rule;
+ map< pair<string,string>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
#endif
const XMLCh* format = nameid.getFormat();
auto_ptr_char temp(format);
if ((rule=m_attrMap.find(make_pair(temp.get(),string()))) != m_attrMap.end()) {
#endif
- Attribute* a = rule->second.first->decode(rule->second.second.c_str(), &nameid, assertingParty, application.getString("entityID").second);
+ Attribute* a = rule->second.first->decode(rule->second.second, &nameid, assertingParty, application.getString("entityID").second);
if (a)
attributes.push_back(a);
}
) const
{
#ifdef HAVE_GOOD_STL
- map< pair<xstring,xstring>,pair<AttributeDecoder*,string> >::const_iterator rule;
+ map< pair<xstring,xstring>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
#else
- map< pair<string,string>,pair<AttributeDecoder*,string> >::const_iterator rule;
+ map< pair<string,string>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
#endif
const XMLCh* name = attr.getAttributeName();
auto_ptr_char temp2(format);
if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {
#endif
- Attribute* a = rule->second.first->decode(rule->second.second.c_str(), &attr, assertingParty, application.getString("entityID").second);
+ Attribute* a = rule->second.first->decode(rule->second.second, &attr, assertingParty, application.getString("entityID").second);
if (a)
attributes.push_back(a);
}
) const
{
#ifdef HAVE_GOOD_STL
- map< pair<xstring,xstring>,pair<AttributeDecoder*,string> >::const_iterator rule;
+ map< pair<xstring,xstring>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
#else
- map< pair<string,string>,pair<AttributeDecoder*,string> >::const_iterator rule;
+ map< pair<string,string>,pair< AttributeDecoder*,vector<string> > >::const_iterator rule;
#endif
const XMLCh* name = attr.getName();
auto_ptr_char temp2(format);
if ((rule=m_attrMap.find(make_pair(temp1.get(),temp2.get()))) != m_attrMap.end()) {
#endif
- Attribute* a = rule->second.first->decode(rule->second.second.c_str(), &attr, assertingParty, application.getString("entityID").second);
+ Attribute* a = rule->second.first->decode(rule->second.second, &attr, assertingParty, application.getString("entityID").second);
if (a)
attributes.push_back(a);
}
return m_attributes;\r
}\r
const multimap<string,const Attribute*>& getIndexedAttributes() const {\r
- if (m_attributes.empty())\r
- unmarshallAttributes();\r
+ if (m_attributeIndex.empty()) {\r
+ if (m_attributes.empty())\r
+ unmarshallAttributes();\r
+ for (vector<Attribute*>::const_iterator a = m_attributes.begin(); a != m_attributes.end(); ++a) {\r
+ const vector<string>& aliases = (*a)->getAliases();\r
+ for (vector<string>::const_iterator alias = aliases.begin(); alias != aliases.end(); ++alias)\r
+ m_attributeIndex.insert(make_pair(*alias, *a));\r
+ }\r
+ }\r
return m_attributeIndex;\r
}\r
const vector<const char*>& getAssertionIDs() const {\r
try {\r
attribute = Attribute::unmarshall(attr);\r
m_attributes.push_back(attribute);\r
- m_attributeIndex.insert(make_pair(attribute->getId(),attribute));\r
if (m_cache->m_log.isDebugEnabled())\r
m_cache->m_log.debug("unmarshalled attribute (ID: %s) with %d value%s",\r
attribute->getId(), attr.first().integer(), attr.first().integer()!=1 ? "s" : "");\r
return m_attributes;
}
const multimap<string,const Attribute*>& getIndexedAttributes() const {
- if (m_attributes.empty())
- unmarshallAttributes();
- return m_attributeIndex;
+ if (m_attributeIndex.empty()) {\r
+ if (m_attributes.empty())\r
+ unmarshallAttributes();\r
+ for (vector<Attribute*>::const_iterator a = m_attributes.begin(); a != m_attributes.end(); ++a) {\r
+ const vector<string>& aliases = (*a)->getAliases();\r
+ for (vector<string>::const_iterator alias = aliases.begin(); alias != aliases.end(); ++alias)\r
+ m_attributeIndex.insert(make_pair(*alias, *a));\r
+ }\r
+ }\r
+ return m_attributeIndex;\r
}
const vector<const char*>& getAssertionIDs() const {
if (m_ids.empty()) {