authentic agent: remove obsolete import-wcs-roles command (#35374)
This commit is contained in:
parent
4c39a9d35f
commit
2ad03f8140
6
README
6
README
|
@ -156,12 +156,6 @@ adapted in the AUTHENTIC_MANAGE_COMMAND setting. It should be run with the
|
|||
same rights as the authentic2 process (redefine the command to use sudo if
|
||||
necessary).
|
||||
|
||||
The agent also provide a commands to import roles from w.c.s named
|
||||
import-wcs-roles. It computes the web-service credentials from the hobo.json
|
||||
and use the email of the oldest superuser. Cron job can be created for calling
|
||||
this command when regular synchronization of roles with your w.c.s. instances
|
||||
is needed. The sole option named "--delete" indicate if you want to delete
|
||||
stale roles, default is to not delete them.
|
||||
|
||||
Tests
|
||||
-----
|
||||
|
|
|
@ -1,202 +0,0 @@
|
|||
# hobo - portal to configure and deploy applications
|
||||
# Copyright (C) 2015 Entr'ouvert
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import logging
|
||||
import requests
|
||||
import urllib
|
||||
import urlparse
|
||||
import hashlib
|
||||
import json
|
||||
|
||||
from optparse import make_option
|
||||
|
||||
from django.utils.text import slugify
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.conf import settings
|
||||
|
||||
from authentic2.saml.models import LibertyProvider
|
||||
from authentic2.a2_rbac.models import Role, RoleAttribute
|
||||
from authentic2 import app_settings
|
||||
|
||||
|
||||
from hobo import signature
|
||||
from hobo.multitenant.middleware import TenantMiddleware
|
||||
|
||||
from tenant_schemas.utils import tenant_context
|
||||
|
||||
|
||||
class WcsRoleImporter(object):
|
||||
def __init__(self, liberty_provider, key, orig,
|
||||
attribute_name='role-slug', delete=False):
|
||||
self.service = liberty_provider
|
||||
self.slug = liberty_provider.slug
|
||||
self.key = key
|
||||
self.orig = orig
|
||||
self.attribute_name = attribute_name
|
||||
self.delete = delete
|
||||
assert 'saml/metadata' in self.service.entity_id
|
||||
self.wcs_url = self.service.entity_id.split('saml/metadata')[0]
|
||||
self.logger = logging.getLogger('%s.%s' % (__name__,
|
||||
self.__class__.__name__))
|
||||
self.seen_ids = set()
|
||||
|
||||
def import_roles(self):
|
||||
for role_tpl in self.get_roles():
|
||||
self.seen_ids.add(role_tpl.external_id)
|
||||
self.create_role(role_tpl)
|
||||
if self.delete:
|
||||
self.delete_dead_roles()
|
||||
su_role, created = Role.objects.get_or_create(
|
||||
service=self.service, slug='_a2-hobo-superuser',
|
||||
defaults={'name': _('Superuser')})
|
||||
su_role.attributes.get_or_create(name='is_superuser', kind='string',
|
||||
value='true')
|
||||
|
||||
def create_role(self, role_tpl):
|
||||
defaults = {
|
||||
'name': role_tpl.name,
|
||||
# w.c.s. will always provide a slug but for other services we do
|
||||
# not know
|
||||
'slug': role_tpl.slug or slugify(role_tpl.name),
|
||||
}
|
||||
# search role by external id, create if not found
|
||||
role, created = Role.objects.get_or_create(
|
||||
ou=self.service.ou,
|
||||
external_id=role_tpl.external_id,
|
||||
defaults=defaults)
|
||||
RoleAttribute.objects.filter(role=role).delete()
|
||||
role_attribute, ra_created = RoleAttribute.objects.get_or_create(
|
||||
role=role,
|
||||
name=self.attribute_name,
|
||||
kind='string',
|
||||
defaults={
|
||||
'value': role_tpl.external_id
|
||||
})
|
||||
if created:
|
||||
self.logger.info('imported new role %r(%r) from service %s',
|
||||
role.external_id, role.name, self.slug)
|
||||
# update role attribute value if it has changed
|
||||
if not ra_created:
|
||||
if role_attribute.value != role_tpl.external_id:
|
||||
role_attribute.value = role_tpl.external_id
|
||||
role_attribute.save()
|
||||
# update role name if has changed
|
||||
if not created:
|
||||
# Update name and slug if they have changed
|
||||
if role.name != role_tpl.name:
|
||||
role.name = role_tpl.name
|
||||
role.save()
|
||||
# update emails, emails_to_members and details in RA
|
||||
if role_tpl.emails:
|
||||
ra, created = RoleAttribute.objects.get_or_create(
|
||||
role=role, name='emails', kind='json',
|
||||
defaults={'value': json.dumps(role_tpl.emails)})
|
||||
if ra.value != json.dumps(role_tpl.emails):
|
||||
ra.value = json.dumps(role_tpl.emails)
|
||||
ra.save()
|
||||
ra, created = RoleAttribute.objects.get_or_create(
|
||||
role=role, name='emails_to_members', kind='json',
|
||||
defaults={'value': json.dumps(role_tpl.emails_to_members)})
|
||||
if ra.value != json.dumps(role_tpl.emails_to_members):
|
||||
ra.value = json.dumps(role_tpl.emails_to_members)
|
||||
ra.save()
|
||||
if role_tpl.details:
|
||||
value = json.dumps(role_tpl.details)
|
||||
ra, created = RoleAttribute.objects.get_or_create(
|
||||
role=role, name='details', kind='json',
|
||||
defaults={'value': value})
|
||||
if ra.value != value:
|
||||
ra.value = value
|
||||
ra.save()
|
||||
|
||||
def delete_dead_roles(self):
|
||||
'''Deletes service roles whose id is not in self.seen_ids'''
|
||||
qs = Role.objects.filter(service=self.service) \
|
||||
.exclude(external_id__in=list(self.seen_ids))
|
||||
for role in qs:
|
||||
self.logger.info('deleted dead role %r(%r) from service %s',
|
||||
role.external_id, role.slug, self.slug)
|
||||
qs.delete()
|
||||
|
||||
def get_roles(self):
|
||||
'''Get w.c.s. from its roles web-service by sending a signed GET
|
||||
request.
|
||||
'''
|
||||
url = self.wcs_url + 'api/roles?%s' % urllib.urlencode(
|
||||
{'format': 'json', 'orig': self.orig})
|
||||
signed_url = signature.sign_url(url, self.key)
|
||||
response = requests.get(signed_url, verify=app_settings.A2_VERIFY_SSL)
|
||||
if response.status_code == 200:
|
||||
for role in response.json()['data']:
|
||||
new_role = Role(name=role['text'], external_id=str(role['slug']),
|
||||
slug=str(role['slug']))
|
||||
new_role.description = role.get('details', u'')
|
||||
new_role.emails = role.get('emails', [])
|
||||
new_role.emails_to_members = role.get('emails_to_members', False)
|
||||
new_role.details = role.get('details', '')
|
||||
yield new_role
|
||||
else:
|
||||
self.logger.warn('failed to get roles for %s (response: %s)',
|
||||
self.wcs_url, response.status_code)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Import W.C.S. roles"
|
||||
|
||||
requires_system_checks = False
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument('--delete', action="store_true", dest='delete')
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# traverse list of tenants
|
||||
for tenant in TenantMiddleware.get_tenants():
|
||||
with tenant_context(tenant):
|
||||
if getattr(settings, 'HOBO_ROLE_EXPORT', True):
|
||||
continue
|
||||
self.handle_tenant(tenant, **options)
|
||||
|
||||
def handle_tenant(self, tenant, **options):
|
||||
# extract informations on deployed w.c.s. instances from hobo.json
|
||||
hobo_json_path = os.path.join(tenant.get_directory(), 'hobo.json')
|
||||
if not os.path.exists(hobo_json_path):
|
||||
print 'skipping %s, no hobo.json found' % tenant
|
||||
return
|
||||
hobo_environment = json.load(open(hobo_json_path))
|
||||
# compute our credentials from our hobo configuration
|
||||
me = [x for x in hobo_environment['services'] if x.get('this')]
|
||||
if not me:
|
||||
print 'skipping %s, self services is not marked' % tenant
|
||||
return
|
||||
me = me[0]
|
||||
orig = urlparse.urlsplit(me['base_url']).netloc.split(':')[0]
|
||||
for service_id in settings.KNOWN_SERVICES:
|
||||
if service_id != 'wcs':
|
||||
continue
|
||||
for service in settings.KNOWN_SERVICES[service_id].values():
|
||||
if not service.get('secret'):
|
||||
continue
|
||||
liberty_provider = LibertyProvider.objects.get(
|
||||
entity_id=service['url'] + 'saml/metadata')
|
||||
importer = WcsRoleImporter(
|
||||
liberty_provider=liberty_provider,
|
||||
key=service['secret'],
|
||||
orig=orig,
|
||||
delete=options.get('delete', False),
|
||||
)
|
||||
importer.import_roles()
|
Loading…
Reference in New Issue