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