RFC 3744
Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol
RFC 3744: Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol β¨
okay bestie, welcome to RFC 3744 π This is part 1 of 13, so more is coming. Here's the title block, the stuff about who wrote it and when:
- Network Working Group, RFC number 3744
- Authors: G. Clemm (IBM), J. Reschke (greenbytes), E. Sedlar (Oracle Corporation), and J. Whitehead (U.C. Santa Cruz) π
- Category: Standards Track π₯
- Date: May 2004 πΈ
The header doesn't list anything this one obsoletes or updates, so there's no drama there π«Ά
Status of This Memo π
okay so this one is an Internet standards track protocol for the Internet community, and it's literally asking people to talk about it and suggest improvements π¦ If you want to know where this protocol stands in standardization, check the current edition of the "Internet Official Protocol Standards" (STD 1). Distribution of this memo is unlimited, so share it freely π
Copyright Notice π
Copyright (C) The Internet Society (2004). All Rights Reserved.
Abstract π§
okay the big idea: this document defines a bunch of methods, headers, message bodies, properties, and reports that add Access Control extensions to the WebDAV Distributed Authoring Protocol β¨
The main thing it lets a client do is read and modify access control lists (ACLs). An ACL tells the server whether to allow or deny operations on a resource, like HyperText Transfer Protocol (HTTP) method invocations, for a given principal π
Principals get a lightweight representation as Web resources, which is lowkey genius because it means you can plug in tons of different user management repositories π§ Last bit: search operations let you find and manipulate principals using human names, so you don't need a random ID to look someone up π
Table of Contents π
1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1. Terms. . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.2. Notational Conventions . . . . . . . . . . . . . . . . . 8
2. Principals . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3. Privileges . . . . . . . . . . . . . . . . . . . . . . . . . . 8
3.1. DAV:read Privilege . . . . . . . . . . . . . . . . . . . 10
3.2. DAV:write Privilege. . . . . . . . . . . . . . . . . . . 10
3.3. DAV:write-properties Privilege . . . . . . . . . . . . . 10
3.4. DAV:write-content Privilege. . . . . . . . . . . . . . . 11
3.5. DAV:unlock Privilege . . . . . . . . . . . . . . . . . . 11
3.6. DAV:read-acl Privilege . . . . . . . . . . . . . . . . . 11
3.7. DAV:read-current-user-privilege-set Privilege. . . . . . 12
3.8. DAV:write-acl Privilege. . . . . . . . . . . . . . . . . 12
3.9. DAV:bind Privilege . . . . . . . . . . . . . . . . . . . 12
3.10. DAV:unbind Privilege . . . . . . . . . . . . . . . . . . 12
3.11. DAV:all Privilege. . . . . . . . . . . . . . . . . . . . 13
3.12. Aggregation of Predefined Privileges . . . . . . . . . . 13
4. Principal Properties . . . . . . . . . . . . . . . . . . . . . 13
4.1. DAV:alternate-URI-set. . . . . . . . . . . . . . . . . . 14
4.2. DAV:principal-URL. . . . . . . . . . . . . . . . . . . . 14
4.3. DAV:group-member-set . . . . . . . . . . . . . . . . . . 14
4.4. DAV:group-membership . . . . . . . . . . . . . . . . . . 14
5. Access Control Properties. . . . . . . . . . . . . . . . . . . 15
5.1. DAV:owner. . . . . . . . . . . . . . . . . . . . . . . . 15
5.1.1. Example: Retrieving DAV:owner . . . . . . . . . . 15
5.1.2. Example: An Attempt to Set DAV:owner. . . . . . . 16
5.2. DAV:group. . . . . . . . . . . . . . . . . . . . . . . . 18
5.3. DAV:supported-privilege-set. . . . . . . . . . . . . . . 18
5.3.1. Example: Retrieving a List of Privileges
Supported on a Resource . . . . . . . . . . . . . 19
5.4. DAV:current-user-privilege-set . . . . . . . . . . . . . 21
5.4.1. Example: Retrieving the User's Current Set of
Assigned Privileges . . . . . . . . . . . . . . . 22
5.5. DAV:acl. . . . . . . . . . . . . . . . . . . . . . . . . 23
5.5.1. ACE Principal . . . . . . . . . . . . . . . . . . 23
5.5.2. ACE Grant and Deny. . . . . . . . . . . . . . . . 25
5.5.3. ACE Protection. . . . . . . . . . . . . . . . . . 25
5.5.4. ACE Inheritance . . . . . . . . . . . . . . . . . 25
5.5.5. Example: Retrieving a Resource's Access Control
List. . . . . . . . . . . . . . . . . . . . . . . 25
5.6. DAV:acl-restrictions . . . . . . . . . . . . . . . . . . 27
5.6.1. DAV:grant-only. . . . . . . . . . . . . . . . . . 27
5.6.2. DAV:no-invert ACE Constraint. . . . . . . . . . . 28
5.6.3. DAV:deny-before-grant . . . . . . . . . . . . . . 28
5.6.4. Required Principals . . . . . . . . . . . . . . . 28
5.6.5. Example: Retrieving DAV:acl-restrictions. . . . . 28
5.7. DAV:inherited-acl-set. . . . . . . . . . . . . . . . . . 29
5.8. DAV:principal-collection-set . . . . . . . . . . . . . . 30
5.8.1. Example: Retrieving DAV:principal-collection-set. 30
5.9. Example: PROPFIND to retrieve access control properties. 32
6. ACL Evaluation . . . . . . . . . . . . . . . . . . . . . . . . 36
7. Access Control and existing methods. . . . . . . . . . . . . . 37
7.1. Any HTTP method. . . . . . . . . . . . . . . . . . . . . 37
7.1.1. Error Handling. . . . . . . . . . . . . . . . . . 37
7.2. OPTIONS. . . . . . . . . . . . . . . . . . . . . . . . . 38
7.2.1. Example - OPTIONS . . . . . . . . . . . . . . . . 39
7.3. MOVE . . . . . . . . . . . . . . . . . . . . . . . . . . 39
7.4. COPY . . . . . . . . . . . . . . . . . . . . . . . . . . 39
7.5. LOCK . . . . . . . . . . . . . . . . . . . . . . . . . . 39
8. Access Control Methods . . . . . . . . . . . . . . . . . . . . 40
8.1. ACL. . . . . . . . . . . . . . . . . . . . . . . . . . . 40
8.1.1. ACL Preconditions . . . . . . . . . . . . . . . . 40
8.1.2. Example: the ACL method . . . . . . . . . . . . . 42
8.1.3. Example: ACL method failure due to protected
ACE conflict. . . . . . . . . . . . . . . . . . . 43
8.1.4. Example: ACL method failure due to an
inherited ACE conflict. . . . . . . . . . . . . . 44
8.1.5. Example: ACL method failure due to an attempt
to set grant and deny in a single ACE . . . . . . 45
9. Access Control Reports . . . . . . . . . . . . . . . . . . . . 46
9.1. REPORT Method. . . . . . . . . . . . . . . . . . . . . . 46
9.2. DAV:acl-principal-prop-set Report. . . . . . . . . . . . 47
9.2.1. Example: DAV:acl-principal-prop-set Report. . . . 48
9.3. DAV:principal-match REPORT . . . . . . . . . . . . . . . 49
9.3.1. Example: DAV:principal-match REPORT . . . . . . . 50
9.4. DAV:principal-property-search REPORT . . . . . . . . . . 51
9.4.1. Matching. . . . . . . . . . . . . . . . . . . . . 53
9.4.2. Example: successful DAV:principal-property-search
REPORT. . . . . . . . . . . . . . . . . . . . . . 54
9.5. DAV:principal-search-property-set REPORT . . . . . . . . 56
9.5.1. Example: DAV:principal-search-property-set
REPORT. . . . . . . . . . . . . . . . . . . . . . 58
10. XML Processing . . . . . . . . . . . . . . . . . . . . . . . . 59
11. Internationalization Considerations. . . . . . . . . . . . . . 59
12. Security Considerations. . . . . . . . . . . . . . . . . . . . 60
12.1. Increased Risk of Compromised Users. . . . . . . . . . . 60
12.2. Risks of the DAV:read-acl and
DAV:current-user-privilege-set Privileges. . . . . . . . 60
12.3. No Foreknowledge of Initial ACL. . . . . . . . . . . . . 61
13. Authentication . . . . . . . . . . . . . . . . . . . . . . . . 61
14. IANA Considerations. . . . . . . . . . . . . . . . . . . . . . 62
15. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 62
16. References . . . . . . . . . . . . . . . . . . . . . . . . . . 62
16.1. Normative References . . . . . . . . . . . . . . . . . . 62
16.2. Informative References . . . . . . . . . . . . . . . . . 63
Appendices
A. WebDAV XML Document Type Definition Addendum . . . . . . . . . 64
B. WebDAV Method Privilege Table (Normative). . . . . . . . . . . 67
Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 71
Full Copyright Statement. . . . . . . . . . . . . . . . . . . . . 72
Part 1 of 13 is done, bestie π¦ Part 2 is next, and we're getting into the good stuff π
1. Introduction β¨
okay bestie, so the whole goal of the WebDAV access control extensions is to give everyone an interoperable way to handle discretionary access control π for content and metadata on WebDAV servers. it works on a repo as basic as a UNIX file system, but it also handles way fancier models π . the core vibe is that who you are decides what you can do to a resource. the "who you are" part is a "principal" identifier, and users, client software, servers, and groups all get one π. the "what you can do" part lives in a single "access control list" (ACL) attached to each resource. an ACL holds a bunch of "access control entries" (ACEs), and each ACE names a principal and lists privileges that are either granted or denied to them. when a principal sends an operation (like an HTTP or WebDAV method) at a resource, the server checks the ACEs in the ACL to see if that principal is allowed π.
since every ACE has a principal's identifier in it, client software run by a human needs a way to pick that principal π«Ά. this spec uses http(s) scheme URLs to identify principals, and those principals are WebDAV-capable resources. ngl, those URLs aren't guaranteed to make any sense to a human. like, http://www.example.com/u/256432 and http://www.example.com/people/Greg.Stein are both valid URLs that could point at the same principal π. to fix that, every principal resource has the DAV:displayname property, which holds a human-readable name for it β¨.
okay now this is the tricky part π§ . since one principal can have multiple URLs, it gets hard to tell which principal an ACE is actually talking about. a client can't figure out that an ACE granting read to http://www.example.com/people/Greg.Stein also affects http://www.example.com/u/256432. a client has no way to know that two URLs point at the same principal resource. so this spec says clients must use just one of the possible URLs for a principal when they make ACEs. wait, sorry, let me be precise, the original says "requires", not "must", so the real thing is: this specification requires clients to use just one of the many possible URLs for a principal when creating ACEs. a client can find out which URL to use by fetching the DAV:principal-URL property (Section 4.2) from a principal resource. and no matter which of the principal's URLs you send PROPFIND to, that property always gives back the same URL π¦.
with hundreds to thousands of principals, the question becomes how a human picks just one π. one approach is to spread the principals across lots of collections so there are only a few per collection. for example, you could have a two level hierarchy where the first level has 36 collections (a-z, 0-9), and the second level has another 36, giving you collections /a/a/, /a/b/, ..., /a/z/. so a principal with the last name "Stein" would sit at /s/t/Stein. honestly that's pre-computing a common search on last name and baking it into a folder structure π. the catch is it only handles a small set of predefined searches, and walking down the hierarchy adds extra steps (down, then back up) even when the user already knows the name. organizing principal URLs into a hierarchy is a totally valid namespace choice, but users shouldn't be forced to navigate it just to pick a principal πΈ.
so this spec gives you substring searches over a small set of properties on principal resources β¨. you can search by last name, first name, user name, job title, and so on. two separate searches are supported, and both use the REPORT method: one to search principal resources (DAV:principal-property-search, Section 9.4), and one to find out which properties are searchable at all (DAV:principal-search-property-set, Section 9.5) π.
once a principal shows up in an ACE, the server evaluating that ACE has to know who is making the protocol request, and it has to check that they really are who they claim to be. that check is called authentication π. this spec intentionally skips authentication, since HTTP already has several authentication mechanisms [RFC2617]. still, some authentication mechanism has to be available to validate a principal's identity. HTTP Digest Authentication is one example, and every WebDAV compliant implementation is required to support it π.
these issues are out of scope for this doc, so don't come looking for them here π ββοΈ:
- access control that only applies to one particular property on a resource (except the access control properties
DAV:aclandDAV:current-user-privilege-set), instead of the whole resource, - role-based security (where a role is basically a dynamically defined group of principals),
- how an ACL on a resource gets initialized,
- an ACL that applies globally to all resources, rather than to one particular resource.
- creating and maintaining resources that represent people or computational agents (principals), and groups of these.
here's how the spec is laid out πΊοΈ. Section 1.1 defines the key concepts used all the way through, followed by a deeper look at principals (Section 2) and privileges (Section 3). properties defined on principals are in Section 4, and access control properties for content resources are in Section 5. how ACLs get evaluated is in Section 6. client discovery of access control capability using OPTIONS is in Section 7.2. interactions between access control and existing HTTP and WebDAV methods are in the rest of Section 7. the access control setting method, ACL, is in Section 8. four reports that give limited server-side searching are in Section 9. then there are sections on XML processing (Section 10), internationalization (Section 11), security considerations (Section 12), and authentication (Section 13) to round it out π. and there's an appendix (Appendix A) with an XML Document Type Definition (DTD) for the XML elements defined here π.
1.1. Terms
this doc uses the terms defined in HTTP [RFC2616] and WebDAV [RFC2518]. on top of those, these terms are defined too π:
principal
A "principal" is a distinct human or computational actor that initiates access to network resources. in this protocol, a principal is an HTTP resource that represents such an actor π.
group
A "group" is a principal that represents a set of other principals π«.
privilege
A "privilege" controls access to a particular set of HTTP operations on a resource π.
aggregate privilege
An "aggregate privilege" is a privilege that contains a set of other privileges π¦.
abstract privilege
The modifier "abstract", when applied to a privilege on a resource, means the privilege cannot be set in an access control element (ACE) on that resource π«.
access control list (ACL)
An "ACL" is a list of access control elements that define access control to a particular resource π.
access control element (ACE)
An "ACE" either grants or denies a particular set of (non-abstract) privileges for a particular principal β .
inherited ACE
An "inherited ACE" is an ACE that is dynamically shared from the ACL of another resource. when a shared ACE changes on the primary resource, it is also changed on inheriting resources π¦.
protected property
A "protected property" is one whose value cannot be updated except by a method explicitly defined as updating that specific property. in particular, a protected property cannot be updated with a PROPPATCH request π‘οΈ.
1.2. Notational Conventions
the augmented BNF this doc uses to describe protocol elements is described in Section 2.1 of [RFC2616]. since that augmented BNF uses the basic production rules from Section 2.2 of [RFC2616], those rules apply here too π§©.
the key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119] π―.
XML element definitions in this doc use XML element type declarations (as found in XML Document Type Declarations), described in Section 3.2 of [REC-XML]. when an XML element type in the "DAV:" namespace gets referenced in this doc outside of an XML fragment, the string "DAV:" gets prefixed to the element name π .
2. Principals
a principal is a network resource that represents a distinct human or computational actor that initiates access to network resources πΈ. users and groups are represented as principals in lots of implementations, and other types of principals are possible too. a URI of any scheme MAY be used to identify a principal resource π. however, servers implementing this specification MUST expose principal resources at an http(s) URL. that's a privileged scheme that points to resources with extra properties, as described in Section 4 β¨. so a principal resource can have multiple URIs, and one of them has to be an http(s) scheme URL π. although an implementation SHOULD support PROPFIND and MAY support PROPPATCH to access and modify information about a principal, it is not required to do so π«Ά.
a principal resource may be a group, where a group is a principal that represents a set of other principals, called the members of the group π―ββοΈ. if a person or computational agent matches a principal resource that is a member of a group, they also match the group π. group membership is recursive, so if a principal is a member of group GRPA, and GRPA is a member of group GRPB, then the principal is also a member of GRPB πͺ.
3. Privileges π
Okay so privileges are basically the bouncers π
. Being able to run a method on a resource MUST be controlled by one or more privileges. If you're writing an extension that adds brand-new HTTP methods, you SHOULD say which privileges they need, either by defining new ones or by mapping to the ones below β¨. A principal with zero privileges on a resource MUST be denied any HTTP access to it, UNLESS they match an ACE built with the DAV:all, DAV:authenticated, or DAV:unauthenticated pseudo-principals (see Section 5.5.1) π«Ά. Servers MUST report a 403 "Forbidden" error when access is denied, except when the privilege is about hiding whether the resource exists at all. In that case, 404 "Not Found" may be returned instead π.
Privileges can be containers for other privileges, and those are called "aggregate privileges" π¦. If a principal is granted or denied an aggregate privilege, it's semantically the same as granting or denying each privilege inside it, one by one. For example, an implementation might define add-member and remove-member privileges that control adding and removing members of a group π―. Since those change the state of a group, they'd be aggregated under the DAV:write privilege on that group. So granting DAV:write on a group would also grant add-member and remove-member β¨.
Privileges can also be declared "abstract" for a given resource, which means they can't be set in an ACE on that resource π¦. Aggregate and non-aggregate privileges can both be abstract. Abstract privileges are super useful for modeling privileges that wouldn't otherwise be exposed through the protocol. They also give server implementations flexibility in how they carry out the privileges defined in this spec π. Say a server can't separate the read-resource capability from the read-ACL capability. It can still model DAV:read and DAV:read-acl by declaring them abstract and putting them inside a non-abstract aggregate privilege (say, read-all) that holds both. Then you can set read-all to couple DAV:read and DAV:read-acl together, but you can't set DAV:read or DAV:read-acl on their own π. Since aggregates can be abstract too, abstract privileges can also be used to group and organize non-abstract ones ποΈ. Privilege containment loops are not allowed, so a privilege MUST NOT contain itself. For example, DAV:read cannot contain DAV:read π
ββοΈ.
The privileges that apply to a resource can change based on its DAV:resourcetype, and they can also differ between server implementations π. For interoperability, though, this spec defines a set of well-known privileges (like DAV:read, DAV:write, DAV:read-acl, DAV:write-acl, DAV:read-current-user-privilege-set, and DAV:all). These can at least be used to classify the other privileges on a given resource π. Access permissions on null resources (defined in [RFC2518], Section 3) are solely the ones they inherit, if any. They aren't discoverable either, meaning the access control properties from Section 5 aren't defined on null resources πΈ. When a null resource turns into a stateful one, its initial access control list is set by the server's default ACL value policy, if there is one β¨.
Server implementations MAY define new privileges beyond the ones in this spec π§. Privileges defined by individual implementations MUST NOT use the DAV: namespace. They should use a namespace they control instead, such as an http scheme URL π.
3.1. DAV:read Privilege
The read privilege controls methods that return information about the state of a resource, including its properties π. The methods affected are GET and PROPFIND. Any implementation-defined privilege that also controls access to GET and PROPFIND must be aggregated under DAV:read. So if an ACL grants access to DAV:read, the client can expect that no other privilege needs to be granted to get into GET and PROPFIND π. On top of that, the read privilege MUST control the OPTIONS method π.
<!ELEMENT read EMPTY>
3.2. DAV:write Privilege
The write privilege controls methods that lock a resource or change its content, dead properties, or (for a collection) its membership. Examples are PUT and PROPPATCH βοΈ. Heads up, though: state changes are also controlled through locking (see section 5.3 of [RFC2518]), so real write access means both the write privileges AND the write-locking requirements have to be met π. Any implementation-defined privilege that also controls access to methods that modify content, dead properties, or collection membership must be aggregated under DAV:write. For example, if an ACL grants access to DAV:write, the client can expect that no other privilege needs to be granted to get PUT and PROPPATCH π
.
<!ELEMENT write EMPTY>
3.3. DAV:write-properties Privilege
The DAV:write-properties privilege controls methods that modify a resource's dead properties, like PROPPATCH π¬. Whether this privilege can be used to control access to any live properties is up to the implementation. Any implementation-defined privilege that also controls access to methods that modify dead properties must be aggregated under DAV:write-properties. For example, if an ACL grants access to DAV:write-properties, the client can safely expect that no other privilege needs to be granted to access PROPPATCH π«§.
<!ELEMENT write-properties EMPTY>
3.4. DAV:write-content Privilege
The DAV:write-content privilege controls methods that modify the content of an existing resource, like PUT π. Any implementation-defined privilege that also controls access to content must be aggregated under DAV:write-content. For example, if an ACL grants access to DAV:write-content, the client can safely expect that no other privilege needs to be granted to access PUT. Fun twist: PUT aimed at an unmapped URI creates a brand-new resource, so it's actually controlled by the DAV:bind privilege on the parent collection instead π .
<!ELEMENT write-content EMPTY>
3.5. DAV:unlock Privilege
The DAV:unlock privilege controls using the UNLOCK method when you're NOT the lock owner. (The principal who created a lock can always UNLOCK it, no question π.) The people who can lock a resource are usually the same people who can modify it, but servers can let certain kinds of admins unlock resources that other people locked π¦Έ. Any privilege that controls non-lock-owner access to UNLOCK MUST be aggregated under DAV:unlock.
A lock owner can always remove their lock by sending an UNLOCK with the right lock token and credentials. So even without DAV:unlock privilege, they can still remove locks they own π. Anyone else can only remove a lock if they have DAV:unlock privilege AND they send an UNLOCK with the correct lock token. And lock timeout? Totally unaffected by DAV:unlock β°.
<!ELEMENT unlock EMPTY>
3.6. DAV:read-acl Privilege
The DAV:read-acl privilege controls using PROPFIND to retrieve the DAV:acl property of a resource π΅οΈββοΈ.
<!ELEMENT read-acl EMPTY>
3.7. DAV:read-current-user-privilege-set Privilege
The DAV:read-current-user-privilege-set privilege controls using PROPFIND to retrieve the DAV:current-user-privilege-set property of a resource π―. Clients use this property to visually show which UI items depend on permissions. For example, they might gray out resources that aren't writable π©Ά.
This privilege is kept separate from DAV:read-acl for a reason. Most users need access to the privileges available to the current user (since that's what builds the UI), but the full ACL can contain info that isn't appropriate for the current authenticated user π€«. So the group of people who can view the full ACL is expected to be much smaller than the group who can read the current user privilege set. That's why each one needs its own privilege π.
<!ELEMENT read-current-user-privilege-set EMPTY>
3.8. DAV:write-acl Privilege
The DAV:write-acl privilege controls using the ACL method to modify a resource's DAV:acl property π οΈ.
<!ELEMENT write-acl EMPTY>
3.9. DAV:bind Privilege
The DAV:bind privilege lets a method add a new member URL to the specified collection, for example via PUT or MKCOL πͺ΄. It's ignored for resources that aren't collections.
<!ELEMENT bind EMPTY>
3.10. DAV:unbind Privilege
The DAV:unbind privilege lets a method remove a member URL from the specified collection, for example via DELETE or MOVE ποΈ. It's ignored for resources that aren't collections.
<!ELEMENT unbind EMPTY>
3.11. DAV:all Privilege
DAV:all is an aggregate privilege that contains the entire set of privileges that can be applied to the resource π.
<!ELEMENT all EMPTY>
3.12. Aggregation of Predefined Privileges
Server implementations are free to aggregate the predefined privileges (defined above in Sections 3.1-3.10), subject to the following limitations π§©:
DAV:read-aclMUST NOT containDAV:read,DAV:write,DAV:write-acl,DAV:write-properties,DAV:write-content, orDAV:read-current-user-privilege-set.DAV:write-aclMUST NOT containDAV:write,DAV:read,DAV:read-acl, orDAV:read-current-user-privilege-set.DAV:read-current-user-privilege-setMUST NOT containDAV:write,DAV:read,DAV:read-acl, orDAV:write-acl.DAV:writeMUST NOT containDAV:read,DAV:read-acl, orDAV:read-current-user-privilege-set.DAV:readMUST NOT containDAV:write,DAV:write-acl,DAV:write-properties, orDAV:write-content.DAV:writeMUST containDAV:bind,DAV:unbind,DAV:write-properties, andDAV:write-content.
4. Principal Properties π·
Principals show up to clients as WebDAV resources, identified by a URL πͺͺ. A principal MUST have a non-empty DAV:displayname property (defined in Section 13.2 of [RFC2518]) and a DAV:resourcetype property (defined in Section 13.9 of [RFC2518]). On top of that, a principal MUST report the DAV:principal XML element in the value of its DAV:resourcetype property. The element type declaration for DAV:principal looks like this π:
<!ELEMENT principal EMPTY>
This protocol defines some extra properties for a principal too. Getting access control info can be expensive for a server, so the name and value of these properties SHOULD NOT be returned by a PROPFIND allprop request (as defined in Section 12.14.1 of [RFC2518]) π’.
4.1. DAV:alternate-URI-set β¨
okay so this one is a protected property π and if it's not empty, it holds URIs pointing to network resources with extra info about the principal π. Think of it as a little "more about me" card π . One expected use is storing an LDAP [RFC2255] scheme URL π¦. A user-agent that spots an LDAP URL could use LDAP [RFC2251] to grab more machine-readable directory info about the principal and show it in its UI πΈ. Support for this property is REQUIRED π, and the value is empty if no alternate URI exists for the principal π«Ά.
<!ELEMENT alternate-URI-set (href*)>
4.2. DAV:principal-URL π
a principal can have many URLs π, but there has to be one "principal URL" that clients can use to uniquely identify it π. This protected property holds the URL that MUST be used to identify this principal in an ACL request π. Support for this property is REQUIRED β¨.
<!ELEMENT principal-URL (href)>
4.3. DAV:group-member-set π§
this property lives on a group principal and lists the principals that are direct members of that group π. A group can also be a member of another group π, so it can have indirect members too (aka the members of its direct members) π. A URL in the DAV:group-member-set for a principal MUST be the DAV:principal-URL of that principal π₯.
<!ELEMENT group-member-set (href*)>
4.4. DAV:group-membership π
this protected property tells you which groups the principal is directly a member of π¦. Note that a server may let a group be a member of another group π«Ά. In that case, you'd need to query the DAV:group-membership of those other groups to figure out which groups the principal is indirectly in π. Support for this property is REQUIRED π.
<!ELEMENT group-membership (href*)>
5. Access Control Properties π
this spec adds a bunch of new properties for WebDAV resources πΈ. Access control properties can be fetched like any other WebDAV property, using the PROPFIND method β¨. Getting access control info can be expensive on lots of servers π, so a PROPFIND allprop request (as defined in Section 12.14.1 of [RFC2518]) SHOULD NOT return the names and values of the properties defined in this section π.
Access control properties (especially DAV:acl and DAV:inherited-acl-set) are defined on the resource identified by the Request-URI of a PROPFIND request π§. The big consequence? If a resource can be reached through multiple URIs, the access control property values are the same across all of those URIs π.
HTTP resources that support the WebDAV Access Control Protocol MUST contain the following properties π. Null resources (described in Section 3 of [RFC2518]) MUST NOT contain the following properties π«Ά.
5.1. DAV:owner π
this property identifies a particular principal as the "owner" of the resource π. The owner often has special access control powers (e.g., the owner frequently has permanent DAV:write-acl privilege) π₯, so clients might show the resource owner in their user interface β¨.
Servers MAY implement DAV:owner as a protected property π¦, and MAY return an empty DAV:owner element as the property value if no owner information is available πΈ.
<!ELEMENT owner (href?)>
5.1.1. Example: Retrieving DAV:owner π
this example shows a client request for the DAV:owner property from a collection resource at http://www.example.com/papers/ π. The principal making the request is authenticated with Digest authentication π. The DAV:owner value is the URL http://www.example.com/acl/users/gstein, wrapped in the DAV:href XML element π
.
Request <<
PROPFIND /papers/ HTTP/1.1
Host: www.example.com
Content-type: text/xml; charset="utf-8"
Content-Length: xxx
Depth: 0
Authorization: Digest username="jim",
realm="users@example.com", nonce="...",
uri="/papers/", response="...", opaque="..."
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop>
<D:owner/>
</D:prop>
</D:propfind>
Response <<
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.example.com/papers/</D:href>
<D:propstat>
<D:prop>
<D:owner>
<D:href>http://www.example.com/acl/users/gstein</D:href>
</D:owner>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
5.1.2. Example: An Attempt to Set DAV:owner π
this one shows a client trying to change DAV:owner on the resource at http://www.example.com/papers π. DAV:owner is protected on this server, so it replies with a 207 (Multi-Status) response containing a 403 (Forbidden) status code for the attempt to set DAV:owner π. Section 8.2.1 of [RFC2518] covers PROPPATCH status code info, Section 11 of [RFC2518] covers the Multi-Status response, and Sections 1.6 and 3.12 of [RFC3253] cover extra error marshaling for PROPPATCH attempts on protected properties π.
Request <<
PROPPATCH /papers/ HTTP/1.1
Host: www.example.com
Content-type: text/xml; charset="utf-8"
Content-Length: xxx
Depth: 0
Authorization: Digest username="jim",
realm="users@example.com", nonce="...",
uri="/papers/", response="...", opaque="..."
<?xml version="1.0" encoding="utf-8" ?>
<D:propertyupdate xmlns:D="DAV:">
<D:set>
<D:prop>
<D:owner>
<D:href>http://www.example.com/acl/users/jim</D:href>
</D:owner>
</D:prop>
</D:set>
</D:propertyupdate>
Response <<
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.example.com/papers/</D:href>
<D:propstat>
<D:prop><D:owner/></D:prop>
<D:status>HTTP/1.1 403 Forbidden</D:status>
<D:responsedescription>
<D:error><D:cannot-modify-protected-property/></D:error>
Failure to set protected property (DAV:owner)
</D:responsedescription>
</D:propstat>
</D:response>
</D:multistatus>
5.2. DAV:group π«Ά
this property identifies a particular principal as the "group" of the resource π. You'll usually spot it on repositories that use the Unix privileges model π§.
Servers MAY implement DAV:group as a protected property β¨, and MAY return an empty DAV:group element as the property value if no group information is available πΈ.
<!ELEMENT group (href?)>
5.3. DAV:supported-privilege-set π
this is a protected property that lists the privileges defined for the resource π. Each privilege shows up as an XML element, and aggregate privileges list all of the privileges they aggregate as sub-elements π.
<!ELEMENT supported-privilege-set (supported-privilege*)>
<!ELEMENT supported-privilege
(privilege, abstract?, description, supported-privilege*)>
<!ELEMENT privilege ANY>
An abstract privilege MUST NOT be used in an ACE for that resource π . Servers MUST fail an attempt to set an abstract privilege π.
<!ELEMENT abstract EMPTY>
A description is a human-readable explanation of what the privilege controls access to π. Servers MUST indicate the human language of the description using the xml:lang attribute π, and SHOULD consider the HTTP Accept-Language request header when picking one of several available languages π«Ά.
<!ELEMENT description #PCDATA>
It's envisioned that a WebDAV ACL-aware admin client would list the supported privileges in a dialog box and let the user pick non-abstract privileges to apply in an ACE π . The privileges tree is super useful for programmatically mapping well-known privileges (defined by WebDAV or other standards groups) onto the privileges a particular server supports π¦. It also hides complexity: when an implementation allows a huge number of privileges, the tree shows aggregates to the user instead π.
5.3.1. Example: Retrieving a List of Privileges Supported on a Resource
okay so this example is a client asking for the DAV:supported-privilege-set property on http://www.example.com/papers/ π¦ the value comes back as a whole tree of supported privileges, and every privilege is named as "[XML Namespace , localname]" so nobody gets confused π
[DAV:, all] (aggregate, abstract)
|
+-- [DAV:, read] (aggregate)
|
+-- [DAV:, read-acl] (abstract)
+-- [DAV:, read-current-user-privilege-set] (abstract)
|
+-- [DAV:, write] (aggregate)
|
+-- [DAV:, write-acl] (abstract)
+-- [DAV:, write-properties]
+-- [DAV:, write-content]
|
+-- [DAV:, unlock]
this privilege tree is not normative πΈ (except it has to reflect the normative aggregation rules from Section 3.12, so it's giving rules), and tons of other privilege trees could totally exist too π
Request <<
PROPFIND /papers/ HTTP/1.1
Host: www.example.com
Content-type: text/xml; charset="utf-8"
Content-Length: xxx
Depth: 0
Authorization: Digest username="gclemm",
realm="users@example.com", nonce="...",
uri="/papers/", response="...", opaque="..."
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop>
<D:supported-privilege-set/>
</D:prop>
</D:propfind>
Response <<
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.example.com/papers/</D:href>
<D:propstat>
<D:prop>
<D:supported-privilege-set>
<D:supported-privilege>
<D:privilege><D:all/></D:privilege>
<D:abstract/>
<D:description xml:lang="en">
Any operation
</D:description>
<D:supported-privilege>
<D:privilege><D:read/></D:privilege>
<D:description xml:lang="en">
Read any object
</D:description>
<D:supported-privilege>
<D:privilege><D:read-acl/></D:privilege>
<D:abstract/>
<D:description xml:lang="en">Read ACL</D:description>
</D:supported-privilege>
<D:supported-privilege>
<D:privilege>
<D:read-current-user-privilege-set/>
</D:privilege>
<D:abstract/>
<D:description xml:lang="en">
Read current user privilege set property
</D:description>
</D:supported-privilege>
</D:supported-privilege>
<D:supported-privilege>
<D:privilege><D:write/></D:privilege>
<D:description xml:lang="en">
Write any object
</D:description>
<D:supported-privilege>
<D:privilege><D:write-acl/></D:privilege>
<D:description xml:lang="en">
Write ACL
</D:description>
<D:abstract/>
</D:supported-privilege>
<D:supported-privilege>
<D:privilege><D:write-properties/></D:privilege>
<D:description xml:lang="en">
Write properties
</D:description>
</D:supported-privilege>
<D:supported-privilege>
<D:privilege><D:write-content/></D:privilege>
<D:description xml:lang="en">
Write resource content
</D:description>
</D:supported-privilege>
</D:supported-privilege>
<D:supported-privilege>
<D:privilege><D:unlock/></D:privilege>
<D:description xml:lang="en">
Unlock resource
</D:description>
</D:supported-privilege>
</D:supported-privilege>
</D:supported-privilege-set>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
5.4. DAV:current-user-privilege-set
okay this one is so good π«Ά DAV:current-user-privilege-set is a protected property holding the exact set of privileges the server has computed for the currently authenticated HTTP user π aggregate privileges and the privileges they contain are both listed. user-agents can look at this value and adjust their UI, like graying out a menu item or button for anything the current principal can't do π it's also super useful for figuring out what the current principal can do without actually trying the operation first β¨
<!ELEMENT current-user-privilege-set (privilege*)>
<!ELEMENT privilege ANY>
if the current user is granted a specific privilege, that privilege must belong to the set of privileges that may be set on this resource π so, every element in the DAV:current-user-privilege-set property MUST identify a non-abstract privilege from the DAV:supported-privilege-set property. no exceptions bestie π
5.4.1. Example: Retrieving the User's Current Set of Assigned Privileges
continuing from Section 5.3.1 π§ this example has a client asking for the DAV:current-user-privilege-set property on the resource at http://www.example.com/papers/. the principal making the request has the username "khare", and the request uses Digest authentication π₯ "khare" has been granted the DAV:read privilege. DAV:read contains DAV:read-acl and DAV:read-current-user-privilege-set (see Section 5.3.1), so "khare" can read the ACL property and the DAV:current-user-privilege-set property too π but DAV:all, DAV:read-acl, DAV:write-acl and DAV:read-current-user-privilege-set are NOT listed in the value, since (for this example) they're abstract privileges π and DAV:write isn't listed either, because "khare" isn't in any ACE granting write permission to that principal π
Request <<
PROPFIND /papers/ HTTP/1.1
Host: www.example.com
Content-type: text/xml; charset="utf-8"
Content-Length: xxx
Depth: 0
Authorization: Digest username="khare",
realm="users@example.com", nonce="...",
uri="/papers/", response="...", opaque="..."
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop>
<D:current-user-privilege-set/>
</D:prop>
</D:propfind>
Response <<
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.example.com/papers/</D:href>
<D:propstat>
<D:prop>
<D:current-user-privilege-set>
<D:privilege><D:read/></D:privilege>
</D:current-user-privilege-set>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
5.5. DAV:acl
this is a protected property that holds the list of access control entries (ACEs), which spell out which principals get which privileges on this resource π
<!ELEMENT acl (ace*) >
each DAV:ace element says which privileges are either granted or denied to a single principal π and if the DAV:acl property is empty, no principal gets any privilege at all π
<!ELEMENT ace ((principal | invert), (grant|deny), protected?,
inherited?)>
5.5.1. ACE Principal
the DAV:principal element identifies the principal this ACE applies to π
<!ELEMENT principal (href | all | authenticated | unauthenticated
| property | self)>
the current user matches DAV:href only if they're authenticated as being (or being a member of) the principal identified by the URL inside that DAV:href π¦ the current user always matches DAV:all β¨
<!ELEMENT all EMPTY>
the current user matches DAV:authenticated only if they're authenticated π«Ά
<!ELEMENT authenticated EMPTY>
the current user matches DAV:unauthenticated only if they're not authenticated πΈ
<!ELEMENT unauthenticated EMPTY>
okay here's the tea: DAV:all is the union of DAV:authenticated and DAV:unauthenticated π₯ for any given request, the user matches either DAV:authenticated or DAV:unauthenticated, but never both, because those two are disjoint sets π
a DAV:property principal in a DAV:acl property of a resource only matches the current user if the value of the identified property on that resource contains at most one DAV:href XML element, the URI value of that DAV:href identifies a principal, and the current user is authenticated as being (or being a member of) that principal π§ for example, if the DAV:property element contained <DAV:owner/>, the current user would only match the DAV:property principal if they're authenticated as matching the principal identified by the DAV:owner property of the resource π
<!ELEMENT property ANY>
the current user matches DAV:self in a DAV:acl property of the resource only if that resource is a principal and that principal matches the current user. or, if the principal is a group, a member of that group matches the current user π
<!ELEMENT self EMPTY>
some servers may support ACEs that apply to users NOT matching the current principal, like all users who aren't in a particular group π that can be done by wrapping the DAV:principal element with DAV:invert β¨
<!ELEMENT invert principal>
5.5.2. ACE Grant and Deny
each DAV:grant or DAV:deny element specifies the set of privileges to be either granted or denied to the specified principal π a DAV:grant or DAV:deny element in the DAV:acl of a resource MUST only contain non-abstract elements from the DAV:supported-privilege-set of that resource. no abstract stuff sneaking in π ββοΈ
<!ELEMENT grant (privilege+)>
<!ELEMENT deny (privilege+)>
<!ELEMENT privilege ANY>
5.5.3. ACE Protection
a server shows that an ACE is protected by including the DAV:protected element in the ACE π‘οΈ if the ACL of a resource has an ACE with a DAV:protected element, trying to remove that ACE from the ACL MUST fail. protected means protected, periodt π
<!ELEMENT protected EMPTY>
5.5.4. ACE Inheritance
if a DAV:inherited element is present, it means this ACE is inherited from another resource, which is identified by the URL inside a DAV:href element π an inherited ACE can't be changed directly. instead, you have to modify the ACL on the resource it's inherited from π¦
ngl this part is a little tricky, so read carefully π€ ACE inheritance is NOT the same thing as ACL initialization. ACL initialization defines the ACL a newly created resource will use (if one isn't specified). ACE inheritance is about an ACE that's logically shared, so an update to the resource containing the ACE affects the ACE of every resource that inherits it β¨ how ACLs get initialized, or how ACEs get inherited, isn't defined by this document π§
<!ELEMENT inherited (href)>
5.5.5. Example: Retrieving a Resource's Access Control List π¦
Okay so this one picks up right where the last examples left off (Sections 5.3.1 and 5.4.1) π . The client asks for the DAV:acl property on http://www.example.com/papers/, and there are two ACEs in this ACL π
ACE #1: The group at http://www.example.com/acl/groups/maintainers (the site maintainers π) gets DAV:write privilege. Since DAV:write contains the DAV:write-acl privilege (see Section 5.3.1) for this example, the "maintainers" group can also edit the access control list. Main character energy π
ACE #2: All principals (DAV:all) get DAV:read privilege. Since DAV:read contains DAV:read-acl and DAV:read-current-user-privilege-set for this example, every user (including all the "maintainers" members) can read DAV:acl and DAV:current-user-privilege-set πΈ
>> Request <<
PROPFIND /papers/ HTTP/1.1
Host: www.example.com
Content-type: text/xml; charset="utf-8"
Content-Length: xxx
Depth: 0
Authorization: Digest username="masinter",
realm="users@example.com", nonce="...",
uri="/papers/", response="...", opaque="..."
<D:propfind xmlns:D="DAV:">
<D:prop>
<D:acl/>
</D:prop>
</D:propfind>
>> Response <<
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.example.com/papers/</D:href>
<D:propstat>
<D:prop>
<D:acl>
<D:ace>
<D:principal>
<D:href
>http://www.example.com/acl/groups/maintainers</D:href>
</D:principal>
<D:grant>
<D:privilege><D:write/></D:privilege>
</D:grant>
</D:ace>
<D:ace>
<D:principal>
<D:all/>
</D:principal>
<D:grant>
<D:privilege><D:read/></D:privilege>
</D:grant>
</D:ace>
</D:acl>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
5.6. DAV:acl-restrictions π₯
This protected property tells clients which types of ACLs this server supports, so they don't go around getting errors all day π When a client tries to set an ACL through the ACL method, the server may reject that attempt if it doesn't match the spec. The following properties show the restrictions the client must observe before setting an ACL:
<grant-only>Deny ACEs are not supported<no-invert>Inverted ACEs are not supported<deny-before-grant>All deny ACEs must occur before any grant ACEs<required-principal>Indicates which principals are required to be present
<!ELEMENT acl-restrictions (grant-only?, no-invert?,
deny-before-grant?,
required-principal?)>
5.6.1. DAV:grant-only β¨
This element says ACEs with deny clauses are not allowed. Nope, not happening π ββοΈ
<!ELEMENT grant-only EMPTY>
5.6.2. DAV:no-invert ACE Constraint π
This element says ACEs with the <invert> element are not allowed.
<!ELEMENT no-invert EMPTY>
5.6.3. DAV:deny-before-grant π§
This element says all deny ACEs must come before all grant ACEs. Order matters, bestie π
<!ELEMENT deny-before-grant EMPTY>
5.6.4. Required Principals π«Ά
The required principal elements list which principals must have an ACE defined in the ACL π
<!ELEMENT required-principal
(all? | authenticated? | unauthenticated? | self? | href* |
property*)>
For example, this element requires that the ACL contain a DAV:owner property ACE:
<D:required-principal xmlns:D="DAV:">
<D:property><D:owner/></D:property>
</D:required-principal>
5.6.5. Example: Retrieving DAV:acl-restrictions π
In this example, the client asks for the value of the DAV:acl-restrictions property. Digest authentication gives credentials for the principal operating the client π
>> Request <<
PROPFIND /papers/ HTTP/1.1
Host: www.example.com
Content-type: text/xml; charset="utf-8"
Content-Length: xxx
Depth: 0
Authorization: Digest username="srcarter",
realm="users@example.com", nonce="...",
uri="/papers/", response="...", opaque="..."
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop>
<D:acl-restrictions/>
</D:prop>
</D:propfind>
>> Response <<
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.example.com/papers/</D:href>
<D:propstat>
<D:prop>
<D:acl-restrictions>
<D:grant-only/>
<D:required-principal>
<D:all/>
</D:required-principal>
</D:acl-restrictions>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
5.7. DAV:inherited-acl-set πΈ
This protected property holds a set of URLs pointing at other resources that also control access to this resource. To get a privilege on a resource, the ACL on that resource (in its DAV:acl property) has to grant it, AND the ACL of every resource listed in that resource's DAV:inherited-acl-set property has to grant it too. So basically, the privileges from the current ACL get ANDed with the privileges from each inherited ACL. Double check energy π₯
<!ELEMENT inherited-acl-set (href*)>
5.8. DAV:principal-collection-set π
This protected property of a resource holds a set of URLs pointing at the root collections that contain the principals available on the server implementing this resource. A WebDAV Access Control Protocol user agent can use DAV:principal-collection-set to fetch the DAV:displayname property (specified in Section 13.2 of [RFC2518]) of all the principals on that server π¦ That gives it human-readable names for each principal, which can show up in a user interface.
<!ELEMENT principal-collection-set (href*)>
Different servers can control different parts of the URL namespace, so different resources on the same host MAY have different DAV:principal-collection-set values π The collections in DAV:principal-collection-set MAY live on different hosts from the resource. The URLs in DAV:principal-collection-set SHOULD be http or https scheme URLs π For security and scalability reasons, a server MAY report only a subset of all the principal collections it knows about, so clients should not assume they got an exhaustive listing. A server MAY also choose to report none of the principal collections it knows about, in which case the property value is empty.
The value of DAV:principal-collection-set sets the scope of the DAV:principal-property-search REPORT (defined in Section 9.4). Clients use that REPORT to fill their user interface with a list of principals π So if a server limits how much principal info a client can get, it'll mess with the client's ability to edit access control lists, because it's hard to find the URL of a principal to use in an ACE π
5.8.1. Example: Retrieving DAV:principal-collection-set β¨
In this example, the client asks for the value of the DAV:principal-collection-set property on the collection at http://www.example.com/papers/. The property contains two URLs, http://www.example.com/acl/users/ and http://www.example.com/acl/groups/, both wrapped in DAV:href XML elements. Digest authentication gives credentials for the principal operating the client π«Ά
The client could reasonably follow this up with two separate PROPFIND requests to get the DAV:displayname property of the members of the two collections (/acl/users and /acl/groups). That info could power a user interface for creating access control entries π§
>> Request <<
PROPFIND /papers/ HTTP/1.1
Host: www.example.com
Content-type: text/xml; charset="utf-8"
Content-Length: xxx
Depth: 0
Authorization: Digest username="yarong",
realm="users@example.com", nonce="...",
uri="/papers/", response="...", opaque="..."
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop>
<D:principal-collection-set/>
</D:prop>
</D:propfind>
>> Response <<
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.example.com/papers/</D:href>
<D:propstat>
<D:prop>
<D:principal-collection-set>
<D:href>http://www.example.com/acl/users/</D:href>
<D:href>http://www.example.com/acl/groups/</D:href>
</D:principal-collection-set>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
5.9. Example: PROPFIND to retrieve access control properties π
Okay bestie, this is the big access control showcase β¨ It shows how you can grab all the access control info with a PROPFIND request by asking for DAV:owner, DAV:supported-privilege-set, DAV:current-user-privilege-set, and DAV:acl π
>> Request <<
PROPFIND /top/container/ HTTP/1.1
Host: www.example.com
Content-type: text/xml; charset="utf-8"
Content-Length: xxx
Depth: 0
Authorization: Digest username="ejw",
realm="users@example.com", nonce="...",
uri="/top/container/", response="...", opaque="..."
<?xml version="1.0" encoding="utf-8" ?>
<D:propfind xmlns:D="DAV:">
<D:prop>
<D:owner/>
<D:supported-privilege-set/>
<D:current-user-privilege-set/>
<D:acl/>
</D:prop>
</D:propfind>
>> Response <<
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:"
xmlns:A="http://www.example.com/acl/">
<D:response>
<D:href>http://www.example.com/top/container/</D:href>
<D:propstat>
<D:prop>
<D:owner>
<D:href>http://www.example.com/users/gclemm</D:href>
</D:owner>
<D:supported-privilege-set>
<D:supported-privilege>
<D:privilege><D:all/></D:privilege>
<D:abstract/>
<D:description xml:lang="en">
Any operation
</D:description>
<D:supported-privilege>
<D:privilege><D:read/></D:privilege>
<D:description xml:lang="en">
Read any object
</D:description>
</D:supported-privilege>
<D:supported-privilege>
<D:privilege><D:write/></D:privilege>
<D:abstract/>
<D:description xml:lang="en">
Write any object
</D:description>
<D:supported-privilege>
<D:privilege><A:create/></D:privilege>
<D:description xml:lang="en">
Create an object
</D:description>
</D:supported-privilege>
<D:supported-privilege>
<D:privilege><A:update/></D:privilege>
<D:description xml:lang="en">
Update an object
</D:description>
</D:supported-privilege>
</D:supported-privilege>
<D:supported-privilege>
<D:privilege><A:delete/></D:privilege>
<D:description xml:lang="en">
Delete an object
</D:description>
</D:supported-privilege>
<D:supported-privilege>
<D:privilege><D:read-acl/></D:privilege>
<D:description xml:lang="en">
Read the ACL
</D:description>
</D:supported-privilege>
<D:supported-privilege>
<D:privilege><D:write-acl/></D:privilege>
<D:description xml:lang="en">
Write the ACL
</D:description>
</D:supported-privilege>
</D:supported-privilege>
</D:supported-privilege-set>
<D:current-user-privilege-set>
<D:privilege><D:read/></D:privilege>
<D:privilege><D:read-acl/></D:privilege>
</D:current-user-privilege-set>
<D:acl>
<D:ace>
<D:principal>
<D:href>http://www.example.com/users/esedlar</D:href>
</D:principal>
<D:grant>
<D:privilege><D:read/></D:privilege>
<D:privilege><D:write/></D:privilege>
<D:privilege><D:read-acl/></D:privilege>
</D:grant>
</D:ace>
<D:ace>
<D:principal>
<D:href>http://www.example.com/groups/mrktng</D:href>
</D:principal>
<D:deny>
<D:privilege><D:read/></D:privilege>
</D:deny>
</D:ace>
<D:ace>
<D:principal>
<D:property><D:owner/></D:property>
</D:principal>
<D:grant>
<D:privilege><D:read-acl/></D:privilege>
<D:privilege><D:write-acl/></D:privilege>
</D:grant>
</D:ace>
<D:ace>
<D:principal><D:all/></D:principal>
<D:grant>
<D:privilege><D:read/></D:privilege>
</D:grant>
<D:inherited>
<D:href>http://www.example.com/top</D:href>
</D:inherited>
</D:ace>
</D:acl>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
The value of the DAV:owner property is a single DAV:href XML element containing the URL of the principal that owns this resource π
The value of the DAV:supported-privilege-set property is a tree of supported privileges (using "[XML Namespace , localname]" to identify each privilege) π³
[DAV:, all] (aggregate, abstract)
|
+-- [DAV:, read]
+-- [DAV:, write] (aggregate, abstract)
|
+-- [http://www.example.com/acl, create]
+-- [http://www.example.com/acl, update]
+-- [http://www.example.com/acl, delete]
+-- [DAV:, read-acl]
+-- [DAV:, write-acl]
The DAV:current-user-privilege-set property contains two privileges, DAV:read, and DAV:read-acl. So the current authenticated user can only read the resource, and read the DAV:acl property on it π The DAV:acl property contains a set of four ACEs:
ACE #1: The principal identified by the URL http://www.example.com/users/esedlar is granted the DAV:read, DAV:write, and DAV:read-acl privileges. π
ACE #2: The principals identified by the URL http://www.example.com/groups/mrktng are denied the DAV:read privilege. In this example, the principal URL identifies a group. π
ACE #3: In this ACE, the principal is a property principal, specifically the DAV:owner property. When evaluating this ACE, the value of the DAV:owner property is retrieved, and is examined to see if it contains a DAV:href XML element. If so, the URL within the DAV:href element is read, and identifies a principal. In this ACE, the owner is granted DAV:read-acl, and DAV:write-acl privileges. π
ACE #4: This ACE grants the DAV:all principal (all users) the DAV:read privilege. This ACE is inherited from the resource http://www.example.com/top, the parent collection of this resource. π¦
6. ACL Evaluation β¨
Okay so, WebDAV ACLs are evaluated in a similar way to ACLs on Windows NT and in NFSv4 [RFC3530]). An ACL gets evaluated to figure out whether or not access will be granted for a WebDAV request π₯ ACEs are kept in a particular order and get evaluated until all of the permissions the current request needs have been granted. At that point the ACL evaluation stops and access is granted π
But if, during ACL evaluation, a <deny> ACE (matching the current user) shows up for a privilege that hasn't been granted yet, the evaluation stops and access is denied π Not having all of the required privileges granted also means access is denied, periodt.
Note that the semantics of lots of other existing ACL systems can be represented with this mechanism, by mixing deny and grant ACEs π For example, think about the standard "rwx" privilege scheme used by UNIX. In this scheme, if the current user owns the file, access is granted if the matching privilege bit is set and denied if it isn't set, no matter what permissions are set on the file's group and for the world π§ An ACL for UNIX permissions of "r--rw-r--" might look something like this:
<D:acl>
<D:ace>
<D:principal>
<D:property><D:owner/></D:property>
</D:principal>
<D:grant>
<D:privilege><D:read/></D:privilege>
</D:grant>
</D:ace>
<D:ace>
<D:principal>
<D:property><D:owner/></D:property>
</D:principal>
<D:deny>
<D:privilege><D:all/></D:privilege>
</D:deny>
</D:ace>
<D:ace>
<D:principal>
<D:property><D:group/></D:property>
</D:principal>
<D:grant>
<D:privilege><D:read/></D:privilege>
<D:privilege><D:write/></D:privilege>
</D:grant>
</D:ace>
<D:ace>
<D:principal>
<D:property><D:group/></D:property>
</D:principal>
<D:deny>
<D:privilege><D:all/></D:privilege>
</D:deny>
</D:ace>
<D:ace>
<D:principal><D:all></D:principal>
<D:grant>
<D:privilege><D:read/></D:privilege>
</D:grant>
</D:ace>
</D:acl>
and the <acl-restrictions> would be defined as:
<D:no-invert/>
<D:required-principal>
<D:all/>
<D:property><D:owner/></D:property>
<D:property><D:group/><D:group/>
</D:required-principal>
Note that the client can still get errors from a UNIX server even if it's obeying the <acl-restrictions>. That includes <D:allowed-principal> (adding an ACE that specifies a principal other than the ones in the ACL above) or <D:ace-conflict> (trying to reorder the ACEs in the example above) π₯Ί These particular implementation semantics are too complex to be captured with the simple (but general) declarative restrictions, so that's just how it goes β¨
7. Access Control and existing methods π¦
Now we're getting to the fun part, bestie! This section defines how access control functionality affects the methods that already exist π
7.1. Any HTTP method πΈ
7.1.1. Error Handling π
The WebDAV ACL mechanism requires the use of HTTP method "preconditions" as described in section 1.6 of RFC3253 for ALL HTTP methods. Every HTTP method also has an extra precondition called DAV:need-privileges. If an HTTP method fails because of insufficient privileges, the response body to the "403 Forbidden" error MUST contain the <DAV:error> element. That element contains the <DAV:need-privileges> element, which contains one or more <DAV:resource> elements. These say which resource didn't have enough privileges and what privileges were lacking π
<!ELEMENT need-privileges (resource)* >
<!ELEMENT resource ( href , privilege ) >
Since some methods need multiple permissions on multiple resources, this info is needed to clear up any ambiguity π§© There's no requirement that every privilege violation gets reported. For implementation reasons, some servers may only report the first privilege violation π For example:
>> Request <<
MOVE /a/b/ HTTP/1.1
Host: www.example.com
Destination: http://www.example.com/c/d
>> Response <<
HTTP/1.1 403 Forbidden
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<D:error xmlns:D="DAV:">
<D:need-privileges>
<D:resource>
<D:href>/a</D:href>
<D:privilege><D:unbind/></D:privilege>
</D:resource>
<D:resource>
<D:href>/c</D:href>
<D:privilege><D:bind/></D:privilege>
</D:resource>
</D:need-privileges>
</D:error>
7.2. OPTIONS β¨
okay bestie, so if a server does access control, it MUST put access-control in the DAV response header of any OPTIONS response for any resource it hosts π
. And when that token shows up in the DAV header, it MUST mean the server covers every MUST level requirement and every REQUIRED feature in this spec. no half-baked support, it's all or nothing π«Ά
7.2.1. Example - OPTIONS π
Request <<
OPTIONS /foo.html HTTP/1.1
Host: www.example.com
Content-Length: 0
Response <<
HTTP/1.1 200 OK
DAV: 1, 2, access-control
Allow: OPTIONS, GET, PUT, PROPFIND, PROPPATCH, ACL
here the response is basically saying "yep, I do access control π" and that /foo.html can have its access control list changed with the ACL method. iconic behaviour π¦
7.3. MOVE π
when a resource gets moved somewhere else with a MOVE request, the non-inherited and non-protected ACEs in its DAV:acl property MUST NOT be changed, or else the MOVE just fails π. the inherited and protected ACEs? the spec is intentionally leaving those undefined πΈ so server devs get to pick how they handle inheritance and protection. flexibility era β¨
7.4. COPY πͺ
the DAV:acl property on the destination resource of a COPY MUST end up the same as if that resource had been freshly created with an individual creation request, like MKCOL or PUT π. so if a client wants to keep the ACL through a copy, it has to read DAV:acl before the COPY, then do an ACL operation on the new resource to put the original list back, as much as that's possible. the copy doesn't carry it over automatically, so you gotta do the work yourself π
7.5. LOCK π
a lock on a resource makes sure only the lock owner can change ACEs that are neither inherited nor protected. those are the only ACEs a client can edit with an ACL request anyway π§ so a lock doesn't cover inherited or protected ACEs, because a client can't modify them with an ACL request on that resource in the first place. makes sense, no notes π
8. Access Control Methods π
8.1. ACL π
the ACL method is how you change the access control list of a resource, the one you can read through the DAV:acl property π§. it only lets you touch ACEs that are not inherited and not protected π. when you invoke it, every non-inherited, non-protected ACE in the list gets set to exactly match the ACEs inside the DAV:acl XML element (the one described in Section 5.5) of the request body. an ACL request body MUST contain only one DAV:acl XML element π. and unless those non-inherited and non-protected ACEs can be updated to be exactly what the ACL request asks for, the ACL request MUST fail π. all or nothing, bestie π«Ά
the ACEs you can see in DAV:acl might only be part of the full set on that resource. if so, an ACL request only changes the ACEs visible to the current user and leaves any invisible ACE alone π¦
to avoid stepping on another client's DAV:acl changes, a client SHOULD grab a WebDAV lock on the resource before it reads the DAV:acl property of a resource it's planning to update π
Implementation Note: okay so two super common moves are adding an ACE to an existing list or removing one. to do that, a client uses PROPFIND to fetch theDAV:aclproperty, then parses the returned list and strips out all the inherited and protected ACEs (those are tagged with theDAV:inheritedandDAV:protectedXML elements). with what's left (the non-inherited, non-protected ACEs), the client can add or remove as many ACEs as it wants, then sends the final set in the request body of the ACL method. it's giving tidy housekeeping β¨
8.1.1. ACL Preconditions π
an implementation MUST enforce the constraints below on an ACL request π
. if one gets broken, the server MUST respond with a 403 (Forbidden) or a 409 (Conflict), and the indicated XML element MUST come back as a child of a top-level DAV:error element in an XML response body π¨
these status elements are usually written as empty XML elements (they're defined as EMPTY in the DTD), but implementations MAY add extra descriptive XML elements as children of the status element πΈ. clients MUST be able to accept children of these status elements π«Ά. clients that don't understand the extra XML elements should ignore them.
here's the full list of preconditions:
(DAV:no-ace-conflict): the ACEs submitted in the ACL request MUST NOT conflict with each other. this is the catchall error for when some implementation-specific ACL restriction got violated π₯²(DAV:no-protected-ace-conflict): the ACEs submitted in the ACL request MUST NOT conflict with the protected ACEs on the resource. for example, if the resource has a protected ACE grantingDAV:writeto a certain principal, it would be inconsistent for the ACL request to submit an ACE denyingDAV:writeto that same principal π ββοΈ(DAV:no-inherited-ace-conflict): the ACEs submitted in the ACL request MUST NOT conflict with the inherited ACEs on the resource. for example, if the resource inherits an ACE from its parent collection grantingDAV:writeto a certain principal, it'd be inconsistent to submit an ACE denyingDAV:writeto that principal. reporting this error is up to the implementation, so implementations MUST either report it or allow the ACE to be set, and then let the normal ACE evaluation rules decide whether the new ACE actually changes what a specific principal can do π§(DAV:limited-number-of-aces): the number of ACEs submitted in the ACL request MUST NOT go over the number of ACEs the resource allows. BUT ACL-compliant servers MUST support at least one ACE granting privileges to a single principal, and at least one ACE granting privileges to a group π(DAV:deny-before-grant): all non-inherited deny ACEs MUST come before all non-inherited grant ACEs π(DAV:grant-only): the ACEs submitted in the ACL request MUST NOT include a deny ACE. this one only kicks in when the resource's ACL restrictions include the DAV:grant-only constraint (defined in Section 5.6.1) π·(DAV:no-invert): the ACL request MUST NOT include aDAV:invertelement. this only applies when the resource's ACL semantics include the DAV:no-invert constraint (defined in Section 5.6.2) π(DAV:no-abstract): the ACL request MUST NOT try to grant or deny an abstract privilege (see Section 5.3) π«(DAV:not-supported-privilege): the ACEs submitted in the ACL request MUST be supported by the resource π§©(DAV:missing-required-principal): the result of the ACL request MUST have at least one ACE for each principal named in aDAV:required-principalXML element in the ACL semantics of that resource (see Section 5.5) π«Ά(DAV:recognized-principal): every principal URL in the ACL request MUST identify a principal resource π(DAV:allowed-principal): the principals in the ACEs submitted in the ACL request MUST be allowed as principals for the resource. for instance, if a server only lets authenticated principals in, it wouldn't allowDAV:allorDAV:unauthenticatedin an ACE, because those would open the door to unauthenticated access πͺ
8.1.2. Example: the ACL method π
in this example, user "fielding" (authenticated through the Authorization header) gives the principal at http://www.example.com/users/esedlar (aka the user "esedlar") read and write privileges π. the owner of the resource gets read-acl and write-acl privileges, and everyone gets read privileges π
Request <<
ACL /top/container/ HTTP/1.1
Host: www.example.com
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
Authorization: Digest username="fielding",
realm="users@example.com", nonce="...",
uri="/top/container/", response="...", opaque="..."
<?xml version="1.0" encoding="utf-8" ?>
<D:acl xmlns:D="DAV:">
<D:ace>
<D:principal>
<D:href>http://www.example.com/users/esedlar</D:href>
</D:principal>
<D:grant>
<D:privilege><D:read/></D:privilege>
<D:privilege><D:write/></D:privilege>
</D:grant>
</D:ace>
<D:ace>
<D:principal>
<D:property><D:owner/></D:property>
</D:principal>
<D:grant>
<D:privilege><D:read-acl/></D:privilege>
<D:privilege><D:write-acl/></D:privilege>
</D:grant>
</D:ace>
<D:ace>
<D:principal><D:all/></D:principal>
<D:grant>
<D:privilege><D:read/></D:privilege>
</D:grant>
</D:ace>
</D:acl>
Response <<
HTTP/1.1 200 OK
8.1.3. Example: ACL method failure due to protected ACE conflict π
in this request, user "fielding" (again, authenticated through the Authorization header) tries to deny the principal at http://www.example.com/users/esedlar (the user "esedlar") write privileges π
ββοΈ. before this request, the DAV:acl property had a protected ACE (see Section 5.5.3) granting DAV:owner the DAV:read and DAV:write privileges. and guess what? the principal at http://www.example.com/users/esedlar is the owner of the resource π. so the ACL method fails, because the new ACE clashes with the protected ACE and breaks the whole point of ACE protection π₯²
Request <<
ACL /top/container/ HTTP/1.1
Host: www.example.com
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
Authorization: Digest username="fielding",
realm="users@example.com", nonce="...",
uri="/top/container/", response="...", opaque="..."
<?xml version="1.0" encoding="utf-8" ?>
<D:acl xmlns:D="DAV:">
<D:ace>
<D:principal>
<D:href>http://www.example.com/users/esedlar</D:href>
</D:principal>
<D:deny>
<D:privilege><D:write/></D:privilege>
</D:deny>
</D:ace>
</D:acl>
Response <<
HTTP/1.1 403 Forbidden
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<?xml version="1.0" encoding="utf-8" ?>
<D:error xmlns:D="DAV:">
<D:no-protected-ace-conflict/>
</D:error>
8.1.4. Example: ACL method failure due to an inherited ACE conflict β¨
okay so in this request, user "ejw" (authenticated by the Authorization header) tries to change the ACL on http://www.example.com/top/index.html π
and this resource already has two inherited ACEs π
Inherited ACE #1 grants the principal at http://www.example.com/users/ejw (aka "ejw") the http://www.example.com/privs/write-all privilege and DAV:read-acl. on this server, http://www.example.com/privs/write-all is an aggregate privilege that contains DAV:write and DAV:write-acl π
Inherited ACE #2 grants DAV:all the DAV:read privilege πΈ
the request tries to set a (non-inherited) ACE that denies that same ejw principal DAV:write permission. that clashes with inherited ACE #1, so it's a conflict π ngl, whether the server reports an inherited ACE conflict is up to that server's implementation. another server could just let the new ACE in, then use the normal ACE evaluation rules to figure out whether it actually changes what ejw can do β¨
>> Request <<
ACL /top/index.html HTTP/1.1
Host: www.example.com
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
Authorization: Digest username="ejw",
realm="users@example.com", nonce="...",
uri="/top/index.html", response="...", opaque="..."
<?xml version="1.0" encoding="utf-8" ?>
<D:acl xmlns:D="DAV:" xmlns:F="http://www.example.com/privs/">
<D:ace>
<D:principal>
<D:href>http://www.example.com/users/ejw</D:href>
</D:principal>
<D:grant><D:write/></D:grant>
</D:ace>
</D:acl>
>> Response <<
HTTP/1.1 403 Forbidden
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<?xml version="1.0" encoding="utf-8" ?>
<D:error xmlns:D="DAV:">
<D:no-inherited-ace-conflict/>
</D:error>
8.1.5. Example: ACL method failure due to an attempt to set grant and deny in a single ACE π
in this one, user "ygoland" (authenticated by the Authorization header) tries to change the ACL on http://www.example.com/diamond/engagement-ring.gif π the ACL request has a single ACE that's both syntactically and semantically wrong π it tries to grant the group at http://www.example.com/users/friends DAV:read and deny the principal at http://www.example.com/users/ygoland-so (aka "ygoland-so") DAV:read too. but you can't have multiple principal elements or both a grant and a deny element in the same ACE. so the request fails on bad syntax π
>> Request <<
ACL /diamond/engagement-ring.gif HTTP/1.1
Host: www.example.com
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
Authorization: Digest username="ygoland",
realm="users@example.com", nonce="...",
uri="/diamond/engagement-ring.gif", response="...",
opaque="..."
<?xml version="1.0" encoding="utf-8" ?>
<D:acl xmlns:D="DAV:">
<D:ace>
<D:principal>
<D:href>http://www.example.com/users/friends</D:href>
</D:principal>
<D:grant><D:read/></D:grant>
<D:principal>
<D:href>http://www.example.com/users/ygoland-so</D:href>
</D:principal>
<D:deny><D:read/></D:deny>
</D:ace>
</D:acl>
>> Response <<
HTTP/1.1 400 Bad Request
Content-Length: 0
Note that if the request had been split into two ACEs, one to grant and one to deny, it would have been syntactically well formed π«Ά
9. Access Control Reports π
9.1. REPORT Method π
okay the REPORT method (defined in Section 3.6 of [RFC3253]) is basically an extensible way to get information about a resource β¨ PROPFIND gives you the value of one or more named properties, but REPORT can do way more complex processing. it's super useful when the server has everything it needs to handle a complex request (like a query) and the client would otherwise need a bunch of separate requests to get the same info π§
A server that supports the WebDAV Access Control Protocol MUST support the DAV:expand-property report (defined in Section 3.8 of [RFC3253]) π
9.2. DAV:acl-principal-prop-set Report π
the DAV:acl-principal-prop-set report returns, for every principal in the DAV:acl property of the Request-URI that's identified by an http(s) URL or by a DAV:property principal, the values of the properties listed in the REPORT request body π if a principal URL shows up more than once, the report MUST return that principal's properties only once. support for this report is REQUIRED π
one big use for this is grabbing the human readable name (from the DAV:displayname property) of each principal in an ACL. that's great for building UIs that show each ACE in a way people can actually read π
Marshalling
the request body MUST be a DAV:acl-principal-prop-set XML element.
<!ELEMENT acl-principal-prop-set ANY>
ANY value: a sequence of one or more elements, with at most one
DAV:prop element.
prop: see RFC 2518, Section 12.11
this report is only defined when the Depth header has the value "0". other values get you a 400 (Bad Request) error response. Note that [RFC3253], Section 3.6, says that if the Depth header isn't there, it defaults to "0" π
the response body for a successful request MUST be a DAV:multistatus XML element (basically the same format as a PROPFIND response). if there are no response elements, the returned multistatus XML element is empty.
multistatus: see RFC 2518, Section 12.9
the response body for a successful DAV:acl-principal-prop-set REPORT request MUST contain a DAV:response element for each principal identified by an http(s) URL that's listed in a DAV:principal XML element of an ACE within the DAV:acl property of the resource identified by the Request-URI π«Ά
Postconditions:
- (DAV:number-of-matches-within-limits): the number of matching principals must fall within server-specific, predefined limits. for example, this could be triggered if a search would return an extremely large number of responses π
9.2.1. Example: DAV:acl-principal-prop-set Report π¦
Resource http://www.example.com/index.html has an ACL with three ACEs:
ACE #1: all principals (DAV:all) have DAV:read and DAV:read-current-user-privilege-set access π
ACE #2: the principal at http://www.example.com/people/gstein (the user "gstein") is granted DAV:write, DAV:write-acl, and DAV:read-acl privileges β¨
ACE #3: the group at http://www.example.com/groups/authors (the "authors" group) is granted DAV:write and DAV:read-acl privileges πΈ
this example shows a DAV:acl-principal-prop-set report asking for the DAV:displayname property. it returns the DAV:displayname for http://www.example.com/people/gstein and http://www.example.com/groups/authors, but not for DAV:all, since that isn't an http(s) URL π
>> Request <<
REPORT /index.html HTTP/1.1
Host: www.example.com
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
Depth: 0
<?xml version="1.0" encoding="utf-8" ?>
<D:acl-principal-prop-set xmlns:D="DAV:">
<D:prop>
<D:displayname/>
</D:prop>
</D:acl-principal-prop-set>
>> Response <<
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.example.com/people/gstein</D:href>
<D:propstat>
<D:prop>
<D:displayname>Greg Stein</D:displayname>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://www.example.com/groups/authors</D:href>
<D:propstat>
<D:prop>
<D:displayname>Site authors</D:displayname>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
</D:response>
</D:multistatus>
9.3. DAV:principal-match REPORT πͺ
the DAV:principal-match REPORT is used to find all members (at any depth) of the collection identified by the Request-URI that are principals and that match the current user π if the collection has principals in it, the report can pick out every member that matches the current user. or, if the collection has resources with a property that identifies a principal (like DAV:owner), the report can find every member whose property identifies a principal that matches the current user. for example, this report can return all the resources in a collection hierarchy that are owned by the current user π§ support for this report is REQUIRED β¨
Marshalling:
the request body MUST be a DAV:principal-match XML element.
<!ELEMENT principal-match ((principal-property | self), prop?)>
<!ELEMENT principal-property ANY>
ANY value: an element whose value identifies a property. The
expectation is the value of the named property typically contains
an href element that contains the URI of a principal
<!ELEMENT self EMPTY>
prop: see RFC 2518, Section 12.11
this report is only defined when the Depth header has the value "0". other values get a 400 (Bad Request) error response. Note that [RFC3253], Section 3.6, states that if the Depth header is not present, it defaults to a value of "0". the response body for a successful request MUST be a DAV:multistatus XML element. if there are no response elements, the returned multistatus XML element is empty.
multistatus: see RFC 2518, Section 12.9
the response body for a successful DAV:principal-match REPORT request MUST contain a DAV:response element for each member of the collection that matches the current user π when the DAV:principal-property element is used, a match happens if the current user is matched by the principal identified by the URI in the DAV:href element of the property named by DAV:principal-property. when the DAV:self element is used in a DAV:principal-match report issued against a group, it matches the group if a member identifies the same principal as the current user π
if DAV:prop is specified in the request body, the properties in that DAV:prop element MUST be reported in the DAV:response elements π
9.3.1. Example: DAV:principal-match REPORT π
okay so this example finds the members of the collection at http://www.example.com/doc that are owned by the current user. π«Ά The current user is "gclemm", and she logs in with Digest authentication π
REPORT /doc/ HTTP/1.1
Host: www.example.com
Authorization: Digest username="gclemm",
realm="users@example.com", nonce="...",
uri="/papers/", response="...", opaque="..."
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
Depth: 0
<?xml version="1.0" encoding="utf-8" ?>
<D:principal-match xmlns:D="DAV:">
<D:principal-property>
<D:owner/>
</D:principal-property>
</D:principal-match>
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset="utf-8"
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:">
<D:response>
<D:href>http://www.example.com/doc/foo.html</D:href>
<D:status>HTTP/1.1 200 OK</D:status>
</D:response>
<D:response>
<D:href>http://www.example.com/doc/img/bar.gif</D:href>
<D:status>HTTP/1.1 200 OK</D:status>
</D:response>
</D:multistatus>
9.4. DAV:principal-property-search REPORT β¨
the DAV:principal-property-search REPORT searches for every principal whose properties contain character data that matches the search criteria in the request. π A big use case is finding a person's or group's principal URL by searching for them by name. That works by searching DAV:displayname, which every principal has.
the server gets to decide how matching works: exact, substring, or prefix matching, and whether it's case-sensitive. πΈ This is on purpose, so the report can work with lots of different user management systems. If the server's user store doesn't force a particular behaviour, the preferred default is caseless substring matching.
for efficiency, servers usually don't support searching on every property. π If a search asks for a property that isn't searchable on a given principal, that principal won't match.
Support for the DAV:principal-property-search report is REQUIRED. π₯
Implementation Note: The value of a WebDAV property is a sequence of well-formed XML, so it can include any character in the Unicode/ISO-10646 standard, which means most known characters in human languages. π Case mapping differs a lot between languages, so case-insensitive matching is tricky. Servers that do substring matching are strongly encouraged to look at "The Unicode Standard" [UNICODE4], especially Section 5.18, Subsection "Caseless Matching", for guidance on their case-insensitive matching algorithms. π
Implementation Note: Some implementations of this protocol store principal metadata in an LDAP repository. The schema for each attribute (kind of like a WebDAV property) in an LDAP repository says whether it supports case-sensitive or caseless searching. π§ Leaving the search method up to the server means the default LDAP attribute search behaviour can be used when implementing the DAV:principal-property-search report, which is a huge perk.
Marshalling:
The request body MUST be a DAV:principal-property-search XML element containing a search specification and an optional list of properties. β¨ For every principal that matches the search specification, the response will contain the value of the requested properties on that principal.
<!ELEMENT principal-property-search
((property-search+), prop?, apply-to-principal-collection-set?) >
By default, the report searches all members (at any depth) of the collection identified by the Request-URI. π If DAV:apply-to-principal-collection-set is specified in the request body, the request is applied to each collection identified by the DAV:principal-collection-set property of the resource identified by the Request-URI instead.
The DAV:property-search element holds a prop element that lists the properties to search, plus a match element that holds the search string.
<!ELEMENT property-search (prop, match) >
prop: see RFC 2518, Section 12.11
<!ELEMENT match #PCDATA >
Multiple property-search elements, or multiple elements inside a DAV:prop element, are interpreted with a logical AND. π§
This report is only defined when the Depth header has the value "0". Other values get a 400 (Bad Request) error response. π
ββοΈ Also, [RFC3253], Section 3.6, says that if the Depth header is missing, it defaults to "0". π
The response body for a successful request MUST be a DAV:multistatus XML element. If there are no response elements, the returned multistatus XML element is empty. π«§
multistatus: see RFC 2518, Section 12.9
The response body for a successful DAV:principal-property-search REPORT request MUST contain a DAV:response element for each principal whose property values satisfy the search specification given in DAV:principal-property-search. π¦
If DAV:prop is specified in the request body, the properties in the DAV:prop element MUST be reported in the DAV:response elements. π
Preconditions:
None
Postconditions:
(DAV:number-of-matches-within-limits): The number of matching principals must fall within server-specific, predefined limits. π For example, this condition might be triggered if a search would return an extremely large number of responses.
9.4.1. Matching π
there are a few cases to think about when matching strings. The easiest one is when a property value is "simple", meaning it only has character information item content (see [REC-XML-INFOSET]). For example, the search string "julian" would match the DAV:displayname property with the value "Julian Reschke". π· On the wire, DAV:displayname in this case is marshalled as:
<D:displayname xmlns:D="DAV:">Julian Reschke</D:displayname>
The property's name is encoded into the XML element information item, and the character information item content of the property is "Julian Reschke".
A more complicated case is when a property has mixed content, which means compound values made of multiple child element items, other kinds of information items, and character information item content. π Take the property "aprop" in the namespace "http://www.example.com/props/", marshalled as:
<W:aprop xmlns:W="http://www.example.com/props/">
{cdata 0}<W:elem1>{cdata 1}</W:elem1>
<W:elem2>{cdata 2}</W:elem2>{cdata 3}
</W:aprop>
In this case, matching happens on each individual contiguous sequence of character information items. In the example above, a search string gets compared against these four strings:
{cdata 0}
{cdata 1}
{cdata 2}
{cdata 3}
So that's four separate matches, one each for {cdata 0}, {cdata 1}, {cdata 2}, and {cdata 3}. π«Ά
9.4.2. Example: successful DAV:principal-property-search REPORT π₯³
in this example, the client asks for the principal URLs of every user whose DAV:displayname contains the substring "doE" and whose "title" property in the namespace "http://BigCorp.com/ns/" (their professional title) contains "Sales". πΌ On top of that, the client asks for five properties to come back with each matching principal:
In the DAV: namespace: displayname
In the http://www.example.com/ns/ namespace: department, phone, office, salary
The response shows that two principal resources match the search, "John Doe" and "Zygdoebert Smith". π The "salary" property in the namespace "http://www.example.com/ns/" isn't returned, because the principal making the request doesn't have enough access rights to read it. π
REPORT /users/ HTTP/1.1
Host: www.example.com
Content-Type: text/xml; charset=utf-8
Content-Length: xxxx
Depth: 0
<?xml version="1.0" encoding="utf-8" ?>
<D:principal-property-search xmlns:D="DAV:">
<D:property-search>
<D:prop>
<D:displayname/>
</D:prop>
<D:match>doE</D:match>
</D:property-search>
<D:property-search>
<D:prop xmlns:B="http://www.example.com/ns/">
<B:title/>
</D:prop>
<D:match>Sales</D:match>
</D:property-search>
<D:prop xmlns:B="http://www.example.com/ns/">
<D:displayname/>
<B:department/>
<B:phone/>
<B:office/>
<B:salary/>
</D:prop>
</D:principal-property-search>
HTTP/1.1 207 Multi-Status
Content-Type: text/xml; charset=utf-8
Content-Length: xxxx
<?xml version="1.0" encoding="utf-8" ?>
<D:multistatus xmlns:D="DAV:" xmlns:B="http://BigCorp.com/ns/">
<D:response>
<D:href>http://www.example.com/users/jdoe</D:href>
<D:propstat>
<D:prop>
<D:displayname>John Doe</D:displayname>
<B:department>Widget Sales</B:department>
<B:phone>234-4567</B:phone>
<B:office>209</B:office>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
<D:propstat>
<D:prop>
<B:salary/>
</D:prop>
<D:status>HTTP/1.1 403 Forbidden</D:status>
</D:propstat>
</D:response>
<D:response>
<D:href>http://www.example.com/users/zsmith</D:href>
<D:propstat>
<D:prop>
<D:displayname>Zygdoebert Smith</D:displayname>
<B:department>Gadget Sales</B:department>
<B:phone>234-7654</B:phone>
<B:office>114</B:office>
</D:prop>
<D:status>HTTP/1.1 200 OK</D:status>
</D:propstat>
<D:propstat>
<D:prop>
<B:salary/>
</D:prop>
<D:status>HTTP/1.1 403 Forbidden</D:status>
</D:propstat>
</D:response>
</D:multistatus>
9.5. DAV:principal-search-property-set REPORT β¨
Okay bestie, this REPORT is how you find out which properties you can actually search with the DAV:principal-property-search REPORT from Section 9.4 π It's basically the menu of search options π
Servers MUST support the DAV:principal-search-property-set REPORT on every collection listed in the value of a DAV:principal-collection-set property π«Ά
A user agent could use the results of this REPORT to build a search box so people can look up principals π Iconic.
Supporting this report is REQUIRED π
Implementation Note: Some clients have really limited screen space for listing searchable properties π± In that case, a user would probably love having the most-searched properties show up on-screen instead of making them scroll through a giant list. One way to signal which ones are the most popular is to put them near the start of the list. Then a client can display the list in order, so the popular properties are likely to be on-screen and don't need any scrolling to pick π
Marshalling:
The request body MUST be an empty DAV:principal-search-property-set XML element π
This report is only defined when the Depth header has the value "0". Any other value gets a 400 (Bad Request) error response π
ββοΈ Also, [RFC3253], Section 3.6, says that if the Depth header isn't there at all, it defaults to "0", so you're not stuck guessing π€
The response body MUST be a DAV:principal-search-property-set XML element π¦ It contains one DAV:principal-search-property XML element for each property that can be searched with the DAV:principal-property-search REPORT. A server MAY limit its response to just a subset of the searchable properties, like the ones an interactive access control client is most likely to need π
<!ELEMENT principal-search-property-set
(principal-search-property*) >
Each DAV:principal-search-property XML element holds exactly one searchable property plus a description of it πΈ
<!ELEMENT principal-search-property (prop, description) >
The DAV:prop element holds one principal property that the server can use for a DAV:principal-property-search REPORT β¨
prop: see RFC 2518, Section 12.11
The description element is a human-readable explanation of what the property represents π Servers MUST indicate the human language of the description using the xml:lang attribute, and SHOULD consider the HTTP Accept-Language request header when picking one of several available languages π
<!ELEMENT description #PCDATA >
9.5.1. Example: DAV:principal-search-property-set REPORT
Let's see it in action π¦ In this example, the client finds out which principal properties are searchable by sending the DAV:principal-search-property-set REPORT to the root of the server's principal URL collection set, which is http://www.example.com/users/.
Request <<
REPORT /users/ HTTP/1.1
Host: www.example.com
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
Accept-Language: en, de
Authorization: BASIC d2FubmFtYWs6cGFzc3dvcmQ=
Depth: 0
<?xml version="1.0" encoding="utf-8" ?>
<D:principal-search-property-set xmlns:D="DAV:"/>
Response <<
HTTP/1.1 200 OK
Content-Type: text/xml; charset="utf-8"
Content-Length: xxx
<?xml version="1.0" encoding="utf-8" ?>
<D:principal-search-property-set xmlns:D="DAV:">
<D:principal-search-property>
<D:prop>
<D:displayname/>
</D:prop>
<D:description xml:lang="en">Full name</D:description>
</D:principal-search-property>
<D:principal-search-property>
<D:prop xmlns:B="http://BigCorp.com/ns/">
<B:title/>
</D:prop>
<D:description xml:lang="en">Job title</D:description>
</D:principal-search-property>
</D:principal-search-property-set>
10. XML Processing π§©
Implementations of this specification MUST support the XML element ignore rule, as specified in Section 23.3.2 of [RFC2518], and the XML Namespace recommendation [REC-XML-NAMES] π
Also, the DAV namespace is reserved for XML elements and property names that are defined in a standards-track or Experimental IETF RFC. So don't just make up stuff in there π ββοΈ
11. Internationalization Considerations π
Okay so in this spec, the only human-readable stuff is the description XML element, which lives inside the DAV:supported-privilege-set property π¬ It explains what the capabilities controlled by a privilege actually do. That means the description element has to be able to hold descriptions in multiple character sets. Since it's inside a WebDAV property, it goes over the wire as XML [REC-XML], so it gets to use XML's language tagging and character set encoding. Honestly, the glow-up is real β¨
XML processors at minimum must be able to read XML elements encoded with the UTF-8 [RFC3629] encoding of the ISO 10646 multilingual plane π The XML examples in this spec show the charset parameter of the Content-Type header, defined in [RFC3023], along with the XML "encoding" attribute. Together they tell both MIME and XML processors what charset is being used π€ This spec also requires server implementations to tag description fields with the xml:lang attribute (see Section 2.12 of [REC-XML]), which says what human language the description is in. On top of that, server implementations should look at the Accept-Language HTTP header to figure out which description string to send back πΈ
For XML elements other than the description element, implementations are expected to treat property names, privilege names, and values as tokens. Then they convert those tokens into readable text in the user's language and character set before showing them to a person π Only a generic WebDAV property display utility would show these raw values to a human π
For error reporting, we follow the HTTP/1.1 status code convention. Each status code comes with a short English description, like 200 (OK) π£ A poorly made user agent might show that message to users, but internationalized apps will ignore it and show an appropriate message in the user's language and character set π«Ά
Further internationalization considerations for this protocol are described in the WebDAV Distributed Authoring protocol specification [RFC2518] π
12. Security Considerations π
Bestie, this part is serious π Applications and users of this access control protocol should be aware of several security considerations, which are detailed below. On top of what's in this document, you should also consider the security considerations in the HTTP/1.1 specification [RFC2616], the WebDAV Distributed Authoring Protocol specification [RFC2518], and the XML Media Types specification [RFC3023] in any security analysis of this protocol π‘οΈ
12.1. Increased Risk of Compromised Users π¨
Here's the tea. Without a way to change ACLs remotely, if one user's login gets compromised, the attacker can only read, modify, move, or delete the resources that user already had access to π But once this access control protocol exists, if one compromised user can change ACLs for a whole bunch of other users (like a super-user), then a single compromised account can mess with way more resources. Yikes π You can reduce this risk by limiting how many people have write-acl privileges across a broad range of resources π
12.2. Risks of the DAV:read-acl and DAV:current-user-privilege-set Privileges π
Reading access privileges might seem harmless, because reading an ACL can't possibly change the resource's state π Like, the access privileges (stored in the DAV:acl property), or the privileges the currently authenticated user has (stored in the DAV:current-user-privilege-set property), feel innocent. BUT, if every resource has world-readable ACLs, an attacker can run an exhaustive search for resources that accidentally left themselves vulnerable, like being world-writable π± The property retrieval method PROPFIND, run with Depth infinity on an entire hierarchy, is a super efficient way to grab the DAV:acl or DAV:current-user-privilege-set properties. Once they find an open resource, they can use it for a denial of service attack by overwriting it over and over π₯ Or they can just modify writable resources in sneaky, undesirable ways π
To reduce this risk, read-acl privileges should not be granted to unauthenticated principals π« Also, restrictions on read-acl and read-current-user-privilege-set privileges for authenticated principals should be carefully analyzed when you deploy this protocol π§ Access to the current-user-privilege-set property is a tradeoff between usability and security. When the current-user-privilege-set is visible, user interfaces can show extra info about permitted and restricted operations, but that same info might also reveal a vulnerability someone could exploit π« So deployments need to weigh this tradeoff against what their environment actually requires π
12.3. No Foreknowledge of Initial ACL π₯Ί
To keep the protocol simpler, this spec intentionally doesn't cover how to manage or discover the initial ACL that gets put on a resource when it's created π€·ββοΈ The only way to find the initial ACL is to create a new resource and then fetch the DAV:acl property. And that only works if the principal who made the resource was also granted the DAV:read-acl privilege π
So a principal could create a resource and then find out its ACL grants privileges they don't want π¬ Even worse, the protocol makes it possible (though unlikely) that the creating principal can't modify the ACL, or even delete the resource π And even when the ACL can be changed, there's a short window where the resource exists with the initial ACL before its new one gets set β³
A few things help with this risk. Human principals are often aware of the default access permissions in their editing environments, and they factor that into what they write π Also, default privilege policies are usually really conservative, which limits the privileges the initial ACL grants π«Ά
13. Authentication π
Authentication mechanisms defined for HTTP and WebDAV also apply to this WebDAV Access Control Protocol πΈ That includes the Basic and Digest authentication mechanisms defined in [RFC2617]. Implementing the ACL spec requires that Basic authentication, if it's used, MUST only be supported over a secure transport such as TLS π No plaintext vibes allowed π ββοΈ
14. IANA Considerations β¨
okay so IANA stuff π
this spec uses the XML element namespace that [RFC2518] already set up, which is the DAV: URI namespace. It was registered earlier in the URI schemes registry, so no new drama πΈ Everything else [RFC2518] says about IANA considerations also applies here π«Ά
15. Acknowledgements
this protocol is a group project from the WebDAV ACL design team π the team is Bernard Chester, Geoff Clemm, Anne Hopkins, Barry Lind, Sean Lyndersay, Eric Sedlar, Greg Stein, and Jim Whitehead. the authors are super grateful for the detailed reviews and comments from Jim Amsden, Dylan Barrell, Gino Basso, Murthy Chintalapati, Lisa Dusseault, Stefan Eissing, Tim Ellison, Yaron Goland, Dennis Hamilton, Laurie Harper, Eckehard Hermann, Ron Jacobs, Chris Knight, Remy Maucherat, Larry Masinter, Joe Orton, Peter Raymond, and Keith Wannamaker π
Keith Wannamaker wrote the initial text for the principal property search sections, so he gets a whole extra crown π Earlier work on WebDAV access control protocols came from Yaron Goland, Paul Leach, Lisa Dusseault, Howard Palmer, and Jon Radoff β¨ and the authors also want to shout out the foundation laid by the DeltaV, WebDAV and HTTP protocol authors, which this protocol is built on, plus the feedback from the WebDAV working group π¦
16. References
16.1. Normative References
[REC-XML]Bray, T., Paoli, J., Sperberg-McQueen, C. and E. Maler, "Extensible Markup Language (XML) 1.0 ((Third ed)", W3C REC REC-xml-20040204, February 2004,<http://www.w3.org/TR/2004/REC-xml-20040204>.[REC-XML-INFOSET]Cowan, J. and R. Tobin, "XML Information Set (Second Edition)", W3C REC REC-xml-infoset-20040204, February 2004,<http://www.w3.org/TR/2004/REC-xml-infoset-20040204/>.[REC-XML-NAMES]Bray, T., Hollander, D. and A. Layman, "Namespaces in XML", W3C REC REC-xml-names-19990114, January 1999,<http://www.w3.org/TR/1999/REC-xml-names-19990114>.[RFC2119]Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.[RFC2518]Goland, Y., Whitehead, E., Faizi, A., Carter, S. and D. Jensen, "HTTP Extensions for Distributed Authoring -- WEBDAV", RFC 2518, February 1999.[RFC2616]Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P. and T. Berners-Lee, "Hypertext Transfer Protocol -- HTTP/1.1", RFC 2616, June 1999.[RFC2617]Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S., Leach, P., Luotonen, A. and L. Stewart, "HTTP Authentication: Basic and Digest Access Authentication", RFC 2617, June 1999.[RFC3023]Murata, M., St.Laurent, S. and D. Kohn, "XML Media Types", RFC 3023, January 2001.[RFC3253]Clemm, G., Amsden, J., Ellison, T., Kaler, C. and J. Whitehead, "Versioning Extensions to WebDAV", RFC 3253, March 2002.[RFC3530]Shepler, S., Ed., Callaghan, B., Robinson, D., Thurlow, R., Beame, C., Eisler, M. and D. Noveck, "Network File System (NFS) version 4 Protocol", RFC 3530, April 2003.[RFC3629]Yergeau, F., "UTF-8, a transformation format of ISO 10646", STD 63, RFC 3629 November 2003.
16.2. Informative References
[RFC2251]Wahl, M., Howes, T. and S. Kille, "Lightweight Directory Access Protocol (v3)", RFC 2251, December 1997.[RFC2255]Howes, T. and M. Smith, "The LDAP URL Format", RFC 2255, December 1997.[UNICODE4]The Unicode Consortium, "The Unicode Standard - Version 4.0", Addison-Wesley , August 2003,<http://www.unicode.org/versions/Unicode4.0.0/>. ISBN 0321185781.
Appendix A. WebDAV XML Document Type Definition Addendum
all the XML elements in this Document Type Definition (DTD) belong to the DAV namespace π think of this DTD as an add-on to the DTD in [RFC2518], section 23.1 β¨
<!-- Privileges -- (Section 3)>
<!ELEMENT read EMPTY>
<!ELEMENT write EMPTY>
<!ELEMENT write-properties EMPTY>
<!ELEMENT write-content EMPTY>
<!ELEMENT unlock EMPTY>
<!ELEMENT read-acl EMPTY>
<!ELEMENT read-current-user-privilege-set EMPTY>
<!ELEMENT write-acl EMPTY>
<!ELEMENT bind EMPTY>
<!ELEMENT unbind EMPTY>
<!ELEMENT all EMPTY>
<!-- Principal Properties (Section 4) -->
<!ELEMENT principal EMPTY>
<!ELEMENT alternate-URI-set (href*)>
<!ELEMENT principal-URL (href)>
<!ELEMENT group-member-set (href*)>
<!ELEMENT group-membership (href*)>
<!-- Access Control Properties (Section 5) -->
<!-- DAV:owner Property (Section 5.1) -->
<!ELEMENT owner (href?)>
<!-- DAV:group Property (Section 5.2) -->
<!ELEMENT group (href?)>
<!-- DAV:supported-privilege-set Property (Section 5.3) -->
<!ELEMENT supported-privilege-set (supported-privilege*)>
<!ELEMENT supported-privilege
(privilege, abstract?, description, supported-privilege*)>
<!ELEMENT privilege ANY>
<!ELEMENT abstract EMPTY>
<!ELEMENT description #PCDATA>
<!-- DAV:current-user-privilege-set Property (Section 5.4) -->
<!ELEMENT current-user-privilege-set (privilege*)>
<!-- DAV:acl Property (Section 5.5) -->
<!ELEMENT acl (ace)* >
<!ELEMENT ace ((principal | invert), (grant|deny), protected?,
inherited?)>
<!ELEMENT principal (href)
| all | authenticated | unauthenticated
| property | self)>
<!ELEMENT all EMPTY>
<!ELEMENT authenticated EMPTY>
<!ELEMENT unauthenticated EMPTY>
<!ELEMENT property ANY>
<!ELEMENT self EMPTY>
<!ELEMENT invert principal>
<!ELEMENT grant (privilege+)>
<!ELEMENT deny (privilege+)>
<!ELEMENT privilege ANY>
<!ELEMENT protected EMPTY>
<!ELEMENT inherited (href)>
<!-- DAV:acl-restrictions Property (Section 5.6) -->
<!ELEMENT acl-restrictions (grant-only?, no-invert?,
deny-before-grant?, required-principal?)>
<!ELEMENT grant-only EMPTY>
<!ELEMENT no-invert EMPTY>
<!ELEMENT deny-before-grant EMPTY>
<!ELEMENT required-principal
(all? | authenticated? | unauthenticated? | self? | href*
|property*)>
<!-- DAV:inherited-acl-set Property (Section 5.7) -->
<!ELEMENT inherited-acl-set (href*)>
<!-- DAV:principal-collection-set Property (Section 5.8) -->
<!ELEMENT principal-collection-set (href*)>
<!-- Access Control and Existing Methods (Section 7) -->
<!ELEMENT need-privileges (resource)* >
<!ELEMENT resource ( href, privilege )
<!-- ACL method preconditions (Section 8.1.1) -->
<!ELEMENT no-ace-conflict EMPTY>
<!ELEMENT no-protected-ace-conflict EMPTY>
<!ELEMENT no-inherited-ace-conflict EMPTY>
<!ELEMENT limited-number-of-aces EMPTY>
<!ELEMENT grant-only EMPTY>
<!ELEMENT no-invert EMPTY>
<!ELEMENT deny-before-grant EMPTY>
<!ELEMENT no-abstract EMPTY>
<!ELEMENT not-supported-privilege EMPTY>
<!ELEMENT missing-required-principal EMPTY>
<!ELEMENT recognized-principal EMPTY>
<!ELEMENT allowed-principal EMPTY>
<!-- REPORTs (Section 9) -->
<!ELEMENT acl-principal-prop-set ANY>
ANY value: a sequence of one or more elements, with at most one
DAV:prop element.
<!ELEMENT principal-match ((principal-property | self), prop?)>
<!ELEMENT principal-property ANY>
ANY value: an element whose value identifies a property. The
expectation is the value of the named property typically contains
an href element that contains the URI of a principal
<!ELEMENT self EMPTY>
<!ELEMENT principal-property-search ((property-search+), prop?) >
<!ELEMENT property-search (prop, match) >
<!ELEMENT match #PCDATA >
<!ELEMENT principal-search-property-set (
principal-search-property*) >
<!ELEMENT principal-search-property (prop, description) >
<!ELEMENT description #PCDATA >
Appendix B. WebDAV Method Privilege Table (Normative) β¨
okay bestie, this table is basically the cheat sheet for which privileges each WebDAV method needs ππ it covers the methods from RFC 2518, 2616, and 3253. the big rule is that if one of the listed privileges is denied, access MUST be denied π« but having all of them doesn't guarantee access π ββοΈ because an implementation MAY define an extra custom privilege that gates existing methods. and lacking the listed privileges doesn't automatically mean denied either, since a sub-privilege aggregated under the listed one might be what's actually doing the gating π€·ββοΈ also, unless it says otherwise, the privileges refer to the current resource being processed π
+---------------------------------+---------------------------------+
| METHOD | PRIVILEGES |
+---------------------------------+---------------------------------+
| GET | <D:read> |
| HEAD | <D:read> |
| OPTIONS | <D:read> |
| PUT (target exists) | <D:write-content> on target |
| | resource |
| PUT (no target exists) | <D:bind> on parent collection |
| | of target |
| PROPPATCH | <D:write-properties> |
| ACL | <D:write-acl> |
| PROPFIND | <D:read> (plus <D:read-acl> and |
| | <D:read-current-user-privilege- |
| | set> as needed) |
| COPY (target exists) | <D:read>, <D:write-content> and |
| | <D:write-properties> on target |
| | resource |
| COPY (no target exists) | <D:read>, <D:bind> on target |
| | collection |
| MOVE (no target exists) | <D:unbind> on source collection |
| | and <D:bind> on target |
| | collection |
| MOVE (target exists) | As above, plus <D:unbind> on |
| | the target collection |
| DELETE | <D:unbind> on parent collection |
| LOCK (target exists) | <D:write-content> |
| LOCK (no target exists) | <D:bind> on parent collection |
| MKCOL | <D:bind> on parent collection |
| UNLOCK | <D:unlock> |
| CHECKOUT | <D:write-properties> |
| CHECKIN | <D:write-properties> |
| REPORT | <D:read> (on all referenced |
| | resources) |
| VERSION-CONTROL | <D:write-properties> |
| MERGE | <D:write-content> |
| MKWORKSPACE | <D:write-content> on parent |
| | collection |
| BASELINE-CONTROL | <D:write-properties> and |
| | <D:write-content> |
| MKACTIVITY | <D:write-content> on parent |
| | collection |
+---------------------------------+---------------------------------+
Index ποΈ
A
ACL method 40
C
Condition Names
DAV:allowed-principal (pre) 42
DAV:deny-before-grant (pre) 41
DAV:grant-only (pre) 41
DAV:limited-number-of-aces (pre) 41
DAV:missing-required-principal (pre) 42
DAV:no-abstract (pre) 41
DAV:no-ace-conflict (pre) 41
DAV:no-inherited-ace-conflict (pre) 41
DAV:no-invert (pre) 41
DAV:no-protected-ace-conflict (pre) 41
DAV:not-supported-privilege (pre) 42
DAV:number-of-matches-within-limits (post) 48, 53
DAV:recognized-principal (pre) 42
D
DAV header
compliance class 'access-control' 38
DAV:acl property 23
DAV:acl-principal-prop-set report 48
DAV:acl-restrictions property 27
DAV:all privilege 13
DAV:allowed-principal precondition 42
DAV:alternate-URI-set property 14
DAV:bind privilege 12
DAV:current-user-privilege-set property 21
DAV:deny-before-grant precondition 41
DAV:grant-only precondition 41
DAV:group property 18
DAV:group-member-set property 14
DAV:group-membership property 14
DAV:inherited-acl-set property 29
DAV:limited-number-of-aces precondition 41
DAV:missing-required-principal precondition 42
DAV:no-abstract precondition 41
DAV:no-ace-conflict precondition 41
DAV:no-inherited-ace-conflict precondition 41
DAV:no-invert precondition 41
DAV:no-protected-ace-conflict precondition 41
DAV:not-supported-privilege precondition 42
DAV:number-of-matches-within-limits postcondition 48, 53
DAV:owner property 15
DAV:principal resource type 13
DAV:principal-collection-set property 30
DAV:principal-match report 50
DAV:principal-property-search 51
DAV:principal-search-property-set 56
DAV:principal-URL property 14
DAV:read privilege 10
DAV:read-acl privilege 11
DAV:read-current-user-privilege-set privilege 12
DAV:recognized-principal precondition 42
DAV:supported-privilege-set property 18
DAV:unbind privilege 12
DAV:unlock privilege 11
DAV:write privilege 10
DAV:write-acl privilege 12
DAV:write-content privilege 10
DAV:write-properties privilege 10
M
Methods
ACL 40
P
Privileges
DAV:all 13
DAV:bind 12
DAV:read 10
DAV:read-acl 11
DAV:read-current-user-privilege-set 12
DAV:unbind 12
DAV:unlock 11
DAV:write 10
DAV:write-acl 12
DAV:write-content 11
DAV:write-properties 10
Properties
DAV:acl 23
DAV:acl-restrictions 27
DAV:alternate-URI-set 14
DAV:current-user-privilege-set 21
DAV:group 18
DAV:group-member-set 14
DAV:group-membership 14
DAV:inherited-acl-set 29
DAV:owner 15
DAV:principal-collection-set 30
DAV:principal-URL 14
DAV:supported-privilege-set 18
R
Reports
DAV:acl-principal-prop-set 47
DAV:principal-match 49
DAV:principal-property-search 51
DAV:principal-search-property-set 56
Resource Types
DAV:principal 13
Authors' Addresses ποΈ
Geoffrey Clemm
IBM
20 Maguire Road
Lexington, MA 02421
EMail: geoffrey.clemm@us.ibm.com
Julian F. Reschke
greenbytes GmbH
Salzmannstrasse 152
Muenster, NW 48159
Germany
EMail: julian.reschke@greenbytes.de
Eric Sedlar
Oracle Corporation
500 Oracle Parkway
Redwood Shores, CA 94065
EMail: eric.sedlar@oracle.com
Jim Whitehead
U.C. Santa Cruz, Dept. of Computer Science
1156 High Street
Santa Cruz, CA 95064
EMail: ejw@cse.ucsc.edu
Full Copyright Statement π
Copyright (C) The Internet Society (2004). this document is subject to the rights, licenses and restrictions in BCP 78, and except as set out there, the authors keep all their rights π
this document and the info in it are provided "AS IS", and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED. that includes, but isn't limited to, any warranty that using the info won't infringe any rights, and any implied warranties of merchantability or fitness for a particular purpose π
Intellectual Property π§
the IETF takes no position on whether any Intellectual Property Rights or other rights that might be claimed to cover the technology in this document are valid or in scope, or on whether any license under those rights might or might not be available. it also doesn't claim to have made any independent effort to find such rights. info about how rights in RFC documents are handled is in BCP 78 and BCP 79 π
copies of IPR disclosures sent to the IETF Secretariat, and any assurances of licenses to be made available, or the result of an attempt to get a general license or permission to use those proprietary rights for implementers or users of this spec, can be found in the IETF online IPR repository at http://www.ietf.org/ipr π
the IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology required to implement this standard. send that info to the IETF at ietf-ipr@ietf.org π«Ά
Acknowledgement πΈ
funding for the RFC Editor function is currently provided by the Internet Society β¨
π¦ where this page comes from
- ietf: rfc3744 2004-05
- π girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms