Skip to content

Commit

Permalink
Merge branch 'devel' into master
Browse files Browse the repository at this point in the history
Conflicts:
	atlas/prodtask/templates/prodtask/_task_detail.html
	setup.cfg
  • Loading branch information
stavrik committed Nov 5, 2014
2 parents 4f05c14 + 9d8d9dc commit 0d75cee
Show file tree
Hide file tree
Showing 43 changed files with 2,808 additions and 607 deletions.
1 change: 1 addition & 0 deletions atlas/auth/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__author__ = 'sbel'
23 changes: 23 additions & 0 deletions atlas/auth/fake/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
==============================================================
Perform fake authentication as a specified user
==============================================================

Prequsities
+++++++++++

User to authenticate as should exist in the database (table 'auth_user').


Configuration
+++++++++++++


settings/config.py
..................

* Add 'atlas.auth.fake.backends.LoginAsBackend' to AUTHENTICATION_BACKENDS
before all other backends.

* Set FAKE_LOGIN_AS_USER = 'username' , pointing to the desired username existing
in the database

Empty file added atlas/auth/fake/__init__.py
Empty file.
20 changes: 20 additions & 0 deletions atlas/auth/fake/backends.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User


class LoginAsBackend(ModelBackend):
""" Authenticate as user specified in configuration file.
The user should exist in the database.
"""
def authenticate(self, request=None):
username = settings.FAKE_LOGIN_AS_USER
if not username:
return

try:
user = User.objects.get(username=username)
except User.DoesNotExist:
return

return user
1 change: 1 addition & 0 deletions atlas/auth/voms/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__author__ = 'sbel'
64 changes: 64 additions & 0 deletions atlas/auth/voms/backends.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from django.conf import settings
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import Group
from django.contrib.auth.models import User

from .interface import VomsInterface
from .models import VomsUser


def add_group(group_name):
try:
group = Group.objects.get(name=group_name)
except Group.DoesNotExist:
group = Group(name=group_name)
group.save()

return group


class VomsBackend(ModelBackend):
""" Adding VOMS-based authentication groups for user. """

def authenticate(self, request=None):
""" Checking user against VOMS data and adding corresponding authentication groups.
Parameters:
request: Http request (HttpRequest).
Returns always None to pass further handling to ShibSSO module.
"""

username = request.META.get(settings.META_USERNAME)

if not username:
return

dn_map = {}
for record in VomsUser.objects.filter(username=username):
dn_map[record.dn] = record.ca

if not dn_map:
return

voms = VomsInterface(settings.VOMS_OPTIONS)
voms_groups = []

for (dn, ca) in dn_map.items():
vo_roles = voms.list_user_roles(dn, ca) or []
vo_groups = voms.list_user_groups(dn, ca) or []
vo_roles = ["vomsrole:" + x for x in vo_roles]
vo_groups = ["vomsgroup:" + x for x in vo_groups]

voms_groups = vo_groups + vo_roles


for group in voms_groups:
add_group(group)

meta_groups = request.META.get(settings.META_GROUP, '')
groups = ';'.join( [x for x in (voms_groups + [meta_groups]) if x] )
request.META[settings.META_GROUP] = groups

return
81 changes: 81 additions & 0 deletions atlas/auth/voms/collector.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/bin/env python

import re
from django.conf import settings

from .interface import VomsInterface
from .models import VomsUser

def run():
"""
Update VOMS mapping nickname <-> (DN, CA) in the database
:return: dictionary, 'added', 'removed' - records added/removed,
'details' - more information on operations performed
"""

voms = VomsInterface(settings.VOMS_OPTIONS)
voms_users = {}

for user_info in voms.list_users():
dn = user_info["DN"]
ca = user_info["CA"]
try:
nickname = voms.get_user_nickname(dn, ca)
except:
# TODO: log the error (e.g. user was removed during data collection)
continue
if not re.match(r"^\w+$", nickname):
# TODO: log the warning
continue

if not voms_users.get(nickname):
voms_users[nickname] = {}
voms_users[nickname].update({dn: ca})

result = {'added': 0, 'removed': 0, 'detailed': []}

for user in VomsUser.objects.all():
info = voms_users.get(user.username)
if not info or not user.dn in info:
try:
user.delete()
except:
# TODO: log the error
continue

result['removed'] += 1
result['detailed'].append({
'action': 'remove', 'username': user.username,
'dn': user.dn, 'ca': user.ca,
})
# TODO: log operation
continue
else:
del voms_users[user.username][user.dn]

for (nickname, info) in voms_users.items():
for (dn, ca) in info.items():
user = VomsUser()

try:
user = VomsUser.objects.get(username=nickname, dn=dn)
except:
user.username = nickname
user.dn = dn
user.ca = ca
try:
user.save()
except:
# TODO: log the error
continue
result['added'] += 1
result['detailed'].append({
'action': 'add', 'username': user.username,
'dn': user.dn, 'ca': user.ca,
})

return result


if __name__ == "__main__":
run()
73 changes: 73 additions & 0 deletions atlas/auth/voms/interface.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import os

from VOMSAdmin.VOMSCommands import VOMSAdminProxy


class VomsInterface:
"""
Retrieving information from VOMS server.
"""

def __init__(self, options):
self.options = dict(options)
self.voms = VOMSAdminProxy(**options)

def list_users(self):
vo_users = self.voms.listUsers()
users = []

for user in vo_users:
user_info = {}
for field in "CA,DN,mail".split(","):
user_info[field] = getattr(user, "_" + field)
users.append(user_info)
return users

def list_user_attributes(self, dn, ca):
"""
Read user's attributes from VOMS server
:param dn: DN of user's certificate
:param ca: DN of the issuer of the certificate (CA)
:return: user's attributes as a dict
"""
result = {}
attrs = self.voms.call_method("list-user-attributes", dn, ca)
for item in attrs:
result[item._attributeClass._name] = item._value
return result

def list_user_groups(self, dn, ca):
"""
Get user's groups in VO from VOMS server
:param dn: DN of user's certificate
:param ca: DN of the issuer of the certificate (CA)
:return: list of groups
"""
return self.voms.call_method("list-user-groups", dn, ca)

def list_user_roles(self, dn, ca):
return self.voms.call_method("list-user-roles", dn, ca)

def get_user_nickname(self, dn, ca):
attributes = self.list_user_attributes(dn, ca)
return attributes.get("nickname")

@staticmethod
def get_identity_options(voms_admin_path="/usr/bin/voms-admin", proxy_cert=None):
import imp
voms_admin = imp.load_source("voms_admin", voms_admin_path)
voms_admin.vlog = lambda msg: None

if proxy_cert:
old_proxy = os.environ.get("X509_USER_PROXY")
os.environ["X509_USER_PROXY"] = proxy_cert
voms_admin.setup_identity()
# Restore initial environment
if old_proxy is None:
del os.environ["X509_USER_PROXY"]
else:
os.environ["X509_USER_PROXY"] = old_proxy
else:
voms_admin.setup_identity()

return voms_admin.options
1 change: 1 addition & 0 deletions atlas/auth/voms/management/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__author__ = 'serge'
1 change: 1 addition & 0 deletions atlas/auth/voms/management/commands/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__author__ = 'serge'
16 changes: 16 additions & 0 deletions atlas/auth/voms/management/commands/updatevomsmap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
__author__ = 'sbel'


from django.core.management.base import BaseCommand, CommandError
from atlas.auth.voms import collector


class Command(BaseCommand):

def handle(self, *args, **options):
# TODO: add verbose and quiet mode
info = collector.run()
# TODO: use logging here
print "Added records: %s" % (info['added'])
print "Removed records: %s" % (info['removed'])

23 changes: 23 additions & 0 deletions atlas/auth/voms/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
__author__ = 'sbel'

from django.db import models
from django.utils import timezone

class VomsUser(models.Model):
id = models.AutoField(db_column='ID', primary_key=True)
username = models.CharField(max_length=60, db_column='USERNAME', db_index=True)
dn = models.CharField(max_length=255, db_column='DN', db_index=True)
ca = models.CharField(max_length=255, db_column='CA')
added_on = models.DateTimeField(auto_now_add=True, db_column='ADDED_ON')

def save(self, *args, **kwargs):
if not self.added_on:
self.added_on = timezone.now()
super(VomsUser, self).save(*args, **kwargs)


class Meta:
managed = True
db_table = u'VOMS_USERS_MAP'
app_label = 'auth'
unique_together = (("username", "dn"),)
Empty file added atlas/deftcore/__init__.py
Empty file.
Empty file added atlas/deftcore/api/__init__.py
Empty file.
Loading

0 comments on commit 0d75cee

Please sign in to comment.