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.workplace.explorer; 029 030import org.opencms.file.CmsGroup; 031import org.opencms.file.CmsObject; 032import org.opencms.file.CmsResource; 033import org.opencms.file.CmsUser; 034import org.opencms.main.CmsException; 035import org.opencms.main.CmsLog; 036import org.opencms.main.OpenCms; 037import org.opencms.monitor.CmsMemoryMonitor; 038import org.opencms.security.CmsAccessControlEntry; 039import org.opencms.security.CmsAccessControlList; 040import org.opencms.security.CmsPermissionSet; 041import org.opencms.security.CmsPermissionSetCustom; 042import org.opencms.security.CmsRole; 043import org.opencms.security.I_CmsPrincipal; 044import org.opencms.util.CmsUUID; 045 046import java.io.Serializable; 047import java.util.HashMap; 048import java.util.Iterator; 049import java.util.List; 050import java.util.Map; 051 052import org.apache.commons.logging.Log; 053 054/** 055 * Explorer type access object, encapsulates access control entries and lists of a explorer type.<p> 056 * 057 * @since 6.0.0 058 */ 059public class CmsExplorerTypeAccess implements Serializable { 060 061 /** Principal key name for the default permission settings. */ 062 public static final String PRINCIPAL_DEFAULT = "DEFAULT"; 063 064 /** The listener used to flush cached access settings. */ 065 protected static CmsExplorerTypeAccessFlushListener flushListener; 066 067 /** The log object for this class. */ 068 private static final Log LOG = CmsLog.getLog(CmsExplorerTypeAccess.class); 069 070 /** The serial version id. */ 071 private static final long serialVersionUID = 1119068085158682112L; 072 073 static { 074 flushListener = new CmsExplorerTypeAccessFlushListener(); 075 flushListener.install(); 076 } 077 078 /** The map of configured access control entries. */ 079 private Map<String, String> m_accessControl; 080 081 /** The acl based on the map of configured access control entries. */ 082 private CmsAccessControlList m_accessControlList; 083 084 /** Cached permissions based on roles. */ 085 private transient Map<String, CmsPermissionSetCustom> m_permissionsCache; 086 087 /** 088 * Constructor, creates an empty, CmsExplorerTypeAccess object.<p> 089 */ 090 public CmsExplorerTypeAccess() { 091 092 m_accessControl = new HashMap<String, String>(); 093 flushListener.add(this); 094 } 095 096 /** 097 * Adds a single access entry to the map of access entries of the explorer type setting.<p> 098 * 099 * This stores the configuration data in a map which is used in the initialize process 100 * to create the access control list.<p> 101 * 102 * @param key the principal of the ace 103 * @param value the permissions for the principal 104 */ 105 public void addAccessEntry(String key, String value) { 106 107 m_accessControl.put(key, value); 108 if (LOG.isDebugEnabled()) { 109 LOG.debug(Messages.get().getBundle().key(Messages.LOG_ADD_ACCESS_ENTRY_2, key, value)); 110 } 111 } 112 113 /** 114 * Creates the access control list from the temporary map.<p> 115 * 116 * @param resourceType the name of the resource type 117 * 118 * @throws CmsException if something goes wrong 119 */ 120 public void createAccessControlList(String resourceType) throws CmsException { 121 122 if (OpenCms.getRunLevel() < OpenCms.RUNLEVEL_2_INITIALIZING) { 123 // we don't need this for simple test cases 124 return; 125 } 126 if (m_permissionsCache == null) { 127 m_permissionsCache = CmsMemoryMonitor.createLRUCacheMap(2048); 128 OpenCms.getMemoryMonitor().register(this.getClass().getName() + "." + resourceType, m_permissionsCache); 129 } else { 130 m_permissionsCache.clear(); 131 } 132 133 m_accessControlList = new CmsAccessControlList(); 134 Iterator<String> i = m_accessControl.keySet().iterator(); 135 while (i.hasNext()) { 136 String key = i.next(); 137 if (!PRINCIPAL_DEFAULT.equals(key)) { 138 String value = m_accessControl.get(key); 139 // get the principal name from the principal String 140 String principal = key.substring(key.indexOf('.') + 1, key.length()); 141 142 // create an OpenCms user context with "Guest" permissions 143 CmsObject cms = OpenCms.initCmsObject(OpenCms.getDefaultUsers().getUserGuest()); 144 145 CmsUUID principalId = null; 146 if (key.startsWith(I_CmsPrincipal.PRINCIPAL_GROUP)) { 147 // read the group 148 principal = OpenCms.getImportExportManager().translateGroup(principal); 149 try { 150 principalId = cms.readGroup(principal).getId(); 151 } catch (CmsException e) { 152 if (LOG.isErrorEnabled()) { 153 LOG.error(e.getLocalizedMessage(), e); 154 } 155 } 156 } else if (key.startsWith(I_CmsPrincipal.PRINCIPAL_USER)) { 157 // read the user 158 principal = OpenCms.getImportExportManager().translateUser(principal); 159 try { 160 principalId = cms.readUser(principal).getId(); 161 } catch (CmsException e) { 162 if (LOG.isErrorEnabled()) { 163 LOG.error(e.getLocalizedMessage(), e); 164 } 165 } 166 } else { 167 // read the role with role name 168 CmsRole role = CmsRole.valueOfRoleName(principal); 169 if (role == null) { 170 // try to read the role in the old fashion with group name 171 role = CmsRole.valueOfGroupName(principal); 172 } 173 principalId = role.getId(); 174 } 175 if (principalId != null) { 176 // create a new entry for the principal 177 CmsAccessControlEntry entry = new CmsAccessControlEntry(null, principalId, value); 178 m_accessControlList.add(entry); 179 } 180 } 181 } 182 } 183 184 /** 185 * Returns the computed access Control List.<p> 186 * 187 * @return the computed access Control List 188 */ 189 public CmsAccessControlList getAccessControlList() { 190 191 return m_accessControlList; 192 } 193 194 /** 195 * Returns the map of access entries of the explorer type setting.<p> 196 * 197 * @return the map of access entries of the explorer type setting 198 */ 199 public Map<String, String> getAccessEntries() { 200 201 return m_accessControl; 202 } 203 204 /** 205 * Calculates the permissions for this explorer type settings 206 * for the user in the given OpenCms user context.<p> 207 * 208 * @param cms the OpenCms user context to calculate the permissions for 209 * @param resource the resource to check the permissions for 210 * 211 * @return the permissions for this explorer type settings for the user in the given OpenCms user context 212 */ 213 public CmsPermissionSet getPermissions(CmsObject cms, CmsResource resource) { 214 215 String cacheKey = getPermissionsCacheKey(cms, resource); 216 CmsPermissionSetCustom permissions; 217 if (cacheKey != null) { 218 permissions = m_permissionsCache.get(cacheKey); 219 if (permissions != null) { 220 return permissions; 221 } 222 } 223 CmsAccessControlList acl = (CmsAccessControlList)m_accessControlList.clone(); 224 225 CmsUser user = cms.getRequestContext().getCurrentUser(); 226 List<CmsGroup> groups = null; 227 try { 228 groups = cms.getGroupsOfUser(user.getName(), false); 229 } catch (CmsException e) { 230 // error reading the groups of the current user 231 LOG.error(Messages.get().getBundle().key(Messages.LOG_READ_GROUPS_OF_USER_FAILED_1, user.getName()), e); 232 } 233 List<CmsRole> roles = null; 234 try { 235 roles = OpenCms.getRoleManager().getRolesForResource(cms, user, resource); 236 } catch (CmsException e) { 237 // error reading the roles of the current user 238 LOG.error(Messages.get().getBundle().key(Messages.LOG_READ_GROUPS_OF_USER_FAILED_1, user.getName()), e); 239 } 240 String defaultPermissions = m_accessControl.get(PRINCIPAL_DEFAULT); 241 // add the default permissions to the acl 242 if ((defaultPermissions != null) && !user.isGuestUser()) { 243 boolean found = false; 244 if (acl.getPermissions(user.getId()) != null) { 245 // acl already contains the user, no need for default 246 found = true; 247 } 248 if (!found && (groups != null)) { 249 // look up all groups to see if we need the default 250 Iterator<CmsGroup> itGroups = groups.iterator(); 251 while (itGroups.hasNext()) { 252 CmsGroup group = itGroups.next(); 253 if (acl.getPermissions(group.getId()) != null) { 254 // acl already contains the group, no need for default 255 found = true; 256 break; 257 } 258 } 259 } 260 if (!found && (roles != null)) { 261 // look up all roles to see if we need the default 262 Iterator<CmsRole> itRoles = roles.iterator(); 263 while (itRoles.hasNext()) { 264 CmsRole role = itRoles.next(); 265 if (acl.getPermissions(role.getId()) != null) { 266 // acl already contains the group, no need for default 267 found = true; 268 break; 269 } 270 } 271 } 272 if (!found) { 273 // add default access control settings for current user 274 CmsAccessControlEntry entry = new CmsAccessControlEntry(null, user.getId(), defaultPermissions); 275 acl.add(entry); 276 } 277 } 278 permissions = acl.getPermissions(user, groups, roles); 279 280 if (cacheKey != null) { 281 m_permissionsCache.put(cacheKey, permissions); 282 } 283 return permissions; 284 } 285 286 /** 287 * Tests if there are any access information stored.<p> 288 * 289 * @return true or false 290 */ 291 public boolean isEmpty() { 292 293 return m_accessControl.isEmpty(); 294 } 295 296 /** 297 * Flushes the permission cache.<p> 298 */ 299 protected void flushCache() { 300 301 if (m_permissionsCache != null) { 302 m_permissionsCache.clear(); 303 } 304 } 305 306 /** 307 * Returns the cache key for the roles and groups of the current user and the given resource.<p> 308 * 309 * In this way, it does not matter if the resource and/or user permissions changes, so we never need to clean the cache.<p> 310 * 311 * And since the cache is a LRU map, old trash entries will be automatically removed.<p> 312 * 313 * @param cms the current cms context 314 * @param resource the resource 315 * 316 * @return the cache key 317 */ 318 private String getPermissionsCacheKey(CmsObject cms, CmsResource resource) { 319 320 try { 321 String userName = cms.getRequestContext().getCurrentUser().getName(); 322 StringBuffer key = new StringBuffer(256); 323 key.append(resource.getRootPath()).append("_"); 324 Iterator<?> itGroups = cms.getGroupsOfUser(userName, true).iterator(); 325 while (itGroups.hasNext()) { 326 CmsGroup group = (CmsGroup)itGroups.next(); 327 key.append(group.getName()).append("_"); 328 } 329 Iterator<?> itRoles = OpenCms.getRoleManager().getRolesOfUser( 330 cms, 331 userName, 332 "", 333 true, 334 true, 335 false).iterator(); 336 while (itRoles.hasNext()) { 337 CmsRole role = (CmsRole)itRoles.next(); 338 key.append(role.getGroupName()).append("_"); 339 } 340 return key.toString(); 341 } catch (CmsException e) { 342 return null; 343 } 344 } 345}