I am trying to implement authorization for this use case:
- user can access only his own resources
- admin can access everything
I am trying out Keycloak and it's resource server. For testing purposes and to understand these scopes and permissions and stuff, I have created test client weather-api
and one resource Weather
with url /weatherforecast
.
Then I have scope weather:read
and policy that every user with role weatherer
can read that resource.
Now when I try to evaluate on a user with that role, I get PERMIT
:
and another user without this role gets DENY.
so I guess my policies and permissions are set correctly.
When I try to use this from my service with user-managed-access disabled, I get permit too.
But when I enable user-managed-access
, it fails.
I see in debug log that it gets permissions token:
{
...
"permissions": [
{
"scopes": [
"weather:read"
],
"rsid": "ae5ac493-b7dc-481e-9204-a664d1558a51"
}
],
...
}
but then the next message is
Policy enforcement result for path [http://192.168.0.9:5001/weatherforecast] is : DENIED
I tried to debug Keycloak library and found something I don't really understand.
In KeycloakAdapterPolicyEnforcer
this part of code:
@Override
protected boolean isAuthorized(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, AccessToken accessToken, OIDCHttpFacade httpFacade, Map<String, List<String>> claims) {
AccessToken original = accessToken;
if (super.isAuthorized(pathConfig, methodConfig, accessToken, httpFacade, claims)) {
return true;
}
accessToken = requestAuthorizationToken(pathConfig, methodConfig, httpFacade, claims);
if (accessToken == null) {
return false;
}
...
}
private AccessToken requestAuthorizationToken(PathConfig pathConfig, PolicyEnforcerConfig.MethodConfig methodConfig, OIDCHttpFacade httpFacade, Map<String, List<String>> claims) {
if (getEnforcerConfig().getUserManagedAccess() != null) {
return null;
}
...
}
so when UserManagedAccess is not null, requestAuthorizationToken
returns null and then it acts like the user is unauthorized with HTTP 401
.
What am I missing here? Why it works only without UMA?
I have looked at these (app-authz-uma-photoz, devconf2019-authz) examples and haven't noticed what I am missing.
Except they are actually creating some resources for users from the Java app, I'm not. But I guess it shouldn't matter if I'm protecting user created resources or single "pre-made" URL, right? It should depend only on correct permissions and since they evaluate to PERMIT
so I don't see why this doesn't work.
And one more question. Isn't this UMA thing overkill for just "user can access his own, admin can access everything" case when there will never be any sharing between users? I was thinking about some simpler way that could work without creating user resources in Keycloak but I couldn't think of anything, I believe I still need to have connected user ID with some resource ID to make this working.