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, boolean, org.opencms.file.CmsResourceFilter) 072 */ 073 public CmsPermissionCheckResult hasPermissions( 074 CmsDbContext dbc, 075 CmsResource resource, 076 CmsPermissionSet requiredPermissions, 077 boolean checkLock, 078 CmsResourceFilter filter) throws CmsException { 079 080 // check if the resource is valid according to the current filter 081 // if not, throw a CmsResourceNotFoundException 082 if (!filter.isValid(dbc.getRequestContext(), resource)) { 083 return I_CmsPermissionHandler.PERM_FILTERED; 084 } 085 086 // checking the filter is less cost intensive then checking the cache, 087 // this is why basic filter results are not cached 088 String cacheKey = m_keyGenerator.getCacheKeyForUserPermissions( 089 filter.requireVisible() && checkLock 090 ? "11" 091 : (!filter.requireVisible() && checkLock ? "01" : (filter.requireVisible() && !checkLock ? "10" : "00")), 092 dbc, 093 resource, 094 requiredPermissions); 095 CmsPermissionCheckResult cacheResult = OpenCms.getMemoryMonitor().getCachedPermission(cacheKey); 096 if (cacheResult != null) { 097 return cacheResult; 098 } 099 100 int denied = 0; 101 102 // if this is the online project, write is rejected 103 if (dbc.currentProject().isOnlineProject()) { 104 denied |= CmsPermissionSet.PERMISSION_WRITE; 105 } 106 107 // check if the current user is admin 108 boolean canIgnorePermissions = m_securityManager.hasRoleForResource( 109 dbc, 110 dbc.currentUser(), 111 CmsRole.VFS_MANAGER, 112 resource); 113 114 // check lock status 115 boolean writeRequired = requiredPermissions.requiresWritePermission() 116 || requiredPermissions.requiresControlPermission(); 117 118 // if the resource type is jsp 119 // write is only allowed for administrators 120 if (writeRequired && !canIgnorePermissions && (CmsResourceTypeJsp.isJsp(resource))) { 121 if (!m_securityManager.hasRoleForResource(dbc, dbc.currentUser(), CmsRole.VFS_MANAGER, resource)) { 122 denied |= CmsPermissionSet.PERMISSION_WRITE; 123 denied |= CmsPermissionSet.PERMISSION_CONTROL; 124 } 125 } 126 127 if (writeRequired && checkLock) { 128 // check lock state only if required 129 CmsLock lock = m_driverManager.getLock(dbc, resource); 130 // if the resource is not locked by the current user, write and control 131 // access must cause a permission error that must not be cached 132 if (lock.isUnlocked() || !lock.isLockableBy(dbc.currentUser())) { 133 return I_CmsPermissionHandler.PERM_NOTLOCKED; 134 } 135 } 136 137 CmsPermissionSetCustom permissions; 138 if (canIgnorePermissions) { 139 // if the current user is administrator, anything is allowed 140 permissions = new CmsPermissionSetCustom(~0); 141 } else { 142 // otherwise, get the permissions from the access control list 143 permissions = m_driverManager.getPermissions(dbc, resource, dbc.currentUser()); 144 } 145 146 // revoke the denied permissions 147 permissions.denyPermissions(denied); 148 149 if ((permissions.getPermissions() & CmsPermissionSet.PERMISSION_VIEW) == 0) { 150 // resource "invisible" flag is set for this user 151 if (!canIgnorePermissions && filter.requireVisible()) { 152 // filter requires visible permission - extend required permission set 153 requiredPermissions = new CmsPermissionSet( 154 requiredPermissions.getAllowedPermissions() | CmsPermissionSet.PERMISSION_VIEW, 155 requiredPermissions.getDeniedPermissions()); 156 } else { 157 // view permissions can be ignored by filter 158 permissions.setPermissions( 159 // modify permissions so that view is allowed 160 permissions.getAllowedPermissions() | CmsPermissionSet.PERMISSION_VIEW, 161 permissions.getDeniedPermissions() & ~CmsPermissionSet.PERMISSION_VIEW); 162 } 163 } 164 165 if (requiredPermissions.requiresDirectPublishPermission()) { 166 // direct publish permission is required 167 if ((permissions.getPermissions() & CmsPermissionSet.PERMISSION_DIRECT_PUBLISH) == 0) { 168 // but the user has no direct publish permission, so check if the user has the project manager role 169 boolean canIgnorePublishPermission = m_securityManager.hasRoleForResource( 170 dbc, 171 dbc.currentUser(), 172 CmsRole.PROJECT_MANAGER, 173 resource); 174 // if not, check the manageable projects 175 if (!canIgnorePublishPermission) { 176 CmsUser user = dbc.currentUser(); 177 Iterator<CmsProject> itProjects = m_driverManager.getAllManageableProjects( 178 dbc, 179 m_driverManager.readOrganizationalUnit(dbc, user.getOuFqn()), 180 true).iterator(); 181 while (itProjects.hasNext()) { 182 CmsProject project = itProjects.next(); 183 if (CmsProject.isInsideProject(m_driverManager.readProjectResources(dbc, project), resource)) { 184 canIgnorePublishPermission = true; 185 break; 186 } 187 } 188 } 189 190 if (canIgnorePublishPermission) { 191 // direct publish permission can be ignored 192 permissions.setPermissions( 193 // modify permissions so that direct publish is allowed 194 permissions.getAllowedPermissions() | CmsPermissionSet.PERMISSION_DIRECT_PUBLISH, 195 permissions.getDeniedPermissions() & ~CmsPermissionSet.PERMISSION_DIRECT_PUBLISH); 196 } 197 } 198 } 199 200 CmsPermissionCheckResult result; 201 if ((requiredPermissions.getPermissions() 202 & (permissions.getPermissions())) == requiredPermissions.getPermissions()) { 203 result = I_CmsPermissionHandler.PERM_ALLOWED; 204 } else { 205 result = I_CmsPermissionHandler.PERM_DENIED; 206 if (LOG.isDebugEnabled()) { 207 LOG.debug( 208 Messages.get().getBundle().key( 209 Messages.LOG_NO_PERMISSION_RESOURCE_USER_4, 210 new Object[] { 211 dbc.getRequestContext().removeSiteRoot(resource.getRootPath()), 212 dbc.currentUser().getName(), 213 requiredPermissions.getPermissionString(), 214 permissions.getPermissionString()})); 215 } 216 } 217 if (dbc.getProjectId().isNullUUID()) { 218 OpenCms.getMemoryMonitor().cachePermission(cacheKey, result); 219 } 220 221 return result; 222 } 223 224 /** 225 * @see org.opencms.security.I_CmsPermissionHandler#init(org.opencms.db.CmsDriverManager, CmsSystemConfiguration) 226 */ 227 public void init(CmsDriverManager driverManager, CmsSystemConfiguration systemConfiguration) { 228 229 m_driverManager = driverManager; 230 m_securityManager = driverManager.getSecurityManager(); 231 232 CmsCacheSettings settings = systemConfiguration.getCacheSettings(); 233 234 String className = settings.getCacheKeyGenerator(); 235 try { 236 // initialize the key generator 237 m_keyGenerator = (I_CmsCacheKey)Class.forName(className).newInstance(); 238 } catch (Exception e) { 239 throw new CmsInitException( 240 org.opencms.main.Messages.get().container( 241 org.opencms.main.Messages.ERR_CRITICAL_CLASS_CREATION_1, 242 className), 243 e); 244 } 245 } 246}