1

I cannot figure out how to get an attribute from the the saml response in place of the NameID value. My IDP team is returning the value I need in an attribute rather than in NameID(which they wont budge on).

Thanks for any help!

I am running MVC Core. I have everything setup and running for NameID from the example 'TestWebAppCore' for ITfoxtec.Identity.Saml2.

I am trying to get this value in place of NameID for the session username:

saml:AttributeStatement>
        <saml:Attribute Name="valueName"

NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"
                        >
            <saml:AttributeValue>IDValue</saml:AttributeValue>
        </saml:Attribute>
    </saml:AttributeStatement>

[Route("AssertionConsumerService")]
    public async Task<IActionResult> AssertionConsumerService()
    {
        var binding = new Saml2PostBinding();

        var saml2AuthnResponse = new Saml2AuthnResponse(config);

        binding.ReadSamlResponse(Request.ToGenericHttpRequest(), saml2AuthnResponse);
        if (saml2AuthnResponse.Status != Saml2StatusCodes.Success) {
            throw new AuthenticationException($"SAML Response status: {saml2AuthnResponse.Status}");
        }

        binding.Unbind(Request.ToGenericHttpRequest(), 
saml2AuthnResponse);
        try {
            await saml2AuthnResponse.CreateSession(HttpContext, 
claimsTransform: (claimsPrincipal) => 
ClaimsTransform.Transform(claimsPrincipal));
        }
        catch (Exception ex) {
            log.writeLog(ex.Message.ToString());
        }

        var relayStateQuery = binding.GetRelayStateQuery();
        var returnUrl = relayStateQuery.ContainsKey(relayStateReturnUrl) 
? relayStateQuery[relayStateReturnUrl] : Url.Content("~/");

        return Redirect(returnUrl);
    }
Anders Revsgaard
  • 3,636
  • 1
  • 9
  • 25

1 Answers1

1

It is probably not possible to logout without the NameID but you can login without.

In .NET the NameID is translated into the ClaimTypes.NameIdentifier claim. The users claims is handled in the ClaimsTransform.CreateClaimsPrincipal method.

You can either translate the incoming custom claim "valueName" to a ClaimTypes.NameIdentifier claim:

private static ClaimsPrincipal CreateClaimsPrincipal(ClaimsPrincipal incomingPrincipal)
{
    var claims = new List<Claim>();

    claims.AddRange(GetSaml2LogoutClaims(incomingPrincipal));
    claims.Add(new Claim(ClaimTypes.NameIdentifier, GetClaimValue(incomingPrincipal, "valueName")));

    return new ClaimsPrincipal(new ClaimsIdentity(claims, incomingPrincipal.Identity.AuthenticationType, ClaimTypes.NameIdentifier, ClaimTypes.Role)
    {
        BootstrapContext = ((ClaimsIdentity)incomingPrincipal.Identity).BootstrapContext
    });
}

Or change the identity claim in the ClaimsIdentity to the incoming custom claim "valueName":

private static ClaimsPrincipal CreateClaimsPrincipal(ClaimsPrincipal incomingPrincipal)
{
    var claims = new List<Claim>();

    // All claims
    claims.AddRange(incomingPrincipal.Claims);

    return new ClaimsPrincipal(new ClaimsIdentity(claims, incomingPrincipal.Identity.AuthenticationType, "valueName", ClaimTypes.Role)
    {
        BootstrapContext = ((ClaimsIdentity)incomingPrincipal.Identity).BootstrapContext
    });
}
Anders Revsgaard
  • 3,636
  • 1
  • 9
  • 25
  • 1
    I just resolved this last night. Your option 1 translating valueName to NameIdentifier was exactly what I did once I realized that portion. Thank's very much for your response to verify! – Bryan Lighton Jun 20 '19 at 12:17