001/*
002 *  Copyright 2017 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.editionfo;
017
018import java.util.Collections;
019import java.util.HashMap;
020import java.util.Map;
021import java.util.Set;
022
023import org.apache.avalon.framework.service.ServiceException;
024import org.apache.avalon.framework.service.ServiceManager;
025import org.apache.avalon.framework.service.Serviceable;
026import org.slf4j.Logger;
027
028import org.ametys.core.group.GroupIdentity;
029import org.ametys.core.right.AccessController;
030import org.ametys.core.right.AccessControllerExtensionPoint;
031import org.ametys.core.user.UserIdentity;
032import org.ametys.plugins.explorer.resources.ResourceCollection;
033import org.ametys.plugins.explorer.rights.ResourceAccessController;
034import org.ametys.plugins.frontedition.AmetysFrontEditionHelper;
035import org.ametys.plugins.workspaces.project.ProjectManager;
036import org.ametys.plugins.workspaces.project.modules.WorkspaceModule;
037import org.ametys.plugins.workspaces.project.modules.WorkspaceModuleExtensionPoint;
038import org.ametys.plugins.workspaces.project.objects.Project;
039import org.ametys.runtime.plugin.component.LogEnabled;
040import org.ametys.web.repository.page.Page;
041import org.ametys.web.repository.page.PagesContainer;
042
043/**
044 * The controller is used for wiki pages edition.
045 * This controller delegates control to the wiki module root.
046 * Beware that this controller works with ResourceAccessController... that should be enabled (and if another AccessController can give rights to resources... that's too bad)
047 */
048public class EditionFOAccessController implements AccessController, Serviceable, LogEnabled
049{
050    private ProjectManager _projectManager;
051    private WorkspaceModuleExtensionPoint _workspaceModuleExtensionPoint;
052    private Logger _logger;
053    private AccessControllerExtensionPoint _accessControllerExtensionPoint;
054    private AccessController _accessController;
055
056    public void service(ServiceManager manager) throws ServiceException
057    {
058        _projectManager = (ProjectManager) manager.lookup(ProjectManager.ROLE);
059        _workspaceModuleExtensionPoint = (WorkspaceModuleExtensionPoint) manager.lookup(WorkspaceModuleExtensionPoint.ROLE);
060        _accessControllerExtensionPoint = (AccessControllerExtensionPoint) manager.lookup(AccessControllerExtensionPoint.ROLE);
061    }
062    
063    public void setLogger(Logger logger)
064    {
065        _logger = logger;
066    }
067    
068    private AccessController _getAccessController()
069    {
070        if (_accessController == null)
071        {
072            _accessController = _accessControllerExtensionPoint.getExtension(ResourceAccessController.class.getName());
073        }
074        return _accessController;
075    }
076    
077    private ResourceCollection _getEditionFOModuleRootFromContext(Object object)
078    {
079        String siteName = _getSiteFromContext(object);
080        for (String projectName : _projectManager.getProjectsForSite(siteName))
081        {
082            Project project = _projectManager.getProject(projectName);
083            if (project == null)
084            {
085                _logger.warn("Cannot find project '{}' associated to the site '{}'.", projectName, siteName);
086                continue;
087            }
088            
089            WorkspaceModule editionFOWorkspaceModule = _workspaceModuleExtensionPoint.getExtension(EditionFOWorkspaceModule.EDITIONFO_MODULE_ID);
090            
091            if (!_isPageInProjectWiki(editionFOWorkspaceModule, project, object))
092            {
093                return null;
094            }
095            
096            return editionFOWorkspaceModule.getModuleRoot(project, false);
097        }
098        
099        return null;
100    }
101    
102    private String _getSiteFromContext(Object context)
103    {
104        if (context instanceof PagesContainer)
105        {
106            return ((PagesContainer) context).getSiteName();
107        }
108        return null;
109    }
110    
111    private boolean _isPageInProjectWiki(WorkspaceModule editionFOWorkspaceModule, Project project, Object object)
112    {
113        if (!(object instanceof PagesContainer))
114        {
115            return false;
116        }
117        PagesContainer page = (PagesContainer) object;
118        String pagePath = page.getPath();
119        
120        return editionFOWorkspaceModule.getModulePages(project, page.getSitemapName())
121                                       .stream()
122                                       .anyMatch(wikiPage -> pagePath.equals(wikiPage.getPath()) || pagePath.contains(wikiPage.getPath() + "/"));
123    }
124    
125    public AccessResult getPermission(UserIdentity user, Set<GroupIdentity> userGroups, String rightId, Object object)
126    {
127        if (AmetysFrontEditionHelper.FRONT_EDITION_RIGHT_ID.equals(rightId) || object instanceof Page)
128        {
129            ResourceCollection moduleRoot = _getEditionFOModuleRootFromContext(object);
130            if (moduleRoot != null)
131            {
132                return _getAccessController().getPermission(user, userGroups, rightId, moduleRoot);
133            }
134        }
135        
136        return AccessResult.UNKNOWN;
137    }
138
139    public AccessResult getReadAccessPermission(UserIdentity user, Set<GroupIdentity> userGroups, Object object)
140    {
141        if (object instanceof Page)
142        {
143            ResourceCollection moduleRoot = _getEditionFOModuleRootFromContext(object);
144            if (moduleRoot != null)
145            {
146                return _getAccessController().getReadAccessPermission(user, userGroups, moduleRoot);
147            }
148        }
149        
150        return AccessResult.UNKNOWN;
151    }
152
153    public Map<String, AccessResult> getPermissionByRight(UserIdentity user, Set<GroupIdentity> userGroups, Object object)
154    {
155        AccessResult accessResult = getPermission(user, userGroups, AmetysFrontEditionHelper.FRONT_EDITION_RIGHT_ID, object);
156        if (accessResult == AccessResult.UNKNOWN)
157        {
158            return Collections.EMPTY_MAP;
159        }
160        else
161        {
162            Map<String, AccessResult> permissions = new HashMap<>();
163            permissions.put(AmetysFrontEditionHelper.FRONT_EDITION_RIGHT_ID, accessResult);
164            return permissions;
165        }
166    }
167
168    public AccessResult getPermissionForAnonymous(String rightId, Object object)
169    {
170        if (AmetysFrontEditionHelper.FRONT_EDITION_RIGHT_ID.equals(rightId) || object instanceof Page)
171        {
172            ResourceCollection moduleRoot = _getEditionFOModuleRootFromContext(object);
173            if (moduleRoot != null)
174            {
175                return _getAccessController().getPermissionForAnonymous(rightId, moduleRoot);
176            }
177        }
178        
179        return AccessResult.UNKNOWN;
180    }
181
182    public AccessResult getReadAccessPermissionForAnonymous(Object object)
183    {
184        if (object instanceof Page)
185        {
186            ResourceCollection moduleRoot = _getEditionFOModuleRootFromContext(object);
187            if (moduleRoot != null)
188            {
189                return _getAccessController().getReadAccessPermissionForAnonymous(moduleRoot);
190            }
191        }
192        
193        return AccessResult.UNKNOWN;
194    }
195
196    public AccessResult getPermissionForAnyConnectedUser(String rightId, Object object)
197    {
198        if (AmetysFrontEditionHelper.FRONT_EDITION_RIGHT_ID.equals(rightId) || object instanceof Page)
199        {
200            ResourceCollection moduleRoot = _getEditionFOModuleRootFromContext(object);
201            if (moduleRoot != null)
202            {
203                return _getAccessController().getPermissionForAnyConnectedUser(rightId, moduleRoot);
204            }
205        }
206        
207        return AccessResult.UNKNOWN;
208    }
209
210    public AccessResult getReadAccessPermissionForAnyConnectedUser(Object object)
211    {
212        if (object instanceof Page)
213        {
214            ResourceCollection moduleRoot = _getEditionFOModuleRootFromContext(object);
215            if (moduleRoot != null)
216            {
217                return _getAccessController().getReadAccessPermissionForAnyConnectedUser(moduleRoot);
218            }
219        }
220        
221        return AccessResult.UNKNOWN;
222    }
223
224    public Map<UserIdentity, AccessResult> getPermissionByUser(String rightId, Object object)
225    {
226        if (AmetysFrontEditionHelper.FRONT_EDITION_RIGHT_ID.equals(rightId) || object instanceof Page)
227        {
228            ResourceCollection moduleRoot = _getEditionFOModuleRootFromContext(object);
229            if (moduleRoot != null)
230            {
231                return _getAccessController().getPermissionByUser(rightId, moduleRoot);
232            }
233
234        }
235
236        return Collections.EMPTY_MAP;
237    }
238
239    public Map<UserIdentity, AccessResult> getReadAccessPermissionByUser(Object object)
240    {
241        if (object instanceof Page)
242        {
243            ResourceCollection moduleRoot = _getEditionFOModuleRootFromContext(object);
244            if (moduleRoot != null)
245            {
246                return _getAccessController().getReadAccessPermissionByUser(moduleRoot);
247            }
248        }
249        
250        return Collections.EMPTY_MAP;
251    }
252
253    public Map<GroupIdentity, AccessResult> getPermissionByGroup(String rightId, Object object)
254    {
255        if (AmetysFrontEditionHelper.FRONT_EDITION_RIGHT_ID.equals(rightId) || object instanceof Page)
256        {
257            ResourceCollection moduleRoot = _getEditionFOModuleRootFromContext(object);
258            if (moduleRoot != null)
259            {
260                return _getAccessController().getPermissionByGroup(rightId, moduleRoot);
261            }
262        }
263
264        return Collections.EMPTY_MAP;
265    }
266
267    public Map<GroupIdentity, AccessResult> getReadAccessPermissionByGroup(Object object)
268    {
269        if (object instanceof Page)
270        {
271            ResourceCollection moduleRoot = _getEditionFOModuleRootFromContext(object);
272            if (moduleRoot != null)
273            {
274                return _getAccessController().getReadAccessPermissionByGroup(moduleRoot);
275            }
276        }
277        
278        return Collections.EMPTY_MAP;
279    }
280
281    public boolean hasUserAnyPermissionOnWorkspace(Set<Object> workspacesContexts, UserIdentity user, Set<GroupIdentity> userGroups, String rightId)
282    {
283        // We do not want that this accesscontroller give access to the backoffice (even if #isSupported would not match in this case)
284        return false;
285    }
286
287    public boolean hasUserAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts, UserIdentity user, Set<GroupIdentity> userGroups)
288    {
289        return false;
290    }
291
292    public boolean hasAnonymousAnyPermissionOnWorkspace(Set<Object> workspacesContexts, String rightId)
293    {
294        // We do not want that this accesscontroller give access to the backoffice (even if #isSupported would not match in this case)
295        return false;
296    }
297
298    public boolean hasAnonymousAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts)
299    {
300        return false;
301    }
302
303    public boolean hasAnyConnectedUserAnyPermissionOnWorkspace(Set<Object> workspacesContexts, String rightId)
304    {
305        // We do not want that this accesscontroller give access to the backoffice (even if #isSupported would not match in this case)
306        return false;
307    }
308
309    public boolean hasAnyConnectedUserAnyReadAccessPermissionOnWorkspace(Set<Object> workspacesContexts)
310    {
311        return false;
312    }
313
314    public boolean isSupported(Object object)
315    {
316        return object instanceof PagesContainer;
317    }
318
319}