Home > Software engineering >  UserStorage SPI in Keycloak with PostgreSQL driver
UserStorage SPI in Keycloak with PostgreSQL driver

Time:08-24

I'm trying to link a Keycloak instance to an external source of users that is a PostgreSQL database. I've followed Keycloak's example on how to implement a custom user federation provider that works with a properties file containing username/password pairs and it works as expected.

Starting from there I changed the code a little so that it connects to my users db instead of reading a properties file but I have this error at providers init:

Failed to init CustomProviderFactory: java.sql.SQLException: No suitable driver found for jdbc:postgresql://postgres:5432/users_db

I run a Docker Compose config with a postgres container so that's why my db host is simply called postgres. (I can psql into my db from another container on the same network with that hostname so I don't think that's the cause of my problem.) The Keycloak container uses a custom image that copies my SPI into the providers directory. Here's the Dockerfile if needed:

FROM quay.io/keycloak/keycloak:latest as builder

# Install custom providers
COPY target/custom-user-provider.jar /opt/keycloak/providers
RUN /opt/keycloak/bin/kc.sh build

FROM quay.io/keycloak/keycloak:latest
COPY --from=builder /opt/keycloak/ /opt/keycloak/
WORKDIR /opt/keycloak
ENTRYPOINT ["/opt/keycloak/bin/kc.sh"]

My problem probably is the org.postgresql.postgresql:42.4.2 dependency that I have in my pom.xml. I've tried multiple artifacts configurations including a JAR with dependencies, a JAR without dependencies and a fat JAR but I'm no expert in Java and I'm not sure I'm building my JAR correctly.

Here is some code from my SPI implementation including the line where it tries to connect to postgres:

CustomUserProviderFactory.java

public class CustomUserProviderFactory implements UserStorageProviderFactory<CustomUserProvider> {
    public static final String PROVIDER_NAME = "custom-user-storage";
    private static final Logger logger = Logger.getLogger(CustomUserProviderFactory.class);

    protected UserRepository userRepository;

    @Override
    public void init(Config.Scope config) {
        try {
            userRepository = new UserRepository();
            logger.error("Loaded users database");
        } catch (SQLException ex) {
            logger.error("Failed to init CustomProviderFactory", ex);
        }

    }

    @Override
    public CustomUserProvider create(KeycloakSession session, ComponentModel model) {
        return new CustomUserProvider(session, model, userRepository);
    }

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

UserRepository.java

public class UserRepository {
    private static final Logger logger = Logger.getLogger(UserRepository.class);

    private final static String url = "jdbc:postgresql://postgres:5432/users_db";
    private final static String username = "user";
    private final static String password = "password";
    private final Connection conn;

    public UserRepository() throws SQLException {
        // Error is thrown here
        conn = DriverManager.getConnection(url, username, password);
    }

    public User getByEmail(String email) throws SQLException {
      // Query user from DB
    }
}

CodePudding user response:

Try to add Class.forName("org.postgresql.Driver"); before conn = DriverManager.getConnection(url, username, password); and see if it solves your problem (see this).

CodePudding user response:

If you are also using postgres as your main Keycloak database, simply change the build command to:

RUN /opt/keycloak/bin/kc.sh build --db postgres

If you are using another databse, you need to add the JDBC driver manually. Simply copy the driver JAR to /opt/keycloak/providers.

  • Related