Skip to content

System.NotSupportedException on ClaimExtensions.Remove with fixed-size claim collection #196

@marcominerva

Description

@marcominerva

Describe the bug

When authenticating, a System.NotSupportedException is thrown with the message "Collection was of a fixed size.".

Error Details

The exception occurs in the SimpleAuthentication.ClaimExtensions.Remove method when using an array of claims that is fixed-size and attempting to remove an item from it. This is visible in the following stack trace:

System.NotSupportedException: Collection was of a fixed size.
   at System.SZArrayHelper.Remove[T](T _)
   at SimpleAuthentication.ClaimExtensions.Remove(IList`1 claims, String type) in /_/src/SimpleAuthentication.Abstractions/ClaimExtensions.cs:line 35
   at SimpleAuthentication.ClaimExtensions.Update(IList`1 claims, String type, String value) in /_/src/SimpleAuthentication.Abstractions/ClaimExtensions.cs:line 21
   at SimpleAuthentication.ApiKey.ApiKeyAuthenticationHandler.<>c__DisplayClass2_0.<HandleAuthenticateAsync>g__CreateAuthenticationSuccessResult|1(String userName, IList`1 claims) in /_/src/SimpleAuthentication/ApiKey/ApiKeyAuthenticationHandler.cs:line 64
   at SimpleAuthentication.ApiKey.ApiKeyAuthenticationHandler.HandleAuthenticateAsync() in /_/src/SimpleAuthentication/ApiKey/ApiKeyAuthenticationHandler.cs:line 38
   ...

Reproduction

The problem occurs in scenarios such as this API key validator implementation:

public class ApiKeyValidator(AtiPortalAuthDataContext commonDbContext) : IApiKeyValidator
{
    public Task<ApiKeyValidationResult> ValidateAsync(string apiKey)
    {
        var validKey = "f1I7S5GXa4wQDgLQWgz0";
        var isValid = CryptographicOperations.FixedTimeEquals(MemoryMarshal.AsBytes(validKey.AsSpan()), MemoryMarshal.AsBytes(apiKey.ToString().AsSpan()));

        if (!isValid)
        {
            return Task.FromResult(ApiKeyValidationResult.Fail("Chiave API non valida"));
        }

        var userName = "Service User";
        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new Claim(ClaimTypes.NameIdentifier, Guid.NewGuid().ToString()),
            new Claim(ClaimTypes.Name, userName),
            new Claim(JwtRegisteredClaimNames.GivenName, "Service"),
            new Claim(JwtRegisteredClaimNames.FamilyName, "User")
        };

        return Task.FromResult(ApiKeyValidationResult.Success(userName, claims));
    }
}

If claims.ToList() is used before returning, the issue does not arise. The same class of issue can also affect BasicAuthentication and JwtBearer validators that use arrays or other fixed-size collections for claims.

Expected behavior

ClaimExtensions.Remove and related methods should work with any IList<Claim> implementation, and not attempt to remove from fixed-size collections such as arrays. There should be either:

  • Input validation and/or defensive copying to a modifiable collection,
  • Or better documentation stating that only modifiable collections are accepted.

Additional context

This error can break authentication flows and is non-obvious to diagnose for consumers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions