Skip to content

Commit

Permalink
[ELY-1894] Add the ability to make use of the IP address of a remote …
Browse files Browse the repository at this point in the history
…client when making authorization decisions
  • Loading branch information
fjuma committed Apr 17, 2020
1 parent 8ca9556 commit 052e015
Show file tree
Hide file tree
Showing 11 changed files with 662 additions and 47 deletions.
Expand Up @@ -29,6 +29,7 @@
import org.wildfly.security.auth.server.event.RealmAuthenticationEvent;
import org.wildfly.security.auth.server.event.RealmAuthorizationEvent;
import org.wildfly.security.auth.server.event.RealmEvent;
import org.wildfly.security.authz.AggregateAttributes;
import org.wildfly.security.authz.Attributes;
import org.wildfly.security.authz.AuthorizationIdentity;
import org.wildfly.security.credential.Credential;
Expand Down
Expand Up @@ -18,6 +18,7 @@

import static org.junit.Assert.assertEquals;
import org.junit.Test;
import org.wildfly.security.authz.AggregateAttributes;
import org.wildfly.security.authz.Attributes;
import org.wildfly.security.authz.Attributes.Entry;
import org.wildfly.security.authz.MapAttributes;
Expand Down
Expand Up @@ -99,6 +99,7 @@ public final class SecurityDomain {
private final Predicate<SecurityDomain> trustedSecurityDomain;
private final Consumer<SecurityEvent> securityEventListener;
private final Function<Evidence, Principal> evidenceDecoder;
private final RoleDecoder roleDecoder;

SecurityDomain(Builder builder, final LinkedHashMap<String, RealmInfo> realmMap) {
this.realmMap = realmMap;
Expand All @@ -112,6 +113,7 @@ public final class SecurityDomain {
this.trustedSecurityDomain = builder.trustedSecurityDomain;
this.securityEventListener = builder.securityEventListener;
this.evidenceDecoder = builder.evidenceDecoder;
this.roleDecoder = builder.roleDecoder;
final Map<String, RoleMapper> originalRoleMappers = builder.categoryRoleMappers;
final Map<String, RoleMapper> copiedRoleMappers;
if (originalRoleMappers.isEmpty()) {
Expand Down Expand Up @@ -698,15 +700,19 @@ Roles mapRoles(SecurityIdentity securityIdentity) {
// zeroth role mapping, just grab roles from the identity
Roles decodedRoles = realmInfo.getRoleDecoder().decodeRoles(identity);

// determine roles based on any runtime attributes associated with the identity
Roles domainDecodedRoles = securityIdentity.getSecurityDomain().getRoleDecoder().decodeRoles(identity);
Roles combinedRoles = decodedRoles.or(domainDecodedRoles);

// apply the first level mapping, which is based on the role mapper associated with a realm.
Roles realmMappedRoles = realmInfo.getRoleMapper().mapRoles(decodedRoles);
Roles realmMappedRoles = realmInfo.getRoleMapper().mapRoles(combinedRoles);

// apply the second level mapping, which is based on the role mapper associated with this security domain.
Roles domainMappedRoles = roleMapper.mapRoles(realmMappedRoles);

if (log.isTraceEnabled()) {
log.tracef("Role mapping: principal [%s] -> decoded roles [%s] -> realm mapped roles [%s] -> domain mapped roles [%s]",
securityIdentity.getPrincipal(), String.join(", ", decodedRoles), String.join(", ", realmMappedRoles), String.join(", ", domainMappedRoles));
log.tracef("Role mapping: principal [%s] -> decoded roles [%s] -> domain decoded roles [%s] -> realm mapped roles [%s] -> domain mapped roles [%s]",
securityIdentity.getPrincipal(), String.join(", ", decodedRoles), String.join(", ", domainDecodedRoles), String.join(", ", realmMappedRoles), String.join(", ", domainMappedRoles));
}

return domainMappedRoles;
Expand Down Expand Up @@ -788,6 +794,10 @@ Function<Evidence, Principal> getEvidenceDecoder() {
return evidenceDecoder;
}

RoleDecoder getRoleDecoder() {
return roleDecoder;
}

/**
* A builder for creating new security domains.
*/
Expand All @@ -807,6 +817,7 @@ public static final class Builder {
private Predicate<SecurityDomain> trustedSecurityDomain = domain -> false;
private Consumer<SecurityEvent> securityEventListener = e -> {};
private Function<Evidence, Principal> evidenceDecoder = evidence -> evidence.getDefaultPrincipal();
private RoleDecoder roleDecoder = RoleDecoder.EMPTY;

Builder() {
}
Expand Down Expand Up @@ -1027,6 +1038,20 @@ public Builder setEvidenceDecoder(EvidenceDecoder evidenceDecoder) {
return this;
}

/**
* Set the role decoder for this security domain.
*
* @param roleDecoder the role decoder (must not be {@code null})
* @return this builder
* @since 1.11.0
*/
public Builder setRoleDecoder(RoleDecoder roleDecoder) {
Assert.checkNotNullParam("roleDecoder", roleDecoder);
assertNotBuilt();
this.roleDecoder = roleDecoder;
return this;
}

/**
* Construct this security domain.
*
Expand Down
Expand Up @@ -207,6 +207,21 @@ public final class SecurityIdentity implements PermissionVerifier, PermissionMap
this.withIdentities = old.withIdentities;
}

SecurityIdentity(final SecurityIdentity old, final Attributes runtimeAttributes) {
this.securityDomain = old.securityDomain;
this.principal = old.principal;
this.realmInfo = old.realmInfo;
this.authorizationIdentity = AuthorizationIdentity.basicIdentity(old.authorizationIdentity, runtimeAttributes);
this.defaultRoles = old.defaultRoles;
this.roleMappers = old.roleMappers;
this.creationTime = old.creationTime;
this.verifier = old.verifier;
this.publicCredentials = old.publicCredentials;
this.privateCredentials = old.privateCredentials;
this.withSuppliedIdentities = null;
this.withIdentities = old.withIdentities;
}

SecurityDomain getSecurityDomain() {
return securityDomain;
}
Expand Down Expand Up @@ -891,6 +906,17 @@ public SecurityIdentity withPrivateCredentials(final IdentityCredentials credent
return credentials == IdentityCredentials.NONE ? this : new SecurityIdentity(this, credentials, true);
}

/**
* Create a new security identity which is the same as this one, but which includes the given runtime attributes.
*
* @param runtimeAttributes the runtime attributes (must not be {@code null})
* @return the new identity
*/
public SecurityIdentity withRuntimeAttributes(final Attributes runtimeAttributes) {
Assert.checkNotNullParam("runtimeAttributes", runtimeAttributes);
return runtimeAttributes == Attributes.EMPTY ? this : new SecurityIdentity(this, runtimeAttributes);
}

/**
* Get the private credentials of this identity. The caller must have the {@code getPrivateCredentials} {@link ElytronPermission}.
*
Expand Down

0 comments on commit 052e015

Please sign in to comment.