001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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, please see the 018 * company website: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://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.tools.accounts; 029 030import org.opencms.file.CmsGroup; 031import org.opencms.file.CmsObject; 032import org.opencms.file.CmsResource; 033import org.opencms.file.CmsResourceFilter; 034import org.opencms.file.CmsUser; 035import org.opencms.jsp.CmsJspActionElement; 036import org.opencms.main.CmsException; 037import org.opencms.main.CmsLog; 038import org.opencms.main.OpenCms; 039import org.opencms.security.CmsAccessControlEntry; 040import org.opencms.security.CmsRole; 041import org.opencms.util.CmsUUID; 042import org.opencms.workplace.list.A_CmsListDialog; 043import org.opencms.workplace.list.CmsListColumnDefinition; 044import org.opencms.workplace.list.CmsListCsvExportIAction; 045import org.opencms.workplace.list.CmsListItem; 046import org.opencms.workplace.list.CmsListMetadata; 047import org.opencms.workplace.list.CmsListMetadata.I_CsvItemFormatter; 048import org.opencms.workplace.list.CmsListOrderEnum; 049import org.opencms.workplace.list.CmsListSearchAction; 050 051import java.io.IOException; 052import java.io.StringWriter; 053import java.util.ArrayList; 054import java.util.Arrays; 055import java.util.Collection; 056import java.util.HashSet; 057import java.util.List; 058import java.util.Locale; 059import java.util.Set; 060 061import org.apache.commons.logging.Log; 062 063import com.google.common.collect.ArrayListMultimap; 064import com.google.common.collect.Multimap; 065 066import au.com.bytecode.opencsv.CSVWriter; 067import jakarta.servlet.http.HttpServletRequest; 068import jakarta.servlet.http.HttpServletResponse; 069import jakarta.servlet.jsp.PageContext; 070 071/** 072 * Group dependencies list view.<p> 073 */ 074public class CmsAllPrincipalDependenciesList extends A_CmsListDialog { 075 076 /** 077 * Helper class for generating the list entries. 078 */ 079 protected static class ElementGenerator { 080 081 /** The access control entry cache. */ 082 private Multimap<CmsUUID, CmsAccessControlEntry> m_ace; 083 084 /** The CMS object used for file operations. */ 085 private CmsObject m_cms; 086 087 /** The generated list entries. */ 088 private List<String[]> m_entries = new ArrayList<String[]>(); 089 090 /** 091 * Creates a new instance.<p> 092 * 093 * @param cms the CMS context to use for file operations 094 * 095 * @throws CmsException if something goes wrong 096 */ 097 public ElementGenerator(CmsObject cms) 098 throws CmsException { 099 100 m_cms = OpenCms.initCmsObject(cms); 101 m_cms.getRequestContext().setSiteRoot(""); 102 } 103 104 /** 105 * Generates the list entries.<p> 106 * 107 * @return a list of string arrays of the form ( name, credential, permissions, path ) 108 * 109 * @throws CmsException if something goes wrong 110 */ 111 public List<String[]> generateEntries() throws CmsException { 112 113 Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms); 114 addDirectEntries( 115 CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_ID, 116 CmsAccessControlEntry.PRINCIPAL_OVERWRITE_ALL_NAME, 117 locale); 118 addDirectEntries( 119 CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_ID, 120 CmsAccessControlEntry.PRINCIPAL_ALL_OTHERS_NAME, 121 locale); 122 for (CmsUser user : getUsers()) { 123 CmsUUID userId = user.getId(); 124 String name = user.getName(); 125 addDirectEntries(userId, name, locale); 126 for (CmsGroup group : m_cms.getGroupsOfUser(user.getName(), false)) { 127 for (CmsAccessControlEntry ace : getAces(group.getId())) { 128 for (CmsResource resource : getResources(ace.getResource())) { 129 String credentials = Messages.get().getBundle(locale).key( 130 Messages.GUI_CREDENTIAL_GROUP_1, 131 group.getName()); 132 addEntry( 133 user.getName(), 134 credentials, 135 getAceString(ace), 136 137 resource.getRootPath()); 138 139 } 140 } 141 } 142 Set<CmsUUID> processedRoles = new HashSet<CmsUUID>(); 143 List<CmsRole> roles = OpenCms.getRoleManager().getRolesOfUser( 144 m_cms, 145 user.getName(), 146 "", 147 true, 148 false, 149 true); 150 for (CmsRole role : roles) { 151 // only generate one entry for each role, independent of the number of OUs 152 if (processedRoles.contains(role.getId())) { 153 continue; 154 } else { 155 processedRoles.add(role.getId()); 156 } 157 for (CmsAccessControlEntry ace : getAces(role.getId())) { 158 for (CmsResource resource : getResources(ace.getResource())) { 159 String credentials = Messages.get().getBundle(locale).key( 160 Messages.GUI_CREDENTIAL_ROLE_1, 161 role.getName(locale)); 162 addEntry( 163 user.getName(), 164 credentials, 165 getAceString(ace), 166 167 resource.getRootPath()); 168 169 } 170 } 171 } 172 } 173 LOG.info("Generated " + m_entries.size() + " entries for " + this.getClass().getName()); 174 return m_entries; 175 } 176 177 /** 178 * Helper method to add the direct ACEs for a principal.<p> 179 * 180 * @param principalId the principal id 181 * @param name the principal name 182 * @param locale the locale 183 * 184 * @throws CmsException if something goes wrong 185 */ 186 protected void addDirectEntries(CmsUUID principalId, String name, Locale locale) throws CmsException { 187 188 for (CmsAccessControlEntry ace : getAces(principalId)) { 189 for (CmsResource resource : getResources(ace.getResource())) { 190 String credentials = Messages.get().getBundle(locale).key(Messages.GUI_CREDENTIAL_DIRECT_0); 191 addEntry(name, credentials, getAceString(ace), resource.getRootPath()); 192 } 193 } 194 } 195 196 /** 197 * Adds a new entry.<p> 198 * 199 * @param user the user name 200 * @param principal the credential name 201 * @param permissions the permission string 202 * @param path the resource path 203 */ 204 private void addEntry(String user, String principal, String permissions, String path) { 205 206 m_entries.add(new String[] {user, "" + principal, permissions, path}); 207 } 208 209 /** 210 * Gets the access control entries for a given principal id.<p> 211 * 212 * @param principalId the principal id 213 * @return the access control entries for that principal id 214 * 215 * @throws CmsException if something goes wrong 216 */ 217 private Collection<CmsAccessControlEntry> getAces(CmsUUID principalId) throws CmsException { 218 219 if (m_ace == null) { 220 m_ace = ArrayListMultimap.create(); 221 List<CmsAccessControlEntry> entries = m_cms.getAllAccessControlEntries(); 222 for (CmsAccessControlEntry entry : entries) { 223 m_ace.put(entry.getPrincipal(), entry); 224 } 225 } 226 return m_ace.get(principalId); 227 } 228 229 /** 230 * Creates a string representation of an access control entry.<p> 231 * 232 * @param ace the access control entry 233 * 234 * @return the string representation of the access control entry 235 */ 236 private String getAceString(CmsAccessControlEntry ace) { 237 238 String result = ace.getPermissions().getPermissionString() 239 + (ace.isResponsible() ? ace.getResponsibleString() : "") 240 + ace.getInheritingString(); 241 if ((ace.getFlags() & CmsAccessControlEntry.ACCESS_FLAGS_OVERWRITE) != 0) { 242 result = result 243 + " (" 244 + Messages.get().getBundle(OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms)).key( 245 Messages.GUI_PERMISSION_COLUMN_OVERWRITE_0) 246 + ")"; 247 } 248 return result; 249 250 } 251 252 /** 253 * Reads all resources with a given resource id.<p> 254 * 255 * @param resourceId the resource id 256 * @return the resources with the given id 257 * @throws CmsException if something goes wrong 258 */ 259 private List<CmsResource> getResources(CmsUUID resourceId) throws CmsException { 260 261 return m_cms.readSiblingsForResourceId(resourceId, CmsResourceFilter.ALL); 262 } 263 264 /** 265 * Gets all users.<p> 266 * 267 * @return the list of all users 268 * 269 * @throws CmsException if something goes wrong 270 */ 271 private List<CmsUser> getUsers() throws CmsException { 272 273 List<CmsUser> users = OpenCms.getOrgUnitManager().getUsersWithoutAdditionalInfo(m_cms, "", true); 274 return users; 275 } 276 277 } 278 279 /**Column id. */ 280 public static final String LIST_COLUMN_CREDENTIAL = "apxu_credential"; 281 282 /**Column id. */ 283 public static final String LIST_COLUMN_PERMISSIONS = "apxu_permissions"; 284 285 /**Column id. */ 286 public static final String LIST_COLUMN_USER = "apxu_user"; 287 288 /** List id constant. */ 289 public static final String LIST_ID = "allpermissionsxusers"; 290 291 /** Logger instance for this class. */ 292 public static final Log LOG = CmsLog.getLog(CmsAllPrincipalDependenciesList.class); 293 294 /**Column id. */ 295 static final String LIST_COLUMN_PATH = "apxu_path"; 296 297 /** 298 * Public constructor.<p> 299 * 300 * @param jsp an initialized JSP action element 301 */ 302 public CmsAllPrincipalDependenciesList(CmsJspActionElement jsp) { 303 304 this(LIST_ID, jsp); 305 } 306 307 /** 308 * Public constructor with JSP variables.<p> 309 * 310 * @param context the JSP page context 311 * @param req the JSP request 312 * @param res the JSP response 313 */ 314 public CmsAllPrincipalDependenciesList(PageContext context, HttpServletRequest req, HttpServletResponse res) { 315 316 this(new CmsJspActionElement(context, req, res)); 317 } 318 319 /** 320 * Protected constructor.<p> 321 * 322 * @param listId the id of the specialized list 323 * @param jsp an initialized JSP action element 324 */ 325 protected CmsAllPrincipalDependenciesList(String listId, CmsJspActionElement jsp) { 326 327 super( 328 jsp, 329 listId, 330 Messages.get().container(Messages.GUI_ALL_PRINCIPAL_DEPENDENCIES_LIST_0), 331 LIST_COLUMN_USER, 332 CmsListOrderEnum.ORDER_ASCENDING, 333 LIST_COLUMN_USER); 334 } 335 336 /** 337 * @see org.opencms.workplace.list.A_CmsListDialog#executeListMultiActions() 338 */ 339 @Override 340 public void executeListMultiActions() { 341 342 throwListUnsupportedActionException(); 343 } 344 345 /** 346 * @see org.opencms.workplace.list.A_CmsListDialog#executeListSingleActions() 347 */ 348 @Override 349 public void executeListSingleActions() { 350 351 throwListUnsupportedActionException(); 352 } 353 354 /** 355 * @see org.opencms.workplace.CmsWorkplace#decodeParamValue(java.lang.String, java.lang.String) 356 * 357 * Overridden because we don't want to 'decode' '+' characters for the search 358 */ 359 @Override 360 protected String decodeParamValue(String paramName, String paramValue) { 361 362 return paramValue; 363 } 364 365 /** 366 * @see org.opencms.workplace.list.A_CmsListDialog#fillDetails(java.lang.String) 367 */ 368 @Override 369 protected void fillDetails(String detailId) { 370 371 // no-op 372 } 373 374 /** 375 * @see org.opencms.workplace.list.A_CmsListDialog#getListItems() 376 */ 377 @Override 378 protected List<CmsListItem> getListItems() throws CmsException { 379 380 try { 381 382 ElementGenerator generator = new ElementGenerator(getCms()); 383 List<String[]> entries = generator.generateEntries(); 384 List<CmsListItem> result = new ArrayList<CmsListItem>(); 385 for (String[] entry : entries) { 386 String user = entry[0]; 387 String principal = entry[1]; 388 String permissions = entry[2]; 389 String path = entry[3]; 390 CmsListItem item = getList().newItem("" + user + "_" + principal + "_" + path); 391 item.set(LIST_COLUMN_USER, user); 392 item.set(LIST_COLUMN_CREDENTIAL, principal); 393 item.set(LIST_COLUMN_PERMISSIONS, permissions); 394 item.set(LIST_COLUMN_PATH, path); 395 result.add(item); 396 } 397 return result; 398 } catch (CmsException e) { 399 LOG.error(e.getLocalizedMessage(), e); 400 throw e; 401 } 402 } 403 404 /** 405 * @see org.opencms.workplace.CmsWorkplace#initMessages() 406 */ 407 @Override 408 protected void initMessages() { 409 410 // add specific dialog resource bundle 411 addMessages(Messages.get().getBundleName()); 412 // add cms dialog resource bundle 413 addMessages(org.opencms.workplace.Messages.get().getBundleName()); 414 // add default resource bundles 415 super.initMessages(); 416 } 417 418 /** 419 * @see org.opencms.workplace.list.A_CmsListDialog#setColumns(org.opencms.workplace.list.CmsListMetadata) 420 */ 421 @Override 422 protected void setColumns(CmsListMetadata metadata) { 423 424 CmsListColumnDefinition userCol = new CmsListColumnDefinition(LIST_COLUMN_USER); 425 userCol.setName(Messages.get().container(Messages.GUI_ALLDEP_LIST_COL_USER_0)); 426 427 CmsListColumnDefinition credentialCol = new CmsListColumnDefinition(LIST_COLUMN_CREDENTIAL); 428 credentialCol.setName(Messages.get().container(Messages.GUI_ALLDEP_LIST_COL_CREDENTIALS_0)); 429 430 CmsListColumnDefinition pathCol = new CmsListColumnDefinition(LIST_COLUMN_PATH); 431 pathCol.setName(Messages.get().container(Messages.GUI_ALLDEP_LIST_COL_PATH_0)); 432 433 CmsListColumnDefinition permCol = new CmsListColumnDefinition(LIST_COLUMN_PERMISSIONS); 434 permCol.setName(Messages.get().container(Messages.GUI_ALLDEP_LIST_COL_PERMISSIONS_0)); 435 436 List<CmsListColumnDefinition> columns = Arrays.asList(userCol, credentialCol, pathCol, permCol); 437 for (CmsListColumnDefinition col : columns) { 438 metadata.addColumn(col); 439 } 440 CmsListSearchAction searchAction = new CmsListSearchAction(metadata.getColumnDefinition(LIST_COLUMN_PATH)); 441 metadata.setSearchAction(searchAction); 442 for (CmsListColumnDefinition col : columns) { 443 if (!searchAction.getColumns().contains(col)) { 444 searchAction.addColumn(col); 445 } 446 } 447 metadata.setCsvItemFormatter(new I_CsvItemFormatter() { 448 449 public String csvHeader() { 450 451 return ""; 452 } 453 454 public String csvItem(CmsListItem item) { 455 456 StringWriter sw = new StringWriter(); 457 try { 458 CSVWriter csvWriter = new CSVWriter(sw); 459 try { 460 csvWriter.writeNext( 461 new String[] { 462 (String)item.get(LIST_COLUMN_USER), 463 (String)item.get(LIST_COLUMN_CREDENTIAL), 464 (String)item.get(LIST_COLUMN_PATH), 465 (String)item.get(LIST_COLUMN_PERMISSIONS)}); 466 } finally { 467 csvWriter.close(); 468 } 469 } catch (IOException e) { 470 // should never happen, log anyway 471 LOG.error(e.getLocalizedMessage(), e); 472 } 473 return sw.getBuffer().toString(); 474 } 475 }); 476 477 } 478 479 /** 480 * @see org.opencms.workplace.list.A_CmsListDialog#setIndependentActions(org.opencms.workplace.list.CmsListMetadata) 481 */ 482 @Override 483 protected void setIndependentActions(CmsListMetadata metadata) { 484 485 metadata.addIndependentAction(new CmsListCsvExportIAction()); 486 487 } 488 489 /** 490 * @see org.opencms.workplace.list.A_CmsListDialog#setMultiActions(org.opencms.workplace.list.CmsListMetadata) 491 */ 492 @Override 493 protected void setMultiActions(CmsListMetadata metadata) { 494 495 // no-op 496 } 497}