dlcs / protagonist

MIT License
7 stars 2 forks source link

Add JWT-based Auth option for API requests #900

Closed p-kaczynski closed 4 weeks ago

p-kaczynski commented 1 month ago

I tried to balance the non-invasive, limited change with doing it at least semi-properly.

I think it should be fine, I ran it locally and it behaved as expected.

Note: this by default will be disabled, config needs to be provided for it to work:

  "DLCS": {
    ...,
    "JwtKey": "iy/umankHwi8fWcUOv0skf4b3vmWip9VhTWxneHokwI=",
    "JwtValidIssuers": [
      "urn:caspian:site:default"
    ]
  }

don't worry, this key is made up for this PR note only

of course key can be any Base64 encoded data, e.g.:

var key = new byte[32];
var rng = System.Security.Cryptography.RandomNumberGenerator.Create();
rng.GetBytes(key);

Convert.ToBase64String(key); // returns the value for config

I opted NOT to include default because it'd surely end up being the actual key in prod deployments at some point down the line ;)

The DLCS:JwtValidIssuers:# should be urn:caspian:site:default, which is the default value used by Portal, though the final term (here default) can be whatever, configurable per env (so even if key reuse happens we still can limit (or allow) cross-env calls.


This will split off the existing path into its own method, do JWT things and if it's indeed a DLCS Customer Id claim, correctly signed, will load the customer from repo by that id and use the first key from the list for this customer, before returning to the usual flow.

I split the code into respective flows, but I really didn't want to throw exceptions for flow control in sth that's ran on every request, exposed to the world, as it can create spurious overheads. So to keep it hopefully light it just returns a wrapped string (FailedCaller) in case of auth failure, which gets turned into AuthenticationResult.

The code could be nicer I'm sure, but I'd prob have to refactor much, much more, and I really, really don't want to break stuff, so make your judgement ;)