Hide keyboard shortcuts

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

""" 

django-model-permissions - simple object permissions for django. 

 

Copyright (C) 2018 Mathias Stelzer 

 

This program is free software: you can redistribute it and/or modify 

it under the terms of the GNU General Public License as published by 

the Free Software Foundation, either version 3 of the License, or 

(at your option) any later version. 

 

This program is distributed in the hope that it will be useful, 

but WITHOUT ANY WARRANTY; without even the implied warranty of 

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

GNU General Public License for more details. 

 

You should have received a copy of the GNU General Public License 

along with this program. If not, see <http://www.gnu.org/licenses/>. 

""" 

from django.conf import settings 

from django.contrib.auth.backends import ( 

ModelBackend as DjangoModelBackend, 

AllowAllUsersModelBackend as DjangoAllowAllUsersModelBackend, 

RemoteUserBackend as DjangoRemoteUserBackend, 

AllowAllUsersRemoteUserBackend as DjangoAllowAllUsersRemoteUserBackend, 

) 

from django.utils.module_loading import import_string 

 

 

# mixins 

 

class BaseObjectBackendMixin(object): 

"""Base class for object permission backends.""" 

 

def get_permission_function(self, obj): 

""" 

Get the function to list the given objects permissions. 

 

This checks the given object for a ``get_permissions`` method and, 

if it doesn't exist, the ``MODEL_PERMISSIONS`` setting to find the 

objects :ref:`manual-permission-function`. 

 

:param obj: The model instance to get the function for. 

:type obj: :class:`django.db.models.Model` 

:return: The function to list the objects permissions. 

:rtype: :class:`callable` 

""" 

get_permissions = getattr(obj, 'get_permissions', None) 

if get_permissions is not None: 

return self.model_permission_wrapper 

 

model_permissions = getattr(settings, 'MODEL_PERMISSIONS', {}) 

f = model_permissions.get(obj._meta.label, None) 

if f is None: 

return 

 

if callable(f): 

return f 

 

# assume string 

return import_string(f) 

 

def model_permission_wrapper(self, user_obj, obj): 

"""Object permission wrapper for the `get_permissions` model method.""" 

return obj.get_permissions(user_obj) 

 

def get_object_permissions(self, user_obj, obj=None): 

""" 

Get object permissions for the given user and object. 

 

Exit early and return an empty set if: 

 

* no object is given 

* the user is 

 

* inactive 

* anonymous 

* a superuser 

 

* no permission function can be found 

 

:param user_obj: User instance. 

:type user_obj: :class:`django.contrib.auth.models.AbstractUser` 

:param obj: Model instance. 

:type obj: :class:`django.db.models.Model` 

:return: Set of permissions. 

:rtype: :class:`set` 

""" 

if obj is None: 

return set() 

 

get_permissions = self.get_permission_function(obj) 

if get_permissions is None: 

return set() 

 

perm_cache_name = '_{}_{}_perm_cache'.format(obj._meta.label, obj.pk) 

if not hasattr(user_obj, perm_cache_name): 

perms = get_permissions(user_obj, obj) 

if perms is None: 

perms = set() 

setattr(user_obj, perm_cache_name, perms) 

return getattr(user_obj, perm_cache_name) 

 

 

class ObjectModelBackendMixin(BaseObjectBackendMixin): 

"""Mixin for dual permission authentication backends.""" 

 

def get_all_permissions(self, user_obj, obj=None): 

"""Get all permissions for the given user and object.""" 

perms = super().get_all_permissions(user_obj) 

perms.update(self.get_object_permissions(user_obj, obj=obj)) 

return perms 

 

 

class ObjectBackendMixin(BaseObjectBackendMixin): 

"""Mixin for object-only permission authentication backends.""" 

 

def get_all_permissions(self, user_obj, obj=None): 

"""Get all permissions for the given user and object.""" 

return self.get_object_permissions(user_obj, obj=obj) 

 

 

# backends 

 

class ObjectBackend(ObjectBackendMixin, DjangoModelBackend): 

"""An authentication backend with object permissions only.""" 

 

pass 

 

 

class ObjectModelBackend(ObjectModelBackendMixin, DjangoModelBackend): 

"""An authentication backend with default and object permissions.""" 

 

pass 

 

 

class AllowAllUsersObjectBackend(ObjectBackendMixin, DjangoAllowAllUsersModelBackend): 

"""Django's `AllowAllUsersModelBackend` with object permissions only.""" 

 

pass 

 

 

class AllowAllUsersObjectModelBackend(ObjectModelBackendMixin, DjangoAllowAllUsersModelBackend): 

"""Django's `AllowAllUsersModelBackend` with dual permissions.""" 

 

pass 

 

 

class RemoteUserObjectBackend(ObjectBackendMixin, DjangoRemoteUserBackend): 

"""Django's `RemoteUserBackend` with object permissions only.""" 

 

pass 

 

 

class RemoteUserBackend(ObjectModelBackendMixin, DjangoRemoteUserBackend): 

"""Django's `RemoteUserBackend` with dual permissions.""" 

 

pass 

 

 

class AllowAllUsersRemoteUserObjectBackend(ObjectBackendMixin, DjangoAllowAllUsersRemoteUserBackend): 

"""Django's `AllowAllUsersRemoteUserBackend` with object permissions only.""" 

 

pass 

 

 

class AllowAllUsersRemoteUserBackend(ObjectModelBackendMixin, DjangoAllowAllUsersRemoteUserBackend): 

"""Django's `AllowAllUsersRemoteUserBackend` with dual permissions.""" 

 

pass