From 81fb692fc4b832a2e183be4ba6eee29c0c763476 Mon Sep 17 00:00:00 2001 From: Christian von Atzigen Date: Tue, 3 Jan 2023 21:19:48 +0100 Subject: [PATCH] Align behavior for getDeferredIdentity and getIdentity in TestIdentityAssociation Signed-off-by: Christian von Atzigen --- .../it/keycloak/ProtectedResource.java | 8 +- .../it/keycloak/TestSecurityLazyAuthTest.java | 4 +- .../security/TestIdentityAssociation.java | 7 +- .../security/TestIdentityAssociationTest.java | 90 +++++++++++++++++++ 4 files changed, 103 insertions(+), 6 deletions(-) create mode 100644 test-framework/security/src/test/java/io/quarkus/test/security/TestIdentityAssociationTest.java diff --git a/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java b/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java index fbe80108b4407..2bac753ec2c0b 100644 --- a/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java +++ b/integration-tests/oidc-code-flow/src/main/java/io/quarkus/it/keycloak/ProtectedResource.java @@ -24,6 +24,7 @@ import io.quarkus.oidc.common.runtime.OidcConstants; import io.quarkus.security.Authenticated; import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.security.runtime.SecurityIdentityAssociation; import io.vertx.ext.web.RoutingContext; @Path("/web-app") @@ -33,6 +34,9 @@ public class ProtectedResource { @Inject SecurityIdentity identity; + @Inject + SecurityIdentityAssociation securityIdentityAssociation; + @Inject Principal principal; @@ -68,13 +72,15 @@ public class ProtectedResource { @Path("test-security") public String testSecurity() { return securityContext.getUserPrincipal().getName() + ":" + identity.getPrincipal().getName() + ":" - + principal.getName(); + + principal.getName() + ":" + + securityIdentityAssociation.getDeferredIdentity().await().indefinitely().getPrincipal().getName(); } @GET @Path("test-security-oidc") public String testSecurityJwt() { return idToken.getName() + ":" + identity.getPrincipal().getName() + ":" + principal.getName() + + ":" + securityIdentityAssociation.getDeferredIdentity().await().indefinitely().getPrincipal().getName() + ":" + idToken.getGroups().iterator().next() + ":" + idToken.getClaim("email") + ":" + userInfo.getString("sub") diff --git a/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java b/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java index df85208b6a1dc..40732c2d319cc 100644 --- a/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java +++ b/integration-tests/oidc-code-flow/src/test/java/io/quarkus/it/keycloak/TestSecurityLazyAuthTest.java @@ -26,14 +26,14 @@ public class TestSecurityLazyAuthTest { @TestSecurity(user = "user1", roles = "viewer") public void testWithDummyUser() { RestAssured.when().get("test-security").then() - .body(is("user1:user1:user1")); + .body(is("user1:user1:user1:user1")); } @Test @TestSecurityMetaAnnotation public void testJwtWithDummyUser() { RestAssured.when().get("test-security-oidc").then() - .body(is("userOidc:userOidc:userOidc:viewer:user@gmail.com:subject:aud")); + .body(is("userOidc:userOidc:userOidc:userOidc:viewer:user@gmail.com:subject:aud")); } @Retention(RetentionPolicy.RUNTIME) diff --git a/test-framework/security/src/main/java/io/quarkus/test/security/TestIdentityAssociation.java b/test-framework/security/src/main/java/io/quarkus/test/security/TestIdentityAssociation.java index 22a009171315a..338fdc0cde875 100644 --- a/test-framework/security/src/main/java/io/quarkus/test/security/TestIdentityAssociation.java +++ b/test-framework/security/src/main/java/io/quarkus/test/security/TestIdentityAssociation.java @@ -56,10 +56,11 @@ public void setIdentity(Uni identity) { @Override public Uni getDeferredIdentity() { - if (testIdentity != null) { - return Uni.createFrom().item(testIdentity); + if (testIdentity == null) { + return delegate.getDeferredIdentity(); } - return delegate.getDeferredIdentity(); + return delegate.getDeferredIdentity().onItem() + .transform(underlying -> underlying.isAnonymous() ? testIdentity : underlying); } @Override diff --git a/test-framework/security/src/test/java/io/quarkus/test/security/TestIdentityAssociationTest.java b/test-framework/security/src/test/java/io/quarkus/test/security/TestIdentityAssociationTest.java new file mode 100644 index 0000000000000..b1eeb6eab711d --- /dev/null +++ b/test-framework/security/src/test/java/io/quarkus/test/security/TestIdentityAssociationTest.java @@ -0,0 +1,90 @@ +package io.quarkus.test.security; + +import static io.quarkus.security.runtime.QuarkusSecurityIdentity.builder; +import static org.junit.jupiter.api.Assertions.assertSame; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import io.quarkus.runtime.BlockingOperationControl; +import io.quarkus.runtime.IOThreadDetector; +import io.quarkus.security.identity.SecurityIdentity; +import io.quarkus.security.runtime.QuarkusPrincipal; +import io.smallrye.mutiny.Uni; + +public class TestIdentityAssociationTest { + + TestIdentityAssociation sut; + + @BeforeEach + void init() { + sut = new TestIdentityAssociation(); + sut.delegate = new DelegateSecurityIdentityAssociation(); + + BlockingOperationControl.setIoThreadDetector(new IOThreadDetector[0]); + } + + @Test + void useDelegateIfTestIdentityIsNull() { + // create anonymous identity + SecurityIdentity mockedIdentity = builder().setAnonymous(true).build(); + Uni mockedIdentityUni = Uni.createFrom().item(mockedIdentity); + sut.setIdentity(mockedIdentity); + sut.setIdentity(mockedIdentityUni); + + // reset testIdentity + sut.setTestIdentity(null); + + // get identity direct + deferred + SecurityIdentity deferred = sut.getDeferredIdentity().await().indefinitely(); + SecurityIdentity identity = sut.getIdentity(); + + // must be the same instance + assertSame(identity, deferred, "Must be same instance directly and deferred"); + assertSame(mockedIdentity, identity, "Expected delegate. (TestIdentity is null)"); + } + + @Test + void useTestIdentityIfDelegateIsAnonymous() { + // create anonymous identity + SecurityIdentity mockedIdentity = builder().setAnonymous(true).build(); + Uni mockedIdentityUni = Uni.createFrom().item(mockedIdentity); + // create test identity + SecurityIdentity mockedTestIdentity = builder().setPrincipal(new QuarkusPrincipal("test-identity")).build(); + sut.setIdentity(mockedIdentity); + sut.setIdentity(mockedIdentityUni); + + // reset testIdentity + sut.setTestIdentity(mockedTestIdentity); + + // get identity direct + deferred + SecurityIdentity deferred = sut.getDeferredIdentity().await().indefinitely(); + SecurityIdentity identity = sut.getIdentity(); + + // must be the same instance + assertSame(identity, deferred, "Must be same instance directly and deferred"); + assertSame(mockedTestIdentity, identity, "Expected testIdentity. (Delegate is anonymous)"); + } + + @Test + void useDelegateIfNotAnonymous() { + // create identity with principal + SecurityIdentity mockedIdentity = builder().setPrincipal(new QuarkusPrincipal("delegate")).build(); + Uni mockedIdentityUni = Uni.createFrom().item(mockedIdentity); + // create test identity + SecurityIdentity mockedTestIdentity = builder().setPrincipal(new QuarkusPrincipal("test-identity")).build(); + sut.setIdentity(mockedIdentity); + sut.setIdentity(mockedIdentityUni); + + // reset testIdentity + sut.setTestIdentity(mockedTestIdentity); + + // get identity direct + deferred + SecurityIdentity deferred = sut.getDeferredIdentity().await().indefinitely(); + SecurityIdentity identity = sut.getIdentity(); + + // must be the same instance + assertSame(identity, deferred, "Must be same instance directly and deferred"); + assertSame(mockedIdentity, identity, "Expected delegate. (Delegate is not anonymous)"); + } +}