Skip to content

Conversation

captainsafia
Copy link
Member

This PR changes the schema for storing signing keys for the user-jwts tool in user secrets to support more modifications in the future. Currently, the signing key is stored in a schema that looks like this:

{
  "Authentication": {
    "Schemes": {
      "Bearer": {
         "dotnet-user-jwts": {
            "KeyMaterial": "somesigningkeyhere"
        }
      }
    }
  }
}

Where the key is stored relative to the issuer and the scheme name. The new format is as follows:

{
  "Authentication": {
    "Schemes": {
      "Bearer": {
         "SigningKey": {
            "Value": "somesigningkeyhere",
            "KeyLength": 32
        }
      }
    }
  }
}

The Issuer is not a top-level unique identifier (only the schemes are) so it doesn't make sense to nest the key under this. The top-level SigningKey property gives us a place to add more options in the future (key algo and key modifications for key length).

@captainsafia captainsafia added old-area-web-frameworks-do-not-use *DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels feature-userjwts The `dotnet user-jwts` CLI tool labels Jul 11, 2022
@captainsafia captainsafia requested review from davidfowl and a team July 11, 2022 23:32
Copy link
Member

@BrennanConroy BrennanConroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add test coverage for the value and length properties

.Where(key => key["Issuer"] == issuer)
.Select(key => key["Value"])
.OfType<string>();
foreach (var signingKey in signingKeys)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are multiple keys per issuer allowed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's possible for a single issuer/authorization server to produce a set of signing keys that the application can use with no preference between them (ref). Most of what I've seen about this touches on them being used for OIDC scenarios, but it helps to support it in some way with JWT since we want the local dev scenario to map nicely to the pod scenario.


secrets ??= new JsonObject();
var signkingKeysPropertyName = GetSigningKeyPropertyName(scheme);
var shortId = Guid.NewGuid().ToString("N").Substring(0, 8);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the id for?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a little bit of a premature optimization. One of the things we discussed was making the key generation more robust in the future (supporting setting different key lengths, support different key types, crpyto algos, etc.). I included an ID field so it'll be easier to unique identifying signing keys in the future.

Copy link
Member

@BrennanConroy BrennanConroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New format:

{
  "Authentication": {
    "Schemes": {
      "Bearer": {
        "SigningKeys": [
          {
            "Id": "FI9W0",
            "Issuer": "dotnet-user-jwts",
            "Value": "somesigningkeyhere",
            "KeyLength": 32
          }
        ]
      }
    }
  }
}

if (secrets.ContainsKey(signkingKeysPropertyName))
{
var signingKeys = secrets[signkingKeysPropertyName].AsArray();
if (reset)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so if multiple keys for the same issuer is allowed, does reset need to delete all keys from the same issuer now?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, to start, I'd only added support for multiple keys for the same issuer in the runtime, but not in the user-jwts tool. My rationale for this was that we would keep the surface area of the tool simpler than what the runtime could support. Users would still be able to support the multiple-keys-per-issuer if they set it up in config themselves, but the tool wouldn't support it.

I realize the incongruency is kinda weird though so maybe we should stick to one-key-per-issuer to keep things simple throughout the board (I want to avoid modifying too much of the existing handling in an RC1 PR).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realize the incongruency is kinda weird though

Yeah, it's strange 😌, unless we have a scenario for multiple keys in the Runtime I don't feel like we should add it yet until both areas are updated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've definitely seen examples of multiple keys from the same issuer being configured so leaving it in the runtime might be useful for now with the prospect of adding support to the tool later on.

@captainsafia captainsafia merged commit 6dd3979 into main Aug 3, 2022
@captainsafia captainsafia deleted the cs/jwt-key-config branch August 3, 2022 16:18
@ghost ghost added this to the 7.0-rc1 milestone Aug 3, 2022
@amcasey amcasey added the area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI label Jun 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-commandlinetools Includes: Command line tools, dotnet-dev-certs, dotnet-user-jwts, and OpenAPI feature-userjwts The `dotnet user-jwts` CLI tool old-area-web-frameworks-do-not-use *DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants