'How to use Keycloak Policy Enforcer with Spring boot application

Keycloak policy enforcer not working with a sample Sprint boot application.

I am using Keycloak version 6.0.1 and trying to integrate a sample Sprint boot application (Sprint boot version 2.1.3). My objective to setup policies and permissions in Keycloak and use Keycloak policy enforcer in my sample Spring boot application so that all authorization decisions are automatically enforced using appropriate permission defined in Keycloak and no code is required in Sample application.

My Sample spring boot application just prints a list of users from a in memory List:

public class JPAUserResource {

    @Autowired
    private UserRepository userRepo;

    @GetMapping(path = "/jpausers")
    public List<JPAUser> retrieveAllUsers() {
        return userRepo.findAll();
    }
}

My application.properties file has following content:

server.port=38080
spring.jpa.show-sql=true
spring.h2.console.enabled=true
logging.level.org.springframework.security=DEBUG
logging.level.org.keycloak.adapters.authorization=DEBUG
#Keycloak Configuration
keycloak.auth-server-url=http://192.168.154.190:18180/auth
keycloak.realm=master
keycloak.resource=login-app
keycloak.principal-attribute=preferred_username
keycloak.credentials.secret=195925d6-b258-407d-a65d-f1fd12d7a876
keycloak.policy-enforcer-config.enforcement-mode=enforcing
keycloak.realm-key=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjyYRe6LxBxO9hVtr4ScsMCBp3aPE9qbJLptPIMQCZR6JhVhOxA1kxhRmVYHXR5pdwiQWU8MriRhAY1JGniG6GNS1+BL+JaUiaGxov4rpD2SIMdrs8YjjSoD3Z8wvsMAopzWG48i9T/ppNaqKTkDZHbHAXOYJn+lymQ4EqpQrJ1Uh+SUA8XcLvWUQ12ty9BieujudWhnAgQ4zxyJY3I8sZwjaRIxndzSlyPJo45lWzXkpqcl92eU/Max7LRM4WKqsUvu86DgqlXbJcz8T+GUeF30ONQDSLX9rwNIT4ZiCVMT7x6YfKXZW6jxC0UiXxZuT23xk8A9iCP4rC9xo1NfGTwIDAQAB
keycloak.policy-enforcer-config.paths[0].path=/jpausers
keycloak.policy-enforcer-config.paths[0].methods[0].method=GET

My Keycloak authorization settings are as below:

{
  "allowRemoteResourceManagement": true,
  "policyEnforcementMode": "ENFORCING",
  "resources": [
    {
      "name": "Default Resource",
      "type": "urn:login-app:resources:default",
      "ownerManagedAccess": false,
      "attributes": {},
      "_id": "501febc8-f3e1-411f-aecf-376b4786c24e",
      "uris": [
        "/*"
      ]
    },
    {
      "name": "jpausers",
      "ownerManagedAccess": false,
      "displayName": "jpausers",
      "attributes": {},
      "_id": "a8f691db-39ef-4b2c-80fb-37224e270f1e",
      "uris": [
        "/jpausers"
      ],
      "scopes": [
        {
          "name": "GET"
        },
        {
          "name": "POST"
        }
      ]
    }
  ],
  "policies": [
    {
      "id": "94518189-3794-451c-9996-eec22543d802",
      "name": "Default Policy",
      "description": "A policy that grants access only for users within this realm",
      "type": "js",
      "logic": "POSITIVE",
      "decisionStrategy": "AFFIRMATIVE",
      "config": {
        "code": "// by default, grants any permission associated with this policy\n$evaluation.grant();\n"
      }
    },
    {
      "id": "0242cf72-365d-49ae-8d5b-4ced24736f24",
      "name": "test_jpa",
      "type": "role",
      "logic": "POSITIVE",
      "decisionStrategy": "UNANIMOUS",
      "config": {
        "roles": "[{\"id\":\"jpa\",\"required\":false}]"
      }
    },
    {
      "id": "5c34e2b4-a56a-45f9-a1cc-94788bcb41b0",
      "name": "test_perm1",
      "type": "resource",
      "logic": "POSITIVE",
      "decisionStrategy": "UNANIMOUS",
      "config": {
        "resources": "[\"jpausers\"]",
        "applyPolicies": "[\"test_jpa\"]"
      }
    }
  ],
  "scopes": [
    {
      "id": "4ee351e6-7095-453a-a4f4-badbc9ec1ba0",
      "name": "GET",
      "displayName": "GET"
    },
    {
      "id": "9119aab2-75a0-49d1-a076-8d9210c3e457",
      "name": "POST",
      "displayName": "POST"
    }
  ]
}

When I send a request to my Rest API '/jpausers', it fails with following messages on console:

*19:17:52.044 [http-nio-38080-exec-1] INFO  o.k.a.authorization.PolicyEnforcer - Paths provided in configuration.
19:17:52.045 [http-nio-38080-exec-1] DEBUG o.k.a.authorization.PolicyEnforcer - Trying to find resource with uri [/jpausers] for path [/jpausers].
19:17:52.151 [http-nio-38080-exec-1] DEBUG o.k.a.authorization.PolicyEnforcer - Initialization complete. Path configurations:
19:17:52.151 [http-nio-38080-exec-1] DEBUG o.k.a.authorization.PolicyEnforcer - PathConfig{name='null', type='null', path='/jpausers', scopes=[], id='a8f691db-39ef-4b2c-80fb-37224e270f1e', enforcerMode='ENFORCING'}
19:17:52.154 [http-nio-38080-exec-1] DEBUG o.k.a.authorization.PolicyEnforcer - Policy enforcement is enabled. Enforcing policy decisions for path [http://192.168.109.97:38080/jpausers].
19:17:52.156 [http-nio-38080-exec-1] DEBUG o.k.a.a.KeycloakAdapterPolicyEnforcer - Sending challenge
19:17:52.157 [http-nio-38080-exec-1] DEBUG o.k.a.authorization.PolicyEnforcer - Policy enforcement result for path [http://192.168.109.97:38080/jpausers] is : DENIED
19:17:52.157 [http-nio-38080-exec-1] DEBUG o.k.a.authorization.PolicyEnforcer - Returning authorization context with permissions:*

UMA Authorization is disabled. I had first retrieved access token using Openid Connect token API with Password credentials grant type and then I am trying to access my Rest API '/jpausers' with access token.

Can someone help with the issue here ? How do I fix this ? Do I have to enable UMA to make policy enforcer work ?



Solution 1:[1]

With quick look, I can see your mapping is not complete in application.properties, you have not mapped your HTTP method to scope you have configured in keycloak. Some thing like this

keycloak.policy-enforcer-config.paths[0].path=/jpausers
keycloak.policy-enforcer-config.paths[0].methods[0].method=GET 
keycloak.policy-enforcer-config.paths[0].methods[0].scopes[0]=GET

Solution 2:[2]

I think you are missing keycloak.securityConstraints[0].securityCollections[0].name= jpausers

Solution 3:[3]

I had the same issue and I was able to resolve it with similar settings in my application properties yaml file as shown below:

    keycloak:
      security-constraints:
        - auth-roles: 
          - "*"
      security-collections:
        - name: 
          patterns:
          - /*

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ravthiru
Solution 2 mehdi mohammadi
Solution 3