OWIN and WS-Federation with CA Siteminder


A customer was having a problem integrating an ASP.NET application with CA Siteminder v12.52. Firstly, there was a problem with using SAML2.0 token formats. To get around that, we reconfigured SM to use SAML1.1 for this application. Still, the application was failing with error message:

ID4037: The key needed to verify the signature could not be resolved from the following security key identifier ‘SecurityKeyIdentifier

After some research it turned out that Systeme.IdentityModel.MetadataSerializer class is having a problem with fully parsing the federation metadata file provided by SM. That portion of the metadata file has the following format in SM:

    <ns8:KeyDescriptor use=signing>
      <ns4:KeyInfo Id=SM6752f8ab2dc045dee02e91fc3e4c3d4dba0da5d201>
        <ns4:X509Data>
          <ns4:X509IssuerSerial>
            <ns4:X509IssuerName>CN=IDMD01PS.wcbsyst.com</ns4:X509IssuerName>
            <ns4:X509SerialNumber>50492557723305036384415117878260826031</ns4:X509SerialNumber>
          </ns4:X509IssuerSerial>
         <ns4:X509Certificate>MIIC7DCCAdSgAwIBAgIQJfyDTK40kYZHN0r2dyZ/rzANBgkqhkiG9w0BAQUFADAfMR0wGwYDVQQDExRJRE1EMDFQUy53Y2JzeXN0LmNvbTAeFw0xNzAyMTQyMTIyMzVaFw0xODAyMTQwMDAwMDBaMB8xHTAbBgNVBAMTFElETUQwMVBTLndjYnN5c3QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2UBgxp/+RcES/cwEPsTIdrlPszSrqDGN4bPpGA3XBeS/RpXyqQNfG1iiSSkdemfnAZ0QpNaMCo/5bZWHQjC842QBkP1bFcwGT9t1HQodH1LyBT0nLZkOuxXxa2ibhrv3tgBtk+nU3hHeqonejNGJxIKnUzvIOlxF39tMu8Fco3GFxTbztyBAvZQBr20G+nYn3+XJ6uL3oOMwNlihu0rqg5FsaU+hsyBPpeR+8jYwft+iYhwJb1COo1Lvx3nbuGHS260R/rTQxo9T3UcI3P4A84UROMH2QPIao6FiakTK5LMh+SSqsKOzWg3MiTSxoqLDfAmALGTPNbt27KjC5WDAWwIDAQABoyQwIjALBgNVHQ8EBAMCBDAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDQYJKoZIhvcNAQEFBQADggEBAAQjyiTQ+aVrNcLqujjwr+1uJ848P0D805hPkkx2QdCVA/a/cwZ4VTpSeMrPM3M2RwtJXDEq1roUePmIiylGYTbggBaOIosTHB6F7Kr1mKxdxX53fvCHWTZFc8rXv85kx/ySOAMHingrtbna1b+rlpRrBPl+l5dZ90bZZNuMBxufTPHBwGNKUQ6TRu5s5BWRDd07yM39agsvxN6Vc8xACKvVc/WKBpVm9YsbMY2FlciMcpBSXpvzblam3KOY0ESszvJEpxzdupESuFxdUzZHo+DNPqCm+vkyxUXO8/DXueb6MI5GBfXbGWmEcoWbPr4KkFYbzp1RqJOQGFLEQevrVsg=</ns4:X509Certificate>
        </ns4:X509Data>
      </ns4:KeyInfo>
    </ns8:KeyDescriptor>

The metadata serializer was picking up the presence of the key but not the raw data and thus not creating a security key in the WS-Federation configuration object. Our solution was to create our own ConfigurationRetriever and pass it as parameter to the WsFederationAuthenticationOptions. Here are the relevant portions of the code:

   1:          public void ConfigureAuth(IAppBuilder app)
   2:          {
   3:              app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
   4:  
   5:              app.UseCookieAuthentication(new CookieAuthenticationOptions());
   6:  
   7:              var metadata = "https://idp.systest.worksafebc.com/affwebservices/public/FederationMetadata/idpevc3pocpartnership";
   8:              app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions()
   9:              {
  10:                  Wtrealm = "https://Meraridom.onmicrosoft.com/WebApplication1b",
  11:                  ConfigurationManager = new Microsoft.IdentityModel.Protocols.ConfigurationManager<WsFederationConfiguration>(
  12:                      metadata, new ConfigurationRetriever(),
  13:                      new DocumentRetriever()),
  14:                  TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters()
  15:                  {
  16:                      ValidAudience = "https://Meraridom.onmicrosoft.com/WebApplication1b",
  17:                  },
  18:                  SignOutWreply = postLogoutRedirectUri,
  19:              });
  20:          }
  21:  
  22:          public class ConfigurationRetriever : Microsoft.IdentityModel.Protocols.IConfigurationRetriever<WsFederationConfiguration>
  23:          {
  24:              public async Task<WsFederationConfiguration> GetConfigurationAsync(string address, IDocumentRetriever retriever, CancellationToken cancel)
  25:              {
  26:                  var conf = new WsFederationConfiguration();
  27:                  var doc = await retriever.GetDocumentAsync(address, cancel);
  28:                  var bytes = Encoding.UTF8.GetBytes(doc);
  29:                  var stream = new MemoryStream(bytes);
  30:                  var ser = new MetadataSerializer();
  31:                  //ser.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
  32:                  var md = (EntityDescriptor)ser.ReadMetadata(stream);
  33:                  conf.Issuer = md.EntityId.Id;
  34:                  foreach (var d in md.RoleDescriptors)
  35:                  {
  36:                      var svc = d as SecurityTokenServiceDescriptor;
  37:                      if ((svc != null) && (svc.PassiveRequestorEndpoints.Count > 0))
  38:                      {
  39:                          conf.TokenEndpoint = svc.PassiveRequestorEndpoints.First().Uri.AbsoluteUri;
  40:                      }
  41:                  }
  42:                  GetCerts(XDocument.Parse(doc), conf.SigningKeys);
  43:                  return conf;
  44:  
  45:              }
  46:              static XNamespace dflt = "http://www.w3.org/2005/08/addressing";
  47:              static XNamespace ns4 = "http://www.w3.org/2000/09/xmldsig#";
  48:              static XNamespace ns8 = "urn:oasis:names:tc:SAML:2.0:metadata";
  49:              private void GetCerts(XDocument metadata, ICollection<SecurityKey> keys)
  50:              {
  51:                  var roleDesc = metadata.Root.Element(ns8 + "RoleDescriptor");
  52:                  foreach (var keyDesc in roleDesc.Elements(ns8 + "KeyDescriptor"))
  53:                  {
  54:                      var useAttr = keyDesc.Attribute("use");
  55:                      if (useAttr == null) continue;
  56:                      if (String.Compare(useAttr.Value, "signing", StringComparison.InvariantCulture) == 0)
  57:                      {
  58:                          var certData = keyDesc.Element(ns4 + "KeyInfo").Element(ns4 + "X509Data").Element(ns4 + "X509Certificate");
  59:                          var data = certData.Value;
  60:                          var bytes = new System.Text.ASCIIEncoding().GetBytes(data);
  61:                          var cert = new X509Certificate2(bytes);
  62:                          var key = new X509AsymmetricSecurityKey(cert);
  63:                          keys.Add(key);
  64:                      }
  65:                  }
  66:              }
  67:          }
  68:          public class DocumentRetriever : Microsoft.IdentityModel.Protocols.IDocumentRetriever
  69:          {
  70:              public async Task<string> GetDocumentAsync(string address, CancellationToken cancel)
  71:              {
  72:                  var client = new HttpClient();
  73:                  return await client.GetStringAsync(address);
  74:              }
  75:          }
  76:  
Comments (0)

Skip to main content