~launchpad-pqm/launchpad/devel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# Copyright 2011 Canonical Ltd.  This software is licensed under the
# GNU Affero General Public License version 3 (see the file LICENSE).

"""Base class to implement the Launchpad security policy."""

__metaclass__ = type

__all__ = [
    'AnonymousAuthorization',
    'AuthorizationBase',
    'DelegatedAuthorization',
    ]

from itertools import (
    izip,
    repeat,
    )

from zope.component import queryAdapter
from zope.interface import implements
from zope.security.permission import checkPermission

from lp.app.interfaces.security import IAuthorization
from lp.registry.interfaces.person import IPerson
from lp.registry.interfaces.role import IPersonRoles


class AuthorizationBase:
    implements(IAuthorization)
    permission = None
    usedfor = None

    def __init__(self, obj):
        self.obj = obj

    def checkUnauthenticated(self):
        """See `IAuthorization.checkUnauthenticated`.

        :return: True or False.
        """
        return False

    def checkAuthenticated(self, user):
        """Return True if the given person has the given permission.

        This method is implemented by security adapters that have not
        been updated to work in terms of IAccount.

        :return: True or False.
        """
        return False

    def checkPermissionIsRegistered(self, obj, permission):
        """Pass through to checkPermission.

        To be replaced during testing.
        """
        return checkPermission(obj, permission)

    def forwardCheckAuthenticated(self, user,
                                  obj=None, permission=None):
        """Forward request to another security adapter.

        Find a matching adapter and call checkAuthenticated on it. Intended
        to be used in checkAuthenticated.

        :param user: The IRolesPerson object that was passed in.
        :param obj: The object to check the permission for. If None, use
            the same object as this adapter.
        :param permission: The permission to check. If None, use the same
            permission as this adapter.
        :return: True or False.
        """
        assert obj is not None or permission is not None, (
            "Please specify either an object or permission to forward to.")
        if obj is None:
            obj = self.obj
        if permission is None:
            permission = self.permission
        # This will raise ValueError if the permission doesn't exist.
        self.checkPermissionIsRegistered(obj, permission)
        next_adapter = queryAdapter(obj, IAuthorization, permission)
        if next_adapter is None:
            return False
        else:
            return next_adapter.checkAuthenticated(user)

    def checkAccountAuthenticated(self, account):
        """See `IAuthorization.checkAccountAuthenticated`.

        :return: True or False.
        """
        # For backward compatibility, delegate to one of
        # checkAuthenticated() or checkUnauthenticated().
        person = IPerson(account, None)
        if person is None:
            return self.checkUnauthenticated()
        else:
            return self.checkAuthenticated(IPersonRoles(person))


class AnonymousAuthorization(AuthorizationBase):
    """Allow any authenticated and unauthenticated user access."""
    permission = 'launchpad.View'

    def checkUnauthenticated(self):
        """Any unauthorized user can see this object."""
        return True

    def checkAuthenticated(self, user):
        """Any authorized user can see this object."""
        return True


class DelegatedAuthorization(AuthorizationBase):

    def __init__(self, obj, forwarded_object=None, permission=None):
        super(DelegatedAuthorization, self).__init__(obj)
        self.forwarded_object = forwarded_object
        if permission is not None:
            self.permission = permission

    def iter_objects(self):
        """Iterator of objects used for authentication checking.

        If an object is provided when the class is instantiated, it will be
        used.  Otherwise this method must be overridden to provide the objects
        to be used.
        """
        if self.forwarded_object is None:
            raise ValueError(
                "Either set forwarded_object or override iter_objects.")
        yield self.forwarded_object

    def checkAuthenticated(self, user):
        """See `IAuthorization`."""
        return izip(self.iter_objects(), repeat(self.permission))

    def checkUnauthenticated(self):
        """See `IAuthorization`."""
        return izip(self.iter_objects(), repeat(self.permission))