KEYCLOAK-11347 - MicroProfile-Config
This commit is contained in:
parent
d3e59bd0d1
commit
56aa14ffab
10 changed files with 383 additions and 125 deletions
|
@ -32,6 +32,10 @@
|
|||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.keycloak</groupId>
|
||||
<artifactId>keycloak-services</artifactId>
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.provider.quarkus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import io.quarkus.runtime.configuration.DeploymentProfileConfigSource;
|
||||
import io.quarkus.runtime.configuration.ExpandingConfigSource;
|
||||
|
||||
import org.eclipse.microprofile.config.spi.ConfigSource;
|
||||
import org.eclipse.microprofile.config.spi.ConfigSourceProvider;
|
||||
|
||||
public class KeycloakConfigSourceProvider implements ConfigSourceProvider {
|
||||
|
||||
private static final String KEYCLOAK_CONFIG_FILE_PROP = "keycloak.config.file";
|
||||
private static final String KEYCLOAK_CONFIG_FILE_ENV = "KEYCLOAK_CONFIG_FILE";
|
||||
|
||||
@Override
|
||||
public Iterable<ConfigSource> getConfigSources(ClassLoader forClassLoader) {
|
||||
|
||||
ArrayList<ConfigSource> sources = new ArrayList<>();
|
||||
|
||||
sources.add(wrap(new KeycloakPropertiesConfigSource.InJar()));
|
||||
|
||||
String fileName = System.getProperty(KEYCLOAK_CONFIG_FILE_PROP);
|
||||
|
||||
if (fileName == null)
|
||||
fileName = System.getenv(KEYCLOAK_CONFIG_FILE_ENV);
|
||||
|
||||
if (fileName != null)
|
||||
sources.add(wrap(new KeycloakPropertiesConfigSource.InFileSystem(fileName)));
|
||||
|
||||
return sources;
|
||||
|
||||
}
|
||||
|
||||
private ConfigSource wrap(ConfigSource source) {
|
||||
return ExpandingConfigSource.wrapper(new ExpandingConfigSource.Cache())
|
||||
.compose(DeploymentProfileConfigSource.wrapper())
|
||||
.apply(source);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.provider.quarkus;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.NoSuchFileException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import io.smallrye.config.PropertiesConfigSource;
|
||||
|
||||
import static org.keycloak.provider.quarkus.MicroProfileConfigProvider.NS_KEYCLOAK;
|
||||
import static org.keycloak.provider.quarkus.MicroProfileConfigProvider.NS_QUARKUS;
|
||||
|
||||
/**
|
||||
* A configuration source for {@code keycloak.properties}.
|
||||
*/
|
||||
public abstract class KeycloakPropertiesConfigSource extends PropertiesConfigSource {
|
||||
|
||||
static final String KEYCLOAK_PROPERTIES = "keycloak.properties";
|
||||
|
||||
KeycloakPropertiesConfigSource(InputStream is, int ordinal) {
|
||||
super(readProperties(is), KEYCLOAK_PROPERTIES, ordinal);
|
||||
}
|
||||
|
||||
private static Map<String, String> readProperties(final InputStream is) {
|
||||
if (is == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
try (Closeable ignored = is) {
|
||||
try (InputStreamReader isr = new InputStreamReader(is, StandardCharsets.UTF_8)) {
|
||||
try (BufferedReader br = new BufferedReader(isr)) {
|
||||
final Properties properties = new Properties();
|
||||
properties.load(br);
|
||||
return transform((Map<String, String>) (Map) properties);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IOError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class InJar extends KeycloakPropertiesConfigSource {
|
||||
public InJar() {
|
||||
super(openStream(), 245);
|
||||
}
|
||||
|
||||
private static InputStream openStream() {
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
if (cl == null) {
|
||||
cl = KeycloakPropertiesConfigSource.class.getClassLoader();
|
||||
}
|
||||
InputStream is;
|
||||
String fileName = "META-INF" + File.separator + KEYCLOAK_PROPERTIES;
|
||||
if (cl == null) {
|
||||
is = ClassLoader.getSystemResourceAsStream(fileName);
|
||||
} else {
|
||||
is = cl.getResourceAsStream(fileName);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class InFileSystem extends KeycloakPropertiesConfigSource {
|
||||
|
||||
public InFileSystem(String fileName) {
|
||||
super(openStream(fileName), 255);
|
||||
}
|
||||
|
||||
private static InputStream openStream(String fileName) {
|
||||
final Path path = Paths.get(fileName);
|
||||
if (Files.exists(path)) {
|
||||
try {
|
||||
return Files.newInputStream(path);
|
||||
} catch (NoSuchFileException | FileNotFoundException e) {
|
||||
return null;
|
||||
} catch (IOException e) {
|
||||
throw new IOError(e);
|
||||
}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, String> transform(Map<String, String> properties) {
|
||||
Map<String, String> result = new HashMap<>(properties.size());
|
||||
properties.keySet().forEach(k -> result.put(transformKey(k), properties.get(k)));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static String transformKey(String key) {
|
||||
|
||||
String namespace, prefix = (key.split("\\."))[0];
|
||||
|
||||
switch (prefix) {
|
||||
case "datasource":
|
||||
case "http":
|
||||
case "log":
|
||||
namespace = NS_QUARKUS;
|
||||
break;
|
||||
default:
|
||||
namespace = NS_KEYCLOAK;
|
||||
}
|
||||
|
||||
return namespace + "." + key;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright 2019 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.provider.quarkus;
|
||||
|
||||
import org.apache.commons.lang3.ArrayUtils;
|
||||
import org.eclipse.microprofile.config.ConfigProvider;
|
||||
|
||||
import org.keycloak.Config;
|
||||
|
||||
public class MicroProfileConfigProvider implements Config.ConfigProvider {
|
||||
|
||||
public static final String NS_KEYCLOAK = "keycloak";
|
||||
public static final String NS_QUARKUS = "quarkus";
|
||||
|
||||
private final org.eclipse.microprofile.config.Config config;
|
||||
|
||||
public MicroProfileConfigProvider() {
|
||||
this.config = ConfigProvider.getConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProvider(String spi) {
|
||||
return scope(spi).get("provider");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config.Scope scope(String... scope) {
|
||||
return new MicroProfileScope(scope);
|
||||
}
|
||||
|
||||
public class MicroProfileScope implements Config.Scope {
|
||||
|
||||
private final String[] scope;
|
||||
private final String prefix;
|
||||
|
||||
public MicroProfileScope(String... scope) {
|
||||
this.scope = scope;
|
||||
this.prefix = String.join(".", ArrayUtils.insert(0, scope, NS_KEYCLOAK));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key) {
|
||||
return getValue(key, String.class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String get(String key, String defaultValue) {
|
||||
return getValue(key, String.class, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getArray(String key) {
|
||||
return getValue(key, String[].class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getInt(String key) {
|
||||
return getValue(key, Integer.class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getInt(String key, Integer defaultValue) {
|
||||
return getValue(key, Integer.class, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(String key) {
|
||||
return getValue(key, Long.class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getLong(String key, Long defaultValue) {
|
||||
return getValue(key, Long.class, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getBoolean(String key) {
|
||||
return getValue(key, Boolean.class, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean getBoolean(String key, Boolean defaultValue) {
|
||||
return getValue(key, Boolean.class, defaultValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Config.Scope scope(String... scope) {
|
||||
return new MicroProfileScope(ArrayUtils.addAll(this.scope, scope));
|
||||
}
|
||||
|
||||
private <T> T getValue(String key, Class<T> clazz, T defaultValue) {
|
||||
T value = config.getOptionalValue(prefix + "." + key, clazz).orElse(defaultValue);
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -17,6 +17,16 @@
|
|||
|
||||
package org.keycloak.provider.quarkus;
|
||||
|
||||
public class JsonConfigProviderFactory extends org.keycloak.services.util.JsonConfigProviderFactory {
|
||||
import java.util.Optional;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.config.ConfigProviderFactory;
|
||||
|
||||
public class MicroProfileConfigProviderFactory implements ConfigProviderFactory {
|
||||
|
||||
@Override
|
||||
public Optional<Config.ConfigProvider> create() {
|
||||
return Optional.of(new MicroProfileConfigProvider());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#
|
||||
# Copyright 2019 Red Hat, Inc. and/or its affiliates
|
||||
# and other contributors as indicated by the @author tags.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
org.keycloak.provider.quarkus.KeycloakConfigSourceProvider
|
|
@ -15,4 +15,4 @@
|
|||
# limitations under the License.
|
||||
#
|
||||
|
||||
org.keycloak.provider.quarkus.JsonConfigProviderFactory
|
||||
org.keycloak.provider.quarkus.MicroProfileConfigProviderFactory
|
||||
|
|
|
@ -1,123 +0,0 @@
|
|||
{
|
||||
|
||||
"hostname": {
|
||||
"provider": "request",
|
||||
|
||||
"fixed": {
|
||||
"hostname": "localhost",
|
||||
"httpPort": "-1",
|
||||
"httpsPort": "-1"
|
||||
}
|
||||
},
|
||||
|
||||
"admin": {
|
||||
"realm": "master"
|
||||
},
|
||||
|
||||
"eventsStore": {
|
||||
"provider": "${keycloak.eventsStore.provider:jpa}"
|
||||
},
|
||||
|
||||
"eventsListener": {
|
||||
"jboss-logging" : {
|
||||
"success-level": "debug",
|
||||
"error-level": "warn"
|
||||
}
|
||||
},
|
||||
|
||||
"realm": {
|
||||
"provider": "${keycloak.realm.provider:jpa}"
|
||||
},
|
||||
|
||||
"user": {
|
||||
"provider": "${keycloak.user.provider:jpa}"
|
||||
},
|
||||
|
||||
"userFederatedStorage": {
|
||||
"provider": "${keycloak.userFederatedStorage.provider:jpa}"
|
||||
},
|
||||
|
||||
"userSessionPersister": {
|
||||
"provider": "${keycloak.userSessionPersister.provider:jpa}"
|
||||
},
|
||||
|
||||
"authorizationPersister": {
|
||||
"provider": "${keycloak.authorization.provider:jpa}"
|
||||
},
|
||||
|
||||
"userCache": {
|
||||
"default" : {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
|
||||
"timer": {
|
||||
"provider": "basic"
|
||||
},
|
||||
|
||||
"theme": {
|
||||
"staticMaxAge": "${keycloak.theme.staticMaxAge:2592000}",
|
||||
"cacheTemplates": "${keycloak.theme.cacheTemplates:true}",
|
||||
"cacheThemes": "${keycloak.theme.cacheThemes:true}",
|
||||
"folder": {
|
||||
"dir": "${keycloak.theme.dir}"
|
||||
}
|
||||
},
|
||||
|
||||
"scheduled": {
|
||||
"interval": 900
|
||||
},
|
||||
|
||||
"connectionsHttpClient": {
|
||||
"default": {}
|
||||
},
|
||||
|
||||
"connectionsJpa": {
|
||||
"default": {
|
||||
"url": "${keycloak.connectionsJpa.url:jdbc:h2:mem:test;DB_CLOSE_DELAY=-1}",
|
||||
"driver": "${keycloak.connectionsJpa.driver:org.h2.Driver}",
|
||||
"driverDialect": "${keycloak.connectionsJpa.driverDialect:}",
|
||||
"user": "${keycloak.connectionsJpa.user:sa}",
|
||||
"password": "${keycloak.connectionsJpa.password:}",
|
||||
"initializeEmpty": true,
|
||||
"migrationStrategy": "update",
|
||||
"showSql": "${keycloak.connectionsJpa.showSql:false}",
|
||||
"formatSql": "${keycloak.connectionsJpa.formatSql:true}",
|
||||
"globalStatsInterval": "${keycloak.connectionsJpa.globalStatsInterval:-1}"
|
||||
}
|
||||
},
|
||||
|
||||
"realmCache": {
|
||||
"default" : {
|
||||
"enabled": true
|
||||
}
|
||||
},
|
||||
|
||||
"connectionsInfinispan": {
|
||||
"default": {
|
||||
"jgroupsUdpMcastAddr": "${keycloak.connectionsInfinispan.jgroupsUdpMcastAddr:234.56.78.90}",
|
||||
"nodeName": "${keycloak.connectionsInfinispan.nodeName,jboss.node.name:}",
|
||||
"siteName": "${keycloak.connectionsInfinispan.siteName,jboss.site.name:}",
|
||||
"clustered": "${keycloak.connectionsInfinispan.clustered:false}",
|
||||
"async": "${keycloak.connectionsInfinispan.async:false}",
|
||||
"sessionsOwners": "${keycloak.connectionsInfinispan.sessionsOwners:1}",
|
||||
"l1Lifespan": "${keycloak.connectionsInfinispan.l1Lifespan:600000}",
|
||||
"remoteStoreEnabled": "${keycloak.connectionsInfinispan.remoteStoreEnabled:false}",
|
||||
"remoteStoreHost": "${keycloak.connectionsInfinispan.remoteStoreServer:localhost}",
|
||||
"remoteStorePort": "${keycloak.connectionsInfinispan.remoteStorePort:11222}",
|
||||
"hotrodProtocolVersion": "${keycloak.connectionsInfinispan.hotrodProtocolVersion}",
|
||||
"stack": "${keycloak.connectionsInfinispan.stack:udp}"
|
||||
}
|
||||
},
|
||||
|
||||
"scripting": {
|
||||
},
|
||||
|
||||
"jta-lookup": {
|
||||
"provider": "${keycloak.jta.lookup.provider:jboss}",
|
||||
"jboss" : {
|
||||
"enabled": true
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
# Main
|
||||
|
||||
admin.realm = master
|
||||
scheduled.interval = 900
|
||||
|
||||
# Theme
|
||||
theme.staticMaxAge = 2592000
|
||||
theme.cacheThemes = true
|
||||
theme.cacheTemplates = true
|
||||
#theme.dir = ${keycloak.home.dir}/themes
|
||||
|
||||
# SPIs
|
||||
|
||||
eventsListener.jboss-logging.success-level = debug
|
||||
eventsListener.jboss-logging.error-level = warn
|
||||
|
||||
connectionsJpa.default.url = jdbc:h2:mem:test;DB_CLOSE_DELAY=-1
|
||||
connectionsJpa.default.driver = org.h2.Driver
|
||||
connectionsJpa.default.user = sa
|
||||
connectionsJpa.default.password = keycloak
|
||||
connectionsJpa.default.initializeEmpty = true
|
||||
connectionsJpa.default.migrationStrategy = update
|
||||
connectionsJpa.default.showSql = false
|
||||
connectionsJpa.default.formatSql = true
|
||||
connectionsJpa.default.globalStatsInterval = -1
|
||||
|
||||
eventsStore.provider=jpa
|
||||
realm.provider=jpa
|
||||
user.provider=jpa
|
||||
userFederatedStorage.provider=jpa
|
||||
userSessionPersister.provider=jpa
|
||||
authorizationPersister.provider=jpa
|
||||
|
||||
userCache.enabled=true
|
||||
|
||||
timer.provider=basic
|
||||
|
||||
hostname.provider = default
|
||||
hostname.default.frontendUrl = ${keycloak.frontendUrl:}
|
||||
hostname.default.forceBackendUrlToFrontendUrl = false
|
Loading…
Reference in a new issue