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
}
}
2
Answers
Try to add
Class.forName("org.postgresql.Driver");
beforeconn = DriverManager.getConnection(url, username, password);
and see if it solves your problem (see this).If you are also using postgres as your main Keycloak database, simply change the build command to:
If you are using another databse, you need to add the JDBC driver manually. Simply copy the driver JAR to
/opt/keycloak/providers
.