From f70634c9a6fdddbd9873aae8186c6bdc32c9b888 Mon Sep 17 00:00:00 2001 From: Farah Juma Date: Tue, 28 Nov 2023 16:45:08 -0500 Subject: [PATCH] [ELY-2705] Update SecurityDomain#createAdHocIdentity so that it also calls SecurityDomain#transform to ensure that the security domain's security identity transformer gets used if configured --- .../security/auth/server/SecurityDomain.java | 2 +- .../auth/server/SecurityIdentity.java | 4 +- .../auth/server/AdHocIdentityTest.java | 151 ++++++++++++++++++ 3 files changed, 154 insertions(+), 3 deletions(-) create mode 100644 tests/base/src/test/java/org/wildfly/security/auth/server/AdHocIdentityTest.java diff --git a/auth/server/base/src/main/java/org/wildfly/security/auth/server/SecurityDomain.java b/auth/server/base/src/main/java/org/wildfly/security/auth/server/SecurityDomain.java index 389def4f891..e9313def179 100644 --- a/auth/server/base/src/main/java/org/wildfly/security/auth/server/SecurityDomain.java +++ b/auth/server/base/src/main/java/org/wildfly/security/auth/server/SecurityDomain.java @@ -675,7 +675,7 @@ public SecurityIdentity createAdHocIdentity(Principal principal) { if (sm != null) { sm.checkPermission(CREATE_AD_HOC_IDENTITY); } - return new SecurityIdentity(this, principal, EMPTY_REALM_INFO, AuthorizationIdentity.EMPTY, emptyMap(), IdentityCredentials.NONE, IdentityCredentials.NONE); + return this.transform(new SecurityIdentity(this, principal, EMPTY_REALM_INFO, AuthorizationIdentity.EMPTY, emptyMap(), IdentityCredentials.NONE, IdentityCredentials.NONE)); } Supplier getAndSetCurrentSecurityIdentity(Supplier newIdentity) { diff --git a/auth/server/base/src/main/java/org/wildfly/security/auth/server/SecurityIdentity.java b/auth/server/base/src/main/java/org/wildfly/security/auth/server/SecurityIdentity.java index 5a0857eed68..c7632469eda 100644 --- a/auth/server/base/src/main/java/org/wildfly/security/auth/server/SecurityIdentity.java +++ b/auth/server/base/src/main/java/org/wildfly/security/auth/server/SecurityIdentity.java @@ -203,7 +203,7 @@ public final class SecurityIdentity implements PermissionVerifier, PermissionMap this.verifier = old.verifier; this.publicCredentials = old.publicCredentials; this.privateCredentials = old.privateCredentials; - this.withSuppliedIdentities = null; + this.withSuppliedIdentities = old.withSuppliedIdentities; this.withIdentities = old.withIdentities; } @@ -218,7 +218,7 @@ public final class SecurityIdentity implements PermissionVerifier, PermissionMap this.verifier = old.verifier; this.publicCredentials = old.publicCredentials; this.privateCredentials = old.privateCredentials; - this.withSuppliedIdentities = null; + this.withSuppliedIdentities = old.withSuppliedIdentities; this.withIdentities = old.withIdentities; } diff --git a/tests/base/src/test/java/org/wildfly/security/auth/server/AdHocIdentityTest.java b/tests/base/src/test/java/org/wildfly/security/auth/server/AdHocIdentityTest.java new file mode 100644 index 00000000000..22a21b50c7a --- /dev/null +++ b/tests/base/src/test/java/org/wildfly/security/auth/server/AdHocIdentityTest.java @@ -0,0 +1,151 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2023 Red Hat, Inc., and individual contributors + * as indicated by the @author tags. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.wildfly.security.auth.server; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Supplier; +import java.util.function.UnaryOperator; + +import org.junit.Assert; +import org.junit.Test; +import org.wildfly.security.auth.permission.LoginPermission; +import org.wildfly.security.auth.realm.SimpleMapBackedSecurityRealm; +import org.wildfly.security.auth.realm.SimpleRealmEntry; +import org.wildfly.security.authz.MapAttributes; +import org.wildfly.security.authz.RoleDecoder; +import org.wildfly.security.authz.RoleMapper; +import org.wildfly.security.authz.Roles; + +/** + * Tests for creating ad hoc identities. + * + * @author Farah Juma + */ +public class AdHocIdentityTest { + + @Test + public void testAdHocIdentityWithoutSecurityIdentityTransformer() { + SecurityDomain domain = getSecurityDomain(null); + SecurityIdentity identity = domain.createAdHocIdentity("alice"); + assertNotNull(identity); + assertEquals("alice", identity.getPrincipal().getName()); + assertTrue(identity.getRoles().isEmpty()); + } + + @Test + public void testAdHocIdentityWithSecurityIdentityTransformer() { + SecurityDomain domain = getSecurityDomain(securityIdentity -> securityIdentity.withDefaultRoleMapper(RoleMapper.constant(Roles.of("constantRole")))); + SecurityIdentity identity = domain.createAdHocIdentity("alice"); + assertNotNull(identity); + assertEquals("alice", identity.getPrincipal().getName()); + assertTrue(identity.getRoles().contains("constantRole")); + } + + @Test + public void testAdHocIdentityWithComplexSecurityIdentityTransformer() { + SecurityDomain outflowDomain = getSecurityDomain(getRealm(), null); + SecurityDomain domain = getSecurityDomain(securityIdentity -> outflow(securityIdentity, outflowDomain)); + + SecurityIdentity identity = domain.createAdHocIdentity("joe"); + assertNotNull(identity); + assertEquals("joe", identity.getPrincipal().getName()); + assertEquals(domain, identity.getSecurityDomain()); + + assertEquals(outflowDomain.getAnonymousSecurityIdentity(), outflowDomain.getCurrentSecurityIdentity()); + SecurityIdentity outflowDomainIdentity = identity.runAsSupplierEx(() -> outflowDomain.getCurrentSecurityIdentity()); + assertEquals("joe", outflowDomainIdentity.getPrincipal().getName()); + assertTrue(outflowDomainIdentity.getRoles().contains("User")); + } + + @Test + public void testAdHocIdentityWithComplexSecurityIdentityTransformerAndDefaultRoleMapper() { + SecurityDomain outflowDomain = getSecurityDomain(getRealm(), null); + + SecurityDomain domain = getSecurityDomain(securityIdentity -> outflow(securityIdentity, outflowDomain)); + SecurityIdentity identity = domain.createAdHocIdentity("joe"); + assertNotNull(identity); + assertEquals("joe", identity.getPrincipal().getName()); + assertEquals(domain, identity.getSecurityDomain()); + + identity = identity.withDefaultRoleMapper(RoleMapper.constant(Roles.of("constantRole"))); + assertTrue(identity.getRoles().contains("constantRole")); + assertEquals(outflowDomain.getAnonymousSecurityIdentity(), outflowDomain.getCurrentSecurityIdentity()); + SecurityIdentity outflowDomainIdentity = identity.runAsSupplierEx(() -> outflowDomain.getCurrentSecurityIdentity()); + assertEquals("joe", outflowDomainIdentity.getPrincipal().getName()); + assertTrue(outflowDomainIdentity.getRoles().contains("User")); + assertFalse(outflowDomainIdentity.getRoles().contains("constantRole")); + } + + private static void addUser(Map securityRealm, String userName, String roles) { + MapAttributes attributes = new MapAttributes(); + attributes.addAll(RoleDecoder.KEY_ROLES, Collections.singletonList(roles)); + securityRealm.put(userName, new SimpleRealmEntry(Collections.emptyList(), attributes)); + } + + private static SecurityDomain getSecurityDomain(UnaryOperator securityIdentityTransformer) { + return getSecurityDomain(null, securityIdentityTransformer); + } + + private static SecurityDomain getSecurityDomain(SecurityRealm realm, UnaryOperator securityIdentityTransformer) { + SecurityDomain.Builder securityDomainBuilder = SecurityDomain.builder(); + if (realm != null) { + securityDomainBuilder.addRealm("default", realm).build(); + securityDomainBuilder.setDefaultRealmName("default"); + securityDomainBuilder.setTrustedSecurityDomainPredicate(securityDomain -> true); // trusts all other domains + } + securityDomainBuilder.setPermissionMapper((permissionMappable, roles) -> LoginPermission.getInstance()); + if (securityIdentityTransformer != null) { + securityDomainBuilder.setSecurityIdentityTransformer(securityIdentityTransformer); + } + return securityDomainBuilder.build(); + } + + private static SecurityRealm getRealm() { + SimpleMapBackedSecurityRealm realm = new SimpleMapBackedSecurityRealm(); + Map users = new HashMap<>(); + addUser(users, "joe", "User"); + addUser(users, "bob", "User"); + realm.setIdentityMap(users); + return realm; + } + + private SecurityIdentity outflow(SecurityIdentity securityIdentity, SecurityDomain outflowDomain) { + return securityIdentity.withSecurityIdentitySupplier(performOutflow(securityIdentity, outflowDomain)); + } + + private static Supplier performOutflow(SecurityIdentity securityIdentity, SecurityDomain securityDomain) { + return () -> { + ServerAuthenticationContext context = securityDomain.createNewAuthenticationContext(); + try { + Assert.assertTrue(context.importIdentity(securityIdentity)); + } catch (RealmUnavailableException e) { + Assert.fail("Unable to import identity"); + } + SecurityIdentity outflowedIdentity = context.getAuthorizedIdentity(); + return new SecurityIdentity[] { outflowedIdentity }; + }; + } +}