From 5b69f25921aa7d7b1ee051944afdc0f309bd54a9 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Sat, 5 Dec 2015 23:47:17 +0100 Subject: [PATCH 3/3] wf/roles: handle case when user attributes are managed by the idp (#9210) If the user's attributes are managed by an idp, we add/remove roles by calling the idp role management web-services. It only works with authentic2. --- wcs/wf/roles.py | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/wcs/wf/roles.py b/wcs/wf/roles.py index d670937..4834fb9 100644 --- a/wcs/wf/roles.py +++ b/wcs/wf/roles.py @@ -14,10 +14,36 @@ # You should have received a copy of the GNU General Public License # along with this program; if not, see . +import urlparse +import urllib + from quixote import get_request, get_publisher from qommon.form import * from wcs.workflows import WorkflowStatusItem, register_item_class -from wcs.roles import get_user_roles +from wcs.roles import get_user_roles, Role +from qommon.ident.idp import is_idp_manage_user_attributes +from qommon.misc import http_post_request, http_delete_request +from qommon.publisher import get_cfg, get_logger +from wcs.api import sign_url + + +def get_secret(url): + domain = urlparse.urlparse(url).netloc.split(':')[0] + secret = get_publisher().get_site_option(domain, 'api-secrets') + return secret + + +def roles_ws_url(role_uuid, user_uuid): + idps = get_cfg('idp', {}) + entity_id = idps.values()[0]['metadata_url'] + base_url = entity_id.split('idp/saml2/metadata')[0] + url = urlparse.urljoin(base_url, '/api/roles/%s/members/%s/' % (urllib.quote(role_uuid), + urllib.quote(user_uuid))) + secret = get_secret(url) + orig = get_request().get_server().split(':')[0] + url += '?orig=%s' % orig + return sign_url(url, secret) + class AddRoleWorkflowStatusItem(WorkflowStatusItem): description = N_('Add Role to User') @@ -50,6 +76,12 @@ class AddRoleWorkflowStatusItem(WorkflowStatusItem): # we can't work on anonymous or user_hash'ed forms return user = get_publisher().user_class.get(formdata.user_id) + if user.name_identifiers and is_idp_manage_user_attributes(): + self.perform_idp(user, formdata) + else: + self.perform_local(user, formdata) + + def perform_local(self, user, formdata): if not user.roles: user.roles = [] if not self.role_id in user.roles: @@ -60,6 +92,17 @@ class AddRoleWorkflowStatusItem(WorkflowStatusItem): # changes. get_request().user = user + def perform_idp(self, user, formdata): + role = Role.get(self.role_id) + role_uuid = role.slug + user_uuid = user.name_identifiers[0] + response, status, data, auth_header = http_post_request( + roles_ws_url(role_uuid, user_uuid)) + if status != 201: + get_logger().error('failed to add role %r to user %r', + role, user) + + register_item_class(AddRoleWorkflowStatusItem) @@ -86,6 +129,12 @@ class RemoveRoleWorkflowStatusItem(WorkflowStatusItem): # we can't work on anonymous or user_hash'ed forms return user = get_publisher().user_class.get(formdata.user_id) + if user.name_identifiers and is_idp_manage_user_attributes(): + self.perform_idp(user, formdata) + else: + self.perform_local(user, formdata) + + def perform_local(self, user, formdata): if user.roles and self.role_id in user.roles: user.roles.remove(self.role_id) user.store() @@ -94,4 +143,14 @@ class RemoveRoleWorkflowStatusItem(WorkflowStatusItem): # with the changes. get_request().user = user + def perform_idp(self, user, formdata): + role = Role.get(self.role_id) + role_uuid = role.slug + user_uuid = user.name_identifiers[0] + response, status, data, auth_header = http_delete_request( + roles_ws_url(role_uuid, user_uuid)) + if status != 200: + get_logger().error('failed to remove role %r from user %r', + role, user) + register_item_class(RemoveRoleWorkflowStatusItem) -- 2.1.4