From 1b4de2b762bb7583f80f4a2816fa341b39c78bd9 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Wed, 9 Sep 2015 09:32:38 +0200 Subject: [PATCH] new notify command to handle role provisionning/deprovisionning messages (fixes #8219) It gets wcs roles from uuid or slug of the authentic2 role; if role is using a slug it's replaced by the uuid. It handles rename by using uuid as the slug of roles. Targetted tenants are identified through their SAML entity id. --- wcs/ctl/notify.py | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 wcs/ctl/notify.py diff --git a/wcs/ctl/notify.py b/wcs/ctl/notify.py new file mode 100644 index 0000000..be129f9 --- /dev/null +++ b/wcs/ctl/notify.py @@ -0,0 +1,104 @@ +# w.c.s. - web application for online forms +# Copyright (C) 2005-2014 Entr'ouvert +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . + +import os +import sys +import json + +from wcs.roles import Role +from qommon.ctl import Command +from qommon.publisher import get_cfg + + +class CmdNotify(Command): + name = 'notify' + + def execute(self, base_options, sub_options, args): + import publisher + + self.base_options = base_options + if sub_options.extra: + if not self.config.has_section('extra'): + self.config.add_section('extra') + for i, extra in enumerate(sub_options.extra): + self.config.set('extra', 'cmd_line_extra_%d' % i, extra) + publisher.WcsPublisher.configure(self.config) + pub = publisher.WcsPublisher.create_publisher() + + global_app_dir = pub.app_dir + + if args[1] == '-': + # get environment definition from stdin + notification = json.load(sys.stdin) + else: + notification = json.load(file(args[1])) + + if not isinstance(notification, dict) \ + or '@type' not in notification \ + or notification['@type'] not in ['provision', 'deprovision'] \ + or 'objects' not in notification \ + or 'audience' not in notification \ + or not isinstance(notification['audience'], list) \ + or not isinstance(notification['objects'], list): + sys.exit(1) + action = notification['@type'] + audience = notification['audience'] + full = notification['full'] if full in notification else False + for hostname in os.listdir(global_app_dir): + pub.app_dir = os.path.join(global_app_dir, hostname) + pub.set_config() + # Verify tenant is in audience + entity_id = get_cfg('sp', {}).get('saml2_providerid') + if not entity_id or entity_id not in audience: + continue + + uuids = set() + # Now provision/deprovision + for o in notification['objects']: + t = o['@type'] + if t != 'role' \ + or 'uuid' not in o \ + or 'name' not in o \ + or 'slug' not in o: + continue + uuid = o['uuid'].encode(publisher.site_charset) + uuids.add(uuid) + slug = o['slug'].encode(publisher.site_charset) + name = o['name'].encode(publisher.site_charset) + # Find existing role + try: + role = Role.get_on_index(uuid, 'slug') + except KeyError: + try: + role = Role.get_on_index(slug, 'slug') + except KeyError: + # New role + if action != 'provision': + continue + role = Role(name=name) + if action == 'provision': + # Provision/rename + role.name = name + role.slug = uuid + role.store() + elif action == 'provision': + # Deprovision + role.remove_self() + # All roles have been sent + if full: + for role in Role.select(): + if role.slug not in uuids: + role.remove_self() -- 2.1.4