admin管理员组

文章数量:1389260

I have gradle project lets call it keycloak-poc which uses keycloak 26.1.3 version. Here is my docker-compose.yaml file which I am using to start a docker cluster with 2 containers, 1 postgres db and the other is keycloak.

name: keycloak-poc
services:
  postgres:
    image: postgres:latest
    container_name: keycloak_postgres
    restart: always
    environment:
      POSTGRES_PASSWORD: keycloak
      POSTGRES_USER: keycloak
      POSTGRES_DB: kc_database
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data
  keycloak:
    image: quay.io/keycloak/keycloak:26.1.3
    environment:
      KC_DB: postgres
      KC_DB_URL: jdbc:postgresql://postgres:5432/kc_database
      KC_DB_USERNAME: keycloak
      KC_DB_PASSWORD: keycloak
      KC_HOSTNAME: localhost
      KEYCLOAK_ADMIN: xxxx
      KEYCLOAK_ADMIN_PASSWORD: xxxx
      AZURE_AD_CLIENT_ID: xxxx-xxxx-xxxx-xxxx-xxxx
      AZURE_AD_CLIENT_SECRET: xxxxxxxxxxxxxxxx
      AZURE_AD_TENANT_ID: xxxxx-xxx-xxx-xxx-xxx
      KC_LOG_LEVEL: DEBUG
      QUARKUS_LOG_LEVEL: DEBUG
      DEBUG: TRUE
      DEBUG_PORT: 8787
      JAVA_OPTS: "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:8787"

    ports:
      - "8080:8080"
      - "8787:8787"
    volumes:
      - type: bind
        source: ./build/libs/keycloak-poc-1.0-SNAPSHOT.jar
        target: /opt/keycloak/providers/keycloak-poc-1.0-SNAPSHOT.jar
      - ./imports:/opt/keycloak/data/import
      - ./build/external-libs:/opt/keycloak/providers
    command:
      - "start-dev"
      - "--import-realm"
      - "--verbose"  # Add the verbose flag to gather more logs
    depends_on:
      - postgres

volumes:
  postgres_data:
    driver: local

Here is my application.properties file:

# Log settings
quarkus.log.level=TRACE
quarkus.hibernate-orm.log.sql=true

# Datasource custds
quarkus.datasource.custds.db-kind=oracle
quarkus.datasource.custds.username=xxxxxx
quarkus.datasource.custds.password=xxxxxx
quarkus.datasource.custds.jdbc.url=jdbc:oracle:thin:@//xx.xx.xx.xx:1521/xxxxxx
quarkus.datasource.custds.jdbc.driver=oracle.jdbc.xa.client.OracleXADataSource
quarkus.datasource.custds.jdbc.datasource-class=oracle.jdbc.xa.client.OracleXADataSource
quarkus.datasource.custds.jdbc.transactions=xa

# Hibernate ORM - Multiple Persistence Units Configuration
quarkus.hibernate-orm.active-persistence-units=custds
quarkus.hibernate-orm.persistence-units."custds".packages=xx.xx.keycloak.mappers.oidc

# Ignore any persistence.xml
quarkus.hibernate-orm.persistence-xml.ignore=true

# Make sure to use the correct Persistence Unit name
quarkus.hibernate-orm.persistence-unit-name=custds
quarkus.hibernate-orm.persistence-unit=custds

# Hibernate ORM enabled
quarkus.hibernate-orm.enabled=true

The project must be able to connect to multiple databases, becase it will be integrated with a legacy system so this I cannot change.

I am trying to create a protocol mapper which I will use to call legacy code which requires EntityManager instance. My idea is to get an instance of the entity manager for the datasource "custds" which I have defined in the application.properties file and call the legacy code..

Here is the code for my protocol mapper. The protocol mapper is properly displayed in the keycloak UI and the code is executed when I try to generate JWT token using the keycloak api(http://localhost:8080/realms/xxxxx/protocol/openid-connect/token)

package xx.xx.keycloak.mappers.oidc;

import jakarta.activation.DataSource;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;
import jakarta.persistence.PersistenceUnit;
import .keycloak.models.ClientSessionContext;
import .keycloak.models.KeycloakSession;
import .keycloak.models.ProtocolMapperModel;
import .keycloak.models.UserSessionModel;
import .keycloak.protocol.oidc.mappers.*;
import .keycloak.provider.ProviderConfigProperty;
import .keycloak.representations.IDToken;

import javax.naming.Context;
import javax.naming.InitialContext;
import java.util.ArrayList;
import java.util.List;

public class XXXXProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper, OIDCIDTokenMapper, UserInfoTokenMapper {

    private static final List<ProviderConfigProperty> configProperties = new ArrayList<>();

    static {
        OIDCAttributeMapperHelper.addTokenClaimNameConfig(configProperties);
        OIDCAttributeMapperHelper.addIncludeInTokensConfig(configProperties, XXXXProtocolMapper.class);
    }

    public static final String PROVIDER_ID = "oidc-xxxx-mapper";

    @Override
    public String getDisplayCategory() {
        return TOKEN_MAPPER_CATEGORY;
    }

    @Override
    public String getDisplayType() {
        return "xxxxxxxxxxx";
    }

    @Override
    public String getHelpText() {
        return "xxxxxxxxxxx";
    }

    @Override
    public List<ProviderConfigProperty> getConfigProperties() {
        return configProperties;
    }

    @Override
    public String getId() {
        return PROVIDER_ID;
    }

    @Override
    protected void setClaim(IDToken token, ProtocolMapperModel mappingModel,
                            UserSessionModel userSession, KeycloakSession keycloakSession,
                            ClientSessionContext clientSessionCtx) {

        Connector connector = new Connector();
        connector.execute();
    }
}

package xx.xx.keycloak.mappers.oidc;

import io.quarkus.arc.Arc;
import io.quarkus.hibernate.orm.PersistenceUnit;
import jakarta.enterprise.context.RequestScoped;
import jakarta.enterprise.inject.Instance;
import jakarta.inject.Inject;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Persistence;

import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class Connector {

    @Inject
    @PersistenceUnit("custds")
    EntityManager em;

    public void execute() {

        Instance<EntityManagerFactory> emfs = Arc.container().select(EntityManagerFactory.class);

        Set<String> persistenceUnitNames = emfs.stream()
                .map(emf -> (String) emf.getProperties().get("hibernate.ejb.persistenceUnitName"))
                .collect(Collectors.toSet());

        System.out.println("Available Persistence Units: " + persistenceUnitNames);

        System.out.println(em);
        EntityManager em = Arc.container()
                .instance(EntityManager.class, new PersistenceUnit.PersistenceUnitLiteral("custds"))
                .get();
        Object o = Arc.container().instance(EntityManager.class);
    }
}

The connector class will be the one which will have to make the connection to the oracle database. I have tried various approaches as you can see in the body of the execute method, but the EntityManager is always null.

keycloak-1 | Available Persistence Units: [null]

I tried everything from the official documentation of quarkus and keycloak, but nothing seems to work. I have seen similar threads here with same issues, but nothing helps.

本文标签: