This is an automated email from the ASF dual-hosted git repository. ahuber pushed a commit to branch 3358-allow_safe_act_w_view_perm in repository https://gitbox.apache.org/repos/asf/causeway.git
commit 18ff04ca21f2d9312ef5bdabfa3aad0445a9ae84 Author: andi-huber <[email protected]> AuthorDate: Fri Feb 10 10:38:01 2023 +0100 CAUSEWAY-3358: modifies AuthorizationManager to consider action semantics --- .../core/config/CausewayConfiguration.java | 10 ++++-- .../specloader/SpecificationLoaderDefault.java | 20 +++++++++++- core/security/src/main/java/module-info.java | 1 + .../manager/ActionSemanticsResolver.java | 37 ++++++++++++++++++++++ .../manager/AuthorizationManager.java | 21 ++++++++++++ 5 files changed, 86 insertions(+), 3 deletions(-) diff --git a/core/config/src/main/java/org/apache/causeway/core/config/CausewayConfiguration.java b/core/config/src/main/java/org/apache/causeway/core/config/CausewayConfiguration.java index 20c2ea7efe..bd85548840 100644 --- a/core/config/src/main/java/org/apache/causeway/core/config/CausewayConfiguration.java +++ b/core/config/src/main/java/org/apache/causeway/core/config/CausewayConfiguration.java @@ -74,8 +74,6 @@ import org.apache.causeway.applib.services.userui.UserMenu; import org.apache.causeway.applib.value.semantics.TemporalValueSemantics.TemporalEditingPattern; import org.apache.causeway.commons.internal.base._NullSafe; import org.apache.causeway.commons.internal.context._Context; -import org.apache.causeway.core.config.CausewayConfiguration.Core; -import org.apache.causeway.core.config.CausewayConfiguration.Viewer; import org.apache.causeway.core.config.metamodel.facets.ActionConfigOptions; import org.apache.causeway.core.config.metamodel.facets.CollectionLayoutConfigOptions; import org.apache.causeway.core.config.metamodel.facets.DomainObjectConfigOptions; @@ -115,6 +113,14 @@ public class CausewayConfiguration { private final Security security = new Security(); @Data public static class Security { + + /** + * If set, allows <i>Actions</i> with SAFE Semantics to be invoked with only VIEWING permissions. + * <p> + * default: false + */ + private boolean allowActionsWithSafeSemanticsToBeInvokedWithOnlyViewingPermission = false; + private final Shiro shiro = new Shiro(); @Data public static class Shiro { diff --git a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/SpecificationLoaderDefault.java b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/SpecificationLoaderDefault.java index c45b6c46b9..2fb788992f 100644 --- a/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/SpecificationLoaderDefault.java +++ b/core/metamodel/src/main/java/org/apache/causeway/core/metamodel/specloader/SpecificationLoaderDefault.java @@ -40,7 +40,9 @@ import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.lang.Nullable; import org.springframework.stereotype.Service; +import org.apache.causeway.applib.Identifier; import org.apache.causeway.applib.annotation.PriorityPrecedence; +import org.apache.causeway.applib.annotation.SemanticsOf; import org.apache.causeway.applib.id.LogicalType; import org.apache.causeway.applib.services.menu.MenuBarsService; import org.apache.causeway.applib.services.metamodel.BeanSort; @@ -73,6 +75,7 @@ import org.apache.causeway.core.metamodel.services.classsubstitutor.ClassSubstit import org.apache.causeway.core.metamodel.services.classsubstitutor.ClassSubstitutor.Substitution; import org.apache.causeway.core.metamodel.services.classsubstitutor.ClassSubstitutorRegistry; import org.apache.causeway.core.metamodel.spec.ObjectSpecification; +import org.apache.causeway.core.metamodel.spec.feature.ObjectAction; import org.apache.causeway.core.metamodel.specloader.facetprocessor.FacetProcessor; import org.apache.causeway.core.metamodel.specloader.postprocessor.PostProcessor; import org.apache.causeway.core.metamodel.specloader.specimpl.IntrospectionState; @@ -81,6 +84,7 @@ import org.apache.causeway.core.metamodel.specloader.validator.MetaModelValidato import org.apache.causeway.core.metamodel.specloader.validator.ValidationFailure; import org.apache.causeway.core.metamodel.specloader.validator.ValidationFailures; import org.apache.causeway.core.metamodel.valuetypes.ValueSemanticsResolverDefault; +import org.apache.causeway.core.security.authorization.manager.ActionSemanticsResolver; import lombok.Getter; import lombok.NonNull; @@ -107,7 +111,10 @@ import lombok.extern.log4j.Log4j2; @Priority(PriorityPrecedence.EARLY) @Qualifier("Default") @Log4j2 -public class SpecificationLoaderDefault implements SpecificationLoader { +public class SpecificationLoaderDefault +implements + SpecificationLoader, + ActionSemanticsResolver { private final CausewayConfiguration causewayConfiguration; private final CausewaySystemEnvironment causewaySystemEnvironment; @@ -532,6 +539,17 @@ public class SpecificationLoaderDefault implements SpecificationLoader { return validationFailures; } + // -- ACTION SEMANTICS RESOLVER + + @Override + public Optional<SemanticsOf> getActionSemanticsOf(final Identifier identifier) { + if(!identifier.getType().isAction()) { + return Optional.empty(); + } + return specForLogicalType(identifier.getLogicalType()) + .flatMap(objSpec->objSpec.getAction(identifier.getMemberLogicalName())) + .map(ObjectAction::getSemantics); + } // -- HELPER diff --git a/core/security/src/main/java/module-info.java b/core/security/src/main/java/module-info.java index 41e034b5bc..8a2e34aaa7 100644 --- a/core/security/src/main/java/module-info.java +++ b/core/security/src/main/java/module-info.java @@ -42,4 +42,5 @@ module org.apache.causeway.security.api { requires spring.context; requires spring.core; requires spring.tx; + requires org.apache.causeway.core.config; } \ No newline at end of file diff --git a/core/security/src/main/java/org/apache/causeway/core/security/authorization/manager/ActionSemanticsResolver.java b/core/security/src/main/java/org/apache/causeway/core/security/authorization/manager/ActionSemanticsResolver.java new file mode 100644 index 0000000000..4a15c1d37e --- /dev/null +++ b/core/security/src/main/java/org/apache/causeway/core/security/authorization/manager/ActionSemanticsResolver.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.causeway.core.security.authorization.manager; + +import java.util.Optional; + +import org.apache.causeway.applib.Identifier; +import org.apache.causeway.applib.annotation.SemanticsOf; + +/** + * Internal service, to resolve <i>Action's</i> {@link SemanticsOf} given their {@link Identifier}. + */ +public interface ActionSemanticsResolver { + + /** + * Optionally the {@link SemanticsOf} of the <i>Action</i> represented by {@link Identifier}, + * based on whether the identifier represents an <i>Action</i>. + */ + Optional<SemanticsOf> getActionSemanticsOf(Identifier identifier); + +} diff --git a/core/security/src/main/java/org/apache/causeway/core/security/authorization/manager/AuthorizationManager.java b/core/security/src/main/java/org/apache/causeway/core/security/authorization/manager/AuthorizationManager.java index cbf04f1b89..f5a8f69955 100644 --- a/core/security/src/main/java/org/apache/causeway/core/security/authorization/manager/AuthorizationManager.java +++ b/core/security/src/main/java/org/apache/causeway/core/security/authorization/manager/AuthorizationManager.java @@ -31,10 +31,12 @@ import org.springframework.stereotype.Service; import org.apache.causeway.applib.Identifier; import org.apache.causeway.applib.annotation.PriorityPrecedence; +import org.apache.causeway.applib.annotation.SemanticsOf; import org.apache.causeway.applib.services.iactnlayer.InteractionContext; import org.apache.causeway.applib.services.sudo.SudoService; import org.apache.causeway.commons.internal.assertions._Assert; import org.apache.causeway.commons.internal.base._NullSafe; +import org.apache.causeway.core.config.CausewayConfiguration; import org.apache.causeway.core.security.authorization.Authorizor; /** @@ -49,12 +51,20 @@ import org.apache.causeway.core.security.authorization.Authorizor; public class AuthorizationManager { private final Authorizor authorizor; + private final ActionSemanticsResolver actionSemanticsResolver; + private final boolean allowActionsWithSafeSemanticsToBeInvokedWithOnlyViewingPermission; @Inject public AuthorizationManager( + final CausewayConfiguration config, + final ActionSemanticsResolver actionSemanticsResolver, final List<Authorizor> authorizors, final Optional<AuthorizorChooser> authorizorChooserIfAny) { + this.allowActionsWithSafeSemanticsToBeInvokedWithOnlyViewingPermission = + config.getSecurity().isAllowActionsWithSafeSemanticsToBeInvokedWithOnlyViewingPermission(); + this.actionSemanticsResolver = actionSemanticsResolver; + _Assert.assertTrue(_NullSafe.size(authorizors)>0, ()-> String.format( "At least one %s is required to be registered for injection.", @@ -86,6 +96,11 @@ public class AuthorizationManager { if (authorizor.isUsable(authentication, identifier)) { return true; } + if (allowActionsWithSafeSemanticsToBeInvokedWithOnlyViewingPermission + && isActionWithSafeSemantics(identifier) + && this.isVisible(authentication, identifier)) { + return true; + } return false; } @@ -130,4 +145,10 @@ public class AuthorizationManager { return (identifier.getClassName().equals("")); } + private boolean isActionWithSafeSemantics(final Identifier identifier) { + return actionSemanticsResolver.getActionSemanticsOf(identifier) + .map(SemanticsOf::isSafeInNature) + .orElse(false); + } + }
