8
0
Fork 0
mirror of https://gitlab2.federez.net/re2o/re2o synced 2024-11-27 15:12:25 +00:00

Add support for acl based on instances

This commit is contained in:
Maël Kervella 2017-12-02 01:46:51 +00:00 committed by root
parent 92888edc7f
commit e91d4ff186

View file

@ -21,20 +21,27 @@
""" """
Set of templatetags for using acl in templates: Set of templatetags for using acl in templates:
- can_create - can_create (model)
- cannot_create - cannot_create (model)
- can_edit (instance)
- cannot_edit (instance)
Some templatetags require a model to calculate the acl while others are need
an instance of a model (either Model.can_xxx or instance.can_xxx)
**Parameters**: **Parameters**:
model_name - The model_name that needs to be checked for the current user model_name or instance - Either the model_name (if templatetag is based on
model) or an instantiated object (if templatetag is base on instance)
that needs to be checked for the current user
args - Any other argument that is interpreted as a python object and passed args - Any other argument that is interpreted as a python object and passed
to the acl function (can_xxx) to the acl function (can_xxx)
**Usage**: **Usage**:
{% <acl_name> model [arg1 [arg2 [...]]]%} {% <acl_name> <obj> [arg1 [arg2 [...]]]%}
<template stuff> <template stuff>
[{% can_else %} [{% acl_else %}
<template stuff>] <template stuff>]
{% can_end %} {% acl_end %}
where <acl_name> is one of the templatetag names available where <acl_name> is one of the templatetag names available
(can_xxx or cannot_xxx) (can_xxx or cannot_xxx)
@ -42,16 +49,25 @@ Set of templatetags for using acl in templates:
**Example**: **Example**:
{% can_create Machine targeted_user %} {% can_create Machine targeted_user %}
<p>I'm authorized to create new machines for this guy \\o/</p> <p>I'm authorized to create new machines for this guy \\o/</p>
{% can_else %} {% acl_else %}
<p>Why can't I create a little machine for this guy ? :(</p> <p>Why can't I create a little machine for this guy ? :(</p>
{% can_end %} {% acl_end %}
{% can_edit user %}
<p>Oh I can edit myself oO</p>
{% acl_else %}
<p>Sniff can't edit my own infos ...</p>
{% acl_end %}
**How to modify**: **How to modify**:
To add a new acl function (can_xxx or cannot_xxx), add an entry in To add a new acl function (can_xxx or cannot_xxx),
'get_callback' and register your tag with the other ones juste before - if it's based on a model (like can_create), add an entry in
'can_generic' definition 'get_callback' and register your tag with the other ones juste before
To add a new model, add an entry in 'get_model' and be sure the acl 'acl_model_generic' definition
function exists in the model definition - if it's bases on an instance (like can_edit), just register yout tag with
the other ones juste before 'acl_instance_generic' definition
To add support for a new model, add an entry in 'get_model' and be sure
the acl function exists in the model definition
""" """
@ -77,75 +93,75 @@ def get_model(model_name):
# machines # machines
if model_name == 'Machine': if model_name == 'Machine':
return machines.Machine return machines.Machine
elif model_name == 'MachineType': if model_name == 'MachineType':
return machines.MachineType return machines.MachineType
elif model_name == 'IpType': if model_name == 'IpType':
return machines.IpType return machines.IpType
elif model_name == 'Vlan': if model_name == 'Vlan':
return machines.Vlan return machines.Vlan
elif model_name == 'Nas': if model_name == 'Nas':
return machines.Nas return machines.Nas
elif model_name == 'SOA': if model_name == 'SOA':
return machines.SOA return machines.SOA
elif model_name == 'Extension': if model_name == 'Extension':
return machines.Extension return machines.Extension
elif model_name == 'Mx': if model_name == 'Mx':
return machines.Mx return machines.Mx
elif model_name == 'Ns': if model_name == 'Ns':
return machines.Ns return machines.Ns
elif model_name == 'Txt': if model_name == 'Txt':
return machines.Txt return machines.Txt
elif model_name == 'Srv': if model_name == 'Srv':
return machines.Srv return machines.Srv
elif model_name == 'Interface': if model_name == 'Interface':
return machines.Interface return machines.Interface
elif model_name == 'Domain': if model_name == 'Domain':
return machines.Domain return machines.Domain
elif model_name == 'IpList': if model_name == 'IpList':
return machines.IpList return machines.IpList
elif model_name == 'Service': if model_name == 'Service':
return machines.Service return machines.Service
elif model_name == 'Service_link': if model_name == 'Service_link':
return machines.Service_link return machines.Service_link
elif model_name == 'OuverturePortList': if model_name == 'OuverturePortList':
return machines.OuverturePortList return machines.OuverturePortList
elif model_name == 'OuverturePort': if model_name == 'OuverturePort':
return machines.OuverturePort return machines.OuverturePort
# topologie # topologie
# TODO # TODO
# users # users
# TODO # TODO
else: raise template.TemplateSyntaxError(
raise template.TemplateSyntaxError( "%r is not a valid model for an acl tag" % model_name
"%r is not a valid model for an acl tag" % model_name )
)
def get_callback(tag_name, model_name): def get_callback(tag_name, obj):
"""Return the right function to call back to check for acl""" """Return the right function to call back to check for acl"""
model = get_model(model_name)
if tag_name == 'can_create': if tag_name == 'can_create':
return acl_fct(model.can_create, False) return acl_fct(obj.can_create, False)
if tag_name == 'cannot_create': if tag_name == 'cannot_create':
return acl_fct(model.can_create, True) return acl_fct(obj.can_create, True)
else: if tag_name == 'can_edit':
raise template.TemplateSyntaxError( return acl_fct(obj.can_edit, False)
"%r tag is not a valid can_xxx tag" % tag_name if tag_name == 'cannot_edit':
) return acl_fct(obj.can_edit, True)
raise template.TemplateSyntaxError(
"%r tag is not a valid can_xxx tag" % tag_name
)
def acl_fct(callback, reverse): def acl_fct(callback, reverse):
"""Build a function to use as an acl checker""" """Build a function to use as an acl checker"""
def acl_fct_normal(*args, **kwargs): def acl_fct_normal(user, *args, **kwargs):
"""The can_xxx checker callback""" """The can_xxx checker callback"""
return callback(*args, **kwargs) return callback(user, *args, **kwargs)
def acl_fct_reverse(*args, **kwargs): def acl_fct_reverse(user, *args, **kwargs):
"""The cannot_xxx checker callback""" """The cannot_xxx checker callback"""
can, msg = callback(*args, **kwargs) can, msg = callback(user, *args, **kwargs)
return not can, msg return not can, msg
return acl_fct_reverse if reverse else acl_fct_normal return acl_fct_reverse if reverse else acl_fct_normal
@ -153,8 +169,8 @@ def acl_fct(callback, reverse):
@register.tag('can_create') @register.tag('can_create')
@register.tag('cannot_create') @register.tag('cannot_create')
def can_generic(parser, token): def acl_model_filter(parser, token):
"""Generic definition of an acl templatetag""" """Generic definition of an acl templatetag for acl based on model"""
try: try:
tag_content = token.split_contents() tag_content = token.split_contents()
@ -167,7 +183,8 @@ def can_generic(parser, token):
% token.contents.split()[0] % token.contents.split()[0]
) )
callback = get_callback(tag_name, model_name) model = get_model(model_name)
callback = get_callback(tag_name, model)
# {% can_create %} # {% can_create %}
oknodes = parser.parse(('can_else', 'can_end')) oknodes = parser.parse(('can_else', 'can_end'))
@ -183,11 +200,44 @@ def can_generic(parser, token):
# {% can_create_end %} # {% can_create_end %}
assert token.contents == 'can_end' assert token.contents == 'can_end'
return CanNode(callback, oknodes, konodes, *args) return AclModelNode(callback, oknodes, konodes, *args)
class CanNode(Node): @register.tag('can_edit')
"""A node for the compiled ACL block""" @register.tag('cannot_edit')
def acl_instance_filter(parser, token):
"""Generic definition of an acl templatetag for acl based on instance"""
try:
tag_content = token.split_contents()
tag_name = tag_content[0]
instance_name = tag_content[1]
args = tag_content[2:]
except ValueError:
raise template.TemplateSyntaxError(
"%r tag require at least 1 argument : the instance"
% token.contents.split()[0]
)
# {% can_create %}
oknodes = parser.parse(('can_else', 'can_end'))
token = parser.next_token()
# {% can_create_else %}
if token.contents == 'can_else':
konodes = parser.parse(('can_end'))
token = parser.next_token()
else:
konodes = NodeList()
# {% can_create_end %}
assert token.contents == 'can_end'
return AclInstanceNode(tag_name, instance_name, oknodes, konodes, *args)
class AclModelNode(Node):
"""A node for the compiled ACL block when acl is base on model"""
def __init__(self, callback, oknodes, konodes, *args): def __init__(self, callback, oknodes, konodes, *args):
self.callback = callback self.callback = callback
@ -201,3 +251,22 @@ class CanNode(Node):
if can: if can:
return self.oknodes.render(context) return self.oknodes.render(context)
return self.konodes.render(context) return self.konodes.render(context)
class AclInstanceNode(Node):
"""A node for the compiled ACL block when acl is based on instance"""
def __init__(self, tag_name, instance_name, oknodes, konodes, *args):
self.tag_name = tag_name
self.instance = template.Variable(instance_name)
self.oknodes = oknodes
self.konodes = konodes
self.args = [template.Variable(arg) for arg in args]
def render(self, context):
callback = get_callback(self.tag_name, self.instance.resolve(context))
resolved_args = [arg.resolve(context) for arg in self.args]
can, _ = callback(context['user'], *(resolved_args))
if can:
return self.oknodes.render(context)
return self.konodes.render(context)