001/* 002 * Copyright 2020 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.plugins.workspaces.project.rights.accesscontroller; 017 018import java.util.Map; 019import java.util.Set; 020import java.util.regex.Matcher; 021import java.util.regex.Pattern; 022 023import org.apache.avalon.framework.service.ServiceException; 024import org.apache.avalon.framework.service.ServiceManager; 025import org.apache.avalon.framework.service.Serviceable; 026 027import org.ametys.core.group.GroupIdentity; 028import org.ametys.core.right.AccessController; 029import org.ametys.core.right.ProfileAssignmentStorageExtensionPoint; 030import org.ametys.core.right.RightManager.RightResult; 031import org.ametys.core.user.UserIdentity; 032import org.ametys.plugins.explorer.resources.ModifiableResourceCollection; 033import org.ametys.plugins.explorer.resources.ResourceCollection; 034import org.ametys.plugins.repository.AmetysObject; 035import org.ametys.plugins.repository.AmetysObjectResolver; 036import org.ametys.plugins.workspaces.project.ProjectManager; 037import org.ametys.plugins.workspaces.project.modules.WorkspaceModule; 038import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint; 039import org.ametys.plugins.workspaces.project.objects.Project; 040import org.ametys.plugins.workspaces.project.rights.ProjectRightHelper; 041 042/** 043 * Give the read right on modules if the user as any other profile on it. 044 * This controller has no cache by itself on the underlying non cached ProfileAssignmentStorageExtensionPoint ; but as it works only on the read right, the top level cache in the RightManager do the job 045 */ 046public class ModuleAccessController implements AccessController, Serviceable 047{ 048 private static Pattern __MODULE_ROOT_PATH_PATTERN = Pattern.compile("^(/ametys:plugins/workspaces/projects/(?:[^/]+)/ametys-internal:resources/(?:[^/]+)).*$"); 049 050 /** The extension point for the profile assignment storages */ 051 protected ProfileAssignmentStorageExtensionPoint _profileAssignmentStorageEP; 052 /** the right helper */ 053 protected ProjectRightHelper _projectRightHelper; 054 /** The Ametys object resolver */ 055 protected AmetysObjectResolver _resolver; 056 /** The module extension point */ 057 protected WorkspaceModuleExtensionPoint _moduleEP; 058 /** The project manager */ 059 protected ProjectManager _projectManager; 060 061 public void service(ServiceManager manager) throws ServiceException 062 { 063 _profileAssignmentStorageEP = (ProfileAssignmentStorageExtensionPoint) manager.lookup(ProfileAssignmentStorageExtensionPoint.ROLE); 064 _projectRightHelper = (ProjectRightHelper) manager.lookup(ProjectRightHelper.ROLE); 065 _resolver = (AmetysObjectResolver) manager.lookup(AmetysObjectResolver.ROLE); 066 _moduleEP = (WorkspaceModuleExtensionPoint) manager.lookup(WorkspaceModuleExtensionPoint.ROLE); 067 _projectManager = (ProjectManager) manager.lookup(ProjectManager.ROLE); 068 } 069 070 public boolean isSupported(Object object) 071 { 072 if (object instanceof AmetysObject) 073 { 074 String path = ((AmetysObject) object).getPath(); 075 return path.startsWith("/ametys:plugins/workspaces/projects/") 076 && path.contains("/ametys-internal:resources/"); 077 } 078 else 079 { 080 return false; 081 } 082 } 083 084 private boolean _isModuleActivated(ResourceCollection moduleRoot) 085 { 086 Project project = moduleRoot.getParent().getParent(); 087 088 WorkspaceModule module = _moduleEP.getModuleByName(moduleRoot.getName()); 089 if (module == null) 090 { 091 throw new IllegalStateException("Can not find module from the module root name '" + moduleRoot.getName() + "'"); 092 } 093 094 return _projectManager.isModuleActivated(project, module.getId()); 095 } 096 097 private ModifiableResourceCollection _getModuleRoot(Object object) 098 { 099 AmetysObject node = (AmetysObject) object; 100 101 Matcher matcher = __MODULE_ROOT_PATH_PATTERN.matcher(node.getPath()); 102 if (matcher.matches()) 103 { 104 String rootPath = matcher.group(1); 105 if (node.getPath().equals(rootPath)) 106 { 107 return (ModifiableResourceCollection) node; 108 } 109 else 110 { 111 return (ModifiableResourceCollection) _resolver.resolveByPath(rootPath); 112 } 113 } 114 115 throw new IllegalArgumentException("Node " + node.getPath() + " is not a module path"); 116 } 117 118 public AccessResult getPermission(UserIdentity user, Set<GroupIdentity> userGroups, String rightId, Object object) 119 { 120 return AccessResult.UNKNOWN; 121 } 122 123 public AccessResult getReadAccessPermission(UserIdentity user, Set<GroupIdentity> userGroups, Object object) 124 { 125 ModifiableResourceCollection root = _getModuleRoot(object); 126 127 if (!_isModuleActivated(root)) 128 { 129 return AccessResult.UNKNOWN; 130 } 131 else 132 { 133 return _profileAssignmentStorageEP.getPermissions(user, userGroups, _projectRightHelper.getProfilesIds(), root) 134 .values().stream() 135 .anyMatch(ar -> ar.toRightResult() == RightResult.RIGHT_ALLOW) ? AccessResult.USER_ALLOWED : AccessResult.UNKNOWN; 136 } 137 } 138 139 public Map<String, AccessResult> getPermissionByRight(UserIdentity user, Set<GroupIdentity> userGroups, Object object) 140 { 141 return Map.of(); 142 } 143 144 public AccessResult getPermissionForAnonymous(String rightId, Object object) 145 { 146 return AccessResult.UNKNOWN; 147 } 148 149 public AccessResult getReadAccessPermissionForAnonymous(Object object) 150 { 151 ModifiableResourceCollection root = _getModuleRoot(object); 152 153 if (!_isModuleActivated(root)) 154 { 155 return AccessResult.UNKNOWN; 156 } 157 else 158 { 159 return _profileAssignmentStorageEP.getPermissionForAnonymous(_projectRightHelper.getProfilesIds(), root); 160 } 161 } 162 163 public AccessResult getPermissionForAnyConnectedUser(String rightId, Object object) 164 { 165 return AccessResult.UNKNOWN; 166 } 167 168 public AccessResult getReadAccessPermissionForAnyConnectedUser(Object object) 169 { 170 ModifiableResourceCollection root = _getModuleRoot(object); 171 172 if (!_isModuleActivated(root)) 173 { 174 return AccessResult.UNKNOWN; 175 } 176 else 177 { 178 return _profileAssignmentStorageEP.getPermissionForAnyConnectedUser(_projectRightHelper.getProfilesIds(), _getModuleRoot(object)); 179 } 180 } 181 182 public Map<UserIdentity, AccessResult> getPermissionByUser(String rightId, Object object) 183 { 184 return Map.of(); 185 } 186 187 public Map<UserIdentity, AccessResult> getReadAccessPermissionByUser(Object object) 188 { 189 ModifiableResourceCollection root = _getModuleRoot(object); 190 191 if (!_isModuleActivated(root)) 192 { 193 return Map.of(); 194 } 195 else 196 { 197 return _profileAssignmentStorageEP.getPermissionsByUser(_projectRightHelper.getProfilesIds(), root); 198 } 199 } 200 201 public Map<GroupIdentity, AccessResult> getPermissionByGroup(String rightId, Object object) 202 { 203 return Map.of(); 204 } 205 206 public Map<GroupIdentity, AccessResult> getReadAccessPermissionByGroup(Object object) 207 { 208 ModifiableResourceCollection root = _getModuleRoot(object); 209 210 if (!_isModuleActivated(root)) 211 { 212 return Map.of(); 213 } 214 else 215 { 216 return _profileAssignmentStorageEP.getPermissionsByGroup(_projectRightHelper.getProfilesIds(), root); 217 } 218 } 219 220 public boolean hasUserAnyPermissionOnWorkspace(Set<Object> workspacesContexts, UserIdentity user, Set<GroupIdentity> userGroups, String rightId) 221 { 222 return false; 223 } 224 225 public boolean hasUserAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts, UserIdentity user, Set<GroupIdentity> userGroups) 226 { 227 return false; // No need to forward to workspace 228 } 229 230 public boolean hasAnonymousAnyPermissionOnWorkspace(Set<Object> workspacesContexts, String rightId) 231 { 232 return false; 233 } 234 235 public boolean hasAnonymousAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts) 236 { 237 return false; // No need to forward to workspace 238 } 239 240 public boolean hasAnyConnectedUserAnyPermissionOnWorkspace(Set<Object> workspacesContexts, String rightId) 241 { 242 return false; 243 } 244 245 public boolean hasAnyConnectedUserAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts) 246 { 247 return false; // No need to forward to workspace 248 } 249}