Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

""" 

Provides a set of pluggable permission policies. 

""" 

from __future__ import unicode_literals 

import inspect 

import warnings 

 

SAFE_METHODS = ['GET', 'HEAD', 'OPTIONS'] 

 

from rest_framework.compat import oauth2_provider_scope, oauth2_constants 

 

 

class BasePermission(object): 

    """ 

    A base class from which all permission classes should inherit. 

    """ 

 

    def has_permission(self, request, view): 

        """ 

        Return `True` if permission is granted, `False` otherwise. 

        """ 

        return True 

 

    def has_object_permission(self, request, view, obj): 

        """ 

        Return `True` if permission is granted, `False` otherwise. 

        """ 

        if len(inspect.getargspec(self.has_permission).args) == 4: 

            warnings.warn( 

                'The `obj` argument in `has_permission` is deprecated. ' 

                'Use `has_object_permission()` instead for object permissions.', 

                DeprecationWarning, stacklevel=2 

            ) 

            return self.has_permission(request, view, obj) 

        return True 

 

 

class AllowAny(BasePermission): 

    """ 

    Allow any access. 

    This isn't strictly required, since you could use an empty 

    permission_classes list, but it's useful because it makes the intention 

    more explicit. 

    """ 

    def has_permission(self, request, view): 

        return True 

 

 

class IsAuthenticated(BasePermission): 

    """ 

    Allows access only to authenticated users. 

    """ 

 

    def has_permission(self, request, view): 

        if request.user and request.user.is_authenticated(): 

            return True 

        return False 

 

 

class IsAdminUser(BasePermission): 

    """ 

    Allows access only to admin users. 

    """ 

 

    def has_permission(self, request, view): 

        if request.user and request.user.is_staff: 

            return True 

        return False 

 

 

class IsAuthenticatedOrReadOnly(BasePermission): 

    """ 

    The request is authenticated as a user, or is a read-only request. 

    """ 

 

    def has_permission(self, request, view): 

        if (request.method in SAFE_METHODS or 

            request.user and 

            request.user.is_authenticated()): 

            return True 

        return False 

 

 

class DjangoModelPermissions(BasePermission): 

    """ 

    The request is authenticated using `django.contrib.auth` permissions. 

    See: https://docs.djangoproject.com/en/dev/topics/auth/#permissions 

 

    It ensures that the user is authenticated, and has the appropriate 

    `add`/`change`/`delete` permissions on the model. 

 

    This permission can only be applied against view classes that 

    provide a `.model` or `.queryset` attribute. 

    """ 

 

    # Map methods into required permission codes. 

    # Override this if you need to also provide 'view' permissions, 

    # or if you want to provide custom permission codes. 

    perms_map = { 

        'GET': [], 

        'OPTIONS': [], 

        'HEAD': [], 

        'POST': ['%(app_label)s.add_%(model_name)s'], 

        'PUT': ['%(app_label)s.change_%(model_name)s'], 

        'PATCH': ['%(app_label)s.change_%(model_name)s'], 

        'DELETE': ['%(app_label)s.delete_%(model_name)s'], 

    } 

 

    authenticated_users_only = True 

 

    def get_required_permissions(self, method, model_cls): 

        """ 

        Given a model and an HTTP method, return the list of permission 

        codes that the user is required to have. 

        """ 

        kwargs = { 

            'app_label': model_cls._meta.app_label, 

            'model_name': model_cls._meta.module_name 

        } 

        return [perm % kwargs for perm in self.perms_map[method]] 

 

    def has_permission(self, request, view): 

        model_cls = getattr(view, 'model', None) 

        queryset = getattr(view, 'queryset', None) 

 

        if model_cls is None and queryset is not None: 

            model_cls = queryset.model 

 

        # Workaround to ensure DjangoModelPermissions are not applied 

        # to the root view when using DefaultRouter. 

        if model_cls is None and getattr(view, '_ignore_model_permissions', False): 

            return True 

 

        assert model_cls, ('Cannot apply DjangoModelPermissions on a view that' 

                           ' does not have `.model` or `.queryset` property.') 

 

        perms = self.get_required_permissions(request.method, model_cls) 

 

        if (request.user and 

            (request.user.is_authenticated() or not self.authenticated_users_only) and 

            request.user.has_perms(perms)): 

            return True 

        return False 

 

 

class DjangoModelPermissionsOrAnonReadOnly(DjangoModelPermissions): 

    """ 

    Similar to DjangoModelPermissions, except that anonymous users are 

    allowed read-only access. 

    """ 

    authenticated_users_only = False 

 

 

class TokenHasReadWriteScope(BasePermission): 

    """ 

    The request is authenticated as a user and the token used has the right scope 

    """ 

 

    def has_permission(self, request, view): 

        token = request.auth 

        read_only = request.method in SAFE_METHODS 

 

        if not token: 

            return False 

 

        if hasattr(token, 'resource'):  # OAuth 1 

            return read_only or not request.auth.resource.is_readonly 

        elif hasattr(token, 'scope'):  # OAuth 2 

            required = oauth2_constants.READ if read_only else oauth2_constants.WRITE 

            return oauth2_provider_scope.check(required, request.auth.scope) 

 

        assert False, ('TokenHasReadWriteScope requires either the' 

        '`OAuthAuthentication` or `OAuth2Authentication` authentication ' 

        'class to be used.')