001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH (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, 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.util.CmsUUID; 031 032import java.util.Comparator; 033import java.util.StringTokenizer; 034 035/** 036 * An access control entry defines the permissions of a user or group for a distinct resource.<p> 037 * 038 * Besides the <code>CmsPermissionSet</code> to define the permissions, the access control entry 039 * contains the UUID of the resource and of the principal (user or group) who has the defined permissions. 040 * Since the principal is identified by its UUID, any other entity may act as principal also. 041 * 042 * <p>Additionally, the entry stores various flags:<br> 043 * <code>ACCESS_FLAGS_DELETED</code> indicates that this entry is deleted<br> 044 * <code>ACCESS_FLAGS_INHERIT</code> indicates that this entry should be inherited<br> 045 * <code>ACCESS_FLAGS_OVERWRITE</code> indicates that this entry overwrites inherited settings<br> 046 * <code>ACCESS_FLAGS_INHERITED</code> indicates that this entry is inherited<br> 047 * <code>ACCESS_FLAGS_USER</code> indicates that the principal is a single user<br> 048 * <code>ACCESS_FLAGS_GROUP</code> indicates that the principal is a group 049 * </p> 050 * 051 * @since 6.0.0 052 */ 053public class CmsAccessControlEntry { 054 055 /** Flag to indicate the principal type 'all others'. */ 056 public static final int ACCESS_FLAGS_ALLOTHERS = 128; 057 058 /** Flag to indicate the principal type group. */ 059 public static final int ACCESS_FLAGS_GROUP = 32; 060 061 /** Flag to indicate that an access control entry should be inherited. */ 062 public static final int ACCESS_FLAGS_INHERIT = 2; 063 064 /** Flag to indicate that an access control entry was inherited (read only). */ 065 public static final int ACCESS_FLAGS_INHERITED = 8; 066 067 /** Flag to indicate that an access control entry overwrites inherited entries. */ 068 public static final int ACCESS_FLAGS_OVERWRITE = 4; 069 070 /** Flag to indicate the principal type 'overwrite all'. */ 071 public static final int ACCESS_FLAGS_OVERWRITE_ALL = 256; 072 073 /** Flag to indicate that the principal is responsible for the resource. */ 074 public static final int ACCESS_FLAGS_RESPONSIBLE = 64; 075 076 /** Flag to indicate the principal type role. */ 077 public static final int ACCESS_FLAGS_ROLE = 512; 078 079 /** Flag to indicate the principal type user. */ 080 public static final int ACCESS_FLAGS_USER = 16; 081 082 /** 083 * ACE comparator.<p> 084 * 085 * Sorts the given list of {@link CmsAccessControlEntry} objects.<p> 086 * 087 * The 'overwrite all' ace in first place, the 'all others' ace in second place.<p> 088 */ 089 public static final Comparator<CmsAccessControlEntry> COMPARATOR_ACE = new Comparator<CmsAccessControlEntry>() { 090 091 /** 092 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) 093 */ 094 public int compare(CmsAccessControlEntry ace1, CmsAccessControlEntry ace2) { 095 096 if (ace1 == ace2) { 097 return 0; 098 } 099 CmsUUID id1 = (ace1).getPrincipal(); 100 CmsUUID id2 = (ace2).getPrincipal(); 101 return COMPARATOR_PRINCIPALS.compare(id1, id2); 102 } 103 }; 104 105 /** 106 * ACE principals comparator.<p> 107 * 108 * Sorts the given list of {@link CmsAccessControlEntry} objects.<p> 109 * 110 * The 'overwrite all' ace in first place, the 'all others' ace in second place.<p> 111 */ 112 public static final Comparator<CmsUUID> COMPARATOR_PRINCIPALS = new Comparator<CmsUUID>() { 113 114 /** 115 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) 116 */ 117 public int compare(CmsUUID id1, CmsUUID id2) { 118 119 if (id1 == id2) { 120 return 0; 121 } 122 if (id1.equals(id2)) { 123 return 0; 124 } else if (id1.equals(PRINCIPAL_OVERWRITE_ALL_ID)) { 125 return -1; 126 } else if (id1.equals(PRINCIPAL_ALL_OTHERS_ID)) { 127 if (id2.equals(PRINCIPAL_OVERWRITE_ALL_ID)) { 128 return 1; 129 } else { 130 return -1; 131 } 132 } else if (id2.equals(PRINCIPAL_ALL_OTHERS_ID)) { 133 if (id1.equals(PRINCIPAL_OVERWRITE_ALL_ID)) { 134 return -1; 135 } else { 136 return 1; 137 } 138 } else if (id2.equals(PRINCIPAL_OVERWRITE_ALL_ID)) { 139 return 1; 140 } 141 return id1.compareTo(id2); 142 } 143 }; 144 145 /** The used id for ace's that apply to all other principals. */ 146 public static final CmsUUID PRINCIPAL_ALL_OTHERS_ID; 147 148 /** The used name for ace's that apply to all other principals. */ 149 public static final String PRINCIPAL_ALL_OTHERS_NAME = "ALL_OTHERS"; 150 151 /** The used id for ace's that overwrites all inherited permissions. */ 152 public static final CmsUUID PRINCIPAL_OVERWRITE_ALL_ID; 153 154 /** The used name for ace's that overwrites all inherited permissions. */ 155 public static final String PRINCIPAL_OVERWRITE_ALL_NAME = "OVERWRITE_ALL"; 156 157 /** UUID which is used to read all access control entries, should never be written to the database. */ 158 public static final CmsUUID PRINCIPAL_READALL_ID; 159 160 /** Flags of this access control entry. */ 161 private int m_flags; 162 163 /** The permission set. */ 164 private CmsPermissionSetCustom m_permissions; 165 166 /** Id of the principal. */ 167 private CmsUUID m_principal; 168 169 /** Id of the resource. */ 170 private CmsUUID m_resource; 171 172 /** 173 * Constructor to create a new access control entry for a given resource 174 * based on an existing access control entry.<p> 175 * 176 * @param resource the resource 177 * @param base the base for the created access control entry 178 */ 179 public CmsAccessControlEntry(CmsUUID resource, CmsAccessControlEntry base) { 180 181 m_resource = resource; 182 m_principal = base.m_principal; 183 m_permissions = base.m_permissions; 184 m_flags = base.m_flags; 185 } 186 187 /** 188 * Constructor to create a new access control entry on a given resource and a given principal.<p> 189 * Permissions are specified as permission set, flags as bitset. 190 * 191 * @param resource the resource 192 * @param principal the id of a principal (user or group) 193 * @param permissions the set of allowed and denied permissions as permission set 194 * @param flags additional flags of the access control entry 195 */ 196 public CmsAccessControlEntry(CmsUUID resource, CmsUUID principal, CmsPermissionSet permissions, int flags) { 197 198 m_resource = resource; 199 m_principal = principal; 200 m_permissions = new CmsPermissionSetCustom(permissions); 201 m_flags = flags; 202 } 203 204 /** 205 * Constructor to create a new access control entry on a given resource and a given principal.<p> 206 * Permissions and flags are specified as bitsets. 207 * 208 * @see CmsPermissionSet 209 * 210 * @param resource the resource 211 * @param principal the id of a principal (user or group) 212 * @param allowed the set of allowed permissions 213 * @param denied set set of explicitly denied permissions 214 * @param flags additional flags of the access control entry 215 */ 216 public CmsAccessControlEntry(CmsUUID resource, CmsUUID principal, int allowed, int denied, int flags) { 217 218 m_resource = resource; 219 m_principal = principal; 220 m_permissions = new CmsPermissionSetCustom(allowed, denied); 221 m_flags = flags; 222 } 223 224 /** 225 * Constructor to create a new access control entry on a given resource and a given principal.<p> 226 * Permission and flags are specified as string of the format {{+|-}{r|w|v|c|i}}* 227 * 228 * @param resource the resource 229 * @param principal the id of a principal (user or group) 230 * @param acPermissionString allowed and denied permissions and also flags 231 */ 232 public CmsAccessControlEntry(CmsUUID resource, CmsUUID principal, String acPermissionString) { 233 234 m_resource = resource; 235 m_principal = principal; 236 m_flags = 0; 237 238 StringTokenizer tok = new StringTokenizer(acPermissionString, "+-", true); 239 StringBuffer permissionString = new StringBuffer(); 240 241 while (tok.hasMoreElements()) { 242 String prefix = tok.nextToken(); 243 String suffix = tok.nextToken(); 244 switch (suffix.charAt(0)) { 245 case 'I': 246 case 'i': 247 if (prefix.charAt(0) == '+') { 248 m_flags |= CmsAccessControlEntry.ACCESS_FLAGS_INHERIT; 249 } 250 if (prefix.charAt(0) == '-') { 251 m_flags &= ~CmsAccessControlEntry.ACCESS_FLAGS_INHERIT; 252 } 253 break; 254 case 'O': 255 case 'o': 256 if (prefix.charAt(0) == '+') { 257 m_flags |= CmsAccessControlEntry.ACCESS_FLAGS_OVERWRITE; 258 } 259 if (prefix.charAt(0) == '-') { 260 m_flags &= ~CmsAccessControlEntry.ACCESS_FLAGS_OVERWRITE; 261 } 262 break; 263 case 'L': 264 case 'l': 265 if (prefix.charAt(0) == '+') { 266 m_flags |= CmsAccessControlEntry.ACCESS_FLAGS_RESPONSIBLE; 267 } 268 if (prefix.charAt(0) == '-') { 269 m_flags &= ~CmsAccessControlEntry.ACCESS_FLAGS_RESPONSIBLE; 270 } 271 break; 272 default: 273 permissionString.append(prefix); 274 permissionString.append(suffix); 275 break; 276 } 277 } 278 279 m_permissions = new CmsPermissionSetCustom(permissionString.toString()); 280 } 281 282 static { 283 PRINCIPAL_ALL_OTHERS_ID = CmsUUID.getConstantUUID(PRINCIPAL_ALL_OTHERS_NAME.toLowerCase()); 284 PRINCIPAL_OVERWRITE_ALL_ID = CmsUUID.getConstantUUID(PRINCIPAL_OVERWRITE_ALL_NAME.toLowerCase()); 285 PRINCIPAL_READALL_ID = CmsUUID.getConstantUUID("principal-read-all"); 286 } 287 288 /** 289 * Sets the explicitly denied permissions in the access control entry.<p> 290 * 291 * @param denied the denied permissions as bitset 292 */ 293 public void denyPermissions(int denied) { 294 295 m_permissions.denyPermissions(denied); 296 } 297 298 /** 299 * @see java.lang.Object#equals(java.lang.Object) 300 */ 301 @Override 302 public boolean equals(Object obj) { 303 304 if (obj == this) { 305 return true; 306 } 307 if (obj instanceof CmsAccessControlEntry) { 308 CmsAccessControlEntry other = (CmsAccessControlEntry)obj; 309 if (other.m_flags != m_flags) { 310 return false; 311 } 312 if (other.getPermissions().getAllowedPermissions() != getPermissions().getAllowedPermissions()) { 313 return false; 314 } 315 if (other.getPermissions().getDeniedPermissions() != getPermissions().getDeniedPermissions()) { 316 return false; 317 } 318 if (!other.m_resource.equals(m_resource)) { 319 return false; 320 } 321 if (!other.m_principal.equals(m_principal)) { 322 return false; 323 } 324 return true; 325 } 326 return false; 327 } 328 329 /** 330 * Returns the currently allowed permissions as bitset.<p> 331 * 332 * @return the allowed permissions 333 */ 334 public int getAllowedPermissions() { 335 336 return m_permissions.getAllowedPermissions(); 337 } 338 339 /** 340 * Returns the currently denied permissions as bitset.<p> 341 * 342 * @return the denied permissions 343 */ 344 public int getDeniedPermissions() { 345 346 return m_permissions.getDeniedPermissions(); 347 } 348 349 /** 350 * Returns the current flags of the access control entry.<p> 351 * 352 * @return bitset with flag values 353 */ 354 public int getFlags() { 355 356 return m_flags; 357 } 358 359 /** 360 * Returns the string representation of the "inherit" flag.<p> 361 * 362 * @return string of the format {{+|-}i}* 363 */ 364 public String getInheritingString() { 365 366 if (isInheriting()) { 367 return "+i"; 368 } else { 369 return "-i"; 370 } 371 } 372 373 /** 374 * Returns the current permission set (both allowed and denied permissions).<p> 375 * 376 * @return the set of permissions 377 */ 378 public CmsPermissionSet getPermissions() { 379 380 return m_permissions; 381 } 382 383 /** 384 * Returns the principal assigned with this access control entry.<p> 385 * 386 * @return the principal 387 */ 388 public CmsUUID getPrincipal() { 389 390 return m_principal; 391 } 392 393 /** 394 * Returns the resource assigned with this access control entry.<p> 395 * 396 * @return the resource 397 */ 398 public CmsUUID getResource() { 399 400 return m_resource; 401 } 402 403 /** 404 * Returns the string representation of the "responsible" flag.<p> 405 * 406 * @return string of the format {{+|-}l}* 407 */ 408 public String getResponsibleString() { 409 410 if (isResponsible()) { 411 return "+l"; 412 } else { 413 return "-l"; 414 } 415 } 416 417 /** 418 * Sets the allowed permissions in the access control entry.<p> 419 * 420 * @param allowed the allowed permissions as bitset 421 */ 422 public void grantPermissions(int allowed) { 423 424 m_permissions.grantPermissions(allowed); 425 } 426 427 /** 428 * @see java.lang.Object#hashCode() 429 */ 430 @Override 431 public int hashCode() { 432 433 if (m_permissions != null) { 434 return m_permissions.hashCode() * m_flags; 435 } 436 return CmsUUID.getNullUUID().hashCode(); 437 } 438 439 /** 440 * Checks if the {@link #ACCESS_FLAGS_ALLOTHERS} flag is set.<p> 441 * 442 * @return <code>true</code> if the {@link #ACCESS_FLAGS_ALLOTHERS} flag is set 443 */ 444 public boolean isAllOthers() { 445 446 return (m_flags & ACCESS_FLAGS_ALLOTHERS) == ACCESS_FLAGS_ALLOTHERS; 447 } 448 449 /** 450 * Returns if this access control entry has the inherited flag set.<p> 451 * Note: to check if an access control entry is inherited, also the 452 * resource id and the id of the current resource must be different. 453 * 454 * @return true, if the inherited flag is set 455 */ 456 public boolean isInherited() { 457 458 return ((m_flags & CmsAccessControlEntry.ACCESS_FLAGS_INHERITED) > 0); 459 } 460 461 /** 462 * Returns if this ace is being inherited to the folder subresources.<p> 463 * 464 * @return <code>true</code>, if this ace is being inherited to the folder subresources 465 */ 466 public boolean isInheriting() { 467 468 return ((m_flags & CmsAccessControlEntry.ACCESS_FLAGS_INHERIT) > 0); 469 } 470 471 /** 472 * Checks if the {@link #ACCESS_FLAGS_OVERWRITE_ALL} flag is set.<p> 473 * 474 * @return <code>true</code> if the {@link #ACCESS_FLAGS_OVERWRITE_ALL} flag is set 475 */ 476 public boolean isOverwriteAll() { 477 478 return (m_flags & ACCESS_FLAGS_OVERWRITE_ALL) == ACCESS_FLAGS_OVERWRITE_ALL; 479 } 480 481 /** 482 * Returns if the principal is responsible for the current resource.<p> 483 * 484 * @return true ,if the principal is responsible for the current resource 485 */ 486 public boolean isResponsible() { 487 488 return ((m_flags & CmsAccessControlEntry.ACCESS_FLAGS_RESPONSIBLE) > 0); 489 } 490 491 /** 492 * Resets the given flags in the access control entry.<p> 493 * 494 * @param flags bitset with flag values to reset 495 */ 496 public void resetFlags(int flags) { 497 498 m_flags &= ~flags; 499 } 500 501 /** 502 * Sets the given flags in the access control entry.<p> 503 * 504 * @param flags bitset with flag values to set 505 */ 506 public void setFlags(int flags) { 507 508 m_flags |= flags; 509 } 510 511 /** 512 * Sets the access flags to identify the given principal type.<p> 513 * 514 * @param principal the principal to set the flags for 515 */ 516 public void setFlagsForPrincipal(I_CmsPrincipal principal) { 517 518 setFlags( 519 principal.isGroup() ? CmsAccessControlEntry.ACCESS_FLAGS_GROUP : CmsAccessControlEntry.ACCESS_FLAGS_USER); 520 } 521 522 /** 523 * Sets the allowed and denied permissions of the access control entry.<p> 524 * 525 * @param permissions the set of permissions 526 */ 527 public void setPermissions(CmsPermissionSet permissions) { 528 529 m_permissions.setPermissions(permissions); 530 } 531 532 /** 533 * Returns the String representation of this access control entry object.<p> 534 * @see java.lang.Object#toString() 535 */ 536 @Override 537 public String toString() { 538 539 return "[Ace:] " 540 + "ResourceId=" 541 + m_resource 542 + ", PrincipalId=" 543 + m_principal 544 + ", Permissions=" 545 + m_permissions.toString() 546 + ", Flags=" 547 + m_flags; 548 } 549}