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