25

My context:

  • .Net RESTful web service
  • Client (mixed platforms, technologies, lib capabilities) has obtained a SAML token
  • Trying to accept the token for authentication/authorization in the REST service
    • in HTTP Authorization / X-Authorization header
    • as query parameter
  • Will also support SWT later, but need to get SAML tokens going

Details:

I have a SAML token in a string:

<saml:Assertion xmlns:saml="..." ...> ..etc... </>

In an HttpModule, I want to convert this into a ClaimsPrincipal so that my service can do the usual Thread.CurrentPrincipal as IClaimsPrincipal stuff.

I found a couple enticing pages/blogs/etc... that looked helpful:

I'm stuck literally trying to turn the SAML token into the ClaimsPrincipal (via SecurityToken intermediate step or direct... happy either way). The sample code from Cibrax's idea uses the following for the crucial verification and deserialization step:

SecurityTokenSerializer securityTokenSerializer 
    = new SecurityTokenSerializerAdapter(
        FederatedAuthentication.SecurityTokenHandlers, 
        MessageSecurityVersion.Default.SecurityVersion, 
        false, new SamlSerializer(), null, null);

SecurityToken theToken 
    = WSFederationAuthenticationModule.GetSecurityToken(
        theSamlTokenInStringForm, securityTokenSerializer);

The wall I've hit is that the RTM version of WIF does not expose this overload of GetSecurityToken... it only exposes:

WSFederationAuthenticationModule fam = new WSFederationAuthenticationModule();
SecurityToken theToken = fam.GetSecurityToken(HttpRequest theRequest);
SecurityToken theToken = fam.GetSecurityToken(SignInResponseMessage message);

Thanks for helping me to get unstuck!

Tyler

Tyler
  • 859
  • 1
  • 8
  • 10

4 Answers4

3

Just found this helpful. http://www.tecsupra.com/blog/system-identitymodel-manually-parsing-the-saml-token/

Basic idea: You need the XML of the "Audience"-node and then you can use the SecurityTokenHandlerCollection and use "ValidateToken"

From the post:

       string samlTokenXml = signInResponseXml
            .DocumentElement  // <trust:RequestSecurityTokenResponseCollection>
            .ChildNodes[0] // <trust:RequestSecurityTokenResponse>
            .ChildNodes[2] // <trust:RequestedSecurityToken>
            .InnerXml; // <Assertion>

        var xmlTextReader = new XmlTextReader(new StringReader(samlTokenXml));

        SecurityTokenHandlerCollection handlers = 
       FederatedAuthentication.FederationConfiguration.IdentityConfiguration.SecurityTokenHandlers;

        // read the token
        SecurityToken securityToken = handlers.ReadToken(xmlTextReader);
Robert Muehsig
  • 5,206
  • 2
  • 29
  • 33
  • I think you meant "Assertion" rather "Audience" and "ReadToken" rather than "ValidateToken", but the article is quite good +1 – Sebastian K Mar 24 '14 at 15:25
  • Just checked my solution: At first I read the SecurityToken via "ReadToken" and validate it via "ValidateToken" (which is not present in the code snippet, but is needed)- so you are correct. – Robert Muehsig Mar 24 '14 at 15:36
1

I want to share some resources I found very useful in implementing essentially the same scenario. Basically, Dominick Baier is a god in this space. His blog is full of great info on the subject:

http://leastprivilege.com/

For converting a SAML/SWT token to IClaimsIdentity in a RESTful service:

http://www.develop.com/wcfrest/

http://identitymodel.codeplex.com/

Veli Gebrev
  • 2,481
  • 4
  • 31
  • 48
0

Ok, some progress... if I do the following, I get further:

Microsoft.IdentityModel.Configuration.ServiceConfiguration serviceConfig
    = new Microsoft.IdentityModel.Configuration.ServiceConfiguration();

// Now read the token and convert it to an IPrincipal
SecurityToken theToken = null;
ClaimsIdentityCollection claimsIdentity = null;
using (XmlReader reader = XmlReader.Create(new StringReader(authSamlString)))
{
    theToken = serviceConfig.SecurityTokenHandlers.ReadToken(reader);
    claimsIdentity = serviceConfig.SecurityTokenHandlers.ValidateToken(theToken);
}

IPrincipal principal = new ClaimsPrincipal(claimsIdentity);

The next wall I've hit:

I'm now getting an exception in the wizard-generated REST service host allocation here:

<%@ ServiceHost Language="C#" Debug="true" Service="Sample.RestService.Service" Factory="Sample.RestService.AppServiceHostFactory"%>

using System;
using System.ServiceModel;
using System.ServiceModel.Activation;
using Microsoft.ServiceModel.Web.SpecializedServices;

namespace Sample.RestService 
{
  class AppServiceHostFactory : ServiceHostFactory
  {
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        /// ***** The exception occurs on the next line *****
        return new SingletonServiceHost(serviceType, baseAddresses);
    }
  }
}

The exception details:

System.Configuration.ConfigurationErrorsException occurred
  Message="This element is not currently associated with any context"
  Source="System.Configuration"
  BareMessage="This element is not currently associated with any context"
  Line=0
  StackTrace:
       at System.Configuration.ConfigurationElement.get_EvaluationContext()
  InnerException: {{NONE}}
Kiquenet
  • 14,494
  • 35
  • 148
  • 243
Tyler
  • 859
  • 1
  • 8
  • 10
  • which version of .Net is this on? If less than 4 see http://stackoverflow.com/questions/1189331/first-chance-system-configuration-configurationerrorsexception-this-element-is for a likely explanation of what you are seeing! – Rich O'Kelly Nov 16 '11 at 12:42
0

For resolving the last exception please check the tag and its contents and make sure its correct. I can't say which element has issue. We go this error some times and everytime the reason was malformed identitymodel section.

Joy George Kunjikkuru
  • 1,495
  • 13
  • 27