1 |
1 |
'''Views for Authentic2 API'''
|
|
2 |
import json
|
2 |
3 |
import smtplib
|
3 |
4 |
|
4 |
5 |
from django.db import models
|
... | ... | |
11 |
12 |
from django_rbac.utils import get_ou_model
|
12 |
13 |
|
13 |
14 |
from rest_framework import serializers
|
|
15 |
from rest_framework.viewsets import ModelViewSet
|
|
16 |
from rest_framework.routers import SimpleRouter
|
14 |
17 |
from rest_framework.generics import GenericAPIView
|
15 |
18 |
from rest_framework.response import Response
|
16 |
|
from rest_framework import authentication, permissions, status
|
|
19 |
from rest_framework import permissions, status
|
|
20 |
from rest_framework.exceptions import PermissionDenied
|
17 |
21 |
|
18 |
22 |
from . import utils, decorators
|
|
23 |
from .models import Attribute, AttributeValue
|
19 |
24 |
|
20 |
25 |
|
21 |
26 |
class HasUserAddPermission(permissions.BasePermission):
|
... | ... | |
83 |
88 |
|
84 |
89 |
|
85 |
90 |
class BaseRpcView(RpcMixin, GenericAPIView):
|
86 |
|
authentication_classes = (authentication.BasicAuthentication,)
|
87 |
91 |
permission_classes = (permissions.IsAuthenticated,
|
88 |
92 |
HasUserAddPermission)
|
89 |
93 |
|
... | ... | |
200 |
204 |
if request.user.is_anonymous():
|
201 |
205 |
return {}
|
202 |
206 |
return request.user.to_json()
|
|
207 |
|
|
208 |
|
|
209 |
_class_cache = {}
|
|
210 |
|
|
211 |
|
|
212 |
def attributes_hash(attributes):
|
|
213 |
attributes = sorted(attributes, key=lambda at: at.name)
|
|
214 |
return hash(tuple((at.name, at.required) for at in attributes))
|
|
215 |
|
|
216 |
|
|
217 |
def get_user_class():
|
|
218 |
attributes = Attribute.objects.filter(kind='string')
|
|
219 |
key = 'user-class-%s' % attributes_hash(attributes)
|
|
220 |
if key not in _class_cache:
|
|
221 |
user_class = get_user_model()
|
|
222 |
|
|
223 |
class Meta:
|
|
224 |
proxy = True
|
|
225 |
fields = {
|
|
226 |
'Meta': Meta,
|
|
227 |
'__module__': user_class.__module__,
|
|
228 |
}
|
|
229 |
for at in attributes:
|
|
230 |
def new_property(at):
|
|
231 |
def get_property(self):
|
|
232 |
try:
|
|
233 |
return json.loads(
|
|
234 |
AttributeValue.objects.with_owner(self).get(attribute=at).content)
|
|
235 |
except AttributeValue.DoesNotExist:
|
|
236 |
return ''
|
|
237 |
|
|
238 |
def set_property(self, value):
|
|
239 |
at.set_value(self, value)
|
|
240 |
return property(get_property, set_property)
|
|
241 |
fields[at.name] = new_property(at)
|
|
242 |
_class_cache[key] = type('NewUserClass', (user_class,), fields)
|
|
243 |
return _class_cache[key]
|
|
244 |
|
|
245 |
|
|
246 |
class BaseUserSerializer(serializers.ModelSerializer):
|
|
247 |
ou = serializers.SlugRelatedField(
|
|
248 |
queryset=get_ou_model().objects.all(),
|
|
249 |
slug_field='slug',
|
|
250 |
required=False, allow_null=True)
|
|
251 |
date_joined = serializers.DateTimeField(read_only=True)
|
|
252 |
last_login = serializers.DateTimeField(read_only=True)
|
|
253 |
|
|
254 |
def check_perm(self, perm, ou):
|
|
255 |
self.context['view'].check_perm(perm, ou)
|
|
256 |
|
|
257 |
def create(self, validated_data):
|
|
258 |
extra_field = {}
|
|
259 |
for at in Attribute.objects.filter(kind='string'):
|
|
260 |
if at.name in validated_data:
|
|
261 |
extra_field[at.name] = validated_data.pop(at.name)
|
|
262 |
self.check_perm('custom_user.add_user', validated_data.get('ou'))
|
|
263 |
instance = super(BaseUserSerializer, self).create(validated_data)
|
|
264 |
for key, value in extra_field.iteritems():
|
|
265 |
setattr(instance, key, value)
|
|
266 |
if 'password' in validated_data:
|
|
267 |
instance.set_password(validated_data['password'])
|
|
268 |
instance.save()
|
|
269 |
return instance
|
|
270 |
|
|
271 |
def update(self, instance, validated_data):
|
|
272 |
extra_field = {}
|
|
273 |
for at in Attribute.objects.filter(kind='string'):
|
|
274 |
if at.name in validated_data:
|
|
275 |
extra_field[at.name] = validated_data.pop(at.name)
|
|
276 |
# Double check: to move an user from one ou into another you must be administrator of both
|
|
277 |
self.check_perm('custom_user.change_user', instance.ou)
|
|
278 |
self.check_perm('custom_user.change_user', validated_data.get('ou'))
|
|
279 |
super(BaseUserSerializer, self).update(instance, validated_data)
|
|
280 |
for key, value in extra_field.iteritems():
|
|
281 |
setattr(instance, key, value)
|
|
282 |
if 'password' in validated_data:
|
|
283 |
instance.set_password(validated_data['password'])
|
|
284 |
instance.save()
|
|
285 |
return instance
|
|
286 |
|
|
287 |
class Meta:
|
|
288 |
model = get_user_class()
|
|
289 |
exclude = ('date_joined', 'user_permissions', 'groups', 'last_login')
|
|
290 |
|
|
291 |
|
|
292 |
class UsersAPI(ModelViewSet):
|
|
293 |
filter_fields = ['username', 'first_name', 'last_name']
|
|
294 |
ordering_fields = ['username', 'first_name', 'last_name']
|
|
295 |
|
|
296 |
def get_serializer_class(self):
|
|
297 |
attributes = Attribute.objects.filter(kind='string')
|
|
298 |
key = 'user-serializer-%s' % attributes_hash(attributes)
|
|
299 |
if key not in _class_cache:
|
|
300 |
attrs = {}
|
|
301 |
for at in attributes:
|
|
302 |
attrs[at.name] = serializers.CharField(required=at.required)
|
|
303 |
_class_cache[key] = type('UserSerializer', (BaseUserSerializer,), attrs)
|
|
304 |
return _class_cache[key]
|
|
305 |
|
|
306 |
def get_queryset(self):
|
|
307 |
User = get_user_class()
|
|
308 |
return self.request.user.filter_by_perm(['custom_user.view_user'], User.objects.all())
|
|
309 |
|
|
310 |
def check_perm(self, perm, ou):
|
|
311 |
if ou:
|
|
312 |
if not self.request.user.has_ou_perm(perm, ou):
|
|
313 |
raise PermissionDenied(u'You do not have permission %s in %s' % (perm, ou))
|
|
314 |
else:
|
|
315 |
if not self.request.user.has_perm(perm):
|
|
316 |
raise PermissionDenied(u'You do not have permission %s' % perm)
|
|
317 |
|
|
318 |
def perform_destroy(self, instance):
|
|
319 |
self.check_perm('custom_user.delete_user', instance.ou)
|
|
320 |
super(UsersAPI, self).perform_destroy(instance)
|
|
321 |
|
|
322 |
|
|
323 |
router = SimpleRouter()
|
|
324 |
router.register(r'users', UsersAPI, base_name='a2-api-users')
|