Prevent Public Resource Creation
From https://github.com/cassproject/CASS/issues/226
The goal of this change is to allow server admins to prevent public creation of competencies, frameworks, etc. by requiring that those requests be associated with a logged-in user and presumably leave that enforcement to an OIDC provider.
Security Impact: This will hopefully harden CASS against fuzz attackers. Presumptive Impact: Servers configured this way will require a slightly modified UI that will understand when their respective instance requires authorized users and disable their "Add New __" widgets when necessary. These changes aren't included here and will be added later.
@Lomilar My initial stab is to just add a middleware block between the auth and skyrepo steps, but this ends up snagging internal user creation requests made by the auth step -- calling the global EcRepository instance when it detects a new user login.
https://github.com/cassproject/CASS/blob/master/src/main/server/shims/auth.js#L111
Currently the EcRepository seems to route its requests into the same /api endpoint as everything else, but I didn't notice any special headers / keys on those auto-generated requests to distinguish them from requests made by the client. Is there a way to validate those internal requests so that this block can ignore them?
Open to alternatives also.
There is a missing authentication method, which is the only real method, which is via signature sheets (can be present in headers or in a POST).
I'd really look at injecting something like this into the signature sheet validation checks, since all OIDC/PKI (client side certs)/JWT based authentication ultimately results in a signature sheet proxy so that data modifications have the correct fingerprints.
https://github.com/cassproject/CASS/blob/bf3be7585073d7f86060f763a11e30eb90ecbf57/src/main/server/skyRepo.js#L150
To see where this translation occurs, look at https://github.com/cassproject/CASS/blob/master/src/main/server/shims/auth.js
This puts shims in to convert authentication of all sorts into signature sheets, something we call a "securing proxy".
To put it explicitly:
- [ ] If there's no signatures in the signature sheet, there should be a rejection.
That was the first try, but could've sworn I was still logging empty sheets when the user was logged in.
Will try that next then.
That may be -- gets and whatnot don't have signature sheets necessarily, but let's ram our faces into that roadblock and find a way through.
I think the intent is to provide something a bit more useful and nuanced than border security, which anyone deploying cass could put in.
So I tried a few different approaches based on your initial suggestion.
- Inserting a block into the last part of
signatureSheetcall ended up still allowing resources to be created anonymously, but not viewed as the search did get blocked.
let blockPublicCreation = !!process.env.NO_PUBLIC;
if (blockPublicCreation && sigSheet.length == 0)
error("Forbidden", 403);
this.ctx.put("signatureSheet", sigSheet);
return sigSheet;
-
Adding a flag to the
signatureSheetcall to indicate whether the requester intended to create resources, but this ended up still being omitted if thevalidateSignaturecall was creating something new as it didn't need to validate ownership for those. -
Ignoring the signature sheet in
ctxif the request expects to make resources, which does work for existing users but ends up with the same issue as before where new users cause things to get squirrely and error out.
About there, looking for a way to confirm that the new object created with the auth handler was creating using the internal EcPpk class
if (p == null)
{
p = new EcPerson();
p.addOwner(i.ppk.toPk());
p.assignId(repo.selectedServerProxy == null ? repo.selectedServer : repo.selectedServerProxy,i.ppk.toPk().fingerprint());
p.name = name;
p.email = email;
await repo.saveTo(p);
}
Namely, this modified part of the validateSignatures call:
var signatures = await ((signatureSheet).call(this));
let signaturesPresent = signatures.length > 0;
let signaturesRequired = !!process.env.NO_PUBLIC;
if (oldGet == null) {
if (signaturesRequired && !signaturesPresent)
error("Forbidden, no public etc.", 403);
else
return null;
}
My thought atm is that validateSignatures will need to accept an argument for the object being created, which would let us check its owner and ID as being correctly from the EcPpk class in the cass library.
@Lomilar looking through the new user object and the signature workflow, I'm not seeing a way to verify the first-time user's EcRepo.saveTo() call with signatures as it only has a public key initially -- with the signature sheet being generated afterwards for the ID manager
await repo.saveTo(p);
}
let host = repo.selectedServerProxy == null ? repo.selectedServer : repo.selectedServerProxy;
let signatureSheet = await eim.signatureSheet(60000, host );
req.headers.signatureSheet = signatureSheet;
req.eim = eim;
Is there any other way to verify the authenticity of this initial Create Person job?
It looks like there's an eim overload for the saveTo function which does create a signature for the request at least, will look at that.
edit: looks like that did the trick -- may have unintended consequenes though if it's expecting to always use the default EcIdentityManager instance?
Will be testing this on a live instance today to see if anything weird comes up.
So after a day or so and adjusting the changes to be a bit more precise, it seems to be behaving without any issues:
- Resource creation requires a logged-in user, giving a 403 otherwise
- Previously-existing anonymous resources can still be modified / deleted by anyone
- Only owners can modify their own resources
@Lomilar for the UI portion, the least invasive option might be exposing some sort of /api/about on the server that would return a set of feature properties -- with the first (and only atm) being blockPublicCreation. The Vue components would then be rebound and enabled / disabled depending on the combination of there being a known user and the server blocking public additions.
We're a bit pressed this week but I will work the UI side of this PR if the /about approach seems fine.
Kudos, SonarCloud Quality Gate passed! 
0 Bugs
0 Vulnerabilities
0 Security Hotspots
0 Code Smells
No Coverage information
0.0% Duplication