Add Client resource type and scopes to authorization schema#5
Add Client resource type and scopes to authorization schema#5ShashankFC wants to merge 1 commit into
Conversation
…valuation implementation for ClientsPermissionsV2 Closes #35564 Signed-off-by: Martin Kanis <mkanis@redhat.com>
1 similar comment
|
Claude finished @ShashankFC's task in 1m 52s —— View job Code Review CompleteI've reviewed the PR that adds Client resource type and scopes to the authorization schema. Here's my detailed feedback: SummaryThis PR implements fine-grained authorization for Clients in Keycloak's V2 authorization framework. The implementation adds the Positive Aspects
Issues and Recommendations1. Inconsistent Client Resolution Logic (AdminPermissionsSchema.java:93-94, 175-183)The private String resolveClient(KeycloakSession session, String id) {
RealmModel realm = session.getContext().getRealm();
ClientModel client = session.clients().getClientById(realm, id);
if (client == null) {
client = session.clients().getClientByClientId(realm, id);
}
return client == null ? null : client.getId();
}Issue: This method accepts either a client UUID or clientId string, but always returns the UUID. This is inconsistent with the Recommendation: Add documentation to clarify that this method normalizes any client identifier to the UUID. 2. Potential NullPointerException (ClientPermissionsV2.java:214-222)Resource resource = resourceStore.findByName(server, client.getId(), server.getId());
if (resource == null) {
// check if there is permission for "all-clients". If so, load its resource and proceed with evaluation
resource = AdminPermissionsSchema.SCHEMA.getResourceTypeResource(session, server, AdminPermissionsSchema.CLIENTS_RESOURCE_TYPE);
if (authz.getStoreFactory().getPolicyStore().findByResource(server, resource).isEmpty()) {
return false;
}
}Issue: After Severity: High - This could cause a NullPointerException. Recommendation: Add null check: if (resource == null) {
resource = AdminPermissionsSchema.SCHEMA.getResourceTypeResource(session, server, AdminPermissionsSchema.CLIENTS_RESOURCE_TYPE);
if (resource == null || authz.getStoreFactory().getPolicyStore().findByResource(server, resource).isEmpty()) {
return false;
}
}3. Code Duplication (ClientPermissionsV2.java:207-235, 237-260)The two Recommendation: Consider extracting the common evaluation logic into a private helper method to reduce duplication and improve maintainability. 4. Unused Method Parameter (ClientPermissionsV2.java:262-272)private EvaluationContext getEvaluationContext(ClientModel authorizedClient, AccessToken token) {
ClientModelIdentity identity = new ClientModelIdentity(session, authorizedClient, token);
return new DefaultEvaluationContext(identity, session) {
@Override
public Map<String, Collection<String>> getBaseAttributes() {
Map<String, Collection<String>> attributes = super.getBaseAttributes();
attributes.put("kc.client.id", List.of(authorizedClient.getClientId()));
return attributes;
}
};
}Issue: This method is never called in the class. It appears to be leftover code or prepared for future functionality. Recommendation: Either remove this method if unused, or add a TODO comment explaining its future purpose. 5. Missing Documentation (ClientPermissionEvaluator.java:30-196)The interface has been updated with V2-specific comments, but the overall javadoc could be clearer about when V2 behavior applies vs V1. Recommendation: Add class-level documentation explaining the difference between V1 and V2 implementations and when each applies (controlled by the 6. Test Cleanup Logic (PermissionClientTest.java:79-83)@AfterEach
public void onAfter() {
ScopePermissionsResource permissions = getScopePermissionsResource(client);
permissions.findAll(null, null, null, -1, -1).forEach(p -> permissions.findById(p.getId()).remove());
}Issue: This cleanup could fail silently if permission removal fails, and it doesn't follow the cleanup pattern used in Recommendation: Consider using the realm cleanup mechanism for consistency and better error handling. 7. Error Handling in Schema Initialization (AdminPermissionsSchema.java:106-110)resource.updateScopes(getResourceTypes().get(resourceType).getScopes().stream().map(scopeName -> {
Scope findByName = scopeStore.findByName(resourceServer, scopeName);
if (findByName == null) throw new ModelException("No scopes found.");
return findByName;
}).collect(Collectors.toSet()));Issue: The error message "No scopes found." doesn't indicate which scope was not found, making debugging difficult. Recommendation: Improve error message: if (findByName == null) throw new ModelException("Scope '" + scopeName + "' not found for resource type '" + resourceType + "'.");8. Unclear Logic in getResourceName (AdminPermissionsSchema.java:311-322)The method only handles the USERS resource type case but doesn't have an else clause for CLIENTS: if (USERS.getType().equals(resourceType)) {
if (resource.getName().equals(USERS_RESOURCE_TYPE)) {
return "All users";
}
UserModel user = session.users().getUserById(session.getContext().getRealm(), resource.getName());
if (user == null) {
throw new ModelIllegalStateException("User not found for resource [" + resource.getId() + "]");
}
return user.getUsername();
}
return resource.getDisplayName();Issue: Since CLIENTS resource type was added, this method should handle that case too for consistent naming. Recommendation: Add handling for CLIENTS resource type: if (CLIENTS.getType().equals(resourceType)) {
if (resource.getName().equals(CLIENTS_RESOURCE_TYPE)) {
return "All clients";
}
ClientModel client = session.clients().getClientById(session.getContext().getRealm(), resource.getName());
if (client == null) {
throw new ModelIllegalStateException("Client not found for resource [" + resource.getId() + "]");
}
return client.getClientId();
}Minor Observations
ConclusionThe implementation is solid and follows established patterns. The critical issue is the potential NullPointerException in Recommendation: Address the NullPointerException issue (#2) and consider implementing the missing CLIENTS handling in |
Test 5nn---nReplicated from ai-code-review-evaluation/keycloak-greptile#5