Skip to content

Commit

Permalink
Merge pull request #511 from refinedmods/feat/GH-90/security-manager
Browse files Browse the repository at this point in the history
Security Manager
  • Loading branch information
raoulvdberge authored Apr 3, 2024
2 parents 8ce67c7 + 31566d3 commit 5334b8d
Show file tree
Hide file tree
Showing 647 changed files with 5,742 additions and 1,210 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

- Security Card
- Fallback Security Card
- Security Manager

### Changed

- The permissions for a Security Card must be configured through the card itself, instead of via the Security Manager.
- The Security Card can be bound to other (currently online) players via its GUI.
- The binding of a Security Card can now be cleared.
- The Security Card tooltip and GUI now show whether the permission has been touched/changed in any way.
- A global (fallback) permission set for a network can be defined using the Fallback Security Card instead of using an "unbound" Security Card.
- As soon as a Security Manager is placed, the storage network will be locked down by default. Start adding Security Cards to allow or deny specific access to players.
- To not lock the entire network by default for players who do not have a matching Security Card, a Fallback Security Card can be used to configure this behavior.
- Smooth scrolling, screen size and max row stretch are no longer Grid-specific settings, but are now global settings.

### Fixed
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,6 @@ enableSonarQube("refinedmods_refinedstorage2")
sonarqube {
properties {
property "sonar.coverage.exclusions", "refinedstorage2-platform-forge/**/*,refinedstorage2-platform-fabric/**/*,refinedstorage2-platform-common/**/*,refinedstorage2-platform-api/**/*"
property "sonar.cpd.exclusions", "refinedstorage2-platform-forge/src/main/java/com/refinedmods/refinedstorage2/platform/forge/integration/recipemod/rei/*,refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/integration/recipemod/rei/*"
property "sonar.cpd.exclusions", "refinedstorage2-platform-forge/src/main/java/com/refinedmods/refinedstorage2/platform/forge/recipemod/rei/*,refinedstorage2-platform-fabric/src/main/java/com/refinedmods/refinedstorage2/platform/fabric/recipemod/rei/*"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@
@FunctionalInterface
public interface SecurityDecisionProvider {
SecurityDecision isAllowed(Permission permission, SecurityActor actor);

default SecurityDecision isAllowed(Permission permission) {
return SecurityDecision.PASS;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.refinedmods.refinedstorage2.api.network.security;

import java.util.Collections;
import java.util.Set;

import org.apiguardian.api.API;

@API(status = API.Status.STABLE, since = "2.0.0-milestone.3.5")
public record SecurityPolicy(Set<Permission> allowedPermissions) {
public static final SecurityPolicy EMPTY = new SecurityPolicy(Collections.emptySet());

public boolean isAllowed(final Permission permission) {
return allowedPermissions.contains(permission);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.refinedmods.refinedstorage2.api.network.impl.node.security;

import com.refinedmods.refinedstorage2.api.network.impl.storage.AbstractNetworkNode;
import com.refinedmods.refinedstorage2.api.network.security.Permission;
import com.refinedmods.refinedstorage2.api.network.security.SecurityActor;
import com.refinedmods.refinedstorage2.api.network.security.SecurityDecision;
import com.refinedmods.refinedstorage2.api.network.security.SecurityDecisionProvider;

import javax.annotation.Nullable;

public class SecurityDecisionProviderProxyNetworkNode extends AbstractNetworkNode implements SecurityDecisionProvider {
private long energyUsage;
@Nullable
private SecurityDecisionProvider delegate;

public SecurityDecisionProviderProxyNetworkNode(final long energyUsage) {
this.energyUsage = energyUsage;
}

public SecurityDecisionProviderProxyNetworkNode(final long energyUsage, final SecurityDecisionProvider delegate) {
this(energyUsage);
this.delegate = delegate;
}

public void setDelegate(@Nullable final SecurityDecisionProvider delegate) {
this.delegate = delegate;
}

public void setEnergyUsage(final long energyUsage) {
this.energyUsage = energyUsage;
}

@Override
public long getEnergyUsage() {
return energyUsage;
}

@Override
public SecurityDecision isAllowed(final Permission permission, final SecurityActor actor) {
if (delegate == null) {
return SecurityDecision.PASS;
}
return delegate.isAllowed(permission, actor);
}

@Override
public SecurityDecision isAllowed(final Permission permission) {
if (delegate == null) {
return SecurityDecision.PASS;
}
return delegate.isAllowed(permission);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@ParametersAreNonnullByDefault
@FieldsAndMethodsAreNonnullByDefault
package com.refinedmods.refinedstorage2.api.network.impl.node.security;

import com.refinedmods.refinedstorage2.api.core.FieldsAndMethodsAreNonnullByDefault;

import javax.annotation.ParametersAreNonnullByDefault;
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.refinedmods.refinedstorage2.api.network.impl.security;

import com.refinedmods.refinedstorage2.api.network.security.Permission;
import com.refinedmods.refinedstorage2.api.network.security.SecurityActor;
import com.refinedmods.refinedstorage2.api.network.security.SecurityDecision;
import com.refinedmods.refinedstorage2.api.network.security.SecurityDecisionProvider;
import com.refinedmods.refinedstorage2.api.network.security.SecurityPolicy;

import java.util.HashMap;
import java.util.Map;
import javax.annotation.Nullable;

public class SecurityDecisionProviderImpl implements SecurityDecisionProvider {
private final Map<SecurityActor, SecurityPolicy> policyByActor = new HashMap<>();
@Nullable
private SecurityPolicy defaultPolicy;

public SecurityDecisionProviderImpl setPolicy(final SecurityActor actor, final SecurityPolicy policy) {
policyByActor.put(actor, policy);
return this;
}

public SecurityDecisionProviderImpl setDefaultPolicy(@Nullable final SecurityPolicy policy) {
this.defaultPolicy = policy;
return this;
}

public void clearPolicies() {
policyByActor.clear();
}

@Override
public SecurityDecision isAllowed(final Permission permission, final SecurityActor actor) {
final SecurityPolicy policy = policyByActor.get(actor);
if (policy == null) {
return SecurityDecision.PASS;
}
return allowOrDeny(policy.isAllowed(permission));
}

@Override
public SecurityDecision isAllowed(final Permission permission) {
if (defaultPolicy == null) {
return SecurityDecision.PASS;
}
return allowOrDeny(defaultPolicy.isAllowed(permission));
}

private static SecurityDecision allowOrDeny(final boolean allowed) {
return allowed ? SecurityDecision.ALLOW : SecurityDecision.DENY;
}
}
Original file line number Diff line number Diff line change
@@ -1,42 +1,69 @@
package com.refinedmods.refinedstorage2.api.network.impl.security;

import com.refinedmods.refinedstorage2.api.core.CoreValidations;
import com.refinedmods.refinedstorage2.api.network.node.container.NetworkNodeContainer;
import com.refinedmods.refinedstorage2.api.network.security.Permission;
import com.refinedmods.refinedstorage2.api.network.security.SecurityActor;
import com.refinedmods.refinedstorage2.api.network.security.SecurityDecision;
import com.refinedmods.refinedstorage2.api.network.security.SecurityDecisionProvider;
import com.refinedmods.refinedstorage2.api.network.security.SecurityNetworkComponent;
import com.refinedmods.refinedstorage2.api.network.security.SecurityPolicy;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;

public class SecurityNetworkComponentImpl implements SecurityNetworkComponent {
private final Set<SecurityDecisionProvider> providers = new HashSet<>();
private final Set<SecurityDecisionProvider> providers = new LinkedHashSet<>();
private final SecurityPolicy defaultPolicy;

public SecurityNetworkComponentImpl(final SecurityPolicy defaultPolicy) {
this.defaultPolicy = defaultPolicy;
}

@Override
public void onContainerAdded(final NetworkNodeContainer container) {
if (container instanceof SecurityDecisionProvider provider) {
if (container.getNode() instanceof SecurityDecisionProvider provider) {
providers.add(provider);
}
}

@Override
public void onContainerRemoved(final NetworkNodeContainer container) {
if (container instanceof SecurityDecisionProvider provider) {
if (container.getNode() instanceof SecurityDecisionProvider provider) {
providers.remove(provider);
}
}

@Override
public boolean isAllowed(final Permission permission, final SecurityActor actor) {
for (final SecurityDecisionProvider provider : providers) {
final SecurityDecision decision = provider.isAllowed(permission, actor);
if (decision == SecurityDecision.DENY) {
return false;
} else if (decision == SecurityDecision.ALLOW) {
return true;
}
if (providers.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 boolean anyDenied = decisions.stream().anyMatch(decision -> decision == SecurityDecision.DENY);
if (anyDenied) {
return false;
}
final boolean anyAllowed = decisions.stream().anyMatch(decision -> decision == SecurityDecision.ALLOW);
if (anyAllowed) {
return true;
}
return tryFallback(permission);
}

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());
final boolean anyDenied = decisions.stream().anyMatch(decision -> decision == SecurityDecision.DENY);
if (anyDenied) {
return false;
}
return true;
return decisions.stream().anyMatch(decision -> decision == SecurityDecision.ALLOW);
}
}
Loading

0 comments on commit 5334b8d

Please sign in to comment.