Most SAML attribute values are simple string values. For example:
<saml:Attribute Name=“support-email”>
saml:AttributeValuesupport@componentspace.com</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name=“sales-email”>
saml:AttributeValuesales@componentspace.com</saml:AttributeValue>
</saml:Attribute>
However, it’s also possible to specify XML as the SAML attribute value. For example:
<saml:Attribute Name=“email-addresses”>
saml:AttributeValue
support@componentspace.com
sales@componentspace.com
</saml:AttributeValue>
</saml:Attribute>
The following code calls the SAML high-level API and includes an attribute whose value is XML.
var attributes = new Dictionary<string, string>();
var xmlDocument = new XmlDocument();
xmlDocument.PreserveWhitespace = true;
xmlDocument.LoadXml(“support@componentspace.comsales@componentspace.com”);
attributes[“email-addresses”] = xmlDocument.DocumentElement.FirstChild.OuterXml;
SAMLIdentityProvider.SendSSO(Response, userName, attributes);
The equivalent code using the SAML low-level API is:
var attributeStatement = new AttributeStatement();
SAMLAttribute.RegisterAttributeValueSerializer(“email-addresses”, null, new XmlAttributeValueSerializer());
var samlAttribute = new SAMLAttribute(“email-addresses”, null, null);
var xmlDocument = new XmlDocument();
xmlDocument.PreserveWhitespace = true;
xmlDocument.LoadXml(“support@componentspace.comsales@componentspace.com”);
samlAttribute.Values.Add(new AttributeValue(xmlDocument.DocumentElement.FirstChild));
attributeStatement.Attributes.Add(samlAttribute);
<saml:Assertion Version="2.0" ID="12345" IssueInstant="2018-04-28T17:10:44Z"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
Employee1
Department1
Employee2
Department2
1. For this I am generating list in my custom object first from data.
I have class (Custom)as below
public class SAMLModuleAttribute
{
public SAMLModuleAttribute()
{
}
public SAMLModuleAttribute(string attributename, string friendlyname, string attributevalue)
{
this.AttributeName = attributename;
this.FriendlyName = friendlyname;
this.AttributeValue = attributevalue;
}
public string AttributeName { get; set; }
public string FriendlyName { get; set; }
public string AttributeValue { get; set; }
public List AttributeValues { get; set; }
}
Then I am using it to generate below Object structure
var lstAttributes =List();
var samlAttribute = new SAMLModuleAttribute("Employees", "","");
samlAttribute.AttributeValues = new List();
foreach (var employee in employeeList)
{
samlAttribute.AttributeValues.Add(new SAMLModuleAttributeValue
{
Name = "Employee",
Value = "Employee1"
});
samlAttribute.AttributeValues.Add(new SAMLModuleAttributeValue
{
Name = "Department",
Value = "Department1"
});
}
lstAttributes.Add(samlAttribute);
2. Then I am passing it to first fill it in Saml low lecvel api of componenet space using AttributeStatement
AttributeStatement attStatement = new AttributeStatement();
CreateMultiValueSAMLAttributes(lstAttributes,attStatement);
private void CreateMultiValueSAMLAttributes(List lstAttributes, AttributeStatement attStatement)
SAMLAttribute.RegisterAttributeValueSerializer("Employees", null, new XmlAttributeValueSerializer());
foreach (SAMLModuleAttribute attb in lstAttributes)
{
SAMLAttribute attrib = new SAMLAttribute(attb.AttributeName, SAMLIdentifiers.AttributeNameFormats.Basic,
attb.FriendlyName, attb.AttributeValue);
if (attb.AttributeValues != null && attb.AttributeValues.Count > 0)
{
XmlDocument doc = new XmlDocument();
XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration("1.0", "UTF-8", null);
XmlElement root = doc.DocumentElement;
doc.InsertBefore(xmlDeclaration, root);
XmlElement employeeElement = doc.CreateElement(string.Empty, "Employees", string.Empty);
doc.AppendChild(employeeElement);
foreach (var attrinuteValue in attb.AttributeValues)
{
XmlElement attributeValueNode = doc.CreateElement(string.Empty, attrinuteValue.Name, string.Empty);
XmlText attributeValue = doc.CreateTextNode(attrinuteValue.Value);
attributeValueNode.AppendChild(attributeValue);
accountElement.AppendChild(attributeValueNode);
///The Above code will add Xml Strucure like when loop completes Employee1 Department1 Employee2 Department2
// inside parent node
XmlElement employeeNode = doc.CreateElement(string.Empty, "Employee", string.Empty);
XmlText attributeValue = doc.CreateTextNode("Employee1";
employeeNode.AppendChild(attributeValue);
XmlElement deptNode = doc.CreateElement(string.Empty, "Department", string.Empty);
XmlText attributeValue = doc.CreateTextNode("Department1";
deptNode.AppendChild(attributeValue);
}
var xmlDocument = new XmlDocument();
xmldocument.PreserveWhitespace = true;
xmldocument.LoadXml(doc.DocumentElement.OuterXml);
attrib.Values.Add(new AttributeValue(xmldocument.DocumentElement));
}
attStatement.Attributes.Add(attrib);
}
}
And finally I am using To Xml on SamlAssertion to get Saml string from it
SAMLAssertion samlAssertion = new SAMLAssertion();
--code to fill Saml Assertion
samlAssertion.Statements.Add(attStatement);
string samlString= samlAssertion.ToXml().OuterXml.ToString();
But above line generates saml as below
Actual SAMl I am getting
<saml:Assertion Version="2.0" ID="12345" IssueInstant="2018-04-28T17:10:44Z"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
System.Xml.XmlElement
Instead of below which is expected
<saml:Assertion Version="2.0" ID="12345" IssueInstant="2018-04-28T17:10:44Z"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">
Employee1
Department1
Employee2
Department2
It seems it cannot serlize it properly the InnerXml under parent EMployees node and genartes incorrect xml as System.Xml.XmlElement
Can you please help to resolve this.
The following code generates the required XML.
For brevity, it loads the attribute values XML from strings but you can construct these however you wish.
// Employees attribute values are to be serialized as XML.
SAMLAttribute.RegisterAttributeValueSerializer(“Employees”, null, new XmlAttributeValueSerializer());
// Load some test employee records.
var xmlDocument = new XmlDocument()
{
PreserveWhitespace = true
};
xmlDocument.LoadXml(“Employee1Department1”);
var employee1 = xmlDocument.DocumentElement.ChildNodes;
xmlDocument.LoadXml(“Employee2Department2”);
var employee2 = xmlDocument.DocumentElement.ChildNodes;
// Create the example SAML assertion.
var samlAssertion = new SAMLAssertion();
samlAssertion.Statements.Add(new AttributeStatement()
{
Attributes = new ArrayList()
{
new SAMLAttribute()
{
Name = “Employees”,
FriendlyName = “Employees”,
NameFormat = SAMLIdentifiers.AttributeNameFormats.Basic,
Values = new List()
{
new AttributeValue()
{
Data = employee1
},
new AttributeValue()
{
Data = employee2
}
}
}
}
});
// Serialize the SAMl assertion to an XML string.
var xmlText = samlAssertion.ToString();
For brevity, it loads the attribute values XML from strings but you can construct these however you wish.
// Employees attribute values are to be serialized as XML.
SAMLAttribute.RegisterAttributeValueSerializer("Employees", null, new XmlAttributeValueSerializer());
// Load some test employee records.
var xmlDocument = new XmlDocument()
{
PreserveWhitespace = true
};
xmldocument.LoadXml("Employee1Department1");
var employee1 = xmldocument.DocumentElement.ChildNodes;
xmldocument.LoadXml("Employee2Department2");
var employee2 = xmldocument.DocumentElement.ChildNodes;
// Create the example SAML assertion.
var samlAssertion = new SAMLAssertion();
samlAssertion.Statements.Add(new AttributeStatement()
{
Attributes = new ArrayList()
{
new SAMLAttribute()
{
Name = "Employees",
FriendlyName = "Employees",
NameFormat = SAMLIdentifiers.AttributeNameFormats.Basic,
Values = new List()
{
new AttributeValue()
{
Data = employee1
},
new AttributeValue()
{
Data = employee2
}
}
}
}
});
// Serialize the SAMl assertion to an XML string.
var xmlText = samlAssertion.ToString();
Hi Mitchell ,
I tried it but the last line var xmlText = samlAssertion.ToString(); gives me output ComponentSpace.SAML2.Assertions.SAMLAssertion.
And when I tried samlAssertion.ToXml() or samlAssertion.ToXml().OuterXml it gives below exception during Serlization
"Unable to cast object of type 'System.Xml.XmlChildNodes' to type 'System.Xml.XmlElement'."}System.Exception {System.InvalidCastException
'samlAssertion.ToXml()' threw an exception of type 'ComponentSpace.SAML2.SAMLSerializationException'
It seems it cannot serilize it properly.
If you run the code you shared you will get the above output i.e.
xmlText = samlAssertion.ToString(); gives me output ComponentSpace.SAML2.Assertions.SAMLAssertion.
And
xmlText = samlAssertion.ToXml(); gives exception
"Unable to cast object of type 'System.Xml.XmlChildNodes' to type 'System.Xml.XmlElement'."}System.Exception {System.InvalidCastException
Please help me to resolve this.
Thanks,
Amol
What version of the product are you using?
https://www.componentspace.com/Forums/31/Determining-the-Component-Version-and-License
https://www.componentspace.com/Forums/31/Determining-the-Component-Version-and-License
I am using 2.1.0.4
That version is almost 10 years old.
You should upgrade to pick up the latest functionality.
https://www.componentspace.com/documentation/saml-for-asp-net/ComponentSpace%20SAML%20for%20ASP.NET%20Release%20Notes.pdf