Skip to content

Commit

Permalink
Run blocking security tasks from duplicated context
Browse files Browse the repository at this point in the history
  • Loading branch information
michalvavrik committed Jul 28, 2023
1 parent 9419f8e commit 48bd965
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 127 deletions.
Original file line number Diff line number Diff line change
@@ -1,43 +1,36 @@
package io.quarkus.oidc.runtime;

import java.util.function.Consumer;
import java.util.function.Supplier;

import io.quarkus.arc.Arc;
import io.quarkus.oidc.OidcRequestContext;
import io.quarkus.runtime.BlockingOperationControl;
import io.quarkus.runtime.ExecutorRecorder;
import io.quarkus.security.spi.runtime.BlockingSecurityExecutor;
import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.subscription.UniEmitter;

public class BlockingTaskRunner<T> implements OidcRequestContext<T> {
public Uni<T> runBlocking(Supplier<T> function) {
return Uni.createFrom().deferred(new Supplier<Uni<? extends T>>() {

private final BlockingSecurityExecutor blockingExecutor;

public BlockingTaskRunner() {
this.blockingExecutor = new BlockingSecurityExecutor() {

private volatile BlockingSecurityExecutor delegate = null;

@Override
public Uni<T> get() {
if (BlockingOperationControl.isBlockingAllowed()) {
try {
return Uni.createFrom().item(function.get());
} catch (Throwable t) {
return Uni.createFrom().failure(t);
}
} else {
return Uni.createFrom().emitter(new Consumer<UniEmitter<? super T>>() {
@Override
public void accept(UniEmitter<? super T> uniEmitter) {
ExecutorRecorder.getCurrent().execute(new Runnable() {
@Override
public void run() {
try {
uniEmitter.complete(function.get());
} catch (Throwable t) {
uniEmitter.fail(t);
}
}
});
}
});
public <O> Uni<O> executeBlocking(Supplier<? extends O> supplier) {
if (delegate == null) {
delegate = Arc.container().select(BlockingSecurityExecutor.class).get();
}
return delegate.executeBlocking(supplier);
}
});
};
}

public BlockingTaskRunner(BlockingSecurityExecutor blockingExecutor) {
this.blockingExecutor = blockingExecutor;
}

public Uni<T> runBlocking(Supplier<T> function) {
return blockingExecutor.executeBlocking(function);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import io.quarkus.security.AuthenticationRedirectException;
import io.quarkus.security.identity.IdentityProviderManager;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.spi.runtime.BlockingSecurityExecutor;
import io.quarkus.vertx.http.runtime.security.ChallengeData;
import io.smallrye.jwt.algorithm.KeyEncryptionAlgorithm;
import io.smallrye.jwt.build.Jwt;
Expand Down Expand Up @@ -74,10 +75,15 @@ public class CodeAuthenticationMechanism extends AbstractOidcAuthenticationMecha
private static final String INTERNAL_IDTOKEN_HEADER = "internal";
private static final Logger LOG = Logger.getLogger(CodeAuthenticationMechanism.class);

private final BlockingTaskRunner<String> createTokenStateRequestContext = new BlockingTaskRunner<String>();
private final BlockingTaskRunner<AuthorizationCodeTokens> getTokenStateRequestContext = new BlockingTaskRunner<AuthorizationCodeTokens>();
private final BlockingTaskRunner<String> createTokenStateRequestContext;
private final BlockingTaskRunner<AuthorizationCodeTokens> getTokenStateRequestContext;
private final SecureRandom secureRandom = new SecureRandom();

public CodeAuthenticationMechanism(BlockingSecurityExecutor blockingExecutor) {
this.createTokenStateRequestContext = new BlockingTaskRunner<>(blockingExecutor);
this.getTokenStateRequestContext = new BlockingTaskRunner<>(blockingExecutor);
}

public Uni<SecurityIdentity> authenticate(RoutingContext context,
IdentityProviderManager identityProviderManager, OidcTenantConfig oidcTenantConfig) {
final Map<String, Cookie> cookies = context.request().cookieMap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import io.quarkus.oidc.TokenStateManager;
import io.quarkus.oidc.UserInfo;
import io.quarkus.oidc.UserInfoCache;
import io.quarkus.security.spi.runtime.BlockingSecurityExecutor;
import io.smallrye.mutiny.Uni;
import io.vertx.ext.web.RoutingContext;

Expand Down Expand Up @@ -64,12 +65,16 @@ public class DefaultTenantConfigResolver {
@ConfigProperty(name = "quarkus.http.proxy.enable-forwarded-prefix")
boolean enableHttpForwardedPrefix;

private final BlockingTaskRunner<OidcTenantConfig> blockingRequestContext = new BlockingTaskRunner<OidcTenantConfig>();
private final BlockingTaskRunner<OidcTenantConfig> blockingRequestContext;

private volatile boolean securityEventObserved;

private ConcurrentHashMap<String, BackChannelLogoutTokenCache> backChannelLogoutTokens = new ConcurrentHashMap<>();

public DefaultTenantConfigResolver(BlockingSecurityExecutor blockingExecutor) {
this.blockingRequestContext = new BlockingTaskRunner<OidcTenantConfig>(blockingExecutor);
}

@PostConstruct
public void verifyResolvers() {
if (tenantConfigResolver.isResolvable() && tenantConfigResolver.isAmbiguous()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.identity.request.AuthenticationRequest;
import io.quarkus.security.identity.request.TokenAuthenticationRequest;
import io.quarkus.security.spi.runtime.BlockingSecurityExecutor;
import io.quarkus.vertx.http.runtime.security.ChallengeData;
import io.quarkus.vertx.http.runtime.security.HttpAuthenticationMechanism;
import io.quarkus.vertx.http.runtime.security.HttpCredentialTransport;
Expand All @@ -28,11 +29,12 @@ public class OidcAuthenticationMechanism implements HttpAuthenticationMechanism
HttpCredentialTransport.Type.AUTHORIZATION_CODE, OidcConstants.CODE_FLOW_CODE);

private final BearerAuthenticationMechanism bearerAuth = new BearerAuthenticationMechanism();
private final CodeAuthenticationMechanism codeAuth = new CodeAuthenticationMechanism();
private final CodeAuthenticationMechanism codeAuth;
private final DefaultTenantConfigResolver resolver;

public OidcAuthenticationMechanism(DefaultTenantConfigResolver resolver) {
public OidcAuthenticationMechanism(DefaultTenantConfigResolver resolver, BlockingSecurityExecutor blockingExecutor) {
this.resolver = resolver;
this.codeAuth = new CodeAuthenticationMechanism(blockingExecutor);
this.bearerAuth.init(this, resolver);
this.codeAuth.init(this, resolver);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
import java.util.function.Supplier;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import org.eclipse.microprofile.jwt.Claims;
import org.jboss.logging.Logger;
Expand All @@ -31,6 +30,7 @@
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.identity.request.TokenAuthenticationRequest;
import io.quarkus.security.runtime.QuarkusSecurityIdentity;
import io.quarkus.security.spi.runtime.BlockingSecurityExecutor;
import io.quarkus.vertx.http.runtime.security.HttpSecurityUtils;
import io.smallrye.mutiny.Uni;
import io.vertx.core.json.JsonObject;
Expand All @@ -47,12 +47,17 @@ public class OidcIdentityProvider implements IdentityProvider<TokenAuthenticatio
private static final Uni<TokenVerificationResult> NULL_CODE_ACCESS_TOKEN_UNI = Uni.createFrom().nullItem();
private static final String CODE_ACCESS_TOKEN_RESULT = "code_flow_access_token_result";

@Inject
DefaultTenantConfigResolver tenantResolver;
private final DefaultTenantConfigResolver tenantResolver;
private final BlockingTaskRunner<Void> uniVoidOidcContext;
private final BlockingTaskRunner<TokenIntrospection> getIntrospectionRequestContext;
private final BlockingTaskRunner<UserInfo> getUserInfoRequestContext;

private BlockingTaskRunner<Void> uniVoidOidcContext = new BlockingTaskRunner<Void>();
private BlockingTaskRunner<TokenIntrospection> getIntrospectionRequestContext = new BlockingTaskRunner<TokenIntrospection>();
private BlockingTaskRunner<UserInfo> getUserInfoRequestContext = new BlockingTaskRunner<UserInfo>();
public OidcIdentityProvider(DefaultTenantConfigResolver tenantResolver, BlockingSecurityExecutor blockingExecutor) {
this.tenantResolver = tenantResolver;
this.uniVoidOidcContext = new BlockingTaskRunner<>(blockingExecutor);
this.getIntrospectionRequestContext = new BlockingTaskRunner<>(blockingExecutor);
this.getUserInfoRequestContext = new BlockingTaskRunner<>(blockingExecutor);
}

@Override
public Class<TokenAuthenticationRequest> getRequestType() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
import io.quarkus.oidc.TenantConfigResolver;
import io.quarkus.oidc.common.runtime.OidcCommonConfig;
import io.quarkus.oidc.common.runtime.OidcCommonUtils;
import io.quarkus.runtime.ExecutorRecorder;
import io.quarkus.runtime.LaunchMode;
import io.quarkus.runtime.RuntimeValue;
import io.quarkus.runtime.TlsConfig;
Expand Down Expand Up @@ -83,8 +82,7 @@ public TenantConfigBean get() {
public Uni<TenantConfigContext> apply(OidcTenantConfig config) {
return createDynamicTenantContext(vertxValue, config, tlsConfig, config.getTenantId().get());
}
},
ExecutorRecorder.getCurrent());
});
}
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package io.quarkus.oidc.runtime;

import java.util.Map;
import java.util.concurrent.Executor;
import java.util.function.Function;

import jakarta.enterprise.context.spi.CreationalContext;
Expand All @@ -21,8 +20,7 @@ public TenantConfigBean(
Map<String, TenantConfigContext> staticTenantsConfig,
Map<String, TenantConfigContext> dynamicTenantsConfig,
TenantConfigContext defaultTenant,
Function<OidcTenantConfig, Uni<TenantConfigContext>> tenantConfigContextFactory,
Executor blockingExecutor) {
Function<OidcTenantConfig, Uni<TenantConfigContext>> tenantConfigContextFactory) {
this.staticTenantsConfig = staticTenantsConfig;
this.dynamicTenantsConfig = dynamicTenantsConfig;
this.defaultTenant = defaultTenant;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.function.Consumer;
import java.util.function.Supplier;

import io.quarkus.runtime.BlockingOperationControl;
import io.quarkus.security.identity.AuthenticationRequestContext;
import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.subscription.UniEmitter;
Expand All @@ -20,19 +21,32 @@ static BlockingSecurityExecutor createBlockingExecutor(Supplier<Executor> execut
return new BlockingSecurityExecutor() {
@Override
public <T> Uni<T> executeBlocking(Supplier<? extends T> function) {
return Uni.createFrom().emitter(new Consumer<UniEmitter<? super T>>() {
return Uni.createFrom().deferred(new Supplier<Uni<? extends T>>() {
@Override
public void accept(UniEmitter<? super T> uniEmitter) {
executorSupplier.get().execute(new Runnable() {
@Override
public void run() {
try {
uniEmitter.complete(function.get());
} catch (Throwable t) {
uniEmitter.fail(t);
}
public Uni<? extends T> get() {
if (BlockingOperationControl.isBlockingAllowed()) {
try {
return Uni.createFrom().item(function.get());
} catch (Throwable t) {
return Uni.createFrom().failure(t);
}
});
} else {
return Uni.createFrom().emitter(new Consumer<UniEmitter<? super T>>() {
@Override
public void accept(UniEmitter<? super T> uniEmitter) {
executorSupplier.get().execute(new Runnable() {
@Override
public void run() {
try {
uniEmitter.complete(function.get());
} catch (Throwable t) {
uniEmitter.fail(t);
}
}
});
}
});
}
}
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

import org.jboss.logging.Logger;

import io.quarkus.runtime.BlockingOperationControl;
import io.quarkus.security.AuthenticationFailedException;
import io.quarkus.security.identity.AuthenticationRequestContext;
import io.quarkus.security.identity.IdentityProvider;
Expand All @@ -38,22 +37,7 @@ public class QuarkusIdentityProviderManagerImpl implements IdentityProviderManag
private final AuthenticationRequestContext blockingRequestContext = new AuthenticationRequestContext() {
@Override
public Uni<SecurityIdentity> runBlocking(Supplier<SecurityIdentity> function) {
return Uni.createFrom().deferred(new Supplier<Uni<? extends SecurityIdentity>>() {
@Override
public Uni<SecurityIdentity> get() {
if (BlockingOperationControl.isBlockingAllowed()) {
try {
SecurityIdentity result = function.get();
return Uni.createFrom().item(result);
} catch (Throwable t) {
return Uni.createFrom().failure(t);
}
} else {
return blockingExecutor.executeBlocking(function);
}
}
});

return blockingExecutor.executeBlocking(function);
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;

import org.jboss.logging.Logger;

import io.quarkus.runtime.BlockingOperationControl;
import io.quarkus.runtime.ExecutorRecorder;
import io.quarkus.security.AuthenticationFailedException;
import io.quarkus.security.ForbiddenException;
import io.quarkus.security.identity.IdentityProviderManager;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.spi.runtime.AuthorizationController;
import io.quarkus.security.spi.runtime.BlockingSecurityExecutor;
import io.smallrye.mutiny.Uni;
import io.smallrye.mutiny.subscription.UniEmitter;
import io.smallrye.mutiny.subscription.UniSubscriber;
import io.smallrye.mutiny.subscription.UniSubscription;
import io.vertx.ext.web.RoutingContext;
Expand All @@ -31,52 +31,37 @@ abstract class AbstractHttpAuthorizer {
private final IdentityProviderManager identityProviderManager;
private final AuthorizationController controller;
private final List<HttpSecurityPolicy> policies;
private final BlockingSecurityExecutor blockingExecutor;

AbstractHttpAuthorizer(HttpAuthenticator httpAuthenticator, IdentityProviderManager identityProviderManager,
AuthorizationController controller, List<HttpSecurityPolicy> policies) {
AuthorizationController controller, List<HttpSecurityPolicy> policies,
BlockingSecurityExecutor blockingExecutor) {
this.httpAuthenticator = httpAuthenticator;
this.identityProviderManager = identityProviderManager;
this.controller = controller;
this.policies = policies;
this.blockingExecutor = blockingExecutor;
}

/**
* context that allows for running blocking tasks
*/
private static final HttpSecurityPolicy.AuthorizationRequestContext CONTEXT = new HttpSecurityPolicy.AuthorizationRequestContext() {
private final HttpSecurityPolicy.AuthorizationRequestContext CONTEXT = new HttpSecurityPolicy.AuthorizationRequestContext() {
@Override
public Uni<HttpSecurityPolicy.CheckResult> runBlocking(RoutingContext context, Uni<SecurityIdentity> identity,
public Uni<HttpSecurityPolicy.CheckResult> runBlocking(RoutingContext context, Uni<SecurityIdentity> identityUni,
BiFunction<RoutingContext, SecurityIdentity, HttpSecurityPolicy.CheckResult> function) {
if (BlockingOperationControl.isBlockingAllowed()) {
try {
HttpSecurityPolicy.CheckResult res = function.apply(context, identity.await().indefinitely());
return Uni.createFrom().item(res);
} catch (Throwable t) {
return Uni.createFrom().failure(t);
}
}
try {
return Uni.createFrom().emitter(new Consumer<UniEmitter<? super HttpSecurityPolicy.CheckResult>>() {
@Override
public void accept(UniEmitter<? super HttpSecurityPolicy.CheckResult> uniEmitter) {

ExecutorRecorder.getCurrent().execute(new Runnable() {
@Override
public void run() {
try {
HttpSecurityPolicy.CheckResult val = function.apply(context,
identity.await().indefinitely());
uniEmitter.complete(val);
} catch (Throwable t) {
uniEmitter.fail(t);
return identityUni
.flatMap(new Function<SecurityIdentity, Uni<? extends HttpSecurityPolicy.CheckResult>>() {
@Override
public Uni<? extends HttpSecurityPolicy.CheckResult> apply(SecurityIdentity identity) {
return blockingExecutor.executeBlocking(new Supplier<HttpSecurityPolicy.CheckResult>() {
@Override
public HttpSecurityPolicy.CheckResult get() {
return function.apply(context, identity);
}
}
});
}
});
} catch (Exception e) {
return Uni.createFrom().failure(e);
}
});
}
});
}
};

Expand Down
Loading

0 comments on commit 48bd965

Please sign in to comment.