Example #1
0
        def manage_FTPstat(self, REQUEST):
            """Psuedo stat, used by FTP for directory listings.
            """
            from AccessControl.User import nobody
            warn(
                u'manage_FTPstat is deprecated and will be removed in '
                u'Zope 5.',
                DeprecationWarning,
                stacklevel=2)
            mode = 0o0100000

            if (hasattr(aq_base(self), 'manage_FTPget')):
                try:
                    if getSecurityManager().validate(None, self,
                                                     'manage_FTPget',
                                                     self.manage_FTPget):
                        mode = mode | 0o0440
                except Unauthorized:
                    pass

                if nobody.allowed(
                        self.manage_FTPget,
                        getRoles(self, 'manage_FTPget', self.manage_FTPget,
                                 ())):
                    mode = mode | 0o0004

            # check write permissions
            if hasattr(aq_base(self), 'PUT'):
                try:
                    if getSecurityManager().validate(None, self, 'PUT',
                                                     self.PUT):
                        mode = mode | 0o0220
                except Unauthorized:
                    pass

                if nobody.allowed(self.PUT, getRoles(self, 'PUT', self.PUT,
                                                     ())):
                    mode = mode | 0o0002

            # get size
            if hasattr(aq_base(self), 'get_size'):
                size = self.get_size()
            elif hasattr(aq_base(self), 'manage_FTPget'):
                size = len(self.manage_FTPget())
            else:
                size = 0
            # get modification time
            if hasattr(aq_base(self), '_p_mtime'):
                mtime = DateTime(self._p_mtime).timeTime()
            else:
                mtime = time.time()
            # get owner and group
            owner = group = 'Zope'
            if hasattr(aq_base(self), 'get_local_roles'):
                for user, roles in self.get_local_roles():
                    if 'Owner' in roles:
                        owner = user
                        break
            return marshal.dumps(
                (mode, 0, 0, 1, owner, group, size, mtime, mtime, mtime))
Example #2
0
        def manage_FTPstat(self, REQUEST):
            """Psuedo stat, used by FTP for directory listings.
            """
            from AccessControl.User import nobody
            mode = 0o0100000

            if (hasattr(aq_base(self), 'manage_FTPget')):
                try:
                    if getSecurityManager().validate(
                            None, self, 'manage_FTPget', self.manage_FTPget):
                        mode = mode | 0o0440
                except Unauthorized:
                    pass

                if nobody.allowed(
                        self.manage_FTPget,
                        getRoles(self, 'manage_FTPget',
                                 self.manage_FTPget, ())):
                    mode = mode | 0o0004

            # check write permissions
            if hasattr(aq_base(self), 'PUT'):
                try:
                    if getSecurityManager().validate(None, self,
                                                     'PUT', self.PUT):
                        mode = mode | 0o0220
                except Unauthorized:
                    pass

                if nobody.allowed(
                        self.PUT,
                        getRoles(self, 'PUT', self.PUT, ())):
                    mode = mode | 0o0002

            # get size
            if hasattr(aq_base(self), 'get_size'):
                size = self.get_size()
            elif hasattr(aq_base(self), 'manage_FTPget'):
                size = len(self.manage_FTPget())
            else:
                size = 0
            # get modification time
            if hasattr(aq_base(self), '_p_mtime'):
                mtime = DateTime(self._p_mtime).timeTime()
            else:
                mtime = time.time()
            # get owner and group
            owner = group = 'Zope'
            if hasattr(aq_base(self), 'get_local_roles'):
                for user, roles in self.get_local_roles():
                    if 'Owner' in roles:
                        owner = user
                        break
            return marshal.dumps(
                (mode, 0, 0, 1, owner, group, size, mtime, mtime, mtime))
        def manage_FTPstat(self, REQUEST):
            """Psuedo stat, used by FTP for directory listings.
            """
            mode = 0o0040000
            from AccessControl.User import nobody
            # check to see if we are acquiring our objectValues or not
            if not (len(REQUEST.PARENTS) > 1 and self.objectValues()
                    == REQUEST.PARENTS[1].objectValues()):
                try:
                    if getSecurityManager().validate(None, self,
                                                     'manage_FTPlist',
                                                     self.manage_FTPlist):
                        mode = mode | 0o0770
                except Exception:
                    pass

                if nobody.allowed(
                        self,
                        getRoles(self, 'manage_FTPlist', self.manage_FTPlist,
                                 ())):
                    mode = mode | 0o0007
            if hasattr(aq_base(self), '_p_mtime'):
                mtime = DateTime(self._p_mtime).timeTime()
            else:
                mtime = time.time()
            # get owner and group
            owner = group = 'Zope'
            for user, roles in self.get_local_roles():
                if 'Owner' in roles:
                    owner = user
                    break
            return marshal.dumps(
                (mode, 0, 0, 1, owner, group, 0, mtime, mtime, mtime))
Example #4
0
    def manage_FTPstat(self,REQUEST):
        """Psuedo stat, used by FTP for directory listings.
        """
        mode=0040000
        from AccessControl.User import nobody
        # check to see if we are acquiring our objectValues or not
        if not (len(REQUEST.PARENTS) > 1 and
                self.objectValues() == REQUEST.PARENTS[1].objectValues()):
            try:
                if getSecurityManager().validate(
                    None, self, 'manage_FTPlist', self.manage_FTPlist
                    ):
                    mode=mode | 0770
            except: pass

            if nobody.allowed(
                self,
                getRoles(self, 'manage_FTPlist', self.manage_FTPlist, ())):
                mode=mode | 0007
        if hasattr(aq_base(self), '_p_mtime'):
            mtime = DateTime(self._p_mtime).timeTime()
        else:
            mtime = time.time()
        # get owner and group
        owner=group='Zope'
        for user, roles in self.get_local_roles():
            if 'Owner' in roles:
                owner=user
                break
        return marshal.dumps((mode,0,0,1,owner,group,0,mtime,mtime,mtime))
Example #5
0
    def testGetRolesWithMultiThread(self):
        from AccessControl.ZopeSecurityPolicy import getRoles

        class C(object):
            pass

        class V1(object):
            class __roles__(object):
                @staticmethod
                def rolesForPermissionOn(ob):
                    return ['Member']

        class V2(object):
            class __roles__(object):
                @staticmethod
                def rolesForPermissionOn(ob):
                    return ['User']

        c = C()
        c.v1 = V1()
        c.v2 = V2()

        self.assertEqual(getRoles(c, None, c.v1, 42), ['Member'])
        self.assertEqual(getRoles(c, None, c.v2, 42), ['User'])
        mark = []

        def loop():
            while 1:
                getRoles(c, None, c.v2, 42)
                if len(mark) > 0:
                    return

        thread.start_new_thread(loop, ())
        try:
            for i in range(1000):
                self.assertEqual(getRoles(c, None, c.v1, 42), ['Member'])
        finally:
            mark.append(None)
Example #6
0
    def testGetRolesWithMultiThread(self):
        from AccessControl.ZopeSecurityPolicy import getRoles

        class C(object):
            pass

        class V1(object):
            class __roles__(object):
                @staticmethod
                def rolesForPermissionOn(ob):
                    return ['Member']

        class V2(object):
            class __roles__(object):
                @staticmethod
                def rolesForPermissionOn(ob):
                    return ['User']

        c = C()
        c.v1 = V1()
        c.v2 = V2()

        self.assertEqual(getRoles(c, None, c.v1, 42), ['Member'])
        self.assertEqual(getRoles(c, None, c.v2, 42), ['User'])
        mark = []

        def loop():
            while 1:
                getRoles(c, None, c.v2, 42)
                if len(mark) > 0:
                    return
        thread.start_new_thread(loop, ())
        try:
            for i in range(1000):
                self.assertEqual(getRoles(c, None, c.v1, 42), ['Member'])
        finally:
            mark.append(None)
 def loop():
     while 1:
         getRoles(c, None, c.v2, 42)
         if len(mark) > 0:
             return
    def validate(self,
                 accessed,
                 container,
                 name,
                 value,
                 context,
                 roles=_noroles,
                 getattr=getattr,
                 _noroles=_noroles,
                 valid_aq_=('aq_parent', 'aq_inner', 'aq_explicit')):

        ############################################################
        # Provide special rules for the acquisition attributes
        if isinstance(name, str):
            if name.startswith('aq_') and name not in valid_aq_:
                if self._verbose:
                    raiseVerbose(
                        'aq_* names (other than %s) are not allowed' %
                        ', '.join(valid_aq_), accessed, container, name, value,
                        context)
                raise Unauthorized(name, value)

        containerbase = aq_base(container)
        accessedbase = aq_base(accessed)
        if accessedbase is accessed:
            # accessed is not a wrapper, so assume that the
            # value could not have been acquired.
            accessedbase = container

        ############################################################
        # If roles weren't passed in, we'll try to get them from the object

        if roles is _noroles:
            roles = getRoles(container, name, value, _noroles)

        ############################################################
        # We still might not have any roles

        if roles is _noroles:

            ############################################################
            # We have an object without roles and we didn't get a list
            # of roles passed in. Presumably, the value is some simple
            # object like a string or a list.  We'll try to get roles
            # from its container.
            if container is None:
                # Either container or a list of roles is required
                # for ZopeSecurityPolicy to know whether access is
                # allowable.
                if self._verbose:
                    raiseVerbose('No container provided', accessed, container,
                                 name, value, context)
                raise Unauthorized(name, value)

            roles = getattr(container, '__roles__', roles)
            if roles is _noroles:
                if containerbase is container:
                    # Container is not wrapped.
                    if containerbase is not accessedbase:
                        if self._verbose:
                            raiseVerbose(
                                'Unable to find __roles__ in the container '
                                'and the container is not wrapped', accessed,
                                container, name, value, context)
                        raise Unauthorized(name, value)
                else:
                    # Try to acquire roles
                    try:
                        roles = aq_acquire(container, '__roles__')
                    except AttributeError:
                        if containerbase is not accessedbase:
                            if self._verbose:
                                raiseVerbose(
                                    'Unable to find or acquire __roles__ '
                                    'from the container', accessed, container,
                                    name, value, context)
                            raise Unauthorized(name, value)

            # We need to make sure that we are allowed to
            # get unprotected attributes from the container. We are
            # allowed for certain simple containers and if the
            # container says we can. Simple containers
            # may also impose name restrictions.
            p = Containers(type(container), None)
            if p is None:
                p = getattr(container,
                            '__allow_access_to_unprotected_subobjects__', None)

            if p is not None:
                if not isinstance(p, int):  # catches bool too
                    if isinstance(p, dict):
                        if isinstance(name, basestring):
                            p = p.get(name)
                        else:
                            p = 1
                    else:
                        p = p(name, value)

            if not p:
                if self._verbose:
                    raiseVerbose('The container has no security assertions',
                                 accessed, container, name, value, context)
                raise Unauthorized(name, value)

            if roles is _noroles:
                return 1

            # We are going to need a security-aware object to pass
            # to allowed(). We'll use the container.
            value = container

        # Short-circuit tests if we can:
        try:
            if roles is None or 'Anonymous' in roles:
                return 1
        except TypeError:
            # 'roles' isn't a sequence
            LOG.error("'%s' passed as roles"
                      " during validation of '%s' is not a sequence." %
                      ( ` roles `, name))
            raise

        # Check executable security
        stack = context.stack
        if stack:
            eo = stack[-1]

            # If the executable had an owner, can it execute?
            if self._ownerous:
                owner = eo.getOwner()
                if (owner is not None) and not owner.allowed(value, roles):
                    # We don't want someone to acquire if they can't
                    # get an unacquired!
                    if self._verbose:
                        if len(roles) < 1:
                            raiseVerbose("The object is marked as private",
                                         accessed, container, name, value,
                                         context)
                        elif userHasRolesButNotInContext(owner, value, roles):
                            raiseVerbose(
                                "The owner of the executing script is defined "
                                "outside the context of the object being "
                                "accessed",
                                accessed,
                                container,
                                name,
                                value,
                                context,
                                required_roles=roles,
                                eo_owner=owner,
                                eo=eo)
                        else:
                            raiseVerbose(
                                "The owner of the executing script does not "
                                "have the required permission",
                                accessed,
                                container,
                                name,
                                value,
                                context,
                                required_roles=roles,
                                eo_owner=owner,
                                eo=eo,
                                eo_owner_roles=getUserRolesInContext(
                                    owner, value))
                    raise Unauthorized(name, value)

            # Proxy roles, which are a lot safer now.
            proxy_roles = getattr(eo, '_proxy_roles', None)
            if proxy_roles:
                # Verify that the owner actually can state the proxy role
                # in the context of the accessed item; users in subfolders
                # should not be able to use proxy roles to access items
                # above their subfolder!
                owner = eo.getWrappedOwner()

                if owner is not None:
                    if container is not containerbase:
                        # Unwrapped objects don't need checking
                        if not owner._check_context(container):
                            # container is higher up than the owner,
                            # deny access
                            if self._verbose:
                                raiseVerbose(
                                    "The owner of the executing script is "
                                    "defined outside the context of the "
                                    "object being accessed.  The script has "
                                    "proxy roles, but they do not apply in "
                                    "this context.",
                                    accessed,
                                    container,
                                    name,
                                    value,
                                    context,
                                    required_roles=roles,
                                    eo_owner=owner,
                                    eo=eo)
                            raise Unauthorized(name, value)

                for r in proxy_roles:
                    if r in roles:
                        return 1

                # Proxy roles actually limit access!
                if self._verbose:
                    if len(roles) < 1:
                        raiseVerbose("The object is marked as private",
                                     accessed, container, name, value, context)
                    else:
                        raiseVerbose(
                            "The proxy roles set on the executing script "
                            "do not allow access",
                            accessed,
                            container,
                            name,
                            value,
                            context,
                            eo=eo,
                            eo_proxy_roles=proxy_roles,
                            required_roles=roles)
                raise Unauthorized(name, value)

        try:
            if self._authenticated and context.user.allowed(value, roles):
                return 1
        except AttributeError:
            pass

        if self._verbose:
            if len(roles) < 1:
                raiseVerbose("The object is marked as private", accessed,
                             container, name, value, context)
            elif not self._authenticated:
                raiseVerbose(
                    "Authenticated access is not allowed by this "
                    "security policy", accessed, container, name, value,
                    context)
            elif userHasRolesButNotInContext(context.user, value, roles):
                raiseVerbose(
                    "Your user account is defined outside "
                    "the context of the object being accessed",
                    accessed,
                    container,
                    name,
                    value,
                    context,
                    required_roles=roles,
                    user=context.user)
            else:
                raiseVerbose(
                    "Your user account does not "
                    "have the required permission",
                    accessed,
                    container,
                    name,
                    value,
                    context,
                    required_roles=roles,
                    user=context.user,
                    user_roles=getUserRolesInContext(context.user, value))
        raise Unauthorized(name, value)
    def validate(self, accessed, container, name, value, context,
                 roles=_noroles, getattr=getattr, _noroles=_noroles,
                 valid_aq_=('aq_parent', 'aq_inner', 'aq_explicit')):

        ############################################################
        # Provide special rules for the acquisition attributes
        if isinstance(name, str):
            if name.startswith('aq_') and name not in valid_aq_:
                if self._verbose:
                    raiseVerbose(
                        'aq_* names (other than %s) are not allowed'
                        % ', '.join(valid_aq_),
                        accessed,
                        container,
                        name,
                        value,
                        context,
                    )
                raise Unauthorized(name, value)

        containerbase = aq_base(container)
        accessedbase = aq_base(accessed)
        if accessedbase is accessed:
            # accessed is not a wrapper, so assume that the
            # value could not have been acquired.
            accessedbase = container

        ############################################################
        # If roles weren't passed in, we'll try to get them from the object

        if roles is _noroles:
            roles = getRoles(container, name, value, _noroles)

        ############################################################
        # We still might not have any roles

        if roles is _noroles:

            ############################################################
            # We have an object without roles and we didn't get a list
            # of roles passed in. Presumably, the value is some simple
            # object like a string or a list.  We'll try to get roles
            # from its container.
            if container is None:
                # Either container or a list of roles is required
                # for ZopeSecurityPolicy to know whether access is
                # allowable.
                if self._verbose:
                    raiseVerbose(
                        'No container provided',
                        accessed, container, name, value, context)
                raise Unauthorized(name, value)

            roles = getattr(container, '__roles__', roles)
            if roles is _noroles:
                if containerbase is container:
                    # Container is not wrapped.
                    if containerbase is not accessedbase:
                        if self._verbose:
                            raiseVerbose(
                                'Unable to find __roles__ in the container '
                                'and the container is not wrapped',
                                accessed,
                                container,
                                name,
                                value,
                                context,
                            )
                        raise Unauthorized(name, value)
                else:
                    # Try to acquire roles
                    try:
                        roles = aq_acquire(container, '__roles__')
                    except AttributeError:
                        if containerbase is not accessedbase:
                            if self._verbose:
                                raiseVerbose(
                                    'Unable to find or acquire __roles__ '
                                    'from the container',
                                    accessed, container, name, value, context)
                            raise Unauthorized(name, value)

            # We need to make sure that we are allowed to
            # get unprotected attributes from the container. We are
            # allowed for certain simple containers and if the
            # container says we can. Simple containers
            # may also impose name restrictions.
            p = Containers(type(container), None)
            if p is None:
                p = getattr(container,
                            '__allow_access_to_unprotected_subobjects__',
                            None)

            if p is not None:
                if not isinstance(p, (bool, int)):
                    if isinstance(p, dict):

                        if isinstance(name, string_types):
                            p = p.get(name)
                        else:
                            p = 1
                    else:
                        p = p(name, value)

            if not p:
                if self._verbose:
                    raiseVerbose(
                        'The container has no security assertions',
                        accessed,
                        container,
                        name,
                        value,
                        context,
                    )
                raise Unauthorized(name, value)

            if roles is _noroles:
                return 1

            # We are going to need a security-aware object to pass
            # to allowed(). We'll use the container.
            value = container

        # Short-circuit tests if we can:
        try:
            if roles is None or 'Anonymous' in roles:
                return 1
        except TypeError:
            # 'roles' isn't a sequence
            LOG.error(
                "'%r' passed as roles"
                " during validation of '%s' is not a sequence." % (
                    roles,
                    name,
                ),
            )
            raise

        # Check executable security
        stack = context.stack
        if stack:
            eo = stack[-1]

            # If the executable had an owner, can it execute?
            if self._ownerous:
                owner = eo.getOwner()
                if (owner is not None) and not owner.allowed(value, roles):
                    # We don't want someone to acquire if they can't
                    # get an unacquired!
                    if self._verbose:
                        if len(roles) < 1:
                            raiseVerbose(
                                "The object is marked as private",
                                accessed,
                                container,
                                name,
                                value,
                                context,
                            )
                        elif userHasRolesButNotInContext(owner, value, roles):
                            raiseVerbose(
                                "The owner of the executing script is defined "
                                "outside the context of the object being "
                                "accessed",
                                accessed,
                                container,
                                name,
                                value,
                                context,
                                required_roles=roles,
                                eo_owner=owner,
                                eo=eo,
                            )
                        else:
                            raiseVerbose(
                                "The owner of the executing script does not "
                                "have the required permission",
                                accessed,
                                container,
                                name,
                                value,
                                context,
                                required_roles=roles,
                                eo_owner=owner,
                                eo=eo,
                                eo_owner_roles=getUserRolesInContext(owner,
                                                                     value),
                            )
                    raise Unauthorized(name, value)

            # Proxy roles, which are a lot safer now.
            proxy_roles = getattr(eo, '_proxy_roles', None)
            if proxy_roles:
                # Verify that the owner actually can state the proxy role
                # in the context of the accessed item; users in subfolders
                # should not be able to use proxy roles to access items
                # above their subfolder!
                owner = eo.getWrappedOwner()

                if owner is not None:
                    if container is not containerbase:
                        # Unwrapped objects don't need checking
                        if not owner._check_context(container):
                            # container is higher up than the owner,
                            # deny access
                            if self._verbose:
                                raiseVerbose(
                                    "The owner of the executing script is "
                                    "defined outside the context of the "
                                    "object being accessed.  The script has "
                                    "proxy roles, but they do not apply in "
                                    "this context.",
                                    accessed, container, name, value, context,
                                    required_roles=roles, eo_owner=owner,
                                    eo=eo)
                            raise Unauthorized(name, value)

                for r in proxy_roles:
                    if r in roles:
                        return 1

                # Proxy roles actually limit access!
                if self._verbose:
                    if len(roles) < 1:
                        raiseVerbose(
                            "The object is marked as private",
                            accessed, container, name, value, context)
                    else:
                        raiseVerbose(
                            "The proxy roles set on the executing script "
                            "do not allow access",
                            accessed, container, name, value, context,
                            eo=eo, eo_proxy_roles=proxy_roles,
                            required_roles=roles)
                raise Unauthorized(name, value)

        try:
            if self._authenticated and context.user.allowed(value, roles):
                return 1
        except AttributeError:
            pass

        if self._verbose:
            if len(roles) < 1:
                raiseVerbose(
                    "The object is marked as private",
                    accessed, container, name, value, context)
            elif not self._authenticated:
                raiseVerbose(
                    "Authenticated access is not allowed by this "
                    "security policy",
                    accessed, container, name, value, context)
            elif userHasRolesButNotInContext(context.user, value, roles):
                raiseVerbose(
                    "Your user account is defined outside "
                    "the context of the object being accessed",
                    accessed, container, name, value, context,
                    required_roles=roles, user=context.user)
            else:
                raiseVerbose(
                    "Your user account does not "
                    "have the required permission",
                    accessed, container, name, value, context,
                    required_roles=roles, user=context.user,
                    user_roles=getUserRolesInContext(context.user, value))
        raise Unauthorized(name, value)
Example #10
0
    def traverse(self, path, response=None, validated_hook=None):
        """Traverse the object space

        The REQUEST must already have a PARENTS item with at least one
        object in it.  This is typically the root object.
        """
        request = self
        request_get = request.get
        if response is None:
            response = self.response

        # remember path for later use
        browser_path = path

        # Cleanup the path list
        if path[:1] == '/':
            path = path[1:]
        if path[-1:] == '/':
            path = path[:-1]
        clean = []
        for item in path.split('/'):
            # Make sure that certain things that dont make sense
            # cannot be traversed.
            if item in ('REQUEST', 'aq_self', 'aq_base'):
                return response.notFoundError(path)
            if not item or item == '.':
                continue
            elif item == '..':
                del clean[-1]
            else:
                clean.append(item)
        path = clean

        # How did this request come in? (HTTP GET, PUT, POST, etc.)
        method = request_get('REQUEST_METHOD', 'GET').upper()

        # Probably a browser
        no_acquire_flag = 0
        if (method in ('GET', 'POST', 'PURGE')
                and not is_xmlrpc_response(response)):
            # index_html is still the default method, only any object can
            # override it by implementing its own __browser_default__ method
            method = 'index_html'
        elif self.maybe_webdav_client:
            # Probably a WebDAV client.
            no_acquire_flag = 1

        URL = request['URL']
        parents = request['PARENTS']
        object = parents[-1]
        del parents[:]

        self.roles = getRoles(None, None, object, UNSPECIFIED_ROLES)

        # if the top object has a __bobo_traverse__ method, then use it
        # to possibly traverse to an alternate top-level object.
        if hasattr(object, '__bobo_traverse__'):
            try:
                new_object = object.__bobo_traverse__(request)
                if new_object is not None:
                    object = new_object
                    self.roles = getRoles(None, None, object,
                                          UNSPECIFIED_ROLES)
            except Exception:
                pass

        if not path and not method:
            return response.forbiddenError(self['URL'])

        # Traverse the URL to find the object:
        if hasattr(object, '__of__'):
            # Try to bind the top-level object to the request
            # This is how you get 'self.REQUEST'
            object = object.__of__(RequestContainer(REQUEST=request))
        parents.append(object)

        steps = self.steps
        self._steps = _steps = list(map(quote, steps))
        path.reverse()

        request['TraversalRequestNameStack'] = request.path = path
        request['ACTUAL_URL'] = request['URL'] + quote(browser_path)

        # Set the posttraverse for duration of the traversal here
        self._post_traverse = post_traverse = []

        # import time ordering problem
        if HAS_ZSERVER:
            from webdav.NullResource import NullResource
        else:
            NullResource = None

        entry_name = ''
        try:
            # We build parents in the wrong order, so we
            # need to make sure we reverse it when we're done.
            while 1:
                bpth = getattr(object, '__before_publishing_traverse__', None)
                if bpth is not None:
                    bpth(object, self)

                path = request.path = request['TraversalRequestNameStack']
                # Check for method:
                if path:
                    entry_name = path.pop()
                else:
                    # If we have reached the end of the path, we look to see
                    # if we can find IBrowserPublisher.browserDefault. If so,
                    # we call it to let the object tell us how to publish it.
                    # BrowserDefault returns the object to be published
                    # (usually self) and a sequence of names to traverse to
                    # find the method to be published.

                    # This is webdav support. The last object in the path
                    # should not be acquired. Instead, a NullResource should
                    # be given if it doesn't exist:
                    if (NullResource is not None and no_acquire_flag
                            and hasattr(object, 'aq_base')
                            and not hasattr(object, '__bobo_traverse__')):

                        if (object.__parent__
                                is not aq_inner(object).__parent__):
                            object = NullResource(parents[-2], object.getId(),
                                                  self).__of__(parents[-2])

                    if IBrowserPublisher.providedBy(object):
                        adapter = object
                    else:
                        adapter = queryMultiAdapter((object, self),
                                                    IBrowserPublisher)
                        if adapter is None:
                            # Zope2 doesn't set up its own adapters in a lot
                            # of cases so we will just use a default adapter.
                            adapter = DefaultPublishTraverse(object, self)

                    object, default_path = adapter.browserDefault(self)
                    if default_path:
                        request._hacked_path = 1
                        if len(default_path) > 1:
                            path = list(default_path)
                            method = path.pop()
                            request['TraversalRequestNameStack'] = path
                            continue
                        else:
                            entry_name = default_path[0]
                    elif (method and hasattr(object, method)
                          and entry_name != method
                          and getattr(object, method) is not None):
                        request._hacked_path = 1
                        entry_name = method
                        method = 'index_html'
                    else:
                        if hasattr(object, '__call__'):
                            self.roles = getRoles(object, '__call__',
                                                  object.__call__, self.roles)
                        if request._hacked_path:
                            i = URL.rfind('/')
                            if i > 0:
                                response.setBase(URL[:i])
                        break
                step = quote(entry_name)
                _steps.append(step)
                request['URL'] = URL = '%s/%s' % (request['URL'], step)

                try:
                    subobject = self.traverseName(object, entry_name)
                    if (hasattr(object, '__bobo_traverse__')
                            or hasattr(object, entry_name)):
                        check_name = entry_name
                    else:
                        check_name = None

                    self.roles = getRoles(object, check_name, subobject,
                                          self.roles)
                    object = subobject
                # traverseName() might raise ZTK's NotFound
                except (KeyError, AttributeError, ztkNotFound):
                    if response.debug_mode:
                        return response.debugError(
                            "Cannot locate object at: %s" % URL)
                    else:
                        return response.notFoundError(URL)
                except Forbidden as e:
                    if self.response.debug_mode:
                        return response.debugError(e.args)
                    else:
                        return response.forbiddenError(entry_name)

                parents.append(object)

                steps.append(entry_name)
        finally:
            parents.reverse()

        # Note - no_acquire_flag is necessary to support
        # things like DAV.  We have to make sure
        # that the target object is not acquired
        # if the request_method is other than GET
        # or POST. Otherwise, you could never use
        # PUT to add a new object named 'test' if
        # an object 'test' existed above it in the
        # heirarchy -- you'd always get the
        # existing object :(
        if (no_acquire_flag and hasattr(parents[1], 'aq_base')
                and not hasattr(parents[1], '__bobo_traverse__')):
            base = aq_base(parents[1])
            if not hasattr(base, entry_name):
                try:
                    if entry_name not in base:
                        raise AttributeError(entry_name)
                except TypeError:
                    raise AttributeError(entry_name)

        # After traversal post traversal hooks aren't available anymore
        del self._post_traverse

        request['PUBLISHED'] = parents.pop(0)

        # Do authorization checks
        user = groups = None
        i = 0

        if 1:  # Always perform authentication.

            last_parent_index = len(parents)
            if hasattr(object, '__allow_groups__'):
                groups = object.__allow_groups__
                inext = 0
            else:
                inext = None
                for i in range(last_parent_index):
                    if hasattr(parents[i], '__allow_groups__'):
                        groups = parents[i].__allow_groups__
                        inext = i + 1
                        break

            if inext is not None:
                i = inext

                if hasattr(groups, 'validate'):
                    v = groups.validate
                else:
                    v = old_validation

                auth = request._auth

                if v is old_validation and self.roles is UNSPECIFIED_ROLES:
                    # No roles, so if we have a named group, get roles from
                    # group keys
                    if hasattr(groups, 'keys'):
                        self.roles = list(groups.keys())
                    else:
                        try:
                            groups = groups()
                        except Exception:
                            pass
                        try:
                            self.roles = list(groups.keys())
                        except Exception:
                            pass

                    if groups is None:
                        # Public group, hack structures to get it to validate
                        self.roles = None
                        auth = ''

                if v is old_validation:
                    user = old_validation(groups, request, auth, self.roles)
                elif self.roles is UNSPECIFIED_ROLES:
                    user = v(request, auth)
                else:
                    user = v(request, auth, self.roles)

                while user is None and i < last_parent_index:
                    parent = parents[i]
                    i = i + 1
                    if hasattr(parent, '__allow_groups__'):
                        groups = parent.__allow_groups__
                    else:
                        continue
                    if hasattr(groups, 'validate'):
                        v = groups.validate
                    else:
                        v = old_validation
                    if v is old_validation:
                        user = old_validation(groups, request, auth,
                                              self.roles)
                    elif self.roles is UNSPECIFIED_ROLES:
                        user = v(request, auth)
                    else:
                        user = v(request, auth, self.roles)

            if user is None and self.roles != UNSPECIFIED_ROLES:
                response.unauthorized()

        if user is not None:
            if validated_hook is not None:
                validated_hook(self, user)
            request['AUTHENTICATED_USER'] = user
            request['AUTHENTICATION_PATH'] = '/'.join(steps[:-i])

        # Remove http request method from the URL.
        request['URL'] = URL

        # Run post traversal hooks
        if post_traverse:
            result = exec_callables(post_traverse)
            if result is not None:
                object = result

        return object
Example #11
0
    def traverse(self, path, response=None, validated_hook=None):
        """Traverse the object space

        The REQUEST must already have a PARENTS item with at least one
        object in it.  This is typically the root object.
        """
        request=self
        request_get=request.get
        if response is None: response=self.response

        # remember path for later use
        browser_path = path

        # Cleanup the path list
        if path[:1]=='/':  path=path[1:]
        if path[-1:]=='/': path=path[:-1]
        clean=[]
        for item in path.split('/'):
            # Make sure that certain things that dont make sense
            # cannot be traversed.
            if item in ('REQUEST', 'aq_self', 'aq_base'):
                return response.notFoundError(path)
            if not item or item=='.':
                continue
            elif item == '..':
                del clean[-1]
            else: clean.append(item)
        path=clean

        # How did this request come in? (HTTP GET, PUT, POST, etc.)
        method = request_get('REQUEST_METHOD', 'GET').upper()

        if method=='GET' or method=='POST' and not isinstance(response,
                                                              xmlrpc.Response):
            # Probably a browser
            no_acquire_flag=0
            # index_html is still the default method, only any object can
            # override it by implementing its own __browser_default__ method
            method = 'index_html'
        elif self.maybe_webdav_client:
            # Probably a WebDAV client.
            no_acquire_flag=1
        else:
            no_acquire_flag=0

        URL=request['URL']
        parents=request['PARENTS']
        object=parents[-1]
        del parents[:]

        self.roles = getRoles(None, None, object, UNSPECIFIED_ROLES)

        # if the top object has a __bobo_traverse__ method, then use it
        # to possibly traverse to an alternate top-level object.
        if hasattr(object,'__bobo_traverse__'):
            try:
                object=object.__bobo_traverse__(request)
                self.roles = getRoles(None, None, object, UNSPECIFIED_ROLES)
            except: pass

        if not path and not method:
            return response.forbiddenError(self['URL'])

        # Traverse the URL to find the object:
        if hasattr(object, '__of__'):
            # Try to bind the top-level object to the request
            # This is how you get 'self.REQUEST'
            object=object.__of__(RequestContainer(REQUEST=request))
        parents.append(object)

        steps=self.steps
        self._steps = _steps = map(quote, steps)
        path.reverse()

        request['TraversalRequestNameStack'] = request.path = path
        request['ACTUAL_URL'] = request['URL'] + quote(browser_path)

        # Set the posttraverse for duration of the traversal here
        self._post_traverse = post_traverse = []

        entry_name = ''
        try:
            # We build parents in the wrong order, so we
            # need to make sure we reverse it when we're done.
            while 1:
                bpth = getattr(object, '__before_publishing_traverse__', None)
                if bpth is not None:
                    bpth(object, self)

                path = request.path = request['TraversalRequestNameStack']
                # Check for method:
                if path:
                    entry_name = path.pop()
                else:
                    # If we have reached the end of the path, we look to see
                    # if we can find IBrowserPublisher.browserDefault. If so,
                    # we call it to let the object tell us how to publish it.
                    # BrowserDefault returns the object to be published
                    # (usually self) and a sequence of names to traverse to
                    # find the method to be published.

                    # This is webdav support. The last object in the path
                    # should not be acquired. Instead, a NullResource should
                    # be given if it doesn't exist:
                    if (no_acquire_flag and
                        hasattr(object, 'aq_base') and
                        not hasattr(object,'__bobo_traverse__')):
                        if object.aq_parent is not object.aq_inner.aq_parent:
                            from webdav.NullResource import NullResource
                            object = NullResource(parents[-2], object.getId(),
                                                  self).__of__(parents[-2])

                    if IBrowserPublisher.providedBy(object):
                        adapter = object
                    else:
                        adapter = queryMultiAdapter((object, self),
                                                    IBrowserPublisher)
                        if adapter is None:
                            # Zope2 doesn't set up its own adapters in a lot
                            # of cases so we will just use a default adapter.
                            adapter = DefaultPublishTraverse(object, self)

                    object, default_path = adapter.browserDefault(self)
                    if default_path:
                        request._hacked_path=1
                        if len(default_path) > 1:
                            path = list(default_path)
                            method = path.pop()
                            request['TraversalRequestNameStack'] = path
                            continue
                        else:
                            entry_name = default_path[0]
                    elif (method and hasattr(object,method)
                          and entry_name != method
                          and getattr(object, method) is not None):
                        request._hacked_path=1
                        entry_name = method
                        method = 'index_html'
                    else:
                        if hasattr(object, '__call__'):
                            self.roles = getRoles(object, '__call__', object.__call__,
                                                  self.roles)
                        if request._hacked_path:
                            i=URL.rfind('/')
                            if i > 0: response.setBase(URL[:i])
                        break
                step = quote(entry_name)
                _steps.append(step)
                request['URL'] = URL = '%s/%s' % (request['URL'], step)

                try:
                    subobject = self.traverseName(object, entry_name)
                    if (hasattr(object,'__bobo_traverse__') or
                        hasattr(object, entry_name)):
                        check_name = entry_name
                    else:
                        check_name = None

                    self.roles = getRoles(
                        object, check_name, subobject,
                        self.roles)
                    object = subobject
                # traverseName() might raise ZTK's NotFound
                except (KeyError, AttributeError, ztkNotFound):
                    if response.debug_mode:
                        return response.debugError(
                            "Cannot locate object at: %s" % URL)
                    else:
                        return response.notFoundError(URL)
                except Forbidden, e:
                    if self.response.debug_mode:
                        return response.debugError(e.args)
                    else:
                        return response.forbiddenError(entry_name)

                parents.append(object)

                steps.append(entry_name)
        finally:
            parents.reverse()

        # Note - no_acquire_flag is necessary to support
        # things like DAV.  We have to make sure
        # that the target object is not acquired
        # if the request_method is other than GET
        # or POST. Otherwise, you could never use
        # PUT to add a new object named 'test' if
        # an object 'test' existed above it in the
        # heirarchy -- you'd always get the
        # existing object :(
        if (no_acquire_flag and
            hasattr(parents[1], 'aq_base') and
            not hasattr(parents[1],'__bobo_traverse__')):
            if not (hasattr(parents[1].aq_base, entry_name) or
                    parents[1].aq_base.has_key(entry_name)):
                raise AttributeError, entry_name

        # After traversal post traversal hooks aren't available anymore
        del self._post_traverse

        request['PUBLISHED'] = parents.pop(0)

        # Do authorization checks
        user=groups=None
        i=0

        if 1:  # Always perform authentication.

            last_parent_index=len(parents)
            if hasattr(object, '__allow_groups__'):
                groups=object.__allow_groups__
                inext=0
            else:
                inext=None
                for i in range(last_parent_index):
                    if hasattr(parents[i],'__allow_groups__'):
                        groups=parents[i].__allow_groups__
                        inext=i+1
                        break

            if inext is not None:
                i=inext

                if hasattr(groups, 'validate'): v=groups.validate
                else: v=old_validation

                auth=request._auth

                if v is old_validation and self.roles is UNSPECIFIED_ROLES:
                    # No roles, so if we have a named group, get roles from
                    # group keys
                    if hasattr(groups,'keys'): self.roles=groups.keys()
                    else:
                        try: groups=groups()
                        except: pass
                        try: self.roles=groups.keys()
                        except: pass

                    if groups is None:
                        # Public group, hack structures to get it to validate
                        self.roles=None
                        auth=''

                if v is old_validation:
                    user=old_validation(groups, request, auth, self.roles)
                elif self.roles is UNSPECIFIED_ROLES: user=v(request, auth)
                else: user=v(request, auth, self.roles)

                while user is None and i < last_parent_index:
                    parent=parents[i]
                    i=i+1
                    if hasattr(parent, '__allow_groups__'):
                        groups=parent.__allow_groups__
                    else: continue
                    if hasattr(groups,'validate'): v=groups.validate
                    else: v=old_validation
                    if v is old_validation:
                        user=old_validation(groups, request, auth, self.roles)
                    elif self.roles is UNSPECIFIED_ROLES: user=v(request, auth)
                    else: user=v(request, auth, self.roles)

            if user is None and self.roles != UNSPECIFIED_ROLES:
                response.unauthorized()

        if user is not None:
            if validated_hook is not None: validated_hook(self, user)
            request['AUTHENTICATED_USER']=user
            request['AUTHENTICATION_PATH']='/'.join(steps[:-i])

        # Remove http request method from the URL.
        request['URL']=URL

        # Run post traversal hooks
        if post_traverse:
            result = exec_callables(post_traverse)
            if result is not None:
                object = result

        return object
Example #12
0
    def test_security_equivalence(self):
        """
        This test demonstrates that the traditional declarative security of
        Zope 2 can be replaced by ZCML statements without any loss of
        information.
        """

        # We start out with two classes, ``Dummy1`` and ``Dummy2``.  They
        # are identical in every way, except that ``Dummy2`` has security
        # declarations and ``Dummy1`` does not.  Before we do anything, none
        # of them have security access controls:

        from AccessControl.tests.testZCML import Dummy1, Dummy2
        self.assertFalse(hasattr(Dummy1, '__ac_permissions__'))
        self.assertFalse(hasattr(Dummy2, '__ac_permissions__'))

        # Before we can make security declarations through ZCML, we need to
        # register the directive and the permission:

        import AccessControl
        from zope.configuration.xmlconfig import XMLConfig
        XMLConfig('meta.zcml', AccessControl)()
        XMLConfig('permissions.zcml', AccessControl)()

        # Now we initialize the security for ``Dummy2`` and provide some
        # ZCML declarations for ``Dummy1``:

        from io import StringIO
        configure_zcml = StringIO(u'''
            <configure xmlns="http://namespaces.zope.org/zope">
              <class class="AccessControl.tests.testZCML.Dummy1">
                <allow attributes="foo" />
                <!--deny attributes="baz" /--> <!-- XXX not yet supported -->
              </class>
              <class class="AccessControl.tests.testZCML.Dummy1">
                <require attributes="bar keg"
                         permission="zope2.ViewManagementScreens"
                         />
              </class>
            </configure>
            ''')
        from zope.configuration.xmlconfig import xmlconfig
        xmlconfig(configure_zcml)

        from AccessControl.class_init import InitializeClass
        InitializeClass(Dummy2)

        # Now we compare their access controls:

        ac1 = getattr(Dummy1, '__ac_permissions__')
        ac2 = getattr(Dummy2, '__ac_permissions__')
        self.assertEqual(
            [(perm, set(attr)) for perm, attr in dict(ac1).items()],
            [(perm, set(attr)) for perm, attr in dict(ac2).items()])

        # Now we look at the individual permissions:

        from AccessControl.ZopeSecurityPolicy import getRoles
        from AccessControl import ACCESS_PUBLIC
        from AccessControl import ACCESS_PRIVATE

        dummy1 = Dummy1()
        self.assertEqual(
            getRoles(dummy1, 'bar', dummy1.bar, ('Def', )),
            ('Manager', ))

        self.assertEqual(
            getRoles(dummy1, 'keg', dummy1.keg, ('Def', )),
            ('Manager', ))

        self.assertEqual(
            getRoles(dummy1, 'foo', dummy1.foo, ('Def', )),
            ACCESS_PUBLIC)

        # XXX Not yet supported.
        # self.assertEqual(
        #     getRoles(dummy1, 'baz', dummy1.baz, ('Def', )),
        #     ACCESS_PRIVATE)

        dummy2 = Dummy2()
        self.assertEqual(
            getRoles(dummy2, 'bar', dummy2.bar, ('Def', )),
            ('Manager', ))

        self.assertEqual(
            getRoles(dummy2, 'keg', dummy2.keg, ('Def', )),
            ('Manager', ))

        self.assertEqual(
            getRoles(dummy2, 'foo', dummy2.foo, ('Def', )),
            ACCESS_PUBLIC)

        self.assertEqual(
            getRoles(dummy2, 'baz', dummy2.baz, ('Def', )),
            ACCESS_PRIVATE)
Example #13
0
    def traverse(self, path, response=None, validated_hook=None):
        """Traverse the object space

        The REQUEST must already have a PARENTS item with at least one
        object in it.  This is typically the root object.
        """
        request=self
        request_get=request.get
        if response is None: response=self.response
        debug_mode=response.debug_mode

        # remember path for later use
        browser_path = path

        # Cleanup the path list
        if path[:1]=='/':  path=path[1:]
        if path[-1:]=='/': path=path[:-1]
        clean=[]
        for item in path.split('/'):
            # Make sure that certain things that dont make sense
            # cannot be traversed.
            if item in ('REQUEST', 'aq_self', 'aq_base'):
                return response.notFoundError(path)
            if not item or item=='.':
                continue
            elif item == '..':
                del clean[-1]
            else: clean.append(item)
        path=clean

        # How did this request come in? (HTTP GET, PUT, POST, etc.)
        method=req_method=request_get('REQUEST_METHOD', 'GET').upper()

        if method=='GET' or method=='POST' and not isinstance(response,
                                                              xmlrpc.Response):
            # Probably a browser
            no_acquire_flag=0
            # index_html is still the default method, only any object can
            # override it by implementing its own __browser_default__ method
            method = 'index_html'
        elif self.maybe_webdav_client:
            # Probably a WebDAV client.
            no_acquire_flag=1
        else:
            no_acquire_flag=0

        URL=request['URL']
        parents=request['PARENTS']
        object=parents[-1]
        del parents[:]

        roles = getRoles(None, None, object, UNSPECIFIED_ROLES)

        # if the top object has a __bobo_traverse__ method, then use it
        # to possibly traverse to an alternate top-level object.
        if hasattr(object,'__bobo_traverse__'):
            try:
                object=object.__bobo_traverse__(request)
                roles = getRoles(None, None, object, UNSPECIFIED_ROLES)
            except: pass

        if not path and not method:
            return response.forbiddenError(self['URL'])

        # Traverse the URL to find the object:
        if hasattr(object, '__of__'):
            # Try to bind the top-level object to the request
            # This is how you get 'self.REQUEST'
            object=object.__of__(RequestContainer(REQUEST=request))
        parents.append(object)

        steps=self.steps
        self._steps = _steps = map(quote, steps)
        path.reverse()

        request['TraversalRequestNameStack'] = request.path = path
        request['ACTUAL_URL'] = request['URL'] + quote(browser_path)

        # Set the posttraverse for duration of the traversal here
        self._post_traverse = post_traverse = []

        entry_name = ''
        try:
            # We build parents in the wrong order, so we
            # need to make sure we reverse it when we're doe.
            while 1:
                bpth = getattr(object, '__before_publishing_traverse__', None)
                if bpth is not None:
                    bpth(object, self)

                path = request.path = request['TraversalRequestNameStack']
                # Check for method:
                if path:
                    entry_name = path.pop()
                elif hasattr(object, '__browser_default__'):
                    # If we have reached the end of the path. We look to see
                    # if the object implements __browser_default__. If so, we
                    # call it to let the object tell us how to publish it
                    # __browser_default__ returns the object to be published
                    # (usually self) and a sequence of names to traverse to
                    # find the method to be published. (Casey)
                    request._hacked_path=1
                    object, default_path = object.__browser_default__(request)
                    if len(default_path) > 1:
                        path = list(default_path)
                        method = path.pop()
                        request['TraversalRequestNameStack'] = path
                        continue
                    else:
                        entry_name = default_path[0]
                elif (method and hasattr(object,method)
                      and entry_name != method
                      and getattr(object, method) is not None):
                    request._hacked_path=1
                    entry_name = method
                    method = 'index_html'
                else:
                    if (hasattr(object, '__call__')):
                        roles = getRoles(object, '__call__', object.__call__,
                                         roles)
                    if request._hacked_path:
                        i=URL.rfind('/')
                        if i > 0: response.setBase(URL[:i])
                    break
                step = quote(entry_name)
                _steps.append(step)
                request['URL'] = URL = '%s/%s' % (request['URL'], step)
                got = 0
                if entry_name[:1]=='_':
                    if debug_mode:
                        return response.debugError(
                          "Object name begins with an underscore at: %s" % URL)
                    else: return response.forbiddenError(entry_name)

                if hasattr(object,'__bobo_traverse__'):
                    try:
                        subobject=object.__bobo_traverse__(request,entry_name)
                        if type(subobject) is type(()) and len(subobject) > 1:
                            # Add additional parents into the path
                            parents[-1:] = list(subobject[:-1])
                            object, subobject = subobject[-2:]
                    except (AttributeError, KeyError):
                        if debug_mode:
                            return response.debugError(
                                "Cannot locate object at: %s" % URL)
                        else:
                            return response.notFoundError(URL)
                else:
                    try:
                        # Note - no_acquire_flag is necessary to support
                        # things like DAV.  We have to make sure
                        # that the target object is not acquired
                        # if the request_method is other than GET
                        # or POST. Otherwise, you could never use
                        # PUT to add a new object named 'test' if
                        # an object 'test' existed above it in the
                        # heirarchy -- you'd always get the
                        # existing object :(

                        if (no_acquire_flag and len(path) == 0 and
                            hasattr(object, 'aq_base')):
                            if hasattr(object.aq_base, entry_name):
                                subobject=getattr(object, entry_name)
                            else: raise AttributeError, entry_name
                        else: subobject=getattr(object, entry_name)
                    except AttributeError:
                        got=1
                        try: subobject=object[entry_name]
                        except (KeyError, IndexError,
                                TypeError, AttributeError):
                            if debug_mode:
                                return response.debugError(
                                    "Cannot locate object at: %s" % URL)
                            else:
                                return response.notFoundError(URL)

                # Ensure that the object has a docstring, or that the parent
                # object has a pseudo-docstring for the object. Objects that
                # have an empty or missing docstring are not published.
                doc = getattr(subobject, '__doc__', None)
                if doc is None:
                    doc = getattr(object, '%s__doc__' % entry_name, None)
                if not doc:
                    return response.debugError(
                        "The object at %s has an empty or missing " \
                        "docstring. Objects must have a docstring to be " \
                        "published." % URL
                        )

                # Hack for security: in Python 2.2.2, most built-in types
                # gained docstrings that they didn't have before. That caused
                # certain mutable types (dicts, lists) to become publishable
                # when they shouldn't be. The following check makes sure that
                # the right thing happens in both 2.2.2+ and earlier versions.

                if not typeCheck(subobject):
                    return response.debugError(
                        "The object at %s is not publishable." % URL
                        )

                roles = getRoles(
                    object, (not got) and entry_name or None, subobject,
                    roles)

                # Promote subobject to object
                object=subobject
                parents.append(object)

                steps.append(entry_name)
        finally:
            parents.reverse()
 
        # After traversal post traversal hooks aren't available anymore
        del self._post_traverse

        request['PUBLISHED'] = parents.pop(0)

        # Do authorization checks
        user=groups=None
        i=0

        if 1:  # Always perform authentication.

            last_parent_index=len(parents)
            if hasattr(object, '__allow_groups__'):
                groups=object.__allow_groups__
                inext=0
            else:
                inext=None
                for i in range(last_parent_index):
                    if hasattr(parents[i],'__allow_groups__'):
                        groups=parents[i].__allow_groups__
                        inext=i+1
                        break

            if inext is not None:
                i=inext

                if hasattr(groups, 'validate'): v=groups.validate
                else: v=old_validation

                auth=request._auth

                if v is old_validation and roles is UNSPECIFIED_ROLES:
                    # No roles, so if we have a named group, get roles from
                    # group keys
                    if hasattr(groups,'keys'): roles=groups.keys()
                    else:
                        try: groups=groups()
                        except: pass
                        try: roles=groups.keys()
                        except: pass

                    if groups is None:
                        # Public group, hack structures to get it to validate
                        roles=None
                        auth=''

                if v is old_validation:
                    user=old_validation(groups, request, auth, roles)
                elif roles is UNSPECIFIED_ROLES: user=v(request, auth)
                else: user=v(request, auth, roles)

                while user is None and i < last_parent_index:
                    parent=parents[i]
                    i=i+1
                    if hasattr(parent, '__allow_groups__'):
                        groups=parent.__allow_groups__
                    else: continue
                    if hasattr(groups,'validate'): v=groups.validate
                    else: v=old_validation
                    if v is old_validation:
                        user=old_validation(groups, request, auth, roles)
                    elif roles is UNSPECIFIED_ROLES: user=v(request, auth)
                    else: user=v(request, auth, roles)

            if user is None and roles != UNSPECIFIED_ROLES:
                response.unauthorized()

        if user is not None:
            if validated_hook is not None: validated_hook(self, user)
            request['AUTHENTICATED_USER']=user
            request['AUTHENTICATION_PATH']='/'.join(steps[:-i])

        # Remove http request method from the URL.
        request['URL']=URL

        # Run post traversal hooks
        if post_traverse:
            result = exec_callables(post_traverse)
            if result is not None:
                object = result

        return object
Example #14
0
    def test_security_equivalence(self):
        """
        This test demonstrates that the traditional declarative security of
        Zope 2 can be replaced by ZCML statements without any loss of
        information.
        """

        # We start out with two classes, ``Dummy1`` and ``Dummy2``.  They
        # are identical in every way, except that ``Dummy2`` has security
        # declarations and ``Dummy1`` does not.  Before we do anything, none
        # of them have security access controls:

        from AccessControl.tests.testZCML import Dummy1, Dummy2
        self.assertFalse(hasattr(Dummy1, '__ac_permissions__'))
        self.assertFalse(hasattr(Dummy2, '__ac_permissions__'))

        # Before we can make security declarations through ZCML, we need to
        # register the directive and the permission:

        import AccessControl
        from zope.configuration.xmlconfig import XMLConfig
        XMLConfig('meta.zcml', AccessControl)()
        XMLConfig('permissions.zcml', AccessControl)()

        # Now we initialize the security for ``Dummy2`` and provide some
        # ZCML declarations for ``Dummy1``:

        from io import StringIO
        configure_zcml = StringIO(u'''
            <configure xmlns="http://namespaces.zope.org/zope">
              <class class="AccessControl.tests.testZCML.Dummy1">
                <allow attributes="foo" />
                <!--deny attributes="baz" /--> <!-- XXX not yet supported -->
              </class>
              <class class="AccessControl.tests.testZCML.Dummy1">
                <require attributes="bar keg"
                         permission="zope2.ViewManagementScreens"
                         />
              </class>
            </configure>
            ''')
        from zope.configuration.xmlconfig import xmlconfig
        xmlconfig(configure_zcml)

        from AccessControl.class_init import InitializeClass
        InitializeClass(Dummy2)

        # Now we compare their access controls:

        ac1 = getattr(Dummy1, '__ac_permissions__')
        ac2 = getattr(Dummy2, '__ac_permissions__')
        self.assertEqual(
            [(perm, set(attr)) for perm, attr in dict(ac1).items()],
            [(perm, set(attr)) for perm, attr in dict(ac2).items()])

        # Now we look at the individual permissions:

        from AccessControl.ZopeSecurityPolicy import getRoles
        from AccessControl import ACCESS_PUBLIC
        from AccessControl import ACCESS_PRIVATE

        dummy1 = Dummy1()
        self.assertEqual(
            getRoles(dummy1, 'bar', dummy1.bar, ('Def', )),
            ('Manager', ))

        self.assertEqual(
            getRoles(dummy1, 'keg', dummy1.keg, ('Def', )),
            ('Manager', ))

        self.assertEqual(
            getRoles(dummy1, 'foo', dummy1.foo, ('Def', )),
            ACCESS_PUBLIC)

        # XXX Not yet supported.
        # self.assertEqual(
        #     getRoles(dummy1, 'baz', dummy1.baz, ('Def', )),
        #     ACCESS_PRIVATE)

        dummy2 = Dummy2()
        self.assertEqual(
            getRoles(dummy2, 'bar', dummy2.bar, ('Def', )),
            ('Manager', ))

        self.assertEqual(
            getRoles(dummy2, 'keg', dummy2.keg, ('Def', )),
            ('Manager', ))

        self.assertEqual(
            getRoles(dummy2, 'foo', dummy2.foo, ('Def', )),
            ACCESS_PUBLIC)

        self.assertEqual(
            getRoles(dummy2, 'baz', dummy2.baz, ('Def', )),
            ACCESS_PRIVATE)