diff --git a/acs/abac/core.py b/acs/abac/core.py
index 85e30dc..8f1fae1 100644
--- a/acs/abac/core.py
+++ b/acs/abac/core.py
@@ -25,6 +25,8 @@ import time
from django.db import transaction
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
+from acs.models import Namespace, UserAlias
+
from acs.abac.models import *
from acs.xacml.constants import *
@@ -574,7 +576,8 @@ def add_assertion_to_profile(profile, source, definition, values,
'''
a = None
logger.debug('add_assertion_to_profile: Add assertion to profile %s \
- - (%s, %s, %s)' % (profile, source, definition, str(values)))
+ - (%s, %s, %s)' % (profile, source, definition, values))
+
try:
data = None
try:
@@ -1043,3 +1046,44 @@ def remove_rule(rule):
else:
transaction.commit()
logger.debug('remove_rule: rule deleted')
+
+def get_identifier_in_source(user, source):
+ if not user:
+ logger.error('get_identifier_in_source: no user provided')
+ return None
+ if not source:
+ logger.error('get_identifier_in_source: no source provided')
+ return None
+ '''
+ If the source is used for authentication and the option
+ is_auth_backend is selected, we consider that the username is the
+ identifier in the ldap, i.e. the dn
+
+ We may do better with django_to_ldap_username() of
+ http://packages.python.org/django-auth-ldap/
+ '''
+ if source.is_auth_backend:
+ return user.username
+ ns = None
+ try:
+ ns = Namespace.objects.get(name=source.name)
+ except ObjectDoesNotExist:
+ logger.error('get_identifier_in_source: no corresponding namespace')
+ return None
+ except MultipleObjectsReturned:
+ logger.critical('get_identifier_in_source: multiple namespaces \
+ corresponding to source %s' % source)
+ return None
+ try:
+ ua = UserAlias.objects.get(user=user, namespace=ns)
+ logger.debug('get_identifier_in_source: user has alias %s in source \
+ %s' % (ua.alias, source.name))
+ return ua.alias
+ except ObjectDoesNotExist:
+ logger.error('get_identifier_in_source: user has no correspondiong \
+ alias for that source')
+ return None
+ except MultipleObjectsReturned:
+ logger.critical('get_identifier_in_source: multiple aliases of user \
+ %s for the source %s' % (user, source))
+ return None
diff --git a/acs/abac/models.py b/acs/abac/models.py
index cfe1c7f..91e5f06 100644
--- a/acs/abac/models.py
+++ b/acs/abac/models.py
@@ -27,21 +27,30 @@ from django.utils.translation import ugettext as _
from acs.xacml.constants import *
-SOURCE_TYPE = (
- ('DIRECT', _('Direct trusted source')),
- ('ANCHOR', _('Trust anchor')))
-
class Source(models.Model):
name = models.CharField(max_length = 100, unique=True)
- public_key_or_ssl_certificate = models.TextField(blank=True)
- type_source = models.CharField(
- max_length = 60, choices = SOURCE_TYPE,
- verbose_name = '',
- default = 'DIRECT')
def __unicode__(self):
- return 'Source %s of type %s' % (self.name, self.type_source)
+ return 'Source %s' % self.name
+
+ def get_source_instance(self):
+ try:
+ return self.ldapsource
+ except:
+ pass
+ return None
+
+
+class LdapSource(Source):
+ server = models.CharField(max_length=100, unique=True)
+ user = models.CharField(max_length=100, blank=True, null=True)
+ password = models.CharField(max_length=100, blank=True, null=True)
+ base = models.CharField(max_length=100)
+ port = models.IntegerField(default=389)
+ ldaps = models.BooleanField(default=False)
+ certificate = models.TextField(blank=True)
+ is_auth_backend = models.BooleanField(default=False)
class AttributeDefinition(models.Model):
diff --git a/acs/alias_mgmt_views.py b/acs/alias_mgmt_views.py
index 29c55c3..e3c9fd3 100644
--- a/acs/alias_mgmt_views.py
+++ b/acs/alias_mgmt_views.py
@@ -39,6 +39,8 @@ from core import get_alias_in_policy, \
from models import UserAlias, Namespace, Policy
+from abac.models import Source, LdapSource
+
from decorators import prevent_access_to_not_user_administrators, \
check_policy_in_session, \
check_authorized_on_users_and_roles
@@ -116,7 +118,8 @@ def list_users_for_aliases(request):
tpl_parameters = \
{'list_any': users,
'authz_policies': plist,
- 'title': 'Pick a policy to synchronize or a user to administrate',
+ 'title': \
+ 'User aliases administration and self-administration enabling',
'type_entity': 'user',
'backlink': root_url}
return render_to_response('list_users_for_aliases.html', tpl_parameters,
@@ -276,29 +279,66 @@ def list_aliases(request, pk=None):
messages.add_message(request, messages.ERROR,
_('Unknown user with id %s') %request.GET['id'])
return HttpResponseRedirect('/list_users_for_aliases')
+
+ sources = None
+ try:
+ sources = Source.objects.all()
+ except Exception, err:
+ logger.error('list_aliases: An error occurred looking for \
+ sources: %s' % err)
+ logger.debug('list_aliases: sources found %s' % sources)
+ source_names = [source.name for source in sources]
+
+ '''
+ Aliases in policies
+ '''
aliases = get_aliases_of_user_without_default(user)
namespaces_in = []
namespaces_all = []
namespaces_not_in = []
list_any = []
for a in aliases:
- namespaces_in.append(a.namespace)
- if is_self_admin(a):
- list_any.append((a, True))
- else:
- list_any.append((a, False))
+ if a.namespace.name not in source_names:
+ namespaces_in.append(a.namespace)
+ if is_self_admin(a):
+ list_any.append((a, True))
+ else:
+ list_any.append((a, False))
policies = Policy.objects.all()
for p in policies:
if is_user_administrator(request.user) \
or is_policy_root_administrator(request.user, p):
namespaces_all.append(p.namespace)
namespaces_not_in = list(set(namespaces_all) - set(namespaces_in))
+
+ '''
+ Aliases in sources
+ '''
+ aliases_sources = []
+ for source in sources:
+ if not (isinstance(source.get_source_instance(), LdapSource) \
+ and source.get_source_instance().is_auth_backend):
+ ns = None
+ try:
+ ns = Namespace.objects.get(name=source.name)
+ except Exception, err:
+ logger.error('list_aliases: An error occurred \
+ looking for the namespace of %s: %s\
+ sources: %s' % (source.name, err))
+ else:
+ try:
+ u = UserAlias.objects.get(user=user, namespace=ns)
+ aliases_sources.append((ns, u))
+ except:
+ aliases_sources.append((ns, None))
+
back_url = '/list_aliases?id=%s' %pk
tpl_parameters = {'namespaces_not_in': namespaces_not_in,
'list_any': list_any,
'title': _('Add or remove an alias of %s') %user,
'user': user,
'type_entity': 'alias',
+ 'aliases_sources': aliases_sources,
'back_url': back_url,
'backlink': 'list_users_for_aliases'}
return render_to_response('list_aliases_and_add.html',
@@ -372,7 +412,7 @@ def set_user_in_policy_from_home(request):
already has the alias %s in this namespace' %(user, a))
messages.add_message(request, messages.ERROR,
_('The user already has the alias %s in this namespace') %a)
- return HttpResponseRedirect('mod_policy?id=' + str(policy.id))
+ return HttpResponseRedirect(backurl)
except ObjectDoesNotExist:
pass
except MultipleObjectsReturned:
@@ -382,7 +422,7 @@ def set_user_in_policy_from_home(request):
_('The user already has multiple aliases in this namespace'))
return HttpResponseRedirect(backurl)
- if not 'alias' in request.POST and not request.POST['alias']:
+ if not 'alias' in request.POST or not request.POST['alias']:
alias = user.username
else:
alias = request.POST['alias']
@@ -407,6 +447,76 @@ def set_user_in_policy_from_home(request):
HttpResponseRedirect('/list_users_for_aliases')
+@csrf_exempt
+@prevent_access_to_not_user_administrators
+def set_user_in_source(request):
+ '''The admin must have admin right on this user'''
+ if request.method == 'POST':
+ if not 'alias' in request.POST or not 'user_id' in request.POST \
+ or not 'namespace_id' in request.POST:
+ logger.error('set_user_in_namespace_from_home: \
+ missing data from %s' %request.user)
+ messages.add_message(request, messages.ERROR, _('Invalid action'))
+ HttpResponseRedirect('/list_users_for_aliases')
+ user = None
+ try:
+ user = User.objects.get(id=request.POST['user_id'])
+ except:
+ logger.error('set_user_in_source: \
+ unknown user with id %s' %request.POST['user_id'])
+ messages.add_message(request, messages.ERROR, _('Unkown user'))
+ HttpResponseRedirect('/list_users_for_aliases')
+ backurl = '/list_aliases?id=' + request.POST['user_id']
+
+ ns = None
+ try:
+ ns = Namespace.objects.get(id=request.POST['namespace_id'])
+ except:
+ logger.error('set_user_in_source: \
+ unknown namespace with id %s' %request.POST['namespace_id'])
+ messages.add_message(request, messages.ERROR,
+ _('Unkown namespace'))
+ return HttpResponseRedirect(backurl)
+
+ '''Create alias'''
+ try:
+ a = UserAlias.objects.get(user=user, namespace=ns)
+ logger.error('set_user_in_source: the user %s \
+ already has the alias %s in this namespace' %(user, a))
+ messages.add_message(request, messages.ERROR,
+ _('The user already has the alias %s in this namespace') %a)
+ return HttpResponseRedirect(backurl)
+ except ObjectDoesNotExist:
+ pass
+ except MultipleObjectsReturned:
+ logger.critical('set_user_in_source: \
+ the user has mulitple aliases in this namespace')
+ messages.add_message(request, messages.ERROR,
+ _('The user already has multiple aliases in this namespace'))
+ return HttpResponseRedirect(backurl)
+
+ if not 'alias' in request.POST or not request.POST['alias']:
+ alias = user.username
+ else:
+ alias = request.POST['alias']
+
+ ua = None
+ try:
+ ua = UserAlias(alias=alias, user=user, namespace=ns)
+ ua.save()
+ except:
+ messages.add_message(request, messages.ERROR,
+ _('Unable to add %s for %s in %s') %(alias, user, ns))
+ return HttpResponseRedirect(backurl)
+
+ messages.add_message(request, messages.INFO,
+ _('User %s added in %s') %(ua, ns))
+ return HttpResponseRedirect(backurl)
+
+ messages.add_message(request, messages.ERROR, _('Unknown action'))
+ HttpResponseRedirect('/list_users_for_aliases')
+
+
@csrf_exempt
@check_policy_in_session
@check_authorized_on_users_and_roles
diff --git a/acs/core.py b/acs/core.py
index 76ceda1..babf3e4 100644
--- a/acs/core.py
+++ b/acs/core.py
@@ -677,9 +677,9 @@ def is_authorized_by_names_with_abac(requestor_name, who_name, what_name,
The requester is different from who that means that the requester must
be authorized on the parameters of its request
'''
- if requestor and (not who or who.user != requestor):
- logger.debug("The requester %s is different from who %s that means that the requester must \
- be authorized on the parameters of its request" % (requestor, who.user))
+ if requestor and (not who or not who.user or who.user != requestor):
+ logger.debug("The requester is different from who that means that the requester must \
+ be authorized on the parameters of its request")
administration = Action.objects.get(name='administration')
p = isAuthorizedRBAC2(set_default_alias(requestor), what, administration)
if not is_policy_object_creator(requestor, policy) and not p:
@@ -698,20 +698,16 @@ def is_authorized_by_names_with_abac(requestor_name, who_name, what_name,
% (requestor, who))
return (False, None, -11)
- if not who.user:
- # We should remove the possibility to have a UserAlias not pointing to a
- # user
- logger.critical('is_authorized_by_names_with_abac: \
- No user associated with that alias %s' % who)
- return (False, None, -12)
-
'''
Attribute loading in profile object
'''
from abac.core import load_profile_by_dic, load_or_create_user_profile
- profile = load_or_create_user_profile(user=who.user)
+ if who.user:
+ profile = load_or_create_user_profile(user=who.user)
+ else:
+ profile = load_or_create_user_profile(user=None)
if not profile:
logger.critical('is_authorized_by_names_with_abac: \
Error to create or load profile for %s' % who)
@@ -738,8 +734,12 @@ def is_authorized_by_names_with_abac(requestor_name, who_name, what_name,
load_profile_by_dic(profile, request.session['attributes'])
if who and not no_attribute_signal:
- attributes_provided = attributes_call.send(sender=None,
- request=request, user=who)
+ if not who.user:
+ attributes_provided = attributes_call.send(sender=None,
+ request=request, user=who)
+ else:
+ attributes_provided = attributes_call.send(sender=None,
+ request=request, user=who.user)
logger.info('is_authorized_by_names_with_abac: signal attributes_call sent')
attributes = {}
diff --git a/acs/deletion_view.py b/acs/deletion_view.py
index 7ee766f..d2579ff 100644
--- a/acs/deletion_view.py
+++ b/acs/deletion_view.py
@@ -17,6 +17,7 @@
along with this program. If not, see
{% trans "In " %}{{ ns.name }}
+{% if alias %} + +{% else %} ++
+{% endif %} +{{ p }}
{% endfor %} diff --git a/acs/urls.py b/acs/urls.py index febbc7d..2cd3339 100644 --- a/acs/urls.py +++ b/acs/urls.py @@ -71,6 +71,8 @@ urlpatterns = patterns('', 'acs.alias_mgmt_views.list_aliases_in_policy'), url(r'^set_user_in_policy$', 'acs.alias_mgmt_views.set_user_in_policy'), + url(r'^set_user_in_source$', + 'acs.alias_mgmt_views.set_user_in_source'), url(r'^list_accesses$', @@ -124,6 +126,9 @@ urlpatterns = patterns('', url(r'^list_abac_permissions$', 'acs.abac_views.list_abac_permissions'), url(r'^del_abac_permission$', 'acs.abac_views.del_abac_permission'), url(r'^add_abac_source$', 'acs.views.add_abac_source'), + url(r'^add_abac_ldap_source$', 'acs.views.add_abac_ldap_source'), + url(r'^list_abac_sources$', 'acs.views.list_abac_sources'), + url(r'^mod_source$', 'acs.views.mod_source'), url(r'^add_admin_view$', 'acs.acs_administration_views.add_admin_view'), diff --git a/acs/views.py b/acs/views.py index 4144654..9fa93dc 100644 --- a/acs/views.py +++ b/acs/views.py @@ -33,9 +33,7 @@ from django.conf import settings from forms import AddRoleForm, AddObjectForm, AddViewForm, AddActionForm, \ AddActivityForm, RoleChangeForm, AcsObjectChangeForm, \ ViewChangeForm, ActionChangeForm, ActivityChangeForm, \ - AddSourceForm - - + AddSourceForm, AddLdapSourceForm from core import is_policy_action_creator, is_policy_object_creator, \ is_policy_user_administrator, is_in_policy, is_valid_regex, \ @@ -55,7 +53,9 @@ from core import is_policy_action_creator, is_policy_object_creator, \ get_alias_in_policy from models import UserAlias, Role, AcsObject, View, Action, Activity, \ - AcsPermission + AcsPermission, Namespace + +from abac.models import Source from decorators import prevent_access_to_normal_users,\ check_policy_in_session, \ @@ -106,6 +106,108 @@ def add_abac_source(request): return return_add_any(request, form, title) +@csrf_exempt +@prevent_access_to_not_user_administrators +def add_abac_ldap_source(request): + title = _('Add a new ABAC LDAP source') + if request.method == 'POST': + if 'cancel' in request.POST: + messages.add_message(request, messages.INFO, + _('Operation canceled')) + return HttpResponseRedirect(root_url) + logger.debug('add_abac_ldap_source: request.POST %s ' % request.POST) + form = AddLdapSourceForm(request.POST) + logger.debug('add_abac_ldap_source: form %s ' % form) + if form.is_valid(): + source = form.save() + Namespace.objects.get_or_create(name=source.name) + logger.debug('add_abac_ldap_source: Ldap source %s created' \ + % source) + messages.add_message(request, messages.INFO, + _('The LDAP source %s has been correctly created.') % source) + return HttpResponseRedirect(root_url) + else: + form = AddLdapSourceForm() + return return_add_any(request, form, title) + + +@csrf_exempt +@prevent_access_to_not_user_administrators +def list_abac_sources(request): + title = _('Modify or delete an ABAC source') + type_entity = 'source' + objects = Source.objects.all() + return return_list_any(request, objects, title, type_entity, + backlink=root_url, back_url='list_abac_sources') + + +@csrf_exempt +@prevent_access_to_not_user_administrators +def mod_source(request): + form = None + source = None + if request.method == 'GET': + if 'source' in request.GET and request.GET['source']: + try: + source = Source.objects.get(id=request.GET['source']) + except: + messages.add_message(request, messages.ERROR, + _('Unknown source')) + return HttpResponseRedirect('/list_abac_sources') + else: + messages.add_message(request, messages.ERROR, + _('Unknown source')) + return HttpResponseRedirect('/list_abac_sources') + + is_ldap = source.get_source_instance() + if is_ldap: + form = AddLdapSourceForm(instance=is_ldap) + else: + form = AddSourceForm(instance=source) + + elif request.method == 'POST': + if 'cancel' in request.POST: + messages.add_message(request, messages.INFO, + _('Operation canceled')) + return HttpResponseRedirect('/list_abac_sources') + if 'id' in request.POST and request.POST['id']: + try: + source = Source.objects.get(id=request.POST['id']) + except: + messages.add_message(request, messages.ERROR, + _('Unknown source')) + return HttpResponseRedirect('/list_abac_sources') + else: + messages.add_message(request, messages.ERROR, + _('Unknown source')) + return HttpResponseRedirect('/list_abac_sources') + + name = source.name + is_ldap = source.get_source_instance() + if is_ldap: + form = AddLdapSourceForm(request.POST, instance=is_ldap) + else: + form = AddSourceForm(request.POST, instance=source) + + if form.is_valid(): + s = form.save() + s.save() + messages.add_message(request, messages.INFO, + _('Source %s modified') % form.cleaned_data['name']) + else: + logger.error('mod_source: Error validating form %s' % form) + + else: + messages.add_message(request, messages.ERROR, + _('Unknown HTTP method %s') %request.method) + return HttpResponseRedirect('/list_abac_sources') + + title = _('Modify the source %s') % source + tpl_p = {'item': source, 'backlink': 'list_abac_sources'} + return return_mod_any(request, form, title, tpl_p=tpl_p, + template_name='mod_any_new.html') + + @csrf_exempt @prevent_access_to_not_user_administrators def list_users(request): @@ -419,6 +521,8 @@ def list_any(request, type_entity): return list_actions(request) elif type_entity == 'activity': return list_activities(request) + elif type_entity == 'source': + return list_abac_sources(request) return HttpResponseRedirect(root_url)