CORD-1316: Implement new credentials system
Change-Id: Iaf869cc275fe78a3dd871dc45ef5bba55cde2027
diff --git a/README.md b/README.md
index 0b93d3f..dc673ad 100644
--- a/README.md
+++ b/README.md
@@ -21,3 +21,4 @@
version is configured with a service graph that includes
`ExampleService`, which is a good platform for understanding how to
build and use XOS.
+
diff --git a/xos/api/utility/sliceplus.py b/xos/api/utility/sliceplus.py
index 591160f..6d6339c 100644
--- a/xos/api/utility/sliceplus.py
+++ b/xos/api/utility/sliceplus.py
@@ -9,7 +9,7 @@
from core.xoslib.objects.sliceplus import SlicePlus
from xos.apibase import XOSListCreateAPIView, XOSRetrieveUpdateDestroyAPIView, XOSPermissionDenied
import json
-from core.models import Slice, SlicePrivilege, SliceRole, Instance, Site, Node, User
+from core.models import Slice, Privilege, SliceRole, Instance, Site, Node, User
from operator import itemgetter, attrgetter
from api.xosapi_helpers import PlusObjectMixin, PlusModelSerializer
@@ -67,10 +67,16 @@
ready_sites[site.name] = ready_sites.get(site.name, 0) + 1
users = {}
- for priv in SlicePrivilege.objects.filter(slice=self):
- if not (priv.user.id in users.keys()):
- users[priv.user.id] = {"name": priv.user.email, "id": priv.user.id, "roles": []}
- users[priv.user.id]["roles"].append(priv.role.role)
+ for priv in Privilege.objects.filter(object_id=self.id, accessor_type='User', object_type='Slice'):
+ if not (priv.accessor_id in users.keys()):
+ accessor_user = User.objects.get(pk = priv.accessor_id)
+ users[priv.accessor_id] = {"name": accessor_user.email, "id": priv.accessor_id, "roles": []}
+
+ permission = priv.permission
+ if permission.startswith('role:'):
+ accessor_role = permission[5:]
+ accessor_role.lstrip()
+ users[priv.accessor_id]["roles"].append(accessor_role)
# XXX this assumes there is only one network that can have ports bound
# to it for a given slice. This is intended for the tenant view, which
@@ -159,7 +165,7 @@
if user.is_admin:
qs = SlicePlus.objects.all()
else:
- slice_ids = [sp.slice.id for sp in SlicePrivilege.objects.filter(user=user)]
+ slice_ids = [sp.object_id for sp in Privilege.objects.filter(accessor_id=user.id, accessor_type='User', object_type='Slice')]
qs = SlicePlus.objects.filter(id__in=slice_ids)
return qs
@@ -272,12 +278,12 @@
except:
default_role = SliceRole.objects.get(role="default")
- slice_privs = self.sliceprivileges.all()
- slice_user_ids = [priv.user.id for priv in slice_privs]
+ slice_privs = Privilege.objects.filter(object_id = self.id, object_type = 'Slice', accessor_type='User')
+ slice_user_ids = [priv.accessor_id for priv in slice_privs]
for user_id in new_users:
if (user_id not in slice_user_ids):
- priv = SlicePrivilege(slice=self, user=User.objects.get(id=user_id), role=default_role)
+ priv = Privilege(object_id=self.id, accessor_id=user_id, accessor_type = 'User', permission='role:%s'%default_role.role, object_type = 'Slice')
priv.caller = self.caller
if (not noAct):
priv.save()
diff --git a/xos/core/models/attic/controller_model.py b/xos/core/models/attic/controller_model.py
index 1e07807..9e76572 100644
--- a/xos/core/models/attic/controller_model.py
+++ b/xos/core/models/attic/controller_model.py
@@ -1,10 +1,9 @@
@staticmethod
def select_by_user(user):
-
if user.is_admin:
qs = Controller.objects.all()
else:
- from core.models.deploymentprivilege import DeploymentPrivilege
- deployments = [dp.deployment for dp in DeploymentPrivilege.objects.filter(user=user, role__role__in=['Admin', 'admin'])]
+ from core.models.privilege import Privilege
+ deployments = [dp.deployment for dp in Privilege.objects.filter(accessor_id=user_id, accessor_type='User', permission__in=['role:Admin', 'role:admin'])]
qs = Controller.objects.filter(deployment__in=deployments)
return qs
diff --git a/xos/core/models/attic/controllersiteprivilege_model.py b/xos/core/models/attic/controllersiteprivilege_model.py
index b9d8af4..11ba22d 100644
--- a/xos/core/models/attic/controllersiteprivilege_model.py
+++ b/xos/core/models/attic/controllersiteprivilege_model.py
@@ -3,17 +3,18 @@
return False
if user.is_admin:
return True
- cprivs = ControllerSitePrivilege.objects.filter(site_privilege__user=user)
- for cpriv in dprivs:
- if cpriv.site_privilege.role.role == ['admin', 'Admin']:
+
+ cprivs = ControllerPrivilege.objects.filter(privilege__accessor_id=user.id, privilege__object_type='Site')
+ for cpriv in cprivs:
+ if cpriv.privilege.permission in ['role:admin', 'role:Admin']:
return True
return False
@staticmethod
def select_by_user(user):
if user.is_admin:
- qs = ControllerSitePrivilege.objects.all()
+ qs = ControllerPrivilege.objects.filter(privilege__object_type='Site')
else:
- cpriv_ids = [cp.id for cp in ControllerSitePrivilege.objects.filter(site_privilege__user=user)]
- qs = ControllerSitePrivilege.objects.filter(id__in=cpriv_ids)
+ cpriv_ids = [cp.id for cp in ControllerPrivilege.objects.filter(privilege__accessor_id=user.id, privilege__object_type='Site')]
+ qs = ControllerPrivilege.objects.filter(id__in=cpriv_ids, privilege__object_type='Site')
return qs
diff --git a/xos/core/models/attic/controllersliceprivilege_model.py b/xos/core/models/attic/controllersliceprivilege_model.py
index aaf6053..ab64569 100644
--- a/xos/core/models/attic/controllersliceprivilege_model.py
+++ b/xos/core/models/attic/controllersliceprivilege_model.py
@@ -3,17 +3,17 @@
return False
if user.is_admin:
return True
- cprivs = ControllerSlicePrivilege.objects.filter(slice_privilege__user=user)
- for cpriv in dprivs:
- if cpriv.role.role == ['admin', 'Admin']:
+ cprivs = ControllerPrivilege.objects.filter(privilege__accessor_id=user.id, privilege__object_type='Slice')
+ for cpriv in cprivs:
+ if cpriv.privilege.permission in ['role:admin', 'role:Admin']:
return True
return False
@staticmethod
def select_by_user(user):
if user.is_admin:
- qs = ControllerSlicePrivilege.objects.all()
+ qs = ControllerPrivilege.objects.filter(privilege__object_type='Slice')
else:
- cpriv_ids = [cp.id for cp in ControllerSlicePrivilege.objects.filter(slice_privilege__user=user)]
- qs = ControllerSlicePrivilege.objects.filter(id__in=cpriv_ids)
+ cpriv_ids = [cp.id for cp in ControllerPrivilege.objects.filter(privilege__accessor_id=user.id, privilege__object_type='Slice')]
+ qs = ControllerPrivilege.objects.filter(id__in=cpriv_ids, privilege__object_type='Slice')
return qs
diff --git a/xos/core/models/attic/instance_model.py b/xos/core/models/attic/instance_model.py
index d2e7b89..a86e53d 100644
--- a/xos/core/models/attic/instance_model.py
+++ b/xos/core/models/attic/instance_model.py
@@ -32,10 +32,10 @@
raise ValidationError("Parent field can only be set on Container-vm instances")
if (self.slice.creator != self.creator):
- from core.models.sliceprivilege import SlicePrivilege
+ from core.models.privilege import Privilege
# Check to make sure there's a slice_privilege for the user. If there
# isn't, then keystone will throw an exception inside the observer.
- slice_privs = SlicePrivilege.objects.filter(slice=self.slice, user=self.creator)
+ slice_privs = Privilege.objects.filter(object_id=self.slice.id, accessor_id=self.creator.id, object_type='Slice')
if not slice_privs:
raise ValidationError('instance creator has no privileges on slice')
@@ -108,9 +108,10 @@
return 'ssh -o "ProxyCommand ssh -q %s@%s" ubuntu@%s' % (self.instance_id, self.node.name, self.instance_name)
def get_public_keys(self):
- from core.models.sliceprivilege import SlicePrivilege
- slice_memberships = SlicePrivilege.objects.filter(slice=self.slice)
- pubkeys = set([sm.user.public_key for sm in slice_memberships if sm.user.public_key])
+ from core.models.sliceprivilege import Privilege
+ slice_privileges = Privilege.objects.filter(object_id=self.slice.id, object_type='Slice', accessor_type='User')
+ slice_users = [User.objects.get(pk = priv.accessor_id) for priv in slice_privileges]
+ pubkeys = set([u.public_key for u in slice_users if u.public_key])
if self.creator.public_key:
pubkeys.add(self.creator.public_key)
diff --git a/xos/core/models/attic/service_model.py b/xos/core/models/attic/service_model.py
index d7175b6..9cb2d4d 100644
--- a/xos/core/models/attic/service_model.py
+++ b/xos/core/models/attic/service_model.py
@@ -10,9 +10,9 @@
if user.is_admin:
return cls.objects.all()
else:
- from core.models.serviceprivilege import ServicePrivilege
+ from core.models.privilege import Privilege
service_ids = [
- sp.slice.id for sp in ServicePrivilege.objects.filter(user=user)]
+ sp.object_id for sp in Privilege.objects.filter(accessor_id=user.id, accessor_type='User', object_type='Service')]
return cls.objects.filter(id__in=service_ids)
@property
diff --git a/xos/core/models/attic/slice_model.py b/xos/core/models/attic/slice_model.py
index db53e11..7154c73 100644
--- a/xos/core/models/attic/slice_model.py
+++ b/xos/core/models/attic/slice_model.py
@@ -51,13 +51,14 @@
if user.is_admin:
qs = Slice.objects.all()
else:
- from core.models.sliceprivilege import SlicePrivilege
- from core.models.siteprivilege import SitePrivilege
+ from core.models.privilege import Privilege
# users can see slices they belong to
- slice_ids = [sp.slice.id for sp in SlicePrivilege.objects.filter(user=user)]
+ slice_ids = [sp.object_id for sp in Privilege.objects.filter(accessor_id=user.id, accessor_type='User', object_type='Slice')]
# pis and admins can see slices at their sites
- sites = [sp.site for sp in SitePrivilege.objects.filter(user=user)\
- if (sp.role.role == 'pi') or (sp.role.role == 'admin')]
+ site_ids = [sp.object_id for sp in Privilege.objects.filter(accessor_id=user.id, accessor_type='User', object_type='Site')\
+ if (sp.permission in ['role:pi', 'role:admin'])]
+ sites = [Site.objects.get(pk = site_id) for site_id in site_ids]
+
slice_ids.extend([s.id for s in Slice.objects.filter(site__in=sites)])
qs = Slice.objects.filter(id__in=slice_ids)
return qs
diff --git a/xos/core/models/attic/tenantroot_model.py b/xos/core/models/attic/tenantroot_model.py
index bb09b1e..86208cd 100644
--- a/xos/core/models/attic/tenantroot_model.py
+++ b/xos/core/models/attic/tenantroot_model.py
@@ -23,9 +23,9 @@
if user.is_admin:
return cls.objects.all()
else:
- from core.models.tenantrootprivilege import TenantRootPrivilege
+ from core.models.privilege import Privilege
tr_ids = [
- trp.tenant_root.id for trp in TenantRootPrivilege.objects.filter(user=user)]
+ trp.object_id for trp in Privilege.objects.filter(accessor_id=user.id, accessor_type='User', object_type='TenantRoot')]
return cls.objects.filter(id__in=tr_ids)
# helper function to be used in subclasses that want to ensure
diff --git a/xos/core/models/core.xproto b/xos/core/models/core.xproto
index 587769d..adb5842 100644
--- a/xos/core/models/core.xproto
+++ b/xos/core/models/core.xproto
@@ -57,6 +57,16 @@
optional string policy_status = 32 [default = "0 - Policy in process", max_length = 1024];
}
+message Privilege (XOSBase) {
+ required int32 accessor_id = 1 [null = False];
+ required string accessor_type = 2 [null = False, max_length=1024];
+ required int32 object_id = 3 [null = False];
+ required string object_type = 4 [null = False, max_length=1024];
+ required string permission = 5 [null = False, default = "all", max_length=1024];
+ required string granted = 6 [content_type = "date", auto_now_add = True, max_length=1024];
+ required string expires = 7 [content_type = "date", null = True, max_length=1024];
+}
+
message AddressPool (XOSBase) {
required string name = 1 [db_index = False, max_length = 32, null = False, blank = False];
optional string addresses = 2 [db_index = False, null = True, blank = True, varchar = True];
@@ -124,6 +134,11 @@
optional string tenant_id = 3 [max_length = 200, content_type = "stripped", blank = True, help_text = "Keystone tenant id", null = True, db_index = True];
}
+message ControllerPrivilege (XOSBase) {
+ required manytoone controller->Controller:controllerprivileges = 1 [db_index = True, null = False, blank = False];
+ required manytoone privilege->Privilege:controllerprivileges = 2 [db_index = True, null = False, blank = False];
+ optional string role_id = 3 [max_length = 200, content_type = "stripped", blank = True, help_text = "Keystone id", null = True, db_index = True];
+}
message ControllerSitePrivilege (XOSBase) {
required manytoone controller->Controller:controllersiteprivileges = 1 [db_index = True, null = False, blank = False, unique_with = "site_privilege"];
diff --git a/xos/core/models/user.py b/xos/core/models/user.py
index 0d721e2..3add183 100644
--- a/xos/core/models/user.py
+++ b/xos/core/models/user.py
@@ -322,17 +322,18 @@
msg.send()
def can_update(self, user):
- from core.models.siteprivilege import SitePrivilege
+ from core.models.privilege import Privilege
_cant_update_fieldName = None
if user.can_update_root():
return True
# site pis can update
- site_privs = SitePrivilege.objects.filter(user=user, site=self.site)
+ site_privs = Privilege.objects.filter(accessor_id=user.id, object_id=self.site.id, object_type='Site', accessor_type='User')
for site_priv in site_privs:
- if site_priv.role.role == 'admin':
+ if site_priv.permission == 'role:admin':
return True
- if site_priv.role.role == 'pi':
+
+ if site_priv.permission == 'role:pi':
for fieldName in self.diff.keys():
if fieldName in self.PI_FORBIDDEN_FIELDS:
_cant_update_fieldName = fieldName
@@ -359,28 +360,28 @@
return False
def can_update_deployment(self, deployment):
- from core.models.deploymentprivilege import DeploymentPrivilege
+ from core.models.privilege import Privilege
if self.can_update_root():
return True
- if DeploymentPrivilege.objects.filter(
- deployment=deployment,
- user=self,
- role__role__in=['admin', 'Admin']):
+ if Privilege.objects.filter(
+ object_id=deployment.id,
+ accessor_id=self.id,
+ permission__in=['role:admin', 'role:Admin']):
return True
return False
def can_update_site(self, site, allow=[]):
- from core.models.siteprivilege import SitePrivilege
+ from core.models.privilege import Privilege
if self.can_update_root():
return True
- if SitePrivilege.objects.filter(
- site=site, user=self, role__role__in=['admin', 'Admin'] + allow):
+ if Privilege.objects.filter(
+ object_id=site.id, accessor_id=self.id, accessor_type='User', permission__in=['role:admin', 'role:Admin'] + ['role:'+opt for opt in allow]):
return True
return False
def can_update_slice(self, slice):
- from core.models.sliceprivilege import SlicePrivilege
+ from core.models.privilege import Privilege
if self.can_update_root():
return True
if self == slice.creator:
@@ -388,37 +389,37 @@
if self.can_update_site(slice.site, allow=['pi']):
return True
- if SlicePrivilege.objects.filter(
- slice=slice, user=self, role__role__in=['admin', 'Admin']):
+ if Privilege.objects.filter(
+ object_id=slice.id, accessor_id=self.id, permission__in=['role:admin', 'role:Admin'], accessor_type='User', object_type='Slice'):
return True
return False
def can_update_service(self, service, allow=[]):
- from core.models.serviceprivilege import ServicePrivilege
+ from core.models.privilege import Privilege
if self.can_update_root():
return True
- if ServicePrivilege.objects.filter(
- service=service, user=self, role__role__in=['admin', 'Admin'] + allow):
+ if Privilege.objects.filter(
+ object_id=service.id, accessor_id=self.id, accessor_type='User', permission__in=['role:admin', 'role:Admin'] + ['role:'+opt for opt in allow]):
return True
return False
def can_update_tenant_root(self, tenant_root, allow=[]):
from core.models.tenantroot import TenantRoot
- from core.models.tenantrootprivilege import TenantRootPrivilege
+ from core.models.privilege import Privilege
if self.can_update_root():
return True
- if TenantRootPrivilege.objects.filter(
- tenant_root=tenant_root, user=self, role__role__in=['admin', 'Admin'] + allow):
+ if Privilege.objects.filter(
+ object_id=tenant_root.id, accessor_type='User',accessor_id=self.id, permission__in=['role:admin', 'role:Admin'] + ['role:'+opt for opt in allow]):
return True
return False
def can_update_tenant(self, tenant, allow=[]):
from core.models.tenant import Tenant
- from core.models.tenantprivilege import TenantPrivilege
+ from core.models.privilege import Privilege
if self.can_update_root():
return True
- if TenantPrivilege.objects.filter(
- tenant=tenant, user=self, role__role__in=['admin', 'Admin'] + allow):
+ if Privilege.objects.filter(
+ object_id=tenant.id, accessor_type='User',accessor_id=self.id, permission__in=['role:admin', 'role:Admin'] + ['role:'+opt for opt in allow]):
return True
return False
@@ -428,132 +429,22 @@
def can_update_tenant_privilege(self, tenant_privilege, allow=[]):
return self.can_update_tenant(tenant_privilege.tenant, allow)
- def get_readable_objects(self, filter_by=None):
- """ Returns a list of objects that the user is allowed to read. """
- from core.models import Deployment, Flavor, Image, Network, NetworkTemplate, Node, PlModelMixIn, Site, Slice, SliceTag, Instance, Tag, User, DeploymentPrivilege, SitePrivilege, SlicePrivilege
- models = []
- if filter_by and isinstance(filter_by, list):
- models = [m for m in filter_by if issubclass(m, PlModelMixIn)]
- if not models:
- models = [Deployment, Network, Site,
- Slice, SliceTag, Instance, Tag, User]
- readable_objects = []
- for model in models:
- readable_objects.extend(model.select_by_user(self))
- return readable_objects
-
- def get_permissions(self, filter_by=None):
- """ Return a list of objects for which the user has read or read/write
- access. The object will be an instance of a django model object.
- Permissions will be either 'r' or 'rw'.
-
- e.g.
- [{'object': django_object_instance, 'permissions': 'rw'}, ...]
-
- Returns:
- list of dicts
-
- """
- from core.models import Deployment, Flavor, Image, Network, NetworkTemplate, Node, PlModelMixIn, Site, Slice, SliceTag, Instance, Tag, User, DeploymentPrivilege, SitePrivilege, SlicePrivilege
- READ = 'r'
- READWRITE = 'rw'
- models = []
- if filter_by and isinstance(filter_by, list):
- models = [m for m in filter_by if issubclass(m, PlModelMixIn)]
-
- deployment_priv_objs = [Image, NetworkTemplate, Flavor]
- site_priv_objs = [Node, Slice, User]
- slice_priv_objs = [Instance, Network]
-
- # maps the set of objects a paticular role has write access
- write_map = {
- DeploymentPrivilege: {
- 'admin': deployment_priv_objects,
- },
- SitePrivilege: {
- 'admin': site_priv_objs,
- 'pi': [Slice, User],
- 'tech': [Node],
- },
- SlicePrivilege: {
- 'admin': slice_priv_objs,
- },
- }
-
- privilege_map = {
- DeploymentPrivilege: (Deployment, deployment_priv_objs),
- SitePrivilege: (Site, site_priv_objs),
- SlicePrivilege: (Slice, slice_priv_objs)
- }
- permissions = []
- permission_dict = lambda x, y: {'object': x, 'permission': y}
- for privilege_model, (model, affected_models) in privileg_map.items():
- if models and model not in models:
- continue
-
- # get the objects affected by this privilege model
- affected_objects = []
- for affected_model in affected_models:
- affected_objects.extend(affected_model.select_by_user(self))
-
- if self.is_admin:
- # assume admin users have read/write access to all objects
- for affected_object in affected_objects:
- permissions.append(permission_dict(
- affected_object, READWRITE))
- else:
- # create a dict of the user's per object privileges
- # ex: {princeton_tmack : ['admin']
- privileges = privilege_model.objects.filter(user=self)
- for privilege in privileges:
- object_roles = defaultdict(list)
- obj = None
- roles = []
- for field in dir(privilege):
- if field == model.__name__.lower():
- obj = getattr(privilege, field)
- if obj:
- object_roles[obj].append(privilege.role.role)
-
- # loop through all objects the user has access to and determine
- # if they also have write access
- for affected_object in affected_objects:
- if affected_object not in objects_roles:
- permissions.append(
- permission_dict(affected_object, READ))
- else:
- has_write_permission = False
- for write_role, models in write_dict.items():
- if affected_object._meta.model in models and \
- write_role in object_roles[affected_object]:
- has_write_permission = True
- break
- if has_write_permission:
- permissions.append(
- permission_dict(affected_object, WRITE))
- else:
- permissions.append(
- permission_dict(affected_object, READ))
-
- return permissions
-
- def get_tenant_permissions(self):
- from core.models import Site, Slice
- return self.get_object_permissions(filter_by=[Site, Slice])
-
@staticmethod
def select_by_user(user):
if user.is_admin:
qs = User.objects.all()
else:
# can see all users at any site where this user has pi role
- from core.models.siteprivilege import SitePrivilege
- site_privs = SitePrivilege.objects.filter(user=user)
- sites = [sp.site for sp in site_privs if sp.role.role in [
- 'Admin', 'admin', 'pi']]
+ from core.models.privilege import Privilege
+ site_privs = Privilege.objects.filter(accessor_type='User', accessor_id=user.id, object_type='Site')
+ site_ids = [sp.object_id for sp in site_privs if sp.permission in [
+ 'role:Admin', 'role:admin', 'role:pi']]
+ sites = [Site.objects.get(pk=sid) for sid in site_ids]
+
# get site privs of users at these sites
- site_privs = SitePrivilege.objects.filter(site__in=sites)
- user_ids = [sp.user.id for sp in site_privs] + [user.id]
+ site_privs = Privilege.objects.filter(object_id__in=site_ids, object_type='Site', accessor_type='User')
+
+ user_ids = [sp.accessor_id for sp in site_privs] + [user.id]
qs = User.objects.filter(Q(site__in=sites) | Q(id__in=user_ids))
return qs
diff --git a/xos/core/xoslib/objects/sliceplus.py b/xos/core/xoslib/objects/sliceplus.py
index 9d2868f..5086f79 100644
--- a/xos/core/xoslib/objects/sliceplus.py
+++ b/xos/core/xoslib/objects/sliceplus.py
@@ -1,4 +1,4 @@
-from core.models import Slice, SlicePrivilege, SliceRole, Instance, Site, Node, User
+from core.models import Slice, Privilege, SliceRole, Instance, Site, Node, User
from plus import PlusObjectMixin
from operator import itemgetter, attrgetter
from rest_framework.exceptions import APIException
@@ -38,10 +38,11 @@
ready_sites[site.name] = ready_sites.get(site.name, 0) + 1
users = {}
- for priv in SlicePrivilege.objects.filter(slice=self):
- if not (priv.user.id in users.keys()):
- users[priv.user.id] = {"name": priv.user.email, "id": priv.user.id, "roles": []}
- users[priv.user.id]["roles"].append(priv.role.role)
+ for priv in Privilege.objects.filter(object_id=self.id, object_type='Slice', accessor_type='User'):
+ if not (priv.accessor_id in users.keys()):
+ user = User.objects.get(pk=priv.accessor_id)
+ users[priv.accessor_id] = {"name": user.email, "id": user.id, "roles": []}
+ users[priv.accessor_id]["roles"].append(priv.permission)
# XXX this assumes there is only one network that can have ports bound
# to it for a given slice. This is intended for the tenant view, which
@@ -118,7 +119,7 @@
if user.is_admin:
qs = SlicePlus.objects.all()
else:
- slice_ids = [sp.slice.id for sp in SlicePrivilege.objects.filter(user=user)]
+ slice_ids = [sp.slice.id for sp in Privilege.objects.filter(accessor_type='User',accessor_id=user.id, object_type='Slice')]
qs = SlicePlus.objects.filter(id__in=slice_ids)
return qs
@@ -231,12 +232,12 @@
except:
default_role = SliceRole.objects.get(role="default")
- slice_privs = self.sliceprivileges.all()
- slice_user_ids = [priv.user.id for priv in slice_privs]
+ slice_privs = Privilege.objects.filter(object_id=self.id, object_type='Slice', accessor_type='User')
+ slice_user_ids = [priv.accessor_id for priv in slice_privs]
for user_id in new_users:
if (user_id not in slice_user_ids):
- priv = SlicePrivilege(slice=self, user=User.objects.get(id=user_id), role=default_role)
+ priv = Privilege(object_id=self.id, accessor_id=user_id, permission='role:'+default_role, accessor_type='User', object_type='Slice')
priv.caller = self.caller
if (not noAct):
priv.save()
diff --git a/xos/synchronizers/model_policy.py b/xos/synchronizers/model_policy.py
index d79ed81..6455111 100644
--- a/xos/synchronizers/model_policy.py
+++ b/xos/synchronizers/model_policy.py
@@ -147,7 +147,7 @@
def run_policy_once():
from core.models import Instance,Slice,Controller,Network,User,SlicePrivilege,Site,SitePrivilege,Image,ControllerSlice,ControllerUser,ControllerSite
- models = [Controller, Site, SitePrivilege, Image, ControllerSlice, ControllerSite, ControllerUser, User, Slice, Network, Instance, SlicePrivilege]
+ models = [Controller, Site, SitePrivilege, Image, ControllerSlice, ControllerSite, ControllerUser, User, Slice, Network, Instance, SlicePrivilege, Privilege]
objects = []
deleted_objects = []
diff --git a/xos/tools/cleanup_unique.py b/xos/tools/cleanup_unique.py
index 97710ec..e8358ce 100644
--- a/xos/tools/cleanup_unique.py
+++ b/xos/tools/cleanup_unique.py
@@ -71,6 +71,15 @@
conflict.delete(purge=True)
seen=[]
+for obj in Privilege.objects.all():
+ seen.append(obj.id)
+ conflicts = Privilege.objects.filter(accessor_id=obj.accessor_id, object_id=obj.object_id, permission=obj.permission, accessor_type=obj.accessor_type, object_type=obj.object_type)
+ for conflict in conflicts:
+ if conflict.id not in seen:
+ print "Purging", conflict, conflict.id, "due to duplicate of", obj.id
+ conflict.delete(purge=True)
+
+seen=[]
for obj in SiteDeployment.objects.all():
seen.append(obj.id)
conflicts = SiteDeployment.objects.filter(site=obj.site, deployment=obj.deployment, controller=obj.controller)
diff --git a/xos/tosca/custom_types/xos.m4 b/xos/tosca/custom_types/xos.m4
index e37aaf1..58e3a81 100644
--- a/xos/tosca/custom_types/xos.m4
+++ b/xos/tosca/custom_types/xos.m4
@@ -1004,6 +1004,44 @@
required: false
description: gateway mac address
+ tosca.nodes.Privilege:
+ derived_from: tosca.nodes.Root
+ description: >
+ A permission granted to an accessor (a user, slice etc.) towards some type of access
+ capabilities:
+ privilege:
+ type: tosca.capabilities.xos.privilege
+ properties:
+ xos_base_props
+ accessor_id:
+ type: integer
+ required: true
+ description: id of the object representing the accessor
+ accessor_type:
+ type: string
+ required: true
+ description: name of the model representing the accessor
+ object_id:
+ type: integer
+ required: true
+ description: id of the object being accessed
+ object_type:
+ type: string
+ required: true
+ description: name of the model representing the object being accessed
+ permission:
+ type: string
+ required: true
+ description: a custom name that defines the type of access
+ granted:
+ type: string
+ required: false
+ description: time at which the permission was granted
+ expires:
+ type: string
+ required: false
+ description: time at which the permission is set to expire
+
tosca.nodes.Image:
derived_from: tosca.nodes.Root
description: >
@@ -1348,6 +1386,14 @@
derived_from: tosca.relationships.Root
valid_target_types: [ tosca.capabilities.xos.Image ]
+ tosca.relationships.HasPrivilege:
+ derived_from: tosca.relationships.Root
+ valid_target_types: [ tosca.capabilities.xos.Privilege ]
+
+ tosca.relationships.SupportsPrivilege:
+ derived_from: tosca.relationships.Root
+ valid_target_types: [ tosca.capabilities.xos.Privilege ]
+
tosca.relationships.ConnectsToSlice:
derived_from: tosca.relationships.Root
valid_target_types: [ tosca.capabilities.xos.Slice ]
@@ -1516,3 +1562,7 @@
tosca.capabilities.xos.AddressPool:
derived_from: tosca.capabilities.Root
description: An XOS AddressPool
+
+ tosca.capabilities.xos.Privilege:
+ derived_from: tosca.capabilities.Root
+ description: An XOS Privilege
diff --git a/xos/tosca/resources/deployment.py b/xos/tosca/resources/deployment.py
index ec53849..bb11e0d 100644
--- a/xos/tosca/resources/deployment.py
+++ b/xos/tosca/resources/deployment.py
@@ -15,7 +15,7 @@
# Note: support for Flavors and Images is dropped
rolemap = ( ("tosca.relationships.AdminPrivilege", "admin"), )
- self.postprocess_privileges(DeploymentRole, DeploymentPrivilege, rolemap, obj, "deployment")
+ self.postprocess_privileges(DeploymentRole, 'Deployment', rolemap, obj)
def delete(self, obj):
if obj.sites.exists():
diff --git a/xos/tosca/resources/slice.py b/xos/tosca/resources/slice.py
index df9fcc9..1a633ba 100644
--- a/xos/tosca/resources/slice.py
+++ b/xos/tosca/resources/slice.py
@@ -45,7 +45,7 @@
rolemap = ( ("tosca.relationships.AdminPrivilege", "admin"), ("tosca.relationships.AccessPrivilege", "access"),
("tosca.relationships.PIPrivilege", "pi"), ("tosca.relationships.TechPrivilege", "tech") )
- self.postprocess_privileges(SliceRole, SlicePrivilege, rolemap, obj, "slice")
+ self.postprocess_privileges(SliceRole, 'Slice', rolemap, obj)
def delete(self, obj):
if obj.instances.exists():
diff --git a/xos/tosca/resources/user.py b/xos/tosca/resources/user.py
index f1ff044..87dbaab 100644
--- a/xos/tosca/resources/user.py
+++ b/xos/tosca/resources/user.py
@@ -27,14 +27,14 @@
dest = self.engine.name_to_xos_model(self.user, obj_name)
if dest.__class__.__name__ == "Slice":
role_obj = self.get_xos_object(SliceRole, role=role)
- if not SlicePrivilege.objects.filter(user=user, role=role_obj, slice=dest):
- sp = SlicePrivilege(user=obj, role=role_obj, slice=dest)
+ if not Privilege.objects.filter(accessor_id=obj.id, permission='role:'+role_obj.role, object_id=dest.id, accessor_type='User', object_type='Slice'):
+ sp = Privilege(accessor_id=obj.id, permission='role:'+role_obj.role, object_id=dest.id, accessor_type='User', object_type='Slice')
sp.save()
self.info("Added slice privilege on %s role %s for %s" % (str(dest), str(role), str(obj)))
elif dest.__class__.__name__ == "Site":
role_obj = self.get_xos_object(SiteRole, role=role)
- if not SitePrivilege.objects.filter(user=obj, role=role_obj, site=dest):
- sp = SitePrivilege(user=obj, role=role_obj, site=dest)
+ if not Privilege.objects.filter(accessor_id=obj.id, permission='role:'+role_obj.role, object_id=dest.id, accessor_type='User', object_type='Site'):
+ sp = SitePrivilege(accessor_id=obj.id, permission='role:'+role_obj.role, object_id=dest.id, accessor_type='User', object_type='Site')
sp.save()
self.info("Added site privilege on %s role %s for %s" % (str(dest), str(role), str(obj)))
diff --git a/xos/tosca/resources/xosresource.py b/xos/tosca/resources/xosresource.py
index bc33991..d6dd482 100644
--- a/xos/tosca/resources/xosresource.py
+++ b/xos/tosca/resources/xosresource.py
@@ -3,7 +3,7 @@
import subprocess
import sys
-from core.models import User
+from core.models import User, Privilege
class XOSResource(object):
xos_base_class = "XOSResource"
@@ -148,7 +148,7 @@
return False
return True
- def postprocess_privileges(self, roleclass, privclass, rolemap, obj, toFieldName):
+ def postprocess_privileges(self, roleclass, modelname, rolemap, obj):
for (rel, role) in rolemap:
for email in self.get_requirements(rel):
role_obj = self.get_xos_object(roleclass, throw_exception=False, role=role)
@@ -159,8 +159,8 @@
role_obj.save()
user = self.get_xos_object(User, email=email)
- if not privclass.objects.filter(user=user, role=role_obj, **{toFieldName: obj}):
- sp = privclass(user=user, role=role_obj, **{toFieldName: obj})
+ if not Privilege.objects.filter(accessor_id=user.id, accessor_type='User', object_type=modelname, permission='role:'+role_obj.role, object_id=obj.id):
+ sp = Privilege(accessor_id=user.id, accessor_type='User', object_type=modelname, permission='role:'+role_obj.role, object_id=obj.id)
sp.save()
self.info("Added privilege on %s role %s for %s" % (str(obj), str(role), str(user)))
diff --git a/xos/xos_client/xosapi/convenience/privilege.py b/xos/xos_client/xosapi/convenience/privilege.py
new file mode 100644
index 0000000..d8292cf
--- /dev/null
+++ b/xos/xos_client/xosapi/convenience/privilege.py
@@ -0,0 +1,6 @@
+from xosapi.orm import ORMWrapper, register_convenience_wrapper
+
+class ORMWrapperPrivilege(ORMWrapper):
+ pass
+
+register_convenience_wrapper("Privilege", ORMWrapperPrivilege)
diff --git a/xos/xos_client/xosapi/orm.py b/xos/xos_client/xosapi/orm.py
index ce815b4..84a326f 100644
--- a/xos/xos_client/xosapi/orm.py
+++ b/xos/xos_client/xosapi/orm.py
@@ -503,6 +503,7 @@
return cls(wrapped_class, *args, **kwargs)
import convenience.addresspool
+import convenience.privilege
import convenience.instance
import convenience.cordsubscriberroot
import convenience.volttenant