Record Class AccessControlEntry

java.lang.Object
java.lang.Record
org.exoplatform.caldav.client.AccessControlEntry
Record Components:
principal - whom the entry applies to
inverted - whether it applies to everyone except that principal (DAV:invert)
deny - whether it denies rather than grants
privileges - the privileges granted or denied, as Clark names, never empty for a parsed entry
protectedEntry - whether the server marks it DAV:protected: it cannot be changed, and it is never sent back
inheritedFrom - the resource it is inherited from (DAV:inherited), null when it is this collection's own; an inherited entry is never sent back either

public record AccessControlEntry(AccessControlEntry.AcePrincipal principal, boolean inverted, boolean deny, Set<String> privileges, boolean protectedEntry, String inheritedFrom) extends Record
One access control entry of a collection's DAV:acl, as RFC 3744 §5.5 defines it: who it applies to, whether it grants or denies, which privileges, and whether the server lets it be changed (EXO-90253).

The client parses every entry into this shape entirely or not at all (CollectionAcl.understood()): an ACL request replaces every entry that is neither protected nor inherited (§8.1), so an entry this record could not represent would be deleted by writing the list back. The shape is therefore the whole grammar of §5.5 and no less.

Privileges are held as Clark names, {namespace}local — {DAV:}read, {urn:ietf:params:xml:ns:caldav}read-free-busy — so a privilege of any namespace survives the round trip.

  • Nested Class Summary

    Nested Classes
    Modifier and Type
    Class
    Description
    static final record 
    Whom an entry applies to: one of the six forms RFC 3744 §5.5.1 allows.
  • Field Summary

    Fields
    Modifier and Type
    Field
    Description
    static final String
    The namespace of CalDAV's elements.
    static final String
    The namespace of WebDAV's own elements.
    static final Set<String>
    The privileges an edit share may hold when it is read back (EXO-90378): the read-only set, DAV:write, and the members DAV:write aggregates (RFC 3744 §3.12) — write-properties, write-content, bind and unbind.
    static final String
    DAV:read, the privilege a "can view" share grants.
    static final Set<String>
    The privileges that let a principal see a calendar and nothing more: what "can view" means when an entry is read back.
    static final String
    DAV:write, the privilege a "can edit" share adds (EXO-90378).
  • Constructor Summary

    Constructors
    Constructor
    Description
    AccessControlEntry(AccessControlEntry.AcePrincipal principal, boolean inverted, boolean deny, Set<String> privileges, boolean protectedEntry, String inheritedFrom)
    Creates an instance of a AccessControlEntry record class.
  • Method Summary

    Modifier and Type
    Method
    Description
    boolean
    appliesTo(String canonicalPrincipal)
    Whether this entry names exactly one principal path, compared in the canonical form a recorded principal is held in.
    static String
    clark(String namespace, String localName)
    A Clark name: {namespace}local.
    boolean
    Returns the value of the deny record component.
    editGrantTo(String principalHref)
    The entry eXo writes to share a calendar for editing (EXO-90378): grant DAV:read and DAV:write to one principal, nothing else.
    final boolean
    Indicates whether some other object is "equal to" this one.
    boolean
    Whether this entry is a plain grant carrying exactly what an eXo edit share grants (EXO-90378): reading and writing the calendar, and nothing beyond EDIT_PRIVILEGES.
    boolean
    Whether this entry is of a shape eXo itself writes — a read-only grant or an edit grant (EXO-90378) — and may therefore be carried back unchanged in an ACL request without widening anybody's rights.
    boolean
    Whether this entry lets a principal read the calendar: a grant, not inverted, naming DAV:read or DAV:all.
    boolean
    Whether this entry is a plain grant carrying nothing beyond seeing the calendar.
    final int
    Returns a hash code value for this object.
    Returns the value of the inheritedFrom record component.
    boolean
    Returns the value of the inverted record component.
    boolean
    Whether an ACL request may carry this entry: neither protected nor inherited (RFC 3744 §8.1 leaves both where they are, and sending one is a conflict the server refuses).
    Returns the value of the principal record component.
    static String
    principalHrefOf(String canonicalPrincipal)
    The href a principal path is written as: every segment percent-encoded outside the unreserved set, and a trailing slash, since a principal is a collection.
    Returns the value of the privileges record component.
    boolean
    Returns the value of the protectedEntry record component.
    readGrantTo(String principalHref)
    The entry eXo writes to share a calendar: grant DAV:read to one principal, nothing else.
    final String
    Returns a string representation of this record class.

    Methods inherited from class java.lang.Object

    clone, finalize, getClass, notify, notifyAll, wait, wait, wait
  • Field Details

    • DAV_NS

      public static final String DAV_NS
      The namespace of WebDAV's own elements.
      See Also:
    • CALDAV_NS

      public static final String CALDAV_NS
      The namespace of CalDAV's elements.
      See Also:
    • READ

      public static final String READ
      DAV:read, the privilege a "can view" share grants.
    • WRITE

      public static final String WRITE
      DAV:write, the privilege a "can edit" share adds (EXO-90378). RFC 3744 §3.12 aggregates write-properties, write-content, bind and unbind under it — changing an event, adding one and removing one, which is what an edit share is for. A server may map it to more: on Stalwart it also lets the principal delete or rename the collection itself, see EDIT_PRIVILEGES.
    • READ_ONLY_PRIVILEGES

      public static final Set<String> READ_ONLY_PRIVILEGES
      The privileges that let a principal see a calendar and nothing more: what "can view" means when an entry is read back. DAV:read itself; read-current-user-privilege-set, which Stalwart reports beside it on a read share; and CALDAV:read-free-busy, which RFC 4791 §6.1.1 aggregates under DAV:read.
    • EDIT_PRIVILEGES

      public static final Set<String> EDIT_PRIVILEGES
      The privileges an edit share may hold when it is read back (EXO-90378): the read-only set, DAV:write, and the members DAV:write aggregates (RFC 3744 §3.12) — write-properties, write-content, bind and unbind.

      The grant eXo writes is narrower than this: DAV:read and DAV:write and nothing else, see editGrantTo(String). A server is free to report the aggregate's members beside it, exactly as it reports the read-ish privileges beside DAV:read, and Stalwart does: it stores our DAV:write as its own Modify, Delete, AddItems, ModifyItems, RemoveItems and reports those back as DAV:write plus DAV:write-properties (from Modify) and DAV:write-content (from ModifyItems) — crates/dav/src/common/acl.rs, validate_and_map_aces and current_user_privilege_set, stalwartlabs/stalwart v0.16.0.

      Leaving those two out is what made a grant that had landed read back as unrecognised, and eXo report a share it had really made as not applied. Nothing here widens eXo's own grant: every member is part of DAV:write itself. What DAV:write carries is the server's to say, though, and on Stalwart it is more than writing the calendar's events: the Delete and Modify it maps to also let the principal delete the collection itself, or change its name and properties (crates/dav/src/calendar/delete.rs and proppatch.rs, v0.16.0). That is accepted for a Can-edit share, because no Stalwart ACL grants deleting events without it. DAV:write-acl, DAV:read-acl, DAV:all, DAV:unlock, scheduling and vendor privileges stay outside it.

  • Constructor Details

    • AccessControlEntry

      public AccessControlEntry(AccessControlEntry.AcePrincipal principal, boolean inverted, boolean deny, Set<String> privileges, boolean protectedEntry, String inheritedFrom)
      Creates an instance of a AccessControlEntry record class.
      Parameters:
      principal - the value for the principal record component
      inverted - the value for the inverted record component
      deny - the value for the deny record component
      privileges - the value for the privileges record component
      protectedEntry - the value for the protectedEntry record component
      inheritedFrom - the value for the inheritedFrom record component
  • Method Details

    • readGrantTo

      public static AccessControlEntry readGrantTo(String principalHref)
      The entry eXo writes to share a calendar: grant DAV:read to one principal, nothing else.
      Parameters:
      principalHref - the principal's server-absolute href
      Returns:
      the entry
    • editGrantTo

      public static AccessControlEntry editGrantTo(String principalHref)
      The entry eXo writes to share a calendar for editing (EXO-90378): grant DAV:read and DAV:write to one principal, nothing else.

      DAV:read is written even though a colleague who may write must be able to read: it is what makes the entry recognisable. A grant carrying DAV:write and no read is what Stalwart reports for a right given through JMAP — "may delete", "may write all" — and eXo never writes that shape, so it can keep refusing to carry one back (grantsEditOnly() demands both).

      Parameters:
      principalHref - the principal's server-absolute href
      Returns:
      the entry
    • isModifiable

      public boolean isModifiable()
      Whether an ACL request may carry this entry: neither protected nor inherited (RFC 3744 §8.1 leaves both where they are, and sending one is a conflict the server refuses).
      Returns:
      true for an entry of this collection's own that may be rewritten
    • grantsRead

      public boolean grantsRead()
      Whether this entry lets a principal read the calendar: a grant, not inverted, naming DAV:read or DAV:all.
      Returns:
      true when it grants read
    • grantsReadOnly

      public boolean grantsReadOnly()
      Whether this entry is a plain grant carrying nothing beyond seeing the calendar.
      Returns:
      true when every privilege is a read-only one
    • grantsEditOnly

      public boolean grantsEditOnly()
      Whether this entry is a plain grant carrying exactly what an eXo edit share grants (EXO-90378): reading and writing the calendar, and nothing beyond EDIT_PRIVILEGES.

      Both DAV:read and DAV:write are required. That is what separates a grant eXo itself wrote from the one shape it must keep refusing: a bare DAV:write, which is how Stalwart reports a right given through JMAP, is not edit-only here, so writing the list back still stops rather than widening that right to full write. The aggregate itself is required, not merely its members, so a partial grant — content but not bind, say — is not mistaken for the whole.

      Returns:
      true when every privilege is an edit-share one and both read and write are among them
    • grantsExoShape

      public boolean grantsExoShape()
      Whether this entry is of a shape eXo itself writes — a read-only grant or an edit grant (EXO-90378) — and may therefore be carried back unchanged in an ACL request without widening anybody's rights.
      Returns:
      true for a grant eXo could have written
    • appliesTo

      public boolean appliesTo(String canonicalPrincipal)
      Whether this entry names exactly one principal path, compared in the canonical form a recorded principal is held in.
      Parameters:
      canonicalPrincipal - a principal path, canonical, not null
      Returns:
      true when the entry's principal is an href naming it
    • principalHrefOf

      public static String principalHrefOf(String canonicalPrincipal)
      The href a principal path is written as: every segment percent-encoded outside the unreserved set, and a trailing slash, since a principal is a collection. A canonical path decodes %40 to @; this puts it back, so the server reads the spelling it answers itself.
      Parameters:
      canonicalPrincipal - a server-absolute principal path, decoded, with or without a trailing slash
      Returns:
      the href
    • clark

      public static String clark(String namespace, String localName)
      A Clark name: {namespace}local.
      Parameters:
      namespace - the element's namespace
      localName - the element's local name
      Returns:
      the Clark name
    • toString

      public final String toString()
      Returns a string representation of this record class. The representation contains the name of the class, followed by the name and value of each of the record components.
      Specified by:
      toString in class Record
      Returns:
      a string representation of this object
    • hashCode

      public final int hashCode()
      Returns a hash code value for this object. The value is derived from the hash code of each of the record components.
      Specified by:
      hashCode in class Record
      Returns:
      a hash code value for this object
    • equals

      public final boolean equals(Object o)
      Indicates whether some other object is "equal to" this one. The objects are equal if the other object is of the same class and if all the record components are equal. Reference components are compared with Objects::equals(Object,Object); primitive components are compared with '=='.
      Specified by:
      equals in class Record
      Parameters:
      o - the object with which to compare
      Returns:
      true if this object is the same as the o argument; false otherwise.
    • principal

      public AccessControlEntry.AcePrincipal principal()
      Returns the value of the principal record component.
      Returns:
      the value of the principal record component
    • inverted

      public boolean inverted()
      Returns the value of the inverted record component.
      Returns:
      the value of the inverted record component
    • deny

      public boolean deny()
      Returns the value of the deny record component.
      Returns:
      the value of the deny record component
    • privileges

      public Set<String> privileges()
      Returns the value of the privileges record component.
      Returns:
      the value of the privileges record component
    • protectedEntry

      public boolean protectedEntry()
      Returns the value of the protectedEntry record component.
      Returns:
      the value of the protectedEntry record component
    • inheritedFrom

      public String inheritedFrom()
      Returns the value of the inheritedFrom record component.
      Returns:
      the value of the inheritedFrom record component