VYPR
High severity8.1OSV Advisory· Published Mar 4, 2025· Updated May 18, 2026

CVE-2025-23368

CVE-2025-23368

Description

A flaw was found in Wildfly Elytron integration. The component does not implement sufficient measures to prevent multiple failed authentication attempts within a short time frame, making it more susceptible to brute force attacks via CLI.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

Wildfly Elytron integration lacks rate limiting on authentication attempts, enabling brute force attacks via CLI.

Vulnerability

Description

The Wildfly Elytron integration contains a flaw where it does not implement sufficient measures to prevent multiple failed authentication attempts within a short time frame. This absence of rate limiting makes the component susceptible to brute force attacks via the command-line interface (CLI) [1][2][3].

Exploitation

An attacker with network access to the Wildfly management CLI can repeatedly attempt authentication without being throttled. No prior authentication or special privileges are required beyond network connectivity to the management endpoint. The lack of account lockout or progressive delays allows an attacker to systematically guess credentials [3].

Impact

Successful brute force exploitation could lead to unauthorized access to the Wildfly management interface. An attacker who gains valid credentials can then perform administrative actions on the application server, potentially compromising the entire system [3].

Mitigation

Red Hat has released security updates to address this vulnerability. Patches are available via RHSA-2026:18054, RHSA-2026:18055, and RHSA-2026:18059 for affected Red Hat Enterprise Linux and JBoss Enterprise Application Platform versions. Users are advised to apply the updates promptly [1][2][4].

AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.wildfly.core:wildfly-elytron-integrationMaven
>= 32.0.0.Beta1, < 32.0.0.Beta332.0.0.Beta3
org.wildfly.core:wildfly-elytron-integrationMaven
< 31.0.3.Final31.0.3.Final

Affected products

1

Patches

2
11e873031c52

Merge pull request #6635 from darranl/WFCORE-7192/combined

https://github.com/wildfly/wildfly-coreDarran LofthouseFeb 7, 2026via ghsa
12 files changed · +311 100
  • elytron/src/main/java/org/wildfly/extension/elytron/CachingRealmDefinition.java+46 23 modified
    @@ -7,14 +7,18 @@
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.ElytronDefinition.commonDependencies;
    -import static org.wildfly.extension.elytron.ElytronExtension.getRequiredService;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
    +
    +import java.util.Map;
    +import java.util.concurrent.ConcurrentHashMap;
    +import java.util.function.Consumer;
    +import java.util.function.Function;
     
     import org.jboss.as.controller.AbstractAddStepHandler;
     import org.jboss.as.controller.AttributeDefinition;
     import org.jboss.as.controller.OperationContext;
     import org.jboss.as.controller.OperationFailedException;
     import org.jboss.as.controller.OperationStepHandler;
    -import org.jboss.as.controller.PathAddress;
     import org.jboss.as.controller.PathElement;
     import org.jboss.as.controller.ResourceDefinition;
     import org.jboss.as.controller.RunningMode;
    @@ -32,8 +36,8 @@
     import org.jboss.msc.service.ServiceBuilder;
     import org.jboss.msc.service.ServiceController;
     import org.jboss.msc.service.ServiceName;
    -import org.jboss.msc.service.ServiceRegistry;
     import org.jboss.msc.service.ServiceTarget;
    +import org.jboss.msc.service.StartException;
     import org.jboss.msc.value.InjectedValue;
     import org.wildfly.extension.elytron._private.ElytronSubsystemMessages;
     import org.wildfly.security.auth.realm.CacheableSecurityRealm;
    @@ -73,6 +77,10 @@ class CachingRealmDefinition extends SimpleResourceDefinition {
     
         static final AttributeDefinition[] ATTRIBUTES = new AttributeDefinition[] {REALM_NAME, MAXIMUM_ENTRIES, MAXIMUM_AGE};
     
    +    // Callers are expected to just use a single method get / put / remove not multiple calls so we don't
    +    // need complex locking beyond the Map itself..
    +    private static final Map<String, CachingSecurityRealm> REALMS = new ConcurrentHashMap<>();
    +
         private static final AbstractAddStepHandler ADD = new RealmAddHandler();
         private static final OperationStepHandler REMOVE = new TrivialCapabilityServiceRemoveHandler(ADD, SECURITY_REALM_RUNTIME_CAPABILITY);
     
    @@ -114,36 +122,55 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 int maxEntries = MAXIMUM_ENTRIES.resolveModelAttribute(context, model).asInt();
                 long maxAge = MAXIMUM_AGE.resolveModelAttribute(context, model).asInt();
                 InjectedValue<SecurityRealm> cacheableRealmValue = new InjectedValue<>();
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(realmName, createService(cacheableRealm, maxEntries, maxAge, cacheableRealmValue));
    +
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            Consumer<SecurityRealm> valueConsumer = serviceBuilder.provides(realmName);
    +
    +            final Function<SecurityRealm, SecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), SecurityRealm.class, serviceBuilder);
    +
    +            serviceBuilder.setInstance(createService(context.getCurrentAddressValue(), cacheableRealm, maxEntries, maxAge, cacheableRealmValue, realmTransformer, valueConsumer));
     
                 addRealmDependency(context, serviceBuilder, cacheableRealm, cacheableRealmValue);
                 commonDependencies(serviceBuilder).setInitialMode(context.getRunningMode() == RunningMode.ADMIN_ONLY ? ServiceController.Mode.LAZY : ServiceController.Mode.ACTIVE).install();
             }
     
    -        private TrivialService<SecurityRealm> createService(String realmName, int maxEntries, long maxAge, InjectedValue<SecurityRealm> injector) {
    -            return new TrivialService<>((TrivialService.ValueSupplier<SecurityRealm>) () -> {
    -                SecurityRealm securityRealm = injector.getValue();
    +        private TrivialService<SecurityRealm> createService(String ourRealmName, String wrappedRealmName, int maxEntries, long maxAge,
    +            InjectedValue<SecurityRealm> injector, Function<SecurityRealm, SecurityRealm> realmTransformer, Consumer<SecurityRealm> valueConsumer) {
    +            return new TrivialService<>(new TrivialService.ValueSupplier<SecurityRealm>() {
    +
    +                @Override
    +                public SecurityRealm get() throws StartException {
    +                    SecurityRealm securityRealm = injector.getValue();
     
    -                if (securityRealm instanceof CacheableSecurityRealm) {
    -                    RealmIdentityCache cache = createRealmIdentityCache(maxEntries, maxAge);
    -                    CacheableSecurityRealm cacheableRealm = CacheableSecurityRealm.class.cast(securityRealm);
    +                    if (securityRealm instanceof CacheableSecurityRealm) {
    +                        RealmIdentityCache cache = createRealmIdentityCache(maxEntries, maxAge);
    +                        CacheableSecurityRealm cacheableRealm = CacheableSecurityRealm.class.cast(securityRealm);
     
    -                    if (securityRealm instanceof ModifiableSecurityRealm) {
    -                        return new CachingModifiableSecurityRealm(cacheableRealm, cache);
    +                        CachingSecurityRealm cachingRealm = securityRealm instanceof ModifiableSecurityRealm ?
    +                            new CachingModifiableSecurityRealm(cacheableRealm, cache) : new CachingSecurityRealm(cacheableRealm, cache);
    +
    +                        REALMS.put(ourRealmName, cachingRealm);
    +
    +                        return realmTransformer.apply(cachingRealm);
                         }
     
    -                    return new CachingSecurityRealm(cacheableRealm, cache);
    +                    throw ElytronSubsystemMessages.ROOT_LOGGER.realmDoesNotSupportCache(wrappedRealmName);
                     }
     
    -                throw ElytronSubsystemMessages.ROOT_LOGGER.realmDoesNotSupportCache(realmName);
    -            });
    +                @Override
    +                public void dispose() {
    +                    REALMS.remove(ourRealmName);
    +                }
    +
    +            }, valueConsumer);
             }
     
             private LRURealmIdentityCache createRealmIdentityCache(int maxEntries, long maxAge) {
                 return new LRURealmIdentityCache(maxEntries, maxAge);
             }
     
    -        private void addRealmDependency(OperationContext context, ServiceBuilder<SecurityRealm> serviceBuilder, String realmName, Injector<SecurityRealm> securityRealmInjector) {
    +        private void addRealmDependency(OperationContext context, ServiceBuilder<?> serviceBuilder, String realmName, Injector<SecurityRealm> securityRealmInjector) {
                 String runtimeCapability = RuntimeCapability.buildDynamicCapabilityName(SECURITY_REALM_CAPABILITY, realmName);
                 ServiceName realmServiceName = context.getCapabilityServiceName(runtimeCapability, SecurityRealm.class);
                 REALM_SERVICE_UTIL.addInjection(serviceBuilder, securityRealmInjector, realmServiceName);
    @@ -165,15 +192,11 @@ private ClearCacheHandler() {
     
             @Override
             protected void executeRuntimeStep(final OperationContext context, final ModelNode operation) throws OperationFailedException {
    -            ServiceRegistry serviceRegistry = context.getServiceRegistry(true);
    -            PathAddress currentAddress = context.getCurrentAddress();
    -            RuntimeCapability<Void> runtimeCapability = SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(currentAddress.getLastElement().getValue());
    -            ServiceName realmName = runtimeCapability.getCapabilityServiceName();
    -            ServiceController<SecurityRealm> serviceController = getRequiredService(serviceRegistry, realmName, SecurityRealm.class);
    -            if(serviceController.getState() != ServiceController.State.UP) {
    +            CachingSecurityRealm securityRealm = REALMS.get(context.getCurrentAddressValue());
    +            if (securityRealm == null) {
                     throw ElytronSubsystemMessages.ROOT_LOGGER.cachedRealmServiceNotAvailable();
                 }
    -            CachingSecurityRealm securityRealm = CachingSecurityRealm.class.cast(serviceController.getValue());
    +
                 securityRealm.removeAllFromCache();
             }
         }
    
  • elytron/src/main/java/org/wildfly/extension/elytron/CustomComponentDefinition.java+26 9 modified
    @@ -16,6 +16,7 @@
     import java.security.PrivilegedExceptionAction;
     import java.util.Map;
     import java.util.Set;
    +import java.util.function.BiFunction;
     import java.util.function.Function;
     
     import org.jboss.as.controller.AbstractAddStepHandler;
    @@ -58,14 +59,14 @@ class CustomComponentDefinition<C, T> extends SimpleResourceDefinition {
     
         static final AttributeDefinition[] ATTRIBUTES = {MODULE, CLASS_NAME, CONFIGURATION};
     
    -    CustomComponentDefinition(Class<C> serviceType, Function<C, T> wrapper, String pathKey, @SuppressWarnings("rawtypes") RuntimeCapability ... runtimeCapabilities) {
    +    CustomComponentDefinition(Class<C> serviceType, CustomComponentTransformer<C, T> transformer, String pathKey, @SuppressWarnings("rawtypes") RuntimeCapability ... runtimeCapabilities) {
             super(addAddRemoveHandlers(new Parameters(PathElement.pathElement(pathKey), ElytronExtension.getResourceDescriptionResolver(pathKey))
                 .setAddRestartLevel(OperationEntry.Flag.RESTART_RESOURCE_SERVICES)
                 .setRemoveRestartLevel(OperationEntry.Flag.RESTART_RESOURCE_SERVICES)
    -            .setCapabilities(runtimeCapabilities), serviceType, wrapper, runtimeCapabilities));
    +            .setCapabilities(runtimeCapabilities), serviceType, transformer, runtimeCapabilities));
         }
     
    -    private static <C, T> Parameters addAddRemoveHandlers(Parameters parameters, Class<C> serviceType, Function<C, T> wrapper, RuntimeCapability<?> ... runtimeCapabilities) {
    +    private static <C, T> Parameters addAddRemoveHandlers(Parameters parameters, Class<C> serviceType, CustomComponentTransformer<C, T> wrapper, RuntimeCapability<?> ... runtimeCapabilities) {
             AbstractAddStepHandler add = new ComponentAddHandler<>(serviceType, wrapper, runtimeCapabilities);
             OperationStepHandler remove = new TrivialCapabilityServiceRemoveHandler(add, runtimeCapabilities);
     
    @@ -86,13 +87,13 @@ private static class ComponentAddHandler<C, T> extends BaseAddHandler {
     
             private final RuntimeCapability<?>[] runtimeCapabilities;
             private final Class<C> serviceType;
    -        private final Function<C, T> wrapper;
    +        private final CustomComponentTransformer<C, T> transformer;
     
    -        private ComponentAddHandler(Class<C> serviceType, Function<C, T> wrapper, RuntimeCapability<?> ... runtimeCapabilities) {
    +        private ComponentAddHandler(Class<C> serviceType, CustomComponentTransformer<C, T> transformer, RuntimeCapability<?> ... runtimeCapabilities) {
                 super(Set.of(runtimeCapabilities));
                 this.runtimeCapabilities = runtimeCapabilities;
                 this.serviceType = serviceType;
    -            this.wrapper = wrapper;
    +            this.transformer = transformer;
             }
     
             @Override
    @@ -115,8 +116,11 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                     serviceBuilder.addAliases(toServiceName(runtimeCapabilities[i], address));
                 }
     
    +            String name = context.getCurrentAddressValue();
    +            Object wrapperContext = transformer.prepareTransformer(name, serviceBuilder);
    +
                 commonRequirements(serviceBuilder)
    -                .setInstance(new TrivialService<>(() -> createValue(module, className, configurationMap)))
    +                .setInstance(new TrivialService<>(() -> createValue(wrapperContext, module, className, configurationMap)))
                     .setInitialMode(Mode.ACTIVE)
                     .install();
             }
    @@ -125,7 +129,7 @@ private ServiceName toServiceName(RuntimeCapability<?> runtimeCapability, String
                 return runtimeCapability.fromBaseCapability(addressValue).getCapabilityServiceName();
             }
     
    -        private T createValue(String module, String className, Map<String, String> configuration) throws StartException {
    +        private T createValue(Object transformerContext, String module, String className, Map<String, String> configuration) throws StartException {
                 final ClassLoader classLoader;
                 try {
                     classLoader = doPrivileged((PrivilegedExceptionAction<ClassLoader>) () -> resolveClassLoader(module));
    @@ -143,7 +147,7 @@ private T createValue(String module, String className, Map<String, String> confi
                         }
                     }
     
    -                return wrapper.apply(component);
    +                return transformer.apply(transformerContext, component);
                 } catch (PrivilegedActionException e) {
                     throw new StartException(e.getCause());
                 } catch (Exception e) {
    @@ -156,4 +160,17 @@ private T createValue(String module, String className, Map<String, String> confi
             }
         }
     
    +    static <A, B> CustomComponentTransformer<A, B> wrapFunction(Function<A, B> function) {
    +        return (s, a ) -> function.apply(a);
    +    }
    +
    +    @FunctionalInterface
    +    interface CustomComponentTransformer<A, B> extends BiFunction<Object, A, B> {
    +
    +        default Object prepareTransformer(final String name, final ServiceBuilder<?> serviceBuilder) {
    +            return name;
    +        }
    +
    +    }
    +
     }
    
  • elytron/src/main/java/org/wildfly/extension/elytron/DistributedRealmDefinition.java+15 9 modified
    @@ -8,7 +8,12 @@
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.ElytronDefinition.commonDependencies;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
     
    +import java.util.ArrayList;
    +import java.util.List;
    +import java.util.function.Consumer;
    +import java.util.function.Function;
     
     import org.jboss.as.controller.AbstractAddStepHandler;
     import org.jboss.as.controller.AttributeDefinition;
    @@ -32,16 +37,11 @@
     import org.jboss.msc.service.ServiceName;
     import org.jboss.msc.service.ServiceTarget;
     import org.jboss.msc.value.InjectedValue;
    -
     import org.wildfly.security.auth.realm.DistributedSecurityRealm;
     import org.wildfly.security.auth.server.SecurityDomain;
     import org.wildfly.security.auth.server.SecurityRealm;
     import org.wildfly.security.auth.server.event.SecurityRealmUnavailableEvent;
     
    -import java.util.ArrayList;
    -import java.util.List;
    -import java.util.function.Consumer;
    -
     /**
      * A {@link ResourceDefinition} for a {@link SecurityRealm} for authentication and authorization of identities distributed between multiple realms.
      *
    @@ -110,6 +110,12 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
     
                 List<String> distributedRealms = REALMS.unwrap(context, model);
     
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            Consumer<SecurityRealm> valueConsumer = serviceBuilder.provides(realmName);
    +
    +            final Function<SecurityRealm, SecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), SecurityRealm.class, serviceBuilder);
    +
                 TrivialService<SecurityRealm> distributedRealmService = new TrivialService<SecurityRealm>(() ->
                 {
                     SecurityRealm[] realms = new SecurityRealm[distributedRealmValues.size()];
    @@ -126,10 +132,10 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                         realms[i] = distributedRealmValues.get(i).getValue();
                     }
     
    -                return new DistributedSecurityRealm(ignoreUnavailableRealms, unavailableRealmConsumer, realms);
    -            });
    +                return realmTransformer.apply(new DistributedSecurityRealm(ignoreUnavailableRealms, unavailableRealmConsumer, realms));
    +            }, valueConsumer);
     
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(realmName, distributedRealmService);
    +            serviceBuilder.setInstance(distributedRealmService);
     
                 for (String distributedRealm : distributedRealms) {
                     InjectedValue<SecurityRealm> authorizationRealmValue = new InjectedValue<SecurityRealm>();
    @@ -142,7 +148,7 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                         .install();
             }
     
    -        private void addRealmDependency(OperationContext context, ServiceBuilder<SecurityRealm> serviceBuilder, String realmName, Injector<SecurityRealm> securityRealmInjector) {
    +        private void addRealmDependency(OperationContext context, ServiceBuilder<?> serviceBuilder, String realmName, Injector<SecurityRealm> securityRealmInjector) {
                 String runtimeCapability = RuntimeCapability.buildDynamicCapabilityName(SECURITY_REALM_CAPABILITY, realmName);
                 ServiceName realmServiceName = context.getCapabilityServiceName(runtimeCapability, SecurityRealm.class);
     
    
  • elytron/src/main/java/org/wildfly/extension/elytron/ElytronDefinition.java+18 14 modified
    @@ -5,7 +5,6 @@
     
     package org.wildfly.extension.elytron;
     
    -
     import static org.jboss.as.server.security.VirtualDomainUtil.VIRTUAL_SECURITY_DOMAIN_CREATION_SERVICE;
     import static org.wildfly.extension.elytron.Capabilities.AUTHENTICATION_CONTEXT_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.ELYTRON_RUNTIME_CAPABILITY;
    @@ -23,6 +22,7 @@
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_FACTORY_CREDENTIAL_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.SSL_CONTEXT_CAPABILITY;
    +import static org.wildfly.extension.elytron.CustomComponentDefinition.wrapFunction;
     import static org.wildfly.extension.elytron.ElytronExtension.isServerOrHostController;
     import static org.wildfly.extension.elytron.ElytronScheduledExecutorService.installScheduledExecutorService;
     import static org.wildfly.extension.elytron.ElytronScheduledExecutorService.uninstallScheduledExecutorService;
    @@ -41,6 +41,7 @@
     
     import javax.net.ssl.SSLContext;
     
    +import jakarta.security.auth.message.config.AuthConfigFactory;
     import org.jboss.as.controller.AbstractBoottimeAddStepHandler;
     import org.jboss.as.controller.AttributeMarshaller;
     import org.jboss.as.controller.AttributeParser;
    @@ -77,6 +78,7 @@
     import org.jboss.msc.service.ServiceName;
     import org.jboss.msc.service.ServiceRegistry;
     import org.jboss.msc.service.ServiceTarget;
    +import org.wildfly.extension.elytron.RealmDefinitions.CustomRealmBruteForceTransformer;
     import org.wildfly.extension.elytron.capabilities.CredentialSecurityFactory;
     import org.wildfly.extension.elytron.capabilities.PrincipalTransformer;
     import org.wildfly.extension.elytron.capabilities._private.SecurityEventListener;
    @@ -96,8 +98,6 @@
     import org.wildfly.security.jakarta.authz.AuthorizationRegistration;
     import org.wildfly.security.manager.action.ReadPropertyAction;
     
    -import jakarta.security.auth.message.config.AuthConfigFactory;
    -
     /**
      * Top level {@link ResourceDefinition} for the Elytron subsystem.
      *
    @@ -180,7 +180,7 @@ public void registerChildren(ManagementResourceRegistration resourceRegistration
     
             // Audit
             resourceRegistration.registerSubModel(AuditResourceDefinitions.getAggregateSecurityEventListenerDefinition());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(Consumer.class, SecurityEventListener::from,
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(Consumer.class, wrapFunction(SecurityEventListener::from),
                     ElytronDescriptionConstants.CUSTOM_SECURITY_EVENT_LISTENER, SECURITY_EVENT_LISTENER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(AuditResourceDefinitions.getFileAuditLogResourceDefinition());
             resourceRegistration.registerSubModel(AuditResourceDefinitions.getPeriodicRotatingFileAuditLogResourceDefinition());
    @@ -197,9 +197,9 @@ public void registerChildren(ManagementResourceRegistration resourceRegistration
     
             // Security Realms
             resourceRegistration.registerSubModel(new AggregateRealmDefinition());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(SecurityRealm.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_REALM, SECURITY_REALM_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(SecurityRealm.class, new CustomRealmBruteForceTransformer<>(SecurityRealm.class), ElytronDescriptionConstants.CUSTOM_REALM, SECURITY_REALM_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(ModifiableRealmDecorator.wrap(new CustomComponentDefinition<>(
    -                ModifiableSecurityRealm.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_MODIFIABLE_REALM,
    +                ModifiableSecurityRealm.class, new CustomRealmBruteForceTransformer<>(ModifiableSecurityRealm.class), ElytronDescriptionConstants.CUSTOM_MODIFIABLE_REALM,
                     MODIFIABLE_SECURITY_REALM_RUNTIME_CAPABILITY, SECURITY_REALM_RUNTIME_CAPABILITY)));
             resourceRegistration.registerSubModel(RealmDefinitions.getIdentityRealmDefinition());
             resourceRegistration.registerSubModel(new JdbcRealmDefinition());
    @@ -214,11 +214,11 @@ public void registerChildren(ManagementResourceRegistration resourceRegistration
             resourceRegistration.registerSubModel(new JaasRealmDefinition());
     
             // Security Factories
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(SecurityFactory.class, CredentialSecurityFactory::from, ElytronDescriptionConstants.CUSTOM_CREDENTIAL_SECURITY_FACTORY, SECURITY_FACTORY_CREDENTIAL_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(SecurityFactory.class, wrapFunction(CredentialSecurityFactory::from), ElytronDescriptionConstants.CUSTOM_CREDENTIAL_SECURITY_FACTORY, SECURITY_FACTORY_CREDENTIAL_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(KerberosSecurityFactoryDefinition.getKerberosSecurityFactoryDefinition());
     
             // Permission Mappers
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(PermissionMapper.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_PERMISSION_MAPPER, PERMISSION_MAPPER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(PermissionMapper.class, ElytronDefinition::identity, ElytronDescriptionConstants.CUSTOM_PERMISSION_MAPPER, PERMISSION_MAPPER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(PermissionMapperDefinitions.getLogicalPermissionMapper());
             resourceRegistration.registerSubModel(PermissionMapperDefinitions.getSimplePermissionMapper());
             resourceRegistration.registerSubModel(PermissionMapperDefinitions.getConstantPermissionMapper());
    @@ -230,26 +230,26 @@ public void registerChildren(ManagementResourceRegistration resourceRegistration
             resourceRegistration.registerSubModel(PrincipalDecoderDefinitions.getAggregatePrincipalDecoderDefinition());
             resourceRegistration.registerSubModel(PrincipalDecoderDefinitions.getConcatenatingPrincipalDecoder());
             resourceRegistration.registerSubModel(PrincipalDecoderDefinitions.getConstantPrincipalDecoder());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(PrincipalDecoder.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_PRINCIPAL_DECODER, PRINCIPAL_DECODER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(PrincipalDecoder.class, ElytronDefinition::identity, ElytronDescriptionConstants.CUSTOM_PRINCIPAL_DECODER, PRINCIPAL_DECODER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(PrincipalDecoderDefinitions.getX500AttributePrincipalDecoder());
     
             // Principal Transformers
             resourceRegistration.registerSubModel(PrincipalTransformerDefinitions.getAggregatePrincipalTransformerDefinition());
             resourceRegistration.registerSubModel(PrincipalTransformerDefinitions.getChainedPrincipalTransformerDefinition());
             resourceRegistration.registerSubModel(PrincipalTransformerDefinitions.getConstantPrincipalTransformerDefinition());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(Function.class, PrincipalTransformer::from, ElytronDescriptionConstants.CUSTOM_PRINCIPAL_TRANSFORMER, PRINCIPAL_TRANSFORMER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(Function.class, wrapFunction(PrincipalTransformer::from), ElytronDescriptionConstants.CUSTOM_PRINCIPAL_TRANSFORMER, PRINCIPAL_TRANSFORMER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(PrincipalTransformerDefinitions.getRegexPrincipalTransformerDefinition());
             resourceRegistration.registerSubModel(PrincipalTransformerDefinitions.getRegexValidatingPrincipalTransformerDefinition());
             resourceRegistration.registerSubModel(PrincipalTransformerDefinitions.getCasePrincipalTransformerDefinition());
     
             // Realm Mappers
             resourceRegistration.registerSubModel(RealmMapperDefinitions.getConstantRealmMapper());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(RealmMapper.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_REALM_MAPPER, REALM_MAPPER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(RealmMapper.class, ElytronDefinition::identity, ElytronDescriptionConstants.CUSTOM_REALM_MAPPER, REALM_MAPPER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(RealmMapperDefinitions.getMappedRegexRealmMapper());
             resourceRegistration.registerSubModel(RealmMapperDefinitions.getSimpleRegexRealmMapperDefinition());
     
             // Role Decoders
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(RoleDecoder.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_ROLE_DECODER, ROLE_DECODER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(RoleDecoder.class, ElytronDefinition::identity, ElytronDescriptionConstants.CUSTOM_ROLE_DECODER, ROLE_DECODER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(RoleDecoderDefinitions.getSimpleRoleDecoderDefinition());
             resourceRegistration.registerSubModel(RoleDecoderDefinitions.getSourceAddressRoleDecoderDefinition());
             resourceRegistration.registerSubModel(RoleDecoderDefinitions.getAggregateRoleDecoderDefinition());
    @@ -259,15 +259,15 @@ public void registerChildren(ManagementResourceRegistration resourceRegistration
             resourceRegistration.registerSubModel(RoleMapperDefinitions.getAddPrefixRoleMapperDefinition());
             resourceRegistration.registerSubModel(RoleMapperDefinitions.getAggregateRoleMapperDefinition());
             resourceRegistration.registerSubModel(RoleMapperDefinitions.getConstantRoleMapperDefinition());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(RoleMapper.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_ROLE_MAPPER, ROLE_MAPPER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(RoleMapper.class, ElytronDefinition::identity, ElytronDescriptionConstants.CUSTOM_ROLE_MAPPER, ROLE_MAPPER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(RoleMapperDefinitions.getLogicalRoleMapperDefinition());
             resourceRegistration.registerSubModel(RoleMapperDefinitions.getMappedRoleMapperDefinition());
             resourceRegistration.registerSubModel(RoleMapperDefinitions.getRegexRoleMapperDefinition());
     
             // Evidence Decoders
             resourceRegistration.registerSubModel(EvidenceDecoderDefinitions.getX500SubjectEvidenceDecoderDefinition());
             resourceRegistration.registerSubModel(EvidenceDecoderDefinitions.getX509SubjectAltNameEvidenceDecoderDefinition());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(EvidenceDecoder.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_EVIDENCE_DECODER, EVIDENCE_DECODER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(EvidenceDecoder.class, ElytronDefinition::identity, ElytronDescriptionConstants.CUSTOM_EVIDENCE_DECODER, EVIDENCE_DECODER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(EvidenceDecoderDefinitions.getAggregateEvidenceDecoderDefinition());
     
             // HTTP Mechanisms
    @@ -363,6 +363,10 @@ protected void revertUpdateToRuntime(OperationContext context, ModelNode operati
             });
         }
     
    +    private static <T, U> U identity(T t, U u) {
    +        return u;
    +    }
    +
         @Override
         public void registerAdditionalRuntimePackages(ManagementResourceRegistration resourceRegistration) {
             resourceRegistration.registerAdditionalRuntimePackages(RuntimePackageDependency.required("org.wildfly.security.elytron"));
    
  • elytron/src/main/java/org/wildfly/extension/elytron/FailoverRealmDefinition.java+12 5 modified
    @@ -8,7 +8,7 @@
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.ElytronDefinition.commonDependencies;
    -
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
     
     import org.jboss.as.controller.AbstractAddStepHandler;
     import org.jboss.as.controller.AttributeDefinition;
    @@ -40,6 +40,7 @@
     import org.wildfly.security.auth.server.event.SecurityRealmUnavailableEvent;
     
     import java.util.function.Consumer;
    +import java.util.function.Function;
     
     /**
      * A {@link ResourceDefinition} for a {@link SecurityRealm} which wraps one realm and fails over to another in case the first is unavailable.
    @@ -111,6 +112,12 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
     
                 boolean emitEvents = EMIT_EVENTS.resolveModelAttribute(context, model).asBoolean();
     
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            Consumer<SecurityRealm> valueConsumer = serviceBuilder.provides(realmName);
    +
    +            final Function<SecurityRealm, SecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), SecurityRealm.class, serviceBuilder);
    +
                 TrivialService<SecurityRealm> failoverRealmService = new TrivialService<SecurityRealm>(() ->
                 {
                     SecurityRealm delegate = delegateRealmValue.getValue();
    @@ -120,10 +127,10 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                             domain.handleSecurityEvent(new SecurityRealmUnavailableEvent(domain.getCurrentSecurityIdentity(), delegateRealm));
                         }
                     } : (e) -> {};
    -                return new FailoverSecurityRealm(delegate, failoverRealmValue.getValue(), failoverConsumer);
    -            });
    +                return realmTransformer.apply(new FailoverSecurityRealm(delegate, failoverRealmValue.getValue(), failoverConsumer));
    +            }, valueConsumer);
     
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(realmName, failoverRealmService);
    +            serviceBuilder.setInstance(failoverRealmService);
     
                 addRealmDependency(context, serviceBuilder, delegateRealm, delegateRealmValue);
                 addRealmDependency(context, serviceBuilder, failoverRealm, failoverRealmValue);
    @@ -133,7 +140,7 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                         .install();
             }
     
    -        private void addRealmDependency(OperationContext context, ServiceBuilder<SecurityRealm> serviceBuilder, String realmName, Injector<SecurityRealm> securityRealmInjector) {
    +        private void addRealmDependency(OperationContext context, ServiceBuilder<?> serviceBuilder, String realmName, Injector<SecurityRealm> securityRealmInjector) {
                 String runtimeCapability = RuntimeCapability.buildDynamicCapabilityName(SECURITY_REALM_CAPABILITY, realmName);
                 ServiceName realmServiceName = context.getCapabilityServiceName(runtimeCapability, SecurityRealm.class);
     
    
  • elytron/src/main/java/org/wildfly/extension/elytron/FileSystemRealmDefinition.java+21 5 modified
    @@ -20,6 +20,7 @@
     import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathName;
     import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathResolver;
     import static org.wildfly.extension.elytron.KeyStoreServiceUtil.getModifiableKeyStoreService;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
     import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
     
     import java.io.IOException;
    @@ -31,6 +32,8 @@
     import java.security.PrivateKey;
     import java.security.PublicKey;
     import java.security.UnrecoverableKeyException;
    +import java.util.function.Consumer;
    +import java.util.function.Function;
     import java.util.stream.Stream;
     
     import javax.crypto.SecretKey;
    @@ -72,6 +75,7 @@
     import org.wildfly.extension.elytron.FileAttributeDefinitions.PathResolver;
     import org.wildfly.security.auth.realm.FileSystemSecurityRealm;
     import org.wildfly.security.auth.realm.FileSystemSecurityRealmBuilder;
    +import org.wildfly.security.auth.server.ModifiableSecurityRealm;
     import org.wildfly.security.auth.server.NameRewriter;
     import org.wildfly.security.auth.server.RealmUnavailableException;
     import org.wildfly.security.auth.server.SecurityRealm;
    @@ -299,8 +303,8 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 ServiceTarget serviceTarget = context.getServiceTarget();
     
                 String address = context.getCurrentAddressValue();
    -            ServiceName mainServiceName = MODIFIABLE_SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
    -            ServiceName aliasServiceName = SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
    +            ServiceName modifiableServiceName = MODIFIABLE_SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
    +            ServiceName standardServiceName = SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
     
                 final int levels = LEVELS.resolveModelAttribute(context, model).asInt();
     
    @@ -327,6 +331,15 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 final SecretKey finalKey = key;
                 ServiceRegistry keyStoreServiceRegistry = context.getServiceRegistry(true);
     
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            // This is the Service that will get pulled into a SecurityDomain etc...
    +            Consumer<SecurityRealm> standardConsumer = serviceBuilder.provides(standardServiceName);
    +            // This is the modifiable variant for resources that support modification operations etc..
    +            Consumer<ModifiableSecurityRealm> modifiableConsumer = serviceBuilder.provides(modifiableServiceName);
    +
    +            Function<ModifiableSecurityRealm, ModifiableSecurityRealm> realmTransformer =
    +                    createBruteForceRealmTransformer(context.getCurrentAddressValue(), ModifiableSecurityRealm.class, serviceBuilder);
    +
                 TrivialService<SecurityRealm> fileSystemRealmService = new TrivialService<>(
                         new TrivialService.ValueSupplier<SecurityRealm>() {
     
    @@ -382,8 +395,12 @@ public SecurityRealm get() throws StartException {
                                     fileSystemRealmBuilder.setPrivateKey(privateKey);
                                     fileSystemRealmBuilder.setPublicKey(publicKey);
                                 }
    -                            return fileSystemRealmBuilder.build();
    +                            ModifiableSecurityRealm modifiable = fileSystemRealmBuilder.build();
    +                            ModifiableSecurityRealm wrapped = realmTransformer.apply(modifiable);
    +                            modifiableConsumer.accept(wrapped);
    +                            standardConsumer.accept(wrapped);
     
    +                            return modifiable;
                             }
     
                             @Override
    @@ -396,8 +413,6 @@ public void dispose() {
     
                         });
     
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(mainServiceName, fileSystemRealmService)
    -                    .addAliases(aliasServiceName);
                 if (credentialStore != null) {
                     serviceBuilder.requires(context.getCapabilityServiceName(buildDynamicCapabilityName(CREDENTIAL_STORE_CAPABILITY, credentialStore), CredentialStore.class));
                 }
    @@ -410,6 +425,7 @@ public void dispose() {
                     serviceBuilder.addDependency(PathManagerService.SERVICE_NAME, PathManager.class, pathManagerInjector);
                     serviceBuilder.requires(pathName(relativeTo));
                 }
    +            serviceBuilder.setInstance(fileSystemRealmService);
                 serviceBuilder.install();
             }
     
    
  • elytron/src/main/java/org/wildfly/extension/elytron/JaasRealmDefinition.java+26 17 modified
    @@ -5,6 +5,22 @@
     
     package org.wildfly.extension.elytron;
     
    +import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
    +import static org.wildfly.extension.elytron.ClassLoadingAttributeDefinitions.resolveClassLoader;
    +import static org.wildfly.extension.elytron.ElytronDefinition.commonDependencies;
    +import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathName;
    +import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathResolver;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
    +import static org.wildfly.extension.elytron.SecurityActions.doPrivileged;
    +import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
    +
    +import java.io.File;
    +import java.security.PrivilegedExceptionAction;
    +import java.util.function.Consumer;
    +import java.util.function.Function;
    +
    +import javax.security.auth.callback.CallbackHandler;
    +
     import org.jboss.as.controller.AbstractAddStepHandler;
     import org.jboss.as.controller.AttributeDefinition;
     import org.jboss.as.controller.OperationContext;
    @@ -31,18 +47,6 @@
     import org.wildfly.security.auth.realm.JaasSecurityRealm;
     import org.wildfly.security.auth.server.SecurityRealm;
     
    -import javax.security.auth.callback.CallbackHandler;
    -import java.io.File;
    -import java.security.PrivilegedExceptionAction;
    -
    -import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
    -import static org.wildfly.extension.elytron.ClassLoadingAttributeDefinitions.resolveClassLoader;
    -import static org.wildfly.extension.elytron.ElytronDefinition.commonDependencies;
    -import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathName;
    -import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathResolver;
    -import static org.wildfly.extension.elytron.SecurityActions.doPrivileged;
    -import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
    -
     /**
      * A {@link ResourceDefinition} for a {@link SecurityRealm} backed by a JAAS LoginContext.
      */
    @@ -127,6 +131,13 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
     
                 final InjectedValue<PathManager> pathManagerInjector = new InjectedValue<>();
     
    +            ServiceName realmName = runtimeCapability.getCapabilityServiceName(SecurityRealm.class);
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            Consumer<SecurityRealm> realmConsumer = serviceBuilder.provides(realmName);
    +
    +            Function<SecurityRealm, SecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), SecurityRealm.class, serviceBuilder);
    +
                 CallbackHandler finalCallbackHandler = callbackhandler;
                 TrivialService<SecurityRealm> jaasRealmService = new TrivialService<>(
                         new TrivialService.ValueSupplier<SecurityRealm>() {
    @@ -143,7 +154,7 @@ public SecurityRealm get() throws StartException {
                                     }
                                     rootPath = jaasConfigFile.getPath();
                                 }
    -                            return new JaasSecurityRealm(entryName, rootPath, classLoader, finalCallbackHandler);
    +                            return realmTransformer.apply(new JaasSecurityRealm(entryName, rootPath, classLoader, finalCallbackHandler));
                             }
     
                             @Override
    @@ -153,17 +164,15 @@ public void dispose() {
                                     pathResolver = null;
                                 }
                             }
    -                    });
    -
    -            ServiceName realmName = runtimeCapability.getCapabilityServiceName(SecurityRealm.class);
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(realmName, jaasRealmService);
    +                    }, realmConsumer);
     
                 if (relativeTo != null) {
                     serviceBuilder.addDependency(PathManagerService.SERVICE_NAME, PathManager.class, pathManagerInjector);
                     serviceBuilder.requires(pathName(relativeTo));
                 }
     
                 commonDependencies(serviceBuilder)
    +                    .setInstance(jaasRealmService)
                         .setInitialMode(ServiceController.Mode.ACTIVE)
                         .install();
             }
    
  • elytron/src/main/java/org/wildfly/extension/elytron/JdbcRealmDefinition.java+11 2 modified
    @@ -16,6 +16,7 @@
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.SCRAM_MAPPER;
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.SIMPLE_DIGEST_MAPPER;
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.UTF_8;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
     import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
     
     import java.nio.charset.Charset;
    @@ -24,6 +25,8 @@
     import java.util.HashMap;
     import java.util.List;
     import java.util.Map;
    +import java.util.function.Consumer;
    +import java.util.function.Function;
     
     import javax.sql.DataSource;
     
    @@ -612,8 +615,13 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 final JdbcSecurityRealmBuilder builder = JdbcSecurityRealm.builder();
                 builder.setHashCharset(charset);
     
    -            TrivialService<SecurityRealm> service = new TrivialService<SecurityRealm>(builder::build);
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(realmName, service);
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            Consumer<SecurityRealm> valueConsumer = serviceBuilder.provides(realmName);
    +
    +            Function<SecurityRealm, SecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), SecurityRealm.class, serviceBuilder);
    +
    +            TrivialService<SecurityRealm> service = new TrivialService<SecurityRealm>(() -> realmTransformer.apply(builder.build()), valueConsumer);
     
                 for (ModelNode query : principalQueries.asList()) {
                     String authenticationQuerySql = PrincipalQueryAttributes.SQL.resolveModelAttribute(context, query).asString();
    @@ -639,6 +647,7 @@ public void uninject() {
                     });
                 }
     
    +            serviceBuilder.setInstance(service);
                 commonDependencies(serviceBuilder)
                         .setInitialMode(context.getRunningMode() == RunningMode.ADMIN_ONLY ? ServiceController.Mode.LAZY : ServiceController.Mode.ACTIVE)
                         .install();
    
  • elytron/src/main/java/org/wildfly/extension/elytron/LdapRealmDefinition.java+26 6 modified
    @@ -14,11 +14,14 @@
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.HEX;
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.UTF_8;
     import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
     
     import java.nio.charset.Charset;
     import java.util.Arrays;
     import java.util.List;
     import java.util.Set;
    +import java.util.function.Consumer;
    +import java.util.function.Function;
     
     import javax.naming.InvalidNameException;
     import javax.naming.NamingException;
    @@ -59,6 +62,7 @@
     import org.wildfly.security.auth.realm.ldap.AttributeMapping;
     import org.wildfly.security.auth.realm.ldap.LdapSecurityRealmBuilder;
     import org.wildfly.security.auth.realm.ldap.LdapSecurityRealmBuilder.IdentityMappingBuilder;
    +import org.wildfly.security.auth.server.ModifiableSecurityRealm;
     import org.wildfly.security.auth.server.SecurityRealm;
     import org.wildfly.security.password.spec.Encoding;
     
    @@ -435,8 +439,8 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 ServiceTarget serviceTarget = context.getServiceTarget();
     
                 String address = context.getCurrentAddressValue();
    -            ServiceName mainServiceName = MODIFIABLE_SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
    -            ServiceName aliasServiceName = SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
    +            ServiceName modifiableServiceName = MODIFIABLE_SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
    +            ServiceName standardServiceName = SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
     
                 final LdapSecurityRealmBuilder builder = LdapSecurityRealmBuilder.builder();
     
    @@ -455,10 +459,26 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 builder.setHashEncoding(HEX.equals(hashEncoding) ? Encoding.HEX : Encoding.BASE64);
                 builder.setHashCharset(charset);
     
    -            TrivialService<SecurityRealm> ldapRealmService = new TrivialService<>(builder::build);
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(mainServiceName, ldapRealmService)
    -                    .addAliases(aliasServiceName);
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            // This is the Service that will get pulled into a SecurityDomain etc...
    +            Consumer<SecurityRealm> standardConsumer = serviceBuilder.provides(standardServiceName);
    +            // This is the modifiable variant for resources that support modification operations etc..
    +            Consumer<ModifiableSecurityRealm> modifiableConsumer = serviceBuilder.provides(modifiableServiceName);
     
    +            Function<ModifiableSecurityRealm, ModifiableSecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), ModifiableSecurityRealm.class, serviceBuilder);
    +
    +            TrivialService<SecurityRealm> ldapRealmService =
    +                    new TrivialService<>(() -> {
    +                        ModifiableSecurityRealm modifiable = builder.build();
    +                        ModifiableSecurityRealm wrapped = realmTransformer.apply(modifiable);
    +                        modifiableConsumer.accept(wrapped);
    +                        standardConsumer.accept(wrapped);
    +
    +                        return modifiable;
    +                    });
    +
    +            serviceBuilder.setInstance(ldapRealmService);
                 commonDependencies(serviceBuilder);
     
                 configureIdentityMapping(context, model, builder);
    @@ -467,7 +487,7 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 serviceBuilder.setInitialMode(ServiceController.Mode.ACTIVE).install();
             }
     
    -        private void configureDirContext(OperationContext context, ModelNode model, LdapSecurityRealmBuilder realmBuilder, ServiceBuilder<SecurityRealm> serviceBuilder) throws OperationFailedException {
    +        private void configureDirContext(OperationContext context, ModelNode model, LdapSecurityRealmBuilder realmBuilder, ServiceBuilder<?> serviceBuilder) throws OperationFailedException {
                 String dirContextName = DIR_CONTEXT.resolveModelAttribute(context, model).asStringOrNull();
     
                 String runtimeCapability = RuntimeCapability.buildDynamicCapabilityName(DIR_CONTEXT_CAPABILITY, dirContextName);
    
  • elytron/src/main/java/org/wildfly/extension/elytron/PropertiesRealmDefinition.java+22 8 modified
    @@ -5,6 +5,7 @@
     
     package org.wildfly.extension.elytron;
     
    +
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.BASE64;
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.HEX;
    @@ -13,6 +14,7 @@
     import static org.wildfly.extension.elytron.ElytronExtension.getRequiredService;
     import static org.wildfly.extension.elytron.FileAttributeDefinitions.RELATIVE_TO;
     import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathName;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
     import static org.wildfly.extension.elytron.SecurityActions.doPrivileged;
     import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
     
    @@ -29,6 +31,8 @@
     import java.util.ArrayList;
     import java.util.Date;
     import java.util.List;
    +import java.util.function.Function;
    +import java.util.function.LongSupplier;
     
     import org.jboss.as.controller.AbstractAddStepHandler;
     import org.jboss.as.controller.AttributeDefinition;
    @@ -58,6 +62,7 @@
     import org.jboss.msc.service.ServiceName;
     import org.jboss.msc.service.StartException;
     import org.jboss.msc.value.InjectedValue;
    +import org.wildfly.common.function.ExceptionBiConsumer;
     import org.wildfly.extension.elytron.TrivialResourceDefinition.Builder;
     import org.wildfly.extension.elytron.TrivialService.ValueSupplier;
     import org.wildfly.security.auth.SupportLevel;
    @@ -181,6 +186,8 @@ protected ValueSupplier<SecurityRealm> getValueSupplier(ServiceBuilder<SecurityR
                     }
                 }
     
    +            Function<SecurityRealm, SecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), SecurityRealm.class, serviceBuilder);
                 return new ValueSupplier<SecurityRealm>() {
     
                     private final List<Handle> callbackHandles = new ArrayList<>();
    @@ -192,15 +199,17 @@ public SecurityRealm get() throws StartException {
     
                         try (InputStream usersInputStream = new FileInputStream(usersFile);
                                 InputStream groupsInputStream = groupsFile != null ? new FileInputStream(groupsFile) : null) {
    -                        return new RealmWrapper(LegacyPropertiesSecurityRealm.builder()
    +                        LegacyPropertiesSecurityRealm baseRealm = LegacyPropertiesSecurityRealm.builder()
                                     .setUsersStream(usersInputStream)
                                     .setGroupsStream(groupsInputStream)
                                     .setPlainText(plainText)
                                     .setGroupsAttribute(groupsAttribute)
                                     .setDefaultRealm(digestRealmName)
                                     .setHashEncoding(BASE64.equalsIgnoreCase(hashEncoding) ? Encoding.BASE64 : Encoding.HEX)
                                     .setHashCharset(Charset.forName(hashCharset))
    -                                .build(), usersFile, groupsFile);
    +                                .build();
    +
    +                        return new RealmWrapper(realmTransformer.apply(baseRealm), usersFile, groupsFile, baseRealm::getLoadTime, baseRealm::load);
     
                         } catch (FileNotFoundException e) {
                             throw ROOT_LOGGER.propertyFilesDoesNotExist(e.getMessage());
    @@ -310,14 +319,19 @@ protected void executeRuntimeStep(OperationContext context, ModelNode operation)
     
         private static final class RealmWrapper implements SecurityRealm {
     
    -        private final LegacyPropertiesSecurityRealm delegate;
    +        private final SecurityRealm delegate;
             private final File usersFile;
             private final File groupsFile;
    +        private final LongSupplier loadTimeSupplier;
    +        private final ExceptionBiConsumer<InputStream, InputStream, IOException> propertiesFileLoader;
     
    -        RealmWrapper(LegacyPropertiesSecurityRealm delegate, File usersFile, File groupsFile) {
    +        RealmWrapper(SecurityRealm delegate, File usersFile, File groupsFile, LongSupplier loadTimeSupplier,
    +                ExceptionBiConsumer<InputStream, InputStream, IOException>  propertiesFileLoader) {
                 this.delegate = delegate;
                 this.usersFile = usersFile;
                 this.groupsFile = groupsFile;
    +            this.loadTimeSupplier = loadTimeSupplier;
    +            this.propertiesFileLoader = propertiesFileLoader;
             }
     
             @Override
    @@ -364,14 +378,14 @@ public void handleRealmEvent(RealmEvent event) {
             }
     
             long getLoadTime() {
    -            return delegate.getLoadTime();
    +            return loadTimeSupplier.getAsLong();
             }
     
             void reloadIfNeeded() throws IOException {
    -            long loadTime = delegate.getLoadTime();
    +            long loadTime = loadTimeSupplier.getAsLong();
                 if (shouldReload(loadTime)) {
                     synchronized(this) {
    -                    loadTime = delegate.getLoadTime();
    +                    loadTime = loadTimeSupplier.getAsLong();
                         if (shouldReload(loadTime)) {
                             reloadInternal();
                         }
    @@ -394,7 +408,7 @@ void reload() throws OperationFailedException {
             void reloadInternal() throws IOException {
                 try (InputStream usersInputStream = new FileInputStream(usersFile);
                         InputStream groupsInputStream = groupsFile != null ? new FileInputStream(groupsFile) : null) {
    -                delegate.load(usersInputStream, groupsInputStream);
    +                propertiesFileLoader.accept(usersInputStream, groupsInputStream);
                 }
             }
     
    
  • elytron/src/main/java/org/wildfly/extension/elytron/RealmDefinitions.java+86 0 modified
    @@ -4,12 +4,18 @@
      */
     package org.wildfly.extension.elytron;
     
    +import static org.wildfly.extension.elytron.Capabilities.SCHEDULED_EXECUTOR_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
    +import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
    +import static org.wildfly.security.manager.WildFlySecurityManager.getPropertyPrivileged;
     
     import java.util.Collection;
     import java.util.Collections;
     import java.util.List;
     import java.util.Map;
    +import java.util.concurrent.ScheduledExecutorService;
    +import java.util.function.Function;
    +import java.util.function.Supplier;
     
     import org.jboss.as.controller.AbstractAddStepHandler;
     import org.jboss.as.controller.AttributeDefinition;
    @@ -22,6 +28,7 @@
     import org.jboss.dmr.ModelType;
     import org.jboss.msc.service.ServiceBuilder;
     import org.wildfly.extension.elytron.TrivialService.ValueSupplier;
    +import org.wildfly.security.auth.realm.BruteForceRealmWrapper;
     import org.wildfly.security.auth.realm.SimpleMapBackedSecurityRealm;
     import org.wildfly.security.auth.realm.SimpleRealmEntry;
     import org.wildfly.security.auth.server.SecurityRealm;
    @@ -33,6 +40,15 @@
      */
     class RealmDefinitions {
     
    +    /**
    +     * System properties used to configure brute force protection on the security realms.
    +     */
    +    private static final String BRUTE_FORCE_ENABLED = "wildfly.elytron.realm.%s.brute-force.enabled";
    +    private static final String BRUTE_FORCE_MAX_FAILED_ATTEMPTS = "wildfly.elytron.realm.%s.brute-force.max-failed-attempts";
    +    private static final String BRUTE_FORCE_LOCKOUT_INTERVAL = "wildfly.elytron.realm.%s.brute-force.lockout-interval";
    +    private static final String BRUTE_FORCE_SESSION_TIMEOUT = "wildfly.elytron.realm.%s.brute-force.session-timeout";
    +    private static final String BRUTE_FORCE_MAX_CACHED_SESSIONS = "wildfly.elytron.realm.%s.brute-force.max-cached-sessions";
    +
         static final AttributeDefinition IDENTITY = new SimpleAttributeDefinitionBuilder(ElytronDescriptionConstants.IDENTITY, ModelType.STRING, false)
                 .setAllowExpression(true)
                 .setMinSize(1)
    @@ -83,4 +99,74 @@ protected ValueSupplier<SecurityRealm> getValueSupplier(ServiceBuilder<SecurityR
     
             return new TrivialResourceDefinition(ElytronDescriptionConstants.IDENTITY_REALM, add, IDENTITY_REALM_ATTRIBUTES, SECURITY_REALM_RUNTIME_CAPABILITY);
         }
    +
    +    private static boolean isBruteForceProtectionEnabled(final String realmName) {
    +        return Boolean.parseBoolean(getPropertyPrivileged(String.format(BRUTE_FORCE_ENABLED, realmName), "true"));
    +    }
    +
    +    private static int getBruteForceConfigValue(final String realmName, final String systemPropertyTemplate) {
    +        try {
    +            return Integer.parseInt(getPropertyPrivileged(String.format(systemPropertyTemplate, realmName), "-1"));
    +        } catch (NumberFormatException e) {
    +            return -1;
    +        }
    +    }
    +
    +    static <T extends SecurityRealm> T addBruteForceProtection(final T original, final Class<T> clazz,
    +        final ScheduledExecutorService executor, final String realmName, final int maxAttempts,
    +        final int lockoutInterval, final int sessionTimeout, final int maxCachedSessions) {
    +
    +        return BruteForceRealmWrapper.create()
    +                .wrapping(original)
    +                .withExecutor(executor)
    +                .setRealmName(realmName)
    +                .setMaxFailedAttempts(maxAttempts)
    +                .setLockoutInterval(lockoutInterval)
    +                .setFailureSessionTimeout(sessionTimeout)
    +                .setMaxCachedSessions(maxCachedSessions)
    +                .wrap(clazz);
    +    }
    +
    +    static <T extends SecurityRealm> Function<T, T> createBruteForceRealmTransformer(String name, Class<T> clazz, ServiceBuilder<?> serviceBuilder) {
    +            Function<T, T> transformer;
    +            if (isBruteForceProtectionEnabled(name)) {
    +                final Supplier<ScheduledExecutorService> executorSupplier =
    +                        serviceBuilder.requires(SCHEDULED_EXECUTOR_RUNTIME_CAPABILITY.getCapabilityServiceName());
    +                int maxAttempts = getBruteForceConfigValue(name, BRUTE_FORCE_MAX_FAILED_ATTEMPTS);
    +                int lockoutInterval = getBruteForceConfigValue(name, BRUTE_FORCE_LOCKOUT_INTERVAL);
    +                int sessionTimeout = getBruteForceConfigValue(name, BRUTE_FORCE_SESSION_TIMEOUT);
    +                int maxCachedSessions = getBruteForceConfigValue(name, BRUTE_FORCE_MAX_CACHED_SESSIONS);
    +
    +                ROOT_LOGGER.tracef("Applying brute force protection to '%s' security realm. maxAttempts=%d, lockoutTimeout=%d, sessionTimeout=%d, maxCachedSessions=%d",
    +                    name, maxAttempts, lockoutInterval, sessionTimeout, maxCachedSessions);
    +
    +                transformer = (r) -> addBruteForceProtection(r, clazz, executorSupplier.get(), name, maxAttempts, lockoutInterval, sessionTimeout, maxCachedSessions);
    +            } else {
    +                ROOT_LOGGER.tracef("Not applying brute force protection to '%s' security realm.", name);
    +                transformer = Function.identity();
    +            }
    +
    +            return transformer;
    +    }
    +
    +    static class CustomRealmBruteForceTransformer<T extends SecurityRealm> implements CustomComponentDefinition.CustomComponentTransformer<T, T> {
    +
    +        private final Class<T> securityRealmClazz;
    +
    +        CustomRealmBruteForceTransformer(Class<T> securityRealmClazz) {
    +            this.securityRealmClazz = securityRealmClazz;
    +        }
    +
    +        @Override
    +        public Object prepareTransformer(String name, ServiceBuilder<?> serviceBuilder) {
    +            return createBruteForceRealmTransformer(name, securityRealmClazz, serviceBuilder);
    +        }
    +
    +        @Override
    +        public T apply(Object o, T securityRealm) {
    +            return ((Function<T, T>) o).apply(securityRealm);
    +        }
    +
    +    }
    +
     }
    
  • elytron/src/test/java/org/wildfly/extension/elytron/RealmsTestCase.java+2 2 modified
    @@ -625,10 +625,10 @@ public void testJAASRealm() throws Exception {
                     Assert.fail(services.getBootError().toString());
                 }
     
    -            JaasSecurityRealm securityRealm;
    +            SecurityRealm securityRealm;
                 if (!(JdkUtils.isIbmJdk())) {
                     ServiceName serviceName = Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY.getCapabilityServiceName("myJaasRealm");
    -                securityRealm = (JaasSecurityRealm) services.getContainer().getService(serviceName).getValue();
    +                securityRealm = (SecurityRealm) services.getContainer().getService(serviceName).getValue();
                     Assert.assertNotNull(securityRealm);
                 } else {
                     // IBM JDK 8 does not recognize default policy type "JavaLoginConfig" so the path to JAAS configuration file must be provided via system property
    
a6f9d7534aa4

Merge pull request #6634 from darranl/WFCORE-7192/combined

https://github.com/wildfly/wildfly-coreDarran LofthouseFeb 7, 2026via ghsa
12 files changed · +311 100
  • elytron/src/main/java/org/wildfly/extension/elytron/CachingRealmDefinition.java+46 23 modified
    @@ -7,14 +7,18 @@
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.ElytronDefinition.commonDependencies;
    -import static org.wildfly.extension.elytron.ElytronExtension.getRequiredService;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
    +
    +import java.util.Map;
    +import java.util.concurrent.ConcurrentHashMap;
    +import java.util.function.Consumer;
    +import java.util.function.Function;
     
     import org.jboss.as.controller.AbstractAddStepHandler;
     import org.jboss.as.controller.AttributeDefinition;
     import org.jboss.as.controller.OperationContext;
     import org.jboss.as.controller.OperationFailedException;
     import org.jboss.as.controller.OperationStepHandler;
    -import org.jboss.as.controller.PathAddress;
     import org.jboss.as.controller.PathElement;
     import org.jboss.as.controller.ResourceDefinition;
     import org.jboss.as.controller.RunningMode;
    @@ -32,8 +36,8 @@
     import org.jboss.msc.service.ServiceBuilder;
     import org.jboss.msc.service.ServiceController;
     import org.jboss.msc.service.ServiceName;
    -import org.jboss.msc.service.ServiceRegistry;
     import org.jboss.msc.service.ServiceTarget;
    +import org.jboss.msc.service.StartException;
     import org.jboss.msc.value.InjectedValue;
     import org.wildfly.extension.elytron._private.ElytronSubsystemMessages;
     import org.wildfly.security.auth.realm.CacheableSecurityRealm;
    @@ -73,6 +77,10 @@ class CachingRealmDefinition extends SimpleResourceDefinition {
     
         static final AttributeDefinition[] ATTRIBUTES = new AttributeDefinition[] {REALM_NAME, MAXIMUM_ENTRIES, MAXIMUM_AGE};
     
    +    // Callers are expected to just use a single method get / put / remove not multiple calls so we don't
    +    // need complex locking beyond the Map itself..
    +    private static final Map<String, CachingSecurityRealm> REALMS = new ConcurrentHashMap<>();
    +
         private static final AbstractAddStepHandler ADD = new RealmAddHandler();
         private static final OperationStepHandler REMOVE = new TrivialCapabilityServiceRemoveHandler(ADD, SECURITY_REALM_RUNTIME_CAPABILITY);
     
    @@ -114,36 +122,55 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 int maxEntries = MAXIMUM_ENTRIES.resolveModelAttribute(context, model).asInt();
                 long maxAge = MAXIMUM_AGE.resolveModelAttribute(context, model).asInt();
                 InjectedValue<SecurityRealm> cacheableRealmValue = new InjectedValue<>();
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(realmName, createService(cacheableRealm, maxEntries, maxAge, cacheableRealmValue));
    +
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            Consumer<SecurityRealm> valueConsumer = serviceBuilder.provides(realmName);
    +
    +            final Function<SecurityRealm, SecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), SecurityRealm.class, serviceBuilder);
    +
    +            serviceBuilder.setInstance(createService(context.getCurrentAddressValue(), cacheableRealm, maxEntries, maxAge, cacheableRealmValue, realmTransformer, valueConsumer));
     
                 addRealmDependency(context, serviceBuilder, cacheableRealm, cacheableRealmValue);
                 commonDependencies(serviceBuilder).setInitialMode(context.getRunningMode() == RunningMode.ADMIN_ONLY ? ServiceController.Mode.LAZY : ServiceController.Mode.ACTIVE).install();
             }
     
    -        private TrivialService<SecurityRealm> createService(String realmName, int maxEntries, long maxAge, InjectedValue<SecurityRealm> injector) {
    -            return new TrivialService<>((TrivialService.ValueSupplier<SecurityRealm>) () -> {
    -                SecurityRealm securityRealm = injector.getValue();
    +        private TrivialService<SecurityRealm> createService(String ourRealmName, String wrappedRealmName, int maxEntries, long maxAge,
    +            InjectedValue<SecurityRealm> injector, Function<SecurityRealm, SecurityRealm> realmTransformer, Consumer<SecurityRealm> valueConsumer) {
    +            return new TrivialService<>(new TrivialService.ValueSupplier<SecurityRealm>() {
    +
    +                @Override
    +                public SecurityRealm get() throws StartException {
    +                    SecurityRealm securityRealm = injector.getValue();
     
    -                if (securityRealm instanceof CacheableSecurityRealm) {
    -                    RealmIdentityCache cache = createRealmIdentityCache(maxEntries, maxAge);
    -                    CacheableSecurityRealm cacheableRealm = CacheableSecurityRealm.class.cast(securityRealm);
    +                    if (securityRealm instanceof CacheableSecurityRealm) {
    +                        RealmIdentityCache cache = createRealmIdentityCache(maxEntries, maxAge);
    +                        CacheableSecurityRealm cacheableRealm = CacheableSecurityRealm.class.cast(securityRealm);
     
    -                    if (securityRealm instanceof ModifiableSecurityRealm) {
    -                        return new CachingModifiableSecurityRealm(cacheableRealm, cache);
    +                        CachingSecurityRealm cachingRealm = securityRealm instanceof ModifiableSecurityRealm ?
    +                            new CachingModifiableSecurityRealm(cacheableRealm, cache) : new CachingSecurityRealm(cacheableRealm, cache);
    +
    +                        REALMS.put(ourRealmName, cachingRealm);
    +
    +                        return realmTransformer.apply(cachingRealm);
                         }
     
    -                    return new CachingSecurityRealm(cacheableRealm, cache);
    +                    throw ElytronSubsystemMessages.ROOT_LOGGER.realmDoesNotSupportCache(wrappedRealmName);
                     }
     
    -                throw ElytronSubsystemMessages.ROOT_LOGGER.realmDoesNotSupportCache(realmName);
    -            });
    +                @Override
    +                public void dispose() {
    +                    REALMS.remove(ourRealmName);
    +                }
    +
    +            }, valueConsumer);
             }
     
             private LRURealmIdentityCache createRealmIdentityCache(int maxEntries, long maxAge) {
                 return new LRURealmIdentityCache(maxEntries, maxAge);
             }
     
    -        private void addRealmDependency(OperationContext context, ServiceBuilder<SecurityRealm> serviceBuilder, String realmName, Injector<SecurityRealm> securityRealmInjector) {
    +        private void addRealmDependency(OperationContext context, ServiceBuilder<?> serviceBuilder, String realmName, Injector<SecurityRealm> securityRealmInjector) {
                 String runtimeCapability = RuntimeCapability.buildDynamicCapabilityName(SECURITY_REALM_CAPABILITY, realmName);
                 ServiceName realmServiceName = context.getCapabilityServiceName(runtimeCapability, SecurityRealm.class);
                 REALM_SERVICE_UTIL.addInjection(serviceBuilder, securityRealmInjector, realmServiceName);
    @@ -165,15 +192,11 @@ private ClearCacheHandler() {
     
             @Override
             protected void executeRuntimeStep(final OperationContext context, final ModelNode operation) throws OperationFailedException {
    -            ServiceRegistry serviceRegistry = context.getServiceRegistry(true);
    -            PathAddress currentAddress = context.getCurrentAddress();
    -            RuntimeCapability<Void> runtimeCapability = SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(currentAddress.getLastElement().getValue());
    -            ServiceName realmName = runtimeCapability.getCapabilityServiceName();
    -            ServiceController<SecurityRealm> serviceController = getRequiredService(serviceRegistry, realmName, SecurityRealm.class);
    -            if(serviceController.getState() != ServiceController.State.UP) {
    +            CachingSecurityRealm securityRealm = REALMS.get(context.getCurrentAddressValue());
    +            if (securityRealm == null) {
                     throw ElytronSubsystemMessages.ROOT_LOGGER.cachedRealmServiceNotAvailable();
                 }
    -            CachingSecurityRealm securityRealm = CachingSecurityRealm.class.cast(serviceController.getValue());
    +
                 securityRealm.removeAllFromCache();
             }
         }
    
  • elytron/src/main/java/org/wildfly/extension/elytron/CustomComponentDefinition.java+26 9 modified
    @@ -16,6 +16,7 @@
     import java.security.PrivilegedExceptionAction;
     import java.util.Map;
     import java.util.Set;
    +import java.util.function.BiFunction;
     import java.util.function.Function;
     
     import org.jboss.as.controller.AbstractAddStepHandler;
    @@ -58,14 +59,14 @@ class CustomComponentDefinition<C, T> extends SimpleResourceDefinition {
     
         static final AttributeDefinition[] ATTRIBUTES = {MODULE, CLASS_NAME, CONFIGURATION};
     
    -    CustomComponentDefinition(Class<C> serviceType, Function<C, T> wrapper, String pathKey, @SuppressWarnings("rawtypes") RuntimeCapability ... runtimeCapabilities) {
    +    CustomComponentDefinition(Class<C> serviceType, CustomComponentTransformer<C, T> transformer, String pathKey, @SuppressWarnings("rawtypes") RuntimeCapability ... runtimeCapabilities) {
             super(addAddRemoveHandlers(new Parameters(PathElement.pathElement(pathKey), ElytronExtension.getResourceDescriptionResolver(pathKey))
                 .setAddRestartLevel(OperationEntry.Flag.RESTART_RESOURCE_SERVICES)
                 .setRemoveRestartLevel(OperationEntry.Flag.RESTART_RESOURCE_SERVICES)
    -            .setCapabilities(runtimeCapabilities), serviceType, wrapper, runtimeCapabilities));
    +            .setCapabilities(runtimeCapabilities), serviceType, transformer, runtimeCapabilities));
         }
     
    -    private static <C, T> Parameters addAddRemoveHandlers(Parameters parameters, Class<C> serviceType, Function<C, T> wrapper, RuntimeCapability<?> ... runtimeCapabilities) {
    +    private static <C, T> Parameters addAddRemoveHandlers(Parameters parameters, Class<C> serviceType, CustomComponentTransformer<C, T> wrapper, RuntimeCapability<?> ... runtimeCapabilities) {
             AbstractAddStepHandler add = new ComponentAddHandler<>(serviceType, wrapper, runtimeCapabilities);
             OperationStepHandler remove = new TrivialCapabilityServiceRemoveHandler(add, runtimeCapabilities);
     
    @@ -86,13 +87,13 @@ private static class ComponentAddHandler<C, T> extends BaseAddHandler {
     
             private final RuntimeCapability<?>[] runtimeCapabilities;
             private final Class<C> serviceType;
    -        private final Function<C, T> wrapper;
    +        private final CustomComponentTransformer<C, T> transformer;
     
    -        private ComponentAddHandler(Class<C> serviceType, Function<C, T> wrapper, RuntimeCapability<?> ... runtimeCapabilities) {
    +        private ComponentAddHandler(Class<C> serviceType, CustomComponentTransformer<C, T> transformer, RuntimeCapability<?> ... runtimeCapabilities) {
                 super(Set.of(runtimeCapabilities));
                 this.runtimeCapabilities = runtimeCapabilities;
                 this.serviceType = serviceType;
    -            this.wrapper = wrapper;
    +            this.transformer = transformer;
             }
     
             @Override
    @@ -115,8 +116,11 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                     serviceBuilder.addAliases(toServiceName(runtimeCapabilities[i], address));
                 }
     
    +            String name = context.getCurrentAddressValue();
    +            Object wrapperContext = transformer.prepareTransformer(name, serviceBuilder);
    +
                 commonRequirements(serviceBuilder)
    -                .setInstance(new TrivialService<>(() -> createValue(module, className, configurationMap)))
    +                .setInstance(new TrivialService<>(() -> createValue(wrapperContext, module, className, configurationMap)))
                     .setInitialMode(Mode.ACTIVE)
                     .install();
             }
    @@ -125,7 +129,7 @@ private ServiceName toServiceName(RuntimeCapability<?> runtimeCapability, String
                 return runtimeCapability.fromBaseCapability(addressValue).getCapabilityServiceName();
             }
     
    -        private T createValue(String module, String className, Map<String, String> configuration) throws StartException {
    +        private T createValue(Object transformerContext, String module, String className, Map<String, String> configuration) throws StartException {
                 final ClassLoader classLoader;
                 try {
                     classLoader = doPrivileged((PrivilegedExceptionAction<ClassLoader>) () -> resolveClassLoader(module));
    @@ -143,7 +147,7 @@ private T createValue(String module, String className, Map<String, String> confi
                         }
                     }
     
    -                return wrapper.apply(component);
    +                return transformer.apply(transformerContext, component);
                 } catch (PrivilegedActionException e) {
                     throw new StartException(e.getCause());
                 } catch (Exception e) {
    @@ -156,4 +160,17 @@ private T createValue(String module, String className, Map<String, String> confi
             }
         }
     
    +    static <A, B> CustomComponentTransformer<A, B> wrapFunction(Function<A, B> function) {
    +        return (s, a ) -> function.apply(a);
    +    }
    +
    +    @FunctionalInterface
    +    interface CustomComponentTransformer<A, B> extends BiFunction<Object, A, B> {
    +
    +        default Object prepareTransformer(final String name, final ServiceBuilder<?> serviceBuilder) {
    +            return name;
    +        }
    +
    +    }
    +
     }
    
  • elytron/src/main/java/org/wildfly/extension/elytron/DistributedRealmDefinition.java+15 9 modified
    @@ -8,7 +8,12 @@
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.ElytronDefinition.commonDependencies;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
     
    +import java.util.ArrayList;
    +import java.util.List;
    +import java.util.function.Consumer;
    +import java.util.function.Function;
     
     import org.jboss.as.controller.AbstractAddStepHandler;
     import org.jboss.as.controller.AttributeDefinition;
    @@ -32,16 +37,11 @@
     import org.jboss.msc.service.ServiceName;
     import org.jboss.msc.service.ServiceTarget;
     import org.jboss.msc.value.InjectedValue;
    -
     import org.wildfly.security.auth.realm.DistributedSecurityRealm;
     import org.wildfly.security.auth.server.SecurityDomain;
     import org.wildfly.security.auth.server.SecurityRealm;
     import org.wildfly.security.auth.server.event.SecurityRealmUnavailableEvent;
     
    -import java.util.ArrayList;
    -import java.util.List;
    -import java.util.function.Consumer;
    -
     /**
      * A {@link ResourceDefinition} for a {@link SecurityRealm} for authentication and authorization of identities distributed between multiple realms.
      *
    @@ -110,6 +110,12 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
     
                 List<String> distributedRealms = REALMS.unwrap(context, model);
     
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            Consumer<SecurityRealm> valueConsumer = serviceBuilder.provides(realmName);
    +
    +            final Function<SecurityRealm, SecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), SecurityRealm.class, serviceBuilder);
    +
                 TrivialService<SecurityRealm> distributedRealmService = new TrivialService<SecurityRealm>(() ->
                 {
                     SecurityRealm[] realms = new SecurityRealm[distributedRealmValues.size()];
    @@ -126,10 +132,10 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                         realms[i] = distributedRealmValues.get(i).getValue();
                     }
     
    -                return new DistributedSecurityRealm(ignoreUnavailableRealms, unavailableRealmConsumer, realms);
    -            });
    +                return realmTransformer.apply(new DistributedSecurityRealm(ignoreUnavailableRealms, unavailableRealmConsumer, realms));
    +            }, valueConsumer);
     
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(realmName, distributedRealmService);
    +            serviceBuilder.setInstance(distributedRealmService);
     
                 for (String distributedRealm : distributedRealms) {
                     InjectedValue<SecurityRealm> authorizationRealmValue = new InjectedValue<SecurityRealm>();
    @@ -142,7 +148,7 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                         .install();
             }
     
    -        private void addRealmDependency(OperationContext context, ServiceBuilder<SecurityRealm> serviceBuilder, String realmName, Injector<SecurityRealm> securityRealmInjector) {
    +        private void addRealmDependency(OperationContext context, ServiceBuilder<?> serviceBuilder, String realmName, Injector<SecurityRealm> securityRealmInjector) {
                 String runtimeCapability = RuntimeCapability.buildDynamicCapabilityName(SECURITY_REALM_CAPABILITY, realmName);
                 ServiceName realmServiceName = context.getCapabilityServiceName(runtimeCapability, SecurityRealm.class);
     
    
  • elytron/src/main/java/org/wildfly/extension/elytron/ElytronDefinition.java+18 14 modified
    @@ -5,7 +5,6 @@
     
     package org.wildfly.extension.elytron;
     
    -
     import static org.jboss.as.server.security.VirtualDomainUtil.VIRTUAL_SECURITY_DOMAIN_CREATION_SERVICE;
     import static org.wildfly.extension.elytron.Capabilities.AUTHENTICATION_CONTEXT_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.ELYTRON_RUNTIME_CAPABILITY;
    @@ -23,6 +22,7 @@
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_FACTORY_CREDENTIAL_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.SSL_CONTEXT_CAPABILITY;
    +import static org.wildfly.extension.elytron.CustomComponentDefinition.wrapFunction;
     import static org.wildfly.extension.elytron.ElytronExtension.isServerOrHostController;
     import static org.wildfly.extension.elytron.ElytronScheduledExecutorService.installScheduledExecutorService;
     import static org.wildfly.extension.elytron.ElytronScheduledExecutorService.uninstallScheduledExecutorService;
    @@ -41,6 +41,7 @@
     
     import javax.net.ssl.SSLContext;
     
    +import jakarta.security.auth.message.config.AuthConfigFactory;
     import org.jboss.as.controller.AbstractBoottimeAddStepHandler;
     import org.jboss.as.controller.AttributeMarshaller;
     import org.jboss.as.controller.AttributeParser;
    @@ -77,6 +78,7 @@
     import org.jboss.msc.service.ServiceName;
     import org.jboss.msc.service.ServiceRegistry;
     import org.jboss.msc.service.ServiceTarget;
    +import org.wildfly.extension.elytron.RealmDefinitions.CustomRealmBruteForceTransformer;
     import org.wildfly.extension.elytron.capabilities.CredentialSecurityFactory;
     import org.wildfly.extension.elytron.capabilities.PrincipalTransformer;
     import org.wildfly.extension.elytron.capabilities._private.SecurityEventListener;
    @@ -96,8 +98,6 @@
     import org.wildfly.security.jakarta.authz.AuthorizationRegistration;
     import org.wildfly.security.manager.action.ReadPropertyAction;
     
    -import jakarta.security.auth.message.config.AuthConfigFactory;
    -
     /**
      * Top level {@link ResourceDefinition} for the Elytron subsystem.
      *
    @@ -180,7 +180,7 @@ public void registerChildren(ManagementResourceRegistration resourceRegistration
     
             // Audit
             resourceRegistration.registerSubModel(AuditResourceDefinitions.getAggregateSecurityEventListenerDefinition());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(Consumer.class, SecurityEventListener::from,
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(Consumer.class, wrapFunction(SecurityEventListener::from),
                     ElytronDescriptionConstants.CUSTOM_SECURITY_EVENT_LISTENER, SECURITY_EVENT_LISTENER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(AuditResourceDefinitions.getFileAuditLogResourceDefinition());
             resourceRegistration.registerSubModel(AuditResourceDefinitions.getPeriodicRotatingFileAuditLogResourceDefinition());
    @@ -197,9 +197,9 @@ public void registerChildren(ManagementResourceRegistration resourceRegistration
     
             // Security Realms
             resourceRegistration.registerSubModel(new AggregateRealmDefinition());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(SecurityRealm.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_REALM, SECURITY_REALM_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(SecurityRealm.class, new CustomRealmBruteForceTransformer<>(SecurityRealm.class), ElytronDescriptionConstants.CUSTOM_REALM, SECURITY_REALM_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(ModifiableRealmDecorator.wrap(new CustomComponentDefinition<>(
    -                ModifiableSecurityRealm.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_MODIFIABLE_REALM,
    +                ModifiableSecurityRealm.class, new CustomRealmBruteForceTransformer<>(ModifiableSecurityRealm.class), ElytronDescriptionConstants.CUSTOM_MODIFIABLE_REALM,
                     MODIFIABLE_SECURITY_REALM_RUNTIME_CAPABILITY, SECURITY_REALM_RUNTIME_CAPABILITY)));
             resourceRegistration.registerSubModel(RealmDefinitions.getIdentityRealmDefinition());
             resourceRegistration.registerSubModel(new JdbcRealmDefinition());
    @@ -214,11 +214,11 @@ public void registerChildren(ManagementResourceRegistration resourceRegistration
             resourceRegistration.registerSubModel(new JaasRealmDefinition());
     
             // Security Factories
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(SecurityFactory.class, CredentialSecurityFactory::from, ElytronDescriptionConstants.CUSTOM_CREDENTIAL_SECURITY_FACTORY, SECURITY_FACTORY_CREDENTIAL_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(SecurityFactory.class, wrapFunction(CredentialSecurityFactory::from), ElytronDescriptionConstants.CUSTOM_CREDENTIAL_SECURITY_FACTORY, SECURITY_FACTORY_CREDENTIAL_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(KerberosSecurityFactoryDefinition.getKerberosSecurityFactoryDefinition());
     
             // Permission Mappers
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(PermissionMapper.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_PERMISSION_MAPPER, PERMISSION_MAPPER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(PermissionMapper.class, ElytronDefinition::identity, ElytronDescriptionConstants.CUSTOM_PERMISSION_MAPPER, PERMISSION_MAPPER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(PermissionMapperDefinitions.getLogicalPermissionMapper());
             resourceRegistration.registerSubModel(PermissionMapperDefinitions.getSimplePermissionMapper());
             resourceRegistration.registerSubModel(PermissionMapperDefinitions.getConstantPermissionMapper());
    @@ -230,26 +230,26 @@ public void registerChildren(ManagementResourceRegistration resourceRegistration
             resourceRegistration.registerSubModel(PrincipalDecoderDefinitions.getAggregatePrincipalDecoderDefinition());
             resourceRegistration.registerSubModel(PrincipalDecoderDefinitions.getConcatenatingPrincipalDecoder());
             resourceRegistration.registerSubModel(PrincipalDecoderDefinitions.getConstantPrincipalDecoder());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(PrincipalDecoder.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_PRINCIPAL_DECODER, PRINCIPAL_DECODER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(PrincipalDecoder.class, ElytronDefinition::identity, ElytronDescriptionConstants.CUSTOM_PRINCIPAL_DECODER, PRINCIPAL_DECODER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(PrincipalDecoderDefinitions.getX500AttributePrincipalDecoder());
     
             // Principal Transformers
             resourceRegistration.registerSubModel(PrincipalTransformerDefinitions.getAggregatePrincipalTransformerDefinition());
             resourceRegistration.registerSubModel(PrincipalTransformerDefinitions.getChainedPrincipalTransformerDefinition());
             resourceRegistration.registerSubModel(PrincipalTransformerDefinitions.getConstantPrincipalTransformerDefinition());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(Function.class, PrincipalTransformer::from, ElytronDescriptionConstants.CUSTOM_PRINCIPAL_TRANSFORMER, PRINCIPAL_TRANSFORMER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(Function.class, wrapFunction(PrincipalTransformer::from), ElytronDescriptionConstants.CUSTOM_PRINCIPAL_TRANSFORMER, PRINCIPAL_TRANSFORMER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(PrincipalTransformerDefinitions.getRegexPrincipalTransformerDefinition());
             resourceRegistration.registerSubModel(PrincipalTransformerDefinitions.getRegexValidatingPrincipalTransformerDefinition());
             resourceRegistration.registerSubModel(PrincipalTransformerDefinitions.getCasePrincipalTransformerDefinition());
     
             // Realm Mappers
             resourceRegistration.registerSubModel(RealmMapperDefinitions.getConstantRealmMapper());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(RealmMapper.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_REALM_MAPPER, REALM_MAPPER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(RealmMapper.class, ElytronDefinition::identity, ElytronDescriptionConstants.CUSTOM_REALM_MAPPER, REALM_MAPPER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(RealmMapperDefinitions.getMappedRegexRealmMapper());
             resourceRegistration.registerSubModel(RealmMapperDefinitions.getSimpleRegexRealmMapperDefinition());
     
             // Role Decoders
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(RoleDecoder.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_ROLE_DECODER, ROLE_DECODER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(RoleDecoder.class, ElytronDefinition::identity, ElytronDescriptionConstants.CUSTOM_ROLE_DECODER, ROLE_DECODER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(RoleDecoderDefinitions.getSimpleRoleDecoderDefinition());
             resourceRegistration.registerSubModel(RoleDecoderDefinitions.getSourceAddressRoleDecoderDefinition());
             resourceRegistration.registerSubModel(RoleDecoderDefinitions.getAggregateRoleDecoderDefinition());
    @@ -259,15 +259,15 @@ public void registerChildren(ManagementResourceRegistration resourceRegistration
             resourceRegistration.registerSubModel(RoleMapperDefinitions.getAddPrefixRoleMapperDefinition());
             resourceRegistration.registerSubModel(RoleMapperDefinitions.getAggregateRoleMapperDefinition());
             resourceRegistration.registerSubModel(RoleMapperDefinitions.getConstantRoleMapperDefinition());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(RoleMapper.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_ROLE_MAPPER, ROLE_MAPPER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(RoleMapper.class, ElytronDefinition::identity, ElytronDescriptionConstants.CUSTOM_ROLE_MAPPER, ROLE_MAPPER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(RoleMapperDefinitions.getLogicalRoleMapperDefinition());
             resourceRegistration.registerSubModel(RoleMapperDefinitions.getMappedRoleMapperDefinition());
             resourceRegistration.registerSubModel(RoleMapperDefinitions.getRegexRoleMapperDefinition());
     
             // Evidence Decoders
             resourceRegistration.registerSubModel(EvidenceDecoderDefinitions.getX500SubjectEvidenceDecoderDefinition());
             resourceRegistration.registerSubModel(EvidenceDecoderDefinitions.getX509SubjectAltNameEvidenceDecoderDefinition());
    -        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(EvidenceDecoder.class, Function.identity(), ElytronDescriptionConstants.CUSTOM_EVIDENCE_DECODER, EVIDENCE_DECODER_RUNTIME_CAPABILITY));
    +        resourceRegistration.registerSubModel(new CustomComponentDefinition<>(EvidenceDecoder.class, ElytronDefinition::identity, ElytronDescriptionConstants.CUSTOM_EVIDENCE_DECODER, EVIDENCE_DECODER_RUNTIME_CAPABILITY));
             resourceRegistration.registerSubModel(EvidenceDecoderDefinitions.getAggregateEvidenceDecoderDefinition());
     
             // HTTP Mechanisms
    @@ -363,6 +363,10 @@ protected void revertUpdateToRuntime(OperationContext context, ModelNode operati
             });
         }
     
    +    private static <T, U> U identity(T t, U u) {
    +        return u;
    +    }
    +
         @Override
         public void registerAdditionalRuntimePackages(ManagementResourceRegistration resourceRegistration) {
             resourceRegistration.registerAdditionalRuntimePackages(RuntimePackageDependency.required("org.wildfly.security.elytron"));
    
  • elytron/src/main/java/org/wildfly/extension/elytron/FailoverRealmDefinition.java+12 5 modified
    @@ -8,7 +8,7 @@
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.ElytronDefinition.commonDependencies;
    -
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
     
     import org.jboss.as.controller.AbstractAddStepHandler;
     import org.jboss.as.controller.AttributeDefinition;
    @@ -40,6 +40,7 @@
     import org.wildfly.security.auth.server.event.SecurityRealmUnavailableEvent;
     
     import java.util.function.Consumer;
    +import java.util.function.Function;
     
     /**
      * A {@link ResourceDefinition} for a {@link SecurityRealm} which wraps one realm and fails over to another in case the first is unavailable.
    @@ -111,6 +112,12 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
     
                 boolean emitEvents = EMIT_EVENTS.resolveModelAttribute(context, model).asBoolean();
     
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            Consumer<SecurityRealm> valueConsumer = serviceBuilder.provides(realmName);
    +
    +            final Function<SecurityRealm, SecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), SecurityRealm.class, serviceBuilder);
    +
                 TrivialService<SecurityRealm> failoverRealmService = new TrivialService<SecurityRealm>(() ->
                 {
                     SecurityRealm delegate = delegateRealmValue.getValue();
    @@ -120,10 +127,10 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                             domain.handleSecurityEvent(new SecurityRealmUnavailableEvent(domain.getCurrentSecurityIdentity(), delegateRealm));
                         }
                     } : (e) -> {};
    -                return new FailoverSecurityRealm(delegate, failoverRealmValue.getValue(), failoverConsumer);
    -            });
    +                return realmTransformer.apply(new FailoverSecurityRealm(delegate, failoverRealmValue.getValue(), failoverConsumer));
    +            }, valueConsumer);
     
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(realmName, failoverRealmService);
    +            serviceBuilder.setInstance(failoverRealmService);
     
                 addRealmDependency(context, serviceBuilder, delegateRealm, delegateRealmValue);
                 addRealmDependency(context, serviceBuilder, failoverRealm, failoverRealmValue);
    @@ -133,7 +140,7 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                         .install();
             }
     
    -        private void addRealmDependency(OperationContext context, ServiceBuilder<SecurityRealm> serviceBuilder, String realmName, Injector<SecurityRealm> securityRealmInjector) {
    +        private void addRealmDependency(OperationContext context, ServiceBuilder<?> serviceBuilder, String realmName, Injector<SecurityRealm> securityRealmInjector) {
                 String runtimeCapability = RuntimeCapability.buildDynamicCapabilityName(SECURITY_REALM_CAPABILITY, realmName);
                 ServiceName realmServiceName = context.getCapabilityServiceName(runtimeCapability, SecurityRealm.class);
     
    
  • elytron/src/main/java/org/wildfly/extension/elytron/FileSystemRealmDefinition.java+21 5 modified
    @@ -20,6 +20,7 @@
     import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathName;
     import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathResolver;
     import static org.wildfly.extension.elytron.KeyStoreServiceUtil.getModifiableKeyStoreService;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
     import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
     
     import java.io.IOException;
    @@ -31,6 +32,8 @@
     import java.security.PrivateKey;
     import java.security.PublicKey;
     import java.security.UnrecoverableKeyException;
    +import java.util.function.Consumer;
    +import java.util.function.Function;
     import java.util.stream.Stream;
     
     import javax.crypto.SecretKey;
    @@ -72,6 +75,7 @@
     import org.wildfly.extension.elytron.FileAttributeDefinitions.PathResolver;
     import org.wildfly.security.auth.realm.FileSystemSecurityRealm;
     import org.wildfly.security.auth.realm.FileSystemSecurityRealmBuilder;
    +import org.wildfly.security.auth.server.ModifiableSecurityRealm;
     import org.wildfly.security.auth.server.NameRewriter;
     import org.wildfly.security.auth.server.RealmUnavailableException;
     import org.wildfly.security.auth.server.SecurityRealm;
    @@ -299,8 +303,8 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 ServiceTarget serviceTarget = context.getServiceTarget();
     
                 String address = context.getCurrentAddressValue();
    -            ServiceName mainServiceName = MODIFIABLE_SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
    -            ServiceName aliasServiceName = SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
    +            ServiceName modifiableServiceName = MODIFIABLE_SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
    +            ServiceName standardServiceName = SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
     
                 final int levels = LEVELS.resolveModelAttribute(context, model).asInt();
     
    @@ -327,6 +331,15 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 final SecretKey finalKey = key;
                 ServiceRegistry keyStoreServiceRegistry = context.getServiceRegistry(true);
     
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            // This is the Service that will get pulled into a SecurityDomain etc...
    +            Consumer<SecurityRealm> standardConsumer = serviceBuilder.provides(standardServiceName);
    +            // This is the modifiable variant for resources that support modification operations etc..
    +            Consumer<ModifiableSecurityRealm> modifiableConsumer = serviceBuilder.provides(modifiableServiceName);
    +
    +            Function<ModifiableSecurityRealm, ModifiableSecurityRealm> realmTransformer =
    +                    createBruteForceRealmTransformer(context.getCurrentAddressValue(), ModifiableSecurityRealm.class, serviceBuilder);
    +
                 TrivialService<SecurityRealm> fileSystemRealmService = new TrivialService<>(
                         new TrivialService.ValueSupplier<SecurityRealm>() {
     
    @@ -382,8 +395,12 @@ public SecurityRealm get() throws StartException {
                                     fileSystemRealmBuilder.setPrivateKey(privateKey);
                                     fileSystemRealmBuilder.setPublicKey(publicKey);
                                 }
    -                            return fileSystemRealmBuilder.build();
    +                            ModifiableSecurityRealm modifiable = fileSystemRealmBuilder.build();
    +                            ModifiableSecurityRealm wrapped = realmTransformer.apply(modifiable);
    +                            modifiableConsumer.accept(wrapped);
    +                            standardConsumer.accept(wrapped);
     
    +                            return modifiable;
                             }
     
                             @Override
    @@ -396,8 +413,6 @@ public void dispose() {
     
                         });
     
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(mainServiceName, fileSystemRealmService)
    -                    .addAliases(aliasServiceName);
                 if (credentialStore != null) {
                     serviceBuilder.requires(context.getCapabilityServiceName(buildDynamicCapabilityName(CREDENTIAL_STORE_CAPABILITY, credentialStore), CredentialStore.class));
                 }
    @@ -410,6 +425,7 @@ public void dispose() {
                     serviceBuilder.addDependency(PathManagerService.SERVICE_NAME, PathManager.class, pathManagerInjector);
                     serviceBuilder.requires(pathName(relativeTo));
                 }
    +            serviceBuilder.setInstance(fileSystemRealmService);
                 serviceBuilder.install();
             }
     
    
  • elytron/src/main/java/org/wildfly/extension/elytron/JaasRealmDefinition.java+26 17 modified
    @@ -5,6 +5,22 @@
     
     package org.wildfly.extension.elytron;
     
    +import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
    +import static org.wildfly.extension.elytron.ClassLoadingAttributeDefinitions.resolveClassLoader;
    +import static org.wildfly.extension.elytron.ElytronDefinition.commonDependencies;
    +import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathName;
    +import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathResolver;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
    +import static org.wildfly.extension.elytron.SecurityActions.doPrivileged;
    +import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
    +
    +import java.io.File;
    +import java.security.PrivilegedExceptionAction;
    +import java.util.function.Consumer;
    +import java.util.function.Function;
    +
    +import javax.security.auth.callback.CallbackHandler;
    +
     import org.jboss.as.controller.AbstractAddStepHandler;
     import org.jboss.as.controller.AttributeDefinition;
     import org.jboss.as.controller.OperationContext;
    @@ -31,18 +47,6 @@
     import org.wildfly.security.auth.realm.JaasSecurityRealm;
     import org.wildfly.security.auth.server.SecurityRealm;
     
    -import javax.security.auth.callback.CallbackHandler;
    -import java.io.File;
    -import java.security.PrivilegedExceptionAction;
    -
    -import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
    -import static org.wildfly.extension.elytron.ClassLoadingAttributeDefinitions.resolveClassLoader;
    -import static org.wildfly.extension.elytron.ElytronDefinition.commonDependencies;
    -import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathName;
    -import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathResolver;
    -import static org.wildfly.extension.elytron.SecurityActions.doPrivileged;
    -import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
    -
     /**
      * A {@link ResourceDefinition} for a {@link SecurityRealm} backed by a JAAS LoginContext.
      */
    @@ -127,6 +131,13 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
     
                 final InjectedValue<PathManager> pathManagerInjector = new InjectedValue<>();
     
    +            ServiceName realmName = runtimeCapability.getCapabilityServiceName(SecurityRealm.class);
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            Consumer<SecurityRealm> realmConsumer = serviceBuilder.provides(realmName);
    +
    +            Function<SecurityRealm, SecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), SecurityRealm.class, serviceBuilder);
    +
                 CallbackHandler finalCallbackHandler = callbackhandler;
                 TrivialService<SecurityRealm> jaasRealmService = new TrivialService<>(
                         new TrivialService.ValueSupplier<SecurityRealm>() {
    @@ -143,7 +154,7 @@ public SecurityRealm get() throws StartException {
                                     }
                                     rootPath = jaasConfigFile.getPath();
                                 }
    -                            return new JaasSecurityRealm(entryName, rootPath, classLoader, finalCallbackHandler);
    +                            return realmTransformer.apply(new JaasSecurityRealm(entryName, rootPath, classLoader, finalCallbackHandler));
                             }
     
                             @Override
    @@ -153,17 +164,15 @@ public void dispose() {
                                     pathResolver = null;
                                 }
                             }
    -                    });
    -
    -            ServiceName realmName = runtimeCapability.getCapabilityServiceName(SecurityRealm.class);
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(realmName, jaasRealmService);
    +                    }, realmConsumer);
     
                 if (relativeTo != null) {
                     serviceBuilder.addDependency(PathManagerService.SERVICE_NAME, PathManager.class, pathManagerInjector);
                     serviceBuilder.requires(pathName(relativeTo));
                 }
     
                 commonDependencies(serviceBuilder)
    +                    .setInstance(jaasRealmService)
                         .setInitialMode(ServiceController.Mode.ACTIVE)
                         .install();
             }
    
  • elytron/src/main/java/org/wildfly/extension/elytron/JdbcRealmDefinition.java+11 2 modified
    @@ -16,6 +16,7 @@
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.SCRAM_MAPPER;
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.SIMPLE_DIGEST_MAPPER;
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.UTF_8;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
     import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
     
     import java.nio.charset.Charset;
    @@ -24,6 +25,8 @@
     import java.util.HashMap;
     import java.util.List;
     import java.util.Map;
    +import java.util.function.Consumer;
    +import java.util.function.Function;
     
     import javax.sql.DataSource;
     
    @@ -612,8 +615,13 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 final JdbcSecurityRealmBuilder builder = JdbcSecurityRealm.builder();
                 builder.setHashCharset(charset);
     
    -            TrivialService<SecurityRealm> service = new TrivialService<SecurityRealm>(builder::build);
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(realmName, service);
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            Consumer<SecurityRealm> valueConsumer = serviceBuilder.provides(realmName);
    +
    +            Function<SecurityRealm, SecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), SecurityRealm.class, serviceBuilder);
    +
    +            TrivialService<SecurityRealm> service = new TrivialService<SecurityRealm>(() -> realmTransformer.apply(builder.build()), valueConsumer);
     
                 for (ModelNode query : principalQueries.asList()) {
                     String authenticationQuerySql = PrincipalQueryAttributes.SQL.resolveModelAttribute(context, query).asString();
    @@ -639,6 +647,7 @@ public void uninject() {
                     });
                 }
     
    +            serviceBuilder.setInstance(service);
                 commonDependencies(serviceBuilder)
                         .setInitialMode(context.getRunningMode() == RunningMode.ADMIN_ONLY ? ServiceController.Mode.LAZY : ServiceController.Mode.ACTIVE)
                         .install();
    
  • elytron/src/main/java/org/wildfly/extension/elytron/LdapRealmDefinition.java+26 6 modified
    @@ -14,11 +14,14 @@
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.HEX;
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.UTF_8;
     import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
     
     import java.nio.charset.Charset;
     import java.util.Arrays;
     import java.util.List;
     import java.util.Set;
    +import java.util.function.Consumer;
    +import java.util.function.Function;
     
     import javax.naming.InvalidNameException;
     import javax.naming.NamingException;
    @@ -59,6 +62,7 @@
     import org.wildfly.security.auth.realm.ldap.AttributeMapping;
     import org.wildfly.security.auth.realm.ldap.LdapSecurityRealmBuilder;
     import org.wildfly.security.auth.realm.ldap.LdapSecurityRealmBuilder.IdentityMappingBuilder;
    +import org.wildfly.security.auth.server.ModifiableSecurityRealm;
     import org.wildfly.security.auth.server.SecurityRealm;
     import org.wildfly.security.password.spec.Encoding;
     
    @@ -435,8 +439,8 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 ServiceTarget serviceTarget = context.getServiceTarget();
     
                 String address = context.getCurrentAddressValue();
    -            ServiceName mainServiceName = MODIFIABLE_SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
    -            ServiceName aliasServiceName = SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
    +            ServiceName modifiableServiceName = MODIFIABLE_SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
    +            ServiceName standardServiceName = SECURITY_REALM_RUNTIME_CAPABILITY.fromBaseCapability(address).getCapabilityServiceName();
     
                 final LdapSecurityRealmBuilder builder = LdapSecurityRealmBuilder.builder();
     
    @@ -455,10 +459,26 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 builder.setHashEncoding(HEX.equals(hashEncoding) ? Encoding.HEX : Encoding.BASE64);
                 builder.setHashCharset(charset);
     
    -            TrivialService<SecurityRealm> ldapRealmService = new TrivialService<>(builder::build);
    -            ServiceBuilder<SecurityRealm> serviceBuilder = serviceTarget.addService(mainServiceName, ldapRealmService)
    -                    .addAliases(aliasServiceName);
    +            ServiceBuilder<?> serviceBuilder = serviceTarget.addService();
    +            // This is the Service that will get pulled into a SecurityDomain etc...
    +            Consumer<SecurityRealm> standardConsumer = serviceBuilder.provides(standardServiceName);
    +            // This is the modifiable variant for resources that support modification operations etc..
    +            Consumer<ModifiableSecurityRealm> modifiableConsumer = serviceBuilder.provides(modifiableServiceName);
     
    +            Function<ModifiableSecurityRealm, ModifiableSecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), ModifiableSecurityRealm.class, serviceBuilder);
    +
    +            TrivialService<SecurityRealm> ldapRealmService =
    +                    new TrivialService<>(() -> {
    +                        ModifiableSecurityRealm modifiable = builder.build();
    +                        ModifiableSecurityRealm wrapped = realmTransformer.apply(modifiable);
    +                        modifiableConsumer.accept(wrapped);
    +                        standardConsumer.accept(wrapped);
    +
    +                        return modifiable;
    +                    });
    +
    +            serviceBuilder.setInstance(ldapRealmService);
                 commonDependencies(serviceBuilder);
     
                 configureIdentityMapping(context, model, builder);
    @@ -467,7 +487,7 @@ protected void performRuntime(OperationContext context, ModelNode operation, Mod
                 serviceBuilder.setInitialMode(ServiceController.Mode.ACTIVE).install();
             }
     
    -        private void configureDirContext(OperationContext context, ModelNode model, LdapSecurityRealmBuilder realmBuilder, ServiceBuilder<SecurityRealm> serviceBuilder) throws OperationFailedException {
    +        private void configureDirContext(OperationContext context, ModelNode model, LdapSecurityRealmBuilder realmBuilder, ServiceBuilder<?> serviceBuilder) throws OperationFailedException {
                 String dirContextName = DIR_CONTEXT.resolveModelAttribute(context, model).asStringOrNull();
     
                 String runtimeCapability = RuntimeCapability.buildDynamicCapabilityName(DIR_CONTEXT_CAPABILITY, dirContextName);
    
  • elytron/src/main/java/org/wildfly/extension/elytron/PropertiesRealmDefinition.java+22 8 modified
    @@ -5,6 +5,7 @@
     
     package org.wildfly.extension.elytron;
     
    +
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.BASE64;
     import static org.wildfly.extension.elytron.ElytronDescriptionConstants.HEX;
    @@ -13,6 +14,7 @@
     import static org.wildfly.extension.elytron.ElytronExtension.getRequiredService;
     import static org.wildfly.extension.elytron.FileAttributeDefinitions.RELATIVE_TO;
     import static org.wildfly.extension.elytron.FileAttributeDefinitions.pathName;
    +import static org.wildfly.extension.elytron.RealmDefinitions.createBruteForceRealmTransformer;
     import static org.wildfly.extension.elytron.SecurityActions.doPrivileged;
     import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
     
    @@ -29,6 +31,8 @@
     import java.util.ArrayList;
     import java.util.Date;
     import java.util.List;
    +import java.util.function.Function;
    +import java.util.function.LongSupplier;
     
     import org.jboss.as.controller.AbstractAddStepHandler;
     import org.jboss.as.controller.AttributeDefinition;
    @@ -58,6 +62,7 @@
     import org.jboss.msc.service.ServiceName;
     import org.jboss.msc.service.StartException;
     import org.jboss.msc.value.InjectedValue;
    +import org.wildfly.common.function.ExceptionBiConsumer;
     import org.wildfly.extension.elytron.TrivialResourceDefinition.Builder;
     import org.wildfly.extension.elytron.TrivialService.ValueSupplier;
     import org.wildfly.security.auth.SupportLevel;
    @@ -181,6 +186,8 @@ protected ValueSupplier<SecurityRealm> getValueSupplier(ServiceBuilder<SecurityR
                     }
                 }
     
    +            Function<SecurityRealm, SecurityRealm> realmTransformer =
    +                createBruteForceRealmTransformer(context.getCurrentAddressValue(), SecurityRealm.class, serviceBuilder);
                 return new ValueSupplier<SecurityRealm>() {
     
                     private final List<Handle> callbackHandles = new ArrayList<>();
    @@ -192,15 +199,17 @@ public SecurityRealm get() throws StartException {
     
                         try (InputStream usersInputStream = new FileInputStream(usersFile);
                                 InputStream groupsInputStream = groupsFile != null ? new FileInputStream(groupsFile) : null) {
    -                        return new RealmWrapper(LegacyPropertiesSecurityRealm.builder()
    +                        LegacyPropertiesSecurityRealm baseRealm = LegacyPropertiesSecurityRealm.builder()
                                     .setUsersStream(usersInputStream)
                                     .setGroupsStream(groupsInputStream)
                                     .setPlainText(plainText)
                                     .setGroupsAttribute(groupsAttribute)
                                     .setDefaultRealm(digestRealmName)
                                     .setHashEncoding(BASE64.equalsIgnoreCase(hashEncoding) ? Encoding.BASE64 : Encoding.HEX)
                                     .setHashCharset(Charset.forName(hashCharset))
    -                                .build(), usersFile, groupsFile);
    +                                .build();
    +
    +                        return new RealmWrapper(realmTransformer.apply(baseRealm), usersFile, groupsFile, baseRealm::getLoadTime, baseRealm::load);
     
                         } catch (FileNotFoundException e) {
                             throw ROOT_LOGGER.propertyFilesDoesNotExist(e.getMessage());
    @@ -310,14 +319,19 @@ protected void executeRuntimeStep(OperationContext context, ModelNode operation)
     
         private static final class RealmWrapper implements SecurityRealm {
     
    -        private final LegacyPropertiesSecurityRealm delegate;
    +        private final SecurityRealm delegate;
             private final File usersFile;
             private final File groupsFile;
    +        private final LongSupplier loadTimeSupplier;
    +        private final ExceptionBiConsumer<InputStream, InputStream, IOException> propertiesFileLoader;
     
    -        RealmWrapper(LegacyPropertiesSecurityRealm delegate, File usersFile, File groupsFile) {
    +        RealmWrapper(SecurityRealm delegate, File usersFile, File groupsFile, LongSupplier loadTimeSupplier,
    +                ExceptionBiConsumer<InputStream, InputStream, IOException>  propertiesFileLoader) {
                 this.delegate = delegate;
                 this.usersFile = usersFile;
                 this.groupsFile = groupsFile;
    +            this.loadTimeSupplier = loadTimeSupplier;
    +            this.propertiesFileLoader = propertiesFileLoader;
             }
     
             @Override
    @@ -364,14 +378,14 @@ public void handleRealmEvent(RealmEvent event) {
             }
     
             long getLoadTime() {
    -            return delegate.getLoadTime();
    +            return loadTimeSupplier.getAsLong();
             }
     
             void reloadIfNeeded() throws IOException {
    -            long loadTime = delegate.getLoadTime();
    +            long loadTime = loadTimeSupplier.getAsLong();
                 if (shouldReload(loadTime)) {
                     synchronized(this) {
    -                    loadTime = delegate.getLoadTime();
    +                    loadTime = loadTimeSupplier.getAsLong();
                         if (shouldReload(loadTime)) {
                             reloadInternal();
                         }
    @@ -394,7 +408,7 @@ void reload() throws OperationFailedException {
             void reloadInternal() throws IOException {
                 try (InputStream usersInputStream = new FileInputStream(usersFile);
                         InputStream groupsInputStream = groupsFile != null ? new FileInputStream(groupsFile) : null) {
    -                delegate.load(usersInputStream, groupsInputStream);
    +                propertiesFileLoader.accept(usersInputStream, groupsInputStream);
                 }
             }
     
    
  • elytron/src/main/java/org/wildfly/extension/elytron/RealmDefinitions.java+86 0 modified
    @@ -4,12 +4,18 @@
      */
     package org.wildfly.extension.elytron;
     
    +import static org.wildfly.extension.elytron.Capabilities.SCHEDULED_EXECUTOR_RUNTIME_CAPABILITY;
     import static org.wildfly.extension.elytron.Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY;
    +import static org.wildfly.extension.elytron._private.ElytronSubsystemMessages.ROOT_LOGGER;
    +import static org.wildfly.security.manager.WildFlySecurityManager.getPropertyPrivileged;
     
     import java.util.Collection;
     import java.util.Collections;
     import java.util.List;
     import java.util.Map;
    +import java.util.concurrent.ScheduledExecutorService;
    +import java.util.function.Function;
    +import java.util.function.Supplier;
     
     import org.jboss.as.controller.AbstractAddStepHandler;
     import org.jboss.as.controller.AttributeDefinition;
    @@ -22,6 +28,7 @@
     import org.jboss.dmr.ModelType;
     import org.jboss.msc.service.ServiceBuilder;
     import org.wildfly.extension.elytron.TrivialService.ValueSupplier;
    +import org.wildfly.security.auth.realm.BruteForceRealmWrapper;
     import org.wildfly.security.auth.realm.SimpleMapBackedSecurityRealm;
     import org.wildfly.security.auth.realm.SimpleRealmEntry;
     import org.wildfly.security.auth.server.SecurityRealm;
    @@ -33,6 +40,15 @@
      */
     class RealmDefinitions {
     
    +    /**
    +     * System properties used to configure brute force protection on the security realms.
    +     */
    +    private static final String BRUTE_FORCE_ENABLED = "wildfly.elytron.realm.%s.brute-force.enabled";
    +    private static final String BRUTE_FORCE_MAX_FAILED_ATTEMPTS = "wildfly.elytron.realm.%s.brute-force.max-failed-attempts";
    +    private static final String BRUTE_FORCE_LOCKOUT_INTERVAL = "wildfly.elytron.realm.%s.brute-force.lockout-interval";
    +    private static final String BRUTE_FORCE_SESSION_TIMEOUT = "wildfly.elytron.realm.%s.brute-force.session-timeout";
    +    private static final String BRUTE_FORCE_MAX_CACHED_SESSIONS = "wildfly.elytron.realm.%s.brute-force.max-cached-sessions";
    +
         static final AttributeDefinition IDENTITY = new SimpleAttributeDefinitionBuilder(ElytronDescriptionConstants.IDENTITY, ModelType.STRING, false)
                 .setAllowExpression(true)
                 .setMinSize(1)
    @@ -83,4 +99,74 @@ protected ValueSupplier<SecurityRealm> getValueSupplier(ServiceBuilder<SecurityR
     
             return new TrivialResourceDefinition(ElytronDescriptionConstants.IDENTITY_REALM, add, IDENTITY_REALM_ATTRIBUTES, SECURITY_REALM_RUNTIME_CAPABILITY);
         }
    +
    +    private static boolean isBruteForceProtectionEnabled(final String realmName) {
    +        return Boolean.parseBoolean(getPropertyPrivileged(String.format(BRUTE_FORCE_ENABLED, realmName), "true"));
    +    }
    +
    +    private static int getBruteForceConfigValue(final String realmName, final String systemPropertyTemplate) {
    +        try {
    +            return Integer.parseInt(getPropertyPrivileged(String.format(systemPropertyTemplate, realmName), "-1"));
    +        } catch (NumberFormatException e) {
    +            return -1;
    +        }
    +    }
    +
    +    static <T extends SecurityRealm> T addBruteForceProtection(final T original, final Class<T> clazz,
    +        final ScheduledExecutorService executor, final String realmName, final int maxAttempts,
    +        final int lockoutInterval, final int sessionTimeout, final int maxCachedSessions) {
    +
    +        return BruteForceRealmWrapper.create()
    +                .wrapping(original)
    +                .withExecutor(executor)
    +                .setRealmName(realmName)
    +                .setMaxFailedAttempts(maxAttempts)
    +                .setLockoutInterval(lockoutInterval)
    +                .setFailureSessionTimeout(sessionTimeout)
    +                .setMaxCachedSessions(maxCachedSessions)
    +                .wrap(clazz);
    +    }
    +
    +    static <T extends SecurityRealm> Function<T, T> createBruteForceRealmTransformer(String name, Class<T> clazz, ServiceBuilder<?> serviceBuilder) {
    +            Function<T, T> transformer;
    +            if (isBruteForceProtectionEnabled(name)) {
    +                final Supplier<ScheduledExecutorService> executorSupplier =
    +                        serviceBuilder.requires(SCHEDULED_EXECUTOR_RUNTIME_CAPABILITY.getCapabilityServiceName());
    +                int maxAttempts = getBruteForceConfigValue(name, BRUTE_FORCE_MAX_FAILED_ATTEMPTS);
    +                int lockoutInterval = getBruteForceConfigValue(name, BRUTE_FORCE_LOCKOUT_INTERVAL);
    +                int sessionTimeout = getBruteForceConfigValue(name, BRUTE_FORCE_SESSION_TIMEOUT);
    +                int maxCachedSessions = getBruteForceConfigValue(name, BRUTE_FORCE_MAX_CACHED_SESSIONS);
    +
    +                ROOT_LOGGER.tracef("Applying brute force protection to '%s' security realm. maxAttempts=%d, lockoutTimeout=%d, sessionTimeout=%d, maxCachedSessions=%d",
    +                    name, maxAttempts, lockoutInterval, sessionTimeout, maxCachedSessions);
    +
    +                transformer = (r) -> addBruteForceProtection(r, clazz, executorSupplier.get(), name, maxAttempts, lockoutInterval, sessionTimeout, maxCachedSessions);
    +            } else {
    +                ROOT_LOGGER.tracef("Not applying brute force protection to '%s' security realm.", name);
    +                transformer = Function.identity();
    +            }
    +
    +            return transformer;
    +    }
    +
    +    static class CustomRealmBruteForceTransformer<T extends SecurityRealm> implements CustomComponentDefinition.CustomComponentTransformer<T, T> {
    +
    +        private final Class<T> securityRealmClazz;
    +
    +        CustomRealmBruteForceTransformer(Class<T> securityRealmClazz) {
    +            this.securityRealmClazz = securityRealmClazz;
    +        }
    +
    +        @Override
    +        public Object prepareTransformer(String name, ServiceBuilder<?> serviceBuilder) {
    +            return createBruteForceRealmTransformer(name, securityRealmClazz, serviceBuilder);
    +        }
    +
    +        @Override
    +        public T apply(Object o, T securityRealm) {
    +            return ((Function<T, T>) o).apply(securityRealm);
    +        }
    +
    +    }
    +
     }
    
  • elytron/src/test/java/org/wildfly/extension/elytron/RealmsTestCase.java+2 2 modified
    @@ -625,10 +625,10 @@ public void testJAASRealm() throws Exception {
                     Assert.fail(services.getBootError().toString());
                 }
     
    -            JaasSecurityRealm securityRealm;
    +            SecurityRealm securityRealm;
                 if (!(JdkUtils.isIbmJdk())) {
                     ServiceName serviceName = Capabilities.SECURITY_REALM_RUNTIME_CAPABILITY.getCapabilityServiceName("myJaasRealm");
    -                securityRealm = (JaasSecurityRealm) services.getContainer().getService(serviceName).getValue();
    +                securityRealm = (SecurityRealm) services.getContainer().getService(serviceName).getValue();
                     Assert.assertNotNull(securityRealm);
                 } else {
                     // IBM JDK 8 does not recognize default policy type "JavaLoginConfig" so the path to JAAS configuration file must be provided via system property
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

13

News mentions

0

No linked articles in our index yet.