Search code examples
c#kentor-authservices

Kentor AuthServices Sending AuthnRequests Asp.Net Core


I have an Asp.Net Core web application in which I'm currently in the process of implementing a SP-initiated SSO using Kentor AuthServices. Now, I received the metadata file from the idP in the following format:

<?xml version="1.0" encoding="UTF-8"?>
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" 
 xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" 
 entityID="https://exampleidp.com">
<md:IDPSSODescriptor 
 protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
   <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
      <X509Data>
         <X509Certificate>ExampleCertificate</X509Certificate>
      </X509Data>
   </KeyInfo>
</md:KeyDescriptor>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified
</md:NameIDFormat>
<md:SingleSignOnService
 Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
 Location="https://exampleidp.com/loginpage"/>
<md:SingleLogoutService 
 Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" 
 Location="https://exampleidp.com/logoutpage"/>
<saml:Attribute Name="accountID" 
 NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" 
 FriendlyName="accountID"/>
<saml:Attribute Name="email" 
 NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" 
 FriendlyName="email"/>
<saml:Attribute Name="firstName" 
 NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" 
 FriendlyName="firstName"/>
<saml:Attribute Name="lastName" 
 NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:basic" 
 FriendlyName="lastName"/> 
</md:IDPSSODescriptor>
<md:ContactPerson contactType="technical">
   <md:GivenName>Exampleidp</md:GivenName>
   <md:SurName>Support</md:SurName>
   <md:EmailAddress>[email protected]</md:EmailAddress>
</md:ContactPerson>
<md:Organization>
   <md:OrganizationName xml:lang="en">Example Idp</md:OrganizationName>
   <md:OrganizationDisplayName xml:lang="en">Example Idp</md:OrganizationDisplayName>
   <md:OrganizationURL xml:lang="en">http://exampleidp.com/</md:OrganizationURL>
</md:Organization>  
</md:EntityDescriptor>

along with two certificates for signing. In my Startup.cs I have added the following code snippet in ConfigureServices:

.AddSaml2(options =>
        {
            options.SPOptions.EntityId = new EntityId("http://myapp.com");
            options.IdentityProviders.Add(
                new IdentityProvider(
                    new EntityId("myapp.com/Metadata.xml"), options.SPOptions)
                {
                    LoadMetadata = true
                });
        })

and the following code snippet in Configure:

app.UseAuthentication();

UPDATE

After looking through the source code more I was finally able to wrap my head around and generate AuthnRequests like the following (which I verified with the idP):

<saml2p:AuthnRequest xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" 
 xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" 
 ID="idcc70905185a04a94b05282e0c544e086" Version="2.0" IssueInstant="2017-
 11-13T14:47:56Z" 
 ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" 
 AssertionConsumerServiceURL="http://myapp.com/saml">
    <saml2:Issuer>http://myapp.com</saml2:Issuer>
    <saml2p:NameIDPolicy Format="urn:oasis:names:tc:SAML:1.1:nameid-
     format:unspecified" AllowCreate="true" />
</saml2p:AuthnRequest>

EDIT: My main concern now is how I need to send the AuthnRequest to the idP. It appears, if I'm on the right track, that I need to deflate and encode the AuthnRequest in order for the idP to properly handle it. I'm wondering how I might go about achieving this (it also looks like I may need to include RelayState information?) either using existing Kentor code or possibly it's easy enough to do myself?


Solution

  • FINAL UPDATE WITH ANSWER: After much research and poking around I was finally able to resolve what ended up being my last issue which was setting the AuthnRequest to the proper deflated and base64 encoded string that needed to be sent to the idP. I achieved this using the following chunk of code:

    var param = "";
            var bytes = Encoding.UTF8.GetBytes(authnRequest.ToXElement().ToString());
            using (var output = new MemoryStream())
            {
                using (var zip = new DeflateStream(output, CompressionMode.Compress))
                {
                    zip.Write(bytes, 0, bytes.Length);
                }
                var base64String = Convert.ToBase64String(output.ToArray());
                param =  HttpUtility.UrlEncode(base64String);
            }
    

    which triggered the proper response by the idP so I am now able to properly trigger a SSO for my SP and grab the response values from the idP.