diff --git a/services/policies/persistence/src/main/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/AbstractPolicyActionCommandStrategy.java b/services/policies/persistence/src/main/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/AbstractPolicyActionCommandStrategy.java index 8ff1e611f0..2a70b9b3a7 100644 --- a/services/policies/persistence/src/main/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/AbstractPolicyActionCommandStrategy.java +++ b/services/policies/persistence/src/main/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/AbstractPolicyActionCommandStrategy.java @@ -12,10 +12,16 @@ */ package org.eclipse.ditto.services.policies.persistence.actors.strategies.commands; +import org.eclipse.ditto.model.base.common.HttpStatusCode; +import org.eclipse.ditto.model.policies.EffectedPermissions; +import org.eclipse.ditto.model.policies.PoliciesResourceType; +import org.eclipse.ditto.model.policies.PolicyEntry; +import org.eclipse.ditto.services.models.policies.Permission; import org.eclipse.ditto.services.policies.common.config.PolicyConfig; import org.eclipse.ditto.services.policies.persistence.actors.resolvers.SubjectIdFromActionResolver; import org.eclipse.ditto.services.utils.akka.AkkaClassLoader; import org.eclipse.ditto.signals.commands.policies.actions.PolicyActionCommand; +import org.eclipse.ditto.signals.commands.policies.exceptions.PolicyActionFailedException; import akka.actor.ActorSystem; @@ -37,4 +43,29 @@ abstract class AbstractPolicyActionCommandStrategy { + final String resourceType = resource.getResourceKey().getResourceType(); + final EffectedPermissions permissions = resource.getEffectedPermissions(); + return PoliciesResourceType.THING.equals(resourceType) && + permissions.getGrantedPermissions().contains(Permission.READ) && + !permissions.getRevokedPermissions().contains(Permission.READ); + }); + } + + PolicyActionFailedException getExceptionForNoEntryWithThingReadPermission() { + return PolicyActionFailedException.newBuilderForActivateTokenIntegration() + .status(HttpStatusCode.NOT_FOUND) + .description("No policy entry found with READ permission for things.") + .build(); + } + } diff --git a/services/policies/persistence/src/main/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivatePolicyTokenIntegrationStrategy.java b/services/policies/persistence/src/main/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivatePolicyTokenIntegrationStrategy.java index 5290c1c8cc..b28d9d67a3 100644 --- a/services/policies/persistence/src/main/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivatePolicyTokenIntegrationStrategy.java +++ b/services/policies/persistence/src/main/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivatePolicyTokenIntegrationStrategy.java @@ -43,7 +43,6 @@ import org.eclipse.ditto.services.utils.persistentactors.results.ResultFactory; import org.eclipse.ditto.signals.commands.policies.actions.ActivatePolicyTokenIntegration; import org.eclipse.ditto.signals.commands.policies.actions.ActivatePolicyTokenIntegrationResponse; -import org.eclipse.ditto.signals.commands.policies.exceptions.PolicyActionFailedException; import org.eclipse.ditto.signals.events.policies.PolicyEvent; import org.eclipse.ditto.signals.events.policies.SubjectsModifiedPartially; @@ -74,11 +73,10 @@ protected Result> doApply(final Context context, .stream() .map(nonNullPolicy::getEntryFor) .flatMap(Optional::stream) + .filter(this::containsThingReadPermission) .collect(Collectors.toList()); - if (entries.isEmpty() || entries.size() != command.getLabels().size()) { - // Command is constructed incorrectly. This is a bug. - return ResultFactory.newErrorResult( - PolicyActionFailedException.newBuilderForActivateTokenIntegration().build(), command); + if (entries.isEmpty()) { + return ResultFactory.newErrorResult(getExceptionForNoEntryWithThingReadPermission(), command); } final PolicyBuilder policyBuilder = nonNullPolicy.toBuilder(); final Map activatedSubjects = new HashMap<>(); diff --git a/services/policies/persistence/src/main/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivateTokenIntegrationStrategy.java b/services/policies/persistence/src/main/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivateTokenIntegrationStrategy.java index fcb9930f5b..c1cf7cdd83 100644 --- a/services/policies/persistence/src/main/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivateTokenIntegrationStrategy.java +++ b/services/policies/persistence/src/main/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivateTokenIntegrationStrategy.java @@ -38,7 +38,6 @@ import org.eclipse.ditto.services.utils.persistentactors.results.ResultFactory; import org.eclipse.ditto.signals.commands.policies.actions.ActivateTokenIntegration; import org.eclipse.ditto.signals.commands.policies.actions.ActivateTokenIntegrationResponse; -import org.eclipse.ditto.signals.commands.policies.exceptions.PolicyEntryNotAccessibleException; import org.eclipse.ditto.signals.events.policies.PolicyEvent; import org.eclipse.ditto.signals.events.policies.SubjectCreated; import org.eclipse.ditto.signals.events.policies.SubjectModified; @@ -67,7 +66,8 @@ protected Result> doApply(final Context context, final SubjectExpiry commandSubjectExpiry = SubjectExpiry.newInstance(command.getExpiry()); final DittoHeaders dittoHeaders = command.getDittoHeaders(); - final Optional optionalEntry = nonNullPolicy.getEntryFor(label); + final Optional optionalEntry = nonNullPolicy.getEntryFor(label) + .filter(this::containsThingReadPermission); if (optionalEntry.isPresent()) { final PolicyEntry policyEntry = optionalEntry.get(); final SubjectId subjectId; @@ -99,7 +99,7 @@ protected Result> doApply(final Context context, final PolicyEvent event; if (policyEntry.getSubjects().getSubject(adjustedSubject.getId()).isPresent()) { event = SubjectModified.of(policyId, label, adjustedSubject, nextRevision, getEventTimestamp(), - dittoHeaders); + dittoHeaders); } else { event = SubjectCreated.of(policyId, label, adjustedSubject, nextRevision, getEventTimestamp(), dittoHeaders); @@ -114,15 +114,13 @@ protected Result> doApply(final Context context, command); } } else { - // Policy is configured incorrectly - return ResultFactory.newErrorResult( - PolicyEntryNotAccessibleException.newBuilder(policyId, label).dittoHeaders(dittoHeaders).build(), - command); + return ResultFactory.newErrorResult(getExceptionForNoEntryWithThingReadPermission(), command); } } @Override - public Optional previousEntityTag(final ActivateTokenIntegration command, @Nullable final Policy previousEntity) { + public Optional previousEntityTag(final ActivateTokenIntegration command, + @Nullable final Policy previousEntity) { // activated subjects do not support entity tag return Optional.empty(); } diff --git a/services/policies/persistence/src/test/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivatePolicyTokenIntegrationStrategyTest.java b/services/policies/persistence/src/test/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivatePolicyTokenIntegrationStrategyTest.java index 6b77141506..1f42429746 100644 --- a/services/policies/persistence/src/test/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivatePolicyTokenIntegrationStrategyTest.java +++ b/services/policies/persistence/src/test/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivatePolicyTokenIntegrationStrategyTest.java @@ -24,16 +24,18 @@ import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.placeholders.UnresolvedPlaceholderException; import org.eclipse.ditto.model.policies.Label; +import org.eclipse.ditto.model.policies.Policy; import org.eclipse.ditto.model.policies.PolicyId; +import org.eclipse.ditto.model.policies.ResourceKey; import org.eclipse.ditto.model.policies.SubjectId; import org.eclipse.ditto.model.policies.SubjectIdInvalidException; import org.eclipse.ditto.model.policies.SubjectIssuer; +import org.eclipse.ditto.services.models.policies.Permission; import org.eclipse.ditto.services.policies.common.config.DefaultPolicyConfig; import org.eclipse.ditto.services.policies.persistence.TestConstants; import org.eclipse.ditto.services.utils.persistentactors.commands.CommandStrategy; import org.eclipse.ditto.signals.commands.policies.actions.ActivatePolicyTokenIntegration; import org.eclipse.ditto.signals.commands.policies.actions.ActivatePolicyTokenIntegrationResponse; -import org.eclipse.ditto.signals.commands.policies.exceptions.PolicyActionFailedException; import org.eclipse.ditto.signals.events.policies.SubjectsModifiedPartially; import org.junit.Before; import org.junit.Test; @@ -130,7 +132,7 @@ public void rejectEmptyLabels() { final ActivatePolicyTokenIntegration command = ActivatePolicyTokenIntegration.of(context.getState(), subjectId, expiry, List.of(), dittoHeaders); assertErrorResult(underTest, TestConstants.Policy.POLICY, command, - PolicyActionFailedException.newBuilderForActivateTokenIntegration().build()); + underTest.getExceptionForNoEntryWithThingReadPermission()); } @Test @@ -141,8 +143,26 @@ public void rejectNonexistentLabel() { final SubjectId subjectId = SubjectId.newInstance("integration:this-is-me"); final DittoHeaders dittoHeaders = DittoHeaders.empty(); final ActivatePolicyTokenIntegration command = - ActivatePolicyTokenIntegration.of(context.getState(), subjectId, expiry, List.of(nonexistentLabel), dittoHeaders); + ActivatePolicyTokenIntegration.of(context.getState(), subjectId, expiry, List.of(nonexistentLabel), + dittoHeaders); assertErrorResult(underTest, TestConstants.Policy.POLICY, command, - PolicyActionFailedException.newBuilderForActivateTokenIntegration().build()); + underTest.getExceptionForNoEntryWithThingReadPermission()); + } + + @Test + public void rejectEntryWithoutThingReadPermission() { + final CommandStrategy.Context context = getDefaultContext(); + final Label label = Label.of("empty-entry"); + final Instant expiry = Instant.now().plus(Duration.ofDays(1L)); + final SubjectId subjectId = SubjectId.newInstance("integration:this-is-me"); + final DittoHeaders dittoHeaders = DittoHeaders.empty(); + final ActivatePolicyTokenIntegration command = + ActivatePolicyTokenIntegration.of(context.getState(), subjectId, expiry, List.of(label), dittoHeaders); + final Policy policy = TestConstants.Policy.POLICY.toBuilder() + .forLabel(label) + .setSubject(TestConstants.Policy.SUPPORT_SUBJECT) + .setGrantedPermissions(ResourceKey.newInstance("policy:/"), Permission.READ) + .build(); + assertErrorResult(underTest, policy, command, underTest.getExceptionForNoEntryWithThingReadPermission()); } } diff --git a/services/policies/persistence/src/test/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivateTokenIntegrationStrategyTest.java b/services/policies/persistence/src/test/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivateTokenIntegrationStrategyTest.java index a78bb95b62..15ee93ca26 100644 --- a/services/policies/persistence/src/test/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivateTokenIntegrationStrategyTest.java +++ b/services/policies/persistence/src/test/java/org/eclipse/ditto/services/policies/persistence/actors/strategies/commands/ActivateTokenIntegrationStrategyTest.java @@ -21,10 +21,14 @@ import org.eclipse.ditto.model.base.headers.DittoHeaders; import org.eclipse.ditto.model.placeholders.UnresolvedPlaceholderException; +import org.eclipse.ditto.model.policies.Label; +import org.eclipse.ditto.model.policies.Policy; import org.eclipse.ditto.model.policies.PolicyId; +import org.eclipse.ditto.model.policies.ResourceKey; import org.eclipse.ditto.model.policies.SubjectId; import org.eclipse.ditto.model.policies.SubjectIdInvalidException; import org.eclipse.ditto.model.policies.SubjectIssuer; +import org.eclipse.ditto.services.models.policies.Permission; import org.eclipse.ditto.services.policies.common.config.DefaultPolicyConfig; import org.eclipse.ditto.services.policies.persistence.TestConstants; import org.eclipse.ditto.services.utils.persistentactors.commands.CommandStrategy; @@ -107,4 +111,21 @@ public void activateTokenIntegrationWithUnsupportedPlaceholder() { assertErrorResult(underTest, TestConstants.Policy.POLICY, command, UnresolvedPlaceholderException.newBuilder("{{request:subjectId}}").build()); } + + @Test + public void rejectEntryWithoutThingReadPermission() { + final CommandStrategy.Context context = getDefaultContext(); + final Label label = Label.of("empty-entry"); + final Instant expiry = Instant.now().plus(Duration.ofDays(1L)); + final SubjectId subjectId = SubjectId.newInstance("integration:this-is-me"); + final DittoHeaders dittoHeaders = DittoHeaders.empty(); + final ActivateTokenIntegration command = + ActivateTokenIntegration.of(context.getState(), label, subjectId, expiry, dittoHeaders); + final Policy policy = TestConstants.Policy.POLICY.toBuilder() + .forLabel(label) + .setSubject(TestConstants.Policy.SUPPORT_SUBJECT) + .setGrantedPermissions(ResourceKey.newInstance("policy:/"), Permission.READ) + .build(); + assertErrorResult(underTest, policy, command, underTest.getExceptionForNoEntryWithThingReadPermission()); + } } diff --git a/services/policies/persistence/src/test/resources/test.conf b/services/policies/persistence/src/test/resources/test.conf index 06d14bbd44..1477e63c31 100755 --- a/services/policies/persistence/src/test/resources/test.conf +++ b/services/policies/persistence/src/test/resources/test.conf @@ -49,6 +49,16 @@ akka { } } +akka { + management.http.port = 0 + remote { + artery { + canonical.hostname = "127.0.0.1" + canonical.port = 0 + } + } +} + akka.contrib.persistence.mongodb.mongo { driver = "akka.contrib.persistence.mongodb.ScalaDriverPersistenceExtension" }