Ejemplo n.º 1
0
def save_related_job_templates(sender, instance, **kwargs):
    '''save_related_job_templates loops through all of the
    job templates that use an Inventory or Project that have had their
    Organization updated. This triggers the rebuilding of the RBAC hierarchy
    and ensures the proper access restrictions.
    '''
    if sender not in (Project, Inventory):
        raise ValueError('This signal callback is only intended for use with Project or Inventory')

    if instance._prior_values_store.get('organization_id') != instance.organization_id:
        jtq = JobTemplate.objects.filter(**{sender.__name__.lower(): instance})
        for jt in jtq:
            update_role_parentage_for_instance(jt)
Ejemplo n.º 2
0
def save_related_job_templates(sender, instance, **kwargs):
    '''save_related_job_templates loops through all of the
    job templates that use an Inventory that have had their
    Organization updated. This triggers the rebuilding of the RBAC hierarchy
    and ensures the proper access restrictions.
    '''
    if sender is not Inventory:
        raise ValueError(
            'This signal callback is only intended for use with Project or Inventory'
        )

    update_fields = kwargs.get('update_fields', None)
    if ((update_fields and not ('organization' in update_fields
                                or 'organization_id' in update_fields))
            or kwargs.get('created', False)):
        return

    if instance._prior_values_store.get(
            'organization_id') != instance.organization_id:
        jtq = JobTemplate.objects.filter(**{sender.__name__.lower(): instance})
        for jt in jtq:
            parents_added, parents_removed = update_role_parentage_for_instance(
                jt)
            if parents_added or parents_removed:
                logger.info(
                    'Permissions on JT {} changed due to inventory {} organization change from {} to {}.'
                    .format(
                        jt.pk, instance.pk,
                        instance._prior_values_store.get('organization_id'),
                        instance.organization_id))
Ejemplo n.º 3
0
def rebuild_role_parentage(apps, schema_editor, models=None):
    """
    This should be called in any migration when any parent_role entry
    is modified so that the cached parent fields will be updated. Ex:
        foo_role = ImplicitRoleField(
            parent_role=['bar_role']  # change to parent_role=['admin_role']
        )

    This is like rebuild_role_hierarchy, but that method updates ancestors,
    whereas this method updates parents.
    """
    start = time()
    seen_models = set()
    model_ct = 0
    noop_ct = 0
    ContentType = apps.get_model('contenttypes', "ContentType")
    additions = set()
    removals = set()

    role_qs = Role.objects
    if models:
        # update_role_parentage_for_instance is expensive
        # if the models have been downselected, ignore those which are not in the list
        ct_ids = list(
            ContentType.objects.filter(
                model__in=[name.lower()
                           for name in models]).values_list('id', flat=True))
        role_qs = role_qs.filter(content_type__in=ct_ids)

    for role in role_qs.iterator():
        if not role.object_id:
            continue
        model_tuple = (role.content_type_id, role.object_id)
        if model_tuple in seen_models:
            continue
        seen_models.add(model_tuple)

        # The GenericForeignKey does not work right in migrations
        # with the usage as role.content_object
        # so we do the lookup ourselves with current migration models
        ct = role.content_type
        app = ct.app_label
        ct_model = apps.get_model(app, ct.model)
        content_object = ct_model.objects.get(pk=role.object_id)

        parents_added, parents_removed = update_role_parentage_for_instance(
            content_object)
        additions.update(parents_added)
        removals.update(parents_removed)
        if parents_added:
            model_ct += 1
            logger.debug('Added to parents of roles {} of {}'.format(
                parents_added, content_object))
        if parents_removed:
            model_ct += 1
            logger.debug('Removed from parents of roles {} of {}'.format(
                parents_removed, content_object))
        else:
            noop_ct += 1

    logger.debug('No changes to role parents for {} resources'.format(noop_ct))
    logger.debug('Added parents to {} roles'.format(len(additions)))
    logger.debug('Removed parents from {} roles'.format(len(removals)))
    if model_ct:
        logger.info(
            'Updated implicit parents of {} resources'.format(model_ct))

    logger.info('Rebuild parentage completed in %f seconds' % (time() - start))

    # this is ran because the ordinary signals for
    # Role.parents.add and Role.parents.remove not called in migration
    Role.rebuild_role_ancestor_list(list(additions), list(removals))
Ejemplo n.º 4
0
def test_update_parents_keeps_teams(team, project):
    project.update_role.parents.add(team.member_role)
    assert team.member_role in project.update_role  # test prep sanity check
    update_role_parentage_for_instance(project)
    assert team.member_role in project.update_role  # actual assertion