diff --git a/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/QuarkusIdentityProviderManagerImpl.java b/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/QuarkusIdentityProviderManagerImpl.java index f2139649f24a1a..a4ba70a667a5a3 100644 --- a/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/QuarkusIdentityProviderManagerImpl.java +++ b/extensions/security/runtime/src/main/java/io/quarkus/security/runtime/QuarkusIdentityProviderManagerImpl.java @@ -224,6 +224,12 @@ public QuarkusIdentityProviderManagerImpl build() { throw new IllegalStateException( "No AnonymousIdentityProvider registered. An instance of AnonymousIdentityProvider must be provided to allow the Anonymous identity to be created."); } + providers.values().forEach(providers -> providers.sort(new Comparator() { + @Override + public int compare(IdentityProvider o1, IdentityProvider o2) { + return Integer.compare(o2.priority(), o1.priority()); + } + })); if (blockingExecutor == null) { throw new IllegalStateException("no blocking executor specified"); } diff --git a/extensions/security/runtime/src/test/java/io/quarkus/security/runtime/QuarkusIdentityProviderManagerImplTest.java b/extensions/security/runtime/src/test/java/io/quarkus/security/runtime/QuarkusIdentityProviderManagerImplTest.java new file mode 100644 index 00000000000000..bab61bced37ed6 --- /dev/null +++ b/extensions/security/runtime/src/test/java/io/quarkus/security/runtime/QuarkusIdentityProviderManagerImplTest.java @@ -0,0 +1,81 @@ +package io.quarkus.security.runtime; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.concurrent.Executors; + +import org.junit.jupiter.api.Test; + +import io.quarkus.security.AuthenticationFailedException; +import io.quarkus.security.identity.AuthenticationRequestContext; +import io.quarkus.security.identity.IdentityProvider; +import io.quarkus.security.identity.IdentityProviderManager; +import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.security.identity.request.BaseAuthenticationRequest; +import io.smallrye.mutiny.Uni; + +class QuarkusIdentityProviderManagerImplTest { + + @Test + void testIdentityProviderPriority() { + IdentityProviderManager identityProviderManager = QuarkusIdentityProviderManagerImpl.builder() + .addProvider(new TestIdentityProviderSystemLastPriority()) + .addProvider(new TestIdentityProviderUserLastPriority()) + .addProvider(new TestIdentityProviderUserFirstPriority()) + .addProvider(new TestIdentityProviderSystemFirstPriority()) + .addProvider(new AnonymousIdentityProvider()) + .setBlockingExecutor(Executors.newSingleThreadExecutor()) + .build(); + + SecurityIdentity identity = identityProviderManager.authenticateBlocking(new TestAuthenticationRequest()); + + assertEquals(new QuarkusPrincipal("Bob"), identity.getPrincipal()); + } + + static class TestAuthenticationRequest extends BaseAuthenticationRequest { + } + + abstract static class TestIdentityProvider implements IdentityProvider { + @Override + public Class getRequestType() { + return TestAuthenticationRequest.class; + } + + @Override + public Uni authenticate(TestAuthenticationRequest request, AuthenticationRequestContext context) { + throw new AuthenticationFailedException(getClass().getSimpleName()); + } + } + + static class TestIdentityProviderUserFirstPriority extends TestIdentityProvider { + @Override + public int priority() { + return Integer.MAX_VALUE; + } + + @Override + public Uni authenticate(TestAuthenticationRequest request, AuthenticationRequestContext context) { + SecurityIdentity identity = QuarkusSecurityIdentity.builder() + .setPrincipal(new QuarkusPrincipal("Bob")) + .build(); + return Uni.createFrom().item(identity); + } + } + + static class TestIdentityProviderUserLastPriority extends TestIdentityProvider { + } + + static class TestIdentityProviderSystemFirstPriority extends TestIdentityProvider { + @Override + public int priority() { + return SYSTEM_FIRST; + } + } + + static class TestIdentityProviderSystemLastPriority extends TestIdentityProvider { + @Override + public int priority() { + return SYSTEM_LAST; + } + } +}