3
votes

There's a question about using SAML in ASP.Net Core, but I need additional help.

The only answer there mentions Kentor.AuthServices, but I don't understand how to use it. Everything I find on this or other SAML libraries, the documentation, blog posts, and sample applications are all about contacting some external authentication service and handling login and logout.

But I don't need any of that. The setup I'm working with does that in an edge-facing firewall application, and login/logout requests never reach my application. All I get is a SAML token in a cookie, which I need to validate and turn into a ClaimsPrincipal. I can't (the deployment network setup is insanely paranoid) and don't want to contact any identity provider.

Currently I've written a piece of middleware that takes the cookie, parses it, and parses out the parts I need for the claims principal. But I don't do any validation, either of the XML signature or of the SAML validity (valid time attributes etc). With .Net Core 2.0 Preview 2 I can do the XML signature validation, but I'm still stuck on doing the SAML validation. Is there a library that simply validates SAML constraints and does nothing else (or, at least, where I can ignore everything else)? I believe Kentor or ITfoxtec or elerch's SAML2.Core must contain such functionality, but I can't figure out where it is.

2

2 Answers

1
votes

I have done this with SecurityTokenHandlerCollection class in System.IdentityModel.Tokens I hope this code will help you.

 public Saml2SecurityToken DeserializeSAMLResponse(string samlResponse)
    {
        //Deserializing saml response

        Saml2SecurityToken token;
        using (var reader = XmlReader.Create(new StringReader(samlResponse)))
        {
            reader.ReadToFollowing("Assertion", Infrastructure.Enumerations.StringEnum.GetStringValue(SAMLProtocoles.SAML_20_ASSERTION));
            // Deserialize the token so that data can be taken from it and plugged into the RSTR
            SecurityTokenHandlerCollection tokenHandlerCollection = SecurityTokenHandlerCollection.CreateDefaultSecurityTokenHandlerCollection();
            token = (Saml2SecurityToken)tokenHandlerCollection.ReadToken(reader.ReadSubtree());
        }

        //Deserializing successful
        return token;
    }

It will internally validate the SAML and parse it in Saml2SecurityToken After you get the token you can the the Users Credentials like this

  public User ReadSamlResponse(string samlResponse, string profileName, bool isSAMLProfile = true)
    {
        User User = new User();
        var DecodedSamlResponse = Convert.FromBase64String(samlResponse);
        string ResponseDecoded = coding.UTF8.GetString(DecodedSamlResponse);

            Saml2SecurityToken Token = _samlAuthenticationService.DeserializeSAMLResponse(ResponseDecoded);
            if ()// apply condition here if you need to validate signature
            {
                if (!_samlAuthenticationService.ValidateSamlToken(ResponseDecoded, AuthenticationConnector, isSAMLProfile))
                    throw new Exception("Signature is invalid");
            }

            User = GetUserFromToken(Token);
            return User;
        }

And to get User for Security Token you can do this

 public User GetUserFromToken(Saml2SecurityToken Token)
    {
        //Get user information from the token started
        User User = new User();
        if (Token != null)
        {
            if (Token.Assertion.Subject.NameId != null && (Token.Assertion.Subject.NameId.Format == null || Token.Assertion.Subject.NameId.Format.OriginalString == "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"))
                User.EmailAddress = Token.Assertion.Subject.NameId.Value;
            foreach (var Statement in Token.Assertion.Statements)
            {
                var AttributeStatement = Statement as Saml2AttributeStatement;
                var AuthenticationStatement = Statement as Saml2AuthenticationStatement;
                if (AttributeStatement != null)
                    foreach (var Saml2Attribute in AttributeStatement.Attributes)
                    {
                        if (Saml2Attribute.Name.Equals("mail") || Saml2Attribute.Name.Equals("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"))
                            User.EmailAddress = Saml2Attribute.Values[0];
                        if (Saml2Attribute.Name.Equals("uid") || Saml2Attribute.Name.Equals("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"))
                            User.Name = Saml2Attribute.Values[0];
                        if (Saml2Attribute.Name.Equals("phone"))
                            User.MobileNumber = Saml2Attribute.Values[0];
                        if (Saml2Attribute.Name.Equals("title"))
                            User.JobTitle = Saml2Attribute.Values[0];
                        if (Saml2Attribute.Name.Equals("company"))
                            User.CompanyName = Saml2Attribute.Values[0];
                    }
                if (AuthenticationStatement != null)
                {
                    User.SAMLSessionIndex = AuthenticationStatement.SessionIndex;
                }
            }
        }
        //Successfully parsed user credentials
        return User;
    }