[abac] An ABAC permission can be set for a user, a role, or anybody.

An ABAC permission can now be set on a user, a role or anybody.

    For a decision request about a user or a role, it works the same way has
    regular RBAC permissions execpt that moreover the ABAC rule must be
    satisfied.

    For permissions on anyone, it means that ACS is combined with a system
    able to maintain sessions without authentication. The owner of such a
    session must be able to bring (certified) attributes. It can then be granted
    the permissions that have ABAC rules that are satisfied.
This commit is contained in:
Mikaël Ates 2011-08-26 11:12:05 +02:00
parent 6ec65d84a3
commit 83fc3d5a36
3 changed files with 90 additions and 17 deletions

View File

@ -623,6 +623,17 @@ def add_abac_permission(request):
messages.add_message(request, messages.ERROR,
_('No object for How provided'))
return return_add_abac_permission_form(request)
who = None
if 'who_matches' in request.POST \
and request.POST['who_matches'] != '_':
try:
who = get_who_from_one_post_field(request, 'who_matches')
except Exception, err:
logger.error('add_permission: \
Fail to find who due to %s' % err)
messages.add_message(request, messages.ERROR,
_('Fail to find who due to %s') % err)
return return_add_abac_permission_form(request)
try:
what = get_what_from_one_post_field(request, 'what_matches')
how = get_how_from_one_post_field(request, 'how_matches')
@ -636,7 +647,8 @@ def add_abac_permission(request):
or not check_action_or_activity(request, how):
return return_add_abac_permission_form(request)
p, message = check_data_and_create_permission(request, what, how)
p, message = \
check_data_and_create_permission(request, who, what, how)
if not p:
messages.add_message(request, messages.ERROR,
@ -661,7 +673,7 @@ def add_abac_permission(request):
@transaction.commit_manually
def check_data_and_create_permission(request, what, how):
def check_data_and_create_permission(request, who, what, how):
p = None
try:
rule = None
@ -793,7 +805,10 @@ def check_data_and_create_permission(request, what, how):
rule.expression = expression
rule.save()
p = AcsAbacPermission(what=what, how=how, rule=rule)
if who:
p = AcsAbacPermission(who=who, what=what, how=how, rule=rule)
else:
p = AcsAbacPermission(what=what, how=how, rule=rule)
if not p:
raise Exception('Fail to create permission')
try:
@ -974,6 +989,21 @@ def return_add_abac_permission_form(request, template_name='add_abac_permission.
if 'rule' in request.session:
tpl_p['rule'] = request.session['rule']
tpl_p['who_to_display'] = \
return_list_users_authorized_for_admin(
set_default_alias(request.user)) + \
return_list_roles_authorized_for_admin(
set_default_alias(request.user))
tpl_p['who_to_display'] = \
filter_list_in_namespace(tpl_p['who_to_display'], policy.namespace)
if is_policy_user_administrator(request.user, policy):
for a in UserAlias.objects.filter(namespace=policy.namespace):
if not a in tpl_p['who_to_display']:
tpl_p['who_to_display'].append(a)
for a in Role.objects.filter(namespace=policy.namespace):
if not a in tpl_p['who_to_display']:
tpl_p['who_to_display'].append(a)
tpl_p['what_to_display'] = \
return_list_objects_authorized_for_admin(
set_default_alias(request.user)) + \
@ -1076,8 +1106,6 @@ def del_abac_permission(request):
logger.debug('del_abac_permission: deletion of %s' % p)
# Todo: remove all data associated: predicates, values, rule, etc
p.delete()
messages.add_message(request, messages.INFO,

View File

@ -255,10 +255,14 @@ class AcsPermission(models.Model):
class AcsAbacPermission(models.Model):
content_type_who = models.ForeignKey(ContentType, related_name = "who_abac", blank=True, null=True)
content_type_what = models.ForeignKey(ContentType, related_name = "what_abac")
content_type_how = models.ForeignKey(ContentType, related_name = "how_abac")
object_id_who = models.PositiveIntegerField(blank=True, null=True)
object_id_what = models.PositiveIntegerField()
object_id_how = models.PositiveIntegerField()
who = generic.GenericForeignKey(ct_field='content_type_who',
fk_field='object_id_who')
what = generic.GenericForeignKey(ct_field='content_type_what',
fk_field='object_id_what')
how = generic.GenericForeignKey(ct_field='content_type_how',
@ -277,24 +281,44 @@ class AcsAbacPermission(models.Model):
"content_type_how", "object_id_how"))
def __unicode__(self):
s = _('Permission on %s to perform %s if "%s"') \
%(self.what, self.how.name, self.rule)
if self.who:
s = _('Permission of %s on %s to perform %s if "%s"') \
% (self.who, self.what, self.how.name, self.rule)
else:
s = _('Permission of anyone on %s to perform %s if "%s"') \
% (self.what, self.how.name, self.rule)
if self.expiration_date:
s += _(' (expires on %s)' %self.expiration_date)
return s
def save(self, *args, **kwargs):
p = None
t_who = None
if self.who:
if not isinstance(self.who, (UserAlias, Role)):
raise Exception('What is %s, not a User or a Role') \
%ContentType.objects.get_for_model(self.what)
t_who = ContentType.objects.get_for_model(self.who)
t_what = ContentType.objects.get_for_model(self.what)
t_how = ContentType.objects.get_for_model(self.how)
'''We check here the unicity, not redundant with unique_together'''
try:
p = AcsAbacPermission.objects.get(rule=self.rule,
content_type_what__pk=t_what.id,
object_id_what=self.what.id,
content_type_how__pk=t_how.id,
object_id_how=self.how.id,
)
if self.who:
p = AcsAbacPermission.objects.get(rule=self.rule,
content_type_who__pk=t_who.id,
object_id_who=self.who.id,
content_type_what__pk=t_what.id,
object_id_what=self.what.id,
content_type_how__pk=t_how.id,
object_id_how=self.how.id,
)
else:
p = AcsAbacPermission.objects.get(rule=self.rule,
content_type_what__pk=t_what.id,
object_id_what=self.what.id,
content_type_how__pk=t_how.id,
object_id_how=self.how.id,
)
except MultipleObjectsReturned:
raise Exception('This should never happen')
except ObjectDoesNotExist:
@ -304,6 +328,9 @@ class AcsAbacPermission(models.Model):
if not isinstance(self.how, (Action, Activity)):
raise Exception('How is %s, not an Action or an Activity') \
%ContentType.objects.get_for_model(self.how)
if self.who:
self.content_type_who = ContentType.objects.get_for_model(self.who)
self.object_id_who = self.who.id
self.content_type_what = ContentType.objects.get_for_model(self.what)
self.object_id_what = self.what.id
self.content_type_how = ContentType.objects.get_for_model(self.how)

View File

@ -429,6 +429,23 @@
{% if what_to_display and how_to_display %}
<form method="post" action="">
{% if who_to_display %}
<p>
<h3>{% trans "Who" %}</h3>
<p>{% trans "You can set an ABAC rule on a user a role or anybody. If you indicate 'Anybody' in the following list, it means that there exist mechanisms to make a user able to present (certified) attributes to the system. If you indicate a role, take that it does not conflict with a role in the rule that the user should not have, for instance due to heritage and a 'not' statement." %}
</p>
<select name="who_matches" id="id_who_matches">
<option value="_">-- {% trans "Anybody" %} --</option>
{% for it in who_to_display %}
{% if it|klass == "UserAlias" %}
<option value="{{ it.id }}_{{ it|klass }}">{{ it.alias }}</option>
{% else %}
<option value="{{ it.id }}_{{ it|klass }}">{{ it.name }}</option>
{% endif %}
{% endfor %}
</select>
</p>
{% endif %}
<p>
<h3>{% trans "What" %}</h3>
<select name="what_matches" id="id_what_matches">
@ -447,7 +464,7 @@
</p>
<p>
<br style="clear: both;"/>
<input type="submit" name="add_permission" value="{% trans "Add" %}"/>
<input type="submit" name="add_permission" value="{% trans "Add permission" %}"/>
</p>
</form>
@ -461,12 +478,13 @@
{% endif %}
{% endif %}
<br style="clear: both;"/>
<form method="post" action="">
<input type="submit" name="cancel_all" value="{% trans "Cancel Rule" %}"/>
<input type="submit" name="cancel_all" value="{% trans "Cancel permission creation" %}"/>
</form>
{% endif %}
</div>
<p><a href="{{ backlink }}">{% trans "Back" %}</a></p>