Skip to content

Commit

Permalink
Merge pull request #513 from refinedmods/feat/GH-90/permission-checks
Browse files Browse the repository at this point in the history
Permission checks
  • Loading branch information
raoulvdberge authored Apr 4, 2024
2 parents 5334b8d + 147a90e commit 9bf2e5e
Show file tree
Hide file tree
Showing 112 changed files with 1,056 additions and 1,604 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ public interface SecurityDecisionProvider {
default SecurityDecision isAllowed(Permission permission) {
return SecurityDecision.PASS;
}

default boolean isActive() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,15 @@ public void onContainerRemoved(final NetworkNodeContainer container) {

@Override
public boolean isAllowed(final Permission permission, final SecurityActor actor) {
if (providers.isEmpty()) {
final Set<SecurityDecisionProvider> activeProviders = providers.stream()
.filter(SecurityDecisionProvider::isActive)
.collect(Collectors.toSet());
if (activeProviders.isEmpty()) {
return defaultPolicy.isAllowed(permission);
}
final Set<SecurityDecision> decisions = providers.stream().map(provider -> CoreValidations.validateNotNull(
provider.isAllowed(permission, actor),
"Decision cannot be null"
)).collect(Collectors.toSet());
final Set<SecurityDecision> decisions = activeProviders.stream().map(provider ->
CoreValidations.validateNotNull(provider.isAllowed(permission, actor), "Decision cannot be null")
).collect(Collectors.toSet());
final boolean anyDenied = decisions.stream().anyMatch(decision -> decision == SecurityDecision.DENY);
if (anyDenied) {
return false;
Expand All @@ -52,14 +54,13 @@ public boolean isAllowed(final Permission permission, final SecurityActor actor)
if (anyAllowed) {
return true;
}
return tryFallback(permission);
return tryFallback(permission, activeProviders);
}

private boolean tryFallback(final Permission permission) {
final Set<SecurityDecision> decisions = providers.stream().map(provider -> CoreValidations.validateNotNull(
provider.isAllowed(permission),
"Decision cannot be null"
)).collect(Collectors.toSet());
private boolean tryFallback(final Permission permission, final Set<SecurityDecisionProvider> activeProviders) {
final Set<SecurityDecision> decisions = activeProviders.stream().map(provider ->
CoreValidations.validateNotNull(provider.isAllowed(permission), "Decision cannot be null")
).collect(Collectors.toSet());
final boolean anyDenied = decisions.stream().anyMatch(decision -> decision == SecurityDecision.DENY);
if (anyDenied) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.refinedmods.refinedstorage2.api.network.impl.node.security.SecurityDecisionProviderProxyNetworkNode;
import com.refinedmods.refinedstorage2.api.network.security.Permission;
import com.refinedmods.refinedstorage2.api.network.security.SecurityActor;
import com.refinedmods.refinedstorage2.api.network.security.SecurityDecisionProvider;
import com.refinedmods.refinedstorage2.api.network.security.SecurityNetworkComponent;
import com.refinedmods.refinedstorage2.api.network.security.SecurityPolicy;

Expand All @@ -16,11 +17,13 @@
class SecurityNetworkComponentImplTest {
SecurityNetworkComponent sut;
SecurityDecisionProviderImpl securityDecisionProvider;
SecurityDecisionProviderProxyNetworkNode node;

@BeforeEach
void setUp() {
sut = new SecurityNetworkComponentImpl(policy(TestPermissions.ALLOW_BY_DEFAULT));
securityDecisionProvider = new SecurityDecisionProviderImpl();
node = createNode(securityDecisionProvider);
}

@Test
Expand All @@ -38,7 +41,7 @@ void shouldUseDefaultPolicyIfNoSecurityDecisionProvidersArePresent() {
@Test
void shouldDenyAllIfAtLeastOneSecurityDecisionProviderIsPresent() {
// Arrange
sut.onContainerAdded(() -> new SecurityDecisionProviderProxyNetworkNode(0, securityDecisionProvider));
sut.onContainerAdded(() -> node);

// Act & assert
assertThat(sut.isAllowed(TestPermissions.ALLOW_BY_DEFAULT, TestActors.A)).isFalse();
Expand All @@ -50,11 +53,27 @@ void shouldDenyAllIfAtLeastOneSecurityDecisionProviderIsPresent() {
assertThat(sut.isAllowed(TestPermissions.OTHER2, TestActors.B)).isFalse();
}

@Test
void shouldUseDefaultPolicyIfAllSecurityDecisionProvidersAreInactive() {
// Arrange
sut.onContainerAdded(() -> createNode(new SecurityDecisionProviderImpl()
.setDefaultPolicy(policy(TestPermissions.OTHER)), false));

// Act & assert
assertThat(sut.isAllowed(TestPermissions.ALLOW_BY_DEFAULT, TestActors.A)).isTrue();
assertThat(sut.isAllowed(TestPermissions.OTHER, TestActors.A)).isFalse();
assertThat(sut.isAllowed(TestPermissions.OTHER2, TestActors.A)).isFalse();

assertThat(sut.isAllowed(TestPermissions.ALLOW_BY_DEFAULT, TestActors.B)).isTrue();
assertThat(sut.isAllowed(TestPermissions.OTHER, TestActors.B)).isFalse();
assertThat(sut.isAllowed(TestPermissions.OTHER2, TestActors.B)).isFalse();
}

@Test
void shouldAllowOrDeny() {
// Arrange
securityDecisionProvider.setPolicy(TestActors.A, policy(TestPermissions.OTHER));
sut.onContainerAdded(() -> new SecurityDecisionProviderProxyNetworkNode(0, securityDecisionProvider));
sut.onContainerAdded(() -> node);

// Act & assert
assertThat(sut.isAllowed(TestPermissions.ALLOW_BY_DEFAULT, TestActors.A)).isFalse();
Expand All @@ -69,18 +88,22 @@ void shouldAllowOrDeny() {
@Test
void shouldOnlyAllowIfAllSecurityDecisionProvidersAllow() {
// Arrange
sut.onContainerAdded(() -> new SecurityDecisionProviderProxyNetworkNode(0, new SecurityDecisionProviderImpl()
sut.onContainerAdded(() -> createNode(new SecurityDecisionProviderImpl()
.setPolicy(TestActors.A, policy(TestPermissions.OTHER))
));

sut.onContainerAdded(() -> new SecurityDecisionProviderProxyNetworkNode(0, new SecurityDecisionProviderImpl()
sut.onContainerAdded(() -> createNode(new SecurityDecisionProviderImpl()
.setPolicy(TestActors.A, policy(TestPermissions.OTHER2))
));

sut.onContainerAdded(() -> new SecurityDecisionProviderProxyNetworkNode(0, new SecurityDecisionProviderImpl()
sut.onContainerAdded(() -> createNode(new SecurityDecisionProviderImpl()
.setPolicy(TestActors.B, policy(TestPermissions.OTHER))
));

sut.onContainerAdded(() -> createNode(new SecurityDecisionProviderImpl()
.setPolicy(TestActors.A, policy(TestPermissions.ALLOW_BY_DEFAULT))
.setDefaultPolicy(policy(TestPermissions.OTHER, TestPermissions.OTHER2)), false));

// Act & assert
assertThat(sut.isAllowed(TestPermissions.OTHER, TestActors.A)).isFalse();
assertThat(sut.isAllowed(TestPermissions.OTHER2, TestActors.A)).isFalse();
Expand All @@ -95,17 +118,17 @@ void shouldOnlyAllowIfAllSecurityDecisionProvidersAllow() {
@Test
void shouldUseDefaultPolicyOfSecurityDecisionProviderIfAllProvidersPassDecision() {
// Arrange
sut.onContainerAdded(() -> new SecurityDecisionProviderProxyNetworkNode(0, new SecurityDecisionProviderImpl()
sut.onContainerAdded(() -> createNode(new SecurityDecisionProviderImpl()
.setPolicy(TestActors.A, policy(TestPermissions.OTHER))
.setDefaultPolicy(policy(TestPermissions.ALLOW_BY_DEFAULT))
));

sut.onContainerAdded(() -> new SecurityDecisionProviderProxyNetworkNode(0, new SecurityDecisionProviderImpl()
sut.onContainerAdded(() -> createNode(new SecurityDecisionProviderImpl()
.setPolicy(TestActors.A, policy(TestPermissions.OTHER))
.setDefaultPolicy(policy(TestPermissions.ALLOW_BY_DEFAULT, TestPermissions.OTHER2))
));

sut.onContainerAdded(() -> new SecurityDecisionProviderProxyNetworkNode(0, new SecurityDecisionProviderImpl()
sut.onContainerAdded(() -> createNode(new SecurityDecisionProviderImpl()
.setPolicy(TestActors.C, policy(TestPermissions.OTHER))
));

Expand All @@ -126,11 +149,11 @@ void shouldUseDefaultPolicyOfSecurityDecisionProviderIfAllProvidersPassDecision(
@Test
void shouldRemoveContainer() {
// Arrange
sut.onContainerAdded(() -> new SecurityDecisionProviderProxyNetworkNode(0, new SecurityDecisionProviderImpl()
sut.onContainerAdded(() -> createNode(new SecurityDecisionProviderImpl()
.setDefaultPolicy(policy(TestPermissions.ALLOW_BY_DEFAULT))
));

final var removedNode = new SecurityDecisionProviderProxyNetworkNode(0, new SecurityDecisionProviderImpl()
final var removedNode = createNode(new SecurityDecisionProviderImpl()
.setDefaultPolicy(policy(TestPermissions.OTHER)));
sut.onContainerAdded(() -> removedNode);

Expand All @@ -144,7 +167,7 @@ void shouldRemoveContainer() {
@Test
void shouldClearPolicies() {
// Arrange
sut.onContainerAdded(() -> new SecurityDecisionProviderProxyNetworkNode(0, securityDecisionProvider));
sut.onContainerAdded(() -> node);
securityDecisionProvider.setPolicy(TestActors.A, policy(TestPermissions.OTHER));
securityDecisionProvider.setDefaultPolicy(policy(TestPermissions.OTHER2));

Expand All @@ -156,6 +179,17 @@ void shouldClearPolicies() {
assertThat(sut.isAllowed(TestPermissions.OTHER2, TestActors.A)).isTrue();
}

private static SecurityDecisionProviderProxyNetworkNode createNode(final SecurityDecisionProvider provider) {
return createNode(provider, true);
}

private static SecurityDecisionProviderProxyNetworkNode createNode(final SecurityDecisionProvider provider,
final boolean active) {
final var node = new SecurityDecisionProviderProxyNetworkNode(0, provider);
node.setActive(active);
return node;
}

enum TestPermissions implements Permission {
ALLOW_BY_DEFAULT, OTHER, OTHER2
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.refinedmods.refinedstorage2.api.network.Network;
import com.refinedmods.refinedstorage2.api.network.NetworkComponent;
import com.refinedmods.refinedstorage2.api.network.energy.EnergyStorage;
import com.refinedmods.refinedstorage2.api.network.security.SecurityActor;
import com.refinedmods.refinedstorage2.api.network.security.SecurityPolicy;
import com.refinedmods.refinedstorage2.api.resource.ResourceKey;
import com.refinedmods.refinedstorage2.platform.api.constructordestructor.ConstructorStrategyFactory;
Expand Down Expand Up @@ -48,7 +47,9 @@
import java.util.Optional;
import java.util.Set;

import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
Expand All @@ -57,6 +58,7 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import org.apiguardian.api.API;

@API(status = API.Status.STABLE, since = "2.0.0-milestone.1.0")
Expand Down Expand Up @@ -112,7 +114,7 @@ public interface PlatformApi {
void requestNetworkNodeUpdate(PlatformNetworkNodeContainer container, Level level);

GridInsertionStrategy createGridInsertionStrategy(AbstractContainerMenu containerMenu,
Player player,
ServerPlayer player,
Grid grid);

void addGridInsertionStrategyFactory(GridInsertionStrategyFactory insertionStrategyFactory);
Expand All @@ -122,13 +124,13 @@ GridInsertionStrategy createGridInsertionStrategy(AbstractContainerMenu containe
GridInsertionHints getGridInsertionHints();

GridExtractionStrategy createGridExtractionStrategy(AbstractContainerMenu containerMenu,
Player player,
ServerPlayer player,
Grid grid);

void addGridExtractionStrategyFactory(GridExtractionStrategyFactory extractionStrategyFactory);

GridScrollingStrategy createGridScrollingStrategy(AbstractContainerMenu containerMenu,
Player player,
ServerPlayer player,
Grid grid);

void addGridScrollingStrategyFactory(GridScrollingStrategyFactory scrollingStrategyFactory);
Expand Down Expand Up @@ -189,5 +191,9 @@ EnergyStorage asBlockItemEnergyStorage(

SecurityPolicy createDefaultSecurityPolicy();

SecurityActor createPlayerSecurityActor(ServerPlayer player);
void sendNoPermissionToOpenMessage(ServerPlayer player, Component target);

void sendNoPermissionMessage(ServerPlayer player, Component message);

boolean canPlaceNetworkNode(ServerPlayer player, Level level, BlockPos pos, BlockState state);
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.refinedmods.refinedstorage2.api.network.Network;
import com.refinedmods.refinedstorage2.api.network.NetworkComponent;
import com.refinedmods.refinedstorage2.api.network.energy.EnergyStorage;
import com.refinedmods.refinedstorage2.api.network.security.SecurityActor;
import com.refinedmods.refinedstorage2.api.network.security.SecurityPolicy;
import com.refinedmods.refinedstorage2.api.resource.ResourceKey;
import com.refinedmods.refinedstorage2.platform.api.constructordestructor.ConstructorStrategyFactory;
Expand Down Expand Up @@ -49,7 +48,9 @@
import java.util.Set;
import javax.annotation.Nullable;

import net.minecraft.core.BlockPos;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.player.Player;
Expand All @@ -58,6 +59,7 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;

public class PlatformApiProxy implements PlatformApi {
@Nullable
Expand Down Expand Up @@ -194,7 +196,7 @@ public void requestNetworkNodeUpdate(final PlatformNetworkNodeContainer containe

@Override
public GridInsertionStrategy createGridInsertionStrategy(final AbstractContainerMenu containerMenu,
final Player player,
final ServerPlayer player,
final Grid grid) {
return ensureLoaded().createGridInsertionStrategy(containerMenu, player, grid);
}
Expand All @@ -216,7 +218,7 @@ public GridInsertionHints getGridInsertionHints() {

@Override
public GridExtractionStrategy createGridExtractionStrategy(final AbstractContainerMenu containerMenu,
final Player player,
final ServerPlayer player,
final Grid grid) {
return ensureLoaded().createGridExtractionStrategy(containerMenu, player, grid);
}
Expand All @@ -228,7 +230,7 @@ public void addGridExtractionStrategyFactory(final GridExtractionStrategyFactory

@Override
public GridScrollingStrategy createGridScrollingStrategy(final AbstractContainerMenu containerMenu,
final Player player,
final ServerPlayer player,
final Grid grid) {
return ensureLoaded().createGridScrollingStrategy(containerMenu, player, grid);
}
Expand Down Expand Up @@ -372,8 +374,21 @@ public SecurityPolicy createDefaultSecurityPolicy() {
}

@Override
public SecurityActor createPlayerSecurityActor(final ServerPlayer player) {
return ensureLoaded().createPlayerSecurityActor(player);
public void sendNoPermissionToOpenMessage(final ServerPlayer player, final Component target) {
ensureLoaded().sendNoPermissionToOpenMessage(player, target);
}

@Override
public void sendNoPermissionMessage(final ServerPlayer player, final Component message) {
ensureLoaded().sendNoPermissionMessage(player, message);
}

@Override
public boolean canPlaceNetworkNode(final ServerPlayer player,
final Level level,
final BlockPos pos,
final BlockState state) {
return ensureLoaded().canPlaceNetworkNode(player, level, pos, state);
}

private PlatformApi ensureLoaded() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import java.util.List;

import net.minecraft.server.level.ServerPlayer;
import org.apiguardian.api.API;

@API(status = API.Status.STABLE, since = "2.0.0-milestone.3.0")
Expand All @@ -23,5 +24,5 @@ public interface Grid {

List<TrackedResourceAmount> getResources(Class<? extends Actor> actorType);

GridOperations createOperations(ResourceType resourceType, Actor actor);
GridOperations createOperations(ResourceType resourceType, ServerPlayer player);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import com.refinedmods.refinedstorage2.platform.api.grid.Grid;

import net.minecraft.world.entity.player.Player;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.AbstractContainerMenu;
import org.apiguardian.api.API;

@API(status = API.Status.STABLE, since = "2.0.0-milestone.2.6")
@FunctionalInterface
public interface GridExtractionStrategyFactory {
GridExtractionStrategy create(AbstractContainerMenu containerMenu, Player player, Grid grid);
GridExtractionStrategy create(AbstractContainerMenu containerMenu, ServerPlayer player, Grid grid);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import com.refinedmods.refinedstorage2.platform.api.grid.Grid;

import net.minecraft.world.entity.player.Player;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.AbstractContainerMenu;
import org.apiguardian.api.API;

@API(status = API.Status.STABLE, since = "2.0.0-milestone.2.6")
@FunctionalInterface
public interface GridInsertionStrategyFactory {
GridInsertionStrategy create(AbstractContainerMenu containerMenu, Player player, Grid grid);
GridInsertionStrategy create(AbstractContainerMenu containerMenu, ServerPlayer player, Grid grid);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

import com.refinedmods.refinedstorage2.platform.api.grid.Grid;

import net.minecraft.world.entity.player.Player;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.AbstractContainerMenu;
import org.apiguardian.api.API;

@API(status = API.Status.STABLE, since = "2.0.0-milestone.2.6")
@FunctionalInterface
public interface GridScrollingStrategyFactory {
GridScrollingStrategy create(AbstractContainerMenu containerMenu, Player player, Grid grid);
GridScrollingStrategy create(AbstractContainerMenu containerMenu, ServerPlayer player, Grid grid);
}
Loading

0 comments on commit 9bf2e5e

Please sign in to comment.