ProPeler
Home
Console
Upload
information
Create File
Create Folder
About
Tools
:
/
opt
/
cpanel-ccs
/
txdav
/
xml
/
Filename :
rfc3744.py
back
Copy
## # Copyright (c) 2005-2017 Apple Inc. All rights reserved. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. ## """ RFC 3744 (WebDAV Access Control Protocol) XML Elements This module provides XML element definitions for use with WebDAV. See RFC 3744: http://www.ietf.org/rfc/rfc3744.txt """ __all__ = [] from txdav.xml.base import WebDAVElement, PCDATAElement from txdav.xml.base import WebDAVEmptyElement, WebDAVTextElement from txdav.xml.element import dav_namespace, registerElement, registerElementClass ## # Section 3 (Privileges) ## @registerElement @registerElementClass class Read (WebDAVEmptyElement): """ Privilege which controls methods that return information about the state of a resource, including the resource's properties. (RFC 3744, section 3.1) """ name = "read" # For DAV:write element (RFC 3744, section 3.2) see Write class in # rfc2518.py. @registerElement @registerElementClass class WriteProperties (WebDAVEmptyElement): """ Privilege which controls methods that modify the dead properties of a resource. (RFC 3744, section 3.3) """ name = "write-properties" @registerElement @registerElementClass class WriteContent (WebDAVEmptyElement): """ Privilege which controls methods that modify the content of an existing resource. (RFC 3744, section 3.4) """ name = "write-content" @registerElement @registerElementClass class Unlock (WebDAVEmptyElement): """ Privilege which controls the use of the UNLOCK method by a principal other than the lock owner. (RFC 3744, section 3.5) """ name = "unlock" @registerElement @registerElementClass class ReadACL (WebDAVEmptyElement): """ Privilege which controls the use of the PROPFIND method to retrieve the DAV:acl property of a resource. (RFC 3744, section 3.6) """ name = "read-acl" @registerElement @registerElementClass class ReadCurrentUserPrivilegeSet (WebDAVEmptyElement): """ Privilege which controls the use of the PROPFIND method to retrieve the DAV:current-user-privilege-set property of a resource. (RFC 3744, section 3.7) """ name = "read-current-user-privilege-set" @registerElement @registerElementClass class WriteACL (WebDAVEmptyElement): """ Privilege which controls the use of the ACL method to modify the DAV:acl property of a resource. (RFC 3744, section 3.8) """ name = "write-acl" @registerElement @registerElementClass class Bind (WebDAVEmptyElement): """ Privilege which allows a method to add a new member URL from the a collection resource. (RFC 3744, section 3.9) """ name = "bind" @registerElement @registerElementClass class Unbind (WebDAVEmptyElement): """ Privilege which allows a method to remove a member URL from the a collection resource. (RFC 3744, section 3.10) """ name = "unbind" @registerElement @registerElementClass class All (WebDAVEmptyElement): """ Aggregate privilege that contains the entire set of privileges that can be applied to a resource. (RFC 3744, section 3.11) Principal which matches all users. (RFC 3744, section 5.5.1) """ name = "all" ## # Section 4 (Principal Properties) ## @registerElement @registerElementClass class Principal (WebDAVElement): """ Indicates a principal resource type. (RFC 3744, section 4) Identifies the principal to which an ACE applies. (RFC 3744, section 5.5.1) """ name = "principal" allowed_children = { (dav_namespace, "href"): (0, 1), (dav_namespace, "all"): (0, 1), (dav_namespace, "authenticated"): (0, 1), (dav_namespace, "unauthenticated"): (0, 1), (dav_namespace, "property"): (0, 1), (dav_namespace, "self"): (0, 1), } def validate(self): super(Principal, self).validate() if len(self.children) > 1: raise ValueError( "Exactly one of DAV:href, DAV:all, DAV:authenticated, " "DAV:unauthenticated, DAV:property or DAV:self is required for " "{0}, got: {1!r}".format( self.sname(), self.children ) ) @registerElement @registerElementClass class AlternateURISet (WebDAVElement): """ Property which contains the URIs of network resources with additional descriptive information about the principal. (RFC 3744, section 4.1) """ name = "alternate-URI-set" hidden = True protected = True allowed_children = {(dav_namespace, "href"): (0, None)} @registerElement @registerElementClass class PrincipalURL (WebDAVElement): """ Property which contains the URL that must be used to identify this principal in an ACL request. (RFC 3744, section 4.2) """ name = "principal-URL" hidden = True protected = True allowed_children = {(dav_namespace, "href"): (0, 1)} @registerElement @registerElementClass class GroupMemberSet (WebDAVElement): """ Property which identifies the principals that are direct members of a group principal. (RFC 3744, section 4.3) """ name = "group-member-set" hidden = True allowed_children = {(dav_namespace, "href"): (0, None)} @registerElement @registerElementClass class GroupMembership (WebDAVElement): """ Property which identifies the group principals in which a principal is directly a member. (RFC 3744, section 4.4) """ name = "group-membership" hidden = True protected = True allowed_children = {(dav_namespace, "href"): (0, None)} ## # Section 5 (Access Control Properties) ## # For DAV:owner element (RFC 3744, section 5.1) see Owner class in # rfc2518.py. @registerElement @registerElementClass class Group (WebDAVElement): """ Property which identifies a particular principal as being the group principal of a resource. (RFC 3744, section 5.2) """ name = "group" hidden = True protected = True # may be protected, per RFC 3744, section 5.2 allowed_children = {(dav_namespace, "href"): (0, 1)} @registerElement @registerElementClass class SupportedPrivilegeSet (WebDAVElement): """ Property which identifies the privileges defined for a resource. (RFC 3744, section 5.3) """ name = "supported-privilege-set" hidden = True protected = True allowed_children = {(dav_namespace, "supported-privilege"): (0, None)} @registerElement @registerElementClass class SupportedPrivilege (WebDAVElement): """ Identifies a privilege defined for a resource. (RFC 3744, section 5.3) """ name = "supported-privilege" allowed_children = { (dav_namespace, "privilege"): (1, 1), (dav_namespace, "abstract"): (0, 1), (dav_namespace, "description"): (1, 1), (dav_namespace, "supported-privilege"): (0, None), } @registerElement @registerElementClass class Privilege (WebDAVElement): """ Identifies a privilege. (RFC 3744, sections 5.3 and 5.5.1) """ name = "privilege" allowed_children = {WebDAVElement: (0, None)} def isAggregateOf(self, subprivilege, supportedPrivileges): """ Check whether this privilege is an aggregate of another. @param subprivilege: a L{Privilege} @param supportedPrivileges: a L{SupportedPrivilegeSet} @return: C{True} is this privilege is an aggregate of C{subprivilege} according to C{supportedPrivileges}. """ # DAV: all is an aggregate of all privileges if len(self.children) == 1 and self.children[0].qname() == (dav_namespace, "all"): return True def isAggregate(supportedPrivilege): sp = supportedPrivilege.childOfType(Privilege) if sp == self: def find(supportedPrivilege): if supportedPrivilege.childOfType(Privilege) == subprivilege: return True for child in supportedPrivilege.childrenOfType(SupportedPrivilege): if find(child): return True else: return False return find(supportedPrivilege) else: for child in supportedPrivilege.childrenOfType(SupportedPrivilege): if isAggregate(child): return True else: return False for supportedPrivilege in supportedPrivileges.children: if isAggregate(supportedPrivilege): return True else: return False def expandAggregate(self, supportedPrivileges): """ Expand this privilege into the set of privileges aggregated under it based on the structure of the given supported privileges. If this privilege is not an aggregate, just return it as-is. @param supportedPrivileges: a L{SupportedPrivilegeSet} @return: the list of expanded L{Privileges} """ # Find ourselves in supported privileges def find(supportedPrivilege): """ Find the supportPrivilege which matches this privilege. """ if supportedPrivilege.childOfType(Privilege) == self: return supportedPrivilege for child in supportedPrivilege.childrenOfType(SupportedPrivilege): result = find(child) if result is not None: return result else: return None for supportedPrivilege in supportedPrivileges.children: result = find(supportedPrivilege) if result is not None: break else: return [self] # Now add sub-privileges recursively aggregates = [] def add(supportedPrivilege): """ Add all sub-privileges to the list. """ aggregates.append(supportedPrivilege.childOfType(Privilege)) for child in supportedPrivilege.childrenOfType(SupportedPrivilege): add(child) add(result) return aggregates @registerElement @registerElementClass class Abstract (WebDAVElement): """ Identifies a privilege as abstract. (RFC 3744, section 5.3) """ name = "abstract" @registerElement @registerElementClass class Description (WebDAVTextElement): """ A human-readable description of what privilege controls access to. (RFC 3744, sections 5.3 and 9.5) """ name = "description" allowed_attributes = {"xml:lang": True} @registerElement @registerElementClass class CurrentUserPrivilegeSet (WebDAVElement): """ Property which contains the exact set of privileges (as computer by the server) granted to the currently authenticated HTTP user. (RFC 3744, section 5.4) """ name = "current-user-privilege-set" hidden = True protected = True allowed_children = {(dav_namespace, "privilege"): (0, None)} # For DAV:privilege element (RFC 3744, section 5.4) see Privilege class above. @registerElement @registerElementClass class ACL (WebDAVElement): """ Property which specifies the list of access control entries which define what privileges are granted to which users for a resource. (RFC 3744, section 5.5) """ name = "acl" hidden = True protected = True allowed_children = {(dav_namespace, "ace"): (0, None)} @registerElement @registerElementClass class ACE (WebDAVElement): """ Specifies the list of access control entries which define what privileges are granted to which users for a resource. (RFC 3744, section 5.5) """ name = "ace" allowed_children = { (dav_namespace, "principal"): (0, 1), (dav_namespace, "invert"): (0, 1), (dav_namespace, "grant"): (0, 1), (dav_namespace, "deny"): (0, 1), (dav_namespace, "protected"): (0, 1), (dav_namespace, "inherited"): (0, 1), } def __init__(self, *children, **attributes): super(ACE, self).__init__(*children, **attributes) self.principal = None self.invert = None self.allow = None self.privileges = None self.inherited = None self.protected = False my_children = [] for child in self.children: namespace, name = child.qname() if isinstance(child, PCDATAElement): continue if (namespace == dav_namespace): if name in ("principal", "invert"): if self.principal is not None: raise ValueError( "Only one of DAV:principal or DAV:invert allowed in {0}, got: {1}".format( self.sname(), self.children ) ) if name == "invert": self.invert = True self.principal = child.children[0] else: self.invert = False self.principal = child elif name in ("grant", "deny"): if self.allow is not None: raise ValueError( "Only one of DAV:grant or DAV:deny allowed in {0}, got: {1}".format( self.sname(), self.children ) ) self.allow = (name == "grant") self.privileges = child.children elif name == "inherited": self.inherited = str(child.children[0]) elif name == "protected": self.protected = True my_children.append(child) self.children = tuple(my_children) if self.principal is None: raise ValueError( "One of DAV:principal or DAV:invert is required in {0}, got: {1}".format( self.sname(), self.children ) ) assert self.invert is not None if self.allow is None: raise ValueError( "One of DAV:grant or DAV:deny is required in {0}, got: {1}".format( self.sname(), self.children ) ) assert self.privileges is not None # For DAV:principal element (RFC 3744, section 5.5.1) see Principal # class above. # For DAV:all element (RFC 3744, section 5.5.1) see All class above. @registerElement @registerElementClass class Authenticated (WebDAVEmptyElement): """ Principal which matches authenticated users. (RFC 3744, section 5.5.1) """ name = "authenticated" @registerElement @registerElementClass class Unauthenticated (WebDAVEmptyElement): """ Principal which matches unauthenticated users. (RFC 3744, section 5.5.1) """ name = "unauthenticated" # For DAV:property element (RFC 3744, section 5.5.1) see Property # class above. @registerElement @registerElementClass class Self (WebDAVEmptyElement): """ Principal which matches a user if a resource is a principal and the user matches the resource. (RFC 3744, sections 5.5.1 and 9.3) """ name = "self" @registerElement @registerElementClass class Invert (WebDAVElement): """ Principal which matches a user if the user does not match the principal contained by this principal. (RFC 3744, section 5.5.1) """ name = "invert" allowed_children = {(dav_namespace, "principal"): (1, 1)} @registerElement @registerElementClass class Grant (WebDAVElement): """ Grants the contained privileges to a principal. (RFC 3744, section 5.5.2) """ name = "grant" allowed_children = {(dav_namespace, "privilege"): (1, None)} @registerElement @registerElementClass class Deny (WebDAVElement): """ Denies the contained privileges to a principal. (RFC 3744, section 5.5.2) """ name = "deny" allowed_children = {(dav_namespace, "privilege"): (1, None)} # For DAV:privilege element (RFC 3744, section 5.5.2) see Privilege # class above. @registerElement @registerElementClass class Protected (WebDAVEmptyElement): """ Identifies an ACE as protected. (RFC 3744, section 5.5.3) """ name = "protected" @registerElement @registerElementClass class Inherited (WebDAVElement): """ Indicates that an ACE is inherited from the resource identified by the contained DAV:href element. (RFC 3744, section 5.5.4) """ name = "inherited" allowed_children = {(dav_namespace, "href"): (1, 1)} @registerElement @registerElementClass class ACLRestrictions (WebDAVElement): """ Property which defines the types of ACLs supported by this server, to avoid clients needlessly getting errors. (RFC 3744, section 5.6) """ name = "acl-restrictions" hidden = True protected = True allowed_children = { (dav_namespace, "grant-only"): (0, 1), (dav_namespace, "no-invert"): (0, 1), (dav_namespace, "deny-before-grant"): (0, 1), (dav_namespace, "required-principal"): (0, 1), } @registerElement @registerElementClass class GrantOnly (WebDAVEmptyElement): """ Indicates that ACEs with deny clauses are not allowed. (RFC 3744, section 5.6.1) """ name = "grant-only" @registerElement @registerElementClass class NoInvert (WebDAVEmptyElement): """ Indicates that ACEs with the DAV:invert element are not allowed. (RFC 3744, section 5.6.2) """ name = "no-invert" @registerElement @registerElementClass class DenyBeforeGrant (WebDAVEmptyElement): """ Indicates that all deny ACEs must precede all grant ACEs. (RFC 3744, section 5.6.3) """ name = "deny-before-grant" @registerElement @registerElementClass class RequiredPrincipal (WebDAVElement): """ Indicates which principals must have an ACE defined in an ACL. (RFC 3744, section 5.6.4) """ name = "required-principal" allowed_children = { (dav_namespace, "all"): (0, 1), (dav_namespace, "authenticated"): (0, 1), (dav_namespace, "unauthenticated"): (0, 1), (dav_namespace, "self"): (0, 1), (dav_namespace, "href"): (0, None), (dav_namespace, "property"): (0, None), } def validate(self): super(RequiredPrincipal, self).validate() type = None for child in self.children: if type is None: type = child.qname() elif child.qname() != type: raise ValueError( "Only one of DAV:all, DAV:authenticated, DAV:unauthenticated, " "DAV:self, DAV:href or DAV:property allowed for {0}, got: {1}".format( self.sname(), self.children ) ) @registerElement @registerElementClass class InheritedACLSet (WebDAVElement): """ Property which contains a set of URLs that identify other resources that also control the access to this resource. (RFC 3744, section 5.7) """ name = "inherited-acl-set" hidden = True protected = True allowed_children = {(dav_namespace, "href"): (0, None)} @registerElement @registerElementClass class PrincipalCollectionSet (WebDAVElement): """ Property which contains a set of URLs that identify the root collections that contain the principals that are available on the server that implements a resource. (RFC 3744, section 5.8) """ name = "principal-collection-set" hidden = True protected = True allowed_children = {(dav_namespace, "href"): (0, None)} ## # Section 7 (Access Control and existing methods) ## @registerElement @registerElementClass class NeedPrivileges (WebDAVElement): """ Error which indicates insufficient privileges. (RFC 3744, section 7.1.1) """ name = "need-privileges" allowed_children = {(dav_namespace, "resource"): (0, None)} @registerElement @registerElementClass class Resource (WebDAVElement): """ Identifies which resource had insufficient privileges. (RFC 3744, section 7.1.1) """ name = "resource" allowed_children = { (dav_namespace, "href"): (1, 1), (dav_namespace, "privilege"): (1, 1), } ## # Section 9 (Access Control Reports) ## @registerElement @registerElementClass class ACLPrincipalPropSet (WebDAVElement): """ Report which returns, for all principals in the DAV:acl property (of the resource identified by the Request-URI) that are identified by http(s) URLs or by a DAV:property principal, the value of the properties specified in the REPORT request body. (RFC 3744, section 9.2) """ name = "acl-principal-prop-set" allowed_children = {WebDAVElement: (0, None)} def validate(self): super(ACLPrincipalPropSet, self).validate() prop = False for child in self.children: if child.qname() == (dav_namespace, "prop"): if prop: raise ValueError( "Only one DAV:prop allowed for {0}, got: {1}".format( self.sname(), self.children ) ) prop = True @registerElement @registerElementClass class PrincipalMatch (WebDAVElement): """ Report used to identify all members (at any depth) of the collection identified by the Request-URI that are principals and that match the current user. (RFC 3744, section 9.3) """ name = "principal-match" allowed_children = { (dav_namespace, "principal-property"): (0, 1), (dav_namespace, "self"): (0, 1), (dav_namespace, "prop"): (0, 1), } def validate(self): super(PrincipalMatch, self).validate() # This element can be empty when uses in supported-report-set if not len(self.children): return principalPropertyOrSelf = False for child in self.children: namespace, name = child.qname() if (namespace == dav_namespace) and name in ("principal-property", "self"): if principalPropertyOrSelf: raise ValueError( "Only one of DAV:principal-property or DAV:self allowed in {0}, got: {1}".format( self.sname(), self.children ) ) principalPropertyOrSelf = True if not principalPropertyOrSelf: raise ValueError( "One of DAV:principal-property or DAV:self is required in {0}, got: {1}".format( self.sname(), self.children ) ) @registerElement @registerElementClass class PrincipalProperty (WebDAVElement): """ Identifies a property. (RFC 3744, section 9.3) """ name = "principal-property" allowed_children = {WebDAVElement: (0, None)} # For DAV:self element (RFC 3744, section 9.3) see Self class above. @registerElement @registerElementClass class PrincipalPropertySearch (WebDAVElement): """ Report which performs a search for all principals whose properties contain character data that matches the search criteria specified in the request. (RFC 3744, section 9.4) """ name = "principal-property-search" allowed_children = { (dav_namespace, "property-search"): (0, None), # This is required but this element must be empty in supported-report-set (dav_namespace, "prop"): (0, 1), (dav_namespace, "apply-to-principal-collection-set"): (0, 1), } allowed_attributes = {"test": False} @registerElement @registerElementClass class PropertySearch (WebDAVElement): """ Contains a DAV:prop element enumerating the properties to be searched and a DAV:match element, containing the search string. (RFC 3744, section 9.4) """ name = "property-search" allowed_children = { (dav_namespace, "prop"): (1, 1), (dav_namespace, "match"): (1, 1), } @registerElement @registerElementClass class Match (WebDAVTextElement): """ Contains a search string. (RFC 3744, section 9.4) """ name = "match" @registerElement @registerElementClass class PrincipalSearchPropertySet (WebDAVElement): """ Report which identifies those properties that may be searched using the DAV:principal-property-search report. (RFC 3744, section 9.5) """ name = "principal-search-property-set" allowed_children = {(dav_namespace, "principal-search-property"): (0, None)} @registerElement @registerElementClass class PrincipalSearchProperty (WebDAVElement): """ Contains exactly one searchable property, and a description of the property. (RFC 3744, section 9.5) """ name = "principal-search-property" allowed_children = { (dav_namespace, "prop"): (1, 1), (dav_namespace, "description"): (1, 1), } @registerElement @registerElementClass class NumberOfMatchesWithinLimits (WebDAVEmptyElement): """ Error which indicates too many results """ name = "number-of-matches-within-limits" # For DAV:description element (RFC 3744, section 9.5) see Description # class above.