001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.security; 029 030import org.opencms.configuration.CmsSystemConfiguration; 031import org.opencms.db.CmsCacheSettings; 032import org.opencms.db.CmsDbContext; 033import org.opencms.db.CmsDriverManager; 034import org.opencms.db.CmsSecurityManager; 035import org.opencms.db.I_CmsCacheKey; 036import org.opencms.file.CmsProject; 037import org.opencms.file.CmsResource; 038import org.opencms.file.CmsResourceFilter; 039import org.opencms.file.CmsUser; 040import org.opencms.file.types.CmsResourceTypeJsp; 041import org.opencms.lock.CmsLock; 042import org.opencms.main.CmsException; 043import org.opencms.main.CmsInitException; 044import org.opencms.main.CmsLog; 045import org.opencms.main.OpenCms; 046 047import java.util.Iterator; 048 049import org.apache.commons.logging.Log; 050 051/** 052 * Generic base driver interface.<p> 053 * 054 * @since 7.0.2 055 */ 056public class CmsDefaultPermissionHandler implements I_CmsPermissionHandler { 057 058 /** The log object for this class. */ 059 private static final Log LOG = CmsLog.getLog(CmsDefaultPermissionHandler.class); 060 061 /** Driver Manager instance. */ 062 protected CmsDriverManager m_driverManager; 063 064 /** Security Manager instance. */ 065 protected CmsSecurityManager m_securityManager; 066 067 /** The class used for cache key generation. */ 068 private I_CmsCacheKey m_keyGenerator; 069 070 /** 071 * @see org.opencms.security.I_CmsPermissionHandler#hasPermissions(org.opencms.db.CmsDbContext, org.opencms.file.CmsResource, org.opencms.security.CmsPermissionSet, org.opencms.security.I_CmsPermissionHandler.LockCheck, org.opencms.file.CmsResourceFilter) 072 */ 073 public CmsPermissionCheckResult hasPermissions( 074 CmsDbContext dbc, 075 CmsResource resource, 076 CmsPermissionSet requiredPermissions, 077 LockCheck checkLock, 078 CmsResourceFilter filter) 079 throws CmsException { 080 081 // check if the resource is valid according to the current filter 082 // if not, throw a CmsResourceNotFoundException 083 if (!filter.isValid(dbc.getRequestContext(), resource)) { 084 return I_CmsPermissionHandler.PERM_FILTERED; 085 } 086 087 // checking the filter is less cost intensive then checking the cache, 088 // this is why basic filter results are not cached 089 String requireVisibleStr = filter.requireVisible() ? "1" : "0"; 090 String lockCheckStr = checkLock.getCode(); 091 String keyPrefix = requireVisibleStr + lockCheckStr; 092 093 String cacheKey = m_keyGenerator.getCacheKeyForUserPermissions(keyPrefix, dbc, resource, requiredPermissions); 094 CmsPermissionCheckResult cacheResult = OpenCms.getMemoryMonitor().getCachedPermission(cacheKey); 095 if (cacheResult != null) { 096 return cacheResult; 097 } 098 099 int denied = 0; 100 101 // if this is the online project, write is rejected 102 if (dbc.currentProject().isOnlineProject()) { 103 denied |= CmsPermissionSet.PERMISSION_WRITE; 104 } 105 106 // check if the current user is admin 107 boolean canIgnorePermissions = m_securityManager.hasRoleForResource( 108 dbc, 109 dbc.currentUser(), 110 CmsRole.VFS_MANAGER, 111 resource); 112 113 // check lock status 114 boolean writeRequired = requiredPermissions.requiresWritePermission() 115 || requiredPermissions.requiresControlPermission(); 116 117 // if the resource type is jsp 118 // write is only allowed for administrators 119 if (writeRequired && !canIgnorePermissions && (CmsResourceTypeJsp.isJsp(resource))) { 120 if (!m_securityManager.hasRoleForResource(dbc, dbc.currentUser(), CmsRole.VFS_MANAGER, resource)) { 121 denied |= CmsPermissionSet.PERMISSION_WRITE; 122 denied |= CmsPermissionSet.PERMISSION_CONTROL; 123 } 124 } 125 126 if (writeRequired && (checkLock != LockCheck.no)) { 127 // check lock state only if required 128 CmsLock lock = m_driverManager.getLock(dbc, resource); 129 // if the resource is not locked by the current user, write and control 130 // access must cause a permission error that must not be cached 131 if (lock.isUnlocked() || !lock.isLockableBy(dbc.currentUser())) { 132 return I_CmsPermissionHandler.PERM_NOTLOCKED; 133 } 134 // if we have a shallow lock, but need a non-shallow one, return NOTLOCKED 135 if (lock.getType().isShallow() && (checkLock != LockCheck.shallowOnly)) { 136 return I_CmsPermissionHandler.PERM_NOTLOCKED; 137 } 138 } 139 140 CmsPermissionSetCustom permissions; 141 if (canIgnorePermissions) { 142 // if the current user is administrator, anything is allowed 143 permissions = new CmsPermissionSetCustom(~0); 144 } else { 145 // otherwise, get the permissions from the access control list 146 permissions = m_driverManager.getPermissions(dbc, resource, dbc.currentUser()); 147 } 148 149 // revoke the denied permissions 150 permissions.denyPermissions(denied); 151 152 if ((permissions.getPermissions() & CmsPermissionSet.PERMISSION_VIEW) == 0) { 153 // resource "invisible" flag is set for this user 154 if (!canIgnorePermissions && filter.requireVisible()) { 155 // filter requires visible permission - extend required permission set 156 requiredPermissions = new CmsPermissionSet( 157 requiredPermissions.getAllowedPermissions() | CmsPermissionSet.PERMISSION_VIEW, 158 requiredPermissions.getDeniedPermissions()); 159 } else { 160 // view permissions can be ignored by filter 161 permissions.setPermissions( 162 // modify permissions so that view is allowed 163 permissions.getAllowedPermissions() | CmsPermissionSet.PERMISSION_VIEW, 164 permissions.getDeniedPermissions() & ~CmsPermissionSet.PERMISSION_VIEW); 165 } 166 } 167 168 if (requiredPermissions.requiresDirectPublishPermission()) { 169 // direct publish permission is required 170 if ((permissions.getPermissions() & CmsPermissionSet.PERMISSION_DIRECT_PUBLISH) == 0) { 171 // but the user has no direct publish permission, so check if the user has the project manager role 172 boolean canIgnorePublishPermission = m_securityManager.hasRoleForResource( 173 dbc, 174 dbc.currentUser(), 175 CmsRole.PROJECT_MANAGER, 176 resource); 177 // if not, check the manageable projects 178 if (!canIgnorePublishPermission) { 179 CmsUser user = dbc.currentUser(); 180 Iterator<CmsProject> itProjects = m_driverManager.getAllManageableProjects( 181 dbc, 182 m_driverManager.readOrganizationalUnit(dbc, user.getOuFqn()), 183 true).iterator(); 184 while (itProjects.hasNext()) { 185 CmsProject project = itProjects.next(); 186 if (CmsProject.isInsideProject(m_driverManager.readProjectResources(dbc, project), resource)) { 187 canIgnorePublishPermission = true; 188 break; 189 } 190 } 191 } 192 193 if (canIgnorePublishPermission) { 194 // direct publish permission can be ignored 195 permissions.setPermissions( 196 // modify permissions so that direct publish is allowed 197 permissions.getAllowedPermissions() | CmsPermissionSet.PERMISSION_DIRECT_PUBLISH, 198 permissions.getDeniedPermissions() & ~CmsPermissionSet.PERMISSION_DIRECT_PUBLISH); 199 } 200 } 201 } 202 203 CmsPermissionCheckResult result; 204 if ((requiredPermissions.getPermissions() 205 & (permissions.getPermissions())) == requiredPermissions.getPermissions()) { 206 result = I_CmsPermissionHandler.PERM_ALLOWED; 207 } else { 208 result = I_CmsPermissionHandler.PERM_DENIED; 209 if (LOG.isDebugEnabled()) { 210 LOG.debug( 211 Messages.get().getBundle().key( 212 Messages.LOG_NO_PERMISSION_RESOURCE_USER_4, 213 new Object[] { 214 dbc.getRequestContext().removeSiteRoot(resource.getRootPath()), 215 dbc.currentUser().getName(), 216 requiredPermissions.getPermissionString(), 217 permissions.getPermissionString()})); 218 } 219 } 220 if (dbc.getProjectId().isNullUUID() && permissions.isCacheable()) { 221 OpenCms.getMemoryMonitor().cachePermission(cacheKey, result); 222 } 223 if (!permissions.isCacheable()) { 224 // if this method is used for checking permissions in resource lists, the resulting resource lists 225 // are not cacheable either if the permission check for this resource isn't 226 boolean[] nocacheArray = (boolean[])dbc.getAttribute(CmsDriverManager.ATTR_PERMISSION_NOCACHE); 227 if (nocacheArray != null) { 228 nocacheArray[0] = true; 229 } 230 } 231 232 return result; 233 } 234 235 /** 236 * @see org.opencms.security.I_CmsPermissionHandler#init(org.opencms.db.CmsDriverManager, CmsSystemConfiguration) 237 */ 238 public void init(CmsDriverManager driverManager, CmsSystemConfiguration systemConfiguration) { 239 240 m_driverManager = driverManager; 241 m_securityManager = driverManager.getSecurityManager(); 242 243 CmsCacheSettings settings = systemConfiguration.getCacheSettings(); 244 245 String className = settings.getCacheKeyGenerator(); 246 try { 247 // initialize the key generator 248 m_keyGenerator = (I_CmsCacheKey)Class.forName(className).newInstance(); 249 } catch (Exception e) { 250 throw new CmsInitException( 251 org.opencms.main.Messages.get().container( 252 org.opencms.main.Messages.ERR_CRITICAL_CLASS_CREATION_1, 253 className), 254 e); 255 } 256 } 257}