#!/usr/bin/env bash

# {{ ansible_managed }}

# Script generated by the 'debops.slapd' Ansible role
# Test the current OpenLDAP Access Control List rules against the defined policy

# Usage:
#
# slapacl-test-suite
#     run standalone to see only policy errors
#
# slapacl-test-suite | more
#     see all policy rules and their status
#
# slapacl-test-suite 2 > /tmp/errors
#     redirect errors to /tmp/errors

set -o nounset  #-o pipefail -o errexit


print_acl () {
    if [ ! -t 1 ] && [ "${print_stdout}" = "true" ] ; then
        if [ "${stdout_has_started}" -gt 0 ] ; then
            printf "\n"
        fi
        stdout_has_started=1
        printf "test: %s\ndn: \"%s\"\n" "${test_name}" "${test_dn}"
        printf "%s\n" "${results}"
    fi
}

check_single_acl () {
    if printf "%s\n" "${results}" | grep -q ": ${policy}" ; then
        if [ ! -t 2 ] && [ -t 1 ] ; then
            printf "."
        fi
        if [ ! -t 1 ] && [ "${print_stdout}" = "true" ] ; then
            if [ "${stdout_has_started}" -gt 0 ] ; then
                printf "\n"
            fi
            stdout_has_started=1
            if [ -t 2 ] ; then
                stderr_has_started=1
            fi
            printf "test: %s\ndn: \"%s\"\n" "${test_name}" "${test_dn}"
            printf "%s\n" "${results}" | grep "authcDN: "
            printf "%s\n" "${results}" | grep -v "authcDN: "
            printf "policy: %s\n" "${policy}"
            if [ -n "${options}" ] ; then
                printf "options: %s\n" "${options}"
            fi
        fi
    else
        if [ ! -t 2 ] && [ -t 1 ] ; then
            printf "X"
        fi
        if [ "${stderr_has_started}" -gt 0 ] ; then
            printf "\n" 1>&2
        fi
        test_has_errors=1
        stderr_has_started=1
        printf "test: %s\ndn: \"%s\"\n" "${test_name}" "${test_dn}" 1>&2
        printf "%s\n" "${results}" | grep "authcDN: " 1>&2
        printf "%s\n" "${results}" | grep -v "authcDN: " 1>&2
        printf "policy: %s\n" "${policy}" 1>&2
        if [ -n "${options}" ] ; then
            printf "options: %s\n" "${options}" 1>&2
        fi
    fi
}

check_multi_acl () {
    if printf "%s\n" "${results}" | grep -v "authcDN: " | diff -u - <( printf "%s\n" "${test_case}" ) > /dev/null ; then
        if [ ! -t 2 ] ; then
            printf "."
        fi
        if [ ! -t 1 ] && [ "${print_stdout}" = "true" ] ; then
            if [ "${stdout_has_started}" -gt 0 ] ; then
                printf "\n"
            fi
            stdout_has_started=1
            if [ -t 2 ] ; then
                stderr_has_started=1
            fi
            printf "test: %s\ndn: \"%s\"\n" "${test_name}" "${test_dn}"
            printf "%s\n" "${results}"
            if [ -n "${options}" ] ; then
                printf "options: %s\n" "${options}"
            fi
        fi
    else
        if [ ! -t 2 ] ; then
            printf "X"
        fi
        if [ "${stderr_has_started}" -gt 0 ] ; then
            printf "\n" 1>&2
        fi
        test_has_errors=1
        stderr_has_started=1
        printf "test: %s\ndn: \"%s\"\n" "${test_name}" "${test_dn}" 1>&2
        printf "%s\n" "${results}" | grep "authcDN: " 1>&2
        printf "%s\n" "${results}" | grep -v "authcDN: " | diff -u - <( printf "%s\n" "${test_case}" ) | grep -v -E '(\-\-\-|\+\+\+|@@)' 1>&2
        if [ -n "${options}" ] ; then
            printf "options: %s\n" "${options}" 1>&2
        fi
    fi
}

test_has_errors=0
stdout_has_started=0
stderr_has_started=0
print_stdout="${SLAPACL_STDOUT:-true}"

if [ ! -t 2 ] && [ -t 1 ] ; then
    printf "Testing OpenLDAP ACL policies "
fi

{% for element in slapd__slapacl_combined_tests | parse_kv_items(merge_keys=['queries']) %}
{%   if element.name|d() and element.dn|d() and element.state|d('present') not in [ 'absent', 'init', 'ignore' ] %}
{%     if not loop.first %}

{%     endif %}
{%     set check_command = 'print_acl' %}
{%     set slapacl_command = [ 'slapacl', '-b', '"${test_dn}"' ] %}
{%     if element.authdn is defined %}
{%       set _ = slapacl_command.extend([ '-D', '"${test_authdn}"' ]) %}
{%     elif element.uid is defined %}
{%       set _ = slapacl_command.extend([ '-U', '"${test_uid}"' ]) %}
{%     endif %}
{%     if element.authzid is defined %}
{%       set _ = slapacl_command.extend([ '-X', '"${test_authzid}"' ]) %}
{%     endif %}
{%     if (element.dry_run|d())|bool %}
{%       set _ = slapacl_command.extend([ '-u' ]) %}
{%     endif %}
{%     if element.debug|d() %}
{%       set _ = slapacl_command.extend([ '-d', '"${debug}"' ]) %}
{%     endif %}
{%     if element.options|d() %}
{%       set _ = slapacl_command.extend( (element.options | selectattr('state', 'equalto', 'present') | map(attribute='name') | list) | map('regex_replace', '^(.*)$', '-o \\1') | list ) %}
{%     endif %}
{%     if element.queries|d() %}
{%       set check_command = 'check_multi_acl' %}
{%       set _ = slapacl_command.extend( (element.queries | selectattr('state', 'equalto', 'present') | map(attribute='name') | list) | map('regex_replace', '^(.*)$', '"\\1"') | list ) %}
{%     elif element.query|d('entry') and element.policy|d() %}
{%       set check_command = 'check_single_acl' %}
{%       set _ = slapacl_command.extend( [ '"' + element.query|d('entry') + '"' ] ) %}
{%     endif %}
{%     set _ = slapacl_command.extend( [ '2>&1' ] ) %}
{%     if element.comment|d() %}
{{ element.comment | regex_replace('\n$','') | comment(prefix='', postfix='') -}}
{%     endif %}
test_name="{{ element.name }}"
test_dn="{{ element.dn }}"
{%     if element.queries|d() %}
unset policy
test_case="{{ element.queries | selectattr('state', 'equalto', 'present') | selectattr('result', 'defined') | map(attribute='result') | list | join('\n') }}"
{%     elif element.query|d('entry') and element.policy|d() %}
{%       if element.policy in [ 'allow', 'allowed', 'accept', 'grant', 'permit' ] %}
policy="ALLOWED"
{%       elif element.policy in [ 'disallow', 'denied', 'reject', 'revoke', 'deny' ] %}
policy="DENIED"
{%       else %}
policy="{{ element.policy }}"
{%       endif %}
{%     endif %}
{%     if element.debug|d() %}
debug="{{ element.debug }}"
{%     endif %}
{%     if element.options is defined %}
options="{{ (element.options | selectattr('state', 'equalto', 'present') | map(attribute='name') | list) | join(' ') | regex_replace('"','\\"') }}"
{%     else %}
options=""
{%     endif %}
{%     if element.authdn is defined %}
test_authdn="{{ element.authdn }}"
{%     elif element.uid is defined %}
test_uid="{{ element.uid }}"
{%     endif %}
{%     if element.authzid is defined %}
test_authzid="{{ element.authzid }}"
{%     endif %}
results="$({{ slapacl_command | join(' ') }})"
{{ check_command }}
{%   endif %}
{% endfor %}

if [ "${test_has_errors}" -eq 0 ] ; then
    if [ ! -t 2 ] && [ -t 1 ] ; then
        printf "\n"
    fi
else
    if [ ! -t 2 ] && [ -t 1 ] ; then
        printf " done, errors found\n"
    fi
    exit 1
fi
