-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: RFC 7523 - allow multiple subjects in trust relationships #2930
Comments
Hello! I think this makes a lot of sense. It is not scalable to create trust relationships for every possible triple. @Xopek it would be awesome to hear your input on this :) |
I've been trying to find how other OAuth 2.0 Servers implement this feature but I haven't had any luck yet. The only solid example I could find is Google's service account's ability to act on behalf of any user in a Google Apps domain without consent from the user (this was already explained in the issue opened in fosite to implement this RFC ory/fosite#305 (comment)). This means that Google automatically applies a domain restriction, and I can't find any other example where the server lets the issuer sign tokens for any user without restriction. I think I wouldn't feel confortable having an issuer with the power to impersonate any user (even though we have full control over it). Our needs are related to service-account authorisation, so we would be happy with just a domain restriction. Just to make it clear, the restriction is not intended to protect the users, but to protect ourselves from our own mistakes and mitigate the damage in case the private key is leaked. Even with the current, more restrictive implementation, someone could just automatically setup trust relationships for every user and have an "unrestricted" issuer. We are looking for something in between. What do you think about having some kind of pattern matching? I'm not a big fan of regular expressions, and it would require filtering the database result again in the code, but that way anyone could setup the trust relationship to their needs (i.e. Whatever we choose to do, I'm available to implement it myself. |
Well, authorization flow using jwt is different from usual one in that manner, that we don't ask resource owner to grant us permission to represent him explicitly, but more like implicitly by showing some secret (signed jwt in our case), that only we and resource owner knows. That's why Trust was created for each subject (where subject is resource owner identity). So that Resource Owner can have granular control over who can represent him. This is especially useful, when the issuer of the jwt is the client itself. I think you don't want to allow any client, that somehow got his hand on private key to represent any Resource Owner. However in https://datatracker.ietf.org/doc/html/rfc7521 there is a second use case, when issuer of the jwt is not client itself, but Token Service. And there is a trust between Authorization Server (Hydra) and Token service. looks like it is your case, @jagobagascon. Well in that case i think it is ok to have some regex for subject, because we will have only one issuer in this case - Token service, and it will control who can request jwt, which will then be used to exchange it for token. But you should understand that in this case it is Token Service duty to control who has ability to request jwt. And jwt should be short lived and used only once to prevent attack, when someone managed to stole one jwt. Anonymous aprouch i think is not good for your case, because anonymous subject should mean anonymous resource owner, and i don't think you want to give some permissions in your system for anonymous user (resource owner). |
Yes, that's exactly our case. But I'm still sceptic about using regular expressions. Compiling a regex is an expensive and slow task. Most applications will do it once at startup and keep it in memory forever. In our case expressions would be stored in the database, so we would have to compile them every time a JWT was received (unless we add some kind of cache). This could mean compiling a single regex, or a dozen of them depending on the issuer. I think that in most cases having a simple domain restriction would be enough. If that's still too restrictive we could even allow some simple patterns like That said, I would like to know what @aeneasr thinks before doing any attempt at implementing this. |
I had some free time so I made an attempt at implementing a simple domain wide trust relationship: #2957. |
We had a little chat with @aeneasr about this feature, so I'm going to try to summarize what we talked here. I'm also going to share a small presentation we did that summarizes our problem, the steps we gave, and our proposal (Google Slides). BackgroundCurrent JWT Assertion implementation requires a trust relationship to exist between the issuer and all the subjects it is allowed to represent, this makes it not scalable enough for some use cases, like an STS (secure token service). That's why we were trying to come up with some kind of restriction that was more flexible than that. What did we try so far?We made an attempt at adding a domain restriction, but that's only useful if the subject is an email field (which is discouraged). We also thought about using some kind of regular expression, and although this is much more flexible than using a domain, it's still not really helpful, because the subject field could contain any kind of user identifier (it could just be a number, and a regex would be useless in this case). So, what are other implementations doing?
We propose more flexibilityHydra is flexible by design, it implements a flexible user management by delegating user identification to an Identity Provider. This way developers can implement user management and login themselves and use any authentication mechanisms required by their use case (token-based 2FA, SMS 2FA, etc). So we propose adding some of that flexibility to Hydra's implementation of the JWT assertion grant. We think Hydra could delegate the decision to trust a JWT token to an external service, just like it does for the login and consent flows. Here are some options: Using an RPC callSimilar to how Envoy Proxy's external authorization filter works, Hydra could make an HTTP request that would answer with an This presents some problems like how to handle timeouts or errors. Using a more powerful expression languageAnother option could be using something like Google CEL. This would allow more complex validations over the incoming JWT (not only the subject). WebAssembly (WASM)
This would allow anyone to implement their own custom logic to validate the contents of the JWT (not the signature, that's Hydra's job). This includes a database access, an remote HTTP call or whatever the system needs.
That being said, these are long term proposals. All three options involve huge changes to Hydra's codebase and require a much deeper analysis. Short term solutionSo, in the short term we propose adding trusts relationships without a subject restriction. Other tools are doing this, and it should be pretty safe as long as it cannot be done by mistake. Currently the issuer trust creation request requires the {
"subject": "subject_id",
"issuer": "issuer_id",
// other options
} So to create unrestricted issuers I would just add another field to the request: {
"unrestricted": true,
"issuer": "issuer_id",
// other options
} One of both, the new field ( I will gladly implement this myself if @aeneasr agrees on the solution. |
The short term solution sounds good to me! I am wondering whether we can find a bit clearer API naming? Maybe |
Mmmm, what about |
Although I have always preference of adding action/verb to the API properties names whenever they're booleans (like |
Preflight checklist
Describe your problem
The current implementation of the RFC requires a trust relationship to exist between the JWT issuer and the authorised subject. This means that a JWT issuer that needs to authorise many users requires a trust relationship for each of them to exist in Hydra.
I understand that in some environments the way this is implemented adds an additional layer of security: you may not have control over the JWT issuer, and this lets you limit who can be authorised by it. But in others (when the JWT issuer is part of your own infrastructure) it just adds a dependency between the issuer and Hydra and doesn't add much value in terms of security.
Our problem is that our JWT issuer does not have access to Hydra's admin backend.
Describe your ideal solution
We want a way to define trust relationships that allow the authorisation of many subjects, either by allowing any subject or only subjects under a certain domain (
*@mydomain.com
) to be authorised.This trust relationships are out of the scope of the RFC, so adding this would have no impact on RFC compliance.
Workarounds or alternatives
I guess that exposing the Hydra backend to the internet (with some kind of security of course) to create a trust relationship before issuing a new JWT token would "fix" our problem.
But there's no way we are doing this. It would create a bunch of new problems, and a new attack vector to our infrastructure.
Version
master branch (The RFC 7523 feature is yet to be released)
Additional Context
There was some discussion about this topic in #2229 (comment).
There it was proposed to use the
anonymous
keyword as a subject and make it a required parameter. And I kinda like that solution, but I'm afraid it could cause problems on systems whereanonymous
is a valid user/subject name. So I think it should just be a flag on grant creation and just keep it as a null value in the database.Pinging @Xopek as he is the one who implemented the RFC, in case he wants to share some thoughts about this.
The text was updated successfully, but these errors were encountered: