package org.pac4j.oidc.authorization.generator;

import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import net.minidev.json.JSONArray;
import net.minidev.json.JSONObject;
import org.pac4j.core.authorization.generator.AuthorizationGenerator;
import org.pac4j.core.context.WebContext;
import org.pac4j.core.profile.UserProfile;
import org.pac4j.oidc.profile.keycloak.KeycloakOidcProfile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Optional;

/**
 * Specific {@link AuthorizationGenerator} to Keycloak.
 *
 * @author Jerome Leleu
 * @since 3.4.0
 */
public class KeycloakRolesAuthorizationGenerator implements AuthorizationGenerator {

    private static final Logger LOGGER = LoggerFactory.getLogger(KeycloakRolesAuthorizationGenerator.class);

    private final String clientId;

    public KeycloakRolesAuthorizationGenerator(final String clientId) {
        this.clientId = clientId;
    }

    @Override
    public Optional<UserProfile> generate(final WebContext context, final UserProfile profile) {

        if (profile instanceof KeycloakOidcProfile) {
            try {
                final JWT jwt = SignedJWT.parse(((KeycloakOidcProfile) profile).getAccessToken().getValue());
                final JWTClaimsSet jwtClaimsSet = jwt.getJWTClaimsSet();

                final JSONObject realmRolesJsonObject = jwtClaimsSet.getJSONObjectClaim("realm_access");
                if (realmRolesJsonObject != null) {
                    final JSONArray realmRolesJsonArray = (JSONArray) realmRolesJsonObject.get("roles");
                    if (realmRolesJsonArray != null) {
                        realmRolesJsonArray.forEach(role -> profile.addRole((String) role));
                    }
                }

                if (clientId != null) {
                    final JSONObject clientRolesJsonObject = (JSONObject) jwtClaimsSet.getJSONObjectClaim("resource_access").get(clientId);
                    if (clientRolesJsonObject != null) {
                        final JSONArray vmsRolesJsonArray = (JSONArray) clientRolesJsonObject.get("roles");
                        if (vmsRolesJsonArray != null) {
                            vmsRolesJsonArray.forEach(role -> profile.addRole((String) role));
                        }
                    }
                }
            } catch (final Exception e) {
                LOGGER.warn("Cannot parse Keycloak roles", e);
            }
        }

        return Optional.of(profile);
    }
}

@@ -1839,38 +1839,32 @@
                 
-final 
 JSONObject clien
@@ -1862,44 +1862,24 @@
 ect 
-clientRolesJsonObject = (JSONObject)
+resourceAccess =
  jwt
@@ -1925,16 +1925,160 @@
 access%22)
+;%0A                    if (resourceAccess != null) %7B%0A                        final JSONObject clientRolesJsonObject = (JSONObject) resourceAccess
 .get(cli
@@ -2085,16 +2085,20 @@
 entId);%0A
+    
         
@@ -2138,32 +2138,36 @@
 ject != null) %7B%0A
+    
                 
@@ -2190,19 +2190,22 @@
 ONArray 
-vms
+client
 RolesJso
@@ -2289,15 +2289,22 @@
     
-if (vms
+    if (client
 Role
@@ -2357,11 +2357,18 @@
     
-vms
+    client
 Role
@@ -2419,32 +2419,62 @@
 String) role));%0A
+                            %7D%0A
                 

fix null pointer (#1289)