io.quarkus.resteasy.reactive.server.runtime.security.EagerSecurityContext Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of quarkus-rest Show documentation
Show all versions of quarkus-rest Show documentation
A Jakarta REST implementation utilizing build time processing and Vert.x. This extension is not compatible with the quarkus-resteasy extension, or any of the extensions that depend on it.
The newest version!
package io.quarkus.resteasy.reactive.server.runtime.security;
import static io.quarkus.security.spi.runtime.SecurityEventHelper.AUTHORIZATION_FAILURE;
import static io.quarkus.security.spi.runtime.SecurityEventHelper.AUTHORIZATION_SUCCESS;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
import jakarta.enterprise.event.Event;
import jakarta.enterprise.event.Observes;
import jakarta.enterprise.inject.spi.BeanManager;
import jakarta.inject.Singleton;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext;
import io.quarkus.arc.InjectableInstance;
import io.quarkus.runtime.ShutdownEvent;
import io.quarkus.runtime.StartupEvent;
import io.quarkus.security.ForbiddenException;
import io.quarkus.security.UnauthorizedException;
import io.quarkus.security.identity.CurrentIdentityAssociation;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.spi.runtime.AuthorizationController;
import io.quarkus.security.spi.runtime.AuthorizationFailureEvent;
import io.quarkus.security.spi.runtime.AuthorizationSuccessEvent;
import io.quarkus.security.spi.runtime.MethodDescription;
import io.quarkus.security.spi.runtime.SecurityEventHelper;
import io.quarkus.vertx.http.runtime.HttpBuildTimeConfig;
import io.quarkus.vertx.http.runtime.security.AbstractPathMatchingHttpSecurityPolicy;
import io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy;
import io.quarkus.vertx.http.runtime.security.JaxRsPathMatchingHttpSecurityPolicy;
import io.quarkus.vertx.http.runtime.security.QuarkusHttpUser;
import io.smallrye.mutiny.Uni;
import io.vertx.ext.web.RoutingContext;
@Singleton
public class EagerSecurityContext {
static EagerSecurityContext instance = null;
private final JaxRsPathMatchingHttpSecurityPolicy jaxRsPathMatchingPolicy;
final SecurityEventHelper eventHelper;
final InjectableInstance identityAssociation;
final AuthorizationController authorizationController;
final boolean doNotRunPermissionSecurityCheck;
final boolean isProactiveAuthDisabled;
EagerSecurityContext(Event authorizationFailureEvent,
@ConfigProperty(name = "quarkus.security.events.enabled") boolean securityEventsEnabled,
Event authorizationSuccessEvent, BeanManager beanManager,
InjectableInstance identityAssociation, AuthorizationController authorizationController,
HttpBuildTimeConfig buildTimeConfig,
JaxRsPathMatchingHttpSecurityPolicy jaxRsPathMatchingPolicy) {
this.isProactiveAuthDisabled = !buildTimeConfig.auth.proactive;
this.identityAssociation = identityAssociation;
this.authorizationController = authorizationController;
this.eventHelper = new SecurityEventHelper<>(authorizationSuccessEvent, authorizationFailureEvent,
AUTHORIZATION_SUCCESS, AUTHORIZATION_FAILURE, beanManager, securityEventsEnabled);
if (jaxRsPathMatchingPolicy.hasNoPermissions()) {
this.jaxRsPathMatchingPolicy = null;
this.doNotRunPermissionSecurityCheck = true;
} else {
this.jaxRsPathMatchingPolicy = jaxRsPathMatchingPolicy;
this.doNotRunPermissionSecurityCheck = false;
}
}
void initSingleton(@Observes StartupEvent event) {
// intention here is to initialize this instance during app startup and make it accessible as singleton to
// all the security ServerRestHandler instances, so that they don't need to access it via CDI programmatically
// and write to a volatile variable during the request; the EagerSecurityHandler is created for each
// endpoint (in case there is HTTP permission configured), so there can be a lot of them
instance = this;
}
void destroySingleton(@Observes ShutdownEvent event) {
instance = null;
}
Uni getDeferredIdentity() {
return Uni.createFrom().deferred(new Supplier>() {
@Override
public Uni get() {
return EagerSecurityContext.instance.identityAssociation.get().getDeferredIdentity();
}
});
}
Uni getPermissionCheck(ResteasyReactiveRequestContext requestContext, SecurityIdentity identity,
MethodDescription invokedMethodDesc) {
final RoutingContext routingContext = requestContext.unwrap(RoutingContext.class);
if (routingContext == null) {
throw new IllegalStateException(
"HTTP Security policy applied only on Quarkus REST cannot be run as 'RoutingContext' is null");
}
record SecurityCheckWithIdentity(SecurityIdentity identity, HttpSecurityPolicy.CheckResult checkResult) {
}
return jaxRsPathMatchingPolicy
.checkPermission(routingContext, identity == null ? getDeferredIdentity() : Uni.createFrom().item(identity),
invokedMethodDesc)
.flatMap(new Function>() {
@Override
public Uni apply(HttpSecurityPolicy.CheckResult checkResult) {
if (identity != null) {
return Uni.createFrom().item(new SecurityCheckWithIdentity(identity, checkResult));
}
if (checkResult.isPermitted() && checkResult.getAugmentedIdentity() == null) {
return Uni.createFrom().item(new SecurityCheckWithIdentity(null, checkResult));
}
// we need to resolve identity either to compare augmented identity or to determine
// whether the identity is anonymous (determines thrown exception for denied access)
return getDeferredIdentity().map(new Function() {
@Override
public SecurityCheckWithIdentity apply(SecurityIdentity identity1) {
return new SecurityCheckWithIdentity(identity1, checkResult);
}
});
}
})
.map(new Function() {
@Override
public SecurityIdentity apply(SecurityCheckWithIdentity checkWithIdentity) {
final HttpSecurityPolicy.CheckResult checkResult = checkWithIdentity.checkResult();
final SecurityIdentity newIdentity;
if (checkResult.getAugmentedIdentity() == null) {
newIdentity = checkWithIdentity.identity();
} else if (checkResult.getAugmentedIdentity() != checkWithIdentity.identity()) {
newIdentity = checkResult.getAugmentedIdentity();
QuarkusHttpUser.setIdentity(newIdentity, routingContext);
identityAssociation.get().setIdentity(newIdentity);
} else {
newIdentity = checkResult.getAugmentedIdentity();
}
// access granted
if (checkResult.isPermitted()) {
if (eventHelper.fireEventOnSuccess()) {
eventHelper.fireSuccessEvent(new AuthorizationSuccessEvent(newIdentity,
AbstractPathMatchingHttpSecurityPolicy.class.getName(),
Map.of(RoutingContext.class.getName(), routingContext)));
}
return newIdentity;
}
// access denied
final RuntimeException exception;
if (newIdentity.isAnonymous()) {
exception = new UnauthorizedException();
} else {
exception = new ForbiddenException();
}
if (eventHelper.fireEventOnFailure()) {
eventHelper.fireFailureEvent(new AuthorizationFailureEvent(newIdentity, exception,
AbstractPathMatchingHttpSecurityPolicy.class.getName(),
Map.of(RoutingContext.class.getName(), routingContext)));
}
throw exception;
}
});
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy