Name Identifiers in SAML assertions


In this post I will show how to setup your Relying Party Trust issuance policy to create name identifier in assertion. For AD FS 2.0 the name identifier is yet another claim but you may want to generate name identifiers if you plan to:

·         Use SAML 2.0 protocol (particularly name identifier is necessary if you plan to take advantage of SAML logout protocol),

·         Federate with non-AD FS 2.0 deployment.

I will show name identifier configuration on two privacy sensitive scenarios: persistent identifier, transient identifier. Persistent identifier is meant to obfuscate the real user identity, so it’s not possible to link user activities across different relying parties. At the same time the STS guarantees that persistent id will remain the same each time same the user logs in again. In SAML 2.0 assertion, it may look similar to:

<Assertion ID=_90bd669e-4a85-412d-9969-90e43e031fac IssueInstant=2010-01-07T02:50:48.719Z Version=2.0 xmlns=urn:oasis:names:tc:SAML:2.0:assertion>

  <Issuer>http://mysts/adfs/services/trust</Issuer>

  […]

  <Subject>

    <NameID Format=urn:oasis:names:tc:SAML:2.0:nameid-format:persistent>zbonsm0Yn9Gnw14uQEEPr6AO7d+IvxwCQN3t+o24jYs=</NameID>

    […]

  </Subject>

  […]

</Assertion>

 

Transient identifier has similar properties but it’s only valid for single login session (i.e. it will be different each time the user authenticates again, but will stay the same as long as the user is authenticated).

 

Before I start I assume you already configured sample Relying Party Trust with basic policy. In case you don’t, here is some recommended reading:

·         Configuring Relying Parties

·         AD FS 2.0 policy language

Persistent name identifier

Step 1. Choose your Relying Party Trust and make a custom issuance transform rule to create unique user identifier claim

For the first rule we have to create advanced rule that will use custom built-in store for generating opaque identifiers. Sample rule below will use Windows Account Name Claim as a seed to generate unique identifier that will persist across all sessions.

c:[type == “http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname” ]

=> add(

  store  = “_OpaqueIdStore”,

  types = (“http://mycompany/internal/persistentId”),

  query = “{0};{1};{2}”,

  param = “ppid”,

  param = c.Value,

  param = c.OriginalIssuer);

 

Note about technical detail: the rule that we are using is attribute extraction rule from one of the built-in attribute stores. The store takes 3 parameters: mode (“ppid”) and 2 parameters that are used as a seed for generating pseudo-random identifier. The result is also mixed with AD FS installation specific secret entropy.

 

Step 2. Transform persistent identifier claim into Name Identifier claim

 

We can use built-in rule to transform the persistent identifier claim created in Step 1 into name identifier claim (see screenshot below).

 

 


Transient name identifier

Step 1. Create custom rule to create per session identifier

For identifier we will use second mode of opaque store where it takes extra entropy to mix into result. In addition to Windows Account Name, we will also use authentication instant to generate identifier that will persist only for current login session.

c1:[Type == “http://schemas.microsoft.com/ws/2008/06/identity/claims/windowsaccountname”] &&

c2:[Type == “http://schemas.microsoft.com/ws/2008/06/identity/claims/authenticationinstant”]

 => add(

       store = “_OpaqueIdStore”,

       types = (“http://mycompany/internal/sessionid”),

       query = “{0};{1};{2};{3};{4}”,

       param = “useEntropy”,

       param = c1.Value,

       param = c1.OriginalIssuer,

       param = “”,

       param = c2.Value);

Note about technical detail: this time we also extract values from built-in store. This time the mode is “useEntropy” – which basically means that we will use 2 extra parameters (3rd and 4th) to additionally mix into returned identifier. Parameter 3 – is site specific entropy (empty means use relying party identifier). Parameter 4 is any other entropy – we use authentication instant.

Step 2. Transform temporary claim into Name Identifier claim

 

We will use similar rule as for persistent name identifier. This time we will change the format of the claim to indicate that Name Identifier will be transient.


Mieszko Matkowski

SDET, AD FS 2.0 Protocols

Comments (4)

  1. irongbest says:

    I am using WIF RTM on a Windows Server2008 64bit computer, I got this error:

    [CryptographicException: Key not valid for use in specified state.

    ]

      System.Security.Cryptography.ProtectedData.Unprotect(Byte[] encryptedData, Byte[] optionalEntropy, DataProtectionScope scope) +425

      Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte[] encoded) +59

    [InvalidOperationException: ID1073: A CryptographicException occurred when attempting to decrypt the cookie using the ProtectedData API (see inner exception for details). If you are using IIS 7.5, this could be due to the loadUserProfile setting on the Application Pool being set to false. ]

      Microsoft.IdentityModel.Web.ProtectedDataCookieTransform.Decode(Byte[] encoded) +151

      Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ApplyTransforms(Byte[] cookie, Boolean outbound) +109

      Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(XmlReader reader, SecurityTokenResolver tokenResolver) +634

      Microsoft.IdentityModel.Tokens.SessionSecurityTokenHandler.ReadToken(Byte[] token, SecurityTokenResolver tokenResolver) +105

      Microsoft.IdentityModel.Web.SessionAuthenticationModule.ReadSessionTokenFromCookie(Byte[] sessionCookie) +239

      Microsoft.IdentityModel.Web.SessionAuthenticationModule.TryReadSessionTokenFromCookie(SessionSecurityToken& sessionToken) +59

      Microsoft.IdentityModel.Web.SessionAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs eventArgs) +52

      System.Web.SyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +68

      System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +75

    This error only happens when I restart the IIS, I am using a domain user as the application pool user.

    I tried a lot:

    1. Use ApplicationPoolIdentity or NetWork Service, then I don’t have this problem after restart IIS.
    2. Use a domain user who is a administrator, I don’t have this problem also.

    3. Only when I switch to the user who have very limit right in the domain, I will got this problem.

    Do WIF have some special requirements on the pool user? or what can I do to solve this problem if I still want to use a domain user?

    This comment is not good to out here, but I cannot find any other related resources to solve this problem, so i have to come here to ask you developers.

    Can you please send my any feedback about this to i.zuo@live.com?

  2. None the Wiser says:

    With the Transient Name Identifier, what URL does the incoming claim type refer to?

    types = ("http://mycompany/internal/sessionid&quot;),

    Meaning what URL is this?

  3. mike says:

    i'm wondering the same as none the wiser and will this help with event 362:

    Encountered error during federation passive sign-out.

    Additional Data

    Exception details:

    Microsoft.IdentityServer.Web.RequestFailedException: MSIS7055: Not all SAML session participants logged out properly. It is recommended to close your browser.

      at Microsoft.IdentityServer.Web.FederationPassiveAuthentication.BuildSamlLogoutResponse(HttpSamlMessage samlMessage)

      at Microsoft.IdentityServer.Web.FederationPassiveAuthentication.SingleLogout(Uri returnUrl, Boolean wsFedInitiated)