diff --git a/docs/src/main/asciidoc/security-ldap.adoc b/docs/src/main/asciidoc/security-ldap.adoc index 83b1695367a83..977ac6abacd07 100644 --- a/docs/src/main/asciidoc/security-ldap.adoc +++ b/docs/src/main/asciidoc/security-ldap.adoc @@ -177,6 +177,18 @@ quarkus.security.ldap.identity-mapping.attribute-mappings."0".filter-base-dn=ou= The `elytron-security-ldap` extension requires a dir-context and an identity-mapping with at least one attribute-mapping to authenticate the user and its identity. +=== Map LDAP groups to `SecurityIdentity` roles + +Previously described application configuration showed how to map `CN` attribute of the LDAP Distinguished Name group to a Quarkus `SecurityIdentity` role. +More specifically, the `standardRole` CN was mapped to a `SecurityIdentity` role and thus allowed access to the `UserResource#me` endpoint. +However, required `SecurityIdentity` roles may differ between applications and you may need to map LDAP groups to local `SecurityIdentity` roles like in the example below: + +[source,properties] +---- +quarkus.http.auth.roles-mapping."standardRole"=user <1> +---- +<1> Map the `standardRole` role to the application-specific `SecurityIdentity` role `user`. + == Testing the Application The application is now protected and the identities are provided by our LDAP server. diff --git a/integration-tests/elytron-security-ldap/src/main/java/io/quarkus/elytron/security/ldap/it/ElytronSecurityLdapResource.java b/integration-tests/elytron-security-ldap/src/main/java/io/quarkus/elytron/security/ldap/it/ElytronSecurityLdapResource.java index 17ca851fdd315..6c193564584ec 100644 --- a/integration-tests/elytron-security-ldap/src/main/java/io/quarkus/elytron/security/ldap/it/ElytronSecurityLdapResource.java +++ b/integration-tests/elytron-security-ldap/src/main/java/io/quarkus/elytron/security/ldap/it/ElytronSecurityLdapResource.java @@ -20,6 +20,8 @@ import jakarta.enterprise.context.ApplicationScoped; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.SecurityContext; @Path("/api") @ApplicationScoped @@ -45,4 +47,11 @@ public String forbidden() { return "authorized"; } + @GET + @Path("/requiresRootRole") + @RolesAllowed("root") + public String getPrincipalName(@Context SecurityContext securityContext) { + return securityContext.getUserPrincipal().getName(); + } + } diff --git a/integration-tests/elytron-security-ldap/src/main/resources/application.properties b/integration-tests/elytron-security-ldap/src/main/resources/application.properties index 4454fc4de0f62..4546c1d3776c1 100644 --- a/integration-tests/elytron-security-ldap/src/main/resources/application.properties +++ b/integration-tests/elytron-security-ldap/src/main/resources/application.properties @@ -14,3 +14,5 @@ quarkus.security.ldap.identity-mapping.attribute-mappings."0".filter-base-dn=ou= quarkus.security.ldap.cache.enabled=true quarkus.security.ldap.cache.max-age=60s quarkus.security.ldap.cache.size=10 + +quarkus.http.auth.roles-mapping."adminRole"=root diff --git a/integration-tests/elytron-security-ldap/src/test/java/io/quarkus/elytron/security/ldap/it/ElytronLdapExtensionTestResources.java b/integration-tests/elytron-security-ldap/src/test/java/io/quarkus/elytron/security/ldap/it/ElytronLdapExtensionTestResources.java deleted file mode 100644 index c0144886d8b05..0000000000000 --- a/integration-tests/elytron-security-ldap/src/test/java/io/quarkus/elytron/security/ldap/it/ElytronLdapExtensionTestResources.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.quarkus.elytron.security.ldap.it; - -import io.quarkus.test.common.QuarkusTestResource; -import io.quarkus.test.ldap.LdapServerTestResource; - -@QuarkusTestResource(LdapServerTestResource.class) -public class ElytronLdapExtensionTestResources { -} diff --git a/integration-tests/elytron-security-ldap/src/test/java/io/quarkus/elytron/security/ldap/it/ElytronSecurityLdapTest.java b/integration-tests/elytron-security-ldap/src/test/java/io/quarkus/elytron/security/ldap/it/ElytronSecurityLdapTest.java index e2e107bdb26e6..5d4f2b0518b00 100644 --- a/integration-tests/elytron-security-ldap/src/test/java/io/quarkus/elytron/security/ldap/it/ElytronSecurityLdapTest.java +++ b/integration-tests/elytron-security-ldap/src/test/java/io/quarkus/elytron/security/ldap/it/ElytronSecurityLdapTest.java @@ -6,11 +6,13 @@ import org.junit.jupiter.api.Test; import com.unboundid.ldap.listener.InMemoryDirectoryServer; -import com.unboundid.ldap.sdk.LDAPException; +import io.quarkus.test.common.WithTestResource; import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.ldap.LdapServerTestResource; import io.restassured.RestAssured; +@WithTestResource(LdapServerTestResource.class) @QuarkusTest class ElytronSecurityLdapTest { @@ -96,9 +98,31 @@ void admin_role_not_authorized() { .statusCode(403); } - @Test() + @Test @Order(8) - void standard_role_authenticated_cached() throws LDAPException { + void testMappingOfLdapGroupsToIdentityRoles() { + // LDAP groups are added as SecurityIdentity roles + // according to the quarkus.security.ldap.identity-mapping.attribute-mappings + // this test verifies that LDAP groups can be remapped to application-specific SecurityIdentity roles + // role 'adminRole' comes from 'cn' and we remapped it to 'root' + RestAssured.given() + .auth().preemptive().basic("standardUser", "standardUserPassword") + .when() + .get("/api/requiresRootRole") + .then() + .statusCode(403); + RestAssured.given() + .auth().preemptive().basic("adminUser", "adminUserPassword") + .when() + .get("/api/requiresRootRole") + .then() + .statusCode(200) + .body(containsString("adminUser")); // that is uid + } + + @Test + @Order(9) + void standard_role_authenticated_cached() { RestAssured.given() .redirects().follow(false) .when()