Skip to content

Commit

Permalink
Merge pull request #10334 from gsmet/security-config
Browse files Browse the repository at this point in the history
Make Elytron Security extensions config overridable at runtime
  • Loading branch information
gsmet committed Jun 30, 2020
2 parents ebaae44 + 7b5790c commit ce2e424
Show file tree
Hide file tree
Showing 13 changed files with 166 additions and 113 deletions.
Expand Up @@ -17,13 +17,12 @@
import io.quarkus.elytron.security.deployment.ElytronPasswordMarkerBuildItem;
import io.quarkus.elytron.security.deployment.SecurityRealmBuildItem;
import io.quarkus.elytron.security.jdbc.JdbcRecorder;
import io.quarkus.elytron.security.jdbc.JdbcSecurityRealmConfig;
import io.quarkus.elytron.security.jdbc.JdbcSecurityRealmBuildTimeConfig;
import io.quarkus.elytron.security.jdbc.JdbcSecurityRealmRuntimeConfig;
import io.quarkus.runtime.RuntimeValue;

class ElytronSecurityJdbcProcessor {

JdbcSecurityRealmConfig jdbc;

@BuildStep
CapabilityBuildItem capability() {
return new CapabilityBuildItem(Capability.SECURITY_ELYTRON_JDBC);
Expand All @@ -36,34 +35,32 @@ FeatureBuildItem feature() {

/**
* Check to see if a JdbcRealmConfig was specified and enabled and create a
* {@linkplain org.wildfly.security.auth.realm.JdbcSecurityRealmConfig}
* {@linkplain org.wildfly.security.auth.realm.JdbcSecurityRealmBuildTimeConfig}
* runtime value to process the user/roles properties files. This also registers the names of the user/roles properties
* files
* to include the build artifact.
*
* @param recorder - runtime security recorder
* @param securityRealm - the producer factory for the SecurityRealmBuildItem
* @param dataSourcesConfigured - ensure that the Agroal datasources are configured first
* @throws Exception - on any failure
* files to include the build artifact.
*/
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void configureJdbcRealmAuthConfig(JdbcRecorder recorder,
JdbcSecurityRealmBuildTimeConfig jdbcSecurityRealmBuildTimeConfig,
JdbcSecurityRealmRuntimeConfig jdbcSecurityRealmRuntimeConfig,
BuildProducer<SecurityRealmBuildItem> securityRealm,
BeanContainerBuildItem beanContainerBuildItem, //we need this to make sure ArC is initialized
List<JdbcDataSourceBuildItem> dataSourcesConfigured) throws Exception {
if (jdbc.enabled) {
RuntimeValue<SecurityRealm> realm = recorder.createRealm(jdbc);
securityRealm.produce(new SecurityRealmBuildItem(realm, jdbc.realmName, null));
if (!jdbcSecurityRealmBuildTimeConfig.enabled) {
return;
}

RuntimeValue<SecurityRealm> realm = recorder.createRealm(jdbcSecurityRealmRuntimeConfig);
securityRealm.produce(new SecurityRealmBuildItem(realm, jdbcSecurityRealmBuildTimeConfig.realmName, null));
}

@BuildStep
ElytronPasswordMarkerBuildItem marker() {
if (jdbc.enabled) {
return new ElytronPasswordMarkerBuildItem();
ElytronPasswordMarkerBuildItem marker(JdbcSecurityRealmBuildTimeConfig jdbcSecurityRealmBuildTimeConfig) {
if (!jdbcSecurityRealmBuildTimeConfig.enabled) {
return null;
}
return null;
return new ElytronPasswordMarkerBuildItem();
}

}
Expand Up @@ -27,7 +27,7 @@ public class JdbcRecorder {
* @param config - the realm config
* @return - runtime value wrapper for the SecurityRealm
*/
public RuntimeValue<SecurityRealm> createRealm(JdbcSecurityRealmConfig config) {
public RuntimeValue<SecurityRealm> createRealm(JdbcSecurityRealmRuntimeConfig config) {
Supplier<Provider[]> providers = new Supplier<Provider[]>() {
@Override
public Provider[] get() {
Expand Down
Expand Up @@ -9,7 +9,7 @@
* {@linkplain org.wildfly.security.auth.realm.jdbc.JdbcSecurityRealm}
*/
@ConfigRoot(name = "security.jdbc", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
public class JdbcSecurityRealmConfig {
public class JdbcSecurityRealmBuildTimeConfig {

/**
* The realm name
Expand All @@ -23,19 +23,11 @@ public class JdbcSecurityRealmConfig {
@ConfigItem
public boolean enabled;

/**
* The principal-queries config
*/
@ConfigItem(name = "principal-query")
public PrincipalQueriesConfig principalQueries;
// https://github.com/wildfly/wildfly-core/blob/master/elytron/src/test/resources/org/wildfly/extension/elytron/security-realms.xml#L18

@Override
public String toString() {
return "JdbcRealmConfig{" +
", realmName='" + realmName + '\'' +
", enabled=" + enabled +
", principalQueries=" + principalQueries +
'}';
}
}
@@ -0,0 +1,27 @@
package io.quarkus.elytron.security.jdbc;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;

/**
* A configuration object for a jdbc based realm configuration,
* {@linkplain org.wildfly.security.auth.realm.jdbc.JdbcSecurityRealm}
*/
@ConfigRoot(name = "security.jdbc", phase = ConfigPhase.RUN_TIME)
public class JdbcSecurityRealmRuntimeConfig {

/**
* The principal-queries config
*/
@ConfigItem(name = "principal-query")
public PrincipalQueriesConfig principalQueries;
// https://github.com/wildfly/wildfly-core/blob/master/elytron/src/test/resources/org/wildfly/extension/elytron/security-realms.xml#L18

@Override
public String toString() {
return "JdbcRealmConfig{" +
"principalQueries=" + principalQueries +
'}';
}
}
Expand Up @@ -16,13 +16,12 @@
import io.quarkus.elytron.security.deployment.SecurityRealmBuildItem;
import io.quarkus.elytron.security.ldap.LdapRecorder;
import io.quarkus.elytron.security.ldap.QuarkusDirContextFactory;
import io.quarkus.elytron.security.ldap.config.LdapSecurityRealmConfig;
import io.quarkus.elytron.security.ldap.config.LdapSecurityRealmBuildTimeConfig;
import io.quarkus.elytron.security.ldap.config.LdapSecurityRealmRuntimeConfig;
import io.quarkus.runtime.RuntimeValue;

class ElytronSecurityLdapProcessor {

LdapSecurityRealmConfig ldap;

@BuildStep
CapabilityBuildItem capability() {
return new CapabilityBuildItem(Capability.SECURITY_ELYTRON_LDAP);
Expand All @@ -36,29 +35,29 @@ FeatureBuildItem feature() {
/**
* Check to see if a LdapRealmConfig was specified and enabled and create a
* {@linkplain org.wildfly.security.auth.realm.ldap.LdapSecurityRealm}
*
* @param recorder - runtime security recorder
* @param securityRealm - the producer factory for the SecurityRealmBuildItem
* @throws Exception - on any failure
*/
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
void configureLdapRealmAuthConfig(LdapRecorder recorder,
LdapSecurityRealmBuildTimeConfig ldapSecurityRealmBuildTimeConfig,
LdapSecurityRealmRuntimeConfig ldapSecurityRealmRuntimeConfig,
BuildProducer<SecurityRealmBuildItem> securityRealm,
BeanContainerBuildItem beanContainerBuildItem //we need this to make sure ArC is initialized
) throws Exception {
if (ldap.enabled) {
RuntimeValue<SecurityRealm> realm = recorder.createRealm(ldap);
securityRealm.produce(new SecurityRealmBuildItem(realm, ldap.realmName, null));
if (!ldapSecurityRealmBuildTimeConfig.enabled) {
return;
}

RuntimeValue<SecurityRealm> realm = recorder.createRealm(ldapSecurityRealmRuntimeConfig);
securityRealm.produce(new SecurityRealmBuildItem(realm, ldapSecurityRealmBuildTimeConfig.realmName, null));
}

@BuildStep
ElytronPasswordMarkerBuildItem marker() {
if (ldap.enabled) {
return new ElytronPasswordMarkerBuildItem();
ElytronPasswordMarkerBuildItem marker(LdapSecurityRealmBuildTimeConfig ldapSecurityRealmBuildTimeConfig) {
if (!ldapSecurityRealmBuildTimeConfig.enabled) {
return null;
}
return null;
return new ElytronPasswordMarkerBuildItem();
}

@BuildStep
Expand Down
Expand Up @@ -15,7 +15,7 @@
import io.quarkus.elytron.security.ldap.config.AttributeMappingConfig;
import io.quarkus.elytron.security.ldap.config.DirContextConfig;
import io.quarkus.elytron.security.ldap.config.IdentityMappingConfig;
import io.quarkus.elytron.security.ldap.config.LdapSecurityRealmConfig;
import io.quarkus.elytron.security.ldap.config.LdapSecurityRealmRuntimeConfig;
import io.quarkus.runtime.RuntimeValue;
import io.quarkus.runtime.annotations.Recorder;

Expand All @@ -25,19 +25,19 @@ public class LdapRecorder {
/**
* Create a runtime value for a {@linkplain LdapSecurityRealm}
*
* @param config - the realm config
* @return - runtime value wrapper for the SecurityRealm
* @param runtimeConfig the realm config
* @return runtime value wrapper for the SecurityRealm
*/
public RuntimeValue<SecurityRealm> createRealm(LdapSecurityRealmConfig config) {
public RuntimeValue<SecurityRealm> createRealm(LdapSecurityRealmRuntimeConfig runtimeConfig) {
LdapSecurityRealmBuilder builder = LdapSecurityRealmBuilder.builder()
.setDirContextSupplier(createDirContextSupplier(config.dirContext))
.setDirContextSupplier(createDirContextSupplier(runtimeConfig.dirContext))
.identityMapping()
.map(createAttributeMappings(config.identityMapping))
.setRdnIdentifier(config.identityMapping.rdnIdentifier)
.setSearchDn(config.identityMapping.searchBaseDn)
.map(createAttributeMappings(runtimeConfig.identityMapping))
.setRdnIdentifier(runtimeConfig.identityMapping.rdnIdentifier)
.setSearchDn(runtimeConfig.identityMapping.searchBaseDn)
.build();

if (config.directVerification) {
if (runtimeConfig.directVerification) {
builder.addDirectEvidenceVerification(false);
}

Expand All @@ -47,8 +47,8 @@ public RuntimeValue<SecurityRealm> createRealm(LdapSecurityRealmConfig config) {
private ExceptionSupplier<DirContext, NamingException> createDirContextSupplier(DirContextConfig dirContext) {
DirContextFactory dirContextFactory = new QuarkusDirContextFactory(
dirContext.url,
dirContext.principal,
dirContext.password);
dirContext.principal.orElse(null),
dirContext.password.orElse(null));
return () -> dirContextFactory.obtainDirContext(DirContextFactory.ReferralMode.IGNORE);
}

Expand Down
@@ -1,5 +1,7 @@
package io.quarkus.elytron.security.ldap.config;

import java.util.Optional;

import io.quarkus.runtime.annotations.ConfigGroup;
import io.quarkus.runtime.annotations.ConfigItem;

Expand All @@ -16,13 +18,13 @@ public class DirContextConfig {
* The principal: user which is used to connect to ldap server (also named "bindDn")
*/
@ConfigItem
public String principal;
public Optional<String> principal;

/**
* The password which belongs to the principal (also named "bindCredential")
*/
@ConfigItem
public String password;
public Optional<String> password;

@Override
public String toString() {
Expand Down
@@ -0,0 +1,33 @@
package io.quarkus.elytron.security.ldap.config;

import io.quarkus.runtime.annotations.ConfigItem;
import io.quarkus.runtime.annotations.ConfigPhase;
import io.quarkus.runtime.annotations.ConfigRoot;

/**
* A configuration object for a LDAP based realm configuration,
* {@linkplain org.wildfly.security.auth.realm.ldap.LdapSecurityRealm}
*/
@ConfigRoot(name = "security.ldap", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
public class LdapSecurityRealmBuildTimeConfig {

/**
* The option to enable the ldap elytron module
*/
@ConfigItem
public boolean enabled;

/**
* The elytron realm name
*/
@ConfigItem(defaultValue = "Quarkus")
public String realmName;

@Override
public String toString() {
return "LdapSecurityRealmBuildTimeConfig{" +
"enabled=" + enabled +
", realmName='" + realmName + '\'' +
'}';
}
}
Expand Up @@ -5,23 +5,11 @@
import io.quarkus.runtime.annotations.ConfigRoot;

/**
* A configuration object for a jdbc based realm configuration,
* Runtime configuration object for a LDAP based realm configuration,
* {@linkplain org.wildfly.security.auth.realm.ldap.LdapSecurityRealm}
*/
@ConfigRoot(name = "security.ldap", phase = ConfigPhase.BUILD_AND_RUN_TIME_FIXED)
public class LdapSecurityRealmConfig {

/**
* The option to enable the ldap elytron module
*/
@ConfigItem
public boolean enabled;

/**
* The elytron realm name
*/
@ConfigItem(defaultValue = "Quarkus")
public String realmName;
@ConfigRoot(name = "security.ldap", phase = ConfigPhase.RUN_TIME)
public class LdapSecurityRealmRuntimeConfig {

/**
* Provided credentials are verified against ldap?
Expand All @@ -43,10 +31,8 @@ public class LdapSecurityRealmConfig {

@Override
public String toString() {
return "LdapSecurityRealmConfig{" +
"enabled=" + enabled +
", realmName='" + realmName + '\'' +
", directVerification=" + directVerification +
return "LdapSecurityRealmRuntimeConfig{" +
"directVerification=" + directVerification +
", dirContext=" + dirContext +
", identityMapping=" + identityMapping +
'}';
Expand Down
Expand Up @@ -17,8 +17,9 @@
import io.quarkus.deployment.builditem.FeatureBuildItem;
import io.quarkus.elytron.security.deployment.ElytronTokenMarkerBuildItem;
import io.quarkus.elytron.security.deployment.SecurityRealmBuildItem;
import io.quarkus.elytron.security.oauth2.runtime.OAuth2Config;
import io.quarkus.elytron.security.oauth2.runtime.OAuth2BuildTimeConfig;
import io.quarkus.elytron.security.oauth2.runtime.OAuth2Recorder;
import io.quarkus.elytron.security.oauth2.runtime.OAuth2RuntimeConfig;
import io.quarkus.elytron.security.oauth2.runtime.auth.OAuth2AuthMechanism;
import io.quarkus.runtime.RuntimeValue;
import io.quarkus.security.identity.SecurityIdentityAugmentor;
Expand All @@ -32,8 +33,6 @@
class OAuth2DeploymentProcessor {
private static final String REALM_NAME = "OAuth2";

OAuth2Config oauth2;

@BuildStep
CapabilityBuildItem capability() {
return new CapabilityBuildItem(Capability.SECURITY_ELYTRON_OAUTH2);
Expand Down Expand Up @@ -61,29 +60,33 @@ ExtensionSslNativeSupportBuildItem activateSslNativeSupport() {
@BuildStep
@Record(ExecutionTime.RUNTIME_INIT)
AdditionalBeanBuildItem configureOauth2RealmAuthConfig(OAuth2Recorder recorder,
OAuth2BuildTimeConfig oauth2BuildTimeConfig,
OAuth2RuntimeConfig oauth2RuntimeConfig,
BuildProducer<SecurityRealmBuildItem> securityRealm) throws Exception {
if (oauth2.enabled) {
RuntimeValue<SecurityRealm> realm = recorder.createRealm(oauth2);
securityRealm.produce(new SecurityRealmBuildItem(realm, REALM_NAME, null));
return AdditionalBeanBuildItem.unremovableOf(OAuth2AuthMechanism.class);
if (!oauth2BuildTimeConfig.enabled) {
return null;
}
return null;

RuntimeValue<SecurityRealm> realm = recorder.createRealm(oauth2RuntimeConfig);
securityRealm.produce(new SecurityRealmBuildItem(realm, REALM_NAME, null));
return AdditionalBeanBuildItem.unremovableOf(OAuth2AuthMechanism.class);
}

@BuildStep
ElytronTokenMarkerBuildItem marker() {
if (oauth2.enabled) {
return new ElytronTokenMarkerBuildItem();
ElytronTokenMarkerBuildItem marker(OAuth2BuildTimeConfig oauth2BuildTimeConfig) {
if (!oauth2BuildTimeConfig.enabled) {
return null;
}
return null;
return new ElytronTokenMarkerBuildItem();
}

@BuildStep
@Record(ExecutionTime.STATIC_INIT)
SyntheticBeanBuildItem augmentor(OAuth2Recorder recorder) {
SyntheticBeanBuildItem augmentor(OAuth2Recorder recorder,
OAuth2BuildTimeConfig oauth2BuildTimeConfig) {
return SyntheticBeanBuildItem.configure(SecurityIdentityAugmentor.class)
.scope(ApplicationScoped.class)
.runtimeValue(recorder.augmentor(oauth2))
.runtimeValue(recorder.augmentor(oauth2BuildTimeConfig))
.unremovable()
.done();
}
Expand Down

0 comments on commit ce2e424

Please sign in to comment.