-
Notifications
You must be signed in to change notification settings - Fork 413
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding generation of accessors for equivalent claims #1829
base: dev
Are you sure you want to change the base?
Conversation
AAD token version of the token See #1800
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a few explanations
@@ -0,0 +1,115 @@ | |||
<#@ template debug="false" hostspecific="false" language="C#" #> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a T4 file that generates the ClaimTypeMapping.cs from the ClaimsKnowledge.tti.
@@ -0,0 +1,141 @@ | |||
<#+ | |||
class ClaimsKnowledge |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class is not product code, but control code to generate the product code.
This data structure describes the claims information.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not understanding why we need a template model.
I have used .tt's when using typescript that will generate different jscript mapped to a release.
How does the tti help us?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It avoids writing 5000 lines of code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jmprieur i will educate myself about this technique.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can spend 10 minutes with you @brentschmaltz if you wish. Also you might want to install this Visual Studio extension: https://marketplace.visualstudio.com/items?itemName=bricelam.T4Language
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jmprieur Would this require users to install this extension to build?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no. not at all. It's an editor extension so that the syntax coloring help understanding the T4 code
</None> | ||
<None Update="ClaimTypeAccessor.tt"> | ||
<LastGenOutput>ClaimTypeAccessor.gen.cs</LastGenOutput> | ||
<Generator>TextTemplatingFileGenerator</Generator> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you save the ClaimTypeAccessor.tt this generates the ClaimTypeAccessor.gen.cs which contain a partial class implementation of ClaimTypeAccessor.cs
new ClaimsKnowledge("Group", true, false, true, "", "\"http://schemas.xmlsoap.org/claims/Group\"", "\"group\""), | ||
new ClaimsKnowledge("GroupsId", true, false, true, "", "ClaimTypes.GroupSid", "\"groupsid\""), | ||
new ClaimsKnowledge("IdTyp", false, false, true, "", "\"idtyp\""), | ||
new ClaimsKnowledge("Idp", false, false, true, "", "\"http://schemas.microsoft.com/identity/claims/identityprovider\"", "\"idp\""), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do we know 'idp' (or any other claim) is or is not 'usableForAuthorization' ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might be. I've started a conversation with a few people about what claim should be. (same for the privacy)
- Adding indication of safety for authorization on all claims
string | GetTenantId | True | OII | "tid"<BR/> "http://schemas.microsoft.com/identity/claims/tenantid" | ||
string | GetAcr | False | | "acr"<BR/> "http://schemas.microsoft.com/claims/authnclassreference" | ||
string | GetAdfs1Email | False | EUPI | "adfs1email"<BR/> "http://schemas.xmlsoap.org/claims/EmailAddress" | ||
string | GetAdfs1Upn | False | EUPI | "adfs1upn"<BR/> "http://schemas.xmlsoap.org/claims/UPN" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know what this claim is. Maybe it's only available when users logged with UPN
string | GetObjectId | True | EUPI | "oid"<BR/> "http://schemas.microsoft.com/identity/claims/objectidentifier" | ||
IEnumerable<string> | GetScopes | True | | "scp"<BR/> "http://schemas.microsoft.com/identity/claims/scope" | ||
string | GetTenantId | True | OII | "tid"<BR/> "http://schemas.microsoft.com/identity/claims/tenantid" | ||
string | GetAcr | False | | "acr"<BR/> "http://schemas.microsoft.com/claims/authnclassreference" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kalyankrishna1: do you mean GetAuthenticationClassReference?
IEnumerable<string> | GetRole | True | | "role"<BR/> "roles"<BR/> ClaimTypes.Role | ||
string | GetSid | False | | "sid" | ||
string | GetUpn | False | | "upn"<BR/> ClaimTypes.Upn | ||
string | GetWinaccountname | False | | "winaccountname"<BR/> ClaimTypes.WindowsAccountName |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -0,0 +1,196 @@ | |||
<#@ template debug="false" hostspecific="false" language="C#" #> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of general concerns:
- some of the categories seems to be AAD specific, IdentityModel has always tried to be neutral?
- can users set their own categories?
- there is no general spec for the category of claims, how can one say claim 'a' is in a category in general?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Do we want to move this into SAL?
- The categories are privacy categories (well defined. could almost be an enum). For 3) will follow-up offline
…m/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet into jmprieur/ClaimsMappingImprovement
…m/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet into jmprieur/ClaimsMappingImprovement
…m/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet into jmprieur/ClaimsMappingImprovement
using System.Security.Claims; | ||
using System.Linq; | ||
|
||
namespace System.IdentityModel.Aad |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The ns is System.IdentityModel.Aad, but folder and file names are Microsoft.IdentityModel.*
All our new work uses Microsoft.IdentityModel.*
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank @brentschmaltz: I fixed the generators (which fixed the code)
a38cc2f
@jmprieur this statement needs some adjustment:
long or short claim types is not a result of token version, it is a result of the claims mapping in the JwtSecurityTokenHandler. For example: v1.appid <-> v2.azp, v1.appidacr <-> v2. azpacr |
string | GetAuthenticationContextClassReference | False | | acr<BR/> http://schemas.microsoft.com/claims/authnclassreference | ||
string | GetAdfs1Email | False | EUPI | adfs1email<BR/> http://schemas.xmlsoap.org/claims/EmailAddress | ||
string | GetAdfs1Upn | False | EUPI | adfs1upn<BR/> http://schemas.xmlsoap.org/claims/UPN | ||
string | GetAmr | False | | amr<BR/> http://schemas.microsoft.com/claims/authnmethodsreferences |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
amr is definitely used in Authorization as this defines how the subject authenticated with the identity provider.
|
||
Type | Accessor | Used for authorization | Privacy | Claims | ||
-- | -- | -- | -- | -- | ||
string | GetActor | False | | actort<BR/> http://schemas.xmlsoap.org/ws/2009/09/identity/claims/actor |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think actor is PII as the return is another token.
/// <returns>All the values of the claims or its equivalents.</returns> | ||
public static IEnumerable<string> GetAllEquivalentClaims(this ClaimsPrincipal user, string claimType) | ||
{ | ||
if (user is null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we have been using the coding style:
_ = user ?? throw new ArgumentNullException();
{ | ||
if (user is null) | ||
{ | ||
throw new ArgumentNullException(nameof(user)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How will this plug into our logging model?
|
||
if (string.IsNullOrEmpty(claimType)) | ||
{ | ||
throw new ArgumentException($"'{nameof(claimType)}' cannot be null or empty.", nameof(claimType)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have been using a single location for log messages, each with an identifier that allows for quickly identifying the assembly and location of the issue.
see: LogMessages
/// <summary> | ||
/// Verifies that the token has any of the claims required. | ||
/// </summary> | ||
/// <param name="user">claims identity</param> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this parameter is a ClaimsPrincipal.
we may want to write:
/// <param name="claimsPrincipal"> the <see cref="ClaimsPrincipal"/> to check for a claim
/// of one of the requiredClaims.</param>
This comment applies to methods below.
/// <param name="user">Claims principal</param> | ||
/// <param name="claimType">Claims type</param> | ||
/// <returns></returns> | ||
public static string GetEquivalentClaim(this ClaimsPrincipal user, string claimType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is not returning a Claim, but a Claim.Value (which may be a complex type, bool, int, null).
In this case, the user will not know the type of the Value as that is contained in Claim.ValueType.
One option is to return a Claim.
Our JWT -> Claim logic is here.
JsonWebToken has added TryGetPayloadValue to try and deal with this.
Adding generation of accessors for claims independently of AAD token version of the token
See #1800
Developer experience:
Add a using:
In the code, on a ClaimsPrincipal or an IdentityPrincipal instance, you will get access to extension methods that retrieve the claims in the instance independently of them being long or short claims (which depends on the token version: v1.0 or v2.0 tokens). Developers will also get completion telling them if the claim is safe or not for use in authorization policies, and what privacy category they belong to
See also the description of the accessors:
ClaimsAccessorDoc.md
Design
This PR a bit different from others: It uses code generation
The claims are described in ClaimsKnowledge.tti (Text Template Include file)
This include file is included in:
ClaimsTypeAccessor
, the other partial being in ClaimsTypeAccessor.cs