001/* 002 * Copyright 2015 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.web.pageaccess; 017 018import java.util.Collection; 019import java.util.Set; 020 021import org.apache.avalon.framework.component.Component; 022import org.apache.avalon.framework.logger.AbstractLogEnabled; 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.cms.repository.Content; 028import org.ametys.core.group.GroupIdentity; 029import org.ametys.core.right.AllowedUsers; 030import org.ametys.core.right.ProfileAssignmentStorageExtensionPoint; 031import org.ametys.core.right.RightManager; 032import org.ametys.core.user.CurrentUserProvider; 033import org.ametys.core.user.UserIdentity; 034import org.ametys.web.repository.content.WebContent; 035import org.ametys.web.repository.page.Page; 036 037/** 038 * Class managing access to contents on the front-office side. 039 */ 040public class ContentAccessManager extends AbstractLogEnabled implements Component, Serviceable 041{ 042 043 /** 044 * Enumeration representing a content access status. 045 */ 046 public enum ContentAccess 047 { 048 /** 049 * The content can be viewed by all users because of one of these reasons: 050 * <ul> 051 * <li>it appears on a public page</li> 052 * <li>it doesn't appear on any page (orphan content) but its sitemap is freely accessible</li> 053 * </ul> 054 */ 055 UNRESTRICTED, 056 057 /** 058 * The content appears on pages with limited access, and the given user can access at least one. 059 */ 060 ALLOWED, 061 062 /** 063 * The content appears on pages with limited access, but the given user can't access any. 064 */ 065 FORBIDDEN 066 } 067 068 /** The component role. */ 069 public static final String ROLE = ContentAccessManager.class.getName(); 070 071 /** The right manager */ 072 protected RightManager _rightManager; 073 074 /** The current user provider */ 075 protected CurrentUserProvider _currentUserProvider; 076 077 /** The component handling profile storage */ 078 protected ProfileAssignmentStorageExtensionPoint _profileAssignmentStorageEP; 079 080 @Override 081 public void service(ServiceManager manager) throws ServiceException 082 { 083 _rightManager = (RightManager) manager.lookup(RightManager.ROLE); 084 _currentUserProvider = (CurrentUserProvider) manager.lookup(CurrentUserProvider.ROLE); 085 _profileAssignmentStorageEP = (ProfileAssignmentStorageExtensionPoint) manager.lookup(ProfileAssignmentStorageExtensionPoint.ROLE); 086 } 087 088 /** 089 * Get the access status of a content, from the user currently connected to the front-office. 090 * @param content the content to test. 091 * @return the content access status. 092 */ 093 public ContentAccess getAccess(Content content) 094 { 095 return getAccess(content, true); 096 } 097 098 /** 099 * Get the access status of a content, from the user currently connected to the front-office. 100 * @param content the content to test. 101 * @param checkUser When true, the user's ability to view the page will be checked 102 * ({@link ContentAccess#ALLOWED} may be returned).<br> 103 * When false, only the content general availability will be checked: {@link ContentAccess#ALLOWED} will never be returned. 104 * @return the content access status. 105 */ 106 public ContentAccess getAccess(Content content, boolean checkUser) 107 { 108 return getAccess(content, _currentUserProvider.getUser(), checkUser); 109 } 110 111 /** 112 * Get the access status of a content from a given user. 113 * @param content the content to test. 114 * @param userIdentity the user identity, can be null (to test anonymous access). 115 * @return the content access status. 116 */ 117 public ContentAccess getAccess(Content content, UserIdentity userIdentity) 118 { 119 return getAccess(content, userIdentity, true); 120 } 121 122 /** 123 * Get the access status of a content from a given user. 124 * The user access is check ONLY on the content's pages. Has read access on content is not enough ! 125 * @param content the content to test. 126 * @param userIdentity the user identity, can be null (to test anonymous access). 127 * @param checkUser When true, the user's ability to view the page will be checked 128 * ({@link ContentAccess#ALLOWED} may be returned).<br> 129 * When false, only the content general availability will be checked: {@link ContentAccess#ALLOWED} will never be returned. 130 * @return the content access status. 131 */ 132 public ContentAccess getAccess(Content content, UserIdentity userIdentity, boolean checkUser) 133 { 134 if (!(content instanceof WebContent)) 135 { 136 return _getContentAccess(content, userIdentity, checkUser); 137 } 138 139 WebContent webContent = (WebContent) content; 140 Collection<Page> contentPages = webContent.getReferencingPages(); 141 142 // Test the restrictions. 143 if (contentPages.isEmpty()) 144 { 145 return _getContentAccess(content, userIdentity, checkUser); 146 } 147 else 148 { 149 for (Page page : contentPages) 150 { 151 // If the content is present in a page that is not restricted, it's visible by all. 152 if (_rightManager.hasAnonymousReadAccess(page)) 153 { 154 return ContentAccess.UNRESTRICTED; 155 } 156 157 // If the user is allowed to see at least one page containing the content, he can access the content. 158 if (checkUser && _rightManager.hasReadAccess(userIdentity, page)) 159 { 160 return ContentAccess.ALLOWED; 161 } 162 } 163 } 164 165 return ContentAccess.FORBIDDEN; 166 } 167 168 private ContentAccess _getContentAccess(Content content, UserIdentity userIdentity, boolean checkUser) 169 { 170 // Returns content access regardless of its pages. 171 172 if (_rightManager.hasAnonymousReadAccess(content)) 173 { 174 return ContentAccess.UNRESTRICTED; 175 } 176 177 return checkUser && _rightManager.hasReadAccess(userIdentity, content) ? ContentAccess.ALLOWED : ContentAccess.FORBIDDEN; 178 } 179 180 /** 181 * Test if the content is displayed in a page having the same access rights as the current page. 182 * @param content the web content. 183 * @param currentPage the current page. 184 * @return true if the content is accessible, false otherwise. 185 */ 186 public boolean isAccessibleByPage(WebContent content, Page currentPage) 187 { 188 if (!_rightManager.hasAnonymousReadAccess(currentPage)) 189 { 190 AllowedUsers currentUsersWithReadAccess = _rightManager.getReadAccessAllowedUsers(currentPage); 191 boolean currentAllowAnyConnectedUser = currentUsersWithReadAccess.isAnyConnectedUserAllowed(); 192 Set<UserIdentity> currentAllowedUsers = currentUsersWithReadAccess.getAllowedUsers(); 193 Set<GroupIdentity> currentAllowedGroups = currentUsersWithReadAccess.getAllowedGroups(); 194 Set<UserIdentity> currentDeniedUsers = currentUsersWithReadAccess.getDeniedUsers(); 195 Set<GroupIdentity> currentDeniedGroups = currentUsersWithReadAccess.getDeniedGroups(); 196 197 Collection<Page> refPages = content.getReferencingPages(); 198 if (!refPages.isEmpty()) 199 { 200 for (Page referencingPage : refPages) 201 { 202 if (!_rightManager.hasAnonymousReadAccess(referencingPage)) 203 { 204 AllowedUsers refUsersWithReadAccess = _rightManager.getReadAccessAllowedUsers(referencingPage); 205 boolean refAllowAnyConnectedUser = refUsersWithReadAccess.isAnyConnectedUserAllowed(); 206 Set<UserIdentity> refAllowedUsers = refUsersWithReadAccess.getAllowedUsers(); 207 Set<GroupIdentity> refAllowedGroups = refUsersWithReadAccess.getAllowedGroups(); 208 Set<UserIdentity> refDeniedUsers = refUsersWithReadAccess.getDeniedUsers(); 209 Set<GroupIdentity> refDeniedGroups = refUsersWithReadAccess.getDeniedGroups(); 210 211 if ((refAllowAnyConnectedUser || (!currentAllowAnyConnectedUser && refAllowedUsers.containsAll(currentAllowedUsers) && refAllowedGroups.containsAll(currentAllowedGroups))) 212 && currentDeniedUsers.containsAll(refDeniedUsers) && currentDeniedGroups.containsAll(refDeniedGroups)) 213 { 214 // The content is referenced by a page either accessible either to all connected users 215 // or restricted to the same population as the current page: display the content. 216 return true; 217 } 218 } 219 else 220 { 221 // The content is referenced by a public page: display the content. 222 return true; 223 } 224 } 225 226 // The content isn't referenced by a page with the same access: do not display the content. 227 return false; 228 } 229 else 230 { 231 // Orphan content 232 if (!_rightManager.hasAnonymousReadAccess(content)) 233 { 234 AllowedUsers refUsersWithReadAccess = _rightManager.getReadAccessAllowedUsers(content); 235 boolean refAllowAnyConnectedUser = refUsersWithReadAccess.isAnyConnectedUserAllowed(); 236 Set<UserIdentity> refAllowedUsers = refUsersWithReadAccess.getAllowedUsers(); 237 Set<GroupIdentity> refAllowedGroups = refUsersWithReadAccess.getAllowedGroups(); 238 Set<UserIdentity> refDeniedUsers = refUsersWithReadAccess.getDeniedUsers(); 239 Set<GroupIdentity> refDeniedGroups = refUsersWithReadAccess.getDeniedGroups(); 240 241 // Check if the content is accessible to all connected users 242 // or restricted to the same population as the current page: display the content. 243 return (refAllowAnyConnectedUser || (!currentAllowAnyConnectedUser && refAllowedUsers.containsAll(currentAllowedUsers) && refAllowedGroups.containsAll(currentAllowedGroups))) 244 && currentDeniedUsers.containsAll(refDeniedUsers) && currentDeniedGroups.containsAll(refDeniedGroups); 245 } 246 else 247 { 248 // The content is anonymous read access: display the content. 249 return true; 250 } 251 } 252 } 253 else 254 { 255 // The current page is not restricted: display only unrestricted contents 256 // N.B: the current user's right are *NOT* tested, as in this mode, the results are cached. 257 return getAccess(content, null, false) == ContentAccess.UNRESTRICTED; 258 } 259 } 260}