Using SAML 2.0 library in a self-hosted ServiceStack application

We are currently evaluating the ComponentSpace libraries as a possible solution to add SAML v1.1 and v2.0 service provider functionality to our existing application. Our application is written on top of ServiceStack, which does not use the System.Web request and response classes (HttpRequest, HttpRequestBase, and so on). Implementing SAML v1.1 was pretty straight forward since I could parse the SAML responses and artifacts from the request myself and use those directly with the ComponentSpace API.

Looking into the SAML v2.0 API however seems to indicate that it is highly reliant on the original System.Web request objects. For example all of the SAMLServiceProvider methods for initiating or receiving SSO requests require an HttpRequest/HttpRequestBase or HttpResponse/HttpResponseBase object as the first parameter. As I mentioned, these are unavailable to us in a self-hosted ServiceStack application. ServiceStack provides its own abstractions to the Request and Response data which we can parse and manipulate manually as needed, but I don’t see any way to use that in conjunction with the ComponentSpace SAML v2.0 API. Are there lower-level methods in the API that I’ve missed which would allow us to parse the required data from requests manually, or is the ComponentSpace library incompatible with hosting frameworks that do not use the System.Web classes?

Thanks for your help!

Please contact support@componentspace.com mentioning this topic.
We are currently implementing changes that should support your requirements but it would be good to exchange emails to go into the specifics.

We too are evaluating the library and have exactly the same issue but with ASP.NET vNext. The next version of ASP.NET has no dependency on System.Web as it uses OWIN. We’d prefer you made an API or layered on an MVC library that returns a ActionResult instead of writing directly to HttpResponse.

In any case, we’d like to know what you have planned as more people will be hitting this issue.

Luke

I’ll just share that I was eventually able to get ComponentSpace working with ServiceStack by creating my own implementations of HttpRequestBase and HttpResponseBase that simply proxies a few relevant methods to an instance of ServiceStack’s request or response object, then using those with the ComponentSpace library. It’s an inelegant solution, but works well enough.

We plan to introduce a version that will remove the System.Web dependencies. At this stage I can’t give a commitment to when this will be available but it’s high on our priority list.
In the meantime, the best option is to extend the HttpRequestBase and HttpResponseBase classes.
You’ll find under the ComponentSpace.SAML2.Utility namespace SAMLHttpRequest, SAMLHttpResponse etc classes which extend HttpRequestBase, HttpResponseBase etc. These classes may meet your requirements. If not then simply extend HttpRequestBase and HttpResponseBase.

Thanks for updating the thread!!

For us, this (what Rudism said) won’t work since subclassing HttpResponseBase will mean having to maintain a dependency on System.Web, though we could add that dependency back in, in vNext, and subclass and build our own requests and responses from OWIN pipeline information (I’d expect someone will have already written something to do this, by then).

Has there been any update on this front? It’s two years old but I have a need for this as well.

The recommendation is to use the SAMLHttpRequest and SAMLHttpResponse classes in the ComponentSpace.SAML2.Utility namespace.
These do not remove the dependency on System.Web but are adapter/wrapper classes that may be used to support ServiceStack and other frameworks.
The dependency on System.Web has been removed with the SAML v2.0 .NET standard library that we released earlier this year for ASP.NET Core.
It’s less likely now that we will remove the System.Web dependency from our SAML v2.0 .NET framework class library although, as always, that’s driven by customer demand.

[quote]
ComponentSpace - 10/15/2017
The recommendation is to use the SAMLHttpRequest and SAMLHttpResponse classes in the ComponentSpace.SAML2.Utility namespace.
These do not remove the dependency on System.Web but are adapter/wrapper classes that may be used to support ServiceStack and other frameworks.
The dependency on System.Web has been removed with the SAML v2.0 .NET standard library that we released earlier this year for ASP.NET Core.
It's less likely now that we will remove the System.Web dependency from our SAML v2.0 .NET framework class library although, as always, that's driven by customer demand.
[/quote]

Do these work? If so, is there any documentation on what's required? The basic constructor doesn't appear to be sufficient for the SAMLHttpRequest to be used in the SAMLServiceProvider.ReceiveSSO call. Here's an example:

NameValueCollection formData = await myHttpRequestMessage.Content.ReadAsFormDataAsync();
string samlResponse = formData["samlResponse"];
string relayState = formData["relayState"];

samlResponse = Encoding.UTF8.GetString(Convert.FromBase64String(samlResponse));
relayState = Encoding.UTF8.GetString(Convert.FromBase64String(relayState));

SAMLHttpRequest webRequest = new SAMLHttpRequest(samlResponse, relayState, true);
bool isInResponseTo;
string partnerIdP;
string authnContext;
string userName;
IDictionary attributes;
string relayStateFromMessage;

ComponentSpace.SAML2.SAMLController.Configurations = ComponentSpace.SAML2.Configuration.SAMLConfigurationFile.Load(@"C:\configurationFiles\saml.config");
ComponentSpace.SAML2.SAMLServiceProvider.ReceiveSSO(webRequest,out isInResponseTo,out partnerIdP, out authnContext,
out userName, out attributes, out relayStateFromMessage);

This returns an exception "There is no HTTP context":
at ComponentSpace.SAML2.Utility.SAML.GetHttpContext()
at ComponentSpace.SAML2.Utility.SAML.GetHttpSessionState()
at ComponentSpace.SAML2.Data.SessionIDDelegates.GetSessionIDFromHttpSessionState()
at ComponentSpace.SAML2.Data.AbstractSSOSessionStore.get_SessionID()
at ComponentSpace.SAML2.Data.AbstractSSOSessionStore.CreateSessionIDForType(Type type)
at ComponentSpace.SAML2.Data.HttpSSOSessionStore.Load(Type type)
at ComponentSpace.SAML2.SAMLController.LoadSAMLConfigurationState()
at ComponentSpace.SAML2.InternalSAMLServiceProvider..ctor()
at ComponentSpace.SAML2.SAMLServiceProvider.ReceiveSSO(HttpRequestBase httpRequest, Boolean& isInResponseTo, String& partnerIdP, String& authnContext, String& userName, IDictionary& attributes, String& relayState)

I didn't see anything about the SAMLHttpRequest in the developer guide, but there is some version of in the dll (but a lot of things throw NotImplementedException). I'm using a self-hosted application -- so it doesn't have access to HttpContext.Current -- is that required even using the HttpRequestBase overloads of ReceiveSSO?

Any ideas? Or is this simply not going to work?

You need to provide an HttpContext as well.
At application startup, please include the following code.


using ComponentSpace.SAML2.Utility;

SAML.HttpContext = new SAMLHttpContext();
SAML.HttpSessionState = new SAMLHttpSessionState();



[quote]
ComponentSpace - 12/20/2017
You need to provide an HttpContext as well.
At application startup, please include the following code.


using ComponentSpace.SAML2.Utility;

SAML.HttpContext = new SAMLHttpContext();
SAML.HttpSessionState = new SAMLHttpSessionState();



[/quote]

Thanks -- that helped!

You’re welcome!

[quote]
ComponentSpace - 12/21/2017
You're welcome!
[/quote]

Unfortunately, I'm note able to get much farther. Now the ReceiveSSO request is throwing an exception, "The method or operation is not implemented"
at System.Web.HttpContextBase.get_Request()
at ComponentSpace.SAML2.Utility.SAML.ToAbsoluteURL(String url)
at ComponentSpace.SAML2.AbstractSAMLProvider.CheckDestination(StatusResponseType samlResponse, String destinationUrl)
at ComponentSpace.SAML2.InternalSAMLServiceProvider.ProcessSAMLResponse(XmlElement samlResponseElement, Boolean& isInResponseTo, String& authnContext, String& userName, SAMLAttribute[]& attributes)
at ComponentSpace.SAML2.InternalSAMLServiceProvider.ReceiveSSO(HttpRequestBase httpRequest, Boolean& isInResponseTo, String& partnerIdP, String& authnContext, String& userName, SAMLAttribute[]& attributes, String& relayState)
at ComponentSpace.SAML2.SAMLServiceProvider.ReceiveSSO(HttpRequestBase httpRequest, Boolean& isInResponseTo, String& partnerIdP, String& authnContext, String& userName, IDictionary& attributes, String& relayState)

I have enabled the tracing logs, but there's not any additional information there. The last line in the trace log is:
ComponentSpace.SAML2 Verbose: 0 : 86428/8: 12/21/2017 3:35:40 PM: The SAML response signature verified.

Any ideas? I'm trying to process a SAML response in my application, where the response is generated by the example application MVCExampleIdentityProvider (in the SAMLExamplesVS2015 solution). Any ideas?

In your saml.config for the PartnerIdentityProvider, please set DisableDestinationCheck=“true”.

[quote]
ComponentSpace - 12/21/2017
In your saml.config for the PartnerIdentityProvider, please set DisableDestinationCheck="true".
[/quote]

I tried this, but it didn't make a difference -- the same error/stacktrace is still being reported. In my service application (where I'm calling ReceiveSSO), here is the SAML configuration file PartnerIdentityProvider for the MVC Example Identity Provider:

http://localhost/MvcExampleIdentityProvider"
Description="MVC Example Identity Provider"
SignAuthnRequest="true"
SingleSignOnServiceUrl="http://localhost/MvcExampleIdentityProvider/SAML/SSOService"
SingleLogoutServiceUrl="http://localhost/MvcExampleIdentityProvider/SAML/SLOService"
DisableDestinationCheck="true"
PartnerCertificateFile="C:\Program Files (x86)\ComponentSpace SAML v2.0 for .NET\Examples\SSO\HighLevelAPI\MVC\MvcExampleIdentityProvider\Certificates\idp.cer"/>

Any ideas? It's hard for me to tell which Identity Provider is being used, but I think that this is the correct one. I'm receiving a SAML message with an issuer of:
http://localhost/MvcExampleIdentityProvider
so it seems like this is the one that should be identified as the Identity Provider.

Just to confirm, the issuer field in the SAML message is used to lookup the corresponding by its Name.
Please contact us by email mentioning your forum post so we can provide a debug version to investigate the issue further.

[quote]
ComponentSpace - 1/2/2018
Just to confirm, the issuer field in the SAML message is used to lookup the corresponding by its Name.
Please contact us by email mentioning your forum post so we can provide a debug version to investigate the issue further.
[/quote]

Yes -- I did check the PartnerIdentityProvider - the saml message's issuer is http://localhost/MvcExampleIdentityProvider, so I believe that it should be using the PartnerIdentityProvider where I set the DisableDestinationCheck = "true" flag.

I will send an email -- although I have had better luck with the low level Api. I'm able to use the sample application MvcExampleIdentityProvider to send SAML responses to my application and use the low level api to read them, validate signatures, decrypt encrypted assertions, etc.




Received, thanks.
I’ve email you an update. Please try that and let me know how it goes.