Repository navigation
AuthZen Evaluation API - #47632
AuthZen Evaluation API#47632
Conversation
4d1fe11 to
f5d790f
Compare
fb41003 to
041f8fa
Compare
There was a problem hiding this comment.
@ryanemerson Only a few comments.
041f8fa to
742318a
Compare
|
Additional checks added so that we ensure that a client is enabled and that the token is associated with the client I have moved all AuthZen functionality and tests from When trying my original solution with the AuthZen Interop tests, I found some issues with my implementation which I have also addressed. To help ensure interop works as expected, I have added an additional test N.B. Unfortunately the interop tests utilise Base64 IDs for |
8e1574b to
71a3001
Compare
Closes keycloak#47629 Signed-off-by: Ryan Emerson <remerson@ibm.com>
71a3001 to
28b52f1
Compare
|
Great to see AuthZen land in Keycloak! The OpenID Foundation Conformance Testing Suite has some support for testing the AuthZen Evaluation API that you might want to checkout: https://gitlab.com/openid/conformance-suite/-/tree/master/src/main/java/net/openid/conformance/authzen?ref_type=heads See also: https://gitlab.com/openid/conformance-suite/-/wikis/Developers/Build-&-Run |
|
Thanks @thomasdarimont , I wasn't aware of that. I'll take a look 👍 |
There was a problem hiding this comment.
Thanks, @ryanemerson. LGTM. Only a single comment.
Not sure if you want to update the copyright (year) in some files. Not a blocker.
| void index(BuildProducer<IndexDependencyBuildItem> indexDependencyBuildItemBuildProducer) { | ||
| indexDependencyBuildItemBuildProducer.produce(new IndexDependencyBuildItem("org.liquibase", "liquibase-core")); | ||
| indexDependencyBuildItemBuildProducer.produce(new IndexDependencyBuildItem("org.keycloak", "keycloak-services")); | ||
| indexDependencyBuildItemBuildProducer.produce(new IndexDependencyBuildItem("org.keycloak", "keycloak-authzen-services")); |
There was a problem hiding this comment.
Isn't enough to add an empty META-INF/beans.xml file at authzen-services? IIRC, that was enough for SCIM and I remember trying the same change but later dropped it.
There was a problem hiding this comment.
That works! I have reverted the changes to KeycloakProcessor and added the beans.xml file.
| StoreFactory storeFactory = authorization.getStoreFactory(); | ||
|
|
||
| ClientModel client; | ||
| if (request.subject().type() == AuthZen.SubjectType.CLIENT) { |
There was a problem hiding this comment.
Is it by design in this first MVP that the resource server used for policy evaluation is implicitly derived from the Bearer token claim?
This couples “who is calling the PDP” with “which policies to evaluate,” which breaks the gateway pattern when externalizing authorization: a gateway authenticating with its own token cannot evaluate user access against a different resource.
I’m not sure if I might be missing something.
There was a problem hiding this comment.
I think the assumption here is that the PEP is running on the resource server side, checking permissions for protected resources within the resource server. In this case, the PEP will always authenticate using its own token (RS client credentials) and evaluate permissions based on a given (USER) subject.
When the PDP is running behind a gateway, there must be some way to resolve the resource server and then invoke the PDP with a proper token.
Or some other mechanism ...
In authz services, we allow fetching permissions from whatever resource server based on an audience parameter. But in AuthZen (specs), this is seems to be a deployment concern and up to the implementation to decide how to do it?
There was a problem hiding this comment.
In relation to the authentication process between PDP and PEP, the standard use “SHOULD” which means it is up to the PDP to decide which mechanism to use. Options may include mutual TLS, OAuth-based authentication, or API keys.
The PDP SHOULD authenticate the calling PEP
In our case, being both an IdP and an AuthZEN PDP, it makes sense to simplify integration when the PEP is at the API or MCP level and functions as an OAuth Resource Server. In this scenario, token claims can be used when building the AuthZEN Subject-Action-Resource-Context (SARC) model. However, there is no strict relationship between how the PEP is authenticated and how the PDP parses the AuthZEN request.
Regarding authorization architecture, in my experience, FGA can be applied at the MCP/API level, while CGA is applied at the API or Agent/MCP Gateway level.
Since this is the first MVP, we can clarify these assumptions in the documentation, particularly the supported authentication mechanisms between PDP and PEP, as well as how the bearer token is used when building the SARC model.
Signed-off-by: Ryan Emerson <remerson@ibm.com>
Signed-off-by: Ryan Emerson <remerson@ibm.com>
|
I have pushed two commits addressing the outstanding issue. I think we should be good to go now. |
| AuthZen.Subject subject = request.subject(); | ||
| Identity identity = switch (subject.type()) { | ||
| case USER -> { | ||
| UserModel user = session.users().getUserById(realm, subject.id()); |
There was a problem hiding this comment.
The current implementation resolves users exclusively via session.users().getUserById(realm, subject.id()), which implicitly assumes that the PEP can provide the Keycloak internal user ID as subject.id.
In practice, however, a PEP typically only has access to an OAuth access token. Using the sub claim as subject.id may work when sub equals the internal user ID, but this breaks when pairwise subject identifiers are enabled, since sub then becomes client-scoped and no longer maps to a Keycloak user.
This also deviates from the non-normative AuthZen examples, where subject.id is illustrated using human-readable identifiers such as email addresses.
Would it make sense to consider alternative user-resolution strategies (e.g. username/email lookup) that better align with expected PEP inputs?
There was a problem hiding this comment.
+1 I definitely think it would be useful to explore such strategies.
Possible solutions could be making use of the request's subject.properties or providing different subect.type values to control the lookup behaviour.
There was a problem hiding this comment.
I have created #48285 to track the work we want to complete in order for AuthZen support to be good enough for a MVP Experimental feature.
As part of this work, I propose that we make it so that the default lookup semantics for users is based upon the username field, not the UUID like it currently is #48287
We can then add additionally look up strategies based upon the subject.type value with an optional qualifier subject.type=user<.qualifier>, e.g.:
subject.type=user: Lookup based on usernamesubject.type=user.id: AuthZEN allow configurable subject lookup semantics #48288subject.type=user.email: Lookup based on email, 4xx response thrown if a duplicate emails enabled.subject.type=user.<some-other-field>?
The intention would be to just allow username and UUID lookups at first.
|
We are merging this core set of capabilities so that we can start working on follow-ups (some already being discussed here). |
Closes #47629
The Evaluation API is exposed at
/realms/{realm}/authzen/access/v1/evaluation.Two subject.type values are supported:
client: Lookup the KC client identity based upon the passedsubject.iduser: Lookup the KC user identiy based upon the passedsubject.id. The ClientModel is retrieved using the client the request token is issued for.For both
clientanduserthe request properties are merged with those associated with the looked up resource. Should we allow this or just allow the looked up client/user properties and ignore thesubject.propertiesfor these types?Request
resource.propertiesare currently ignored as there did not seem to be an obvious place where to integrate this with the existing Authorization APIs