Пример #1
0
 def __init__(self, domroot=None, aces=None):
     """
     Constructor should be called with either no parameters (create blank ACE),
     or one parameter (a DOM tree or ACE list).
     
     @param domroot: A DOM tree (default: None).
     @type  domroot: L{webdav.WebdavResponse.Element} object
     @param aces:    ACE objects (default: None)
     @type  aces:    C{list} of L{ACE} objects
     
     @raise WebdavError: When non-valid parameters are passed a L{WebdavError} is raised.
     """
     self.withInherited = None
     self.aces          = []
     
     if domroot:
         for child in domroot.children:
             if child.name == Constants.TAG_ACE and child.ns == Constants.NS_DAV:
                 self.addAce(ACE(child))
             else:
                 # This shouldn't happen, someone screwed up with the params ...
                 raise WebdavError('Non-ACE tag handed to ACL constructor: ' + child.ns + child.name)
     elif isinstance(aces, list) or isinstance(aces, tuple):
         self.addAces(aces)
     elif domroot == None and aces == None:
         # no param ==> blank object
         pass
     else:
         # This shouldn't happen, someone screwed up with the params ...
         raise WebdavError('non-valid parameters handed to ACL constructor')
Пример #2
0
 def __init__(self, privilege=None, domroot=None):
     """
     Constructor should be called with either no parameters (create blank Privilege),
     one parameter (a DOM tree or privilege name to inicialize it directly).
     
     @param domroot: A DOM tree (default: None).
     @type  domroot: L{webdav.WebdavResponse.Element} object
     @param privilege: The valid name of a privilege (default: None).
     @type  privilege: C{string}
     
     @raise WebdavError: When non-valid parameters or sets of parameters are 
                         passed a L{WebdavError} is raised.
     """
     self.name = None
     
     if domroot:
         if len(domroot.children) != 1:
             raise WebdavError('Wrong number of elements for Privilege constructor, we have: %i' \
                 % (len(domroot.children)))
         else:
             child = domroot.children[0]
             if child.ns == Constants.NS_DAV and child.name in self._TAG_LIST_PRIVILEGES or \
                child.ns == Constants.NS_TAMINO and child.name in self._TAG_LIST_PRIVILEGES_TAMINO:
                 self.name = child.name
             else:
                 raise WebdavError('Not a valid privilege tag, we have: %s%s' \
                     % (child.ns, child.name))
     elif privilege:
         if privilege in self._TAG_LIST_PRIVILEGES:
             self.name = privilege
         else:
             raise WebdavError('Not a valid privilege tag, we have: %s.' % str(privilege))
Пример #3
0
 def __init__(self, domroot=None):
     """
     Constructor should be called with either no parameters 
     (create blank GrantDeny), or one parameter (a DOM tree).
     
     @param domroot:     A DOM tree (default: None).
     @type  domroot:     L{webdav.WebdavResponse.Element} object
     
     @raise WebdavError: When non-valid parameters are passed a L{WebdavError} is raised.
     """
     self.grantDeny  = 0   # 0: deny, 1: grant
     self.privileges = []
     
     if domroot:
         self.grantDeny = (domroot.name == Constants.TAG_GRANT)
         for child in domroot.children:
             if child.name == Constants.TAG_PRIVILEGE and child.ns == Constants.NS_DAV:
                 self.privileges.append(Privilege(domroot=child))
             else:
                 # This shouldn't happen, someone screwed up with the params ...
                 raise WebdavError('Non-privilege tag handed to GrantDeny constructor: %s' \
                     % child.name)
     elif domroot == None:
         # no param ==> blank object
         pass
     else:
         # This shouldn't happen, someone screwed up with the params ...
         raise WebdavError('Non-valid parameters handed to GrantDeny constructor.')
Пример #4
0
    def testExists(self):
        """ Tests the normal behavior of the exists method. """

        adapter = DataWebdavAdapter("/anotherIdentifier", SimpleMock(),
                                    SimpleMock(), SimpleMock(SimpleMock()))
        self.assertTrue(adapter.exists())
        adapter = DataWebdavAdapter("/anotherIdentifier", SimpleMock(),
                                    SimpleMock(),
                                    SimpleMock(error=WebdavError("", 404)))
        self.assertFalse(adapter.exists())
        adapter = DataWebdavAdapter("/anotherIdentifier", SimpleMock(),
                                    SimpleMock(),
                                    SimpleMock(error=WebdavError("")))
        self.assertRaises(PersistenceError, adapter.exists)
Пример #5
0
    def __init__(self, domroot=None, displayname=None, principalURL=None):
        """
        Constructor should be called with either no parameters (create blank Principal),
        one parameter (a DOM tree), or two parameters (displayname and URL or property tag).
        
        @param domroot:      A DOM tree (default: None).
        @type  domroot:      L{webdav.WebdavResponse.Element} object
        @param displayname:  The display name of a principal (default: None).
        @type  displayname:  C{string}
        @param principalURL: The URL representing a principal (default: None).
        @type  principalURL: C{string}
        
        @raise WebdavError: When non-valid parameters or sets of parameters are 
            passed a L{WebdavError} is raised.
        """
        self.displayname  = None
        self.principalURL = None
        self.property     = None

        if domroot:
            for child in domroot.children:
                if child.ns == Constants.NS_DAV and (child.name in self._TAG_LIST_PRINCIPALS):
                    if child.name == Constants.TAG_PROP:
                        self.displayname = \
                            child.find(Constants.PROP_DISPLAY_NAME, Constants.NS_DAV)
                    elif child.name == Constants.TAG_HREF:
                        self.principalURL = child.textof()
                        if self.principalURL and self.property in self._TAG_LIST_STATUS:
                            raise WebdavError('Principal cannot contain a URL and "%s"' % (self.property))
                    elif child.name == Constants.TAG_PROPERTY:
                        if child.count() == 1:
                            if self.property:
                                raise WebdavError('Property for principal has already been set: old "%s", new "%s"' \
                                    % (self.property, child.pop().name))
                            elif self.principalURL:
                                raise WebdavError('Principal cannot contain a URL and "%s"' % (self.property))
                            else:
                                self.property = child.pop().name
                        else:
                            raise WebdavError("There should be only one value in the property for a principal, we have: %s" \
                                % child.name)
                    else:
                        if self.property:
                            raise WebdavError('Property for principal has already been set: old "%s", new "%s"' \
                                % (self.property, child.name))
                        else:
                            self.property = child.name
                        if self.principalURL and self.property in self._TAG_LIST_STATUS:
                            raise WebdavError('Principal cannot contain a URL and "%s"' % (self.property))
                else: # This shouldn't happen, something's wrong with the DOM tree
                    raise WebdavError('Non-valid tag in principal DOM tree for constructor: %s' % child.name)
        elif displayname == None or principalURL == None:
            if displayname:
                self.displayname  = displayname
            if principalURL:
                self.principalURL = principalURL
        else:
            # This shouldn't happen, someone screwed up with the params ...
            raise WebdavError('Non-valid parameters handed to Principal constructor.')
Пример #6
0
    def _getterMock(self):
        """ Raises a WebDAV-error. """

        if self.raiseError:
            raise WebdavError("")
        else:
            return self.result
Пример #7
0
    def lock(self, owner):
        """
        Locks this resource for exclusive write access. This means that for succeeding
        write operations the returned lock token has to be passed.
        If the methode does not throw an exception the lock has been granted.

        @param owner: describes the lock holder
        @return: lock token string (automatically generated)
        @rtype: L{LockToken}
        """
        response = self.connection.lock(self.path, owner)
        if response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0:
            raise WebdavError(
                "Request failed: " + response.msr.reason, response.msr.code)
        if response.locktoken is None:
            raise WebdavError(
                "Request failed: No lock token in answer")
        return LockToken(self.url, response.locktoken)
Пример #8
0
    def testErrorHandlingUsingLibraryInstances(self):
        """ Tests the error handling when using concrete library instances. """

        adapter = MetadataWebdavAdapter(
            "identifier", SimpleMock(), SimpleMock(), SimpleMock(),
            SimpleMock(SimpleMock(error=WebdavError(""))))
        self.assertRaises(PersistenceError, adapter.retrieve)
        self.assertRaises(PersistenceError, adapter.update, dict())
        self.assertRaises(PersistenceError, adapter.delete, [])
Пример #9
0
 def move(self, toUrl):
     """
     Moves this resource to the given path or renames it.
     
     @param toUrl: new (URI) path
     """
     self.connection.logger.debug("Move to " + repr(toUrl));
     _checkUrl(toUrl)
     response = self.connection.move(self.path, toUrl)
     if  response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0:
         raise WebdavError("Request failed: " + response.msr.reason, response.msr.code)        
Пример #10
0
 def validate(self):
     """
     Check whether this URL contains a WebDAV collection.
     Uses the WebDAV OPTION method.
     
     @raise WebdavError: L{WebdavError} if URL does not contain a WebDAV collection resource.
     """
     super(CollectionStorer, self).validate()
     isCollection = self.readProperty(Constants.NS_DAV, Constants.PROP_RESOURCE_TYPE)
     if not (isCollection and isCollection.children):
         raise WebdavError("Not a collection URL.", 0)        
Пример #11
0
    def testErrorHandling(self):
        self._connectionHelper.error = PersistenceError("")
        self.assertRaises(PersistenceError, self._adapter.retrieveAcl)
        self.assertRaises(PersistenceError, self._adapter.updateAcl, dict())
        self.assertRaises(PersistenceError, self._adapter.retrievePrivileges)

        self._connectionHelper.error = None
        self._connectionHelper.value = SimpleMock(error=WebdavError(""))
        self.assertRaises(PersistenceError, self._adapter.retrieveAcl)
        self.assertRaises(PersistenceError, self._adapter.updateAcl, dict())
        self.assertRaises(PersistenceError, self._adapter.retrievePrivileges)
Пример #12
0
 def validate(self):
     """
     Check whether URL contains a WebDAV resource
     Uses the WebDAV OPTIONS method.
     
     @raise WebdavError: L{WebdavError} if URL does not contain a WebDAV resource
     """
     #davHeader = response.getheader(HTTP_HEADER_DAV)
     davHeader = self.getSpecificOption(Constants.HTTP_HEADER_DAV)
     self.connection.logger.debug("HEADER DAV: %s" % davHeader)
     if not(davHeader) or davHeader.find("2") < 0:   # DAV class 2 supported ?
         raise WebdavError("URL does not support WebDAV", 0)
Пример #13
0
    def _filter_property_response(self, response):
        """ This is a workaround for servers which do not
        correctly handle the depth header.
        I.e., we simply try to identify the matching
        response for the resource. """

        for key in [self.path, self.path[:-1], self.url]: # Server may return path or URL
            try:
                return response.msr[key]
            except KeyError:
                continue
        raise WebdavError("No property result for '%s'" % self.url)
Пример #14
0
 def copy(self, other):
     """
     Copy Privilege object.
     
     @param other: Another privilege to copy.
     @type  other: L{Privilege} object
     
     @raise WebdavError: When an object that is not a L{Privilege} is passed 
         a L{WebdavError} is raised.
     """
     if not isinstance(other, Privilege):
         raise WebdavError('Non-Privilege object passed to copy method: %s' % other.__class__)
     self.name = other.name
Пример #15
0
 def copy(self, other):
     '''Copy an ACL object.
     
     @param other: Another ACL to copy.
     @type  other: L{ACL} object
     
     @raise WebdavError: When an object that is not an L{ACL} is passed 
         a L{WebdavError} is raised.
     '''
     if not isinstance(other, ACL):
         raise WebdavError('Non-ACL object passed to copy method: %s' % other.__class__)
     self.withInherited = other.withInherited
     if other.aces:
         self.addAces(other.aces)
Пример #16
0
 def copy(self, other):
     """Copy Principal object.
     
     @param other: Another principal to copy.
     @type  other: L{Principal} object
     
     @raise WebdavError: When an object that is not a L{Principal} is passed 
         a L{WebdavError} is raised.
     """
     if not isinstance(other, Principal):
         raise WebdavError('Non-Principal object passed to copy method: ' % other.__class__)
     self.displayname  = other.displayname
     self.principalURL = other.principalURL
     self.property     = other.property
Пример #17
0
def extractSupportedPrivilegeSet(userPrivileges):
    """
    Returns a dictionary of supported privileges.
    
    @param userPrivileges: A DOM tree.
    @type  userPrivileges: L{webdav.WebdavResponse.Element} object
    
    @raise WebdavError: When unknown elements appear in the 
        C{DAV:supported-privilege} appear a L{WebdavError} is raised.
    
    @return: A dictionary with privilege names as keys and privilege descriptions as values.
    @rtype:  C{dictionary}
    """
    result = {}
    for element in userPrivileges.children:
        if element.name == Constants.TAG_SUPPORTED_PRIVILEGE:
            privName = ''
            privDescription = ''
            for privilege in element.children:
                if privilege.name == Constants.TAG_PRIVILEGE:
                    privName = privilege.children[0].name
                elif privilege.name == Constants.TAG_DESCRIPTION:
                    privDescription = privilege.textof()
                else:
                    raise WebdavError(
                        'Unknown element in DAV:supported-privilege: ' +
                        privilege.name)

                if privName and privDescription:
                    result[privName] = privDescription
                    privName = ''
                    privDescription = ''
        else:
            raise WebdavError(
                'Invalid element tag in DAV:supported-privilege-set: ' +
                element.name)
    return result
Пример #18
0
    def testErrorHandlingUsingLibraryInstances(self):
        """ Tests the error handling when using concrete library instances. """

        connectionHelperMock = SimpleMock(methodNameResultMap={
            "determineResourceType": (None, WebdavError(""))
        })
        adapter = DataWebdavAdapter("/anotherIdentifier", SimpleMock(),
                                    SimpleMock(""), connectionHelperMock)
        try:
            self.assertFalse(adapter.isLink)
            self.fail("PersistenceError not raised.")
        except PersistenceError:
            self.assertTrue(True)
        try:
            self.assertFalse(adapter.isLeaf)
            self.fail("PersistenceError not raised.")
        except PersistenceError:
            self.assertTrue(True)
        try:
            self.assertFalse(adapter.isCollection)
            self.fail("PersistenceError not raised.")
        except PersistenceError:
            self.assertTrue(True)
        self.assertRaises(PersistenceError, adapter.getChildren)

        connectionHelperMock = SimpleMock(SimpleMock(error=WebdavError("")))
        adapter = DataWebdavAdapter("/anotherIdentifier", SimpleMock(),
                                    SimpleMock(""), connectionHelperMock)
        self.assertRaises(PersistenceError, adapter.createLink,
                          self._defaultAdapter)
        self.assertRaises(PersistenceError, adapter.createResource)
        self.assertRaises(PersistenceError, adapter.createCollection)
        self.assertRaises(PersistenceError, adapter.writeData, StringIO(""))
        self.assertRaises(PersistenceError, adapter.readData)
        self.assertRaises(PersistenceError, adapter.delete)
        self.assertRaises(PersistenceError, adapter.move, self._defaultAdapter)
        self.assertRaises(PersistenceError, adapter.copy, self._defaultAdapter)
Пример #19
0
 def delete(self, lockToken=None):
     """
     Deletes this resource.
     
     @param lockToken: String returned by last lock operation or null.
     @type  lockToken: L{LockToken}
     """
     assert lockToken == None or isinstance(lockToken, LockToken), \
             "Invalid lockToken argument %s" % type(lockToken)
     header = {}
     if lockToken:
         header = lockToken.toHeader()
     response = self.connection.delete(self.path, header)
     if  response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0:
         raise WebdavError("Request failed: " + response.msr.reason, response.msr.code)        
Пример #20
0
 def readProperty(self, nameSpace, name):
     """
     Reads the given property.
     
     @param nameSpace: XML-namespace
     @type nameSpace: string
     @param name: A property name.
     @type name: string
     
     @return: a map from property names to DOM Element or String values.
     """
     results = self.readProperties((nameSpace, name))
     if  len(results) == 0:
         raise WebdavError("Property is missing: " + results.reason)
     return results.values()[0]
Пример #21
0
 def copy(self, toUrl, infinity=True):
     """
     Copies this resource.
     
     @param toUrl: target URI path
     @param infinity: Flag that indicates that the complete content of collection is copied. (default)
     """
     self.connection.logger.debug("Copy to " + repr(toUrl))
     _checkUrl(toUrl)
     if infinity:
         response = self.connection.copy(self.path, toUrl)
     else:
         response = self.connection.copy(self.path, toUrl, 0)
     if  response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0:
         raise WebdavError("Request failed: " + response.msr.reason, response.msr.code)
Пример #22
0
 def copy(self, other):
     """
     Copy a GrantDeny object.
     
     @param other: Another grant or deny clause to copy.
     @type  other: L{GrantDeny} object
     
     @raise WebdavError: When an object that is not an L{GrantDeny} is passed 
         a L{WebdavError} is raised.
     """
     if not isinstance(other, GrantDeny):
         raise WebdavError('Non-GrantDeny object passed to copy method: %s' \
             % other)
     self.grantDeny = other.grantDeny
     if other.privileges:
         self.addPrivileges(other.privileges)
Пример #23
0
    def __init__(self, domroot=None, principal=None, grantDenies=None):
        """
        Constructor should be called with either no parameters (create blank ACE),
        one parameter (a DOM tree or principal), or two parameters (principal and 
        sequence of GrantDenies).
        
        @param domroot:     A DOM tree (default: None).
        @type  domroot:     L{webdav.WebdavResponse.Element} object
        @param principal:   A principal (user or group), (default: None).
        @type  principal:   L{Principal} object
        @param grantDenies: Grant and deny clauses for privileges (default: None).
        @type  grantDenies: sequence of L{GrantDeny} objects
        
        @raise WebdavError: When non-valid parameters are passed a L{WebdavError} is raised.
        """
        self.principal = Principal()
        self.protected = None
        self.inherited = None
        self.invert = None
        self.grantDenies = []

        if domroot:
            self.principal = Principal(domroot=domroot.find(
                Constants.TAG_PRINCIPAL, Constants.NS_DAV))
            self.inherited = domroot.find(Constants.TAG_INHERITED,
                                          Constants.NS_DAV)
            if self.inherited:
                self.inherited = self.inherited.children[0].textof()
            if domroot.find(Constants.TAG_PROTECTED, Constants.NS_DAV):
                self.protected = 1
            for child in domroot.children:
                if child.ns == Constants.NS_DAV \
                        and (child.name == Constants.TAG_GRANT or child.name == Constants.TAG_DENY):
                    self.grantDenies.append(GrantDeny(domroot=child))
        elif isinstance(principal, Principal):
            newPrincipal = Principal()
            newPrincipal.copy(principal)
            self.principal = newPrincipal
            if (isinstance(grantDenies, list)
                    or isinstance(grantDenies, tuple)):
                self.addGrantDenies(grantDenies)
        elif domroot == None and grantDenies == None:
            # no param ==> blank ACE
            pass
        else:
            # This shouldn't happen, someone screwed up with the params ...
            raise WebdavError('non-valid parameters handed to ACE constructor')
Пример #24
0
 def readProperties(self, *names):
     """
     Reads the given properties.
     
     @param names: a list of property names.
                   A property name is a (XmlNameSpace, propertyName) tuple.
     @return: a map from property names to DOM Element or String values.
     """
     assert names, "Property names are missing."
     body = createFindBody(names, self.defaultNamespace)
     response = self.connection.propfind(self.path, body, depth=0)
     properties = response.msr.values()[0]
     if properties.errorCount > 0:
         raise WebdavError(
             "Property is missing on '%s': %s" %
             (self.path, properties.reason), properties.code)
     return properties
Пример #25
0
 def deleteProperties(self, lockToken=None, *names):
     """
     Removes the given properties from this resource.
     
     @param lockToken: if the resource has been locked this is the lock token.
     @type  lockToken: L{LockToken}
     @param names: a collection of property names.
            A property name is a (XmlNameSpace, propertyName) tuple.
     """
     assert lockToken == None or isinstance(lockToken, LockToken), \
             "Invalid lockToken argument %s" % type(lockToken)
     header = {}
     if lockToken:
         header = lockToken.toHeader()
     body = createDeleteBody(names, self.defaultNamespace)
     response = self.connection.proppatch(self.path, body, header)
     if  response.msr.errorCount > 0:
         raise WebdavError("Request failed: " + response.msr.reason, response.msr.code)
Пример #26
0
 def readProperties(self, *names, **kwargs):
     """
     Reads the given properties.
     
     @param names: a list of property names.
                   A property name is a (XmlNameSpace, propertyName) tuple.
     @param ignore404: a boolean flag.
                   Indicates if an error should be raised for missing properties.
     @return: a map from property names to DOM Element or String values.
     """
     assert names, "Property names are missing."
     ignore404 = kwargs.pop('ignore404', False)
     body = createFindBody(names, self.defaultNamespace)
     response = self.connection.propfind(self.path, body, depth=0)
     properties = response.msr.values()[0]
     if  not ignore404 and properties.errorCount > 0 :
         raise WebdavError("Property is missing on '%s': %s" % (self.path, properties.reason), properties.code)
     return properties
Пример #27
0
    def __init__(self, url, connection=None, validateResourceNames=True):
        """
        Creates an instance for the given URL
        User must invoke validate() after construction to check the resource on the server.
        
        @param url: Unique resource location for this storer.
        @type  url: C{string}
        @param connection: this optional parameter contains a Connection object 
            for the host part of the given URL. Passing a connection saves 
            memory by sharing this connection. (defaults to None)
        @type  connection: L{webdav.Connection}
        @raise WebdavError: If validation of resource name path parts fails.
        """

        assert connection == None or isinstance(connection, Connection)
        parts = urlsplit(url, allow_fragments=False)
        self.path = parts[2]
        self.validateResourceNames = validateResourceNames

        # validate URL path
        for part in self.path.split('/'):
            if part != '' and not "ino:" in part:  # explicitly allowing this character sequence as a part of a path (Tamino 4.4)
                if self.validateResourceNames:
                    try:
                        validateResourceName(part)
                    except WrongNameError:
                        raise WebdavError("Found invalid resource name part.")
                self.name = part
        # was: filter(lambda part: part and validateResourceName(part), self.path.split('/'))
        # but filter is deprecated

        self.defaultNamespace = None  # default XML name space of properties
        if connection:
            self.connection = connection
        else:
            conn = parts[1].split(":")
            if len(conn) == 1:
                self.connection = Connection(
                    conn[0], protocol=parts[0])  # host and protocol
            else:
                self.connection = Connection(
                    conn[0], int(conn[1]),
                    protocol=parts[0])  # host and port and protocol
        self.versionHandler = VersionHandler(self.connection, self.path)
Пример #28
0
 def deleteResource(self, name, lockToken=None):
     """
     Delete a collection which is contained within this collection
     
     @param name: leaf name of a contained collection resource
     @param lockToken: None or token returned by last lock operation
     @type  lockToken: L{LockToken}
     """
     assert isinstance(name, types.StringType) or isinstance(name, types.UnicodeType)
     assert lockToken == None or isinstance(lockToken, LockToken), \
             "Invalid lockToken argument %s" % type(lockToken)
     header = {}
     if lockToken:
         header = lockToken.toHeader()
     if self.validateResourceNames:
         validateResourceName(name)
     response = self.connection.delete(self.path + name, header)
     if  response.status == Constants.CODE_MULTISTATUS and response.msr.errorCount > 0:
         raise WebdavError("Request failed: %s" % response.msr.reason, response.msr.code)        
Пример #29
0
 def writeProperties(self, properties, lockToken=None):
     """
     Sets or updates the given properties.
     
     @param lockToken: if the resource has been locked this is the lock token.
     @type  lockToken: L{LockToken}
     @param properties: a map from property names to a String or
                        DOM element value for each property to add or update.
     """
     assert isinstance(properties, types.DictType)
     assert lockToken == None or isinstance(lockToken, LockToken), \
             "Invalid lockToken argument %s" % type(lockToken)
     header = {}
     if lockToken:
         header = lockToken.toHeader()
     body = createUpdateBody(properties, self.defaultNamespace)
     response = self.connection.proppatch(self.path, body, header)
     if  response.msr.errorCount > 0:
         raise WebdavError("Request failed: " + response.msr.reason, response.msr.code)
Пример #30
0
 def copy(self, other):
     '''Copy an ACE object.
     
     @param other: Another ACE to copy.
     @type  other: L{ACE} object
     
     @raise WebdavError: When an object that is not an L{ACE} is passed 
         a L{WebdavError} is raised.
     '''
     if not isinstance(other, ACE):
         raise WebdavError('Non-ACE object passed to copy method: %s.' % other.__class__)
     self.invert    = other.invert
     self.protected = other.protected
     self.inherited = other.inherited
     self.principal = Principal()
     if other.principal:
         self.principal.copy(other.principal)
     if other.grantDenies:
         self.addGrantDenies(other.grantDenies)