001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.isis.extensions.secman.api.permission; 020 021import java.io.Serializable; 022import java.util.Collection; 023import java.util.Collections; 024import java.util.List; 025 026import org.apache.isis.applib.annotation.Programmatic; 027import org.apache.isis.commons.internal.collections._Lists; 028import org.apache.isis.commons.internal.collections._Multimaps; 029import org.apache.isis.extensions.secman.api.IsisModuleExtSecmanApi; 030import org.apache.isis.core.metamodel.services.appfeat.ApplicationFeatureId; 031 032/** 033 * A serializable value object representing a set of (anonymized) 034 * {@link ApplicationPermissionValue permission}s. 035 * 036 * <p> 037 * Intended for value type arithmetic and also for caching. 038 * </p> 039 */ 040public class ApplicationPermissionValueSet implements Serializable { 041 042 private static final long serialVersionUID = 1L; 043 044 045 public static abstract class PropertyDomainEvent<T> extends IsisModuleExtSecmanApi.PropertyDomainEvent<ApplicationPermissionValueSet, T> {} 046 047 public static abstract class CollectionDomainEvent<T> extends IsisModuleExtSecmanApi.CollectionDomainEvent<ApplicationPermissionValueSet, T> {} 048 049 public static abstract class ActionDomainEvent extends IsisModuleExtSecmanApi.ActionDomainEvent<ApplicationPermissionValueSet> {} 050 051 052 053 // -- values 054 private final List<ApplicationPermissionValue> values; 055 /** 056 * Partitions the {@link ApplicationPermissionValue permissions} by feature and within that orders according to their 057 * evaluation precedence. 058 * 059 * <p> 060 * The following sketches out what is stored: 061 * </p> 062 * <pre> 063 * com.foo.Bar#bip -> ALLOW, CHANGING 064 * -> ALLOW, VIEWING 065 * -> VETO, VIEWING 066 * -> VETO, CHANGING 067 * com.foo.Bar -> ALLOW, CHANGING 068 * -> ALLOW, VIEWING 069 * -> VETO, VIEWING 070 * -> VETO, CHANGING 071 * com.foo -> ALLOW, CHANGING 072 * -> ALLOW, VIEWING 073 * -> VETO, VIEWING 074 * -> VETO, CHANGING 075 * com -> ALLOW, CHANGING 076 * -> ALLOW, VIEWING 077 * -> VETO, VIEWING 078 * -> VETO, CHANGING 079 * </pre> 080 * 081 * <p> 082 * Note that {@link org.apache.isis.extensions.security.manager.jdo.dom.permission.ApplicationPermissionRule#ALLOW allow} rule 083 * is ordered before {@link org.apache.isis.extensions.security.manager.jdo.dom.permission.ApplicationPermissionRule#VETO veto} rule 084 * meaning that it is checked first and therefore also takes precedence. 085 * </p> 086 */ 087 private final _Multimaps.SetMultimap<ApplicationFeatureId, ApplicationPermissionValue> permissionsByFeature = 088 _Multimaps.newSortedSetMultimap( 089 Collections.reverseOrder(ApplicationFeatureId.Comparators.natural()), 090 null // natural element order 091 ); 092 093 /** 094 * Note that we require PermissionsEvaluationService to be serializable. 095 */ 096 private PermissionsEvaluationService permissionsEvaluationService; 097 098 099 // -- constructor 100 101 public ApplicationPermissionValueSet( 102 final List<ApplicationPermissionValue> permissionValues, 103 final PermissionsEvaluationService permissionsEvaluationService) { 104 105 this.values = Collections.unmodifiableList(_Lists.newArrayList(permissionValues)); 106 for (final ApplicationPermissionValue permissionValue : permissionValues) { 107 final ApplicationFeatureId featureId = permissionValue.getFeatureId(); 108 permissionsByFeature.putElement(featureId, permissionValue); 109 } 110 this.permissionsEvaluationService = permissionsEvaluationService; 111 } 112 113 114 // -- grants, evaluate 115 116 public static class Evaluation { 117 private final ApplicationPermissionValue permissionValue; 118 private final boolean granted; 119 120 public Evaluation(final ApplicationPermissionValue permissionValue, final boolean granted) { 121 this.permissionValue = permissionValue; 122 this.granted = granted; 123 } 124 125 public ApplicationPermissionValue getCause() { 126 return permissionValue; 127 } 128 129 public boolean isGranted() { 130 return granted; 131 } 132 } 133 134 @Programmatic 135 public boolean grants(final ApplicationFeatureId featureId, final ApplicationPermissionMode mode) { 136 return evaluate(featureId, mode).isGranted(); 137 } 138 139 @Programmatic 140 public Evaluation evaluate( 141 final ApplicationFeatureId featureId, 142 final ApplicationPermissionMode mode) { 143 final List<ApplicationFeatureId> pathIds = featureId.getPathIds(); 144 for (final ApplicationFeatureId pathId : pathIds) { 145 final Collection<ApplicationPermissionValue> permissionValues = permissionsByFeature.get(pathId); 146 final Evaluation evaluation = permissionsEvaluationService.evaluate(featureId, mode, permissionValues); 147 if(evaluation != null) { 148 return evaluation; 149 } 150 } 151 return new Evaluation(null, false); 152 } 153 154 155 // -- equals, hashCode, toString 156 @Override 157 public boolean equals(final Object o) { 158 if (this == o) return true; 159 if (o == null || getClass() != o.getClass()) return false; 160 161 final ApplicationPermissionValueSet that = (ApplicationPermissionValueSet) o; 162 163 return !(values != null ? !values.equals(that.values) : that.values != null); 164 165 } 166 167 @Override 168 public int hashCode() { 169 return values != null ? values.hashCode() : 0; 170 } 171 172 173 @Override 174 public String toString() { 175 return "ApplicationPermissionValueSet{" + 176 "values=" + values + 177 '}'; 178 } 179 180 181 182 183}