Skip to content

Commit

Permalink
[ELY-2468] Update getRealmIdentity so that it attempts to convert the…
Browse files Browse the repository at this point in the history
… given Principal to NamePrincipal if necessary
  • Loading branch information
fjuma committed Oct 21, 2022
1 parent 9b7e1c1 commit ad72460
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,36 @@ public boolean equals(final NamePrincipal obj) {
public String toString() {
return name;
}

/**
* Attempt to convert the given principal to a {@code NamePrincipal}.
*
* @param principal the original principal
* @return the {@code NamePrincipal} or {@code null} if the principal cannot be converted
*/
public static NamePrincipal from(Principal principal) {
if (principal instanceof NamePrincipal) {
return (NamePrincipal) principal;
}
return isConvertibleTo(principal) ? new NamePrincipal(principal.getName()) : null;
}

/**
* Check if the given principal could be converted to a {@code NamePrincipal}.
*
* @param principal the original principal
* @return {@code true} if the principal can be converted to a {@code NamePrincipal} and {@code false} otherwise
*/
public static boolean isConvertibleTo(Principal principal) {
if (principal instanceof NamePrincipal) {
return true;
}
if (principal != null) {
String name = principal.getName();
if (name != null && ! name.isEmpty()) {
return true;
}
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -214,11 +214,11 @@ private String nameFor(Path path) {
}

public RealmIdentity getRealmIdentity(final Principal principal) {
return principal instanceof NamePrincipal ? getRealmIdentity(principal.getName(), false) : RealmIdentity.NON_EXISTENT;
return NamePrincipal.isConvertibleTo(principal) ? getRealmIdentity(principal.getName(), false) : RealmIdentity.NON_EXISTENT;
}

public ModifiableRealmIdentity getRealmIdentityForUpdate(final Principal principal) {
return principal instanceof NamePrincipal ? getRealmIdentity(principal.getName(), true) : ModifiableRealmIdentity.NON_EXISTENT;
return NamePrincipal.isConvertibleTo(principal) ? getRealmIdentity(principal.getName(), true) : ModifiableRealmIdentity.NON_EXISTENT;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,12 @@ public JaasSecurityRealm(final String loginConfiguration, final CallbackHandler

@Override
public RealmIdentity getRealmIdentity(final Principal principal) {
return principal instanceof NamePrincipal ? new JaasRealmIdentity(principal) : RealmIdentity.NON_EXISTENT;
if (principal instanceof NamePrincipal) {
return new JaasRealmIdentity(principal);
} else {
NamePrincipal namePrincipal = NamePrincipal.from(principal);
return namePrincipal != null ? new JaasRealmIdentity(namePrincipal) : RealmIdentity.NON_EXISTENT;
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public KeyStoreBackedSecurityRealm(final KeyStore keyStore, final Supplier<Provi

@Override
public RealmIdentity getRealmIdentity(final Principal principal) throws RealmUnavailableException {
if (principal instanceof NamePrincipal) {
if (NamePrincipal.isConvertibleTo(principal)) {
String name = principal.getName();
log.tracef("KeyStoreRealm: obtaining certificate by alias [%s]", name);
return new KeyStoreRealmIdentity(name);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,23 +96,24 @@ private LegacyPropertiesSecurityRealm(Builder builder) throws IOException {

@Override
public RealmIdentity getRealmIdentity(final Principal principal) throws RealmUnavailableException {
if (! (principal instanceof NamePrincipal)) {
NamePrincipal namePrincipal = NamePrincipal.from(principal);
if (namePrincipal == null) {
log.tracef("PropertiesRealm: unsupported principal type: [%s]", principal);
return RealmIdentity.NON_EXISTENT;
}
final LoadedState loadedState = this.loadedState.get();

final AccountEntry accountEntry = loadedState.getAccounts().get(principal.getName());
final AccountEntry accountEntry = loadedState.getAccounts().get(namePrincipal.getName());

if (accountEntry == null) {
log.tracef("PropertiesRealm: identity [%s] does not exist", principal);
log.tracef("PropertiesRealm: identity [%s] does not exist", namePrincipal);
return RealmIdentity.NON_EXISTENT;
}

return new RealmIdentity() {

public Principal getRealmIdentityPrincipal() {
return principal;
return namePrincipal;
}

@Override
Expand All @@ -138,7 +139,7 @@ public <C extends Credential> C getCredential(final Class<C> credentialType, fin
@Override
public <C extends Credential> C getCredential(final Class<C> credentialType, final String algorithmName, final AlgorithmParameterSpec parameterSpec) throws RealmUnavailableException {
if (accountEntry.getPasswordRepresentation() == null || LegacyPropertiesSecurityRealm.this.getCredentialAcquireSupport(credentialType, algorithmName, parameterSpec) == SupportLevel.UNSUPPORTED) {
log.tracef("PropertiesRealm: Unable to obtain credential for identity [%s]", principal);
log.tracef("PropertiesRealm: Unable to obtain credential for identity [%s]", namePrincipal);
return null;
}

Expand All @@ -150,7 +151,7 @@ public <C extends Credential> C getCredential(final Class<C> credentialType, fin
} else if (ALGORITHM_DIGEST_MD5.equals(algorithmName)) {
clear = false;
} else {
log.tracef("PropertiesRealm: Unable to obtain credential for identity [%s]: unsupported algorithm [%s]", principal, algorithmName);
log.tracef("PropertiesRealm: Unable to obtain credential for identity [%s]: unsupported algorithm [%s]", namePrincipal, algorithmName);
return null;
}

Expand Down Expand Up @@ -191,7 +192,7 @@ public <C extends Credential> C getCredential(final Class<C> credentialType, fin
@Override
public boolean verifyEvidence(final Evidence evidence) throws RealmUnavailableException {
if (accountEntry.getPasswordRepresentation() == null || !(evidence instanceof PasswordGuessEvidence)) {
log.tracef("Unable to verify evidence for identity [%s]", principal);
log.tracef("Unable to verify evidence for identity [%s]", namePrincipal);
return false;
}
final char[] guess = ((PasswordGuessEvidence) evidence).getGuess();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ public void setPasswordMap(final String name, final Password password) {

@Override
public RealmIdentity getRealmIdentity(final Principal principal) {
if (! (principal instanceof NamePrincipal)) {
if (! NamePrincipal.isConvertibleTo(principal)) {
return RealmIdentity.NON_EXISTENT;
}
String name = rewriter.rewriteName(principal.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public static JdbcSecurityRealmBuilder builder() {

@Override
public RealmIdentity getRealmIdentity(final Principal principal) {
if (! (principal instanceof NamePrincipal)) {
if (! NamePrincipal.isConvertibleTo(principal)) {
return RealmIdentity.NON_EXISTENT;
}
return new JdbcRealmIdentity(principal.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ private void registerIdentityChangeListener(final DirContext dirContext, final C
}

private ModifiableRealmIdentity getRealmIdentity(final Principal principal, final boolean exclusive) {
if (! (principal instanceof NamePrincipal)) {
if (! NamePrincipal.isConvertibleTo(principal)) {
return ModifiableRealmIdentity.NON_EXISTENT;
}
String name = nameRewriter.rewriteName(principal.getName());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,24 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.security.Principal;
import java.security.spec.AlgorithmParameterSpec;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.junit.BeforeClass;
import org.junit.Test;
import org.wildfly.security.auth.SupportLevel;
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.Roles;
import org.wildfly.security.credential.Credential;
import org.wildfly.security.evidence.Evidence;
import org.wildfly.security.permission.PermissionVerifier;

/**
Expand All @@ -48,6 +53,8 @@ public class IdentityPropagationTest {
private static SecurityDomain domain1;
private static SecurityDomain domain2;
private static SecurityDomain domain3;
private static SecurityDomain domain4;
private static SecurityDomain domain5;

@BeforeClass
public static void setupSecurityDomains() {
Expand Down Expand Up @@ -93,6 +100,23 @@ public static void setupSecurityDomains() {
trustedSecurityDomains.add(domain2);
builder.setTrustedSecurityDomainPredicate(trustedSecurityDomains::contains);
domain3 = builder.build();

// domain4 contains a custom realm
builder = SecurityDomain.builder();
builder.addRealm("customRealm", new CustomRealm()).build();
builder.setDefaultRealmName("customRealm");
builder.setPermissionMapper((permissionMappable, roles) -> PermissionVerifier.from(new LoginPermission()));
domain4 = builder.build();

// domain5 trusts domain4
builder = SecurityDomain.builder();
builder.addRealm("usersRealm", realm1).setRoleMapper(rolesToMap -> Roles.of("UserRole")).build();
builder.setDefaultRealmName("usersRealm");
trustedSecurityDomains = new HashSet<>();
trustedSecurityDomains.add(domain4);
builder.setTrustedSecurityDomainPredicate(trustedSecurityDomains::contains);
builder.setPermissionMapper((permissionMappable, roles) -> PermissionVerifier.from(new LoginPermission()));
domain5 = builder.build();
}

@Test
Expand Down Expand Up @@ -153,6 +177,28 @@ public void testInflowFromSameDomain() throws Exception {
assertTrue(inflowedIdentity.getAttributes().get("roles").containsAll(establishedIdentity.getAttributes().get("roles")));
}

@Test
public void testInflowSecurityIdentityWithCustomPrincipal() throws Exception {
// establish an identity using domain4
ServerAuthenticationContext context = domain4.createNewAuthenticationContext();
assertTrue(context.verifyEvidence(new Evidence() {
@Override
public Principal getPrincipal() {
return new CustomRealm.CustomPrincipal("joe");
}
}));
assertTrue(context.authorize());
SecurityIdentity establishedIdentity = context.getAuthorizedIdentity();

// import the established identity into domain5
context = domain5.createNewAuthenticationContext();
assertTrue(context.importIdentity(establishedIdentity));
SecurityIdentity inflowedIdentity = context.getAuthorizedIdentity();
assertEquals("joe", inflowedIdentity.getPrincipal().getName());
assertEquals(domain5, inflowedIdentity.getSecurityDomain());
assertTrue(inflowedIdentity.getRoles().contains("UserRole"));
}

private static void addUser(Map<String, SimpleRealmEntry> securityRealm, String userName, String roles) {
MapAttributes attributes = new MapAttributes();
attributes.addAll(RoleDecoder.KEY_ROLES, Collections.singletonList(roles));
Expand All @@ -162,4 +208,98 @@ private static void addUser(Map<String, SimpleRealmEntry> securityRealm, String
private SecurityIdentity getIdentityFromDomain(final SecurityDomain securityDomain, final String userName) {
return securityDomain.getAnonymousSecurityIdentity().createRunAsIdentity(userName, false);
}

private static class CustomRealm implements SecurityRealm {

@Override
public RealmIdentity getRealmIdentity(Principal principal) throws RealmUnavailableException {
return new CustomRealmIdentity(new CustomPrincipal(principal.getName()));
}

@Override
public RealmIdentity getRealmIdentity(Evidence evidence) throws RealmUnavailableException {
throw new RealmUnavailableException();
}

@Override
public SupportLevel getCredentialAcquireSupport(Class<? extends Credential> credentialType, String algorithmName, AlgorithmParameterSpec parameterSpec) throws RealmUnavailableException {
return SupportLevel.UNSUPPORTED;
}

@Override
public SupportLevel getEvidenceVerifySupport(Class<? extends Evidence> evidenceType, String algorithmName) throws RealmUnavailableException {
return SupportLevel.UNSUPPORTED;
}

private class CustomRealmIdentity implements RealmIdentity {

CustomPrincipal principal;

public CustomRealmIdentity(CustomPrincipal principal) {
this.principal = principal;
}

@Override
public Principal getRealmIdentityPrincipal() {
return principal;
}

@Override
public SupportLevel getCredentialAcquireSupport(Class<? extends Credential> credentialType, String algorithmName, AlgorithmParameterSpec parameterSpec) throws RealmUnavailableException {
return SupportLevel.UNSUPPORTED;
}

@Override
public <C extends Credential> C getCredential(Class<C> credentialType) throws RealmUnavailableException {
return null;
}

@Override
public SupportLevel getEvidenceVerifySupport(Class<? extends Evidence> evidenceType, String algorithmName) throws RealmUnavailableException {
return SupportLevel.UNSUPPORTED;
}

@Override
public boolean verifyEvidence(Evidence evidence) throws RealmUnavailableException {
return principal != null;
}

@Override
public boolean exists() throws RealmUnavailableException {
return principal != null;
}
}

private static class CustomPrincipal implements Principal {
private final String name;

public CustomPrincipal(String name) {
this.name = name;
}

@Override
public String getName() {
return name;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CustomPrincipal that = (CustomPrincipal) o;
if (! name.equals(that.name)) return false;
return true;
}

@Override
public int hashCode() {
return name.hashCode();
}

@Override
public String toString() {
return name;
}
}
}
}

0 comments on commit ad72460

Please sign in to comment.