Commit 2e64ae8a by Belákovics Ádám

Add basic authorization

parent 93307f6f
......@@ -17,6 +17,7 @@ django-cors-headers = "*"
openstacksdk = "*"
python-novaclient = "*"
keystoneauth1 = "*"
django-guardian = "*"
[requires]
python_version = "3.6"
from django.contrib import admin
# Register your models here.
from django.apps import AppConfig
class AuthorizationConfig(AppConfig):
name = 'authorization'
from guardian.shortcuts import get_objects_for_user
import logging
logger = logging.getLogger(__name__)
class AuthorizationMixin():
authorization = {}
def get_objects_with_perms(self, user, method, instance):
auth_params = self.authorization[method]
if auth_params:
return get_objects_for_user(user, auth_params["perms"], instance)
else:
logger.error(f"Invalid method for authorization: {method}")
def has_perms_for_object(self, user, method, instance):
auth_params = self.authorization[method]
if auth_params:
for perm in auth_params["perms"]:
user.has_perm('')
else:
logger.error(f"Invalid method for authorization: {method}")
def has_perms_for_model(self, user, method, model):
auth_params = self.authorization[method]
if auth_params:
pass
else:
logger.error(f"Invalid method for authorization: {method}")
from django.db import models
# Create your models here.
from django.contrib.auth.models import User
from instance.models import Instance
from guardian.shortcuts import get_objects_for_user
test_user = User.objects.get(username="test")
get_objects_for_user(test_user, "use_instance", Instance)
from django.test import TestCase
# Create your tests here.
from django.shortcuts import render
# Create your views here.
......@@ -2,6 +2,13 @@ from django.contrib import admin
from instance.models import Instance, Flavor, Lease
admin.site.register(Instance)
from guardian.admin import GuardedModelAdmin
class InstanceAdmin(GuardedModelAdmin):
pass
admin.site.register(Instance, InstanceAdmin)
admin.site.register(Flavor)
admin.site.register(Lease)
......@@ -5,8 +5,8 @@ from django.utils import timezone
from datetime import timedelta
from image.models import Disk
from interface_openstack.implementation.vm.instance import (
OSVirtualMachineManager
)
OSVirtualMachineManager
)
import logging
logger = logging.getLogger(__name__)
......@@ -45,8 +45,8 @@ class Flavor(models.Model):
name = models.CharField(blank=True, max_length=100)
description = models.CharField(blank=True, max_length=200)
remote_id = models.CharField(
max_length=100, help_text="ID of the instance on the backend"
)
max_length=100, help_text="ID of the instance on the backend"
)
ram = models.IntegerField(blank=True, null=True)
vcpu = models.IntegerField(blank=True, null=True)
initial_disk = models.IntegerField(blank=True, null=True)
......@@ -82,6 +82,18 @@ class Instance(models.Model):
"""
from template.models import ImageTemplate
class Meta:
permissions = (
('create_instance', 'Can create a new VM.'),
('use_instance', 'Can access the VM connection info.'),
('operate_instance', 'Can use basic lifecycle methods of the VM.'),
('administer_instance', 'Can delete VM.'),
('access_console', 'Can access the graphical console of a VM.'),
('change_resources', 'Can change resources of a VM.'),
('manage_access', 'Can manage access rights for the VM.'),
('config_ports', 'Can configure port forwards.'),
)
name = models.CharField(max_length=100,
help_text="Human readable name of instance")
......@@ -168,10 +180,10 @@ class Instance(models.Model):
lease = self.lease
return (
timezone.now() + timedelta(
seconds=lease.suspend_interval_in_sec),
seconds=lease.suspend_interval_in_sec),
timezone.now() + timedelta(
seconds=lease.delete_interval_in_sec)
)
seconds=lease.delete_interval_in_sec)
)
def delete(self):
try:
......@@ -193,5 +205,5 @@ class Instance(models.Model):
@classmethod
def generate_password(self):
return User.objects.make_random_password(
allowed_chars='abcdefghijklmnopqrstuvwx'
'ABCDEFGHIJKLMNOPQRSTUVWX123456789')
allowed_chars='abcdefghijklmnopqrstuvwx'
'ABCDEFGHIJKLMNOPQRSTUVWX123456789')
......@@ -8,15 +8,33 @@ from rest_framework.decorators import action
from template.serializers import InstanceFromTemplateSerializer
from interface_openstack.implementation.vm.instance import (
OSVirtualMachineManager
)
OSVirtualMachineManager
)
from instance.models import Instance, Flavor, Lease
from instance.serializers import InstanceSerializer, FlavorSerializer
from template.models import ImageTemplate
from template.serializers import ImageTemplateModelSerializer
from authorization.mixins import AuthorizationMixin
class InstanceViewSet(ViewSet):
authorization = {
"list": {"auth_type": "filter", "perms": ["use_instance"]},
"create": {"auth_type": "class", "perms": ["create_instance"]},
"retrieve": {"auth_type": "object", "perms": ["use_instance"]},
"destroy": {"auth_type": "object", "perms": ["administer_instance"]},
"template": {"auth_type": "object", "perms": ["use_instance"]},
"start": {"auth_type": "object", "perms": ["operate_instance"]},
"stop": {"auth_type": "object", "perms": ["operate_instance"]},
"suspend": {"auth_type": "object", "perms": ["operate_instance"]},
"wake_up": {"auth_type": "object", "perms": ["operate_instance"]},
"reset": {"auth_type": "object", "perms": ["operate_instance"]},
"reboot": {"auth_type": "object", "perms": ["operate_instance"]},
}
class InstanceViewSet(AuthorizationMixin, ViewSet):
authorization = authorization
def get_object(self, pk):
try:
......@@ -25,7 +43,7 @@ class InstanceViewSet(ViewSet):
raise Http404
def list(self, request):
instances = Instance.objects.all()
instances = self.get_objects_with_perms(request.user, "list", Instance)
return Response(InstanceSerializer(instances, many=True).data)
def create(self, request):
......@@ -34,6 +52,8 @@ class InstanceViewSet(ViewSet):
# flavor = Flavor.objects.get(pk=data["flavor"])
# lease = Lease.objects.get(pk=data["lease"])
newInstance = Instance.create_instance_from_template(
params={"name": data["name"],
"description": data["description"],
......@@ -61,13 +81,15 @@ class InstanceViewSet(ViewSet):
return Response(merged_dict)
def update(self, request, pk, format=None):
instance = self.get_object(pk)
serializer = InstanceSerializer(instance, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
# I think we need separate actions for this behaviour because of the access control - BAdam
# def update(self, request, pk, format=None):
# instance = self.get_object(pk)
# serializer = InstanceSerializer(instance, data=request.data)
# if serializer.is_valid():
# serializer.save()
# return Response(serializer.data)
# return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def destroy(self, request, pk, format=None):
instance = self.get_object(pk)
......
......@@ -41,6 +41,7 @@ INSTALLED_APPS = [
"djoser",
"rest_framework_swagger",
"corsheaders",
"guardian",
]
LOCAL_APPS = [
......@@ -48,6 +49,7 @@ LOCAL_APPS = [
"instance",
"storage",
"template",
"authorization",
]
INSTALLED_APPS += LOCAL_APPS
......@@ -111,6 +113,7 @@ REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema' # needed for swagger
}
# Internationalization
......@@ -229,3 +232,10 @@ LOGGING = {
for i in LOCAL_APPS:
LOGGING['loggers'][i] = {'handlers': ['console'], 'level': 'DEBUG'}
# Configure django-guardian for the authorization
AUTHENTICATION_BACKENDS = (
'django.contrib.auth.backends.ModelBackend', # this is default
'guardian.backends.ObjectPermissionBackend',
)
......@@ -11,3 +11,5 @@ for i in LOCAL_APPS:
ADMIN_ENABLED = True
ALLOWED_HOSTS = ['*']
AUTH_PASSWORD_VALIDATORS = []
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment