parent
68d14783f5
commit
5f2191813a
12 changed files with 119 additions and 57 deletions
|
@ -1,24 +0,0 @@
|
||||||
package org.keycloak.config;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class AllOptions {
|
|
||||||
|
|
||||||
public static final List<Option<?>> ALL_OPTIONS = new ArrayList<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
ALL_OPTIONS.addAll(CachingOptions.ALL_OPTIONS);
|
|
||||||
ALL_OPTIONS.addAll(DatabaseOptions.ALL_OPTIONS);
|
|
||||||
ALL_OPTIONS.addAll(FeatureOptions.ALL_OPTIONS);
|
|
||||||
ALL_OPTIONS.addAll(HealthOptions.ALL_OPTIONS);
|
|
||||||
ALL_OPTIONS.addAll(HostnameOptions.ALL_OPTIONS);
|
|
||||||
ALL_OPTIONS.addAll(HttpOptions.ALL_OPTIONS);
|
|
||||||
ALL_OPTIONS.addAll(LoggingOptions.ALL_OPTIONS);
|
|
||||||
ALL_OPTIONS.addAll(MetricsOptions.ALL_OPTIONS);
|
|
||||||
ALL_OPTIONS.addAll(ProxyOptions.ALL_OPTIONS);
|
|
||||||
ALL_OPTIONS.addAll(TransactionOptions.ALL_OPTIONS);
|
|
||||||
ALL_OPTIONS.addAll(VaultOptions.ALL_OPTIONS);
|
|
||||||
ALL_OPTIONS.addAll(StorageOptions.ALL_OPTIONS);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -29,6 +29,7 @@ import static org.keycloak.representations.provider.ScriptProviderDescriptor.AUT
|
||||||
import static org.keycloak.representations.provider.ScriptProviderDescriptor.MAPPERS;
|
import static org.keycloak.representations.provider.ScriptProviderDescriptor.MAPPERS;
|
||||||
import static org.keycloak.representations.provider.ScriptProviderDescriptor.POLICIES;
|
import static org.keycloak.representations.provider.ScriptProviderDescriptor.POLICIES;
|
||||||
import static org.keycloak.quarkus.runtime.Environment.getProviderFiles;
|
import static org.keycloak.quarkus.runtime.Environment.getProviderFiles;
|
||||||
|
import static org.keycloak.theme.ClasspathThemeProviderFactory.KEYCLOAK_THEMES_JSON;
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.spi.PersistenceUnitTransactionType;
|
import javax.persistence.spi.PersistenceUnitTransactionType;
|
||||||
|
@ -132,8 +133,10 @@ import org.keycloak.representations.provider.ScriptProviderDescriptor;
|
||||||
import org.keycloak.representations.provider.ScriptProviderMetadata;
|
import org.keycloak.representations.provider.ScriptProviderMetadata;
|
||||||
import org.keycloak.quarkus.runtime.integration.web.NotFoundHandler;
|
import org.keycloak.quarkus.runtime.integration.web.NotFoundHandler;
|
||||||
import org.keycloak.services.ServicesLogger;
|
import org.keycloak.services.ServicesLogger;
|
||||||
|
import org.keycloak.theme.ClasspathThemeProviderFactory;
|
||||||
import org.keycloak.theme.ClasspathThemeResourceProviderFactory;
|
import org.keycloak.theme.ClasspathThemeResourceProviderFactory;
|
||||||
import org.keycloak.theme.FolderThemeProviderFactory;
|
import org.keycloak.theme.FolderThemeProviderFactory;
|
||||||
|
import org.keycloak.theme.JarThemeProviderFactory;
|
||||||
import org.keycloak.theme.ThemeResourceSpi;
|
import org.keycloak.theme.ThemeResourceSpi;
|
||||||
import org.keycloak.transaction.JBossJtaTransactionManagerLookup;
|
import org.keycloak.transaction.JBossJtaTransactionManagerLookup;
|
||||||
import org.keycloak.quarkus.runtime.Environment;
|
import org.keycloak.quarkus.runtime.Environment;
|
||||||
|
@ -163,6 +166,7 @@ class KeycloakProcessor {
|
||||||
FilesPlainTextVaultProviderFactory.class,
|
FilesPlainTextVaultProviderFactory.class,
|
||||||
BlacklistPasswordPolicyProviderFactory.class,
|
BlacklistPasswordPolicyProviderFactory.class,
|
||||||
ClasspathThemeResourceProviderFactory.class,
|
ClasspathThemeResourceProviderFactory.class,
|
||||||
|
JarThemeProviderFactory.class,
|
||||||
JpaMapStorageProviderFactory.class);
|
JpaMapStorageProviderFactory.class);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
|
@ -316,11 +320,26 @@ class KeycloakProcessor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
recorder.configSessionFactory(factories, defaultProviders, preConfiguredProviders, Environment.isRebuild());
|
recorder.configSessionFactory(factories, defaultProviders, preConfiguredProviders, loadThemesFromClassPath(), Environment.isRebuild());
|
||||||
|
|
||||||
return new KeycloakSessionFactoryPreInitBuildItem();
|
return new KeycloakSessionFactoryPreInitBuildItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<ClasspathThemeProviderFactory.ThemesRepresentation> loadThemesFromClassPath() {
|
||||||
|
try {
|
||||||
|
List<ClasspathThemeProviderFactory.ThemesRepresentation> themes = new ArrayList<>();
|
||||||
|
Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(KEYCLOAK_THEMES_JSON);
|
||||||
|
|
||||||
|
while (resources.hasMoreElements()) {
|
||||||
|
themes.add(JsonSerialization.readValue(resources.nextElement().openStream(), ClasspathThemeProviderFactory.ThemesRepresentation.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
return themes;
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException("Failed to load themes", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void configureThemeResourceProviders(Map<Spi, Map<Class<? extends Provider>, Map<String, Class<? extends ProviderFactory>>>> factories, Spi spi) {
|
private void configureThemeResourceProviders(Map<Spi, Map<Class<? extends Provider>, Map<String, Class<? extends ProviderFactory>>>> factories, Spi spi) {
|
||||||
try {
|
try {
|
||||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
|
|
@ -47,6 +47,7 @@ import org.keycloak.provider.Provider;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
import org.keycloak.provider.Spi;
|
import org.keycloak.provider.Spi;
|
||||||
import org.keycloak.quarkus.runtime.storage.legacy.infinispan.CacheManagerFactory;
|
import org.keycloak.quarkus.runtime.storage.legacy.infinispan.CacheManagerFactory;
|
||||||
|
import org.keycloak.theme.ClasspathThemeProviderFactory;
|
||||||
|
|
||||||
import io.quarkus.runtime.RuntimeValue;
|
import io.quarkus.runtime.RuntimeValue;
|
||||||
import io.quarkus.runtime.ShutdownContext;
|
import io.quarkus.runtime.ShutdownContext;
|
||||||
|
@ -69,10 +70,10 @@ public class KeycloakRecorder {
|
||||||
Map<Spi, Map<Class<? extends Provider>, Map<String, Class<? extends ProviderFactory>>>> factories,
|
Map<Spi, Map<Class<? extends Provider>, Map<String, Class<? extends ProviderFactory>>>> factories,
|
||||||
Map<Class<? extends Provider>, String> defaultProviders,
|
Map<Class<? extends Provider>, String> defaultProviders,
|
||||||
Map<String, ProviderFactory> preConfiguredProviders,
|
Map<String, ProviderFactory> preConfiguredProviders,
|
||||||
Boolean reaugmented) {
|
List<ClasspathThemeProviderFactory.ThemesRepresentation> themes, Boolean reaugmented) {
|
||||||
Config.init(new MicroProfileConfigProvider());
|
Config.init(new MicroProfileConfigProvider());
|
||||||
Profile.setInstance(new QuarkusProfile());
|
Profile.setInstance(new QuarkusProfile());
|
||||||
QuarkusKeycloakSessionFactory.setInstance(new QuarkusKeycloakSessionFactory(factories, defaultProviders, preConfiguredProviders, reaugmented));
|
QuarkusKeycloakSessionFactory.setInstance(new QuarkusKeycloakSessionFactory(factories, defaultProviders, preConfiguredProviders, themes, reaugmented));
|
||||||
}
|
}
|
||||||
|
|
||||||
public RuntimeValue<CacheManagerFactory> createCacheInitializer(String config, ShutdownContext shutdownContext) {
|
public RuntimeValue<CacheManagerFactory> createCacheInitializer(String config, ShutdownContext shutdownContext) {
|
||||||
|
|
|
@ -63,9 +63,13 @@ public class MicroProfileConfigProvider implements Config.ConfigProvider {
|
||||||
private final String[] scope;
|
private final String[] scope;
|
||||||
private final String prefix;
|
private final String prefix;
|
||||||
|
|
||||||
public MicroProfileScope(String... scope) {
|
public MicroProfileScope(String... scopes) {
|
||||||
this.scope = scope;
|
this.scope = scopes;
|
||||||
this.prefix = NS_KEYCLOAK_PREFIX + String.join(OPTION_PART_SEPARATOR, ArrayUtils.insert(0, scope, "spi"));
|
StringBuilder prefix = new StringBuilder(NS_KEYCLOAK_PREFIX).append("spi");
|
||||||
|
for (String scope : scopes) {
|
||||||
|
prefix.append(OPTION_PART_SEPARATOR).append(scope);
|
||||||
|
}
|
||||||
|
this.prefix = prefix.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -21,7 +21,7 @@ import java.util.function.Predicate;
|
||||||
public final class PropertyMappers {
|
public final class PropertyMappers {
|
||||||
|
|
||||||
public static String VALUE_MASK = "*******";
|
public static String VALUE_MASK = "*******";
|
||||||
static final MappersConfig MAPPERS = new MappersConfig();
|
private static final MappersConfig MAPPERS = new MappersConfig();
|
||||||
|
|
||||||
private PropertyMappers(){}
|
private PropertyMappers(){}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.keycloak.quarkus.runtime.integration;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.keycloak.Config;
|
import org.keycloak.Config;
|
||||||
|
@ -26,8 +27,10 @@ import org.keycloak.provider.Provider;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
import org.keycloak.provider.ProviderFactory;
|
||||||
import org.keycloak.provider.ProviderManagerRegistry;
|
import org.keycloak.provider.ProviderManagerRegistry;
|
||||||
import org.keycloak.provider.Spi;
|
import org.keycloak.provider.Spi;
|
||||||
|
import org.keycloak.quarkus.runtime.themes.QuarkusJarThemeProviderFactory;
|
||||||
import org.keycloak.services.DefaultKeycloakSessionFactory;
|
import org.keycloak.services.DefaultKeycloakSessionFactory;
|
||||||
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
import org.keycloak.services.resources.admin.permissions.AdminPermissions;
|
||||||
|
import org.keycloak.theme.ClasspathThemeProviderFactory;
|
||||||
|
|
||||||
public final class QuarkusKeycloakSessionFactory extends DefaultKeycloakSessionFactory {
|
public final class QuarkusKeycloakSessionFactory extends DefaultKeycloakSessionFactory {
|
||||||
|
|
||||||
|
@ -52,6 +55,7 @@ public final class QuarkusKeycloakSessionFactory extends DefaultKeycloakSessionF
|
||||||
Map<Spi, Map<Class<? extends Provider>, Map<String, Class<? extends ProviderFactory>>>> factories,
|
Map<Spi, Map<Class<? extends Provider>, Map<String, Class<? extends ProviderFactory>>>> factories,
|
||||||
Map<Class<? extends Provider>, String> defaultProviders,
|
Map<Class<? extends Provider>, String> defaultProviders,
|
||||||
Map<String, ProviderFactory> preConfiguredProviders,
|
Map<String, ProviderFactory> preConfiguredProviders,
|
||||||
|
List<ClasspathThemeProviderFactory.ThemesRepresentation> themes,
|
||||||
Boolean reaugmented) {
|
Boolean reaugmented) {
|
||||||
this.provider = defaultProviders;
|
this.provider = defaultProviders;
|
||||||
this.factories = factories;
|
this.factories = factories;
|
||||||
|
@ -69,6 +73,10 @@ public final class QuarkusKeycloakSessionFactory extends DefaultKeycloakSessionF
|
||||||
factory = lookupProviderFactory(entry.getValue());
|
factory = lookupProviderFactory(entry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (factory instanceof QuarkusJarThemeProviderFactory) {
|
||||||
|
((QuarkusJarThemeProviderFactory) factory).setThemes(themes);
|
||||||
|
}
|
||||||
|
|
||||||
Config.Scope scope = Config.scope(spi.getName(), factory.getId());
|
Config.Scope scope = Config.scope(spi.getName(), factory.getId());
|
||||||
|
|
||||||
factory.init(scope);
|
factory.init(scope);
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright ${YEAR} 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.quarkus.runtime.themes;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.keycloak.Config;
|
||||||
|
import org.keycloak.theme.JarThemeProviderFactory;
|
||||||
|
|
||||||
|
public class QuarkusJarThemeProviderFactory extends JarThemeProviderFactory {
|
||||||
|
|
||||||
|
public void setThemes(List<ThemesRepresentation> themes) {
|
||||||
|
for (ThemesRepresentation theme : themes) {
|
||||||
|
loadThemes(Thread.currentThread().getContextClassLoader(), theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Config.Scope config) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,4 @@
|
||||||
org.keycloak.quarkus.runtime.themes.QuarkusFolderThemeProviderFactory
|
org.keycloak.quarkus.runtime.themes.QuarkusFolderThemeProviderFactory
|
||||||
|
org.keycloak.quarkus.runtime.themes.QuarkusJarThemeProviderFactory
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -32,13 +32,19 @@ public class WebAuthnCredentialProviderFactory implements CredentialProviderFact
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CredentialProvider create(KeycloakSession session) {
|
public CredentialProvider create(KeycloakSession session) {
|
||||||
return new WebAuthnCredentialProvider(session, converter);
|
return new WebAuthnCredentialProvider(session, createOrGetObjectConverter());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private ObjectConverter createOrGetObjectConverter() {
|
||||||
public void init(Config.Scope config) {
|
if (converter == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (converter == null) {
|
||||||
converter = new ObjectConverter();
|
converter = new ObjectConverter();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return converter;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getId() {
|
public String getId() {
|
||||||
|
|
|
@ -30,11 +30,22 @@ public class WebAuthnPasswordlessCredentialProviderFactory implements Credential
|
||||||
|
|
||||||
public static final String PROVIDER_ID = "keycloak-webauthn-passwordless";
|
public static final String PROVIDER_ID = "keycloak-webauthn-passwordless";
|
||||||
|
|
||||||
private static ObjectConverter objectConverter = new ObjectConverter();
|
private ObjectConverter converter;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CredentialProvider create(KeycloakSession session) {
|
public CredentialProvider create(KeycloakSession session) {
|
||||||
return new WebAuthnPasswordlessCredentialProvider(session, objectConverter);
|
return new WebAuthnPasswordlessCredentialProvider(session, createOrGetObjectConverter());
|
||||||
|
}
|
||||||
|
|
||||||
|
private ObjectConverter createOrGetObjectConverter() {
|
||||||
|
if (converter == null) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (converter == null) {
|
||||||
|
converter = new ObjectConverter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return converter;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -68,24 +68,6 @@ public class SamlProtocolFactory extends AbstractLoginProtocolFactory {
|
||||||
public void init(Config.Scope config) {
|
public void init(Config.Scope config) {
|
||||||
//PicketLinkCoreSTS sts = PicketLinkCoreSTS.instance();
|
//PicketLinkCoreSTS sts = PicketLinkCoreSTS.instance();
|
||||||
//sts.installDefaultConfiguration();
|
//sts.installDefaultConfiguration();
|
||||||
|
|
||||||
this.destinationValidator = DestinationValidator.forProtocolMap(config.getArray("knownProtocols"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return SamlProtocol.LOGIN_PROTOCOL;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, ProtocolMapperModel> getBuiltinMappers() {
|
|
||||||
return builtins;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Map<String, ProtocolMapperModel> builtins = new HashMap<>();
|
|
||||||
static List<ProtocolMapperModel> defaultBuiltins = new ArrayList<>();
|
|
||||||
|
|
||||||
static {
|
|
||||||
ProtocolMapperModel model;
|
ProtocolMapperModel model;
|
||||||
model = UserPropertyAttributeStatementMapper.createAttributeMapper("X500 email",
|
model = UserPropertyAttributeStatementMapper.createAttributeMapper("X500 email",
|
||||||
"email",
|
"email",
|
||||||
|
@ -111,9 +93,21 @@ public class SamlProtocolFactory extends AbstractLoginProtocolFactory {
|
||||||
model = RoleListMapper.create("role list", "Role", AttributeStatementHelper.BASIC, null, false);
|
model = RoleListMapper.create("role list", "Role", AttributeStatementHelper.BASIC, null, false);
|
||||||
builtins.put("role list", model);
|
builtins.put("role list", model);
|
||||||
defaultBuiltins.add(model);
|
defaultBuiltins.add(model);
|
||||||
|
this.destinationValidator = DestinationValidator.forProtocolMap(config.getArray("knownProtocols"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getId() {
|
||||||
|
return SamlProtocol.LOGIN_PROTOCOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, ProtocolMapperModel> getBuiltinMappers() {
|
||||||
|
return builtins;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, ProtocolMapperModel> builtins = new HashMap<>();
|
||||||
|
private List<ProtocolMapperModel> defaultBuiltins = new ArrayList<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void createDefaultClientScopesImpl(RealmModel newRealm) {
|
protected void createDefaultClientScopesImpl(RealmModel newRealm) {
|
||||||
|
|
|
@ -102,8 +102,14 @@ public class ClasspathThemeProviderFactory implements ThemeProviderFactory {
|
||||||
|
|
||||||
protected void loadThemes(ClassLoader classLoader, InputStream themesInputStream) {
|
protected void loadThemes(ClassLoader classLoader, InputStream themesInputStream) {
|
||||||
try {
|
try {
|
||||||
ThemesRepresentation themesRep = JsonSerialization.readValue(themesInputStream, ThemesRepresentation.class);
|
loadThemes(classLoader, JsonSerialization.readValue(themesInputStream, ThemesRepresentation.class));
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException("Failed to load themes", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void loadThemes(ClassLoader classLoader, ThemesRepresentation themesRep) {
|
||||||
|
try {
|
||||||
for (ThemeRepresentation themeRep : themesRep.getThemes()) {
|
for (ThemeRepresentation themeRep : themesRep.getThemes()) {
|
||||||
for (String t : themeRep.getTypes()) {
|
for (String t : themeRep.getTypes()) {
|
||||||
Theme.Type type = Theme.Type.valueOf(t.toUpperCase());
|
Theme.Type type = Theme.Type.valueOf(t.toUpperCase());
|
||||||
|
|
Loading…
Reference in a new issue