When retrieving claims information from the user token, the SDK documentation mentions that the claims can come in the form of several supported datatypes. When I was setting up a test for dealing with each type, a number of those types were impossible to set up in Active Directory. It turns out that Active Directory itself only supports a subset.
Introduction
Over the past weeks, I've been writing an open version of whoami. As part of displaying the user's token claims, I use GetTokenInformation
to retrieve that information from the user token. A user or device claim can have different datatype
s, which depend on the type of the attribute. However, it turned out to be impossible to test all supported datatype
s.
I am documenting it here in case someone ever runs into the same issue so they don't have to spend a day tracking down the issue.
Datatype Documentation
The documentation for GetTokenInformation specifies that the following datatype
s are supported for claims:
Value | Meaning |
CLAIM_SECURITY_ATTRIBUTE_TYPE_INT64
0x0001 |
The Values member refers to an array of LONG64 values. |
CLAIM_SECURITY_ATTRIBUTE_TYPE_UINT64
0x0002 |
The Values member refers to an array of ULONG64 values. |
CLAIM_SECURITY_ATTRIBUTE_TYPE_STRING
0x0003 |
The Values member refers to an array of pointers to Unicode string values. |
CLAIM_SECURITY_ATTRIBUTE_TYPE_FQBN
0x0004 |
The Values member refers to an array of CLAIM_SECURITY_ATTRIBUTE_FQBN_VALUE values. |
CLAIM_SECURITY_ATTRIBUTE_TYPE_SID
0x0005 |
The Values member refers to an array of CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE values where the pValue member of each CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE is a PSID . |
CLAIM_SECURITY_ATTRIBUTE_TYPE_BOOLEAN
0x0006 |
The Values member refers to an array of ULONG64 values where each element indicates a Boolean value. The value 1 indicates TRUE and the value 0 indicates FALSE . |
CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING
0x0010 |
The Values member refers to an array of CLAIM_SECURITY_ATTRIBUTE_OCTET_STRING_VALUE values. |
However, no matter what I did, even after modifying the AD schema in my sandbox, I could not set up a claim with CLAIM_SECURITY_ATTRIBUTE_TYPE_SID
or CLAIM_SECURITY_ATTRIBUTE_TYPE_OCTET_STRING
datatype
. I also didn't find CLAIM_SECURITY_ATTRIBUTE_TYPE_FQBN
but that is just a string
so that didn't matter. The main reason I wanted to set up those claims types was that I wanted to see how whoami displayed such claims, so that I could format my output the same way.
The Documentation Inconsistency
Eventually after a lot of searching, I found the relevant Directory Services protocol documentation. This clearly documents the datatype
of user claims on the Directory Services side:
typedef struct _CLAIM_ENTRY {
CLAIM_ID Id;
CLAIM_TYPE Type;
[switch_is(Type), switch_type(CLAIM_TYPE)]
union {
[case(CLAIM_TYPE_INT64)]
struct {
[range(1, 10*1024*1024)] ULONG ValueCount;
[size_is(ValueCount)] LONG64* Int64Values;
};
[case(CLAIM_TYPE_UINT64)]
struct {
[range(1, 10*1024*1024)] ULONG ValueCount;
[size_is(ValueCount)] ULONG64* Uint64Values;
};
[case(CLAIM_TYPE_STRING)]
struct {
[range(1, 10*1024*1024)] ULONG ValueCount;
[size_is(ValueCount), string] LPWSTR* StringValues;
};
[case(CLAIM_TYPE_BOOLEAN)]
struct {
[range(1, 10*1024*1024)] ULONG ValueCount;
[size_is(ValueCount)] ULONG64* BooleanValues;
};
[default] ;
} Values;
} CLAIM_ENTRY,
*PCLAIM_ENTRY;
This proves conclusively that on the Directory Services side, SID and Octet string are not supported claims types. This also means that the documentation for GetTokenInformation
is incorrect.
Or rather, what I suspect is that the team who defined the interface for GetTokenInformation
simply took the list of supported attribute types. Technically, every AD attribute could be used as a claims type, so rather than worry about what is currently supported as claims types, the interface has the typedef
s to deal with future changes.
Thoughts about those Unsupported datatypes
After thinking about it for a bit, I've come to the conclusion that those unsupported datatype
s do not make sense in the context of user claims.
Consider SID attributes. For example, if you want to link object A to object B, you could use a SID attribute. Conceivably, you could then define a claims type to put a requirement on this link. For example, only users whose user account is linked to a given SID can access resource R. Then again, you can also implement this using a Distinguished Name. It would also have the advantage that it's user readable, and transferrable when object B is migrated (because a DN can be reusable but an SID isn't).
An Octet string has even less possible use cases that I can see. It's basically a binary blob. Sure, you could put a whole lot of things into an Octet string. Hashes, encrypted information, certificates, whatever. The problem there would be for Kerberos to do something sensible with that information to make a yes / no decision about granting access. It would require a lot of additional complexity and it would essentially be something that looks suspiciously like a certificate which already has good support.
I've not seen a way to set up a FQBN claim either, but that is less of a problem because it's essentially just a string
so IF we would receive it, we can read it like any other string
.
Conclusion
For the purpose of testing, it is currently impossible to do anything with those unsupported datatype
s, so you don't have to worry about them. The best thing to do in my opinion is to handle the datatype
s that are supported, and trigger an error on the other type identifiers. Should Microsoft ever get around to support them, you at least get a proper error message.
History
- 7th October, 2022: First version