refactor(authorization): Add authorizedActor function to Authorizer interface (#4678)

This commit is contained in:
Dexter Lee 2022-04-15 10:24:59 -07:00 committed by GitHub
parent b9a0f3c60e
commit 0f669d5622
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 95 additions and 49 deletions

View File

@ -0,0 +1,17 @@
package com.datahub.authorization;
import com.linkedin.common.urn.Urn;
import java.util.List;
import lombok.Builder;
import lombok.Value;
@Value
@Builder
public class AuthorizedActors {
String privilege;
List<Urn> users;
List<Urn> groups;
boolean allUsers;
boolean allGroups;
}

View File

@ -1,6 +1,7 @@
package com.datahub.authorization;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Nonnull;
@ -20,4 +21,12 @@ public interface Authorizer {
* Authorizes an action based on the actor, the resource, & required privileges.
*/
AuthorizationResult authorize(AuthorizationRequest request);
/**
* Retrieves the current list of actors authorized to for a particular privilege against
* an optional resource
*/
AuthorizedActors authorizedActors(
final String privilege,
final Optional<ResourceSpec> resourceSpec);
}

View File

@ -1,12 +1,19 @@
package com.datahub.authorization;
import com.linkedin.common.urn.Urn;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.List;
import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
/**
* A configurable chain of {@link Authorizer}s executed in series to attempt to authenticate an inbound request.
*
@ -43,11 +50,11 @@ public class AuthorizerChain implements Authorizer {
// Authorization was successful - Short circuit
return result;
} else {
log.debug("Received DENY result from Authorizer with class name {}. message: {}", authorizer.getClass().getCanonicalName(), result.getMessage());
log.debug("Received DENY result from Authorizer with class name {}. message: {}",
authorizer.getClass().getCanonicalName(), result.getMessage());
}
} catch (Exception e) {
log.error(
"Caught exception while attempting to authorize request using Authorizer {}. Skipping authorizer.",
log.error("Caught exception while attempting to authorize request using Authorizer {}. Skipping authorizer.",
authorizer.getClass().getCanonicalName(), e);
}
}
@ -55,6 +62,59 @@ public class AuthorizerChain implements Authorizer {
return new AuthorizationResult(request, AuthorizationResult.Type.DENY, null);
}
@Override
public AuthorizedActors authorizedActors(String privilege, Optional<ResourceSpec> resourceSpec) {
if (this.authorizers.isEmpty()) {
return null;
}
AuthorizedActors finalAuthorizedActors = this.authorizers.get(0).authorizedActors(privilege, resourceSpec);
for (int i = 1; i < this.authorizers.size(); i++) {
finalAuthorizedActors = mergeAuthorizedActors(finalAuthorizedActors,
this.authorizers.get(i).authorizedActors(privilege, resourceSpec));
}
return finalAuthorizedActors;
}
private AuthorizedActors mergeAuthorizedActors(@Nullable AuthorizedActors original,
@Nullable AuthorizedActors other) {
if (original == null) {
return other;
}
if (other == null) {
return original;
}
boolean isAllUsers = original.isAllUsers() || other.isAllUsers();
List<Urn> mergedUsers;
if (isAllUsers) {
// If enabled for all users, no need to check users
mergedUsers = Collections.emptyList();
} else {
Set<Urn> users = new HashSet<>(original.getUsers());
users.addAll(other.getUsers());
mergedUsers = new ArrayList<>(users);
}
boolean isAllGroups = original.isAllGroups() || other.isAllGroups();
List<Urn> mergedGroups;
if (isAllGroups) {
// If enabled for all users, no need to check users
mergedGroups = Collections.emptyList();
} else {
Set<Urn> groups = new HashSet<>(original.getGroups());
groups.addAll(other.getGroups());
mergedGroups = new ArrayList<>(groups);
}
return AuthorizedActors.builder()
.allUsers(original.isAllUsers() || other.isAllUsers())
.allGroups(original.isAllGroups() || other.isAllGroups())
.users(mergedUsers)
.groups(mergedGroups)
.build();
}
/**
* Returns an instance of {@link DataHubAuthorizer} if it is present in the Authentication chain,
* or null if it cannot be found.

View File

@ -131,7 +131,7 @@ public class DataHubAuthorizer implements Authorizer {
*/
public AuthorizedActors authorizedActors(
final String privilege,
final Optional<ResourceSpec> resourceSpec) throws RuntimeException {
final Optional<ResourceSpec> resourceSpec) {
// Step 1: Find policies granting the privilege.
final List<DataHubPolicyInfo> policiesToEvaluate = _policyCache.getOrDefault(privilege, new ArrayList<>());
@ -309,44 +309,4 @@ public class DataHubAuthorizer implements Authorizer {
.map(Owner::getOwner)
.collect(Collectors.toList());
}
/**
* Class used to represent all users authorized to perform a particular privilege.
*/
public static class AuthorizedActors {
final String _privilege;
final List<Urn> _users;
final List<Urn> _groups;
final Boolean _allUsers;
final Boolean _allGroups;
public AuthorizedActors(final String privilege, final List<Urn> users, final List<Urn> groups, final Boolean allUsers, final Boolean allGroups) {
_privilege = privilege;
_users = users;
_groups = groups;
_allUsers = allUsers;
_allGroups = allGroups;
}
public String getPrivilege() {
return _privilege;
}
public List<Urn> getUsers() {
return _users;
}
public List<Urn> getGroups() {
return _groups;
}
public Boolean allUsers() {
return _allUsers;
}
public Boolean allGroups() {
return _allGroups;
}
}
}

View File

@ -209,12 +209,12 @@ public class DataHubAuthorizerTest {
@Test
public void testAuthorizedActorsActivePolicy() throws Exception {
final DataHubAuthorizer.AuthorizedActors actors =
final AuthorizedActors actors =
_dataHubAuthorizer.authorizedActors("EDIT_ENTITY_TAGS", // Should be inside the active policy.
Optional.of(new ResourceSpec("dataset", "urn:li:dataset:1")));
assertTrue(actors.allUsers());
assertTrue(actors.allGroups());
assertTrue(actors.isAllUsers());
assertTrue(actors.isAllGroups());
assertEquals(new HashSet<>(actors.getUsers()), ImmutableSet.of(
Urn.createFromString("urn:li:corpuser:user1"),