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