Need to add Extensions to AuthnRequest

Hi,

I am rewriting SP-initiated SSO from a another project which is ASP.NET Core app. In there we used:

_samlServiceProvider.OnAuthnRequestCreated += OnAuthRequestCreated;

private AuthnRequest OnAuthRequestCreated(AuthnRequest arg)
{
arg.Extensions = _extensionFactory.Generate(arg); // we generate needed extensions
return arg;
}

We used OnAuthRequestCreated event to add needed data to AuthnRequest.Extensions. I need something similar in SAML for .NET (for ASP.NET MVC). How and where do I edit AuthnRequest and add Extensions in High Level API? Thank you in advance.


Below is some example code demonstrating using the ISAMLObserver interface to update the SAML authn request with extensions data.


using ComponentSpace.SAML2.Notifications;
using ComponentSpace.SAML2.Protocols;

public class SAMLObserver : AbstractSAMLObserver
{
public override AuthnRequest OnAuthnRequestCreated(AuthnRequest authnRequest)
{
var xmlDocument = new XmlDocument();
xmlDocument.LoadXml(“”);

authnRequest.Extensions = new Extensions()
{
Data = xmlDocument.ChildNodes
};

return authnRequest;
}
}



You need to subscribe to events, for example, at application start-up in Global.asax.


protected void Application_Start()
{
SAMLObservable.Subscribe(new SAMLObserver());
}


The OnAuthnRequestCreated will be called whenever a SAML authn request has been created. It’s your opportunity to update the authn request.
There are no changes required to the code where you call SAMLServiceProvider.InitiateSSO.

Wonderful. Thank you for quick and most helpful reply.

Best regards

You’re welcome.

I have a follow up question. If I had this code in ASP.NET Core version:

var items = new List();
// here I create 2 extensions which are then encrypted into a EncryptedExtensions object
_creator.HandleRequest(items, arg);
// now there is only 1 item in items List (the EncryptedExtension object)
authnRequest.Extensions = new Extensions(items); // this is then sent in SAML request

How would rewrite this part in ASP.NET MVC application? I am asking, because I am experiencing some problems when sending the SAML request, and it returns this error:
ComponentSpace.SAML2.Exceptions.SAMLErrorStatusException: ‘An error SAML response status was received. urn:oasis:names:tc:SAML:2.0:status:Requester: Error parsing request extensions’

Since the constructor for ASP.NET MVC version of SAML library expects XmlNodeList and not List like the Core version, I am not sure how to pass my EncryptedExtensions object into authnRequest.Extensions.

Thank you for your help.




If you’ve serialized your extensions to an XmlElement and this is the document element, you should be able to use the XmlDocument.ChildNodes property.


authnRequest.Extensions = new Extensions()
{
Data = xmlDocument.ChildNodes
};


If there’s still an issue, please enable SAML trace and send the generated log file as an email attachment to support@componentspace.com mentioning your forum post.
https://www.componentspace.com/Forums/17/Enabing-SAML-Trace
Also include a section of your code where you’re setting the extension.
Check with the identity provider to see if they have more specific error information in their logs.

In ASP.NET Core version, I am instancing a new Extensions() object providing List which only includes EncryptedExtensions object of XmlElement type:
var items = new List();
XmlElement encryptedExtensions = … generating the XmlElement …
items.Add(encryptedExtensions);
authnRequest.Extensions = new Extensions(items);


And now in ASP.NET MVC I have the same XmlElement encryptedExtensions and I am not sure how to pass it to Extensions constructor, since it’s expecting XmlNodeList object. I tried these 2 things:

1) passing directly encryptedExtensions to Extensions constructor:
XmlElement encryptedExtensions = … generating the XmlElement …
authnRequest.Extensions = new Extensions(encryptedExtensions); // throws this exception right here - ComponentSpace.SAML2.Exceptions.SAMLSerializationException: ‘The XML is not an Extensions.’


2) appending encryptedExtensions into xmlDocument and passing that
XmlElement encryptedExtensions = … generating the XmlElement …
xmldocument.AppendChild(encryptedExtensions);
authnRequest.Extensions = new Extensions() { Data = xmldocument.ChildNodes };
// this throws exception when I try SAMLServiceProvider.ReceiveSSO() - ComponentSpace.SAML2.Exceptions.SAMLErrorStatusException: ‘An error SAML response status was received. urn:oasis:names:tc:SAML:2.0:status:Requester: Error parsing request extensions’



It’s the point 2 code you should use.
Please enable SAML trace and send the generated log file to support@componentspace.com as an email attachment.
https://www.componentspace.com/Forums/17/Enabing-SAML-Trace
I can validate whether the XML looks ok.
If it does, you’ll have to ask the IdP for the specific information as to why they can’t parse the extensions.

I sent the log file over email. Thank you again for your help.

Thanks for the log.
I copied the SAML authn request from the log and ran our ValidateAgainstSchema console app that validates the XML against the SAML XML schemas.
The ValidateAgainstSchema project is under the Examples\Utility folder.


ValidateAgainstSchema.exe authnrequest.xml
Loading authnrequest.xml
Validating against XML schemas
Validated: False
The element ‘Extensions’ in namespace ‘urn:oasis:names:tc:SAML:2.0:protocol’ has invalid child element ‘EncryptedExtensions’. List of possible elements expected: any element in namespace ‘##other’.
Elapsed time: 146.3557 ms


The issue is that the XML schema expects the EncryptedExtensions to be under a namespace.
If you updated your EncryptedExtensions to specify a namespace declaration (eg ), the XML validates against the schema.
Of course, you would still have to confirm with the IdP what namespace it expects for the EncryptedExtensions element.

[quote]
ComponentSpace - 3/6/2019
Below is some example code demonstrating using the ISAMLObserver interface to update the SAML authn request with extensions data.


using ComponentSpace.SAML2.Notifications;
using ComponentSpace.SAML2.Protocols;

public class SAMLObserver : AbstractSAMLObserver
{
public override AuthnRequest OnAuthnRequestCreated(AuthnRequest authnRequest)
{
var xmlDocument = new XmlDocument();
xmldocument.LoadXml("");

authnRequest.Extensions = new Extensions()
{
Data = xmldocument.ChildNodes
};

return authnRequest;
}
}



You need to subscribe to events, for example, at application start-up in Global.asax.


protected void Application_Start()
{
SAMLObservable.Subscribe(new SAMLObserver());
}


The OnAuthnRequestCreated will be called whenever a SAML authn request has been created. It’s your opportunity to update the authn request.
There are no changes required to the code where you call SAMLServiceProvider.InitiateSSO.
[/quote]

Hello,
I'm evaluating your products and I need to understand how to add some custom attribute to a SAML Request (for example the attribute AttributeConsumingServiceIndex).
After some readings I understand that I have to ovverride a SAMLObserver. Can you provide an example in .NET Core 3.1 to set this item?

Regards
Erik

Hi Erik,

Please note that this topic refers to SAML for ASP.NET rather than SAML for ASP.NET Core. A better approach when using SAML for ASP.NET Core is to hook into the OnAuthnRequestCreated event and set the AttributeConsumingServiceIndex property as shown in the following example.


// Set the AttributeConsumingServiceIndex in the authn request.
_samlServiceProvider.Events.OnAuthnRequestCreated += (httpContext, authnRequest) =>
{
authnRequest.AssertionConsumerServiceIndex = 1;

return authnRequest;
};

// Initiate single sign-on to the identity provider (SP-initiated SSO).
var partnerName = _configuration[“PartnerName”];

await _samlServiceProvider.InitiateSsoAsync(partnerName);


[quote]
ComponentSpace - 2/15/2021
Hi Erik,

Please note that this topic refers to SAML for ASP.NET rather than SAML for ASP.NET Core. A better approach when using SAML for ASP.NET Core is to hook into the OnAuthnRequestCreated event and set the AttributeConsumingServiceIndex property as shown in the following example.


// Set the AttributeConsumingServiceIndex in the authn request.
_samlServiceProvider.Events.OnAuthnRequestCreated += (httpContext, authnRequest) =>
{
authnRequest.AssertionConsumerServiceIndex = 1;

return authnRequest;
};

// Initiate single sign-on to the identity provider (SP-initiated SSO).
var partnerName = _configuration["PartnerName"];

await _samlServiceProvider.InitiateSsoAsync(partnerName);


[/quote]

Hi,
excuse me for the wrong topic.
Thank you for the reply, now I am able to set this attribute.

Regards
Erik

Not a problem. You’re very welcome.