[keycloak-user] UserStorageProvider for an external database
Bart Lievens
bart.lievens at unifiedpost.com
Sun Dec 9 07:26:16 EST 2018
Hello,
I solved the problem not by adding a datasource to WildFly but by adding the configuration parameters to the UserStorageProviderFactory
and creating the EntityManager inside the UserStorageProviderFactory and then passing it on when creating a UserStorageProvider.
My UserStorageProviderFactory looks something like (with 4.6.0.Final & 4.7.0.Final) :
public class ExternalUserStorageProviderFactory implements UserStorageProviderFactory<ExternalUserStorageProvider> {
private static final transient Logger logger = LoggerFactory.getLogger(ExternalUserStorageProviderFactory.class);
private static final String CONF_NAME_JDBC_URL = "jdbcUrl";
private static final String CONF_NAME_JDBC_USER = "user";
private static final String CONF_NAME_JDBC_PASSWORD = "password";
protected static final List<ProviderConfigProperty> configMetadata;
private Map<String, EntityManager> entityManagers = new HashMap<>();
static {
ProviderConfigurationBuilder builder = ProviderConfigurationBuilder.create();
builder.property().name(CONF_NAME_JDBC_URL).type(ProviderConfigProperty.STRING_TYPE).label("Jdbc Url")
.defaultValue("jdbc:postgresql://host:port/database")
.helpText("Postgres JDBC Connection URL to external user db")
.add();
builder.property().name(CONF_NAME_JDBC_USER).type(ProviderConfigProperty.STRING_TYPE).label("Jdbc User")
.helpText("JDBC Connection User")
.add();
builder.property().name(CONF_NAME_JDBC_PASSWORD).type(ProviderConfigProperty.PASSWORD).label("Jdbc Password")
.helpText("JDBC Connection Password")
.add();
configMetadata = builder.build();
}
@Override
public List<ProviderConfigProperty> getConfigProperties() {
return configMetadata;
}
@Override
public void validateConfiguration(KeycloakSession session, RealmModel realm, ComponentModel componentModel) throws ComponentValidationException {
if (componentModel.getConfig().getFirst(CONF_NAME_JDBC_URL) == null
|| componentModel.getConfig().getFirst(CONF_NAME_JDBC_USER) == null
|| componentModel.getConfig().getFirst(CONF_NAME_JDBC_PASSWORD) == null) {
throw new ComponentValidationException("The jdbc Url, User and Password are requirec");
}
try {
createEntityManager(componentModel);
} catch (Exception e) {
logger.warn("Invalid configuration {}", e.getCause() == null ? e.getMessage() : e.getCause().getMessage());
throw new ComponentValidationException("Could not setup jdbc connection : " + (e.getCause() == null ? e.getMessage() : e.getCause().getMessage()));
}
}
@Override
public ExternalUserStorageProvider create(KeycloakSession session, ComponentModel model) {
try {
if (entityManagers.get(model.getId()) == null) {
createEntityManager(model);
}
return new ExternalUserStorageProvider(entityManagers.get(model.getId()), model, session);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public String getId() {
return "external-user-db";
}
@Override
public String getHelpText() {
return "External User Database Storage Provider";
}
private void createEntityManager(ComponentModel model) {
logger.info("creating entityManager for {}", model.getName());
Properties properties = getProperties(model);
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("external-user-storage", properties);
entityManagers.put(model.getId(), entityManagerFactory.createEntityManager());
}
private Properties getProperties(ComponentModel model) {
Properties properties = new Properties();
// Add class loader needed to find persistence.xml
properties.put(AvailableSettings.CLASSLOADERS, Arrays.asList(this.getClass().getClassLoader()));
// Set JPA properties
properties.put(AvailableSettings.JPA_PERSISTENCE_PROVIDER, HibernatePersistenceProvider.class.getName());
properties.put(AvailableSettings.JPA_TRANSACTION_TYPE, PersistenceUnitTransactionType.JTA.name());
// postgresql jdbc connection config
properties.put(AvailableSettings.JPA_JDBC_DRIVER, "org.postgresql.Driver");
properties.put(AvailableSettings.JPA_JDBC_URL, EnvUtil.replace(model.getConfig().getFirst(CONF_NAME_JDBC_URL)));
properties.put(AvailableSettings.JPA_JDBC_USER, EnvUtil.replace(model.getConfig().getFirst(CONF_NAME_JDBC_USER)));
properties.put(AvailableSettings.JPA_JDBC_PASSWORD, EnvUtil.replace(model.getConfig().getFirst(CONF_NAME_JDBC_PASSWORD)));
// hibernate
properties.put(AvailableSettings.DIALECT, org.hibernate.dialect.PostgreSQL95Dialect.class.getName());
properties.put(AvailableSettings.SHOW_SQL, Boolean.FALSE);
// set JTA properties
properties.put(AvailableSettings.JTA_PLATFORM, JBossAppServerJtaPlatform.class.getName());
return properties;
}
}
More information about the keycloak-user
mailing list