diff --git a/.github/actions/acme_clients/action.yml b/.github/actions/acme_clients/action.yml index 2b428c24..230527de 100644 --- a/.github/actions/acme_clients/action.yml +++ b/.github/actions/acme_clients/action.yml @@ -1,4 +1,4 @@ -name: "acme_clients" +name: "acme_clients - enroll, renew and revoke certificates" description: "Test if acme.sh, certbot and lego can enroll, renew and certificates" inputs: ACME_SERVER: @@ -36,6 +36,10 @@ inputs: HOSTNAME_SUFFIX: description: "Hostname suffix" required: true + NAME_SPACE: + description: "Namespace" + required: true + default: "acme" runs: using: "composite" @@ -44,8 +48,8 @@ runs: - name: "Create directories" run: | mkdir -p acme-sh/ - mkdir -p certbot/ - mkdir -p lego/ca + sudo mkdir -p certbot/ + sudo mkdir -p lego/ca sudo cp .github/acme2certifier_cabundle.pem certbot/ sudo cp .github/acme2certifier_cabundle.pem lego/ if [ -f cert-2.pem ]; then @@ -65,30 +69,32 @@ runs: time: 5s - name: "Test if http://acme-srv/directory is accessible" - run: docker run -i --rm --network acme curlimages/curl -f http://$ACME_SERVER:$HTTP_PORT/directory + run: docker run -i --rm --network $NAME_SPACE curlimages/curl -f http://$ACME_SERVER:$HTTP_PORT/directory shell: bash env: ACME_SERVER: ${{ inputs.ACME_SERVER }} HTTP_PORT: ${{ inputs.HTTP_PORT }} HTTPS_PORT: ${{ inputs.HTTPS_PORT }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "Test if https://acme-srv/directory is accessible" - run: docker run -i --rm --network acme curlimages/curl --insecure -f https://$ACME_SERVER:$HTTPS_PORT/directory + run: docker run -i --rm --network $NAME_SPACE curlimages/curl --insecure -f https://$ACME_SERVER:$HTTPS_PORT/directory shell: bash env: ACME_SERVER: ${{ inputs.ACME_SERVER }} HTTP_PORT: ${{ inputs.HTTP_PORT }} HTTPS_PORT: ${{ inputs.HTTPS_PORT }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - - name: "HTTPS - Enroll lego" + - name: "HTTP - Enroll lego" run: | - echo "##### HTTPS - Enroll lego #####" + echo "##### HTTP - Enroll lego #####" if [ "$USE_RSA" == "false" ]; then echo "use ECC" - docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network acme goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.acme --tls run + docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.$NAME_SPACE --tls run else echo "use RSA" - docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network acme goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" --key-type=rsa2048 -d lego$HOSTNAME_SUFFIX.acme --tls run + docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" --key-type=rsa2048 -d lego$HOSTNAME_SUFFIX.$NAME_SPACE --tls run fi shell: bash env: @@ -97,27 +103,41 @@ runs: HTTPS_PORT: ${{ inputs.HTTPS_PORT }} USE_RSA: ${{ inputs.USE_RSA }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} + + - name: "HTTP - Revoke lego" + if: ${{ inputs.REVOCATION == 'true' }} + run: | + echo "#### HTTP - Revoke lego" + docker run -i -v $PWD/lego:/.lego/ --rm --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.$NAME_SPACE revoke + shell: bash + env: + ACME_SERVER: ${{ inputs.ACME_SERVER }} + HTTP_PORT: ${{ inputs.HTTP_PORT }} + HTTPS_PORT: ${{ inputs.HTTPS_PORT }} + HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTPS - Enroll acme.sh" run: | echo "##### HTTPS - Enroll acme.sh #####" if [ "$USE_RSA" == "false" ]; then echo "use ECC" - docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --issue --server https://$ACME_SERVER:$HTTPS_PORT --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.acme --alpn --standalone --debug 1 --output-insecure --insecure + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network $NAME_SPACE --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --issue --server https://$ACME_SERVER:$HTTPS_PORT --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE --alpn --standalone --debug 1 --output-insecure --insecure ECC="_ecc" else echo "use RSA" - docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --issue --server https://$ACME_SERVER:$HTTPS_PORT --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.acme --alpn --standalone --keylength 2048 --debug 1 --output-insecure --insecure + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network $NAME_SPACE --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --issue --server https://$ACME_SERVER:$HTTPS_PORT --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE --alpn --standalone --keylength 2048 --debug 1 --output-insecure --insecure fi - awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert-" c ".pem"}' < acme-sh/acme-sh$HOSTNAME_SUFFIX.acme${ECC}/ca.cer + awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert-" c ".pem"}' < acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/ca.cer if [ "$VERIFY_CERT" == "true" ]; then if [ -f cert-2.pem ]; then echo "Multiple CA certs" - openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.acme${ECC}/acme-sh$HOSTNAME_SUFFIX.acme.cer + openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE.cer else echo "Single Root ca" - openssl verify -CAfile cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.acme${ECC}/acme-sh$HOSTNAME_SUFFIX.acme.cer + openssl verify -CAfile cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE.cer fi fi shell: bash @@ -128,6 +148,7 @@ runs: HTTPS_PORT: ${{ inputs.HTTPS_PORT }} USE_RSA: ${{ inputs.USE_RSA }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTPS - Renew acme.sh" if: ${{ inputs.RENEWAL == 'true' }} @@ -139,15 +160,15 @@ runs: else echo "use RSA" fi - docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --renew --server https://$ACME_SERVER:$HTTPS_PORT --force --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.acme --alpn --standalone --debug 1 --output-insecure --insecure - awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert-" c ".pem"}' < acme-sh/acme-sh$HOSTNAME_SUFFIX.acme${ECC}/ca.cer + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network $NAME_SPACE --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --renew --server https://$ACME_SERVER:$HTTPS_PORT --force --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE --alpn --standalone --debug 1 --output-insecure --insecure + awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert-" c ".pem"}' < acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/ca.cer if [ "$VERIFY_CERT" == "true" ]; then if [ -f cert-2.pem ]; then echo "Multiple CA certs" - openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.acme${ECC}/acme-sh$HOSTNAME_SUFFIX.acme.cer + openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE.cer else echo "Single Root ca" - openssl verify -CAfile cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.acme${ECC}/acme-sh$HOSTNAME_SUFFIX.acme.cer + openssl verify -CAfile cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE.cer fi fi shell: bash @@ -158,29 +179,32 @@ runs: HTTPS_PORT: ${{ inputs.HTTPS_PORT }} USE_RSA: ${{ inputs.USE_RSA }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTPS - Revoke HTTP-01 single domain acme.sh" if: ${{ inputs.REVOCATION == 'true' }} run: | echo "##### HTTPS - Revoke HTTP-01 single domain acme.sh #####" - docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --name acme-sh$HOSTNAME_SUFFIX --network acme neilpang/acme.sh:latest --revoke --server https://$ACME_SERVER:$HTTPS_PORT --revoke -d acme-sh$HOSTNAME_SUFFIX.acme --standalone --debug 2 --output-insecure --insecure + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --name acme-sh$HOSTNAME_SUFFIX --network $NAME_SPACE neilpang/acme.sh:latest --revoke --server https://$ACME_SERVER:$HTTPS_PORT --revoke -d acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE --standalone --debug 2 --output-insecure --insecure shell: bash env: ACME_SERVER: ${{ inputs.ACME_SERVER }} HTTP_PORT: ${{ inputs.HTTP_PORT }} HTTPS_PORT: ${{ inputs.HTTPS_PORT }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTPS - Decativate acme.sh #####" run: | echo "##### HTTPS - Decativate acme.sh" - docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --name acme-sh$HOSTNAME_SUFFIX --network acme neilpang/acme.sh:latest --deactivate-account --server https://$ACME_SERVER:$HTTPS_PORT --debug 2 --output-insecure --insecure + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --name acme-sh$HOSTNAME_SUFFIX --network $NAME_SPACE neilpang/acme.sh:latest --deactivate-account --server https://$ACME_SERVER:$HTTPS_PORT --debug 2 --output-insecure --insecure shell: bash env: ACME_SERVER: ${{ inputs.ACME_SERVER }} HTTP_PORT: ${{ inputs.HTTP_PORT }} HTTPS_PORT: ${{ inputs.HTTPS_PORT }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTP - Enroll acme.sh" run: | @@ -188,19 +212,19 @@ runs: sudo rm -rf acme-sh/* if [ "$USE_RSA" == "false" ]; then echo "use ECC" - docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --issue --server http://$ACME_SERVER:$HTTP_PORT --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.acme --standalone --debug 1 --output-insecure --insecure + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network $NAME_SPACE --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --issue --server http://$ACME_SERVER:$HTTP_PORT --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE --standalone --debug 1 --output-insecure --insecure ECC="_ecc" else echo "use RSA" - docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --issue --server http://$ACME_SERVER:$HTTP_PORT --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.acme --standalone --keylength 2048 --debug 1 --output-insecure --insecure + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network $NAME_SPACE --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --issue --server http://$ACME_SERVER:$HTTP_PORT --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE --standalone --keylength 2048 --debug 1 --output-insecure --insecure fi - awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert-" c ".pem"}' < acme-sh/acme-sh$HOSTNAME_SUFFIX.acme${ECC}/ca.cer + awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert-" c ".pem"}' < acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/ca.cer if [ "$VERIFY_CERT" == "true" ]; then if [ -f cert-2.pem ]; then - openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.acme${ECC}/acme-sh$HOSTNAME_SUFFIX.acme.cer + openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE.cer else echo "single root ca" - openssl verify -CAfile cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.acme${ECC}/acme-sh$HOSTNAME_SUFFIX.acme.cer + openssl verify -CAfile cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE.cer fi fi shell: bash @@ -211,6 +235,7 @@ runs: HTTPS_PORT: ${{ inputs.HTTPS_PORT }} USE_RSA: ${{ inputs.USE_RSA }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTP - Renew acme.sh" if: ${{ inputs.RENEWAL == 'true' }} @@ -222,14 +247,14 @@ runs: else echo "use RSA" fi - docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --renew --server http://$ACME_SERVER:$HTTP_PORT --force --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.acme --standalone --debug 1 --output-insecure --insecure - awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert-" c ".pem"}' < acme-sh/acme-sh$HOSTNAME_SUFFIX.acme${ECC}/ca.cer + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network $NAME_SPACE --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --renew --server http://$ACME_SERVER:$HTTP_PORT --force --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE --standalone --debug 1 --output-insecure --insecure + awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert-" c ".pem"}' < acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/ca.cer if [ "$VERIFY_CERT" == "true" ]; then if [ -f cert-2.pem ]; then - openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.acme${ECC}/acme-sh$HOSTNAME_SUFFIX.acme.cer + openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE.cer else echo "single root ca" - openssl verify -CAfile cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.acme${ECC}/acme-sh$HOSTNAME_SUFFIX.acme.cer + openssl verify -CAfile cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE.cer fi fi shell: bash @@ -240,38 +265,41 @@ runs: HTTPS_PORT: ${{ inputs.HTTPS_PORT }} USE_RSA: ${{ inputs.USE_RSA }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTP - Revoke HTTP-01 single domain acme.sh" if: ${{ inputs.REVOCATION == 'true' }} run: | echo "##### HTTP - Revoke HTTP-01 single domain acme.sh #####" - docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --name acme-sh$HOSTNAME_SUFFIX --network acme neilpang/acme.sh:latest --revoke --server http://$ACME_SERVER:$HTTP_PORT --revoke -d acme-sh$HOSTNAME_SUFFIX.acme --standalone --debug 2 --output-insecure --insecure + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --name acme-sh$HOSTNAME_SUFFIX --network $NAME_SPACE neilpang/acme.sh:latest --revoke --server http://$ACME_SERVER:$HTTP_PORT --revoke -d acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE --standalone --debug 2 --output-insecure --insecure shell: bash env: ACME_SERVER: ${{ inputs.ACME_SERVER }} HTTP_PORT: ${{ inputs.HTTP_PORT }} HTTPS_PORT: ${{ inputs.HTTPS_PORT }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTP - Decativate acme.sh" run: | echo "##### HTTP - Decativate acme.sh #####" - docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --name acme-sh$HOSTNAME_SUFFIX --network acme neilpang/acme.sh:latest --deactivate-account --server http://$ACME_SERVER:$HTTP_PORT --debug 2 --output-insecure --insecure + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --name acme-sh$HOSTNAME_SUFFIX --network $NAME_SPACE neilpang/acme.sh:latest --deactivate-account --server http://$ACME_SERVER:$HTTP_PORT --debug 2 --output-insecure --insecure shell: bash env: ACME_SERVER: ${{ inputs.ACME_SERVER }} HTTP_PORT: ${{ inputs.HTTP_PORT }} HTTPS_PORT: ${{ inputs.HTTPS_PORT }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTPS - Enroll certbot" if: ${{ inputs.USE_CERTBOT == 'true' }} run: | echo "##### HTTPS - Enroll certbot #####" if [ "$USE_RSA" == "false" ]; then - docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network acme -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot certonly --server https://$ACME_SERVER:$HTTPS_PORT --standalone --preferred-challenges http --no-verify-ssl --agree-tos -m 'certbot@example.com' -d certbot$HOSTNAME_SUFFIX.acme --cert-name certbot --issuance-timeout 120 + docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network $NAME_SPACE -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot certonly --server https://$ACME_SERVER:$HTTPS_PORT --standalone --preferred-challenges http --no-verify-ssl --agree-tos -m 'certbot@example.com' -d certbot$HOSTNAME_SUFFIX.$NAME_SPACE --cert-name certbot --issuance-timeout 120 else - docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network acme -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot certonly --server https://$ACME_SERVER:$HTTPS_PORT --standalone --preferred-challenges http --no-verify-ssl --agree-tos -m 'certbot@example.com' --key-type rsa -d certbot$HOSTNAME_SUFFIX.acme --cert-name certbot --issuance-timeout 120 + docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network $NAME_SPACE -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot certonly --server https://$ACME_SERVER:$HTTPS_PORT --standalone --preferred-challenges http --no-verify-ssl --agree-tos -m 'certbot@example.com' --key-type rsa -d certbot$HOSTNAME_SUFFIX.$NAME_SPACE --cert-name certbot --issuance-timeout 120 fi if [ "$VERIFY_CERT" == "true" ]; then @@ -289,27 +317,29 @@ runs: HTTPS_PORT: ${{ inputs.HTTPS_PORT }} USE_RSA: ${{ inputs.USE_RSA }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTPS - Revoke certbot" if: ${{ (inputs.USE_CERTBOT == 'true') && (inputs.REVOCATION == 'true') }} run: | echo "##### HTTPS - Revoke certbot #####" - docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network acme -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot revoke --server https://$ACME_SERVER:$HTTPS_PORT --no-verify-ssl --delete-after-revoke --cert-name certbot + docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network $NAME_SPACE -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot revoke --server https://$ACME_SERVER:$HTTPS_PORT --no-verify-ssl --delete-after-revoke --cert-name certbot shell: bash env: ACME_SERVER: ${{ inputs.ACME_SERVER }} HTTP_PORT: ${{ inputs.HTTP_PORT }} HTTPS_PORT: ${{ inputs.HTTPS_PORT }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTP - Enroll certbot #####" if: ${{ inputs.USE_CERTBOT == 'true' }} run: | - echo "##### HTTPS - Enroll certbot #####" + echo "##### HTTP - Enroll certbot #####" if [ "$USE_RSA" == "false" ]; then - docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network acme -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot certonly --server http://$ACME_SERVER:$HTTP_PORT --standalone --preferred-challenges http --agree-tos -m 'certbot@example.com' -d certbot$HOSTNAME_SUFFIX.acme --cert-name certbot --issuance-timeout 120 + docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network $NAME_SPACE -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot certonly --server http://$ACME_SERVER:$HTTP_PORT --standalone --preferred-challenges http --agree-tos -m 'certbot@example.com' -d certbot$HOSTNAME_SUFFIX.$NAME_SPACE --cert-name certbot --issuance-timeout 120 else - docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network acme -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot certonly --server http://$ACME_SERVER:$HTTP_PORT --standalone --preferred-challenges http --agree-tos -m 'certbot@example.com' --key-type rsa -d certbot$HOSTNAME_SUFFIX.acme --cert-name certbot --issuance-timeout 120 + docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network $NAME_SPACE -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot certonly --server http://$ACME_SERVER:$HTTP_PORT --standalone --preferred-challenges http --agree-tos -m 'certbot@example.com' --key-type rsa -d certbot$HOSTNAME_SUFFIX.$NAME_SPACE --cert-name certbot --issuance-timeout 120 fi if [ "$VERIFY_CERT" == "true" ]; then @@ -327,36 +357,38 @@ runs: HTTP_PORT: ${{ inputs.HTTP_PORT }} HTTPS_PORT: ${{ inputs.HTTPS_PORT }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTP - Revoke certbot" if: ${{ (inputs.USE_CERTBOT == 'true') && (inputs.REVOCATION == 'true') }} run: | echo "##### HTTP - Revoke certbot #####" - docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network acme -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot revoke --server http://$ACME_SERVER:$HTTP_PORT --delete-after-revoke --cert-name certbot + docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network $NAME_SPACE -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot revoke --server http://$ACME_SERVER:$HTTP_PORT --delete-after-revoke --cert-name certbot shell: bash env: ACME_SERVER: ${{ inputs.ACME_SERVER }} HTTP_PORT: ${{ inputs.HTTP_PORT }} HTTPS_PORT: ${{ inputs.HTTPS_PORT }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTPS - Enroll lego" run: | echo "##### HTTPS - Enroll lego #####" if [ "$USE_RSA" == "false" ]; then echo "use ECC" - docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network acme goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.acme --tls run + docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s https://$ACME_SERVER:$HTTPS_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.$NAME_SPACE --tls run else echo "use RSA" - docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network acme goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" --key-type=rsa2048 -d lego$HOSTNAME_SUFFIX.acme --tls run + docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s https://$ACME_SERVER:$HTTPS_PORT -a --email "lego@example.com" --key-type=rsa2048 -d lego$HOSTNAME_SUFFIX.$NAME_SPACE --tls run fi if [ "$VERIFY_CERT" == "true" ]; then if [ -f cert-2.pem ]; then - sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego$HOSTNAME_SUFFIX.acme.crt + sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego$HOSTNAME_SUFFIX.$NAME_SPACE.crt else echo "single root ca" - sudo openssl verify -CAfile cert-1.pem lego/certificates/lego$HOSTNAME_SUFFIX.acme.crt + sudo openssl verify -CAfile cert-1.pem lego/certificates/lego$HOSTNAME_SUFFIX.$NAME_SPACE.crt fi fi shell: bash @@ -367,18 +399,20 @@ runs: HTTPS_PORT: ${{ inputs.HTTPS_PORT }} USE_RSA: ${{ inputs.USE_RSA }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTPS - Revoke lego" if: ${{ inputs.REVOCATION == 'true' }} run: | echo "##### HTTPS - Revoke lego #####" - # docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network acme goacme/lego -s https://$ACME_SERVER:$HTTPS_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.acme revoke + docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s https://$ACME_SERVER:$HTTPS_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.$NAME_SPACE revoke shell: bash env: ACME_SERVER: ${{ inputs.ACME_SERVER }} HTTP_PORT: ${{ inputs.HTTP_PORT }} HTTPS_PORT: ${{ inputs.HTTPS_PORT }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTP - Enroll lego" run: | @@ -386,17 +420,17 @@ runs: sudo rm -rf lego/* if [ "$USE_RSA" == "false" ]; then echo "use ECC" - docker run -i -v $PWD/lego:/.lego/ --rm --name lego$HOSTNAME_SUFFIX --network acme goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.acme --http run + docker run -i -v $PWD/lego:/.lego/ --rm --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.$NAME_SPACE --http run else echo "use RSA" - docker run -i -v $PWD/lego:/.lego/ --rm --name lego$HOSTNAME_SUFFIX --network acme goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" --key-type=rsa2048 -d lego$HOSTNAME_SUFFIX.acme --http run + docker run -i -v $PWD/lego:/.lego/ --rm --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" --key-type=rsa2048 -d lego$HOSTNAME_SUFFIX.$NAME_SPACE --http run fi if [ "$VERIFY_CERT" == "true" ]; then if [ -f cert-2.pem ]; then - sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego$HOSTNAME_SUFFIX.acme.crt + sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego$HOSTNAME_SUFFIX.$NAME_SPACE.crt else echo "single root ca" - sudo openssl verify -CAfile cert-1.pem lego/certificates/lego$HOSTNAME_SUFFIX.acme.crt + sudo openssl verify -CAfile cert-1.pem lego/certificates/lego$HOSTNAME_SUFFIX.$NAME_SPACE.crt fi fi shell: bash @@ -407,18 +441,20 @@ runs: HTTPS_PORT: ${{ inputs.HTTPS_PORT }} USE_RSA: ${{ inputs.USE_RSA }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "HTTP - Revoke lego" if: ${{ inputs.REVOCATION == 'true' }} run: | echo "#### HTTP - Revoke lego" - docker run -i -v $PWD/lego:/.lego/ --rm --name lego$HOSTNAME_SUFFIX --network acme goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.acme revoke + docker run -i -v $PWD/lego:/.lego/ --rm --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.$NAME_SPACE revoke shell: bash env: ACME_SERVER: ${{ inputs.ACME_SERVER }} HTTP_PORT: ${{ inputs.HTTP_PORT }} HTTPS_PORT: ${{ inputs.HTTPS_PORT }} HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} - name: "Delete acme-sh, letsencypt and lego folders" run: | diff --git a/.github/actions/deb_build/action.yml b/.github/actions/deb_build/action.yml index 244bf093..cb41df40 100644 --- a/.github/actions/deb_build/action.yml +++ b/.github/actions/deb_build/action.yml @@ -28,13 +28,13 @@ runs: Pin: origin packages.mozilla.org Pin-Priority: 1000 ' | sudo tee /etc/apt/preferences.d/mozilla - sudo apt update && sudo apt install firefox + sudo apt update && sudo apt install -y firefox --allow-downgrades shell: bash - name: "Prepare environment to build deb package" run: | sudo apt-get update && sudo apt-get -y upgrade - sudo apt-get -y install build-essential fakeroot dpkg-dev devscripts debhelper + sudo apt-get -y install build-essential fakeroot dpkg-dev devscripts debhelper --allow-downgrades rm setup.py rm -f examples/ngnix/acme2certifier.te rm -f examples/nginx/supervisord.conf diff --git a/.github/actions/wf_specific/digicert_ca_handler/enroll_eab/action.yml b/.github/actions/wf_specific/digicert_ca_handler/enroll_eab/action.yml new file mode 100644 index 00000000..cc9e027c --- /dev/null +++ b/.github/actions/wf_specific/digicert_ca_handler/enroll_eab/action.yml @@ -0,0 +1,98 @@ +name: "enroll_eab" +description: "enroll_eab" + +runs: + using: "composite" + steps: + - name: "Sleep for 5s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 5s + + - name: "EAB - Test http://acme-srv/directory is accessible" + run: docker run -i --rm --network acme.dynamop.de curlimages/curl -f http://acme-srv/directory + shell: bash + + - name: "EAB - Test if https://acme-srv/directory is accessible" + run: docker run -i --rm --network acme.dynamop.de curlimages/curl --insecure -f https://acme-srv/directory + shell: bash + + - name: "EAB - 01 - Enroll lego with a template_name taken from list in kid.json" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme.dynamop.de goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw -d lego.acme.dynamop.de --http run + sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego.acme.dynamop.de.crt + sudo openssl x509 -in lego/certificates/lego.acme.dynamop.de.crt -text -noout + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme.dynamop.de goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw -d lego.acme.dynamop.de revoke + shell: bash + + - name: "EAB - 02a - Enroll lego with a template_name taken from header_info NOT included in kid.json (to fail)" + id: legofail01 + continue-on-error: true + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme.dynamop.de goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --user-agent cert_type=unknown -d lego.acme.dynamop.de --http run + shell: bash + + - name: "EAB - 02a - check result " + if: steps.legofail01.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail01.outcome }}" + exit 1 + shell: bash + + - name: "EAB - 02b - Enroll lego with a template_name taken from header_info included in kid.json" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme.dynamop.de goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --user-agent cert_type=ssl_securesite_pro -d lego.acme.dynamop.de --http run + sudo openssl x509 -in lego/certificates/lego.acme.dynamop.de.crt -ext extendedKeyUsage -noout + sudo openssl x509 -in lego/certificates/lego.acme.dynamop.de.crt -issuer --noout + sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego.acme.dynamop.de.crt + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme.dynamop.de goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw -d lego.acme.dynamop.de revoke + shell: bash + + - name: "EAB - 03 - Enroll lego with a template_name/ca_name taken from kid.json" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme.dynamop.de goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_01 --hmac YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg -d lego.acme.dynamop.de --http run + sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego.acme.dynamop.de.crt + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme.dynamop.de goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw -d lego.acme.dynamop.de revoke + shell: bash + + - name: "EAB - 04 - Enroll lego with a not allowed fqdn in kid.json (to fail)" + id: legofail02 + continue-on-error: true + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme.dynamop.de goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_02 --hmac dGhpc19pc19hX3ZlcnlfbG9uZ19obWFjX3RvX21ha2Vfc3VyZV90aGF0X2l0c19tb3JlX3RoYW5fMjU2X2JpdHM -d lego.acme1.dynamop.de --http run + shell: bash + + - name: "EAB - 04a - check result " + if: steps.legofail02.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail02.outcome }}" + exit 1 + shell: bash + + - name: "EAB - 05 - Enroll lego with default values from acme.cfg" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme.dynamop.de goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_03 --hmac YW5kX2ZpbmFsbHlfdGhlX2xhc3RfaG1hY19rZXlfd2hpY2hfaXNfbG9uZ2VyX3RoYW5fMjU2X2JpdHNfYW5kX3Nob3VsZF93b3Jr -d lego.acme.dynamop.de --http run + sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego.acme.dynamop.de.crt + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme.dynamop.de goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw -d lego.acme.dynamop.de revoke + shell: bash + + - name: "EAB - 06 - Enroll lego with not allowed headerinfo-field (should fail)" + id: legofail03 + continue-on-error: true + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme.dynamop.de goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_02 --hmac dGhpc19pc19hX3ZlcnlfbG9uZ19obWFjX3RvX21ha2Vfc3VyZV90aGF0X2l0c19tb3JlX3RoYW5fMjU2X2JpdHM --user-agent cert_type=ssl_securesite_pro -d lego.acme.dynamop.de --http run + shell: bash + + - name: "EAB - 06 - check result " + if: steps.legofail03.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail03.outcome }}" + exit 1 + shell: bash \ No newline at end of file diff --git a/.github/actions/wf_specific/entrust_ca_handler/enroll/action.yml b/.github/actions/wf_specific/entrust_ca_handler/enroll/action.yml new file mode 100644 index 00000000..697565b0 --- /dev/null +++ b/.github/actions/wf_specific/entrust_ca_handler/enroll/action.yml @@ -0,0 +1,237 @@ +name: "acme_clients - enroll, renew and revoke certificates" +description: "Test if acme.sh, certbot and lego can enroll, renew and certificates" +inputs: + ACME_SERVER: + description: "ACME server URL" + required: true + default: "acme-srv" + REVOCATION: + description: "Revocation method" + required: true + default: "true" + USE_RSA: + description: "Use RSA" + required: true + default: "false" + HTTP_PORT: + description: "HTTP port" + required: true + default: "80" + HTTPS_PORT: + description: "HTTPS port" + required: true + default: "443" + HOSTNAME_SUFFIX: + description: "Hostname suffix" + required: true + NAME_SPACE: + description: "Namespace" + required: true + default: "acme" + +runs: + using: "composite" + steps: + + - name: "Create directories" + run: | + sudo mkdir -p certbot/ + sudo mkdir -p lego/ca + sudo cp .github/acme2certifier_cabundle.pem certbot/ + sudo cp .github/acme2certifier_cabundle.pem lego/ + if [ -f cert-2.pem ]; then + echo "delete cert-2.pem" + rm -f cert-2.pem + fi + if [ -f cert-1.pem ]; then + echo "delete cert-1.pem" + rm -f cert-1.pem + fi + ls -la + shell: bash + + - name: "Sleep for 5s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 5s + + - name: "Test if http://acme-srv/directory is accessible" + run: docker run -i --rm --network $NAME_SPACE curlimages/curl -f http://$ACME_SERVER:$HTTP_PORT/directory + shell: bash + env: + ACME_SERVER: ${{ inputs.ACME_SERVER }} + HTTP_PORT: ${{ inputs.HTTP_PORT }} + HTTPS_PORT: ${{ inputs.HTTPS_PORT }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} + + - name: "Test if https://acme-srv/directory is accessible" + run: docker run -i --rm --network $NAME_SPACE curlimages/curl --insecure -f https://$ACME_SERVER:$HTTPS_PORT/directory + shell: bash + env: + ACME_SERVER: ${{ inputs.ACME_SERVER }} + HTTP_PORT: ${{ inputs.HTTP_PORT }} + HTTPS_PORT: ${{ inputs.HTTPS_PORT }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} + + - name: "HTTP - Enroll lego" + run: | + echo "##### HTTP - Enroll lego #####" + if [ "$USE_RSA" == "false" ]; then + echo "use ECC" + docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.$NAME_SPACE --tls run + else + echo "use RSA" + docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" --key-type=rsa2048 -d lego$HOSTNAME_SUFFIX.$NAME_SPACE --tls run + fi + shell: bash + env: + ACME_SERVER: ${{ inputs.ACME_SERVER }} + HTTP_PORT: ${{ inputs.HTTP_PORT }} + HTTPS_PORT: ${{ inputs.HTTPS_PORT }} + USE_RSA: ${{ inputs.USE_RSA }} + HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} + + - name: "HTTP - Revoke lego" + if: ${{ inputs.REVOCATION == 'true' }} + run: | + echo "#### HTTP - Revoke lego" + docker run -i -v $PWD/lego:/.lego/ --rm --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.$NAME_SPACE revoke + shell: bash + env: + ACME_SERVER: ${{ inputs.ACME_SERVER }} + HTTP_PORT: ${{ inputs.HTTP_PORT }} + HTTPS_PORT: ${{ inputs.HTTPS_PORT }} + HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} + + - name: "HTTPS - Enroll acme.sh" + run: | + echo "##### HTTPS - Enroll acme.sh #####" + if [ "$USE_RSA" == "false" ]; then + echo "use ECC" + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network $NAME_SPACE --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --issue --server https://$ACME_SERVER:$HTTPS_PORT --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE --alpn --standalone --debug 1 --output-insecure --insecure + ECC="_ecc" + else + echo "use RSA" + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network $NAME_SPACE --name acme-sh$HOSTNAME_SUFFIX neilpang/acme.sh:latest --issue --server https://$ACME_SERVER:$HTTPS_PORT --accountemail 'acme-sh@example.com' -d acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE --alpn --standalone --keylength 2048 --debug 1 --output-insecure --insecure + fi + + awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert-" c ".pem"}' < acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/ca.cer + if [ "$VERIFY_CERT" == "true" ]; then + if [ -f cert-2.pem ]; then + echo "Multiple CA certs" + openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE.cer + else + echo "Single Root ca" + openssl verify -CAfile cert-1.pem acme-sh/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE${ECC}/acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE.cer + fi + fi + shell: bash + env: + VERIFY_CERT: ${{ inputs.VERIFY_CERT }} + ACME_SERVER: ${{ inputs.ACME_SERVER }} + HTTP_PORT: ${{ inputs.HTTP_PORT }} + HTTPS_PORT: ${{ inputs.HTTPS_PORT }} + USE_RSA: ${{ inputs.USE_RSA }} + HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} + + - name: "HTTPS - Revoke HTTP-01 single domain acme.sh" + if: ${{ inputs.REVOCATION == 'true' }} + run: | + echo "##### HTTPS - Revoke HTTP-01 single domain acme.sh #####" + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --name acme-sh$HOSTNAME_SUFFIX --network $NAME_SPACE neilpang/acme.sh:latest --revoke --server https://$ACME_SERVER:$HTTPS_PORT --revoke -d acme-sh$HOSTNAME_SUFFIX.$NAME_SPACE --standalone --debug 2 --output-insecure --insecure + shell: bash + env: + ACME_SERVER: ${{ inputs.ACME_SERVER }} + HTTP_PORT: ${{ inputs.HTTP_PORT }} + HTTPS_PORT: ${{ inputs.HTTPS_PORT }} + HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} + + - name: "HTTPS - Decativate acme.sh #####" + run: | + echo "##### HTTPS - Decativate acme.sh" + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --name acme-sh$HOSTNAME_SUFFIX --network $NAME_SPACE neilpang/acme.sh:latest --deactivate-account --server https://$ACME_SERVER:$HTTPS_PORT --debug 2 --output-insecure --insecure + shell: bash + env: + ACME_SERVER: ${{ inputs.ACME_SERVER }} + HTTP_PORT: ${{ inputs.HTTP_PORT }} + HTTPS_PORT: ${{ inputs.HTTPS_PORT }} + HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} + + - name: "HTTPS - Enroll certbot" + run: | + echo "##### HTTPS - Enroll certbot #####" + if [ "$USE_RSA" == "false" ]; then + docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network $NAME_SPACE -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot certonly --server https://$ACME_SERVER:$HTTPS_PORT --standalone --preferred-challenges http --no-verify-ssl --agree-tos -m 'certbot@example.com' -d certbot$HOSTNAME_SUFFIX.$NAME_SPACE --cert-name certbot --issuance-timeout 120 + else + docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network $NAME_SPACE -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot certonly --server https://$ACME_SERVER:$HTTPS_PORT --standalone --preferred-challenges http --no-verify-ssl --agree-tos -m 'certbot@example.com' --key-type rsa -d certbot$HOSTNAME_SUFFIX.$NAME_SPACE --cert-name certbot --issuance-timeout 120 + fi + + if [ "$VERIFY_CERT" == "true" ]; then + if [ -f cert-2.pem ]; then + sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem certbot/live/certbot/cert.pem + else + echo "single root ca" + sudo openssl verify -CAfile cert-1.pem certbot/live/certbot/cert.pem + fi + fi + shell: bash + env: + VERIFY_CERT: ${{ inputs.VERIFY_CERT }} + ACME_SERVER: ${{ inputs.ACME_SERVER }} + HTTPS_PORT: ${{ inputs.HTTPS_PORT }} + USE_RSA: ${{ inputs.USE_RSA }} + HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} + + - name: "HTTPS - Revoke certbot" + if: ${{ inputs.REVOCATION == 'true' }} + run: | + echo "##### HTTPS - Revoke certbot #####" + docker run -i --rm --name certbot$HOSTNAME_SUFFIX --network $NAME_SPACE -v $PWD/certbot:/etc/letsencrypt/ certbot/certbot revoke --server https://$ACME_SERVER:$HTTPS_PORT --no-verify-ssl --delete-after-revoke --cert-name certbot + shell: bash + env: + ACME_SERVER: ${{ inputs.ACME_SERVER }} + HTTP_PORT: ${{ inputs.HTTP_PORT }} + HTTPS_PORT: ${{ inputs.HTTPS_PORT }} + HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} + + - name: "HTTP - Enroll lego with wrong domain - should fail" + id: legofail01 + continue-on-error: true + run: | + echo "##### HTTP - Enroll lego #####" + if [ "$USE_RSA" == "false" ]; then + echo "use ECC" + docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" -d lego$HOSTNAME_SUFFIX.acme --tls run + else + echo "use RSA" + docker run -i --rm -e LEGO_CA_CERTIFICATES=.lego/acme2certifier_cabundle.pem -v $PWD/lego:/.lego/ --name lego$HOSTNAME_SUFFIX --network $NAME_SPACE goacme/lego -s http://$ACME_SERVER:$HTTP_PORT -a --email "lego@example.com" --key-type=rsa2048 -d lego$HOSTNAME_SUFFIX.acme --tls run + fi + shell: bash + env: + ACME_SERVER: ${{ inputs.ACME_SERVER }} + HTTP_PORT: ${{ inputs.HTTP_PORT }} + HTTPS_PORT: ${{ inputs.HTTPS_PORT }} + USE_RSA: ${{ inputs.USE_RSA }} + HOSTNAME_SUFFIX: ${{ inputs.HOSTNAME_SUFFIX }} + NAME_SPACE: ${{ inputs.NAME_SPACE }} + + - name: "Check result " + if: steps.legofail01.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail01.outcome }}" + exit 1 + shell: bash + + - name: "Delete acme-sh, letsencypt and lego folders" + run: | + sudo rm -rf lego/* + sudo rm -rf acme-sh/* + sudo rm -rf certbot/* + shell: bash \ No newline at end of file diff --git a/.github/actions/wf_specific/entrust_ca_handler/enroll_eab/action.yml b/.github/actions/wf_specific/entrust_ca_handler/enroll_eab/action.yml new file mode 100644 index 00000000..1ea5936b --- /dev/null +++ b/.github/actions/wf_specific/entrust_ca_handler/enroll_eab/action.yml @@ -0,0 +1,41 @@ +name: "enroll_eab" +description: "enroll_eab" + +runs: + using: "composite" + steps: + - name: "Sleep for 5s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 5s + + - name: "EAB - Test http://acme-srv/directory is accessible" + run: docker run -i --rm --network rm-rf.ninja curlimages/curl -f http://acme-srv/directory + shell: bash + + - name: "EAB - Test if https://acme-srv/directory is accessible" + run: docker run -i --rm --network rm-rf.ninja curlimages/curl --insecure -f https://acme-srv/directory + shell: bash + + - name: "EAB - 01 - Enroll lego with a template_name taken from list in kid.json" + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network rm-rf.ninja goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw -d lego.rm-rf.ninja --http run + sudo docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network rm-rf.ninja goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw -d lego.rm-rf.ninja revoke + shell: bash + + - name: "EAB - 02 - Enroll lego with a not allowed fqdn in kid.json (to fail)" + id: legofail01 + continue-on-error: true + run: | + sudo rm -rf lego/* + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network rm-rf.ninja goacme/lego -s http://acme-srv -a --email "lego@example.com" --key-type=rsa2048 --eab --kid keyid_02 --hmac dGhpc19pc19hX3ZlcnlfbG9uZ19obWFjX3RvX21ha2Vfc3VyZV90aGF0X2l0c19tb3JlX3RoYW5fMjU2X2JpdHM -d lego.rm-rf.ninja --http run + shell: bash + + - name: "EAB - 04a - check result " + if: steps.legofail01.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail01.outcome }}" + exit 1 + shell: bash + diff --git a/.github/actions/wf_specific/xca_ca_handler/enroll_eab_sp/action.yml b/.github/actions/wf_specific/xca_ca_handler/enroll_eab_sp/action.yml new file mode 100644 index 00000000..9b97905d --- /dev/null +++ b/.github/actions/wf_specific/xca_ca_handler/enroll_eab_sp/action.yml @@ -0,0 +1,362 @@ +name: "enroll_eab" +description: "enroll_eab" +inputs: + DEPLOYMENT_TYPE: + description: "Deployment type" + required: true + default: "container" + + +runs: + using: "composite" + steps: + - name: "EAB - Sleep for 10s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 10s + + - name: "EAB - Test http://acme-srv/directory is accessible" + run: docker run -i --rm --network acme curlimages/curl -f http://acme-srv/directory + shell: bash + + - name: "EAB - Test if https://acme-srv/directory is accessible" + run: docker run -i --rm --network acme curlimages/curl --insecure -f https://acme-srv/directory + shell: bash + + - name: "EAB SP - 01a - SUCC - Enroll acme - 1st list entry" + run: | + mkdir -p acme-sh + sudo rm -rf acme-sh/* + openssl genrsa -out acme-sh/acme-sh.acme.key 2048 + openssl req -new -key acme-sh/acme-sh.acme.key -subj '/CN=acme-sh.acme/O=acme corp/OU=acme1/C=AC/serialNumber=00-11-22-33' --addext "subjectAltName = DNS:acme-sh.acme" -outform pem -out acme-sh/acme-sh.acme.csr + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name=acme-sh neilpang/acme.sh:latest --register-account --server http://acme-srv --accountemail 'acme-sh@example.com' --eab-kid keyid_00 --eab-hmac-key V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --debug 3 + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name acme-sh neilpang/acme.sh:latest --signcsr --csr acme.sh/acme-sh.acme.csr --server http://acme-srv --standalone --debug 1 --output-insecure --insecure + awk 'BEGIN {c=0;} /BEGIN CERT/{c++} { print > "cert-" c ".pem"}' < acme-sh/acme-sh.acme/ca.cer + openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh.acme/acme-sh.acme.cer + openssl x509 -in acme-sh/acme-sh.acme/acme-sh.acme.cer -text -noout + shell: bash + + - name: "EAB SP - 01a - SUCC - Enroll lego - 1st list entry" + run: | + sudo mkdir -p lego + sudo rm -rf lego/* + sudo openssl genrsa -out lego/lego.acme.key 2048 + sudo openssl req -new -key lego/lego.acme.key -subj '/CN=lego.acme/O=acme corp/OU=acme1/C=AC/serialNumber=00-11-22-33' --addext "subjectAltName = DNS:lego.acme" -outform pem -out lego/lego.acme.csr + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --csr .lego/lego.acme.csr --http run + sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego.acme.crt + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + shell: bash + + - name: "EAB SP - 01B - SUCC - Enroll acme - 2nd list entry" + run: | + sudo rm -rf acme-sh/* + openssl genrsa -out acme-sh/acme-sh.acme.key 2048 + openssl req -new -key acme-sh/acme-sh.acme.key -subj '/CN=acme-sh.acme/O=acme corp/OU=acme2/C=AC/serialNumber=00-11-22-33' --addext "subjectAltName = DNS:acme-sh.acme" -outform pem -out acme-sh/acme-sh.acme.csr + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name=acme-sh neilpang/acme.sh:latest --register-account --server http://acme-srv --accountemail 'acme-sh@example.com' --eab-kid keyid_00 --eab-hmac-key V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --debug 3 + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name acme-sh neilpang/acme.sh:latest --signcsr --csr acme.sh/acme-sh.acme.csr --server http://acme-srv --standalone --debug 1 --output-insecure --insecure + openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh.acme/acme-sh.acme.cer + openssl x509 -in acme-sh/acme-sh.acme/acme-sh.acme.cer -text -noout + shell: bash + + - name: "EAB SP - 01B - SUCC - Enroll lego - 2nd list entry" + run: | + sudo rm -rf lego/* + sudo openssl genrsa -out lego/lego.acme.key 2048 + sudo openssl req -new -key lego/lego.acme.key -subj '/CN=lego.acme/O=acme corp/OU=acme2/C=AC/serialNumber=00-11-22-33' --addext "subjectAltName = DNS:lego.acme" -outform pem -out lego/lego.acme.csr + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --csr .lego/lego.acme.csr --http run + sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego.acme.crt + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + shell: bash + + - name: "EAB SP - 01C - FAIL - Enroll acme - entry not in list" + id: acmefail01 + continue-on-error: true + run: | + sudo rm -rf acme-sh/* + openssl genrsa -out acme-sh/acme-sh.acme.key 2048 + openssl req -new -key acme-sh/acme-sh.acme.key -subj '/CN=acme-sh.acme/O=acme corp/OU=acme3/C=AC/serialNumber=00-11-22-33' --addext "subjectAltName = DNS:acme-sh.acme" -outform pem -out acme-sh/acme-sh.acme.csr + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name=acme-sh neilpang/acme.sh:latest --register-account --server http://acme-srv --accountemail 'acme-sh@example.com' --eab-kid keyid_00 --eab-hmac-key V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --debug 3 + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name acme-sh neilpang/acme.sh:latest --signcsr --csr acme.sh/acme-sh.acme.csr --server http://acme-srv --standalone --debug 1 --output-insecure --insecure + openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh.acme/acme-sh.acme.cer + openssl x509 -in acme-sh/acme-sh.acme/acme-sh.acme.cer -text -noout + shell: bash + + - name: "Check result" + if: steps.acmefail01.outcome != 'failure' + run: | + echo "acmefail outcome is ${{steps.acmefail01.outcome }}" + exit 1 + shell: bash + + - name: "Sleep for 2s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 2s + + - name: "Check logs for errors" + working-directory: examples/Docker/ + run: | + if [ ${{ inputs.DEPLOYMENT_TYPE }} == "container" ]; then + docker-compose logs > docker-compose.log + cat docker-compose.log | grep "organizationalUnitName: value: acme3 expected: \['acme1', 'acme2'\]" + sudo truncate -s 0 $(docker inspect --format='{{.LogPath}}' acme2certifier_acme-srv_1) + # elif [ ${{ inputs.DEPLOYMENT_TYPE }} == "rpm" ]; then + # docker exec acme-srv grep "organizationalUnitName: value: acme3 expected: \['acme1', 'acme2'\]" /var/log/messages + fi + shell: bash + + - name: "EAB SP - 01C - Fail - Enroll lego - entry not in list" + id: legofail01 + continue-on-error: true + run: | + sudo rm -rf lego/* + sudo openssl genrsa -out lego/lego.acme.key 2048 + sudo openssl req -new -key lego/lego.acme.key -subj '/CN=lego.acme/O=acme corp/OU=acme3/C=AC/serialNumber=00-11-22-33' --addext "subjectAltName = DNS:lego.acme" -outform pem -out lego/lego.acme.csr + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --csr .lego/lego.acme.csr --http run + sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego.acme.crt + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + shell: bash + + - name: "Check result" + if: steps.legofail01.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail01.outcome }}" + exit 1 + shell: bash + + - name: "Sleep for 2s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 2s + + - name: "Check logs for errors" + working-directory: examples/Docker/ + run: | + if [ ${{ inputs.DEPLOYMENT_TYPE }} == "container" ]; then + docker-compose logs > docker-compose.log + cat docker-compose.log | grep "organizationalUnitName: value: acme3 expected: \['acme1', 'acme2'\]" + sudo truncate -s 0 $(docker inspect --format='{{.LogPath}}' acme2certifier_acme-srv_1) + # elif [ ${{ inputs.DEPLOYMENT_TYPE }} == "rpm" ]; then + # docker exec acme-srv grep "organizationalUnitName: value: acme3 expected: \['acme1', 'acme2'\]" /var/log/messages + fi + shell: bash + + - name: "EAB SP - 02 - FAIL - Enroll acme - wildcard entry not present" + id: acmefail02 + continue-on-error: true + run: | + sudo rm -rf acme-sh/* + openssl genrsa -out acme-sh/acme-sh.acme.key 2048 + openssl req -new -key acme-sh/acme-sh.acme.key -subj '/CN=acme-sh.acme/O=acme corp/OU=acme1/C=AC' --addext "subjectAltName = DNS:acme-sh.acme" -outform pem -out acme-sh/acme-sh.acme.csr + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name=acme-sh neilpang/acme.sh:latest --register-account --server http://acme-srv --accountemail 'acme-sh@example.com' --eab-kid keyid_00 --eab-hmac-key V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --debug 3 + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name acme-sh neilpang/acme.sh:latest --signcsr --csr acme.sh/acme-sh.acme.csr --server http://acme-srv --standalone --debug 1 --output-insecure --insecure + openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh.acme/acme-sh.acme.cer + openssl x509 -in acme-sh/acme-sh.acme/acme-sh.acme.cer -text -noout + shell: bash + + - name: "Check result" + if: steps.acmefail02.outcome != 'failure' + run: | + echo "acmefail outcome is ${{steps.acmefail02.outcome }}" + exit 1 + shell: bash + + - name: "Sleep for 2s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 2s + + - name: "Check logs for errors" + working-directory: examples/Docker/ + run: | + if [ ${{ inputs.DEPLOYMENT_TYPE }} == "container" ]; then + docker-compose logs > docker-compose.log + cat docker-compose.log | grep "failed for: \['serialNumber'\]" + sudo truncate -s 0 $(docker inspect --format='{{.LogPath}}' acme2certifier_acme-srv_1) + # elif [ ${{ inputs.DEPLOYMENT_TYPE }} == "rpm" ]; then + # docker exec acme-srv grep "failed for: \['serialNumber'\]" /var/log/messages + fi + shell: bash + + - name: "EAB SP - 02 - FAIL - Enroll lego - wildcard entry not present" + id: legofail02 + continue-on-error: true + run: | + sudo rm -rf lego/* + sudo openssl genrsa -out lego/lego.acme.key 2048 + sudo openssl req -new -key lego/lego.acme.key -subj '/CN=lego.acme/O=acme corp/OU=acme1/C=AC' --addext "subjectAltName = DNS:lego.acme" -outform pem -out lego/lego.acme.csr + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --csr .lego/lego.acme.csr --http run + sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego.acme.crt + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + shell: bash + + - name: "Check result" + if: steps.legofail02.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail02.outcome }}" + exit 1 + shell: bash + + - name: "Sleep for 2s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 2s + + - name: "Check logs for errors" + working-directory: examples/Docker/ + run: | + if [ ${{ inputs.DEPLOYMENT_TYPE }} == "container" ]; then + docker-compose logs > docker-compose.log + cat docker-compose.log | grep "failed for: \['serialNumber'\]" + sudo truncate -s 0 $(docker inspect --format='{{.LogPath}}' acme2certifier_acme-srv_1) + # elif [ ${{ inputs.DEPLOYMENT_TYPE }} == "rpm" ]; then + # docker exec acme-srv grep "failed for: \['serialNumber'\]" /var/log/messages + fi + shell: bash + + - name: "EAB SP - 03 - FAIL - Enroll acme - string check failed" + id: acmefail03 + continue-on-error: true + run: | + sudo rm -rf acme-sh/* + openssl genrsa -out acme-sh/acme-sh.acme.key 2048 + openssl req -new -key acme-sh/acme-sh.acme.key -subj '/CN=acme-sh.acme/O=noacme corp/OU=acme2/C=AC/serialNumber=00-11-22-33' --addext "subjectAltName = DNS:acme-sh.acme" -outform pem -out acme-sh/acme-sh.acme.csr + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name=acme-sh neilpang/acme.sh:latest --register-account --server http://acme-srv --accountemail 'acme-sh@example.com' --eab-kid keyid_00 --eab-hmac-key V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --debug 3 + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name acme-sh neilpang/acme.sh:latest --signcsr --csr acme.sh/acme-sh.acme.csr --server http://acme-srv --standalone --debug 1 --output-insecure --insecure + openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh.acme/acme-sh.acme.cer + openssl x509 -in acme-sh/acme-sh.acme/acme-sh.acme.cer -text -noout + shell: bash + + - name: "Check result" + if: steps.acmefail03.outcome != 'failure' + run: | + echo "acmefail outcome is ${{steps.acmefail03.outcome }}" + exit 1 + shell: bash + + - name: "Sleep for 2s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 2s + + - name: "Check logs for errors" + working-directory: examples/Docker/ + run: | + if [ ${{ inputs.DEPLOYMENT_TYPE }} == "container" ]; then + docker-compose logs > docker-compose.log + cat docker-compose.log | grep "failed for: organizationName: value: noacme corp expected: acme corp" + sudo truncate -s 0 $(docker inspect --format='{{.LogPath}}' acme2certifier_acme-srv_1) + # elif [ ${{ inputs.DEPLOYMENT_TYPE }} == "rpm" ]; then + # docker exec acme-srv grep "failed for: organizationName: value: noacme corp expected: acme corp" /var/log/messages + fi + shell: bash + + - name: "EAB SP - 03 - FAIL - Enroll lego - string check failed" + id: legofail03 + continue-on-error: true + run: | + sudo rm -rf lego/* + sudo openssl genrsa -out lego/lego.acme.key 2048 + sudo openssl req -new -key lego/lego.acme.key -subj '/CN=lego.acme/O=noacme corp/OU=acme2/C=AC/serialNumber=00-11-22-33' --addext "subjectAltName = DNS:lego.acme" -outform pem -out lego/lego.acme.csr + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --csr .lego/lego.acme.csr --http run + sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego.acme.crt + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + shell: bash + + - name: "Check result" + if: steps.legofail03.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail03.outcome }}" + exit 1 + shell: bash + + - name: "Sleep for 2s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 2s + + - name: "Check logs for errors" + working-directory: examples/Docker/ + run: | + if [ ${{ inputs.DEPLOYMENT_TYPE }} == "container" ]; then + docker-compose logs > docker-compose.log + cat docker-compose.log | grep "failed for: organizationName: value: noacme corp expected: acme corp" + sudo truncate -s 0 $(docker inspect --format='{{.LogPath}}' acme2certifier_acme-srv_1) + # elif [ ${{ inputs.DEPLOYMENT_TYPE }} == "rpm" ]; then + # docker exec acme-srv grep "failed for: organizationName: value: noacme corp expected: acme corp" /var/log/messages + fi + shell: bash + + - name: "EAB SP - 04 - FAIL - Enroll acme - string parameter not present" + id: acmefail04 + continue-on-error: true + run: | + sudo rm -rf acme-sh/* + openssl genrsa -out acme-sh/acme-sh.acme.key 2048 + openssl req -new -key acme-sh/acme-sh.acme.key -subj '/CN=acme-sh.acme/O=acme corp/OU=acme2/serialNumber=00-11-22-33' --addext "subjectAltName = DNS:acme-sh.acme" -outform pem -out acme-sh/acme-sh.acme.csr + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name=acme-sh neilpang/acme.sh:latest --register-account --server http://acme-srv --accountemail 'acme-sh@example.com' --eab-kid keyid_00 --eab-hmac-key V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --debug 3 + docker run --rm -i -v "$(pwd)/acme-sh":/acme.sh --network acme --name acme-sh neilpang/acme.sh:latest --signcsr --csr acme.sh/acme-sh.acme.csr --server http://acme-srv --standalone --debug 1 --output-insecure --insecure + openssl verify -CAfile cert-2.pem -untrusted cert-1.pem acme-sh/acme-sh.acme/acme-sh.acme.cer + openssl x509 -in acme-sh/acme-sh.acme/acme-sh.acme.cer -text -noout + shell: bash + + - name: "Check result" + if: steps.acmefail04.outcome != 'failure' + run: | + echo "acmefail outcome is ${{steps.acmefail04.outcome }}" + exit 1 + shell: bash + + - name: "Sleep for 2s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 2s + + - name: "Check logs for errors" + working-directory: examples/Docker/ + run: | + if [ ${{ inputs.DEPLOYMENT_TYPE }} == "container" ]; then + docker-compose logs > docker-compose.log + cat docker-compose.log | grep "failed for: \['countryName'\]" + sudo truncate -s 0 $(docker inspect --format='{{.LogPath}}' acme2certifier_acme-srv_1) + # elif [ ${{ inputs.DEPLOYMENT_TYPE }} == "rpm" ]; then + # docker exec acme-srv grep "failed for: \['countryName'\]" /var/log/messages + fi + shell: bash + + - name: "EAB SP - 04 - FAIL - Enroll acme - string parameter not present" + id: legofail04 + continue-on-error: true + run: | + sudo rm -rf lego/* + sudo openssl genrsa -out lego/lego.acme.key 2048 + sudo openssl req -new -key lego/lego.acme.key -subj '/CN=lego.acme/O=acme corp/OU=acme2/serialNumber=00-11-22-33' --addext "subjectAltName = DNS:lego.acme" -outform pem -out lego/lego.acme.csr + docker run -i -v $PWD/lego:/.lego/ --rm --name lego --network acme goacme/lego -s http://acme-srv -a --email "lego@example.com" --eab --kid keyid_00 --hmac V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw --csr .lego/lego.acme.csr --http run + sudo openssl verify -CAfile cert-2.pem -untrusted cert-1.pem lego/certificates/lego.acme.crt + sudo openssl x509 -in lego/certificates/lego.acme.crt -text -noout + shell: bash + + - name: "Check result" + if: steps.legofail04.outcome != 'failure' + run: | + echo "legofail outcome is ${{steps.legofail04.outcome }}" + exit 1 + shell: bash + + - name: "Sleep for 2s" + uses: juliangruber/sleep-action@v2.0.3 + with: + time: 2s + + - name: "Check logs for errors" + working-directory: examples/Docker/ + run: | + if [ ${{ inputs.DEPLOYMENT_TYPE }} == "container" ]; then + docker-compose logs > docker-compose.log + cat docker-compose.log | grep "failed for: \['countryName'\]" + sudo truncate -s 0 $(docker inspect --format='{{.LogPath}}' acme2certifier_acme-srv_1) + # elif [ ${{ inputs.DEPLOYMENT_TYPE }} == "rpm" ]; then + # docker exec acme-srv grep "failed for: \['countryName'\]" /var/log/messages + fi + shell: bash + diff --git a/.github/workflows/ca_handler_tests_certifier.yml b/.github/workflows/ca_handler_tests_certifier.yml index 9625efd2..2079bf06 100644 --- a/.github/workflows/ca_handler_tests_certifier.yml +++ b/.github/workflows/ca_handler_tests_certifier.yml @@ -13,7 +13,7 @@ jobs: name: "certifier_handler_tests" runs-on: ubuntu-latest strategy: - # max-parallel: 1 + max-parallel: 2 fail-fast: false matrix: websrv: ['apache2', 'nginx'] @@ -276,7 +276,7 @@ jobs: # needs: certifier_handler_tests strategy: fail-fast: false - # max-parallel: 1 + max-parallel: 1 matrix: rhversion: [8, 9] steps: diff --git a/.github/workflows/ca_handler_tests_digicert.yml b/.github/workflows/ca_handler_tests_digicert.yml new file mode 100644 index 00000000..d1f39514 --- /dev/null +++ b/.github/workflows/ca_handler_tests_digicert.yml @@ -0,0 +1,289 @@ +name: CA handler Tests - Digicert CertCentral + +on: + push: + branches: [ 'devel', 'master'] + pull_request: + branches: [ devel ] + schedule: + # * is a special character in YAML so you have to quote this string + - cron: '0 2 * * 6' + +jobs: + digicert_handler_tests: + name: "digicert_handler_tests" + runs-on: ubuntu-latest + strategy: + max-parallel: 1 + fail-fast: false + matrix: + websrv: ['apache2'] + dbhandler: ['wsgi', 'django'] + steps: + - name: "checkout GIT" + uses: actions/checkout@v4 + + - name: "create folders" + run: | + mkdir lego + mkdir acme-sh + mkdir certbot + + - name: "Build container" + uses: ./.github/actions/container_prep + with: + DB_HANDLER: ${{ matrix.dbhandler }} + WEB_SRV: ${{ matrix.websrv }} + NAME_SPACE: acme.dynamop.de + + - name: "Setup a2c with digicert_ca_handler" + run: | + sudo cp .github/openssl_ca_handler.py_acme_srv_default_handler.cfg examples/Docker/data/acme_srv.cfg + sudo chmod 777 examples/Docker/data/acme_srv.cfg + sudo cp test/ca/certsrv_ca_certs.pem examples/Docker/data/ca_certs.pem + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_default_handler.cfg > examples/Docker/data/acme_srv.cfg + sudo echo "handler_file: examples/ca_handler/digicert_ca_handler.py" >> examples/Docker/data/acme_srv.cfg + sudo echo "api_key: $DIGICERT_API_KEY" >> examples/Docker/data/acme_srv.cfg + sudo echo "organization_name: $DIGICERT_ORGNAME" >> examples/Docker/data/acme_srv.cfg + sudo echo "allowed_domainlist: [\"$DIGICERT_DOMAIN\", \"bar.local$\"]" >> examples/Docker/data/acme_srv.cfg + sudo sed -i "s/revocation_reason_check_disable: False/revocation_reason_check_disable: False\nenrollment_timeout:15/g" examples/Docker/data/acme_srv.cfg + cd examples/Docker/ + docker-compose restart + env: + DIGICERT_API_KEY: ${{ secrets.DIGICERT_API_KEY }} + DIGICERT_ORGNAME: ${{ secrets.DIGICERT_ORGNAME }} + DIGICERT_DOMAIN: ${{ secrets.DIGICERT_DOMAIN }} + + - name: "Test enrollment" + uses: ./.github/actions/acme_clients + with: + NAME_SPACE: acme.dynamop.de + USE_CERTBOT: false + + - name: "EAB - Setup a2c with digicert_ca_handler" + run: | + mkdir -p examples/Docker/data + sudo cp .github/openssl_ca_handler.py_acme_srv_default_handler.cfg examples/Docker/data/acme_srv.cfg + sudo chmod 777 examples/Docker/data/acme_srv.cfg + sudo cp test/ca/certsrv_ca_certs.pem examples/Docker/data/ca_certs.pem + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_default_handler.cfg > examples/Docker/data/acme_srv.cfg + sudo echo "handler_file: examples/ca_handler/digicert_ca_handler.py" >> examples/Docker/data/acme_srv.cfg + sudo echo "api_key: $DIGICERT_API_KEY" >> examples/Docker/data/acme_srv.cfg + sudo echo "organization_name: $DIGICERT_ORGNAME" >> examples/Docker/data/acme_srv.cfg + sudo echo "allowed_domainlist: [\"$DIGICERT_DOMAIN\", \"bar.local$\"]" >> examples/Docker/data/acme_srv.cfg + sudo sed -i "s/revocation_reason_check_disable: False/revocation_reason_check_disable: False\nenrollment_timeout:15/g" examples/Docker/data/acme_srv.cfg + sudo echo "eab_profiling: True" >> examples/Docker/data/acme_srv.cfg + sudo sed -i "s/tnauthlist_support: False/tnauthlist_support: False\nheader_info_list: [\"HTTP_USER_AGENT\"]/g" examples/Docker/data/acme_srv.cfg + sudo echo -e "\n\n[EABhandler]" >> examples/Docker/data/acme_srv.cfg + sudo echo "eab_handler_file: /var/www/acme2certifier/examples/eab_handler/kid_profile_handler.py" >> examples/Docker/data/acme_srv.cfg + sudo echo "key_file: volume/kid_profiles.json" >> examples/Docker/data/acme_srv.cfg + + sudo cp examples/eab_handler/kid_profiles.json examples/Docker/data/kid_profiles.json + sudo chmod 777 examples/eab_handler/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \[\"profile_1\", \"profile_2\", \"profile_3\"\]/\"cert_type\"\: \[\"ssl_basic\", \"ssl_securesite_pro\", \"ssl_securesite_flex\"\]/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \"profile_2\"/\"cert_type\"\: \"ssl_securesite_pro\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca\",/\"unknown_key\": \"unknown_value\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca_2\",/\"unknown_key\": \"unknown_value\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/www.example.org/*.acme.dynamop.de/g" examples/Docker/data/kid_profiles.json + sudo sed -i '18,19d' examples/Docker/data/kid_profiles.json + sudo sed -i '8,9d' examples/Docker/data/kid_profiles.json + cd examples/Docker/ + docker-compose restart + env: + DIGICERT_API_KEY: ${{ secrets.DIGICERT_API_KEY }} + DIGICERT_ORGNAME: ${{ secrets.DIGICERT_ORGNAME }} + DIGICERT_DOMAIN: ${{ secrets.DIGICERT_DOMAIN }} + + - name: "EAB - Test enrollment" + uses: ./.github/actions/wf_specific/digicert_ca_handler/enroll_eab + + - name: "Check container configuration" + uses: ./.github/actions/container_check + with: + DB_HANDLER: ${{ matrix.dbhandler }} + WEB_SRV: ${{ matrix.websrv }} + + - name: "[ * ] collecting test logs" + if: ${{ failure() }} + run: | + mkdir -p ${{ github.workspace }}/artifact/upload + sudo cp -rp examples/Docker/data/ ${{ github.workspace }}/artifact/data/ + sudo cp -rp acme-sh/ ${{ github.workspace }}/artifact/acme-sh/ + sudo cp -rp certbot/ ${{ github.workspace }}/artifact/certbot/ + sudo cp -rp lego/ ${{ github.workspace }}/artifact/lego/ + cd examples/Docker + docker-compose logs > ${{ github.workspace }}/artifact/docker-compose.log + sudo tar -C ${{ github.workspace }}/artifact/ -cvzf ${{ github.workspace }}/artifact/upload/artifact.tar.gz docker-compose.log data acme-sh certbot lego + + - name: "[ * ] uploading artificates" + uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: digicert-${{ matrix.websrv }}-${{ matrix.dbhandler }}.tar.gz + path: ${{ github.workspace }}/artifact/upload/ + + digicert_ca_handler_tests_rpm: + name: "digicert_ca_handler_tests_rpm" + runs-on: ubuntu-latest + strategy: + max-parallel: 1 + fail-fast: false + matrix: + rhversion: [8] + execscript: ['rpm_tester.sh', 'django_tester.sh'] + + steps: + - name: "checkout GIT" + uses: actions/checkout@v4 + + - name: "Prepare Alma environment" + uses: ./.github/actions/rpm_prep + with: + GH_SBOM_USER: ${{ secrets.GH_SBOM_USER }} + GH_SBOM_TOKEN: ${{ secrets.GH_SBOM_TOKEN }} + RH_VERSION: ${{ matrix.rhversion }} + NAME_SPACE: acme.dynamop.de + + - name: "Setup a2c with digicert_ca_handler" + if: matrix.execscript == 'rpm_tester.sh' + run: | + sudo mkdir -p data/acme_ca/certs + sudo cp .github/openssl_ca_handler.py_acme_srv_default_handler.cfg data/acme_srv.cfg + sudo chmod 777 data/acme_srv.cfg + sudo cp test/ca/certsrv_ca_certs.pem data/ca_certs.pem + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_default_handler.cfg > data/acme_srv.cfg + sudo echo "handler_file: /opt/acme2certifier/examples/ca_handler/digicert_ca_handler.py" >> data/acme_srv.cfg + sudo echo "api_key: $DIGICERT_API_KEY" >> data/acme_srv.cfg + sudo echo "organization_name: $DIGICERT_ORGNAME" >> data/acme_srv.cfg + sudo echo "allowed_domainlist: [\"$DIGICERT_DOMAIN\", \"bar.local$\"]" >> data/acme_srv.cfg + sudo sed -i "s/revocation_reason_check_disable: False/revocation_reason_check_disable: False\nenrollment_timeout:15/g" data/acme_srv.cfg + env: + DIGICERT_API_KEY: ${{ secrets.DIGICERT_API_KEY }} + DIGICERT_ORGNAME: ${{ secrets.DIGICERT_ORGNAME }} + DIGICERT_DOMAIN: ${{ secrets.DIGICERT_DOMAIN }} + + - name: "Setup a2c with digicert_ca_handler for django" + if: matrix.execscript == 'django_tester.sh' + run: | + sudo mkdir -p data/volume/acme_ca/certs + sudo cp .github/openssl_ca_handler.py_acme_srv_default_handler.cfg data/volume/acme_srv.cfg + sudo chmod 777 data/volume/acme_srv.cfg + sudo cp test/ca/certsrv_ca_certs.pem data/volume/ca_certs.pem + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_default_handler.cfg > data/volume/acme_srv.cfg + sudo echo "handler_file: /opt/acme2certifier/examples/ca_handler/digicert_ca_handler.py" >> data/volume/acme_srv.cfg + sudo echo "api_key: $DIGICERT_API_KEY" >> data/volume/acme_srv.cfg + sudo echo "organization_name: $DIGICERT_ORGNAME" >> data/volume/acme_srv.cfg + sudo echo "allowed_domainlist: [\"$DIGICERT_DOMAIN\", \"bar.local$\"]" >> data/volume/acme_srv.cfg + sudo sed -i "s/revocation_reason_check_disable: False/revocation_reason_check_disable: False\nenrollment_timeout:15/g" data/volume/acme_srv.cfg + env: + DIGICERT_API_KEY: ${{ secrets.DIGICERT_API_KEY }} + DIGICERT_ORGNAME: ${{ secrets.DIGICERT_ORGNAME }} + DIGICERT_DOMAIN: ${{ secrets.DIGICERT_DOMAIN }} + + - name: "Execute install scipt" + run: | + docker exec acme-srv sh /tmp/acme2certifier/$EXEC_SCRIPT + env: + EXEC_SCRIPT: ${{ matrix.execscript }} + + - name: "Test enrollment" + uses: ./.github/actions/acme_clients + with: + NAME_SPACE: acme.dynamop.de + USE_CERTBOT: false + + - name: "EAB - Setup a2c with digicert_ca_handler" + if: matrix.execscript == 'rpm_tester.sh' + run: | + sudo mkdir -p data/acme_ca/certs + sudo cp .github/openssl_ca_handler.py_acme_srv_default_handler.cfg data/acme_srv.cfg + sudo cp test/ca/certsrv_ca_certs.pem data/ca_certs.pem + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_default_handler.cfg > data/acme_srv.cfg + sudo echo "handler_file: examples/ca_handler/digicert_ca_handler.py" >> data/acme_srv.cfg + sudo echo "api_key: $DIGICERT_API_KEY" >> data/acme_srv.cfg + sudo echo "organization_name: $DIGICERT_ORGNAME" >> data/acme_srv.cfg + sudo echo "allowed_domainlist: [\"$DIGICERT_DOMAIN\", \"bar.local$\"]" >> data/acme_srv.cfg + sudo sed -i "s/revocation_reason_check_disable: False/revocation_reason_check_disable: False\nenrollment_timeout:15/g" data/acme_srv.cfg + sudo echo "eab_profiling: True" >> data/acme_srv.cfg + sudo sed -i "s/tnauthlist_support: False/tnauthlist_support: False\nheader_info_list: [\"HTTP_USER_AGENT\"]/g" data/acme_srv.cfg + sudo echo -e "\n\n[EABhandler]" >> data/acme_srv.cfg + sudo echo "eab_handler_file: /opt/acme2certifier/examples/eab_handler/kid_profile_handler.py" >> data/acme_srv.cfg + sudo echo "key_file: /opt/acme2certifier/volume/acme_ca/kid_profiles.json" >> data/acme_srv.cfg + + sudo cp examples/eab_handler/kid_profiles.json data/acme_ca/kid_profiles.json + sudo chmod 777 data/acme_ca/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \[\"profile_1\", \"profile_2\", \"profile_3\"\]/\"cert_type\"\: \[\"ssl_basic\", \"ssl_securesite_pro\", \"ssl_securesite_flex\"\]/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \"profile_2\"/\"cert_type\"\: \"ssl_securesite_pro\"/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca\",/\"unknown_key\": \"unknown_value\"/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca_2\",/\"unknown_key\": \"unknown_value\"/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/www.example.org/*.acme.dynamop.de/g" data/acme_ca/kid_profiles.json + sudo sed -i '18,19d' data/acme_ca/kid_profiles.json + sudo sed -i '8,9d' data/acme_ca/kid_profiles.json + env: + DIGICERT_API_KEY: ${{ secrets.DIGICERT_API_KEY }} + DIGICERT_ORGNAME: ${{ secrets.DIGICERT_ORGNAME }} + DIGICERT_DOMAIN: ${{ secrets.DIGICERT_DOMAIN }} + + - name: "EAB - Setup a2c with digicert_ca_handler" + if: matrix.execscript == 'django_tester.sh' + run: | + sudo mkdir -p data/volume/acme_ca/certs + sudo cp .github/openssl_ca_handler.py_acme_srv_default_handler.cfg data/volume/acme_srv.cfg + sudo chmod 777 data/volume/acme_srv.cfg + sudo cp test/ca/certsrv_ca_certs.pem data/ca_certs.pem + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_default_handler.cfg > data/volume/acme_srv.cfg + sudo echo "handler_file: examples/ca_handler/digicert_ca_handler.py" >> data/volume/acme_srv.cfg + sudo echo "api_key: $DIGICERT_API_KEY" >> data/volume/acme_srv.cfg + sudo echo "organization_name: $DIGICERT_ORGNAME" >> data/volume/acme_srv.cfg + sudo echo "allowed_domainlist: [\"$DIGICERT_DOMAIN\", \"bar.local$\"]" >> data/volume/acme_srv.cfg + sudo sed -i "s/revocation_reason_check_disable: False/revocation_reason_check_disable: False\nenrollment_timeout:15/g" data/volume/acme_srv.cfg + sudo echo "eab_profiling: True" >> data/volume/acme_srv.cfg + sudo sed -i "s/tnauthlist_support: False/tnauthlist_support: False\nheader_info_list: [\"HTTP_USER_AGENT\"]/g" data/volume/acme_srv.cfg + sudo echo -e "\n\n[EABhandler]" >> data/volume/acme_srv.cfg + sudo echo "eab_handler_file: /opt/acme2certifier/examples/eab_handler/kid_profile_handler.py" >> data/volume/acme_srv.cfg + sudo echo "key_file: /opt/acme2certifier/volume/acme_ca/kid_profiles.json" >> data/volume/acme_srv.cfg + + sudo cp examples/eab_handler/kid_profiles.json data/volume/acme_ca/kid_profiles.json + sudo chmod 777 data/volume/acme_ca/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \[\"profile_1\", \"profile_2\", \"profile_3\"\]/\"cert_type\"\: \[\"ssl_basic\", \"ssl_securesite_pro\", \"ssl_securesite_flex\"\]/g" data/volume/acme_ca/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \"profile_2\"/\"cert_type\"\: \"ssl_securesite_pro\"/g" data/volume/acme_ca/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca\",/\"unknown_key\": \"unknown_value\"/g" data/volume/acme_ca/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca_2\",/\"unknown_key\": \"unknown_value\"/g" data/volume/acme_ca/kid_profiles.json + sudo sed -i "s/www.example.org/*.acme.dynamop.de/g" data/volume/acme_ca/kid_profiles.json + sudo sed -i '18,19d' data/volume/acme_ca/kid_profiles.json + sudo sed -i '8,9d' data/volume/acme_ca/kid_profiles.json + env: + DIGICERT_API_KEY: ${{ secrets.DIGICERT_API_KEY }} + DIGICERT_ORGNAME: ${{ secrets.DIGICERT_ORGNAME }} + DIGICERT_DOMAIN: ${{ secrets.DIGICERT_DOMAIN }} + + - name: "Reconfigure a2c" + run: | + docker exec acme-srv sh /tmp/acme2certifier/$EXEC_SCRIPT restart + env: + EXEC_SCRIPT: ${{ matrix.execscript }} + + - name: "EAB - Test enrollment" + uses: ./.github/actions/wf_specific/digicert_ca_handler/enroll_eab + + - name: "[ * ] collecting test logs" + if: ${{ failure() }} + run: | + mkdir -p ${{ github.workspace }}/artifact/upload + docker exec acme-srv tar cvfz /tmp/acme2certifier/a2c.tgz /opt/acme2certifier + sudo cp -rp data/ ${{ github.workspace }}/artifact/data/ + sudo rm ${{ github.workspace }}/artifact/data/*.rpm + sudo cp -rp acme-sh/ ${{ github.workspace }}/artifact/acme-sh/ + sudo cp -rp certbot/ ${{ github.workspace }}/artifact/certbot/ + sudo cp -rp lego/ ${{ github.workspace }}/artifact/lego/ + docker exec acme-srv cat /etc/nginx/nginx.conf.orig > ${{ github.workspace }}/artifact/data/nginx.conf.orig + docker exec acme-srv cat /etc/nginx/nginx.conf > ${{ github.workspace }}/artifact/data/nginx.conf + docker exec acme-srv cat /var/log/messages > ${{ github.workspace }}/artifact/acme-srv.log + sudo tar -C ${{ github.workspace }}/artifact/ -cvzf ${{ github.workspace }}/artifact/upload/artifact.tar.gz data acme-srv.log acme-sh certbot lego + + - name: "[ * ] uploading artificates" + uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: digicert_ca_handler_tests_rpm-rh${{ matrix.rhversion }}-${{ matrix.execscript }}.tar.gz + path: ${{ github.workspace }}/artifact/upload/ diff --git a/.github/workflows/ca_handler_tests_enrust.yml b/.github/workflows/ca_handler_tests_enrust.yml new file mode 100644 index 00000000..9f0cb746 --- /dev/null +++ b/.github/workflows/ca_handler_tests_enrust.yml @@ -0,0 +1,154 @@ +name: CA handler Tests - Entrust Enterprise API + +on: + push: + branches: [ 'devel', 'master'] + pull_request: + branches: [ devel ] + schedule: + # * is a special character in YAML so you have to quote this string + - cron: '0 2 * * 6' + +jobs: + entrust_handler_tests: + name: "entrust_handler_tests" + runs-on: ubuntu-latest + strategy: + max-parallel: 1 + fail-fast: false + matrix: + websrv: ['apache2'] + dbhandler: ['wsgi'] + # dbhandler: ['wsgi', 'django'] + steps: + - name: "checkout GIT" + uses: actions/checkout@v4 + + - name: "create folder" + run: | + mkdir lego + mkdir acme-sh + mkdir certbot + + - name: "Build container" + uses: ./.github/actions/container_prep + with: + DB_HANDLER: ${{ matrix.dbhandler }} + WEB_SRV: ${{ matrix.websrv }} + NAME_SPACE: rm-rf.ninja + + - name: "Setup a2c with entrust_ca_handler" + run: | + sudo mkdir -p examples/Docker/data/ + sudo touch examples/Docker/data/entrust_cert.p12 + sudo chmod a+rw examples/Docker/data/entrust_cert.p12 + sudo echo $ENTRUST_CERT | base64 --decode > examples/Docker/data/entrust_cert.p12 + sudo cp .github/openssl_ca_handler.py_acme_srv_default_handler.cfg examples/Docker/data/acme_srv.cfg + sudo chmod 777 examples/Docker/data/acme_srv.cfg + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_default_handler.cfg > examples/Docker/data/acme_srv.cfg + sudo echo "handler_file: examples/ca_handler/entrust_ca_handler.py" >> examples/Docker/data/acme_srv.cfg + sudo echo "client_cert: volume/entrust_cert.p12" >> examples/Docker/data/acme_srv.cfg + sudo echo "cert_passphrase: $ENTRUST_CERT_PASSPHRASE" >> examples/Docker/data/acme_srv.cfg + sudo echo "organization_name: $ENTRUST_ORGNAME" >> examples/Docker/data/acme_srv.cfg + sudo echo "username: $ENTRUST_USERNAME" >> examples/Docker/data/acme_srv.cfg + sudo echo "password: $ENTRUST_PASSWORD" >> examples/Docker/data/acme_srv.cfg + sudo echo "certtype: $ENTRUST_CERTTYPE" >> examples/Docker/data/acme_srv.cfg + sudo echo "cert_validity_days: 10" >> examples/Docker/data/acme_srv.cfg + sudo echo "request_timeout: 20" >> examples/Docker/data/acme_srv.cfg + sudo echo "allowed_domainlist: [\"*.rm-rf.ninja\", \"bar.local$\"]" >> examples/Docker/data/acme_srv.cfg + sudo sed -i "s/revocation_reason_check_disable: False/revocation_reason_check_disable: False\nenrollment_timeout:15/g" examples/Docker/data/acme_srv.cfg + sudo sed -i "s/challenge_validation_disable: False/challenge_validation_disable: True/g" examples/Docker/data/acme_srv.cfg + # cd examples/Docker/ + # docker-compose restart + env: + ENTRUST_CERT: ${{ secrets.ENTRUST_CERT }} + ENTRUST_CERT_PASSPHRASE: ${{ secrets.ENTRUST_CERT_PASSPHRASE }} + ENTRUST_ORGNAME: ${{ secrets.ENTRUST_ORGNAME }} + ENTRUST_USERNAME: ${{ secrets.ENTRUST_USER }} + ENTRUST_PASSWORD: ${{ secrets.ENTRUST_PASSWORD }} + ENTRUST_CERTTYPE: ${{ secrets.ENTRUST_CERTTYPE }} + + - name: "Test enrollment" + uses: ./.github/actions/wf_specific/entrust_ca_handler/enroll + with: + NAME_SPACE: rm-rf.ninja + USE_CERTBOT: false + USE_RSA: true + + - name: "EAB - Setup a2c with entrust_ca_handler" + run: | + sudo mkdir -p examples/Docker/data/ + sudo touch examples/Docker/data/entrust_cert.p12 + sudo chmod a+rw examples/Docker/data/entrust_cert.p12 + sudo echo $ENTRUST_CERT | base64 --decode > examples/Docker/data/entrust_cert.p12 + sudo cp .github/openssl_ca_handler.py_acme_srv_default_handler.cfg examples/Docker/data/acme_srv.cfg + sudo chmod 777 examples/Docker/data/acme_srv.cfg + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_default_handler.cfg > examples/Docker/data/acme_srv.cfg + sudo echo "handler_file: examples/ca_handler/entrust_ca_handler.py" >> examples/Docker/data/acme_srv.cfg + sudo echo "client_cert: volume/entrust_cert.p12" >> examples/Docker/data/acme_srv.cfg + sudo echo "cert_passphrase: $ENTRUST_CERT_PASSPHRASE" >> examples/Docker/data/acme_srv.cfg + sudo echo "organization_name: $ENTRUST_ORGNAME" >> examples/Docker/data/acme_srv.cfg + sudo echo "username: $ENTRUST_USERNAME" >> examples/Docker/data/acme_srv.cfg + sudo echo "password: $ENTRUST_PASSWORD" >> examples/Docker/data/acme_srv.cfg + sudo echo "certtype: $ENTRUST_CERTTYPE" >> examples/Docker/data/acme_srv.cfg + sudo echo "cert_validity_days: 10" >> examples/Docker/data/acme_srv.cfg + sudo echo "request_timeout: 20" >> examples/Docker/data/acme_srv.cfg + sudo echo "allowed_domainlist: [\"*.rm-rf.ninja\", \"bar.local$\"]" >> examples/Docker/data/acme_srv.cfg + sudo sed -i "s/revocation_reason_check_disable: False/revocation_reason_check_disable: False\nenrollment_timeout:15/g" examples/Docker/data/acme_srv.cfg + sudo sed -i "s/challenge_validation_disable: False/challenge_validation_disable: True/g" examples/Docker/data/acme_srv.cfg + sudo echo "eab_profiling: True" >> examples/Docker/data/acme_srv.cfg + sudo sed -i "s/tnauthlist_support: False/tnauthlist_support: False\nheader_info_list: [\"HTTP_USER_AGENT\"]/g" examples/Docker/data/acme_srv.cfg + sudo echo -e "\n\n[EABhandler]" >> examples/Docker/data/acme_srv.cfg + sudo echo "eab_handler_file: /var/www/acme2certifier/examples/eab_handler/kid_profile_handler.py" >> examples/Docker/data/acme_srv.cfg + sudo echo "key_file: volume/kid_profiles.json" >> examples/Docker/data/acme_srv.cfg + + sudo cp examples/eab_handler/kid_profiles.json examples/Docker/data/kid_profiles.json + sudo chmod 777 examples/eab_handler/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \[\"profile_1\", \"profile_2\", \"profile_3\"\]/\"cert_type\"\: \[\"STANDARD_SSL\", \"ADVANTAGE_SSL\"\]/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \"profile_2\"/\"cert_type\"\: \"ADVANTAGE_SSL\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca\",/\"unknown_key\": \"unknown_value\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca_2\",/\"unknown_key\": \"unknown_value\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/*.example.net/*.rm-rf.ninja/" examples/Docker/data/kid_profiles.json + sudo sed -i '18,19d' examples/Docker/data/kid_profiles.json + sudo sed -i '8,9d' examples/Docker/data/kid_profiles.json + cd examples/Docker/ + docker-compose restart + env: + ENTRUST_CERT: ${{ secrets.ENTRUST_CERT }} + ENTRUST_CERT_PASSPHRASE: ${{ secrets.ENTRUST_CERT_PASSPHRASE }} + ENTRUST_ORGNAME: ${{ secrets.ENTRUST_ORGNAME }} + ENTRUST_USERNAME: ${{ secrets.ENTRUST_USER }} + ENTRUST_PASSWORD: ${{ secrets.ENTRUST_PASSWORD }} + ENTRUST_CERTTYPE: ${{ secrets.ENTRUST_CERTTYPE }} + + - name: "Test enrollment" + uses: ./.github/actions/wf_specific/entrust_ca_handler/enroll_eab + with: + USE_RSA: true + + - name: "Check container configuration" + uses: ./.github/actions/container_check + with: + DB_HANDLER: ${{ matrix.dbhandler }} + WEB_SRV: ${{ matrix.websrv }} + + - name: "[ * ] collecting test logs" + if: ${{ failure() }} + run: | + mkdir -p ${{ github.workspace }}/artifact/upload + sudo cp -rp examples/Docker/data/ ${{ github.workspace }}/artifact/data/ + sudo cp -rp acme-sh/ ${{ github.workspace }}/artifact/acme-sh/ + sudo cp -rp certbot/ ${{ github.workspace }}/artifact/certbot/ + sudo cp -rp lego/ ${{ github.workspace }}/artifact/lego/ + cd examples/Docker + docker-compose logs > ${{ github.workspace }}/artifact/docker-compose.log + # touch ${{ github.workspace }}/artifact/docker-compose.log + sudo tar -C ${{ github.workspace }}/artifact/ -cvzf ${{ github.workspace }}/artifact/upload/artifact.tar.gz docker-compose.log data acme-sh certbot lego + + - name: "[ * ] uploading artificates" + uses: actions/upload-artifact@v4 + if: ${{ failure() }} + with: + name: entrust_handler_tests-${{ matrix.websrv }}-${{ matrix.dbhandler }}.tar.gz + path: ${{ github.workspace }}/artifact/upload/ + diff --git a/.github/workflows/ca_handler_tests_openssl.yml b/.github/workflows/ca_handler_tests_openssl.yml index 49ee5842..fac0b65c 100644 --- a/.github/workflows/ca_handler_tests_openssl.yml +++ b/.github/workflows/ca_handler_tests_openssl.yml @@ -45,7 +45,7 @@ jobs: sudo echo -e "\nopenssl_conf: volume/acme_ca/openssl.cnf" >> examples/Docker/data/acme_srv.cfg sudo touch examples/Docker/data/acme_ca/openssl.cnf sudo chmod 777 examples/Docker/data/acme_ca/openssl.cnf - sudo echo -e "[extensions]\nbasicConstraints = critical, CA:FALSE\nsubjectKeyIdentifier = critical, hash, issuer:always\nauthorityKeyIdentifier = keyid:always, issuer:always" >> examples/Docker/data/acme_ca/openssl.cnf + sudo echo -e "[extensions]\nbasicConstraints = critical, CA:FALSE\nsubjectKeyIdentifier = hash, issuer:always\nauthorityKeyIdentifier = keyid:always, issuer:always" >> examples/Docker/data/acme_ca/openssl.cnf sudo echo -e "keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment, keyAgreement\nextendedKeyUsage = critical, serverAuth, OCSPSigning\n" >> examples/Docker/data/acme_ca/openssl.cnf cd examples/Docker/ docker-compose restart diff --git a/.github/workflows/ca_handler_tests_xca.yml b/.github/workflows/ca_handler_tests_xca.yml index f57a6745..57e1db19 100644 --- a/.github/workflows/ca_handler_tests_xca.yml +++ b/.github/workflows/ca_handler_tests_xca.yml @@ -170,6 +170,53 @@ jobs: - name: "EAB - enrollment" uses: ./.github/actions/wf_specific/xca_ca_handler/enroll_eab + - name: "EAB subject profiling - Setup a2c with xca_ca_handler " + run: | + sudo cp .github/acme2certifier.pem examples/Docker/data/acme2certifier.pem + sudo cp .github/acme2certifier_cert.pem examples/Docker/data/acme2certifier_cert.pem + sudo cp .github/acme2certifier_key.pem examples/Docker/data/acme2certifier_key.pem + sudo cp .github/django_settings.py examples/Docker/data/settings.py + sudo mkdir -p examples/Docker/data/xca + sudo chmod -R 777 examples/Docker/data/xca + sudo cp test/ca/acme2certifier-clean.xdb examples/Docker/data/xca/$XCA_DB_NAME + sudo mkdir -p examples/Docker/data/acme_ca/certs + sudo cp test/ca/sub-ca-key.pem test/ca/sub-ca-crl.pem test/ca/sub-ca-cert.pem test/ca/root-ca-cert.pem examples/Docker/data/acme_ca/ + sudo touch examples/Docker/data/acme_srv.cfg + sudo chmod 777 examples/Docker/data/acme_srv.cfg + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_choosen_handler.cfg > examples/Docker/data/acme_srv.cfg + sudo echo "handler_file: /var/www/acme2certifier/examples/ca_handler/xca_ca_handler.py" >> examples/Docker/data/acme_srv.cfg + sudo echo "xdb_file: volume/xca/$XCA_DB_NAME" >> examples/Docker/data/acme_srv.cfg + sudo echo "issuing_ca_name: $XCA_ISSUING_CA" >> examples/Docker/data/acme_srv.cfg + sudo echo "passphrase: $XCA_PASSPHRASE" >> examples/Docker/data/acme_srv.cfg + sudo echo "ca_cert_chain_list: [\"root-ca\"]" >> examples/Docker/data/acme_srv.cfg + sudo echo "template_name: $XCA_TEMPLATE" >> examples/Docker/data/acme_srv.cfg + sudo echo "eab_profiling: True" >> examples/Docker/data/acme_srv.cfg + sudo sed -i "s/tnauthlist_support: False/tnauthlist_support: False\nheader_info_list: [\"HTTP_USER_AGENT\"]/g" examples/Docker/data/acme_srv.cfg + sudo echo -e "\n\n[EABhandler]" >> examples/Docker/data/acme_srv.cfg + sudo echo "eab_handler_file: /var/www/acme2certifier/examples/eab_handler/kid_profile_handler.py" >> examples/Docker/data/acme_srv.cfg + sudo echo "key_file: volume/kid_profiles.json" >> examples/Docker/data/acme_srv.cfg + + sudo cp examples/eab_handler/kid_profiles.json examples/Docker/data/kid_profiles.json + sudo chmod 777 examples/eab_handler/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \[\"profile_1\", \"profile_2\", \"profile_3\"\]/\"template_name\"\: \"acme\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \"profile_2\"/\"template_name\"\: \"template\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca_2\",/\"issuing_ca_name\": \"root-ca\",\n \"issuing_ca_key\": \"root-ca\"/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca\",/\"unknown_key\": \"unknown_value\",/g" examples/Docker/data/kid_profiles.json + sudo sed -i "s/example.net/acme/g" examples/Docker/data/kid_profiles.json + sudo sed -i '19,20d' examples/Docker/data/kid_profiles.json + sudo sed -i '9d' examples/Docker/data/kid_profiles.json + sudo sed -i "s/\"api_user\"\: \"api_user\",/\"subject\"\: \{\n \"serialNumber\"\: \"*\",\n \"organizationName\"\: \"acme corp\",\n \"organizationalUnitName\"\: \[\"acme1\", \"acme2\"\],\n \"countryName\"\: \"AC\"\n \}/g" examples/Docker/data/kid_profiles.json + cd examples/Docker/ + docker-compose restart + env: + XCA_PASSPHRASE: ${{ secrets.XCA_PASSPHRASE }} + XCA_ISSUING_CA: ${{ secrets.XCA_ISSUING_CA }} + XCA_TEMPLATE: ${{ secrets.XCA_TEMPLATE }} + XCA_DB_NAME: ${{ secrets.XCA_DB_NAME }} + + - name: "EAB subject profiling - enrollment" + uses: ./.github/actions/wf_specific/xca_ca_handler/enroll_eab_sp + - name: "[ * ] collecting test logs" if: ${{ failure() }} run: | @@ -227,11 +274,11 @@ jobs: XCA_TEMPLATE: ${{ secrets.XCA_TEMPLATE }} XCA_DB_NAME: ${{ secrets.XCA_DB_NAME }} - - name: "Execute install scipt" + - name: "No template - Execute install scipt" run: | docker exec acme-srv sh /tmp/acme2certifier/rpm_tester.sh - - name: "Test enrollment" + - name: "No template - Test enrollment" uses: ./.github/actions/acme_clients - name: "No Template - enrollment" @@ -262,7 +309,7 @@ jobs: run: | docker exec acme-srv sh /tmp/acme2certifier/rpm_tester.sh restart - - name: "Test enrollment" + - name: "Template - Test enrollment" uses: ./.github/actions/acme_clients - name: "Template - enrollment" @@ -341,6 +388,52 @@ jobs: - name: "EAB - enrollment" uses: ./.github/actions/wf_specific/xca_ca_handler/enroll_eab + - name: "EAB subject profiling - Setup a2c with xca_ca_handler" + run: | + mkdir -p data/acme_ca + sudo cp test/ca/acme2certifier-clean.xdb data/acme_ca/$XCA_DB_NAME + sudo mkdir -p examples/Docker/data/acme_ca/certs + sudo cp test/ca/sub-ca-key.pem test/ca/sub-ca-crl.pem test/ca/sub-ca-cert.pem test/ca/root-ca-cert.pem data/acme_ca/ + sudo touch data/acme_srv.cfg + sudo chmod 777 data/acme_srv.cfg + sudo head -n -8 .github/openssl_ca_handler.py_acme_srv_default_handler.cfg > data/acme_srv.cfg + sudo echo "handler_file: /opt/acme2certifier/examples/ca_handler/xca_ca_handler.py" >> data/acme_srv.cfg + sudo echo "xdb_file: volume/acme_ca/$XCA_DB_NAME" >> data/acme_srv.cfg + sudo echo "issuing_ca_name: $XCA_ISSUING_CA" >> data/acme_srv.cfg + sudo echo "passphrase: $XCA_PASSPHRASE" >> data/acme_srv.cfg + sudo echo "ca_cert_chain_list: [\"root-ca\"]" >> data/acme_srv.cfg + sudo echo "template_name: $XCA_TEMPLATE" >> data/acme_srv.cfg + sudo echo "eab_profiling: True" >> data/acme_srv.cfg + sudo sed -i "s/tnauthlist_support: False/tnauthlist_support: False\nheader_info_list: [\"HTTP_USER_AGENT\"]/g" data/acme_srv.cfg + sudo echo -e "\n\n[EABhandler]" >> data/acme_srv.cfg + sudo echo "eab_handler_file: /opt/acme2certifier/examples/eab_handler/kid_profile_handler.py" >> data/acme_srv.cfg + sudo echo "key_file: /opt/acme2certifier/volume/acme_ca/kid_profiles.json" >> data/acme_srv.cfg + sudo cp examples/eab_handler/kid_profiles.json data/acme_ca/kid_profiles.json + sudo chmod 777 data/acme_ca/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \[\"profile_1\", \"profile_2\", \"profile_3\"\]/\"template_name\"\: \[\"template\", \"acme\"\]/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/\"profile_id\"\: \"profile_2\"/\"template_name\"\: \"template\"/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca_2\",/\"issuing_ca_name\": \"root-ca\",\n \"issuing_ca_key\": \"root-ca\"/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/\"ca_name\": \"example_ca\",/\"unknown_key\": \"unknown_value\",/g" data/acme_ca/kid_profiles.json + sudo sed -i "s/example.net/acme/g" data/acme_ca/kid_profiles.json + sudo sed -i '19,20d' data/acme_ca/kid_profiles.json + sudo sed -i '9d' data/acme_ca/kid_profiles.json + sudo sed -i "s/\"api_user\"\: \"api_user\",/\"subject\"\: \{\n \"serialNumber\"\: \"*\",\n \"organizationName\"\: \"acme corp\",\n \"organizationalUnitName\"\: \[\"acme1\", \"acme2\"\],\n \"countryName\"\: \"AC\"\n \}/g" data/acme_ca/kid_profiles.json + env: + XCA_PASSPHRASE: ${{ secrets.XCA_PASSPHRASE }} + XCA_ISSUING_CA: ${{ secrets.XCA_ISSUING_CA }} + XCA_TEMPLATE: ${{ secrets.XCA_TEMPLATE }} + XCA_DB_NAME: ${{ secrets.XCA_DB_NAME }} + + - name: "EAB subject profiling - Reconfigure a2c " + run: | + docker exec acme-srv sh /tmp/acme2certifier/rpm_tester.sh + docker exec acme-srv sh /tmp/acme2certifier/rpm_tester.sh restart + + - name: "EAB subject profiling - enrollment" + uses: ./.github/actions/wf_specific/xca_ca_handler/enroll_eab_sp + with: + DEPLOYMENT_TYPE: "rpm" + - name: "[ * ] collecting test logs" if: ${{ failure() }} run: | diff --git a/.github/workflows/codescanner.yml b/.github/workflows/codescanner.yml index 5d49a3e0..91e9748a 100644 --- a/.github/workflows/codescanner.yml +++ b/.github/workflows/codescanner.yml @@ -61,7 +61,7 @@ jobs: python -m pip install --upgrade pip pip install lxml beautifulsoup4 html5lib pip install pytest - pip install pytest-cov + pip install pytest-cov impacket if [ -f requirements.txt ]; then pip install -r requirements.txt; fi pytest --cov=./ --cov-report=xml @@ -94,7 +94,7 @@ jobs: - name: Install pytest coverage and any other packages run: | python -m pip install --upgrade pip - pip install pytest coverage + pip install pytest coverage impacket if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: run coverage diff --git a/.github/workflows/manual-install-test.yml b/.github/workflows/manual-install-test.yml index af3aca32..f42c3c1c 100644 --- a/.github/workflows/manual-install-test.yml +++ b/.github/workflows/manual-install-test.yml @@ -33,6 +33,8 @@ jobs: - name: "Local modification to get a2c running" run: | + sudo chmod a+w /etc/hosts + sudo echo ${{ env.RUNNER_IP }} acme-srv >> /etc/hosts sudo apt-get install -y socat sudo sed -i "s/Listen 80/Listen 8080/g" /etc/apache2/ports.conf sudo sed -i "s/Listen 443/Listen 1443/g" /etc/apache2/ports.conf @@ -49,7 +51,7 @@ jobs: - name: "Test enrollment" uses: ./.github/actions/acme_clients with: - ACME_SERVER: ${{ env.RUNNER_IP }} + ACME_SERVER: acme-srv HTTP_PORT: 8080 HTTPS_PORT: 1443 @@ -90,6 +92,8 @@ jobs: - name: "Local modification to get a2c running" run: | + sudo chmod a+w /etc/hosts + sudo echo ${{ env.RUNNER_IP }} acme-srv >> /etc/hosts sudo apt-get install -y socat sudo sed -i "s/listen 80/listen 8080/g" /etc/nginx/sites-enabled/acme_srv.conf sudo sed -i "s/listen [::]:80/listen [::]:8080/g" /etc/nginx/sites-enabled/acme_srv.conf @@ -107,7 +111,7 @@ jobs: - name: "Test enrollment" uses: ./.github/actions/acme_clients with: - ACME_SERVER: ${{ env.RUNNER_IP }} + ACME_SERVER: acme-srv HTTP_PORT: 8080 HTTPS_PORT: 1443 @@ -284,6 +288,8 @@ jobs: - name: "Modfiy configuration to allow certifiate enrollment" run: | + sudo chmod a+w /etc/hosts + sudo echo ${{ env.RUNNER_IP }} acme-srv >> /etc/hosts # sudo apt-get install -y socat sudo sed -i "s/Listen 80/Listen 8080/g" /etc/apache2/ports.conf sudo sed -i "s/Listen 443/Listen 1443/g" /etc/apache2/ports.conf @@ -300,7 +306,7 @@ jobs: - name: "Test enrollment" uses: ./.github/actions/acme_clients with: - ACME_SERVER: ${{ env.RUNNER_IP }} + ACME_SERVER: acme-srv HTTP_PORT: 8080 HTTPS_PORT: 1443 @@ -403,6 +409,8 @@ jobs: - name: "Modfiy configuration to allow certifiate enrollment" run: | + sudo chmod a+w /etc/hosts + sudo echo ${{ env.RUNNER_IP }} acme-srv >> /etc/hosts sudo sed -i "s/listen 80/listen 8080/g" /etc/nginx/sites-enabled/acme_srv.conf sudo sed -i "s/listen [::]:80/listen [::]:8080/g" /etc/nginx/sites-enabled/acme_srv.conf sudo sed -i "s/listen 443/listen 1443/g" /etc/nginx/sites-enabled/acme_srv_ssl.conf @@ -418,7 +426,7 @@ jobs: - name: "Test enrollment" uses: ./.github/actions/acme_clients with: - ACME_SERVER: ${{ env.RUNNER_IP }} + ACME_SERVER: acme-srv HTTP_PORT: 8080 HTTPS_PORT: 1443 diff --git a/.github/workflows/python-test.yml b/.github/workflows/python-test.yml index dcedc089..985ac1f3 100644 --- a/.github/workflows/python-test.yml +++ b/.github/workflows/python-test.yml @@ -33,7 +33,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - pip install pytest + pip install pytest impacket if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - name: cp diff --git a/.gitignore b/.gitignore index da25b0d5..dfad8fb0 100644 --- a/.gitignore +++ b/.gitignore @@ -143,6 +143,7 @@ acme_srv/ejbca/* acme_srv/ssl/* acme_srv/cn_dump/* acme_srv/fixture +acme_srv/entrust/* *.dll acme_srv/cmp/WindowsCMPOpenSSL/openssl.exe acme_srv/migrations.old diff --git a/CHANGES.md b/CHANGES.md index 3d7e3da2..f7d16b55 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,28 @@ This is a high-level summary of the most important changes. For a full list of changes, see the [git commit log](https://github.com/grindsa/acme2certifier/commits) and pick the appropriate release branch. +# Changes in 0.36 + +**Features and Improvements**: + +- [ca handler](docs/digicert.md) using the [DigiCert CertCentral API](https://dev.digicert.com/en/certcentral-apis.html) +- [ca handler](docs/entrust.md) using the Entrust ECS Enterprise APIl +- [EAB Profiling support](docs/eab_profiling.md) in Microsoft CA handlers +- [#187](https://github.com/grindsa/acme2certifier/pull/187) url option for mscertsrv ca handler +- subject profiling feature +- [strip down python-impacket module](https://github.com/grindsa/acme2certifier/blob/master/docs/mswcce.md#local-installation) in docker images +- [strip down impacket RPM package](https://github.com/grindsa/sbom/tree/main/rpm-repo/RPMs/rhel9) +- YAML config file format supported in [EAB-Profiling feature](docs/eab_profiling.md) +- Upgrade Container images to Ubuntu 24.04 + +**Bugfixes**: + +- openssl-ca-handler: basicConstraints extension will not be marked as critical anymore +- openssl-ca-handler: subjectkeyidentifier extension will not be marked as critical anymore +- fall-back option to python-openssl for Redhat deployments +- detect and handle django installations on Debian/Ubunto systems +- automated schema updates in case of RPM updates + # Changes in 0.35 **Features and Improvements**: diff --git a/README.md b/README.md index d8964c4b..1762a642 100644 --- a/README.md +++ b/README.md @@ -21,19 +21,24 @@ on [rfc8555](https://tools.ietf.org/html/rfc8555) - ca_handler.py - interface towards CA server. The intention of this library is to be modular that an [adaption to other CA servers](docs/ca_handler.md) should be straight forward. As of today the following handlers are available: - - [NetGuard Certificate Manager/Insta Certifier](docs/certifier.md) - - [NetGuard Certificate Lifecycle Manager](docs/nclm.md) - - [Insta ActiveCMS](docs/asa.md) - - [EJBCA](docs/ejbca.md) - - [OpenXPKI](docs/openxpki.md) - - [Microsoft Certificate Enrollment Web Services](docs/mscertsrv.md) - - [Microsoft Windows Client Certificate Enrollment Protocol (MS-WCCE) via RPC/DCOM](docs/mswcce.md) - - [Generic ACME protocol handler supporting Letsencrypt, BuyPass.com and ZeroSSL](docs/acme_ca.md) - - [Generic EST protocol handler](docs/est.md) - - [Generic CMPv2 protocol handler](docs/cmp.md) - - [Openssl](docs/openssl.md) - - [XCA](docs/xca.md) - - [acme2dfn](https://github.com/pfisterer/acme2dfn) (external; ACME proxy for the [German research network's PKI](https://www.pki.dfn.de/ueberblick-dfn-pki/) + +| E - Certificte Enrollment, R - Certificte Revocation, P - [EAB Profiling](docs/eab_profiling.md) |E|R|P| +| :-------- | - | - | - | +| [DigiCert® CertCentral](docs/digicert.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| [Entrust ECS Enterprise](docs/entrust.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| [EJBCA](docs/ejbca.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| [Generic ACME protocol handler supporting Letsencrypt, BuyPass.com and ZeroSSL](docs/acme_ca.md) | :x: | :x: | :white_check_mark: | +| [Generic CMPv2 protocol handler](docs/cmp.md) | :white_check_mark: | :x: | :x: | +| [Generic EST protocol handler](docs/est.md) | :white_check_mark: | :x: | :x: | +| [Insta ActiveCMS](docs/asa.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| [Microsoft Certificate Enrollment Web Services](docs/mscertsrv.md) | :white_check_mark: | :x: | :white_check_mark: | +| [Microsoft Windows Client Certificate Enrollment Protocol (MS-WCCE) via RPC/DCOM](docs/mswcce.md) | :white_check_mark: | :x: | :white_check_mark: | +| [NetGuard Certificate Lifecycle Manager](docs/nclm.md) | :white_check_mark: | :white_check_mark: | :x: | +| [NetGuard Certificate Manager/Insta Certifier](docs/certifier.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| [Openssl](docs/openssl.md) | :white_check_mark: | :white_check_mark: | :x: | +| [OpenXPKI](docs/openxpki.md) | :white_check_mark: | :white_check_mark: | :x: | +| [XCA](docs/xca.md) | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| [acme2dfn](https://github.com/pfisterer/acme2dfn) (external; ACME proxy for the [German research network's PKI](https://www.pki.dfn.de/ueberblick-dfn-pki/)| :white_check_mark: | :x: | :x: | For more up-to-date information and further documentation, please visit the project's home page at: [https://github.com/grindsa/acme2certifier](https://github.com/grindsa/acme2certifier) diff --git a/SECURITY.md b/SECURITY.md index 635491de..3f6ed588 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -6,9 +6,9 @@ | Version | Supported | | ------- | ------------------ | +| 0.36.x | :white_check_mark: | | 0.35.x | :white_check_mark: | -| 0.34.x | :white_check_mark: | -| < 0.34 | :x: | +| < 0.35 | :x: | ## Reporting a Vulnerability diff --git a/acme_srv/helper.py b/acme_srv/helper.py index c3fbaf72..32876138 100644 --- a/acme_srv/helper.py +++ b/acme_srv/helper.py @@ -437,6 +437,7 @@ def cert_ski_get(logger: logging.Logger, certificate: str) -> str: def cryptography_version_get(logger: logging.Logger) -> int: """ get version number of cryptography module """ logger.debug('Helper.cryptography_version_get()') + # pylint: disable=c0415 import cryptography try: @@ -484,7 +485,7 @@ def cert_extensions_py_openssl_get(logger, certificate, recode=True): ext = cert.get_extension(i) extension_list.append(convert_byte_to_string(base64.b64encode(ext.get_data()))) - logger.debug('cert_extensions_py_openssl_get() ended with: {0}'.format(extension_list)) + logger.debug('cert_extensions_py_openssl_get() ended with: %s', extension_list) return extension_list @@ -650,6 +651,22 @@ def csr_extensions_get(logger: logging.Logger, csr: str) -> List[str]: return extension_list +def csr_subject_get(logger: logging.Logger, csr: str) -> Dict[str, str]: + """ get subject from csr as a list of tuples """ + logger.debug('Helper.csr_subject_get()') + # pylint: disable=w0212 + + csr_obj = csr_load(logger, csr) + subject_dic = {} + # get subject and look for common name + subject = csr_obj.subject + for attr in subject: + subject_dic[attr.oid._name] = attr.value + + logger.debug('Helper.csr_subject_get() ended') + return subject_dic + + def decode_deserialize(logger: logging.Logger, string: str) -> Dict: """ decode and deserialize string """ logger.debug('Helper.decode_deserialize()') @@ -814,14 +831,14 @@ def header_info_lookup(logger, csr: str, header_info_field, key: str) -> str: return result -def header_info_get(logger: logging.Logger, csr: str, vlist: List[str] = ('id', 'name', 'header_info')) -> List[str]: +def header_info_get(logger: logging.Logger, csr: str, vlist: List[str] = ('id', 'name', 'header_info'), field_name: str = 'csr') -> List[str]: """ lookup header information """ logger.debug('Helper.header_info_get()') try: from acme_srv.db_handler import DBstore # pylint: disable=c0415 dbstore = DBstore(logger=logger) - result = dbstore.certificates_search('csr', csr, vlist) + result = dbstore.certificates_search(field_name, csr, vlist) except Exception as err: result = [] logger.error('Helper.header_info_get(): error: %s', err) @@ -1708,6 +1725,75 @@ def eab_profile_header_info_check(logger: logging.Logger, cahandler, csr: str, h return error +def cn_validate(logger: logging.Logger, cn: str) -> bool: + """ validate common name """ + logger.debug('Helper.cn_validate(%s)', cn) + + error = False + if cn: + # check if CN is a valid IP address + result = validate_ip(logger, cn) + if not result: + # check if CN is a valid fqdn + result = validate_fqdn(logger, cn) + if not result: + error = 'Profile subject check failed: CN validation failed' + else: + error = 'Profile subject check failed: commonName missing' + + logger.debug('Helper.cn_validate() ended with: %s', error) + return error + + +def eab_profile_subject_string_check(logger: logging.Logger, profile_subject_dic, key: str, value: str) -> str: + """ check if a for a string value taken from profile if its a variable inside a class and apply value """ + logger.debug('Helper.eab_profile_subject_string_check(): string: key: %s, value: %s', key, value) + + error = False + if key == 'commonName': + # check if CN is a valid IP address or fqdn + error = cn_validate(logger, value) + elif key in profile_subject_dic: + if isinstance(profile_subject_dic[key], str) and (value == profile_subject_dic[key] or profile_subject_dic[key] == '*'): + logger.debug('Helper.eab_profile_subject_check() successul for string : %s', key) + del profile_subject_dic[key] + elif isinstance(profile_subject_dic[key], list) and value in profile_subject_dic[key]: + logger.debug('Helper.eab_profile_subject_check() successul for list : %s', key) + del profile_subject_dic[key] + else: + logger.error('Helper.eab_profile_subject_check() failed for: %s: value: %s expected: %s', key, value, profile_subject_dic[key]) + error = f'Profile subject check failed for {key}' + else: + logger.error('Helper.eab_profile_subject_check() failed for: %s', key) + error = f'Profile subject check failed for {key}' + + logger.debug('Helper.eab_profile_subject_string_check() ended') + return error + + +def eab_profile_subject_check(logger: logging.Logger, csr: str, profile_subject_dic: str) -> str: + """ check subject against profile information""" + logger.debug('Helper.eab_profile_subject_check()') + error = None + + # get subject from csr + subject_dic = csr_subject_get(logger, csr) + + # check if all profile subject entries are in csr + for key, value in subject_dic.items(): + error = eab_profile_subject_string_check(logger, profile_subject_dic, key, value) + if error: + break + + # check if we have any entries left in the profile_subject_dic + if not error and profile_subject_dic: + logger.error('Helper.eab_profile_subject_check() failed for: %s', list(profile_subject_dic.keys())) + error = 'Profile subject check failed' + + logger.debug('Helper.eab_profile_subject_check() ended with: %s', error) + return error + + def eab_profile_check(logger: logging.Logger, cahandler, csr: str, handler_hifield: str) -> str: """ check eab profile""" logger.debug('Helper.eab_profile_check()') @@ -1716,7 +1802,9 @@ def eab_profile_check(logger: logging.Logger, cahandler, csr: str, handler_hifie with cahandler.eab_handler(logger) as eab_handler: eab_profile_dic = eab_handler.eab_profile_get(csr) for key, value in eab_profile_dic.items(): - if isinstance(value, str): + if key == 'subject': + result = eab_profile_subject_check(logger, csr, value) + elif isinstance(value, str): eab_profile_string_check(logger, cahandler, key, value) elif isinstance(value, list): # check if we need to execute a function from the handler @@ -1724,8 +1812,8 @@ def eab_profile_check(logger: logging.Logger, cahandler, csr: str, handler_hifie result = cahandler.eab_profile_list_check(eab_handler, csr, key, value) else: result = eab_profile_list_check(logger, cahandler, eab_handler, csr, key, value) - if result: - break + if result: + break # we need to reject situations where profiling is enabled but the header_hifiled is not defined in json if cahandler.header_info_field and handler_hifield not in eab_profile_dic: diff --git a/docs/digicert.md b/docs/digicert.md new file mode 100644 index 00000000..e3bf9687 --- /dev/null +++ b/docs/digicert.md @@ -0,0 +1,116 @@ + + +# Connecting to DigiCert CertCentral + +This handler can be used to enroll certificates from [DigiCert CertCentral](https://dev.digicert.com/en/certcentral-apis.html). + +## Prerequisites + +- you'll need: + - a DigiCert CertCentral subscription :-) + - an [API-Key](https://dev.digicert.com/en/certcentral-apis/authentication.html) for Authentication and Authorization + - an [Organization](https://dev.digicert.com/en/certcentral-apis/services-api/organizations.html) + - a [whitelisted domain](https://dev.digicert.com/en/certcentral-apis/services-api/domains.html) + +## Configuration + +- modify the server configuration (`acme_srv.cfg`) and add the first thre of the below mentioned parameters + +```confag +[CAhandler] +handler_file: examples/ca_handler/digicert_ca_handler.py +api_key: +organization_name: + +allowed_domainlist: +api_url: +organization_id: +cert_type: +signature_hash: +order_validity: +request_timeout: +eab_profiling: +``` + +- api_key - required - API key to access the API +- organization_name - required - Organization name as specified in DigiCert CertCentral +- allowed_domainlist: list of domain-names allowed for enrollment in json format (example: ["bar.local$, bar.foo.local]) +- api_url - optional - URL of the CertCentral API +- organization_id - optional - organization id - configuration prevents additional rest-lookups +- cert_type - optional - [certificte type](https://dev.digicert.com/en/certcentral-apis/services-api/orders.html) to be isused. (default: ssl_basic) +- signature_hash - optional - hash algorithm used for certificate signing - (default: sha256) +- order_validity - optional - oder validity (default: 1 year) +- request_timeout - optional - requests timeout in seconds for requests (default: 5s) +- eab_profiling - optional - [activate eab profiling](eab_profiling.md) (default: False) + +Use your favorite acme client for certificate enrollment. A list of clients used in our regression can be found in the [disclaimer section of our README file](../README.md) + +*Important:* the DigiCert API expectes a CommonName to be set. Hence, certbot cannot be used for certificate enrollment. + +## Passing a cert_type from client to server + +The handler makes use of the [header_info_list feature](header_info.md) allowing an acme-client to specify a [certificate type](https://dev.digicert.com/en/certcentral-apis/services-api/orders.html) to be used during certificate enrollment. This feature is disabled by default and must be activate in `acme_srv.cfg` as shown below + +```config +[Order] +... +header_info_list: ["HTTP_USER_AGENT"] +``` + +The acme-client can then specify the cert_type as part of its user-agent string. + +Example for acme.sh: + +```bash +docker exec -i acme-sh acme.sh --server http:// --issue -d --standalone --useragent cert_type=ssl_securesite_pro --debug 3 --output-insecure +``` + +Example for lego: + +```bash +docker run -i -v $PWD/lego:/.lego/ --rm --name lego goacme/lego -s http:// -a --email "lego@example.com" --user-agent cert_type=ssl_securesite_pro -d --http run +``` + +# eab profiling + +This handler can use the [eab profiling feture](eab_profiling.md) to allow individual enrollment configuration per acme-account as well as restriction of CN and SANs to be submitted within the CSR. The feature is disabled by default and must be activated in `acme_srv.cfg` + +```cfg +[EABhandler] +eab_handler_file: examples/eab_handler/kid_profile_handler.py +key_file: + +[CAhandler] +eab_profiling: True +``` + +below an example key-file used during regression testing: + +```json +{ + "keyid_00": { + "hmac": "V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw", + "cahandler": { + "cert_type": ["ssl_basic", "ssl_securesite_pro", "ssl_securesite_flex"], + "allowed_domainlist": ["www.example.com", "www.example.org", "*.acme"], + "organization_name": "acme2certifier" + } + }, + "keyid_01": { + "hmac": "YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg", + "cahandler": { + "allowed_domainlist": ["www.example.com", "www.example.org", "*.acme"], + "cert_type": "ssl_securesite_pro" + } + }, + "keyid_02": { + "hmac": "dGhpc19pc19hX3ZlcnlfbG9uZ19obWFjX3RvX21ha2Vfc3VyZV90aGF0X2l0c19tb3JlX3RoYW5fMjU2X2JpdHM", + "cahandler": { + "allowed_domainlist": ["www.example.com", "www.example.org"] + } + }, + "keyid_03": { + "hmac": "YW5kX2ZpbmFsbHlfdGhlX2xhc3RfaG1hY19rZXlfd2hpY2hfaXNfbG9uZ2VyX3RoYW5fMjU2X2JpdHNfYW5kX3Nob3VsZF93b3Jr" + } +} +``` diff --git a/docs/eab_profiling.md b/docs/eab_profiling.md index a5a27c16..02fa0fbe 100644 --- a/docs/eab_profiling.md +++ b/docs/eab_profiling.md @@ -26,12 +26,12 @@ eab_handler_file: examples/eab_handler/kid_profile_handler.py key_file: volume/kid_profiles.json ``` -The `key_file` allows the specification enrollmenmt parameters per (external) acme-account. Main identifier is the key_id to be used during account registration. Any parameter used in the [CAhandler] configuration section of a handler can be customized. Below an example configuration to be used for [Insta Certifier](certifier.md) with some explaination: +The `key_file` allows the specification enrollmenmt parameters per (external) acme-account. Main identifier is the key_id to be used during account registration. Any parameter used in the [CAhandler] configuration section of a handler can be customized. Below an example configuration to be used for [Insta Certifier](certifier.md) with some explanation: ```json { "keyid_00": { - "hmac": "V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw", + "hmac": "hmac-key", "cahandler": { "profile_id": "profile_1", "allowed_domainlist": ["*.example.com", "*.example.org", "*.example.fi"], @@ -41,14 +41,14 @@ The `key_file` allows the specification enrollmenmt parameters per (external) ac } }, "keyid_01": { - "hmac": "YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg", + "hmac": "hmac-key", "cahandler": { "profile_id": ["profile_1", "profile_2", "profile_3"], - "allowed_domainlist": ["*.example.fi", "*.acme"], + "allowed_domainlist": ["*.example.fi", "*.acme"] } }, "keyid_02": { - "hmac": "YW5kX2ZpbmFsbHlfdGhlX2xhc3RfaG1hY19rZXlfd2hpY2hfaXNfbG9uZ2VyX3RoYW5fMjU2X2JpdHNfYW5kX3Nob3VsZF93b3Jr" + "hmac": "hmac-key" } } ``` @@ -57,6 +57,75 @@ The `key_file` allows the specification enrollmenmt parameters per (external) ac - Acme-accounts created with keyid "keyid_01" and can specify 3 different profile_ids by using the [header_info feature](header_info.md). Enrollment requests having other profile_ids will be rejected. In case no profile_id get specified the first profile_id in the list ("profile_1") will be used. SAN/CNs to be used are restricted to "example.fi" and ".local" All other enrollment paramters will be taken from acme_srv.cfg - Acme-accounts created with keyid "keyid_02" do not have any restriction. Enrolment parameters will be taken from the [CAhandler] section in ´acme_srv.cfg` +Starting from v0.36 acme2certifier does support profile configuration in yaml format. Below a configuration example providing the same level of functionality than the above json configuration + +```yaml +--- +{ +--- +keyid_00: + hmac: "hmac-key" + cahandler: + profile_id: "profile_1" + allowed_domainlist: + - "*.example.com" + - "*.example.org" + - "*.example.fi" + ca_name: "non_default_ca" + api_user: "non_default_api_user" + api_password: "api_password" +keyid_01: + hmac: "hmac-key" + cahandler: + profile_id: + - "profile_1" + - "profile_2" + - "profile_3" + allowed_domainlist: + - "*.example.fi" + - "*.acme" +keyid_02: + hmac: "hmac-key" +``` + +## subject profiling + +Starting from v0.36 the eab-profiling feature can be used to check and white-list the certificate subject DN. + +Attribute names must follow [RFC3039](https://www.rfc-editor.org/rfc/rfc3039.html#section-3.1.2); every RDN can be white-listed as: + +- string - attribute in CSR DN must match this value +- list - attribute in CSR DN must match one of the list entries +- "*" - any value matches as long as the attribute is present + +The below example configuration will only allow CSR matching the following ciriterias: + +- serial number can be of any value but must be included +- organizationalUnitName must be either "acme1" or "acme2" +- organizationName must be "acme corp" +- countryName must be "AC" +- additional CSR DN such as localityName or stateOrProvinceName are not allowed + +```json +... +{ + "keyid_00": { + "hmac": "hmac-key", + "cahandler": { + "template_name": ["template", "acme"], + "allowed_domainlist": ["www.example.com", "www.example.org", "*.acme"], + "subject": { + "serialNumber": "*", + "organizationName": "acme corp", + "organizationalUnitName": ["acme1", "acme2"], + "countryName": "AC" + } + } + } +} +... +``` + ## Profile verification In the keyfile can be checked for consistency by using the `tools/eab_chk.py` utility. diff --git a/docs/entrust.md b/docs/entrust.md new file mode 100644 index 00000000..9fbc2837 --- /dev/null +++ b/docs/entrust.md @@ -0,0 +1,114 @@ + + +# Connecting to Entrust ECS Enterprise + +This handler can be used to enroll certificates from Entrust ECS Enterprise API. + +## Prerequisites + +- you'll need: + - Username and Password for HTTP-BASIC authentication + - if configured - a client certificate for mutual TLS authentication towards the Entrust RESt API + - an pre-validated Organization name + +## Configuration + +- modify the server configuration (`acme_srv.cfg`) and add the first thre of the below mentioned parameters + +```confag +[CAhandler] +handler_file: examples/ca_handler/entrust_ca_handler.py +username: +password: +certtype: +organization_name: + +client_cert: +cert_passphrase: +cert_validity_days: +allowed_domainlist: +request_timeout: +eab_profiling: +``` + +- username - required - username access the API +- password - required - password to access the PI +- organization_name - required - Organization name as specified in DigiCert CertCentral +- client_cert - optional - client certificate to access the API (to be stored in either pem or pkcs#12 format) +- client_key - optional - client private key to access the API (must be stored in pem format) +- client_passphrase - passphrase to access the client_cert (if stored in pkcs#2 format) +- cert_type - optional - certificate type to be isused. (default: STANDARD_SSL) +- cert_validity_days - certificate validity in days (default: 365) +- allowed_domainlist: list of domain-names allowed for enrollment in json format (example: ["bar.local$, bar.foo.local]) +- request_timeout - optional - requests timeout in seconds for requests (default: 5s) +- eab_profiling - optional - [activate eab profiling](eab_profiling.md) (default: False) + +Use your favorite acme client for certificate enrollment. A list of clients used in our regression can be found in the [disclaimer section of our README file](../README.md) + +## Passing a cert_type from client to server + +The handler makes use of the [header_info_list feature](header_info.md) allowing an acme-client to specify a certificate type to be used during certificate enrollment. This feature is disabled by default and must be activate in `acme_srv.cfg` as shown below + +```config +[Order] +... +header_info_list: ["HTTP_USER_AGENT"] +``` + +The acme-client can then specify the cert_type as part of its user-agent string. + +Example for acme.sh: + +```bash +docker exec -i acme-sh acme.sh --server http:// --issue -d --standalone --useragent cert_type=ADVANTAGE_SSL --debug 3 --output-insecure +``` + +Example for lego: + +```bash +docker run -i -v $PWD/lego:/.lego/ --rm --name lego goacme/lego -s http:// -a --email "lego@example.com" --user-agent cert_type=ADVANTAGE_SSL -d --http run +``` + +# eab profiling + +This handler can use the [eab profiling feture](eab_profiling.md) to allow individual enrollment configuration per acme-account as well as restriction of CN and SANs to be submitted within the CSR. The feature is disabled by default and must be activated in `acme_srv.cfg` + +```cfg +[EABhandler] +eab_handler_file: examples/eab_handler/kid_profile_handler.py +key_file: + +[CAhandler] +eab_profiling: True +``` + +below an example key-file used during regression testing: + +```json +{ + "keyid_00": { + "hmac": "V2VfbmVlZF9hbm90aGVyX3ZlcnkfX2xvbmdfaG1hY190b19jaGVja19lYWJfZm9yX2tleWlkXzAwX2FzX2xlZ29fZW5mb3JjZXNfYW5faG1hY19sb25nZXJfdGhhbl8yNTZfYml0cw", + "cahandler": { + "cert_type": ["ADVANTAGE_SSL", "STANDARD_PLUS_SSL", "WILDCARD_SSL"], + "allowed_domainlist": ["www.example.com", "www.example.org", "*.acme"], + "organization_name": "acme2certifier" + } + }, + "keyid_01": { + "hmac": "YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg", + "cahandler": { + "allowed_domainlist": ["www.example.com", "www.example.org", "*.acme"], + "cert_type": "ADVANTAGE_SSL" + } + }, + "keyid_02": { + "hmac": "dGhpc19pc19hX3ZlcnlfbG9uZ19obWFjX3RvX21ha2Vfc3VyZV90aGF0X2l0c19tb3JlX3RoYW5fMjU2X2JpdHM", + "cahandler": { + "allowed_domainlist": ["www.example.com", "www.example.org"] + } + }, + "keyid_03": { + "hmac": "YW5kX2ZpbmFsbHlfdGhlX2xhc3RfaG1hY19rZXlfd2hpY2hfaXNfbG9uZ2VyX3RoYW5fMjU2X2JpdHNfYW5kX3Nob3VsZF93b3Jr" + } +} +``` diff --git a/docs/install_rpm.md b/docs/install_rpm.md index b8d33c6f..5443d77d 100644 --- a/docs/install_rpm.md +++ b/docs/install_rpm.md @@ -31,7 +31,7 @@ Backports of these packages being part of RHEL9 can be found in the [the a2c rpm Depending on your ca_handler you may need additional modules: -- [python3-impacket-0.11.0-1.el8.noarch.rpm](https://github.com/grindsa/sbom/raw/main/rpm-repo/RPMs/rhel8/python3-impacket-0.11.0-1.el8.noarch.rpm) when using [MS wcce handler](https://github.com/grindsa/acme2certifier/blob/master/docs/mswcce.md) +- [python3-impacket-0.11.0-1.el8.noarch.rpm](https://github.com/grindsa/sbom/raw/main/rpm-repo/RPMs/rhel8/python3-impacket-0.11.0-2grindsa.el8.noarch.rpm) when using [MS wcce handler](https://github.com/grindsa/acme2certifier/blob/master/docs/mswcce.md) - [python3-ntlm-auth-1.5.0-2.el8.noarch.rpm](https://github.com/grindsa/sbom/raw/main/rpm-repo/RPMs/rhel8/python3-ntlm-auth-1.5.0-2.el8.noarch.rpm) when using [MS wse handler](https://github.com/grindsa/acme2certifier/blob/master/docs/mscertsrv.md) - [python3-requests_ntlm-1.1.0-14.el8.noarch.rpm](https://github.com/grindsa/sbom/raw/main/rpm-repo/RPMs/rhel8/python3-requests_ntlm-1.1.0-14.el8.noarch.rpm) when using [MS wse handler](https://github.com/grindsa/acme2certifier/blob/master/docs/mscertsrv.md) - [python3-requests-pkcs12-1.16-1.el8.noarch.rpm](https://github.com/grindsa/sbom/raw/main/rpm-repo/RPMs/rhel8/python3-requests-pkcs12-1.16-1.el8.noarch.rpm) when using [EST](https://github.com/grindsa/acme2certifier/blob/master/docs/est.md) or [EJBCA](https://github.com/grindsa/acme2certifier/blob/master/docs/ejbca.md) handler diff --git a/docs/mswcce.md b/docs/mswcce.md index 3b63b084..5483001d 100644 --- a/docs/mswcce.md +++ b/docs/mswcce.md @@ -16,14 +16,42 @@ When using the handler please be aware of the following limitations: 3. (optional): In case you are installing from RPM or DEB and plan to use kerberos authentication you need an updated [impacket modules of version 0.11 or higher](https://github.com/fortra/impacket) as older versions have issues with the handling of utf8-encoded passwords. If you have no clue from where to get these packaages feel free to use the one being part of [the a2c github repository](https://github.com/grindsa/sbom/tree/main/rpm-repo/RPMs) 4. You need to have a set of credentials with permissions to access the service and enrollment templates -## Installation +## Local Installation -- install the [impacket](https://github.com/SecureAuthCorp/impacket) via pip (the module is already part of the docker images) +- install the [impacket](https://github.com/fortra/impacket) module + +*IMPORTANT*: + +Some malware scanners like Microsoft Defender classify the impacket module as hacking-tool (see [forta/impacket#1762](https://github.com/fortra/impacket/issues/1762) or [forta/impacket#1271](https://github.com/fortra/impacket/issues/1271#issuecomment-1058729047)). Main reason for the alarms are not the library itself but rather the example script coming along with it. To avoid hazzle with your CSIRT team I suggest to install a strip-down version of impacket which which do not contain the scripts flagged by the scanners. Packages for [RH8](https://github.com/grindsa/sbom/raw/main/rpm-repo/RPMs/rhel8/python3-impacket-0.11.0-2grindsa.el8.noarch.rpm) and [RH9](https://github.com/grindsa/sbom/raw/main/rpm-repo/RPMs/rhel9/python3-impacket-0.11.0-2grindsa.el9.noarch.rpm) can be found in my [SBOM repo](https://github.com/grindsa/sbom/tree/main/rpm-repo) + +In case you install impacket from pip or form sources I suggest to: + +- download the impacket package: ```bash -root@rlh:~# pip install impacket +pip3 download impacket --no-deps ``` +- unpack the archive + +```bash + tar xvfz impacket-0.11.0.tar.gz +``` + +- delete all files and subdirectories in `examples` sub-directory + +```bash +rm -rf impacket-0.11.0/examples/* +``` + +- install the package + +```bash +python3 setup.py install +``` + +## Configuration + - modify the server configuration (acme_srv/acme_srv.cfg) and add the following parameters ```config diff --git a/examples/Docker/almalinux-systemd/Dockerfile b/examples/Docker/almalinux-systemd/Dockerfile index 9cdd452b..d263a374 100644 --- a/examples/Docker/almalinux-systemd/Dockerfile +++ b/examples/Docker/almalinux-systemd/Dockerfile @@ -1,15 +1,15 @@ FROM almalinux:9 ENV container docker -RUN (cd /lib/systemd/system/sysinit.target.wants/; for i in ; do [ "$i" == systemd-tmpfiles-setup.service ] || rm -f "$i"; done); +WORKDIR /lib/systemd/system/sysinit.target.wants/ +RUN for i in ; do [ "$i" == systemd-tmpfiles-setup.service ] || rm -f "$i"; done && \ + rm -rf /lib/systemd/system/multi-user.target.wants/ && \ + rm -rf /etc/systemd/system/.wants/ && \ + rm -rf /lib/systemd/system/local-fs.target.wants/ && \ + rm -f /lib/systemd/system/sockets.target.wants/udev && \ + rm -f /lib/systemd/system/sockets.target.wants/initctl && \ + rm -rf /lib/systemd/system/basic.target.wants/ && \ + rm -f /lib/systemd/system/anaconda.target.wants/* -RUN rm -rf /lib/systemd/system/multi-user.target.wants/ \ -&& rm -rf /etc/systemd/system/.wants/ \ -&& rm -rf /lib/systemd/system/local-fs.target.wants/ \ -&& rm -f /lib/systemd/system/sockets.target.wants/udev \ -&& rm -f /lib/systemd/system/sockets.target.wants/initctl \ -&& rm -rf /lib/systemd/system/basic.target.wants/ \ -&& rm -f /lib/systemd/system/anaconda.target.wants/* - -VOLUME [ “/sys/fs/cgroup” ] +# VOLUME [ “/sys/fs/cgroup” ] CMD ["/usr/sbin/init"] diff --git a/examples/Docker/apache2/django/Dockerfile b/examples/Docker/apache2/django/Dockerfile index c6be88ec..4159c0d2 100644 --- a/examples/Docker/apache2/django/Dockerfile +++ b/examples/Docker/apache2/django/Dockerfile @@ -8,19 +8,19 @@ ENV APACHE_LOG_DIR /var/log/apache2 RUN apt-get update && \ DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends -y tzdata && \ DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y \ - python3-pip \ apache2 \ apache2-data \ - libapache2-mod-wsgi-py3 \ curl \ krb5-user \ + libapache2-mod-wsgi-py3 \ libgssapi-krb5-2 \ libkrb5-3 \ - python3-gssapi \ python3-django \ + python3-gssapi \ python3-mysqldb \ - python3-pymysql \ + python3-pip \ python3-psycopg2 \ + python3-pymysql \ python3-yaml \ && rm -rf /var/lib/apt/lists/* &&\ mkdir -p /var/www/acme2certifier/volume && \ @@ -29,13 +29,24 @@ RUN apt-get update && \ COPY ./ /var/www/acme2certifier/ # configure acme2certifier -RUN pip3 install -r /var/www/acme2certifier/requirements.txt --break-system-packages && \ +RUN pip3 install impacket --break-system-packages && \ + rm /usr/local/bin/*.py && \ + rm -rf /usr/local/lib/python3.12/dist-packages/impacket/examples/* && \ + pip3 install -r /var/www/acme2certifier/requirements.txt --break-system-packages && \ cp /var/www/acme2certifier/examples/apache2/apache_django.conf /etc/apache2/sites-enabled/acme2certifier.conf && \ cp -R /var/www/acme2certifier/examples/django/* /var/www/acme2certifier/ && \ cp /var/www/acme2certifier/examples/db_handler/django_handler.py /var/www/acme2certifier/acme_srv/db_handler.py && \ - rm /var/www/acme2certifier/CHANGES.md /var/www/acme2certifier/README.md /var/www/acme2certifier/SECURITY.md /var/www/acme2certifier/setup.py /var/www/acme2certifier/requirements.txt && \ + rm /var/www/acme2certifier/CHANGES.md && \ + rm /var/www/acme2certifier/README.md && \ + rm /var/www/acme2certifier/SECURITY.md && \ + rm /var/www/acme2certifier/setup.py && \ + rm /var/www/acme2certifier/requirements.txt && \ cp /var/www/acme2certifier/examples/Docker/apache2/django/docker-entrypoint.sh /docker-entrypoint.sh && \ - rm -rf /var/www/acme2certifier/examples/Docker /var/www/acme2certifier/examples/db_handler /var/www/acme2certifier/examples/nginx /var/www/acme2certifier/examples/acme_srv.db.example /var/www/acme2certifier/examples/acme2certifier_wsgi.py && \ + rm -rf /var/www/acme2certifier/examples/Docker && \ + rm -rf /var/www/acme2certifier/examples/db_handler && \ + rm -rf /var/www/acme2certifier/examples/nginx && \ + rm -rf /var/www/acme2certifier/examples/acme_srv.db.example && \ + rm -rf /var/www/acme2certifier/examples/acme2certifier_wsgi.py && \ rm /var/www/acme2certifier/acme2certifier/settings.py && \ chown -R www-data:www-data /var/www/acme2certifier/ && \ sed -i "s/default = default_sect/\default = default_sect\nlegacy = legacy_sect/g" /etc/ssl/openssl.cnf && \ diff --git a/examples/Docker/apache2/wsgi/Dockerfile b/examples/Docker/apache2/wsgi/Dockerfile index 035de9f9..fa6eed5e 100644 --- a/examples/Docker/apache2/wsgi/Dockerfile +++ b/examples/Docker/apache2/wsgi/Dockerfile @@ -8,15 +8,15 @@ ENV APACHE_LOG_DIR /var/log/apache2 RUN apt-get update && \ DEBIAN_FRONTEND="noninteractive" apt-get -y install --no-install-recommends tzdata && \ DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y \ - python3-pip \ apache2 \ apache2-data \ - libapache2-mod-wsgi-py3 \ curl \ krb5-user \ + libapache2-mod-wsgi-py3 \ libgssapi-krb5-2 \ libkrb5-3 \ python3-gssapi \ + python3-pip \ && rm -rf /var/lib/apt/lists/* &&\ mkdir -p /var/www/acme2certifier/volume && \ mkdir -p /var/www/acme2certifier/examples /var/www/acme2certifier/examples/ @@ -24,13 +24,25 @@ RUN apt-get update && \ COPY ./ /var/www/acme2certifier/ # configure acme2certifier -RUN pip3 install -r /var/www/acme2certifier/requirements.txt --break-system-packages && \ +RUN pip3 install impacket --break-system-packages && \ + rm /usr/local/bin/*.py && \ + rm -rf /usr/local/lib/python3.12/dist-packages/impacket/examples/* && \ + pip3 install -r /var/www/acme2certifier/requirements.txt --break-system-packages && \ cp /var/www/acme2certifier/examples/apache2/apache_wsgi.conf /etc/apache2/sites-enabled/acme2certifier.conf && \ cp /var/www/acme2certifier/examples/acme2certifier_wsgi.py /var/www/acme2certifier/acme2certifier_wsgi.py && \ cp /var/www/acme2certifier/examples/db_handler/wsgi_handler.py /var/www/acme2certifier/acme_srv/db_handler.py && \ - rm /var/www/acme2certifier/CHANGES.md /var/www/acme2certifier/README.md /var/www/acme2certifier/SECURITY.md /var/www/acme2certifier/setup.py /var/www/acme2certifier/requirements.txt && \ + rm /var/www/acme2certifier/CHANGES.md && \ + rm /var/www/acme2certifier/README.md && \ + rm /var/www/acme2certifier/SECURITY.md && \ + rm /var/www/acme2certifier/setup.py && \ + rm /var/www/acme2certifier/requirements.txt && \ cp /var/www/acme2certifier/examples/Docker/apache2/wsgi/docker-entrypoint.sh /docker-entrypoint.sh && \ - rm -rf /var/www/acme2certifier/examples/Docker /var/www/acme2certifier/examples/django /var/www/acme2certifier/examples/db_handler /var/www/acme2certifier/examples/nginx /var/www/acme2certifier/examples/acme_srv.db.example /var/www/acme2certifier/examples/acme2certifier_wsgi.py && \ + rm -rf /var/www/acme2certifier/examples/Docker && \ + rm -rf /var/www/acme2certifier/examples/django && \ + rm -rf /var/www/acme2certifier/examples/db_handler && \ + rm -rf /var/www/acme2certifier/examples/nginx && \ + rm -rf /var/www/acme2certifier/examples/acme_srv.db.example && \ + rm -rf /var/www/acme2certifier/examples/acme2certifier_wsgi.py && \ chown -R www-data:www-data /var/www/acme2certifier/ && \ sed -i "s/default = default_sect/\default = default_sect\nlegacy = legacy_sect/g" /etc/ssl/openssl.cnf && \ sed -i "s/\[default_sect\]/\[default_sect\]\nactivate = 1\n\[legacy_sect\]\nactivate = 1/g" /etc/ssl/openssl.cnf && \ diff --git a/examples/Docker/nginx/django/Dockerfile b/examples/Docker/nginx/django/Dockerfile index dff12580..27f74e58 100644 --- a/examples/Docker/nginx/django/Dockerfile +++ b/examples/Docker/nginx/django/Dockerfile @@ -4,20 +4,20 @@ LABEL maintainer="grindelsack@gmail.com" RUN apt-get update && \ DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends tzdata && \ DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y \ - python3-pip \ - nginx \ - uwsgi \ - uwsgi-plugin-python3 \ curl \ krb5-user \ libgssapi-krb5-2 \ libkrb5-3 \ - python3-gssapi \ + nginx \ python3-django \ + python3-gssapi \ python3-mysqldb \ - python3-pymysql \ + python3-pip \ python3-psycopg2 \ + python3-pymysql \ python3-yaml \ + uwsgi \ + uwsgi-plugin-python3 \ && rm -rf /var/lib/apt/lists/* &&\ mkdir -p /var/www/acme2certifier/volume && \ mkdir -p /var/www/acme2certifier/examples /var/www/acme2certifier/examples/ && \ @@ -25,7 +25,11 @@ RUN apt-get update && \ COPY ./ /var/www/acme2certifier/ -RUN pip3 install -r /var/www/acme2certifier/requirements.txt --break-system-packages && pip3 install supervisor --break-system-packages && \ +RUN pip3 install impacket --break-system-packages && \ + rm /usr/local/bin/*.py && \ + rm -rf /usr/local/lib/python3.12/dist-packages/impacket/examples/* && \ + pip3 install -r /var/www/acme2certifier/requirements.txt --break-system-packages && \ + pip3 install supervisor --break-system-packages && \ cp -R /var/www/acme2certifier/examples/django/* /var/www/acme2certifier/ && \ cp /var/www/acme2certifier/examples/db_handler/django_handler.py /var/www/acme2certifier/acme_srv/db_handler.py && \ cp /var/www/acme2certifier/examples/nginx/acme2certifier.ini /var/www/acme2certifier && \ @@ -39,8 +43,16 @@ RUN pip3 install -r /var/www/acme2certifier/requirements.txt --break-system-pack sed -i "s/default = default_sect/\default = default_sect\nlegacy = legacy_sect/g" /etc/ssl/openssl.cnf && \ sed -i "s/\[default_sect\]/\[default_sect\]\nactivate = 1\n\[legacy_sect\]\nactivate = 1/g" /etc/ssl/openssl.cnf && \ rm /etc/nginx/sites-enabled/default && \ - rm /var/www/acme2certifier/CHANGES.md /var/www/acme2certifier/README.md /var/www/acme2certifier/SECURITY.md /var/www/acme2certifier/setup.py /var/www/acme2certifier/requirements.txt && \ - rm -rf /var/www/acme2certifier/examples/Docker /var/www/acme2certifier/examples/db_handler /var/www/acme2certifier/examples/apache2 /var/www/acme2certifier/examples/acme_srv.db.example /var/www/acme2certifier/examples/acme2certifier_wsgi.py && \ + rm /var/www/acme2certifier/CHANGES.md && \ + rm /var/www/acme2certifier/README.md && \ + rm /var/www/acme2certifier/SECURITY.md && \ + rm /var/www/acme2certifier/setup.py && \ + rm /var/www/acme2certifier/requirements.txt && \ + rm -rf /var/www/acme2certifier/examples/Docker && \ + rm -rf /var/www/acme2certifier/examples/db_handler && \ + rm -rf /var/www/acme2certifier/examples/apache2 && \ + rm -rf /var/www/acme2certifier/examples/acme_srv.db.example && \ + rm -rf /var/www/acme2certifier/examples/acme2certifier_wsgi.py && \ rm /var/www/acme2certifier/acme2certifier/settings.py && \ chmod a+rx /docker-entrypoint.sh diff --git a/examples/Docker/nginx/wsgi/Dockerfile b/examples/Docker/nginx/wsgi/Dockerfile index fc9a9a4f..052c65ae 100644 --- a/examples/Docker/nginx/wsgi/Dockerfile +++ b/examples/Docker/nginx/wsgi/Dockerfile @@ -3,15 +3,15 @@ LABEL maintainer="grindelsack@gmail.com" RUN apt-get update && \ DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends tzdata && \ DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y \ - python3-pip \ - nginx \ - uwsgi \ - uwsgi-plugin-python3 \ curl \ krb5-user \ libgssapi-krb5-2 \ libkrb5-3 \ + nginx \ python3-gssapi \ + python3-pip \ + uwsgi \ + uwsgi-plugin-python3 \ && rm -rf /var/lib/apt/lists/* &&\ mkdir -p /var/www/acme2certifier/volume && \ mkdir -p /var/www/acme2certifier/examples /var/www/acme2certifier/examples/ && \ @@ -20,7 +20,11 @@ RUN apt-get update && \ COPY ./ /var/www/acme2certifier/ # configure acme2certifier -RUN pip3 install -r /var/www/acme2certifier/requirements.txt --break-system-packages && pip3 install supervisor --break-system-packages && \ +RUN pip3 install impacket --break-system-packages && \ + rm /usr/local/bin/*.py && \ + rm -rf /usr/local/lib/python3.12/dist-packages/impacket/examples/* && \ + pip3 install -r /var/www/acme2certifier/requirements.txt --break-system-packages && \ + pip3 install supervisor --break-system-packages && \ cp /var/www/acme2certifier/examples/acme2certifier_wsgi.py /var/www/acme2certifier/acme2certifier_wsgi.py && \ cp /var/www/acme2certifier/examples/db_handler/wsgi_handler.py /var/www/acme2certifier/acme_srv/db_handler.py && \ cp /var/www/acme2certifier/examples/nginx/acme2certifier.ini /var/www/acme2certifier && \ @@ -34,8 +38,17 @@ RUN pip3 install -r /var/www/acme2certifier/requirements.txt --break-system-pack sed -i "s/default = default_sect/\default = default_sect\nlegacy = legacy_sect/g" /etc/ssl/openssl.cnf && \ sed -i "s/\[default_sect\]/\[default_sect\]\nactivate = 1\n\[legacy_sect\]\nactivate = 1/g" /etc/ssl/openssl.cnf && \ rm /etc/nginx/sites-enabled/default && \ - rm /var/www/acme2certifier/CHANGES.md /var/www/acme2certifier/README.md /var/www/acme2certifier/SECURITY.md /var/www/acme2certifier/setup.py /var/www/acme2certifier/requirements.txt && \ - rm -rf /var/www/acme2certifier/examples/Docker /var/www/acme2certifier/examples/django /var/www/acme2certifier/examples/db_handler /var/www/acme2certifier/examples/apache2 /var/www/acme2certifier/examples/acme_srv.db.example /var/www/acme2certifier/examples/acme2certifier_wsgi.py && \ + rm /var/www/acme2certifier/CHANGES.md && \ + rm /var/www/acme2certifier/README.md && \ + rm /var/www/acme2certifier/SECURITY.md && \ + rm /var/www/acme2certifier/setup.py && \ + rm /var/www/acme2certifier/requirements.txt && \ + rm -rf /var/www/acme2certifier/examples/Docker && \ + rm -rf /var/www/acme2certifier/examples/django && \ + rm -rf /var/www/acme2certifier/examples/db_handler && \ + rm -rf /var/www/acme2certifier/examples/apache2 && \ + rm -rf /var/www/acme2certifier/examples/acme_srv.db.example && \ + rm -rf /var/www/acme2certifier/examples/acme2certifier_wsgi.py && \ chmod a+rx /docker-entrypoint.sh WORKDIR /var/www/acme2certifier diff --git a/examples/Docker/soap-srv/Dockerfile b/examples/Docker/soap-srv/Dockerfile index 3bb53542..0b4dce1e 100644 --- a/examples/Docker/soap-srv/Dockerfile +++ b/examples/Docker/soap-srv/Dockerfile @@ -4,25 +4,22 @@ LABEL maintainer="grindelsack@gmail.com" RUN apt-get update && \ DEBIAN_FRONTEND="noninteractive" apt-get -y install --no-install-recommends tzdata && \ DEBIAN_FRONTEND="noninteractive" apt-get install --no-install-recommends -y \ - python3-pip \ apache2 \ apache2-data \ - libapache2-mod-wsgi-py3 \ curl \ krb5-user \ + libapache2-mod-wsgi-py3 \ libgssapi-krb5-2 \ libkrb5-3 \ python3-gssapi \ + python3-pip \ && rm -rf /var/lib/apt/lists/* # install python requirements COPY requirements.txt /tmp/requirements.txt -RUN pip3 install -r /tmp/requirements.txt - - -# create folders for acme2certifier -RUN mkdir -p /usr/local/soap-srv/acme_srv && \ +RUN pip3 install -r /tmp/requirements.txt &&\ + mkdir -p /usr/local/soap-srv/acme_srv && \ mkdir -p /usr/local/soap-srv/examples/ca_handler COPY examples/soap/mock_soap_srv.py /usr/local/soap-srv/ diff --git a/examples/ca_handler/certsrv.py b/examples/ca_handler/certsrv.py index 8c335d21..53199534 100644 --- a/examples/ca_handler/certsrv.py +++ b/examples/ca_handler/certsrv.py @@ -73,10 +73,11 @@ class Certsrv(object): the password parameter the path to a (unencrypted) private key. """ # pylint: disable=r0913 - def __init__(self, server, username, password, auth_method="basic", + def __init__(self, server, url, username, password, auth_method="basic", cafile=None, verify=True, timeout=TIMEOUT, proxies=None): self.server = server + self.url = url self.timeout = timeout self.auth_method = auth_method self.session = requests.Session() @@ -197,7 +198,11 @@ def get_cert(self, csr, template, encoding="b64", attributes=None): "SaveCert": "yes", } - url = "https://{0}/certsrv/certfnsh.asp".format(self.server) + url = "" + if self.url: + url = "{0}/certfnsh.asp".format(self.url) + else: + url = "https://{0}/certsrv/certfnsh.asp".format(self.server) response = self._post(url, data=data) @@ -241,7 +246,12 @@ def get_existing_cert(self, req_id, encoding="b64"): while fetching the cert. """ - cert_url = "https://{0}/certsrv/certnew.cer".format(self.server) + cert_url = "" + if self.url: + cert_url = "{0}/certnew.cer".format(self.url) + else: + cert_url = "https://{0}/certsrv/certnew.cer".format(self.server) + params = {"ReqID": req_id, "Enc": encoding} response = self._get(cert_url, params=params) @@ -270,7 +280,11 @@ def get_ca_cert(self, encoding="b64"): Returns: The newest CA certificate from the server. """ - url = "https://{0}/certsrv/certcarc.asp".format(self.server) + url = "" + if self.url: + url = "{0}/certcarc.asp".format(self.url) + else: + url = "https://{0}/certsrv/certcarc.asp".format(self.server) response = self._get(url) @@ -278,7 +292,11 @@ def get_ca_cert(self, encoding="b64"): # so that we get the newest CA cert. renewals = re.search(r"var nRenewals=(\d+);", response.text).group(1) - cert_url = "https://{0}/certsrv/certnew.cer".format(self.server) + cert_url = "" + if self.url: + cert_url = "{0}/certnew.cer".format(self.url) + else: + cert_url = "https://{0}/certsrv/certnew.cer".format(self.server) params = {"ReqID": "CACert", "Enc": encoding, "Renewal": renewals} response = self._get(cert_url, params=params) @@ -301,14 +319,23 @@ def get_chain(self, encoding="bin"): Returns: The CA chain from the server, in PKCS#7 format. """ - url = "https://{0}/certsrv/certcarc.asp".format(self.server) + url = "" + if self.url: + url = "{0}/certcarc.asp".format(self.url) + else: + url = "https://{0}/certsrv/certcarc.asp".format(self.server) response = self._get(url) # We have to check how many renewals this server has had, so that we get the newest chain renewals = re.search(r"var nRenewals=(\d+);", response.text).group(1) - chain_url = "https://{0}/certsrv/certnew.p7b".format(self.server) + chain_url = "" + if self.url: + chain_url = "{0}/certnew.p7b".format(self.url) + else: + chain_url = "https://{0}/certsrv/certnew.p7b".format(self.server) + params = {"ReqID": "CACert", "Renewal": renewals, "Enc": encoding} chain_response = self._get(chain_url, params=params) @@ -327,7 +354,11 @@ def check_credentials(self): Returns: True if authentication succeeded, False if it failed. """ - url = "https://{0}/certsrv/".format(self.server) + url = "" + if self.url: + url = "{0}".format(self.url) + else: + url = "https://{0}/certsrv/".format(self.server) try: self._get(url) diff --git a/examples/ca_handler/digicert_ca_handler.py b/examples/ca_handler/digicert_ca_handler.py new file mode 100644 index 00000000..3af0cc9b --- /dev/null +++ b/examples/ca_handler/digicert_ca_handler.py @@ -0,0 +1,376 @@ +# -*- coding: utf-8 -*- +""" CA handler using Digicert CertCentralAPI""" +from __future__ import print_function +from typing import Tuple, Dict +import json +import requests +# pylint: disable=e0401 +from acme_srv.helper import load_config, csr_cn_get, cert_pem2der, b64_encode, allowed_domainlist_check, eab_profile_header_info_check, uts_now, uts_to_date_utc, cert_serial_get, config_eab_profile_load, config_headerinfo_load, csr_san_get + + +CONTENT_TYPE = 'application/json' + + +class CAhandler(object): + """ Digicert CertCentralAP handler """ + + def __init__(self, _debug: bool = None, logger: object = None): + self.logger = logger + self.api_url = 'https://www.digicert.com/services/v2/' + self.api_key = None + self.cert_type = 'ssl_basic' + self.signature_hash = 'sha256' + self.order_validity = 1 + self.proxy = None + self.request_timeout = 10 + self.organization_id = None + self.organization_name = None + self.allowed_domainlist = [] + self.header_info_field = False + self.eab_handler = None + self.eab_profiling = False + + def __enter__(self): + """ Makes CAhandler a Context Manager """ + if not self.api_key: + self._config_load() + return self + + def __exit__(self, *args): + """ cose the connection at the end of the context """ + + def _allowed_domainlist_check(self, csr: str) -> str: + """ check allowed domainlist """ + self.logger.debug('CAhandler._allowed_domainlist_check()') + + error = None + # check CN and SAN against black/whitlist + if self.allowed_domainlist: + # check sans / cn against list of allowed comains from config + result = allowed_domainlist_check(self.logger, csr, self.allowed_domainlist) + if not result: + error = 'Either CN or SANs are not allowed by configuration' + + self.logger.debug('CAhandler._allowed_domainlist_check() ended with %s', error) + return error + + def _api_get(self, url: str) -> Tuple[int, Dict[str, str]]: + """ post data to API """ + self.logger.debug('CAhandler._api_get()') + headers = { + 'X-DC-DEVKEY': self.api_key, + 'Content-Type': CONTENT_TYPE + } + + try: + api_response = requests.get(url=url, headers=headers, proxies=self.proxy, timeout=self.request_timeout) + code = api_response.status_code + try: + content = api_response.json() + except Exception as err_: + self.logger.error('CAhandler._api_get() returned error during json parsing: %s', err_) + content = str(err_) + except Exception as err_: + self.logger.error('CAhandler._api_get() returned error: %s', err_) + code = 500 + content = str(err_) + + return code, content + + def _api_post(self, url: str, data: Dict[str, str]) -> Tuple[int, Dict[str, str]]: + """ post data to API """ + self.logger.debug('CAhandler._api_post()') + headers = { + 'X-DC-DEVKEY': self.api_key, + 'Content-Type': CONTENT_TYPE + } + + try: + api_response = requests.post(url=url, headers=headers, json=data, proxies=self.proxy, timeout=self.request_timeout) + code = api_response.status_code + if api_response.text: + try: + content = api_response.json() + except Exception as err_: + self.logger.error('CAhandler._api_post() returned error during json parsing: %s', err_) + content = str(err_) + else: + content = None + except Exception as err_: + self.logger.error('CAhandler._api_post() returned error: %s', err_) + code = 500 + content = str(err_) + + return code, content + + def _api_put(self, url: str, data: Dict[str, str]) -> Tuple[int, Dict[str, str]]: + """ post data to API """ + self.logger.debug('CAhandler._api_put()') + headers = { + 'X-DC-DEVKEY': self.api_key, + 'Content-Type': CONTENT_TYPE + } + + try: + api_response = requests.put(url=url, headers=headers, json=data, proxies=self.proxy, timeout=self.request_timeout) + code = api_response.status_code + if api_response.text: + try: + content = api_response.json() + except Exception as err_: + self.logger.error('CAhandler._api_put() returned error during json parsing: %s', err_) + content = str(err_) + else: + content = None + except Exception as err_: + self.logger.error('CAhandler._api_put() returned error: %s', err_) + code = 500 + content = str(err_) + + return code, content + + def _config_check(self) -> str: + """ check config """ + self.logger.debug('CAhandler._config_check()') + + error = None + for ele in ['api_url', 'api_key', 'organization_name']: + if not getattr(self, ele): + error = f'{ele} parameter in missing in config file' + self.logger.error('CAhandler._config_check() ended with error: %s', error) + break + + self.logger.debug('CAhandler._config_check() ended with: %s', error) + return error + + def _config_load(self): + """" load config from file """ + self.logger.debug('CAhandler._config_load()') + + config_dic = load_config(self.logger, 'CAhandler') + if 'CAhandler' in config_dic: + cfg_dic = dict(config_dic['CAhandler']) + self.api_url = cfg_dic.get('api_url', 'https://www.digicert.com/services/v2/') + self.api_key = cfg_dic.get('api_key', None) + self.cert_type = cfg_dic.get('cert_type', 'ssl_basic') + self.signature_hash = cfg_dic.get('signature_hash', 'sha256') + self.order_validity = cfg_dic.get('order_validity', 1) + self.request_timeout = cfg_dic.get('request_timeout', 10) + self.organization_id = cfg_dic.get('organization_id', None) + self.organization_name = cfg_dic.get('organization_name', None) + + if 'allowed_domainlist' in config_dic['CAhandler']: + try: + self.allowed_domainlist = json.loads(config_dic['CAhandler']['allowed_domainlist']) + except Exception as err: + self.logger.error('CAhandler._config_load(): failed to parse allowed_domainlist: %s', err) + self.allowed_domainlist = 'failed to parse' + + # load profiling + self.eab_profiling, self.eab_handler = config_eab_profile_load(self.logger, config_dic) + # load header info + self.header_info_field = config_headerinfo_load(self.logger, config_dic) + + self.logger.debug('CAhandler._config_load() ended') + + def _order_send(self, csr: str, csr_cn) -> Tuple[str, str]: + """ place certificate order """ + self.logger.debug('CAhandler._order_send()') + order_url = f'{self.api_url}order/certificate/{self.cert_type}' + + if not csr.endswith('='): + # padding if needed + csr = csr + '=' * (-len(csr) % 4) + + if (not self.organization_id or self.eab_profiling) and self.organization_name and self.api_key: + self.organization_id = self._organiation_id_get() + + if self.organization_id: + data_dic = { + 'certificate': { + 'common_name': csr_cn, + 'csr': csr, + 'signature_hash': self.signature_hash, + 'server_platform': { + 'id': 34 + } + }, + 'organization': { + 'id': self.organization_id, + }, + 'order_validity': { + 'years': self.order_validity + } + } + # enroll certificate + code, content = self._api_post(order_url, data_dic) + else: + self.logger.error('CAhandler._order_send() failed: configuration incomplete: organisation_id is missing') + code = 500 + content = 'organisation_id is missing' + + self.logger.debug('CAhandler._order_send() ended with code: %s', code) + return code, content + + def _order_response_parse(self, content: Dict[str, str]) -> Tuple[str, str, str]: + """ parse order response """ + self.logger.debug('CAhandler._order_response_parse()') + + cert_bundle = None + cert_raw = None + poll_identifier = None + + if content and 'certificate_chain' in content: + cert_bundle = '' + for cert in content['certificate_chain']: + if 'pem' in cert: + cert_bundle += cert['pem'] + '\n' + else: + self.logger.error('CAhandler._order_response_parse() failed: no pem in certificate_chain') + cert_raw = b64_encode(self.logger, cert_pem2der(content['certificate_chain'][0]['pem'])) + if 'id' in content: + poll_identifier = content['id'] + else: + self.logger.error('CAhandler._order_response_parse() polling_identifier generation failed: no id in response') + else: + self.logger.error('CAhandler._order_response_parse() failed: no certificate_chain in response') + + self.logger.debug('CAhandler._order_response_parse() ended') + return cert_bundle, cert_raw, poll_identifier + + def _organiation_id_get(self): + """ get organization ID """ + self.logger.debug('CAhandler._organiation_id_get()') + + org_url = f'{self.api_url}organization' + code, content = self._api_get(org_url) + + organization_id = None + if code in (200, 201): + for org in content['organizations']: + if org['name'] == self.organization_name: + self.logger.debug('CAhandler._organiation_id_get() found organization ID: %s', org['id']) + organization_id = org['id'] + break + + if not organization_id: + self.logger.error('CAhandler._organiation_id_get() failed') + + self.logger.debug('CAhandler._organiation_id_get() ended with: %s', organization_id) + return organization_id + + def _csr_check(self, csr: str) -> str: + """ check csr """ + self.logger.debug('CAhandler._csr_check()') + + # check for allowed domainlist + error = self._allowed_domainlist_check(csr) + + # check for eab profiling and header_info + if not error: + error = eab_profile_header_info_check(self.logger, self, csr, 'cert_type') + + self.logger.debug('CAhandler._csr_check() ended with: %s', error) + return error + + def _csr_cn_lookup(self, csr: str) -> str: + """ lookup CN/ 1st san from CSR """ + self.logger.debug('CAhandler._csr_cn_lookup()') + + csr_cn = csr_cn_get(self.logger, csr) + if not csr_cn: + # lookup first san + san_list = csr_san_get(self.logger, csr) + if san_list and len(san_list) > 0: + for san in san_list: + try: + csr_cn = san.split(':')[1] + break + except Exception as err: + self.logger.error('CAhandler._csr_cn_lookup() split failed: %s', err) + else: + self.logger.error('CAhandler._csr_cn_lookup() no SANs found in CSR') + + self.logger.debug('CAhandler._csr_cn_lookup() ended with: %s', csr_cn) + return csr_cn + + def enroll(self, csr: str) -> Tuple[str, str, str, str]: + """ enroll certificate """ + self.logger.debug('CAhandler.enroll()') + + cert_bundle = None + error = None + cert_raw = None + poll_indentifier = None + + # check configuration + error = self._config_check() + + if not error: + # check csr and profiling + error = self._csr_check(csr) + + if not error: + csr_cn = self._csr_cn_lookup(csr) + code, content = self._order_send(csr, csr_cn) + + if code in (200, 201): + # successful + cert_bundle, cert_raw, poll_indentifier = self._order_response_parse(content) + else: + if 'errors' in content: + error = f"Error during order creation: {code} - {content['errors']}" + else: + error = f'Error during order creation: {code} - {content}' + + self.logger.debug('Certificate.enroll() ended') + return (error, cert_bundle, cert_raw, poll_indentifier) + + def poll(self, _cert_name: str, poll_identifier: str, _csr: str) -> Tuple[str, str, str, str, bool]: + """ poll status of pending CSR and download certificates """ + self.logger.debug('CAhandler.poll()') + + error = 'Method not implemented.' + cert_bundle = None + cert_raw = None + rejected = False + + self.logger.debug('CAhandler.poll() ended') + return (error, cert_bundle, cert_raw, poll_identifier, rejected) + + def revoke(self, certificate_raw: str, _rev_reason: str = 'unspecified', _rev_date: str = uts_to_date_utc(uts_now())) -> Tuple[int, str, str]: + """ revoke certificate """ + self.logger.debug('CAhandler.revoke()') + + code = None + message = None + detail = None + + cert_serial = cert_serial_get(self.logger, certificate_raw, hexformat=True) + + if cert_serial: + revocation_url = f'{self.api_url}certificate/{cert_serial}/revoke' + data_dic = { + 'skip_approval': True + } + code, detail = self._api_put(revocation_url, data_dic) + if code == 204: + # rewrite reponse code to not confuse with success + code = 200 + else: + code = 500 + detail = 'Failed to parse certificate serial' + + self.logger.debug('Certificate.revoke() ended') + return (code, message, detail) + + def trigger(self, _payload: str) -> Tuple[str, str, str]: + """ process trigger message and return certificate """ + self.logger.debug('CAhandler.trigger()') + + error = 'Method not implemented.' + cert_bundle = None + cert_raw = None + + self.logger.debug('CAhandler.trigger() ended with error: %s', error) + return (error, cert_bundle, cert_raw) diff --git a/examples/ca_handler/entrust_ca_handler.py b/examples/ca_handler/entrust_ca_handler.py new file mode 100644 index 00000000..b3fddf55 --- /dev/null +++ b/examples/ca_handler/entrust_ca_handler.py @@ -0,0 +1,607 @@ +# -*- coding: utf-8 -*- +""" CA handler using Entrust ECS Enterprise""" +from __future__ import print_function +from typing import Tuple, Dict, List +import datetime +import os +import json +import requests +from requests_pkcs12 import Pkcs12Adapter +# pylint: disable=e0401 +from acme_srv.helper import load_config, csr_cn_get, cert_pem2der, b64_encode, allowed_domainlist_check, eab_profile_header_info_check, uts_now, uts_to_date_utc, cert_serial_get, config_eab_profile_load, config_headerinfo_load, csr_san_get, header_info_get, b64_url_recode + + +CONTENT_TYPE = 'application/json' + + +# hardcoded Entrust Root Certification Authority - G2 +ENTRUST_ROOT_CA = '''-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- +''' + + +class CAhandler(object): + """ Digicert CertCentralAP handler """ + + def __init__(self, _debug: bool = None, logger: object = None): + self.logger = logger + self.api_url = 'https://api.entrust.net/enterprise/v2' + self.client_cert = None + self.cert_passphrase = None + self.username = None + self.password = None + self.organization_name = None + self.certtype = 'STANDARD_SSL' + self.cert_validity_days = 365 + self.entrust_root_cert = ENTRUST_ROOT_CA + self.proxy = None + self.session = None + self.request_timeout = 10 + + self.allowed_domainlist = [] + self.header_info_field = False + self.eab_handler = None + self.eab_profiling = False + + def __enter__(self): + """ Makes CAhandler a Context Manager """ + if not self.session: + self._config_load() + return self + + def __exit__(self, *args): + """ cose the connection at the end of the context """ + + def _allowed_domainlist_check(self, csr: str) -> str: + """ check allowed domainlist """ + self.logger.debug('CAhandler._allowed_domainlist_check()') + + error = None + # check CN and SAN against black/whitlist + if self.allowed_domainlist: + # check sans / cn against list of allowed comains from config + result = allowed_domainlist_check(self.logger, csr, self.allowed_domainlist) + if not result: + error = 'Either CN or SANs are not allowed by configuration' + + self.logger.debug('CAhandler._allowed_domainlist_check() ended with %s', error) + return error + + def _api_get(self, url: str) -> Tuple[int, Dict[str, str]]: + """ post data to API """ + self.logger.debug('CAhandler._api_get()') + headers = { + 'Content-Type': CONTENT_TYPE + } + + try: + api_response = self.session.get(url=url, headers=headers, proxies=self.proxy, timeout=self.request_timeout) + code = api_response.status_code + try: + content = api_response.json() + except Exception as err_: + self.logger.error('CAhandler._api_get() returned error during json parsing: %s', err_) + content = str(err_) + except Exception as err_: + self.logger.error('CAhandler._api_get() returned error: %s', err_) + code = 500 + content = str(err_) + + return code, content + + def _api_post(self, url: str, data: Dict[str, str]) -> Tuple[int, Dict[str, str]]: + """ post data to API """ + self.logger.debug('CAhandler._api_post()') + headers = { + 'Content-Type': CONTENT_TYPE + } + + try: + api_response = self.session.post(url=url, headers=headers, json=data, proxies=self.proxy, timeout=self.request_timeout) + code = api_response.status_code + if api_response.text: + try: + content = api_response.json() + except Exception as err_: + self.logger.error('CAhandler._api_post() returned error during json parsing: %s', err_) + content = str(err_) + else: + content = None + except Exception as err_: + self.logger.error('CAhandler._api_post() returned error: %s', err_) + code = 500 + content = str(err_) + + return code, content + + def _api_put(self, url: str, data: Dict[str, str]) -> Tuple[int, Dict[str, str]]: + """ post data to API """ + self.logger.debug('CAhandler._api_put()') + headers = { + 'Content-Type': CONTENT_TYPE + } + + try: + api_response = self.session.put(url=url, headers=headers, json=data, proxies=self.proxy, timeout=self.request_timeout) + code = api_response.status_code + if api_response.text: + try: + content = api_response.json() + except Exception as err_: + self.logger.error('CAhandler._api_put() returned error during json parsing: %s', err_) + content = str(err_) + else: + content = None + except Exception as err_: + self.logger.error('CAhandler._api_put() returned error: %s', err_) + code = 500 + content = str(err_) + + return code, content + + def _certificates_get_from_serial(self, cert_serial: str) -> List[str]: + """ get certificates """ + self.logger.debug('CAhandler._certificates_get_from_serial()') + + # for some reason entrust custs leading zeros from serial number + if cert_serial.startswith('0'): + self.logger.info('CAhandler._certificates_get_from_serial() remove leading zeros from serial number') + cert_serial = cert_serial.lstrip('0') + + code, content = self._api_get(self.api_url + f'/certificates?serialNumber={cert_serial}') + + if code == 200 and 'certificates' in content: + cert_list = content['certificates'] + else: + self.logger.error('CAhandler._certificates_get_from_serial() for %s failed with code: %s', cert_serial, code) + cert_list = [] + + self.logger.debug('CAhandler._certificates_get_from_serial() ended with code: %s and %s certificate', code, len(cert_list)) + return cert_list + + def _config_load(self): + """" load config from file """ + self.logger.debug('CAhandler._config_load()') + + config_dic = load_config(self.logger, 'CAhandler') + if 'CAhandler' in config_dic: + cfg_dic = dict(config_dic['CAhandler']) + self.api_url = cfg_dic.get('api_url', 'https://api.entrust.net/enterprise/v2') + try: + self.request_timeout = int(cfg_dic.get('request_timeout', 10)) + except Exception as err: + self.logger.error('CAhandler._config_load(): failed to parse request_timeout %s', err) + try: + self.cert_validity_days = int(cfg_dic.get('cert_validity_days', 365)) + except Exception as err: + self.logger.error('CAhandler._config_load(): failed to parse cert_validity_days %s', err) + + self.username = cfg_dic.get('username', None) + self.password = cfg_dic.get('password', None) + self.organization_name = cfg_dic.get('organization_name', None) + self.certtype = cfg_dic.get('certtype', 'STANDARD_SSL') + self._config_session_load(config_dic) + + if 'allowed_domainlist' in config_dic['CAhandler']: + try: + self.allowed_domainlist = json.loads(config_dic['CAhandler']['allowed_domainlist']) + except Exception as err: + self.logger.error('CAhandler._config_load(): failed to parse allowed_domainlist: %s', err) + self.allowed_domainlist = 'failed to parse' + # load root CA + self._config_root_load(config_dic) + + # load profiling + self.eab_profiling, self.eab_handler = config_eab_profile_load(self.logger, config_dic) + # load header info + self.header_info_field = config_headerinfo_load(self.logger, config_dic) + + self.logger.debug('CAhandler._config_load() ended') + + def _config_passphrase_load(self, config_dic: Dict[str, str]): + """ load passphrase """ + self.logger.debug('CAhandler._config_passphrase_load()') + if 'cert_passphrase_variable' in config_dic['CAhandler'] or 'cert_passphrase' in config_dic['CAhandler']: + if 'cert_passphrase_variable' in config_dic['CAhandler']: + self.logger.debug('CAhandler._config_passphrase_load(): load passphrase from environment variable') + try: + self.cert_passphrase = os.environ[config_dic['CAhandler']['cert_passphrase_variable']] + except Exception as err: + self.logger.error('CAhandler._config_passphrase_load() could not load cert_passphrase_variable:%s', err) + + if 'cert_passphrase' in config_dic['CAhandler']: + self.logger.debug('CAhandler._config_passphrase_load(): load passphrase from config file') + if self.cert_passphrase: + self.logger.info('CAhandler._config_load() overwrite cert_passphrase') + self.cert_passphrase = config_dic['CAhandler']['cert_passphrase'] + self.logger.debug('CAhandler._config_passphrase_load() ended') + + def _config_root_load(self, config_dic: Dict[str, str]): + """ load root CA """ + self.logger.debug('CAhandler._config_root_load()') + if 'entrust_root_cert' in config_dic['CAhandler']: + if os.path.isfile(config_dic['CAhandler']['entrust_root_cert']): + self.logger.debug('CAhandler._config_root_load(): load root CA from config file') + with open(config_dic['CAhandler']['entrust_root_cert'], 'r', encoding='utf8') as ca_file: + self.entrust_root_cert = ca_file.read() + else: + self.logger.error('CAhandler._config_root_load(): root CA file configured but not not found. Using default one.') + + self.logger.debug('CAhandler._config_root_load() ended') + + def _config_session_load(self, config_dic: Dict[str, str]): + """ load session """ + self.logger.debug('CAhandler._config_session_load()') + + with requests.Session() as self.session: + # client auth via pem files + if 'client_cert' in config_dic['CAhandler'] and 'client_key' in config_dic['CAhandler']: + self.logger.debug('CAhandler._config_session_load() cert and key in pem format') + self.session.cert = (config_dic['CAhandler']['client_cert'], config_dic['CAhandler']['client_key']) + + else: + self._config_passphrase_load(config_dic) + if 'client_cert' in config_dic['CAhandler'] and self.cert_passphrase: + self.logger.debug('CAhandler._config_session_load() cert and passphrase') + self.session.mount(self.api_url, Pkcs12Adapter(pkcs12_filename=config_dic['CAhandler']['client_cert'], pkcs12_password=self.cert_passphrase)) + else: + self.logger.warning('CAhandler._config_load() configuration might be incomplete: "client_cert. "client_key" or "client_passphrase[_variable] parameter is missing in config file') + self.session.auth = (self.username, self.password) + + self.logger.debug('CAhandler._config_session_load() ended') + + def _csr_cn_lookup(self, csr: str) -> str: + """ lookup CN/ 1st san from CSR """ + self.logger.debug('CAhandler._csr_cn_lookup()') + + csr_cn = csr_cn_get(self.logger, csr) + if not csr_cn: + # lookup first san + san_list = csr_san_get(self.logger, csr) + if san_list and len(san_list) > 0: + for san in san_list: + try: + csr_cn = san.split(':')[1] + break + except Exception as err: + self.logger.error('CAhandler._csr_cn_lookup() split failed: %s', err) + else: + self.logger.error('CAhandler._csr_cn_lookup() no SANs found in CSR') + + self.logger.debug('CAhandler._csr_cn_lookup() ended with: %s', csr_cn) + return csr_cn + + def _org_domain_cfg_check(self) -> str: + """ check organizations """ + self.logger.debug('CAhandler._organizations_check()') + + error = None + org_dic = self._organizations_get() + if self.organization_name not in org_dic: + error = f'Organization {self.organization_name} not found in Entrust API' + self.logger.error('CAhandler._organizations_check() ended with error: %s', error) + else: + domain_list = self._domains_get(org_dic[self.organization_name]) + if not self.allowed_domainlist: + self.logger.info('CAhandler._organizations_check(): allowed_domainlist is empty, using domains from Entrust API') + self.allowed_domainlist = domain_list + + self.logger.debug('CAhandler._organizations_check() ended with %s', error) + return error + + def _organizations_get(self) -> Dict[str, str]: + """ get organizations """ + self.logger.debug('CAhandler._organizations_get()') + + code, content = self._api_get(self.api_url + '/organizations') + org_dic = {} + if code == 200 and 'organizations' in content: + self.logger.debug('CAhandler._organizations_get() ended with code: 200') + for org in content['organizations']: + if 'verificationStatus' in org and org['verificationStatus'] == 'APPROVED': + if 'name' in org and 'clientId' in org: + org_dic[org['name']] = org['clientId'] + else: + self.logger.error('CAhandler._organizations_get(): malformed response') + + self.logger.debug('CAhandler._organizations_get() ended with code: %s', code) + return org_dic + + def _domains_get(self, org_id: str) -> List[str]: + """ get domains """ + self.logger.debug('CAhandler._domains_get()') + + code, content = self._api_get(self.api_url + f'/clients/{org_id}/domains') + + api_domain_list = [] + if code == 200 and 'domains' in content: + self.logger.debug('CAhandler._domains_get() ended with code: 200') + + for domain in content['domains']: + if 'verificationStatus' in domain and domain['verificationStatus'] == 'APPROVED': + if 'domainName' in domain: + api_domain_list.append(domain['domainName']) + else: + self.logger.error('CAhandler._domains_get(): malformed response') + + self.logger.debug('CAhandler._domains_get() ended with code: %s', code) + return api_domain_list + + def credential_check(self): + """ test connection to Entrust api """ + self.logger.debug('CAhandler.credential_check()') + + error = None + code, content = self._api_get(self.api_url + '/application/version') + if code != 200: + error = f'Connection to Entrust API failed: {content}' + + self.logger.debug('CAhandler.credential_check() ended with code: %s', code) + return error + + def _config_check(self) -> str: + """ check config """ + self.logger.debug('CAhandler._config_check()') + + error = None + for ele in ['api_url', 'username', 'password', 'organization_name']: + if not getattr(self, ele): + error = f'{ele} parameter in missing in config file' + self.logger.error('CAhandler._config_check() ended with error: %s', error) + break + + self.logger.debug('CAhandler._config_check() ended with: %s', error) + return error + + def _enroll_check(self, csr: str) -> str: + """ check csr """ + self.logger.debug('CAhandler._enroll_check()') + + # check for eab profiling and header_info + error = eab_profile_header_info_check(self.logger, self, csr, 'cert_type') + + if not error: + error = self._config_check() + + if not error: + error = self.credential_check() + + if not error: + error = self._org_domain_cfg_check() + + if not error: + # check for allowed domainlist + error = self._allowed_domainlist_check(csr) + + self.logger.debug('CAhandler._enroll_check() ended with %s', error) + return error + + def _trackingid_get(self, cert_raw: str) -> int: + """ get tracking id """ + self.logger.debug('CAhandler._trackingid_get()') + + tracking_id = None + # we misuse header_info_get() to get the tracking id from database + cert_recode = b64_url_recode(self.logger, cert_raw) + pid_list = header_info_get(self.logger, csr=cert_recode, vlist=['poll_identifier'], field_name='cert_raw') + + for ele in pid_list: + if 'poll_identifier' in ele: + tracking_id = ele['poll_identifier'] + break + + if not tracking_id: + # lookup through Entrust API + self.logger.info('CAhandler._trackingid_get(): tracking_id not found in database. Lookup trough Entrust API') + cert_serial = cert_serial_get(self.logger, cert_raw, hexformat=True) + certificate_list = self._certificates_get_from_serial(cert_serial) + for ele in certificate_list: + if 'trackingId' in ele: + tracking_id = ele['trackingId'] + break + + self.logger.debug('CAhandler._trackingid_get() ended with %s', tracking_id) + return tracking_id + + def _response_parse(self, content: Dict[str, str]) -> Tuple[str, str]: + """ parse response """ + self.logger.debug('CAhandler._response_parse()') + + cert_bundle = None + cert_raw = None + poll_indentifier = None + + if 'trackingId' in content: + poll_indentifier = content['trackingId'] + if 'endEntityCert' in content and 'chainCerts' in content: + cert_raw = b64_encode(self.logger, cert_pem2der(content['endEntityCert'])) + for cnt, ca_cert in enumerate(content['chainCerts']): + if cnt == 0: + cert_bundle = ca_cert + '\n' + else: + cert_bundle += ca_cert + '\n' + + # add Entrust Root CA + if cert_bundle: + cert_bundle += self.entrust_root_cert + '\n' + else: + cert_bundle = self.entrust_root_cert + '\n' + self.logger.debug('CAhandler._response_parse() ended') + return cert_bundle, cert_raw, poll_indentifier + + def _enroll(self, csr: str) -> Tuple[str, str]: + """ enroll certificate """ + self.logger.debug('CAhandler._enroll()') + + error = None + cert_raw = None + cert_bundle = None + poll_indentifier = None + + # get CN and SANs + cn = self._csr_cn_lookup(csr) + + # calculate cert expiry date + certexpirydate = datetime.datetime.now() + datetime.timedelta(days=self.cert_validity_days) + + data_dic = { + 'csr': csr, + 'signingAlg': 'SHA-2', + 'eku': "SERVER_AND_CLIENT_AUTH", + 'cn': cn, + 'org': self.organization_name, + 'endUserKeyStorageAgreement': True, + 'certType': self.certtype, + "certExpiryDate": certexpirydate.strftime('%Y-%m-%d') + } + + code, content = self._api_post(self.api_url + '/certificates', data_dic) + + if code == 201: + cert_bundle, cert_raw, poll_indentifier = self._response_parse(content) + else: + if 'errors' in content: + error = f"Error during order creation: {code} - {content['errors']}" + else: + error = f'Error during order creation: {code} - {content}' + self.logger.error('CAhandler._enroll() failed with error: %s', error) + + self.logger.debug('CAhandler._enroll() ended with code: %s', code) + return error, cert_bundle, cert_raw, poll_indentifier + + def revoke_by_trackingid(self, tracking_id: int, _rev_reason: str = 'unspecified') -> Tuple[int, str]: + """ revoke certificate """ + self.logger.debug('CAhandler.revoke_by_trackingid()') + code, content = self._api_post(self.api_url + f'/certificates/{tracking_id}/revocations', {'crlReason': _rev_reason, 'revocationComment': 'revoked by acme2certifier'}) + self.logger.debug('CAhandler.revoke_by_trackingid() ended with code: %s', code) + return code, content + + def certificates_get(self, limit=200) -> List[str]: + """ get certificates """ + self.logger.debug('CAhandler.certificates_get()') + + # set initial values + offset = 0 + cert_list = [] + prev_data = [] + total = 1 + while len(cert_list) < total: + self.logger.info('fetching certs offset: %s, limit: %s, total: %s, buffered: %s', offset, limit, total, len(cert_list)) + code, content = self._api_get(self.api_url + f'/certificates?limit={limit}&offset={offset}') + if code == 200: + # updte loop limit or throw error + if offset == 0: + if 'summary' in content and 'total' in content['summary']: + self.logger.debug('CAhandler.certificates_get() total number of certificates: %s', content['summary']['total']) + total = content['summary']['total'] # get total number of certificates + else: + self.logger.error('CAhandler.certificates_get() failed did not get any total value: %s', content) + break + # extend certificate list or throw error + if 'certificates' in content: + # cover cases where we wont get new data as we have to avoid loops + if prev_data != content['certificates']: + cert_list.extend(content['certificates']) + prev_data = content['certificates'] + offset = offset + limit + else: + self.logger.error('CAhandler.certificates_get() failed to get new data') + break + else: + self.logger.error('CAhandler.certificates_get() failed with code: %s', code) + break + + self.logger.debug('CAhandler.certificates_get() ended with code: %s and %s certificate', code, len(cert_list)) + return cert_list + + def enroll(self, csr: str) -> Tuple[str, str, str, str]: + """ enroll certificate """ + self.logger.debug('CAhandler.enroll()') + + cert_bundle = None + error = None + cert_raw = None + poll_indentifier = None + + error = self._enroll_check(csr) + + if not error: + error, cert_bundle, cert_raw, poll_indentifier = self._enroll(csr) + + self.logger.debug('Certificate.enroll() ended') + return error, cert_bundle, cert_raw, poll_indentifier + + def poll(self, _cert_name: str, poll_identifier: str, _csr: str) -> Tuple[str, str, str, str, bool]: + """ poll status of pending CSR and download certificates """ + self.logger.debug('CAhandler.poll()') + + error = 'Method not implemented.' + cert_bundle = None + cert_raw = None + rejected = False + + self.logger.debug('CAhandler.poll() ended') + return (error, cert_bundle, cert_raw, poll_identifier, rejected) + + def revoke(self, certificate_raw: str, _rev_reason: str = 'unspecified', _rev_date: str = uts_to_date_utc(uts_now())) -> Tuple[int, str, str]: + """ revoke certificate """ + self.logger.debug('CAhandler.revoke()') + + code = None + message = None + detail = None + + # get tracking id as input for revocation call + tracking_id = self._trackingid_get(certificate_raw) + + if tracking_id: + code, content = self.revoke_by_trackingid(tracking_id, _rev_reason) + if code == 200: + message = 'Certificate revoked' + else: + code = 500 + message = 'urn:ietf:params:acme:error:serverInternal' + detail = content + else: + code = 500 + message = 'urn:ietf:params:acme:error:serverInternal' + detail = 'Failed to get tracking id' + + self.logger.debug('CAhandler.poll() ended') + + self.logger.debug('Certificate.revoke() ended') + return (code, message, detail) + + def trigger(self, _payload: str) -> Tuple[str, str, str]: + """ process trigger message and return certificate """ + self.logger.debug('CAhandler.trigger()') + + error = 'Method not implemented.' + cert_bundle = None + cert_raw = None + + self.logger.debug('CAhandler.trigger() ended with error: %s', error) + return (error, cert_bundle, cert_raw) diff --git a/examples/ca_handler/mscertsrv_ca_handler.py b/examples/ca_handler/mscertsrv_ca_handler.py index d76ee928..8783a87c 100644 --- a/examples/ca_handler/mscertsrv_ca_handler.py +++ b/examples/ca_handler/mscertsrv_ca_handler.py @@ -18,6 +18,7 @@ class CAhandler(object): def __init__(self, _debug: bool = False, logger: object = None): self.logger = logger self.host = None + self.url = None self.user = None self.password = None self.auth_method = 'basic' @@ -122,9 +123,21 @@ def _config_hostname_load(self, config_dic: Dict[str, str]): if self.host: self.logger.info('CAhandler._config_load() overwrite host') self.host = config_dic['CAhandler']['host'] - self.logger.debug('CAhandler._config_hostname_load() ended') + def _config_url_load(self, config_dic: Dict[str, str]): + if 'url_variable' in config_dic['CAhandler']: + try: + self.url = os.environ[config_dic['CAhandler']['url_variable']] + except Exception as err: + self.logger.error('CAhandler._config_load() could not load url_variable:%s', err) + if 'url' in config_dic['CAhandler']: + if self.url: + self.logger.info('CAhandler._config_load() overwrite url') + self.url = config_dic['CAhandler']['url'] + + self.logger.debug('CAhandler._config_url_load() ended') + def _config_parameters_load(self, config_dic: Dict[str, str]): """ load hostname """ self.logger.debug('CAhandler._config_parameters_load()') @@ -172,6 +185,7 @@ def _config_load(self): if 'CAhandler' in config_dic: # load parameters from config dic self._config_hostname_load(config_dic) + self._config_url_load(config_dic) self._config_user_load(config_dic) self._config_password_load(config_dic) self._config_parameters_load(config_dic) @@ -285,6 +299,29 @@ def _domainlist_check(self, csr: str) -> bool: self.logger.debug('CAhandler._domainlist_check() ended with: %s', result) return result + def _enroll(self, csr: str) -> Tuple[str, str, str]: + """ enroll certificate """ + self.logger.debug('CAhandler._enroll()') + # setup certserv + ca_server = Certsrv(self.host, self.url, self.user, self.password, self.auth_method, self.ca_bundle, verify=self.verify, proxies=self.proxy) + + error = None + cert_bundle = None + cert_raw = None + + # check connection and credentials + auth_check = self._check_credentials(ca_server) + + if auth_check: + # enroll certificate + (error, cert_bundle, cert_raw) = self._csr_process(ca_server, csr) + else: + self.logger.error('Connection or Credentialcheck failed') + error = 'Connection or Credentialcheck failed.' + + self.logger.debug('CAhandler._enroll() ended with error: %s', error) + return (error, cert_bundle, cert_raw) + def enroll(self, csr: str) -> Tuple[str, str, str, bool]: """ enroll certificate from via MS certsrv """ self.logger.debug('CAhandler.enroll(%s)', self.template) @@ -294,31 +331,17 @@ def enroll(self, csr: str) -> Tuple[str, str, str, bool]: self._parameter_overwrite(csr) - if self.host and self.user and self.password and self.template: + if (self.host or self.url) and self.user and self.password and self.template: # check if domain is in allowed domainlis result = self._domainlist_check(csr) if result: - # check for eab profiling and header_info error = eab_profile_header_info_check(self.logger, self, csr, 'template') - if not error: - # setup certserv - ca_server = Certsrv(self.host, self.user, self.password, self.auth_method, self.ca_bundle, verify=self.verify, proxies=self.proxy) - - # check connection and credentials - auth_check = self._check_credentials(ca_server) - - if auth_check: - - # enroll certificate - (error, cert_bundle, cert_raw) = self._csr_process(ca_server, csr) - - else: - self.logger.error('Connection or Credentialcheck failed') - error = 'Connection or Credentialcheck failed.' + # enroll certificate + (error, cert_bundle, cert_raw) = self._enroll(csr) else: self.logger.error('EAB profile check failed') else: diff --git a/examples/ca_handler/openssl_ca_handler.py b/examples/ca_handler/openssl_ca_handler.py index 822c84b8..ecc78a36 100644 --- a/examples/ca_handler/openssl_ca_handler.py +++ b/examples/ca_handler/openssl_ca_handler.py @@ -135,6 +135,7 @@ def _cert_extension_dic_parse(self, cert_extension_dic: Dict[str, str], cert: st elif ext_name.lower() == 'subjectkeyidentifier': self.logger.info('CAhandler.cert_extesion_dic_parse(): subjectKeyIdentifier') _tmp_dic['name'] = SubjectKeyIdentifier.from_public_key(cert.public_key()) + _tmp_dic['critical'] = False elif ext_name.lower() == 'authoritykeyidentifier': self.logger.info('CAhandler.cert_extesion_dic_parse(): authorityKeyIdentifier') _tmp_dic['name'] = AuthorityKeyIdentifier.from_issuer_public_key(ca_cert.public_key()) diff --git a/examples/install_scripts/debian/control b/examples/install_scripts/debian/control index 63fd840a..db357d03 100644 --- a/examples/install_scripts/debian/control +++ b/examples/install_scripts/debian/control @@ -11,7 +11,7 @@ Rules-Requires-Root: no Package: acme2certifier Architecture: all -Depends: ${misc:Depends}, tzdata, python3-setuptools, python3-jwcrypto, python3-cryptography, python3-openssl, python3-dnspython, python3-pytzdata, python3-configargparse, python3-dateutil, python3-requests, python3-requests-ntlm, python3-socks, python3-josepy, python3-acme, python3-impacket, python3-xmltodict, python3-pyasn1, python3-pyasn1-modules, python3-django, python3-mysqldb, python3-pymysql, python3-psycopg2, python3-yaml +Depends: ${misc:Depends}, tzdata, python3-setuptools, python3-jwcrypto, python3-cryptography, python3-openssl, python3-dnspython, python3-pytzdata, python3-configargparse, python3-dateutil, python3-requests, python3-requests-ntlm, python3-socks, python3-josepy, python3-acme, python3-xmltodict, python3-pyasn1, python3-pyasn1-modules, python3-django, python3-mysqldb, python3-pymysql, python3-psycopg2, python3-yaml Description: Library implementing ACME server functionality acme2certifier is development project to create an ACME protocol proxy. Main intention is to provide ACME services on CA servers which do not support this protocol yet. After installation remember to install either NGINX or apache2! diff --git a/examples/install_scripts/rpm/acme2certifier.spec b/examples/install_scripts/rpm/acme2certifier.spec index e75cf545..44370602 100644 --- a/examples/install_scripts/rpm/acme2certifier.spec +++ b/examples/install_scripts/rpm/acme2certifier.spec @@ -36,7 +36,6 @@ Requires: python3-requests-pkcs12 Requires: python3-pysocks Requires: python3-josepy Requires: python3-acme -Requires: python3-impacket Requires: python3-xmltodict Requires: python3-pyasn1 Requires: python3-pyasn1-modules diff --git a/requirements.txt b/requirements.txt index bbb2f893..2f762c63 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,7 +11,6 @@ requests pysocks josepy acme -impacket xmltodict pyasn1 pyasn1_modules diff --git a/test/test_digicert.py b/test/test_digicert.py new file mode 100644 index 00000000..96d068a9 --- /dev/null +++ b/test/test_digicert.py @@ -0,0 +1,803 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" unittests for openxpki_ca_handler """ +# pylint: disable=C0415, R0904, W0212 +import sys +import os +import unittest +from unittest.mock import patch, Mock, MagicMock +import requests +import base64 +from OpenSSL import crypto + +sys.path.insert(0, '.') +sys.path.insert(1, '..') + +class FakeDBStore(object): + """ face DBStore class needed for mocking """ + # pylint: disable=W0107, R0903 + pass + +class TestACMEHandler(unittest.TestCase): + """ test class for cgi_handler """ + + def setUp(self): + """ setup unittest """ + models_mock = MagicMock() + models_mock.acme_srv.db_handler.DBstore.return_value = FakeDBStore + modules = {'acme_srv.db_handler': models_mock} + patch.dict('sys.modules', modules).start() + import logging + from examples.ca_handler.digicert_ca_handler import CAhandler + logging.basicConfig(level=logging.CRITICAL) + self.logger = logging.getLogger('test_a2c') + self.cahandler = CAhandler(False, self.logger) + self.dir_path = os.path.dirname(os.path.realpath(__file__)) + + def test_001_default(self): + """ default test which always passes """ + self.assertEqual('foo', 'foo') + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._config_load') + def test_002__enter__(self, mock_cfg): + """ test enter called """ + mock_cfg.return_value = True + self.cahandler.__enter__() + self.assertTrue(mock_cfg.called) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._config_load') + def test_003__enter__(self, mock_cfg): + """ test enter api hosts defined """ + mock_cfg.return_value = True + self.cahandler.api_key = 'api_key' + self.cahandler.__enter__() + self.assertFalse(mock_cfg.called) + + def test_004_poll(self): + """ test polling """ + self.assertEqual(('Method not implemented.', None, None, 'poll_identifier', False), self.cahandler.poll('cert_name', 'poll_identifier', 'csr')) + + def test_005_trigger(self): + """ test polling """ + self.assertEqual(('Method not implemented.', None, None), self.cahandler.trigger('payload')) + + @patch('examples.ca_handler.digicert_ca_handler.allowed_domainlist_check') + def test_006_allowed_domainlist_check(self, mock_adc): + """ test allowed_domainlist_check """ + self.cahandler.allowed_domainlist = False + self.assertFalse(self.cahandler._allowed_domainlist_check('csr')) + self.assertFalse(mock_adc.called) + + @patch('examples.ca_handler.digicert_ca_handler.allowed_domainlist_check') + def test_007_allowed_domainlist_check(self, mock_adc): + """ test allowed_domainlist_check """ + self.cahandler.allowed_domainlist = ["test.com"] + mock_adc.return_value = True + self.assertFalse(self.cahandler._allowed_domainlist_check('csr')) + self.assertTrue(mock_adc.called) + + @patch('examples.ca_handler.digicert_ca_handler.allowed_domainlist_check') + def test_008_allowed_domainlist_check(self, mock_adc): + """ test allowed_domainlist_check """ + self.cahandler.allowed_domainlist = ["test.com"] + mock_adc.return_value = False + self.assertEqual('Either CN or SANs are not allowed by configuration', self.cahandler._allowed_domainlist_check('csr')) + self.assertTrue(mock_adc.called) + + @patch.object(requests, 'post') + def test_009__api_post(self, mock_req): + """ test _api_post() """ + mockresponse = Mock() + mockresponse.status_code = 'status_code' + mockresponse.json = lambda: {'foo': 'bar'} + mock_req.return_value = mockresponse + self.assertEqual(('status_code', {'foo': 'bar'}), self.cahandler._api_post('url', 'data')) + + @patch('requests.post') + def test_010__api_post(self, mock_req): + """ test _api_post() """ + mockresponse = Mock() + mockresponse.status_code = 'status_code' + mockresponse.json = "aaaa" + mock_req.return_value = mockresponse + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual(('status_code', "'str' object is not callable"), self.cahandler._api_post('url', 'data')) + self.assertIn("ERROR:test_a2c:CAhandler._api_post() returned error during json parsing: 'str' object is not callable", lcm.output) + + @patch('requests.post') + def test_011__api_post(self, mock_req): + """ test _api_post() """ + mockresponse = Mock() + mockresponse.status_code = 'status_code' + mockresponse.text = None + mock_req.return_value = mockresponse + self.assertEqual(('status_code', None), self.cahandler._api_post('url', 'data')) + + @patch('requests.post') + def test_012__api_post(self, mock_req): + """ test _api_post(= """ + self.cahandler.api_host = 'api_host' + self.cahandler.auth = 'auth' + mock_req.side_effect = Exception('exc_api_post') + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual((500, 'exc_api_post'), self.cahandler._api_post('url', 'data')) + self.assertIn('ERROR:test_a2c:CAhandler._api_post() returned error: exc_api_post', lcm.output) + + @patch.object(requests, 'get') + def test_013__api_get(self, mock_req): + """ test _api_get() """ + mockresponse = Mock() + mockresponse.status_code = 'status_code' + mockresponse.json = lambda: {'foo': 'bar'} + mock_req.return_value = mockresponse + self.assertEqual(('status_code', {'foo': 'bar'}), self.cahandler._api_get('url')) + + @patch('requests.get') + def test_014__api_get(self, mock_req): + """ test _api_get() """ + mockresponse = Mock() + mockresponse.status_code = 'status_code' + mockresponse.json = "aaaa" + mock_req.return_value = mockresponse + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual(('status_code', "'str' object is not callable"), self.cahandler._api_get('url')) + self.assertIn("ERROR:test_a2c:CAhandler._api_get() returned error during json parsing: 'str' object is not callable", lcm.output) + + @patch('requests.get') + def test_015__api_get(self, mock_req): + """ test _api_get() """ + self.cahandler.api_host = 'api_host' + self.cahandler.auth = 'auth' + mock_req.side_effect = Exception('exc_api_get') + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual((500, 'exc_api_get'), self.cahandler._api_get('url')) + self.assertIn('ERROR:test_a2c:CAhandler._api_get() returned error: exc_api_get', lcm.output) + + @patch.object(requests, 'put') + def test_016__api_put(self, mock_req): + """ test _api_put() """ + mockresponse = Mock() + mockresponse.status_code = 'status_code' + mockresponse.json = lambda: {'foo': 'bar'} + mock_req.return_value = mockresponse + self.assertEqual(('status_code', {'foo': 'bar'}), self.cahandler._api_put('url', 'data')) + + @patch('requests.put') + def test_017__api_put(self, mock_req): + """ test _api_put() """ + mockresponse = Mock() + mockresponse.status_code = 'status_code' + mockresponse.json = "aaaa" + mock_req.return_value = mockresponse + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual(('status_code', "'str' object is not callable"), self.cahandler._api_put('url', 'data')) + self.assertIn("ERROR:test_a2c:CAhandler._api_put() returned error during json parsing: 'str' object is not callable", lcm.output) + + @patch('requests.put') + def test_018__api_put(self, mock_req): + """ test _api_put() """ + mockresponse = Mock() + mockresponse.status_code = 'status_code' + mockresponse.text = None + mock_req.return_value = mockresponse + self.assertEqual(('status_code', None), self.cahandler._api_put('url', 'data')) + + @patch('requests.put') + def test_019__api_put(self, mock_req): + """ test _api_put() """ + self.cahandler.api_host = 'api_host' + self.cahandler.auth = 'auth' + mock_req.side_effect = Exception('exc_api_put') + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual((500, 'exc_api_put'), self.cahandler._api_put('url', 'data')) + self.assertIn('ERROR:test_a2c:CAhandler._api_put() returned error: exc_api_put', lcm.output) + + def test_020__config_check(self): + """ test _config_check() """ + self.cahandler.api_url = 'api_url' + self.assertEqual('api_key parameter in missing in config file', self.cahandler._config_check()) + + def test_021__config_check(self): + """ test _config_check() """ + self.cahandler.api_url = 'api_url' + self.cahandler.api_key = 'api_key' + self.assertEqual('organization_name parameter in missing in config file', self.cahandler._config_check()) + + def test_022__config_check(self): + """ test _config_check() """ + self.cahandler.api_url = 'api_url' + self.cahandler.api_key = 'api_key' + self.cahandler.organization_name = 'organization_name' + self.assertFalse(self.cahandler._config_check()) + + @patch('examples.ca_handler.digicert_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.digicert_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.digicert_ca_handler.load_config') + def test_023_config_load(self, mock_load, mock_eab, mock_hdl): + """ test _config_load() """ + mock_load.return_value = {'foo': 'bar'} + mock_eab.return_value = True, 'eab' + mock_hdl.return_value = 'hdl' + self.cahandler._config_load() + self.assertTrue(mock_load.called) + self.assertEqual('https://www.digicert.com/services/v2/', self.cahandler.api_url) + self.assertFalse(self.cahandler.api_key) + self.assertEqual('ssl_basic', self.cahandler.cert_type) + self.assertEqual('sha256', self.cahandler.signature_hash) + self.assertEqual(1, self.cahandler.order_validity) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertFalse(self.cahandler.organization_name) + self.assertFalse(self.cahandler.organization_id) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual('eab', self.cahandler.eab_handler) + self.assertEqual('hdl', self.cahandler.header_info_field) + + @patch('examples.ca_handler.digicert_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.digicert_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.digicert_ca_handler.load_config') + def test_024_config_load(self, mock_load, mock_eab, mock_hdl): + """ test _config_load() """ + mock_load.return_value = {'foo': 'bar', 'CAhandler': {'api_url': 'api_url'}} + mock_eab.return_value = True, 'eab' + mock_hdl.return_value = 'hdl' + self.cahandler._config_load() + self.assertTrue(mock_load.called) + self.assertEqual('api_url', self.cahandler.api_url) + self.assertFalse(self.cahandler.api_key) + self.assertEqual('ssl_basic', self.cahandler.cert_type) + self.assertEqual('sha256', self.cahandler.signature_hash) + self.assertEqual(1, self.cahandler.order_validity) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertFalse(self.cahandler.organization_name) + self.assertFalse(self.cahandler.organization_id) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual('eab', self.cahandler.eab_handler) + self.assertEqual('hdl', self.cahandler.header_info_field) + + @patch('examples.ca_handler.digicert_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.digicert_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.digicert_ca_handler.load_config') + def test_025_config_load(self, mock_load, mock_eab, mock_hdl): + """ test _config_load() """ + mock_load.return_value = {'foo': 'bar', 'CAhandler': {'api_key': 'api_key'}} + mock_eab.return_value = True, 'eab' + mock_hdl.return_value = 'hdl' + self.cahandler._config_load() + self.assertTrue(mock_load.called) + self.assertEqual('https://www.digicert.com/services/v2/', self.cahandler.api_url) + self.assertEqual('api_key', self.cahandler.api_key) + self.assertEqual('ssl_basic', self.cahandler.cert_type) + self.assertEqual('sha256', self.cahandler.signature_hash) + self.assertEqual(1, self.cahandler.order_validity) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertFalse(self.cahandler.organization_name) + self.assertFalse(self.cahandler.organization_id) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual('eab', self.cahandler.eab_handler) + self.assertEqual('hdl', self.cahandler.header_info_field) + + @patch('examples.ca_handler.digicert_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.digicert_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.digicert_ca_handler.load_config') + def test_026_config_load(self, mock_load, mock_eab, mock_hdl): + """ test _config_load() """ + mock_load.return_value = {'foo': 'bar', 'CAhandler': {'signature_hash': 'signature_hash'}} + mock_eab.return_value = True, 'eab' + mock_hdl.return_value = 'hdl' + self.cahandler._config_load() + self.assertTrue(mock_load.called) + self.assertEqual('https://www.digicert.com/services/v2/', self.cahandler.api_url) + self.assertFalse(self.cahandler.api_key) + self.assertEqual('ssl_basic', self.cahandler.cert_type) + self.assertEqual('signature_hash', self.cahandler.signature_hash) + self.assertEqual(1, self.cahandler.order_validity) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertFalse(self.cahandler.organization_name) + self.assertFalse(self.cahandler.organization_id) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual('eab', self.cahandler.eab_handler) + self.assertEqual('hdl', self.cahandler.header_info_field) + + @patch('examples.ca_handler.digicert_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.digicert_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.digicert_ca_handler.load_config') + def test_027_config_load(self, mock_load, mock_eab, mock_hdl): + """ test _config_load() """ + mock_load.return_value = {'foo': 'bar', 'CAhandler': {'cert_type': 'cert_type'}} + mock_eab.return_value = True, 'eab' + mock_hdl.return_value = 'hdl' + self.cahandler._config_load() + self.assertTrue(mock_load.called) + self.assertEqual('https://www.digicert.com/services/v2/', self.cahandler.api_url) + self.assertFalse(self.cahandler.api_key) + self.assertEqual('cert_type', self.cahandler.cert_type) + self.assertEqual('sha256', self.cahandler.signature_hash) + self.assertEqual(1, self.cahandler.order_validity) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertFalse(self.cahandler.organization_name) + self.assertFalse(self.cahandler.organization_id) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual('eab', self.cahandler.eab_handler) + self.assertEqual('hdl', self.cahandler.header_info_field) + + @patch('examples.ca_handler.digicert_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.digicert_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.digicert_ca_handler.load_config') + def test_028_config_load(self, mock_load, mock_eab, mock_hdl): + """ test _config_load() """ + mock_load.return_value = {'foo': 'bar', 'CAhandler': {'order_validity': 2}} + mock_eab.return_value = True, 'eab' + mock_hdl.return_value = 'hdl' + self.cahandler._config_load() + self.assertTrue(mock_load.called) + self.assertEqual('https://www.digicert.com/services/v2/', self.cahandler.api_url) + self.assertFalse(self.cahandler.api_key) + self.assertEqual('ssl_basic', self.cahandler.cert_type) + self.assertEqual('sha256', self.cahandler.signature_hash) + self.assertEqual(2, self.cahandler.order_validity) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertFalse(self.cahandler.organization_name) + self.assertFalse(self.cahandler.organization_id) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual('eab', self.cahandler.eab_handler) + self.assertEqual('hdl', self.cahandler.header_info_field) + + @patch('examples.ca_handler.digicert_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.digicert_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.digicert_ca_handler.load_config') + def test_029_config_load(self, mock_load, mock_eab, mock_hdl): + """ test _config_load() """ + mock_load.return_value = {'foo': 'bar', 'CAhandler': {'request_timeout': 20}} + mock_eab.return_value = True, 'eab' + mock_hdl.return_value = 'hdl' + self.cahandler._config_load() + self.assertTrue(mock_load.called) + self.assertEqual('https://www.digicert.com/services/v2/', self.cahandler.api_url) + self.assertFalse(self.cahandler.api_key) + self.assertEqual('ssl_basic', self.cahandler.cert_type) + self.assertEqual('sha256', self.cahandler.signature_hash) + self.assertEqual(1, self.cahandler.order_validity) + self.assertEqual(20, self.cahandler.request_timeout) + self.assertFalse(self.cahandler.organization_name) + self.assertFalse(self.cahandler.organization_id) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual('eab', self.cahandler.eab_handler) + self.assertEqual('hdl', self.cahandler.header_info_field) + + @patch('examples.ca_handler.digicert_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.digicert_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.digicert_ca_handler.load_config') + def test_030_config_load(self, mock_load, mock_eab, mock_hdl): + """ test _config_load() """ + mock_load.return_value = {'foo': 'bar', 'CAhandler': {'organization_name': 'organization_name'}} + mock_eab.return_value = True, 'eab' + mock_hdl.return_value = 'hdl' + self.cahandler._config_load() + self.assertTrue(mock_load.called) + self.assertEqual('https://www.digicert.com/services/v2/', self.cahandler.api_url) + self.assertFalse(self.cahandler.api_key) + self.assertEqual('ssl_basic', self.cahandler.cert_type) + self.assertEqual('sha256', self.cahandler.signature_hash) + self.assertEqual(1, self.cahandler.order_validity) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertEqual('organization_name', self.cahandler.organization_name) + self.assertFalse(self.cahandler.organization_id) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual('eab', self.cahandler.eab_handler) + self.assertEqual('hdl', self.cahandler.header_info_field) + + @patch('examples.ca_handler.digicert_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.digicert_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.digicert_ca_handler.load_config') + def test_031_config_load(self, mock_load, mock_eab, mock_hdl): + """ test _config_load() """ + mock_load.return_value = {'foo': 'bar', 'CAhandler': {'organization_id': 'organization_id'}} + mock_eab.return_value = True, 'eab' + mock_hdl.return_value = 'hdl' + self.cahandler._config_load() + self.assertTrue(mock_load.called) + self.assertEqual('https://www.digicert.com/services/v2/', self.cahandler.api_url) + self.assertFalse(self.cahandler.api_key) + self.assertEqual('ssl_basic', self.cahandler.cert_type) + self.assertEqual('sha256', self.cahandler.signature_hash) + self.assertEqual(1, self.cahandler.order_validity) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertFalse(self.cahandler.organization_name) + self.assertEqual('organization_id', self.cahandler.organization_id) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual('eab', self.cahandler.eab_handler) + self.assertEqual('hdl', self.cahandler.header_info_field) + + @patch('examples.ca_handler.digicert_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.digicert_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.digicert_ca_handler.load_config') + def test_032_config_load(self, mock_load, mock_eab, mock_hdl): + """ test _config_load() """ + mock_load.return_value = {'foo': 'bar', 'CAhandler': {'allowed_domainlist': '["foo", "bar"]'}} + mock_eab.return_value = True, 'eab' + mock_hdl.return_value = 'hdl' + self.cahandler._config_load() + self.assertTrue(mock_load.called) + self.assertEqual('https://www.digicert.com/services/v2/', self.cahandler.api_url) + self.assertFalse(self.cahandler.api_key) + self.assertEqual('ssl_basic', self.cahandler.cert_type) + self.assertEqual('sha256', self.cahandler.signature_hash) + self.assertEqual(1, self.cahandler.order_validity) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertFalse(self.cahandler.organization_name) + self.assertFalse(self.cahandler.organization_id) + self.assertEqual(['foo', 'bar'], self.cahandler.allowed_domainlist) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual('eab', self.cahandler.eab_handler) + self.assertEqual('hdl', self.cahandler.header_info_field) + + @patch('examples.ca_handler.digicert_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.digicert_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.digicert_ca_handler.load_config') + def test_033_config_load(self, mock_load, mock_eab, mock_hdl): + """ test _config_load() """ + mock_load.return_value = {'foo': 'bar', 'CAhandler': {'allowed_domainlist': '["foo"]'}} + mock_eab.return_value = True, 'eab' + mock_hdl.return_value = 'hdl' + self.cahandler._config_load() + self.assertTrue(mock_load.called) + self.assertEqual('https://www.digicert.com/services/v2/', self.cahandler.api_url) + self.assertFalse(self.cahandler.api_key) + self.assertEqual('ssl_basic', self.cahandler.cert_type) + self.assertEqual('sha256', self.cahandler.signature_hash) + self.assertEqual(1, self.cahandler.order_validity) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertFalse(self.cahandler.organization_name) + self.assertFalse(self.cahandler.organization_id) + self.assertEqual(['foo'], self.cahandler.allowed_domainlist) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual('eab', self.cahandler.eab_handler) + self.assertEqual('hdl', self.cahandler.header_info_field) + + @patch('examples.ca_handler.digicert_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.digicert_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.digicert_ca_handler.load_config') + def test_034_config_load(self, mock_load, mock_eab, mock_hdl): + """ test _config_load() """ + mock_load.return_value = {'foo': 'bar', 'CAhandler': {'allowed_domainlist': "foo"}} + mock_eab.return_value = True, 'eab' + mock_hdl.return_value = 'hdl' + self.cahandler._config_load() + self.assertTrue(mock_load.called) + self.assertEqual('https://www.digicert.com/services/v2/', self.cahandler.api_url) + self.assertFalse(self.cahandler.api_key) + self.assertEqual('ssl_basic', self.cahandler.cert_type) + self.assertEqual('sha256', self.cahandler.signature_hash) + self.assertEqual(1, self.cahandler.order_validity) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertFalse(self.cahandler.organization_name) + self.assertFalse(self.cahandler.organization_id) + self.assertEqual('failed to parse', self.cahandler.allowed_domainlist) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual('eab', self.cahandler.eab_handler) + self.assertEqual('hdl', self.cahandler.header_info_field) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._organiation_id_get') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._api_post') + def test_035_order_send(self, mock_post, mock_orgid): + """ test _order_send() """ + mock_post.return_value = ('code', 'content') + self.cahandler.organization_id = 'organization_id' + self.assertEqual(('code', 'content'), self.cahandler._order_send('csr', 'cn')) + self.assertFalse(mock_orgid.called) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._organiation_id_get') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._api_post') + def test_036_order_send(self, mock_post, mock_orgid): + """ test _order_send() """ + mock_post.return_value = ('code', 'content') + self.assertEqual((500, 'organisation_id is missing'), self.cahandler._order_send('csr', 'cn')) + self.assertFalse(mock_orgid.called) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._organiation_id_get') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._api_post') + def test_037_order_send(self, mock_post, mock_orgid): + """ test _order_send() """ + mock_post.return_value = ('code', 'content') + self.cahandler.eab_profiling = True + self.cahandler.api_key = 'api_key' + self.cahandler.organization_name = 'organization_name' + self.cahandler.organization_id = 'organization_id' + self.assertEqual(('code', 'content'), self.cahandler._order_send('csr', 'cn')) + self.assertTrue(mock_orgid.called) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._organiation_id_get') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._api_post') + def test_038_order_send(self, mock_post, mock_orgid): + """ test _order_send() """ + mock_post.return_value = ('code', 'content') + self.cahandler.eab_profiling = True + self.cahandler.api_key = 'api_key' + self.cahandler.organization_name = 'organization_name' + self.cahandler.organization_id = None + mock_orgid.return_value = 1 + self.assertEqual(('code', 'content'), self.cahandler._order_send('csr', 'cn')) + self.assertTrue(mock_orgid.called) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._organiation_id_get') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._api_post') + def test_039_order_send(self, mock_post, mock_orgid): + """ test _order_send() """ + mock_post.return_value = ('code', 'content') + self.cahandler.api_key = 'api_key' + self.cahandler.organization_name = 'organization_name' + self.cahandler.organization_id = None + mock_orgid.return_value = 1 + self.assertEqual(('code', 'content'), self.cahandler._order_send('csr', 'cn')) + self.assertTrue(mock_orgid.called) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._organiation_id_get') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._api_post') + def test_040_order_send(self, mock_post, mock_orgid): + """ test _order_send() """ + mock_post.return_value = ('code', 'content') + self.cahandler.api_key = 'api_key' + self.cahandler.organization_name = None + self.cahandler.organization_id = None + mock_orgid.return_value = 1 + self.assertEqual((500, 'organisation_id is missing'), self.cahandler._order_send('csr', 'cn')) + self.assertFalse(mock_orgid.called) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._organiation_id_get') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._api_post') + def test_041_order_send(self, mock_post, mock_orgid): + """ test _order_send() """ + mock_post.return_value = ('code', 'content') + self.cahandler.api_key = None + self.cahandler.organization_name = 'organization_name' + self.cahandler.organization_id = None + mock_orgid.return_value = 1 + self.assertEqual((500, 'organisation_id is missing'), self.cahandler._order_send('csr', 'cn')) + self.assertFalse(mock_orgid.called) + + @patch('examples.ca_handler.digicert_ca_handler.cert_pem2der') + @patch('examples.ca_handler.digicert_ca_handler.b64_encode') + def test_042_order_response_parse(self, mock_b64, mock_pem2der): + """ test _order_parse() """ + content_dic = {'id': 'id', 'certificate_chain': [{'pem': 'pem1'}, {'pem': 'pem2'}, {'pem': 'pem3'}]} + mock_b64.return_value = 'b64' + self.assertEqual(('pem1\npem2\npem3\n', 'b64', 'id'), self.cahandler._order_response_parse(content_dic)) + + @patch('examples.ca_handler.digicert_ca_handler.cert_pem2der') + @patch('examples.ca_handler.digicert_ca_handler.b64_encode') + def test_043_order_response_parse(self, mock_b64, mock_pem2der): + """ test _order_parse() """ + content_dic = {'id': 'id', 'cert_chain': [{'pem': 'pem1'}, {'pem': 'pem2'}, {'pem': 'pem3'}]} + mock_b64.return_value = 'b64' + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual((None, None, None), self.cahandler._order_response_parse(content_dic)) + self.assertIn('ERROR:test_a2c:CAhandler._order_response_parse() failed: no certificate_chain in response', lcm.output) + + @patch('examples.ca_handler.digicert_ca_handler.cert_pem2der') + @patch('examples.ca_handler.digicert_ca_handler.b64_encode') + def test_044_order_response_parse(self, mock_b64, mock_pem2der): + """ test _order_parse() """ + content_dic = {'id': 'id', 'certificate_chain': [{'pem': 'pem1'}, {'_pem': 'pem2'}, {'pem': 'pem3'}]} + mock_b64.return_value = 'b64' + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual(('pem1\npem3\n', 'b64', 'id'), self.cahandler._order_response_parse(content_dic)) + self.assertIn('ERROR:test_a2c:CAhandler._order_response_parse() failed: no pem in certificate_chain', lcm.output) + + @patch('examples.ca_handler.digicert_ca_handler.cert_pem2der') + @patch('examples.ca_handler.digicert_ca_handler.b64_encode') + def test_045_order_response_parse(self, mock_b64, mock_pem2der): + """ test _order_parse() """ + content_dic = {'_id': 'id', 'certificate_chain': [{'pem': 'pem1'}, {'pem': 'pem2'}, {'pem': 'pem3'}]} + mock_b64.return_value = 'b64' + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual(('pem1\npem2\npem3\n', 'b64', None), self.cahandler._order_response_parse(content_dic)) + self.assertIn('ERROR:test_a2c:CAhandler._order_response_parse() polling_identifier generation failed: no id in response', lcm.output) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._api_get') + def test_046_organiation_id_get(self, mock_get): + """ test _organiation_id_get() """ + mock_get.return_value = (500, {'id': 'id'}) + self.cahandler.organization_name = 'organization_name' + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._organiation_id_get() + self.assertIn('ERROR:test_a2c:CAhandler._organiation_id_get() failed', lcm.output) + self.assertFalse(self.cahandler.organization_id) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._api_get') + def test_047_organiation_id_get(self, mock_get): + """ test _organiation_id_get() """ + mock_get.return_value = (200, {'organizations': [{'name': 'name1', 'id': 'id1'}, {'name': 'name2', 'id': 'id2'}, {'name': 'name3', 'id': 'id3'}]}) + self.cahandler.organization_name = 'name1' + self.assertEqual('id1', self.cahandler._organiation_id_get()) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._api_get') + def test_048_organiation_id_get(self, mock_get): + """ test _organiation_id_get() """ + mock_get.return_value = (200, {'organizations': [{'name': 'name1', 'id': 'id1'}, {'name': 'name2', 'id': 'id2'}, {'name': 'name3', 'id': 'id3'}]}) + self.cahandler.organization_name = 'name2' + self.assertEqual('id2', self.cahandler._organiation_id_get()) + + @patch('examples.ca_handler.digicert_ca_handler.eab_profile_header_info_check') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._allowed_domainlist_check') + def test_049_csr_check(self, mock_dlchk, mock_ehichk): + """ test _csr_check() """ + mock_dlchk.return_value = 'mock_dlchk' + mock_ehichk.return_value = 'mock_hichk' + + self.assertEqual('mock_dlchk', self.cahandler._csr_check('csr')) + + @patch('examples.ca_handler.digicert_ca_handler.eab_profile_header_info_check') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._allowed_domainlist_check') + def test_050_csr_check(self, mock_dlchk, mock_ehichk): + """ test _csr_check() """ + mock_dlchk.return_value = False + mock_ehichk.return_value = 'mock_hichk' + self.assertEqual('mock_hichk', self.cahandler._csr_check('csr')) + + @patch('examples.ca_handler.digicert_ca_handler.eab_profile_header_info_check') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._allowed_domainlist_check') + def test_051_csr_check(self, mock_dlchk, mock_ehichk): + """ test _csr_check() """ + mock_dlchk.return_value = False + mock_ehichk.return_value = False + self.assertFalse(self.cahandler._csr_check('csr')) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._order_response_parse') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._order_send') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._csr_cn_lookup') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._csr_check') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._config_check') + def test_052_enroll(self, mock_cfgchk, mock_csrchk, mock_cnget, mock_ordersend, mock_orderparse): + """ test enroll() """ + mock_cfgchk.return_value = 'mock_cfgchk' + mock_csrchk.return_value = 'mock_csrchk' + mock_cnget.return_value = 'cn' + mock_ordersend.return_value = ('code', 'content') + mock_orderparse.return_value = ('pem', 'b64', 'id') + self.assertEqual(('mock_cfgchk', None, None, None), self.cahandler.enroll('csr')) + self.assertTrue(mock_cfgchk.called) + self.assertFalse(mock_csrchk.called) + self.assertFalse(mock_cnget.called) + self.assertFalse(mock_ordersend.called) + self.assertFalse(mock_orderparse.called) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._order_response_parse') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._order_send') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._csr_cn_lookup') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._csr_check') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._config_check') + def test_053_enroll(self, mock_cfgchk, mock_csrchk, mock_cnget, mock_ordersend, mock_orderparse): + """ test enroll() """ + mock_cfgchk.return_value = False + mock_csrchk.return_value = 'mock_csrchk' + mock_cnget.return_value = 'cn' + mock_ordersend.return_value = ('code', 'content') + mock_orderparse.return_value = ('pem', 'b64', 'id') + self.assertEqual(('mock_csrchk', None, None, None), self.cahandler.enroll('csr')) + self.assertTrue(mock_cfgchk.called) + self.assertTrue(mock_csrchk.called) + self.assertFalse(mock_cnget.called) + self.assertFalse(mock_ordersend.called) + self.assertFalse(mock_orderparse.called) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._order_response_parse') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._order_send') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._csr_cn_lookup') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._csr_check') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._config_check') + def test_054_enroll(self, mock_cfgchk, mock_csrchk, mock_cnget, mock_ordersend, mock_orderparse): + """ test enroll() """ + mock_cfgchk.return_value = False + mock_csrchk.return_value = False + mock_cnget.return_value = 'cn' + mock_ordersend.return_value = ('code', 'content') + mock_orderparse.return_value = ('pem', 'b64', 'id') + self.assertEqual(('Error during order creation: code - content', None, None, None), self.cahandler.enroll('csr')) + self.assertTrue(mock_cfgchk.called) + self.assertTrue(mock_csrchk.called) + self.assertTrue(mock_cnget.called) + self.assertTrue(mock_ordersend.called) + self.assertFalse(mock_orderparse.called) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._order_response_parse') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._order_send') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._csr_cn_lookup') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._csr_check') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._config_check') + def test_055_enroll(self, mock_cfgchk, mock_csrchk, mock_cnget, mock_ordersend, mock_orderparse): + """ test enroll() """ + mock_cfgchk.return_value = False + mock_csrchk.return_value = False + mock_cnget.return_value = 'cn' + mock_ordersend.return_value = ('code', {'errors': [{'code': 'code', 'message': 'content'}]}) + mock_orderparse.return_value = ('pem', 'b64', 'id') + self.assertEqual(("Error during order creation: code - [{'code': 'code', 'message': 'content'}]", None, None, None), self.cahandler.enroll('csr')) + self.assertTrue(mock_cfgchk.called) + self.assertTrue(mock_csrchk.called) + self.assertTrue(mock_cnget.called) + self.assertTrue(mock_ordersend.called) + self.assertFalse(mock_orderparse.called) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._order_response_parse') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._order_send') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._csr_cn_lookup') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._csr_check') + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._config_check') + def test_056_enroll(self, mock_cfgchk, mock_csrchk, mock_cnget, mock_ordersend, mock_orderparse): + """ test enroll() """ + mock_cfgchk.return_value = False + mock_csrchk.return_value = False + mock_cnget.return_value = 'cn' + mock_ordersend.return_value = (200, 'content') + mock_orderparse.return_value = ('pem', 'b64', 'id') + self.assertEqual((False, 'pem', 'b64', 'id'), self.cahandler.enroll('csr')) + self.assertTrue(mock_cfgchk.called) + self.assertTrue(mock_csrchk.called) + self.assertTrue(mock_cnget.called) + self.assertTrue(mock_ordersend.called) + self.assertTrue(mock_orderparse.called) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._api_put') + @patch('examples.ca_handler.digicert_ca_handler.cert_serial_get') + def test_057_revoke(self, mock_serial, mock_put): + """ test revoke() """ + mock_serial.return_value = 'serial' + mock_put.return_value = ('code', 'content') + self.assertEqual(('code', None, 'content'), self.cahandler.revoke('cert')) + + @patch('examples.ca_handler.digicert_ca_handler.CAhandler._api_put') + @patch('examples.ca_handler.digicert_ca_handler.cert_serial_get') + def test_058_revoke(self, mock_serial, mock_put): + """ test revoke() """ + mock_serial.return_value = None + mock_put.return_value = ('code', 'content') + self.assertEqual((500, None, 'Failed to parse certificate serial'), self.cahandler.revoke('cert')) + + @patch('examples.ca_handler.digicert_ca_handler.csr_san_get') + @patch('examples.ca_handler.digicert_ca_handler.csr_cn_get') + def test_059__csr_cn_lookup(self, mock_cnget, mock_san_get): + """ test _csr_cn_lookup() """ + mock_cnget.return_value = 'cn' + mock_san_get.return_value = ['foo:san1', 'foo:san2'] + self.assertEqual('cn', self.cahandler._csr_cn_lookup('csr')) + + @patch('examples.ca_handler.digicert_ca_handler.csr_san_get') + @patch('examples.ca_handler.digicert_ca_handler.csr_cn_get') + def test_060__csr_cn_lookup(self, mock_cnget, mock_san_get): + """ test _csr_cn_lookup() """ + mock_cnget.return_value = None + mock_san_get.return_value = ['foo:san1', 'foo:san2'] + self.assertEqual('san1', self.cahandler._csr_cn_lookup('csr')) + + @patch('examples.ca_handler.digicert_ca_handler.csr_san_get') + @patch('examples.ca_handler.digicert_ca_handler.csr_cn_get') + def test_061__csr_cn_lookup(self, mock_cnget, mock_san_get): + """ test _csr_cn_lookup() """ + mock_cnget.return_value = None + mock_san_get.return_value = ['foosan1', 'foo:san2'] + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual('san2', self.cahandler._csr_cn_lookup('csr')) + self.assertIn('ERROR:test_a2c:CAhandler._csr_cn_lookup() split failed: list index out of range', lcm.output) + + @patch('examples.ca_handler.digicert_ca_handler.csr_san_get') + @patch('examples.ca_handler.digicert_ca_handler.csr_cn_get') + def test_062__csr_cn_lookup(self, mock_cnget, mock_san_get): + """ test _csr_cn_lookup() """ + mock_cnget.return_value = None + mock_san_get.return_value = None + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertFalse(self.cahandler._csr_cn_lookup('csr')) + self.assertIn('ERROR:test_a2c:CAhandler._csr_cn_lookup() no SANs found in CSR', lcm.output) + +if __name__ == '__main__': + + unittest.main() diff --git a/test/test_entrust.py b/test/test_entrust.py new file mode 100644 index 00000000..cb79b09a --- /dev/null +++ b/test/test_entrust.py @@ -0,0 +1,1251 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +""" unittests for openxpki_ca_handler """ +# pylint: disable=C0415, R0904, W0212 +import sys +import os +import unittest +from unittest.mock import patch, mock_open, Mock, MagicMock +import requests +import base64 +from OpenSSL import crypto + +sys.path.insert(0, '.') +sys.path.insert(1, '..') + +class FakeDBStore(object): + """ face DBStore class needed for mocking """ + # pylint: disable=W0107, R0903 + pass + +class TestACMEHandler(unittest.TestCase): + """ test class for cgi_handler """ + + def setUp(self): + """ setup unittest """ + models_mock = MagicMock() + models_mock.acme_srv.db_handler.DBstore.return_value = FakeDBStore + modules = {'acme_srv.db_handler': models_mock} + patch.dict('sys.modules', modules).start() + import logging + from examples.ca_handler.entrust_ca_handler import CAhandler + logging.basicConfig(level=logging.CRITICAL) + self.logger = logging.getLogger('test_a2c') + self.cahandler = CAhandler(False, self.logger) + self.dir_path = os.path.dirname(os.path.realpath(__file__)) + + def test_001_default(self): + """ default test which always passes """ + self.assertEqual('foo', 'foo') + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_load') + def test_002__enter__(self, mock_cfg): + """ test enter called """ + mock_cfg.return_value = True + self.cahandler.__enter__() + self.assertTrue(mock_cfg.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_load') + def test_003__enter__(self, mock_cfg): + """ test enter api hosts defined """ + mock_cfg.return_value = True + self.cahandler.session = 'session' + self.cahandler.__enter__() + self.assertFalse(mock_cfg.called) + + def test_004_poll(self): + """ test polling """ + self.assertEqual(('Method not implemented.', None, None, 'poll_identifier', False), self.cahandler.poll('cert_name', 'poll_identifier', 'csr')) + + def test_005_trigger(self): + """ test polling """ + self.assertEqual(('Method not implemented.', None, None), self.cahandler.trigger('payload')) + + @patch('examples.ca_handler.entrust_ca_handler.allowed_domainlist_check') + def test_006_allowed_domainlist_check(self, mock_adc): + """ test allowed_domainlist_check """ + self.cahandler.allowed_domainlist = False + self.assertFalse(self.cahandler._allowed_domainlist_check('csr')) + self.assertFalse(mock_adc.called) + + @patch('examples.ca_handler.entrust_ca_handler.allowed_domainlist_check') + def test_007_allowed_domainlist_check(self, mock_adc): + """ test allowed_domainlist_check """ + self.cahandler.allowed_domainlist = ["test.com"] + mock_adc.return_value = True + self.assertFalse(self.cahandler._allowed_domainlist_check('csr')) + self.assertTrue(mock_adc.called) + + @patch('examples.ca_handler.entrust_ca_handler.allowed_domainlist_check') + def test_008_allowed_domainlist_check(self, mock_adc): + """ test allowed_domainlist_check """ + self.cahandler.allowed_domainlist = ["test.com"] + mock_adc.return_value = False + self.assertEqual('Either CN or SANs are not allowed by configuration', self.cahandler._allowed_domainlist_check('csr')) + self.assertTrue(mock_adc.called) + + def test_009__api_post(self): + """ test _api_post() """ + mockresponse = Mock() + mockresponse2 = Mock() + mockresponse2.status_code = 'status_code' + mockresponse2.text = 'foo' + mockresponse2.json = lambda: {'foo': 'bar'} + mockresponse = Mock() + mockresponse.post.side_effect = [mockresponse2] + self.cahandler.session = mockresponse + self.assertEqual(('status_code', {'foo': 'bar'}), self.cahandler._api_post('url', 'data')) + + def test_010__api_post(self): + """ test _api_post() """ + mockresponse2 = Mock() + mockresponse2.status_code = 'status_code' + mockresponse2.text = 'foo' + mockresponse2.json.side_effect = Exception('ex_json') + mockresponse = Mock() + mockresponse.post.side_effect = [mockresponse2] + self.cahandler.session = mockresponse + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual(('status_code', 'ex_json'), self.cahandler._api_post('url', 'data')) + self.assertIn('ERROR:test_a2c:CAhandler._api_post() returned error during json parsing: ex_json', lcm.output) + + def test_011__api_post(self): + """ test _api_post() """ + mockresponse2 = Mock() + mockresponse2.status_code = 'status_code' + mockresponse2.text = None + mockresponse2.json = lambda: {'foo': 'bar'} + mockresponse = Mock() + mockresponse.post.side_effect = [mockresponse2] + self.cahandler.session = mockresponse + self.assertEqual(('status_code', None), self.cahandler._api_post('url', 'data')) + + def test_012__api_post(self): + """ test _api_post(= """ + mockresponse = Mock() + mockresponse.post.side_effect = [Exception('exc_api_post')] + self.cahandler.session = mockresponse + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual((500, 'exc_api_post'), self.cahandler._api_post('url', 'data')) + self.assertIn('ERROR:test_a2c:CAhandler._api_post() returned error: exc_api_post', lcm.output) + + def test_013__api_get(self): + """ test _api_get() """ + mockresponse2 = Mock() + mockresponse2.status_code = 'status_code' + mockresponse2.text = 'foo' + mockresponse2.json = lambda: {'foo': 'bar'} + mockresponse = Mock() + mockresponse.get.side_effect = [mockresponse2] + self.cahandler.session = mockresponse + self.assertEqual(('status_code', {'foo': 'bar'}), self.cahandler._api_get('url')) + + def test_014__api_get(self): + """ test _api_get() """ + mockresponse2 = Mock() + mockresponse2.status_code = 'status_code' + mockresponse2.text = 'foo' + mockresponse2.json.side_effect = Exception('ex_json') + mockresponse = Mock() + mockresponse.get.side_effect = [mockresponse2] + self.cahandler.session = mockresponse + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual(('status_code', 'ex_json'), self.cahandler._api_get('url')) + self.assertIn('ERROR:test_a2c:CAhandler._api_get() returned error during json parsing: ex_json', lcm.output) + + def test_015__api_get(self): + """ test _api_get() """ + mockresponse = Mock() + mockresponse.get.side_effect = [Exception('exc_api_get')] + self.cahandler.session = mockresponse + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual((500, 'exc_api_get'), self.cahandler._api_get('url')) + self.assertIn('ERROR:test_a2c:CAhandler._api_get() returned error: exc_api_get', lcm.output) + + def test_016__api_put(self): + """ test _api_put() """ + mockresponse = Mock() + mockresponse2 = Mock() + mockresponse2.status_code = 'status_code' + mockresponse2.text = 'foo' + mockresponse2.json = lambda: {'foo': 'bar'} + mockresponse = Mock() + mockresponse.put.side_effect = [mockresponse2] + self.cahandler.session = mockresponse + self.assertEqual(('status_code', {'foo': 'bar'}), self.cahandler._api_put('url', 'data')) + + def test_017__api_put(self): + """ test _api_put() """ + mockresponse2 = Mock() + mockresponse2.status_code = 'status_code' + mockresponse2.text = 'foo' + mockresponse2.json.side_effect = Exception('ex_json') + mockresponse = Mock() + mockresponse.put.side_effect = [mockresponse2] + self.cahandler.session = mockresponse + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual(('status_code', 'ex_json'), self.cahandler._api_put('url', 'data')) + self.assertIn('ERROR:test_a2c:CAhandler._api_put() returned error during json parsing: ex_json', lcm.output) + + def test_018__api_put(self): + """ test _api_put() """ + mockresponse2 = Mock() + mockresponse2.status_code = 'foo' + mockresponse2.text = None + mockresponse2.json = lambda: {'foo': 'bar'} + mockresponse = Mock() + mockresponse.put.side_effect = [mockresponse2] + self.cahandler.session = mockresponse + self.assertEqual(('foo', None), self.cahandler._api_put('url', 'data')) + + def test_019__api_put(self): + """ test _api_put() """ + mockresponse = Mock() + mockresponse.put.side_effect = Exception('exc_api_put') + self.cahandler.session = mockresponse + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual((500, 'exc_api_put'), self.cahandler._api_put('url', 'data')) + self.assertIn('ERROR:test_a2c:CAhandler._api_put() returned error: exc_api_put', lcm.output) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_020_certificates_get_from_serial(self, mock_api): + """ test certificates_get_from_serial """ + mock_api.return_value = (200, {'certificates': ['foo', 'bar']}) + self.assertEqual(['foo', 'bar'], self.cahandler._certificates_get_from_serial('serial')) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_021_certificates_get_from_serial(self, mock_api): + """ test certificates_get_from_serial """ + mock_api.return_value = (300, {'certificates': ['foo', 'bar']}) + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertFalse(self.cahandler._certificates_get_from_serial('serial')) + self.assertIn('ERROR:test_a2c:CAhandler._certificates_get_from_serial() for serial failed with code: 300', lcm.output) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_022_certificates_get_from_serial(self, mock_api): + """ test certificates_get_from_serial """ + mock_api.return_value = (200, {'certificates1': ['foo', 'bar']}) + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertFalse(self.cahandler._certificates_get_from_serial('serial')) + self.assertIn('ERROR:test_a2c:CAhandler._certificates_get_from_serial() for serial failed with code: 200', lcm.output) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_023_certificates_get_from_serial(self, mock_api): + """ test certificates_get_from_serial """ + mock_api.return_value = (200, {'certificates': ['foo', 'bar']}) + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual(['foo', 'bar'], self.cahandler._certificates_get_from_serial('0serial')) + self.assertIn('INFO:test_a2c:CAhandler._certificates_get_from_serial() remove leading zeros from serial number', lcm.output) + + @patch('examples.ca_handler.entrust_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.entrust_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_root_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_session_load') + @patch('examples.ca_handler.entrust_ca_handler.load_config') + def test_023_config_load(self, mock_load, mock_session, mock_root, mock_eab, mock_header): + """ test load_config() """ + mock_load.return_value = {'foo': 'bar'} + mock_eab.return_value = (True, 'handler') + mock_header.return_value = 'hil' + self.cahandler._config_load() + self.assertFalse(mock_session.called) + self.assertFalse(mock_root.called) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_header.called) + self.assertEqual('https://api.entrust.net/enterprise/v2', self.cahandler.api_url) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertEqual('handler', self.cahandler.eab_handler) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual(365, self.cahandler.cert_validity_days) + self.assertFalse(self.cahandler.username) + self.assertFalse(self.cahandler.password) + self.assertFalse(self.cahandler.organization_name) + self.assertEqual('STANDARD_SSL', self.cahandler.certtype) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertEqual('hil', self.cahandler.header_info_field) + + @patch('examples.ca_handler.entrust_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.entrust_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_root_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_session_load') + @patch('examples.ca_handler.entrust_ca_handler.load_config') + def test_024_config_load(self, mock_load, mock_session, mock_root, mock_eab, mock_header): + """ test load_config() """ + mock_load.return_value = {'CAhandler': {'foo': 'bar'}} + mock_eab.return_value = (True, 'handler') + mock_header.return_value = 'hil' + self.cahandler._config_load() + self.assertTrue(mock_session.called) + self.assertTrue(mock_root.called) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_header.called) + self.assertEqual('https://api.entrust.net/enterprise/v2', self.cahandler.api_url) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertEqual('handler', self.cahandler.eab_handler) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual(365, self.cahandler.cert_validity_days) + self.assertFalse(self.cahandler.username) + self.assertFalse(self.cahandler.password) + self.assertFalse(self.cahandler.organization_name) + self.assertEqual('STANDARD_SSL', self.cahandler.certtype) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertEqual('hil', self.cahandler.header_info_field) + + @patch('examples.ca_handler.entrust_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.entrust_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_root_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_session_load') + @patch('examples.ca_handler.entrust_ca_handler.load_config') + def test_025_config_load(self, mock_load, mock_session, mock_root, mock_eab, mock_header): + """ test load_config() """ + mock_load.return_value = {'CAhandler': {'api_url': 'api_url', 'foo': 'bar'}} + mock_eab.return_value = (True, 'handler') + mock_header.return_value = 'hil' + self.cahandler._config_load() + self.assertTrue(mock_session.called) + self.assertTrue(mock_root.called) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_header.called) + self.assertEqual('api_url', self.cahandler.api_url) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertEqual('handler', self.cahandler.eab_handler) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual(365, self.cahandler.cert_validity_days) + self.assertFalse(self.cahandler.username) + self.assertFalse(self.cahandler.password) + self.assertFalse(self.cahandler.organization_name) + self.assertEqual('STANDARD_SSL', self.cahandler.certtype) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertEqual('hil', self.cahandler.header_info_field) + + @patch('examples.ca_handler.entrust_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.entrust_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_root_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_session_load') + @patch('examples.ca_handler.entrust_ca_handler.load_config') + def test_026_config_load(self, mock_load, mock_session, mock_root, mock_eab, mock_header): + """ test load_config() """ + mock_load.return_value = {'CAhandler': {'request_timeout': '15', 'foo': 'bar'}} + mock_eab.return_value = (True, 'handler') + mock_header.return_value = 'hil' + self.cahandler._config_load() + self.assertTrue(mock_session.called) + self.assertTrue(mock_root.called) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_header.called) + self.assertEqual('https://api.entrust.net/enterprise/v2', self.cahandler.api_url) + self.assertEqual(15, self.cahandler.request_timeout) + self.assertEqual('handler', self.cahandler.eab_handler) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual(365, self.cahandler.cert_validity_days) + self.assertFalse(self.cahandler.username) + self.assertFalse(self.cahandler.password) + self.assertFalse(self.cahandler.organization_name) + self.assertEqual('STANDARD_SSL', self.cahandler.certtype) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertEqual('hil', self.cahandler.header_info_field) + + @patch('examples.ca_handler.entrust_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.entrust_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_root_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_session_load') + @patch('examples.ca_handler.entrust_ca_handler.load_config') + def test_027_config_load(self, mock_load, mock_session, mock_root, mock_eab, mock_header): + """ test load_config() """ + mock_load.return_value = {'CAhandler': {'request_timeout': 'aa', 'foo': 'bar'}} + mock_eab.return_value = (True, 'handler') + mock_header.return_value = 'hil' + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._config_load() + self.assertIn("ERROR:test_a2c:CAhandler._config_load(): failed to parse request_timeout invalid literal for int() with base 10: 'aa'", lcm.output) + self.assertTrue(mock_session.called) + self.assertTrue(mock_root.called) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_header.called) + self.assertEqual('https://api.entrust.net/enterprise/v2', self.cahandler.api_url) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertEqual('handler', self.cahandler.eab_handler) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual(365, self.cahandler.cert_validity_days) + self.assertFalse(self.cahandler.username) + self.assertFalse(self.cahandler.password) + self.assertFalse(self.cahandler.organization_name) + self.assertEqual('STANDARD_SSL', self.cahandler.certtype) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertEqual('hil', self.cahandler.header_info_field) + + @patch('examples.ca_handler.entrust_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.entrust_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_root_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_session_load') + @patch('examples.ca_handler.entrust_ca_handler.load_config') + def test_028_config_load(self, mock_load, mock_session, mock_root, mock_eab, mock_header): + """ test load_config() """ + mock_load.return_value = {'CAhandler': {'cert_validity_days': '10', 'foo': 'bar'}} + mock_eab.return_value = (True, 'handler') + mock_header.return_value = 'hil' + self.cahandler._config_load() + self.assertTrue(mock_session.called) + self.assertTrue(mock_root.called) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_header.called) + self.assertEqual('https://api.entrust.net/enterprise/v2', self.cahandler.api_url) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertEqual('handler', self.cahandler.eab_handler) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual(10, self.cahandler.cert_validity_days) + self.assertFalse(self.cahandler.username) + self.assertFalse(self.cahandler.password) + self.assertFalse(self.cahandler.organization_name) + self.assertEqual('STANDARD_SSL', self.cahandler.certtype) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertEqual('hil', self.cahandler.header_info_field) + + @patch('examples.ca_handler.entrust_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.entrust_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_root_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_session_load') + @patch('examples.ca_handler.entrust_ca_handler.load_config') + def test_029_config_load(self, mock_load, mock_session, mock_root, mock_eab, mock_header): + """ test load_config() """ + mock_load.return_value = {'CAhandler': {'cert_validity_days': 'aa', 'foo': 'bar'}} + mock_eab.return_value = (True, 'handler') + mock_header.return_value = 'hil' + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._config_load() + self.assertIn("ERROR:test_a2c:CAhandler._config_load(): failed to parse cert_validity_days invalid literal for int() with base 10: 'aa'", lcm.output) + self.assertTrue(mock_session.called) + self.assertTrue(mock_root.called) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_header.called) + self.assertEqual('https://api.entrust.net/enterprise/v2', self.cahandler.api_url) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertEqual('handler', self.cahandler.eab_handler) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual(365, self.cahandler.cert_validity_days) + self.assertFalse(self.cahandler.username) + self.assertFalse(self.cahandler.password) + self.assertFalse(self.cahandler.organization_name) + self.assertEqual('STANDARD_SSL', self.cahandler.certtype) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertEqual('hil', self.cahandler.header_info_field) + + @patch('examples.ca_handler.entrust_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.entrust_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_root_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_session_load') + @patch('examples.ca_handler.entrust_ca_handler.load_config') + def test_030_config_load(self, mock_load, mock_session, mock_root, mock_eab, mock_header): + """ test load_config() """ + mock_load.return_value = {'CAhandler': {'username': 'username', 'foo': 'bar'}} + mock_eab.return_value = (True, 'handler') + mock_header.return_value = 'hil' + self.cahandler._config_load() + self.assertTrue(mock_session.called) + self.assertTrue(mock_root.called) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_header.called) + self.assertEqual('https://api.entrust.net/enterprise/v2', self.cahandler.api_url) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertEqual('handler', self.cahandler.eab_handler) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual(365, self.cahandler.cert_validity_days) + self.assertEqual('username', self.cahandler.username) + self.assertFalse(self.cahandler.password) + self.assertFalse(self.cahandler.organization_name) + self.assertEqual('STANDARD_SSL', self.cahandler.certtype) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertEqual('hil', self.cahandler.header_info_field) + + @patch('examples.ca_handler.entrust_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.entrust_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_root_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_session_load') + @patch('examples.ca_handler.entrust_ca_handler.load_config') + def test_031_config_load(self, mock_load, mock_session, mock_root, mock_eab, mock_header): + """ test load_config() """ + mock_load.return_value = {'CAhandler': {'password': 'password', 'foo': 'bar'}} + mock_eab.return_value = (True, 'handler') + mock_header.return_value = 'hil' + self.cahandler._config_load() + self.assertTrue(mock_session.called) + self.assertTrue(mock_root.called) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_header.called) + self.assertEqual('https://api.entrust.net/enterprise/v2', self.cahandler.api_url) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertEqual('handler', self.cahandler.eab_handler) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual(365, self.cahandler.cert_validity_days) + self.assertFalse(self.cahandler.username) + self.assertEqual('password', self.cahandler.password) + self.assertFalse(self.cahandler.organization_name) + self.assertEqual('STANDARD_SSL', self.cahandler.certtype) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertEqual('hil', self.cahandler.header_info_field) + + @patch('examples.ca_handler.entrust_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.entrust_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_root_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_session_load') + @patch('examples.ca_handler.entrust_ca_handler.load_config') + def test_032_config_load(self, mock_load, mock_session, mock_root, mock_eab, mock_header): + """ test load_config() """ + mock_load.return_value = {'CAhandler': {'organization_name': 'organization_name', 'foo': 'bar'}} + mock_eab.return_value = (True, 'handler') + mock_header.return_value = 'hil' + self.cahandler._config_load() + self.assertTrue(mock_session.called) + self.assertTrue(mock_root.called) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_header.called) + self.assertEqual('https://api.entrust.net/enterprise/v2', self.cahandler.api_url) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertEqual('handler', self.cahandler.eab_handler) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual(365, self.cahandler.cert_validity_days) + self.assertFalse(self.cahandler.username) + self.assertFalse(self.cahandler.password) + self.assertEqual('organization_name', self.cahandler.organization_name) + self.assertEqual('STANDARD_SSL', self.cahandler.certtype) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertEqual('hil', self.cahandler.header_info_field) + + @patch('examples.ca_handler.entrust_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.entrust_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_root_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_session_load') + @patch('examples.ca_handler.entrust_ca_handler.load_config') + def test_033_config_load(self, mock_load, mock_session, mock_root, mock_eab, mock_header): + """ test load_config() """ + mock_load.return_value = {'CAhandler': {'certtype': 'certtype', 'foo': 'bar'}} + mock_eab.return_value = (True, 'handler') + mock_header.return_value = 'hil' + self.cahandler._config_load() + self.assertTrue(mock_session.called) + self.assertTrue(mock_root.called) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_header.called) + self.assertEqual('https://api.entrust.net/enterprise/v2', self.cahandler.api_url) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertEqual('handler', self.cahandler.eab_handler) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual(365, self.cahandler.cert_validity_days) + self.assertFalse(self.cahandler.username) + self.assertFalse(self.cahandler.password) + self.assertFalse(self.cahandler.organization_name) + self.assertEqual('certtype', self.cahandler.certtype) + self.assertFalse(self.cahandler.allowed_domainlist) + self.assertEqual('hil', self.cahandler.header_info_field) + + @patch('examples.ca_handler.entrust_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.entrust_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_root_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_session_load') + @patch('examples.ca_handler.entrust_ca_handler.load_config') + def test_034_config_load(self, mock_load, mock_session, mock_root, mock_eab, mock_header): + """ test load_config() """ + mock_load.return_value = {'CAhandler': {'allowed_domainlist': '["foo", "bar"]', 'foo': 'bar'}} + mock_eab.return_value = (True, 'handler') + mock_header.return_value = 'hil' + self.cahandler._config_load() + self.assertTrue(mock_session.called) + self.assertTrue(mock_root.called) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_header.called) + self.assertEqual('https://api.entrust.net/enterprise/v2', self.cahandler.api_url) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertEqual('handler', self.cahandler.eab_handler) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual(365, self.cahandler.cert_validity_days) + self.assertFalse(self.cahandler.username) + self.assertFalse(self.cahandler.password) + self.assertFalse(self.cahandler.organization_name) + self.assertEqual('STANDARD_SSL', self.cahandler.certtype) + self.assertEqual(['foo', 'bar'], self.cahandler.allowed_domainlist) + self.assertEqual('hil', self.cahandler.header_info_field) + + @patch('examples.ca_handler.entrust_ca_handler.config_headerinfo_load') + @patch('examples.ca_handler.entrust_ca_handler.config_eab_profile_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_root_load') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_session_load') + @patch('examples.ca_handler.entrust_ca_handler.load_config') + def test_035_config_load(self, mock_load, mock_session, mock_root, mock_eab, mock_header): + """ test load_config() """ + mock_load.return_value = {'CAhandler': {'allowed_domainlist': 'bar', 'foo': 'bar'}} + mock_eab.return_value = (True, 'handler') + mock_header.return_value = 'hil' + self.cahandler._config_load() + self.assertTrue(mock_session.called) + self.assertTrue(mock_root.called) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_header.called) + self.assertEqual('https://api.entrust.net/enterprise/v2', self.cahandler.api_url) + self.assertEqual(10, self.cahandler.request_timeout) + self.assertEqual('handler', self.cahandler.eab_handler) + self.assertTrue(self.cahandler.eab_profiling) + self.assertEqual(365, self.cahandler.cert_validity_days) + self.assertFalse(self.cahandler.username) + self.assertFalse(self.cahandler.password) + self.assertFalse(self.cahandler.organization_name) + self.assertEqual('STANDARD_SSL', self.cahandler.certtype) + self.assertEqual('failed to parse', self.cahandler.allowed_domainlist) + self.assertEqual('hil', self.cahandler.header_info_field) + + @patch.dict('os.environ', {'cert_passphrase_var': 'user_var'}) + def test_036_config_passphrase_load(self): + """ test _config_load - load template with user variable """ + config_dic = {'CAhandler': {'cert_passphrase_variable': 'cert_passphrase_var'}} + self.cahandler._config_passphrase_load(config_dic) + self.assertEqual('user_var', self.cahandler.cert_passphrase) + + @patch.dict('os.environ', {'cert_passphrase_var': 'user_var'}) + def test_037_config_passphrase_load(self): + """ test _config_load - load template with user variable """ + config_dic = {'CAhandler': {'cert_passphrase_variable': 'does_not_exist'}} + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._config_passphrase_load(config_dic) + self.assertFalse(self.cahandler.cert_passphrase) + self.assertIn("ERROR:test_a2c:CAhandler._config_passphrase_load() could not load cert_passphrase_variable:'does_not_exist'", lcm.output) + + @patch.dict('os.environ', {'cert_passphrase_var': 'user_var'}) + def test_038_config_passphrase_load(self): + """ test _config_load - load template with user variable """ + config_dic = {'CAhandler': {'cert_passphrase_variable': 'cert_passphrase_var', 'cert_passphrase': 'cert_passphrase'}} + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._config_passphrase_load(config_dic) + self.assertIn('INFO:test_a2c:CAhandler._config_load() overwrite cert_passphrase', lcm.output) + self.assertEqual('cert_passphrase', self.cahandler.cert_passphrase) + + @patch("builtins.open", mock_open(read_data='cert'), create=True) + @patch('os.path.isfile') + def test_039_config_root_load(self, mock_file): + """ _config_root_load() """ + mock_file.return_value = True + config_dic = {'CAhandler': {'entrust_root_cert': 'root_cert'}} + self.cahandler._config_root_load(config_dic) + self.assertEqual('cert', self.cahandler.entrust_root_cert) + + @patch("builtins.open", mock_open(read_data='cert'), create=True) + @patch('os.path.isfile') + def test_040_config_root_load(self, mock_file): + """ _config_root_load() """ + mock_file.return_value = False + config_dic = {'CAhandler': {'entrust_root_cert': 'root_cert'}} + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._config_root_load(config_dic) + self.assertIn('ERROR:test_a2c:CAhandler._config_root_load(): root CA file configured but not not found. Using default one.', lcm.output) + self.assertIn('290IENlcnRpZmljYXRpb24g', self.cahandler.entrust_root_cert) + + @patch("builtins.open", mock_open(read_data='cert'), create=True) + @patch('os.path.isfile') + def test_041_config_root_load(self, mock_file): + """ _config_root_load() """ + mock_file.return_value = False + config_dic = {'CAhandler': {'unk': 'root_cert'}} + self.cahandler._config_root_load(config_dic) + self.assertIn('290IENlcnRpZmljYXRpb24g', self.cahandler.entrust_root_cert) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_passphrase_load') + def test_042_config_session_load(self, mock_sl): + """ _config_session_load() """ + config_dic = {'CAhandler': {'client_cert': 'client_cert', 'client_key': 'client_key'}} + self.cahandler._config_session_load(config_dic) + self.assertFalse(mock_sl.called) + self.assertTrue(self.cahandler.session) + + @patch('examples.ca_handler.entrust_ca_handler.requests.Session') + @patch('examples.ca_handler.entrust_ca_handler.Pkcs12Adapter') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_passphrase_load') + def test_043_config_session_load(self, mock_sl, mock_pkcs12, mock_session): + """ _config_session_load() """ + config_dic = {'CAhandler': {'client_cert': 'client_cert'}} + mock_session.return_value.__enter__.return_value = Mock() + self.cahandler.cert_passphrase = 'cert_passphrase' + self.cahandler._config_session_load(config_dic) + self.assertTrue(mock_sl.called) + self.assertTrue(self.cahandler.session) + self.assertTrue(mock_pkcs12.called) + + @patch('examples.ca_handler.entrust_ca_handler.requests.Session') + @patch('examples.ca_handler.entrust_ca_handler.Pkcs12Adapter') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_passphrase_load') + def test_044_config_session_load(self, mock_sl, mock_pkcs12, mock_session): + """ _config_session_load() """ + config_dic = {'CAhandler': {'foo': 'client_cert'}} + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._config_session_load(config_dic) + self.assertTrue(mock_sl.called) + self.assertTrue(self.cahandler.session) + self.assertIn('WARNING:test_a2c:CAhandler._config_load() configuration might be incomplete: "client_cert. "client_key" or "client_passphrase[_variable] parameter is missing in config file', lcm.output) + self.assertFalse(mock_pkcs12.called) + + @patch('examples.ca_handler.entrust_ca_handler.csr_san_get') + @patch('examples.ca_handler.entrust_ca_handler.csr_cn_get') + def test_045__csr_cn_lookup(self, mock_cnget, mock_san_get): + """ test _csr_cn_lookup() """ + mock_cnget.return_value = 'cn' + mock_san_get.return_value = ['foo:san1', 'foo:san2'] + self.assertEqual('cn', self.cahandler._csr_cn_lookup('csr')) + + @patch('examples.ca_handler.entrust_ca_handler.csr_san_get') + @patch('examples.ca_handler.entrust_ca_handler.csr_cn_get') + def test_046__csr_cn_lookup(self, mock_cnget, mock_san_get): + """ test _csr_cn_lookup() """ + mock_cnget.return_value = None + mock_san_get.return_value = ['foo:san1', 'foo:san2'] + self.assertEqual('san1', self.cahandler._csr_cn_lookup('csr')) + + @patch('examples.ca_handler.entrust_ca_handler.csr_san_get') + @patch('examples.ca_handler.entrust_ca_handler.csr_cn_get') + def test_047__csr_cn_lookup(self, mock_cnget, mock_san_get): + """ test _csr_cn_lookup() """ + mock_cnget.return_value = None + mock_san_get.return_value = ['foosan1', 'foo:san2'] + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual('san2', self.cahandler._csr_cn_lookup('csr')) + self.assertIn('ERROR:test_a2c:CAhandler._csr_cn_lookup() split failed: list index out of range', lcm.output) + + @patch('examples.ca_handler.entrust_ca_handler.csr_san_get') + @patch('examples.ca_handler.entrust_ca_handler.csr_cn_get') + def test_048__csr_cn_lookup(self, mock_cnget, mock_san_get): + """ test _csr_cn_lookup() """ + mock_cnget.return_value = None + mock_san_get.return_value = None + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertFalse(self.cahandler._csr_cn_lookup('csr')) + self.assertIn('ERROR:test_a2c:CAhandler._csr_cn_lookup() no SANs found in CSR', lcm.output) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._domains_get') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._organizations_get') + def test_049_org_domain_cfg_check(self, mock_org, mock_domain): + """ test _org_domain_cfg_check()""" + mock_org.return_value = [] + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual('Organization None not found in Entrust API', self.cahandler._org_domain_cfg_check()) + self.assertTrue(mock_org.called) + self.assertFalse(mock_domain.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._domains_get') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._organizations_get') + def test_050_org_domain_cfg_check(self, mock_org, mock_domain): + """ test _org_domain_cfg_check()""" + mock_org.return_value = {'foo': 1, 'bar': 2} + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual('Organization None not found in Entrust API', self.cahandler._org_domain_cfg_check()) + self.assertTrue(mock_org.called) + self.assertFalse(mock_domain.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._domains_get') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._organizations_get') + def test_051_org_domain_cfg_check(self, mock_org, mock_domain): + """ test _org_domain_cfg_check()""" + mock_org.return_value = {'foo': 1, 'bar': 2} + mock_domain.return_value = ['foo1', 'foo2'] + self.cahandler.organization_name = 'foo1' + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual('Organization foo1 not found in Entrust API', self.cahandler._org_domain_cfg_check()) + self.assertTrue(mock_org.called) + self.assertFalse(mock_domain.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._domains_get') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._organizations_get') + def test_052_org_domain_cfg_check(self, mock_org, mock_domain): + """ test _org_domain_cfg_check()""" + mock_org.return_value = {'foo': 1, 'bar': 2} + mock_domain.return_value = ['foo1', 'foo2'] + self.cahandler.organization_name = 'foo' + self.assertFalse(self.cahandler._org_domain_cfg_check()) + self.assertTrue(mock_org.called) + self.assertTrue(mock_domain.called) + self.assertEqual(['foo1', 'foo2'], self.cahandler.allowed_domainlist) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._domains_get') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._organizations_get') + def test_053_org_domain_cfg_check(self, mock_org, mock_domain): + """ test _org_domain_cfg_check()""" + mock_org.return_value = {'foo': 1, 'bar': 2} + mock_domain.return_value = ['foo1', 'foo2'] + self.cahandler.organization_name = 'foo' + self.cahandler.allowed_domainlist = ['foo3', 'foo4'] + self.assertFalse(self.cahandler._org_domain_cfg_check()) + self.assertTrue(mock_org.called) + self.assertTrue(mock_domain.called) + self.assertEqual(['foo3', 'foo4'], self.cahandler.allowed_domainlist) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_054__organizations_get(self, mock_api): + """ test _organizations_get() """ + mock_api.return_value = (500, 'foo') + self.cahandler.organization_name = 'organization_name' + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._organizations_get() + self.assertIn('ERROR:test_a2c:CAhandler._organizations_get(): malformed response', lcm.output) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_055__organizations_get(self, mock_api): + """ test _organizations_get() """ + input_dic = {'organizations': [{'verificationStatus': 'APPROVED', 'name': 'foo', 'clientId': 1}, {'verificationStatus': 'APPROVED', 'name': 'bar', 'clientId': 2}]} + mock_api.return_value = (200, input_dic) + self.cahandler.organization_name = 'organization_name' + self.assertEqual({'foo': 1, 'bar': 2}, self.cahandler._organizations_get()) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_056__organizations_get(self, mock_api): + """ test _organizations_get() """ + input_dic = {'organizations': [{'verificationStatus': 'NOTAPPROVED', 'name': 'foo', 'clientId': 1}, {'verificationStatus': 'APPROVED', 'name': 'bar', 'clientId': 2}]} + mock_api.return_value = (200, input_dic) + self.cahandler.organization_name = 'organization_name' + self.assertEqual({'bar': 2}, self.cahandler._organizations_get()) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_057__organizations_get(self, mock_api): + """ test _organizations_get() """ + input_dic = {'organizations': [{'name': 'foo', 'clientId': 1}, {'verificationStatus': 'APPROVED', 'name': 'bar', 'clientId': 2}]} + mock_api.return_value = (200, input_dic) + self.cahandler.organization_name = 'organization_name' + self.assertEqual({'bar': 2}, self.cahandler._organizations_get()) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_058__organizations_get(self, mock_api): + """ test _organizations_get() """ + input_dic = {'organizations': [{'verificationStatus': 'APPROVED', '_name': 'foo', '_clientId': 1}, {'verificationStatus': 'APPROVED', 'name': 'bar', 'clientId': 2}]} + mock_api.return_value = (200, input_dic) + self.cahandler.organization_name = 'organization_name' + self.assertEqual({'bar': 2}, self.cahandler._organizations_get()) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_059__domains_get(self, mock_api): + """ test _organizations_get() """ + mock_api.return_value = (500, 'foo') + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._domains_get(1) + self.assertIn('ERROR:test_a2c:CAhandler._domains_get(): malformed response', lcm.output) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_060__domains_get(self, mock_api): + """ test _organizations_get() """ + input_dic = {'domains': [{'verificationStatus': 'APPROVED', 'domainName': 'foo.bar', 'clientId': 1}, {'verificationStatus': 'APPROVED', 'domainName': 'bar.foo', 'clientId': 2}]} + mock_api.return_value = (200, input_dic) + self.assertEqual(['foo.bar', 'bar.foo'], self.cahandler._domains_get(1)) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_061__domains_get(self, mock_api): + """ test _organizations_get() """ + input_dic = {'domains': [{'verificationStatus': 'NOTAPPROVED', 'domainName': 'foo.bar', 'clientId': 1}, {'verificationStatus': 'APPROVED', 'domainName': 'bar.foo', 'clientId': 2}]} + mock_api.return_value = (200, input_dic) + self.assertEqual(['bar.foo'], self.cahandler._domains_get(1)) + + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_062__domains_get(self, mock_api): + """ test _organizations_get() """ + input_dic = {'domains': [{'Status': 'APPROVED', 'domainName': 'foo.bar', 'clientId': 1}, {'verificationStatus': 'APPROVED', 'domainName': 'bar.foo', 'clientId': 2}]} + mock_api.return_value = (200, input_dic) + self.assertEqual(['bar.foo'], self.cahandler._domains_get(1)) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_063__domains_get(self, mock_api): + """ test _organizations_get() """ + input_dic = {'domains': [{'verificationStatus': 'APPROVED', 'Name': 'foo.bar', 'clientId': 1}, {'verificationStatus': 'APPROVED', 'domainName': 'bar.foo', 'clientId': 2}]} + mock_api.return_value = (200, input_dic) + self.assertEqual(['bar.foo'], self.cahandler._domains_get(1)) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_064_credential_check(self, mock_api): + """ test _organizations_get() """ + mock_api.return_value = (500, 'foo') + self.assertEqual('Connection to Entrust API failed: foo', self.cahandler.credential_check()) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_065_credential_check(self, mock_api): + """ test _organizations_get() """ + mock_api.return_value = (200, 'foo') + self.assertFalse(self.cahandler.credential_check()) + + def test_066_oonfig_check(self): + """ test _config_check() """ + self.cahandler.api_url = None + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._config_check() + self.assertIn('ERROR:test_a2c:CAhandler._config_check() ended with error: api_url parameter in missing in config file', lcm.output) + + def test_067_oonfig_check(self): + """ test _config_check() """ + self.cahandler.api_url = 'api_url' + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._config_check() + self.assertIn('ERROR:test_a2c:CAhandler._config_check() ended with error: username parameter in missing in config file', lcm.output) + + def test_068_oonfig_check(self): + """ test _config_check() """ + self.cahandler.api_url = 'api_url' + self.cahandler.username = 'username' + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._config_check() + self.assertIn('ERROR:test_a2c:CAhandler._config_check() ended with error: password parameter in missing in config file', lcm.output) + + def test_069_oonfig_check(self): + """ test _config_check() """ + self.cahandler.api_url = 'api_url' + self.cahandler.username = 'username' + self.cahandler.password = 'password' + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._config_check() + self.assertIn('ERROR:test_a2c:CAhandler._config_check() ended with error: organization_name parameter in missing in config file', lcm.output) + + def test_070_oonfig_check(self): + """ test _config_check() """ + self.cahandler.api_url = 'api_url' + self.cahandler.username = 'username' + self.cahandler.password = 'password' + self.cahandler.organization_name = 'organization_name' + self.assertFalse(self.cahandler._config_check()) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._allowed_domainlist_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._org_domain_cfg_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler.credential_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_check') + @patch('examples.ca_handler.entrust_ca_handler.eab_profile_header_info_check') + def test_071_enroll_check(self, mock_eab, mock_config, mock_credential, mock_org, mock_domain): + """ test _enroll_check() """ + mock_eab.return_value = 'mock_eab_error' + mock_config.return_value = 'mock_config_error' + mock_credential.return_value = 'mock_credential_error' + mock_org.return_value = 'mock_org_error' + mock_domain.return_value = 'mock_domain_error' + self.assertEqual('mock_eab_error', self.cahandler._enroll_check('csr')) + self.assertTrue(mock_eab.called) + self.assertFalse(mock_config.called) + self.assertFalse(mock_credential.called) + self.assertFalse(mock_org.called) + self.assertFalse(mock_domain.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._allowed_domainlist_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._org_domain_cfg_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler.credential_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_check') + @patch('examples.ca_handler.entrust_ca_handler.eab_profile_header_info_check') + def test_072_enroll_check(self, mock_eab, mock_config, mock_credential, mock_org, mock_domain): + """ test _enroll_check() """ + mock_eab.return_value = False + mock_config.return_value = 'mock_config_error' + mock_credential.return_value = 'mock_credential_error' + mock_org.return_value = 'mock_org_error' + mock_domain.return_value = 'mock_domain_error' + self.assertEqual('mock_config_error', self.cahandler._enroll_check('csr')) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_config.called) + self.assertFalse(mock_credential.called) + self.assertFalse(mock_org.called) + self.assertFalse(mock_domain.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._allowed_domainlist_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._org_domain_cfg_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler.credential_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_check') + @patch('examples.ca_handler.entrust_ca_handler.eab_profile_header_info_check') + def test_073_enroll_check(self, mock_eab, mock_config, mock_credential, mock_org, mock_domain): + """ test _enroll_check() """ + mock_eab.return_value = False + mock_config.return_value = False + mock_credential.return_value = 'mock_credential_error' + mock_org.return_value = 'mock_org_error' + mock_domain.return_value = 'mock_domain_error' + self.assertEqual('mock_credential_error', self.cahandler._enroll_check('csr')) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_config.called) + self.assertTrue(mock_credential.called) + self.assertFalse(mock_org.called) + self.assertFalse(mock_domain.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._allowed_domainlist_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._org_domain_cfg_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler.credential_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_check') + @patch('examples.ca_handler.entrust_ca_handler.eab_profile_header_info_check') + def test_074_enroll_check(self, mock_eab, mock_config, mock_credential, mock_org, mock_domain): + """ test _enroll_check() """ + mock_eab.return_value = False + mock_config.return_value = False + mock_credential.return_value = False + mock_org.return_value = 'mock_org_error' + mock_domain.return_value = 'mock_domain_error' + self.assertEqual('mock_org_error', self.cahandler._enroll_check('csr')) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_config.called) + self.assertTrue(mock_credential.called) + self.assertTrue(mock_org.called) + self.assertFalse(mock_domain.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._allowed_domainlist_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._org_domain_cfg_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler.credential_check') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._config_check') + @patch('examples.ca_handler.entrust_ca_handler.eab_profile_header_info_check') + def test_075_enroll_check(self, mock_eab, mock_config, mock_credential, mock_org, mock_domain): + """ test _enroll_check() """ + mock_eab.return_value = False + mock_config.return_value = False + mock_credential.return_value = False + mock_org.return_value = False + mock_domain.return_value = 'mock_domain_error' + self.assertEqual('mock_domain_error', self.cahandler._enroll_check('csr')) + self.assertTrue(mock_eab.called) + self.assertTrue(mock_config.called) + self.assertTrue(mock_credential.called) + self.assertTrue(mock_org.called) + self.assertTrue(mock_domain.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._certificates_get_from_serial') + @patch('examples.ca_handler.entrust_ca_handler.cert_serial_get') + @patch('examples.ca_handler.entrust_ca_handler.header_info_get') + def test_076__trackingid_get(self, mock_header, mock_serial, mock_cert): + """ test _trackingid_get() """ + mock_header.return_value = [{'poll_identifier': 'tracking_id'}, {'poll_identifier': 'tracking_id2'}] + self.assertEqual('tracking_id', self.cahandler._trackingid_get('csr')) + self.assertFalse(mock_serial.called) + self.assertFalse(mock_cert.called) + + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._certificates_get_from_serial') + @patch('examples.ca_handler.entrust_ca_handler.cert_serial_get') + @patch('examples.ca_handler.entrust_ca_handler.header_info_get') + def test_077__trackingid_get(self, mock_header, mock_serial, mock_cert): + """ test _trackingid_get() """ + mock_header.return_value = [{'identifier': 'tracking_id1'}, {'poll_identifier': 'tracking_id2'}] + self.assertEqual('tracking_id2', self.cahandler._trackingid_get('csr')) + self.assertFalse(mock_serial.called) + self.assertFalse(mock_cert.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._certificates_get_from_serial') + @patch('examples.ca_handler.entrust_ca_handler.cert_serial_get') + @patch('examples.ca_handler.entrust_ca_handler.header_info_get') + def test_078__trackingid_get(self, mock_header, mock_serial, mock_cert): + """ test _trackingid_get() """ + mock_header.return_value = [] + mock_serial.return_value = 'serial' + mock_cert.return_value = [{'trackingId': 'tracking_id'}] + self.assertEqual('tracking_id', self.cahandler._trackingid_get('csr')) + self.assertTrue(mock_serial.called) + self.assertTrue(mock_cert.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._certificates_get_from_serial') + @patch('examples.ca_handler.entrust_ca_handler.cert_serial_get') + @patch('examples.ca_handler.entrust_ca_handler.header_info_get') + def test_079__trackingid_get(self, mock_header, mock_serial, mock_cert): + """ test _trackingid_get() """ + mock_header.return_value = [] + mock_serial.return_value = 'serial' + mock_cert.return_value = [{'id': 'tracking_id'}] + self.assertFalse(self.cahandler._trackingid_get('csr')) + self.assertTrue(mock_serial.called) + self.assertTrue(mock_cert.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._certificates_get_from_serial') + @patch('examples.ca_handler.entrust_ca_handler.cert_serial_get') + @patch('examples.ca_handler.entrust_ca_handler.header_info_get') + def test_080__trackingid_get(self, mock_header, mock_serial, mock_cert): + """ test _trackingid_get() """ + mock_header.return_value = [] + mock_serial.return_value = 'serial' + mock_cert.return_value = [{'id': 'tracking_id1'}, {'trackingId': 'tracking_id2'}] + self.assertEqual('tracking_id2', self.cahandler._trackingid_get('csr')) + self.assertTrue(mock_serial.called) + self.assertTrue(mock_cert.called) + + @patch('examples.ca_handler.entrust_ca_handler.b64_encode') + @patch('examples.ca_handler.entrust_ca_handler.cert_pem2der') + def test_081_response_parse(self, mock_der, mock_enc): + """ test _rsponse_parse() """ + mock_der.return_value = 'cert_data' + mock_enc.return_value = 'mock_enc' + self.cahandler.entrust_root_cert = 'root_cert' + response = {"trackingId": "trackingId", 'endEntityCert': 'endEntityCert', 'chainCerts': ['foo1', 'foo2']} + self.assertEqual(('foo1\nfoo2\nroot_cert\n', 'mock_enc', 'trackingId'), self.cahandler._response_parse(response)) + self.assertTrue(mock_der.called) + self.assertTrue(mock_enc.called) + + @patch('examples.ca_handler.entrust_ca_handler.b64_encode') + @patch('examples.ca_handler.entrust_ca_handler.cert_pem2der') + def test_082_response_parse(self, mock_der, mock_enc): + """ test _rsponse_parse() """ + mock_der.return_value = 'cert_data' + mock_enc.return_value = 'mock_enc' + self.cahandler.entrust_root_cert = 'root_cert' + response = {"falsetrackingId": "trackingId", 'endEntityCert': 'endEntityCert', 'chainCerts': ['foo1', 'foo2']} + self.assertEqual(('foo1\nfoo2\nroot_cert\n', 'mock_enc', None), self.cahandler._response_parse(response)) + self.assertTrue(mock_der.called) + self.assertTrue(mock_enc.called) + + @patch('examples.ca_handler.entrust_ca_handler.b64_encode') + @patch('examples.ca_handler.entrust_ca_handler.cert_pem2der') + def test_083_response_parse(self, mock_der, mock_enc): + """ test _rsponse_parse() """ + mock_der.return_value = 'cert_data' + mock_enc.return_value = 'mock_enc' + self.cahandler.entrust_root_cert = 'root_cert' + response = {"trackingId": "trackingId", 'endEntityCert': 'endEntityCert', 'Certs': ['foo1', 'foo2']} + self.assertEqual((None, None, 'trackingId'), self.cahandler._response_parse(response)) + self.assertFalse(mock_der.called) + self.assertFalse(mock_enc.called) + + @patch('examples.ca_handler.entrust_ca_handler.b64_encode') + @patch('examples.ca_handler.entrust_ca_handler.cert_pem2der') + def test_084_response_parse(self, mock_der, mock_enc): + """ test _rsponse_parse() """ + mock_der.return_value = 'cert_data' + mock_enc.return_value = 'mock_enc' + self.cahandler.entrust_root_cert = 'root_cert' + response = {"trackingId": "trackingId", 'EntityCert': 'endEntityCert', 'chainCerts': ['foo1', 'foo2']} + self.assertEqual((None, None, 'trackingId'), self.cahandler._response_parse(response)) + self.assertFalse(mock_der.called) + self.assertFalse(mock_enc.called) + + @patch('examples.ca_handler.entrust_ca_handler.b64_encode') + @patch('examples.ca_handler.entrust_ca_handler.cert_pem2der') + def test_085_response_parse(self, mock_der, mock_enc): + """ test _rsponse_parse() """ + mock_der.return_value = 'cert_data' + mock_enc.return_value = 'mock_enc' + self.cahandler.entrust_root_cert = 'root_cert' + response = {"trackingId": "trackingId", 'endEntityCert': 'endEntityCert', 'chainCerts': []} + self.assertEqual(('root_cert\n', 'mock_enc', 'trackingId'), self.cahandler._response_parse(response)) + self.assertTrue(mock_der.called) + self.assertTrue(mock_enc.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._response_parse') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._csr_cn_lookup') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_post') + def test_086_enroll(self, mock_req, mock_cn, mock_parse): + """ test _enroll() """ + mock_cn.return_value = 'cn' + mock_req.return_value = (201, 'response') + mock_parse.return_value = ('cert_bundle', 'cert_raw', 'poll_indentifier') + self.assertEqual((None, 'cert_bundle', 'cert_raw', 'poll_indentifier'), self.cahandler._enroll('csr')) + self.assertTrue(mock_cn.called) + self.assertTrue(mock_req.called) + self.assertTrue(mock_parse.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._response_parse') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._csr_cn_lookup') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_post') + def test_087_enroll(self, mock_req, mock_cn, mock_parse): + """ test _enroll() """ + mock_cn.return_value = 'cn' + mock_req.return_value = (404, 'response') + mock_parse.return_value = ('cert_bundle', 'cert_raw', 'poll_indentifier') + self.assertEqual(('Error during order creation: 404 - response', None, None, None), self.cahandler._enroll('csr')) + self.assertTrue(mock_cn.called) + self.assertTrue(mock_req.called) + self.assertFalse(mock_parse.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._response_parse') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._csr_cn_lookup') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_post') + def test_088_enroll(self, mock_req, mock_cn, mock_parse): + """ test _enroll() """ + mock_cn.return_value = 'cn' + mock_req.return_value = (404, {'errors': 'response, response2'}) + mock_parse.return_value = ('cert_bundle', 'cert_raw', 'poll_indentifier') + self.assertEqual(('Error during order creation: 404 - response, response2', None, None, None), self.cahandler._enroll('csr')) + self.assertTrue(mock_cn.called) + self.assertTrue(mock_req.called) + self.assertFalse(mock_parse.called) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._enroll') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._enroll_check') + def test_089_enroll(self, mock_chk, mock_enroll): + """ test enroll() """ + mock_chk.return_value = None + mock_enroll.return_value = ('mock_err', 'mock_bundle', 'mock_raw', 'mock_poll') + self.assertEqual(('mock_err', 'mock_bundle', 'mock_raw', 'mock_poll'), self.cahandler.enroll('csr')) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._enroll') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._enroll_check') + def test_090_enroll(self, mock_chk, mock_enroll): + """ test enroll() """ + mock_chk.return_value = 'mock_chk' + mock_enroll.return_value = ('mock_err', 'mock_bundle', 'mock_raw', 'mock_poll') + self.assertEqual(('mock_chk', None, None, None), self.cahandler.enroll('csr')) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_post') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._trackingid_get') + def test_091_revoke(self, mock_track, mock_req): + """ test revoke() """ + mock_track.return_value = 'tracking_id' + mock_req.return_value = (200, 'response') + self.assertEqual((200, 'Certificate revoked', None), self.cahandler.revoke('csr')) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_post') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._trackingid_get') + def test_092_revoke(self, mock_track, mock_req): + """ test revoke() """ + mock_track.return_value = 'tracking_id' + mock_req.return_value = (500, 'response') + self.assertEqual((500, 'urn:ietf:params:acme:error:serverInternal', 'response'), self.cahandler.revoke('csr')) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_post') + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._trackingid_get') + def test_093_revoke(self, mock_track, mock_req): + """ test revoke() """ + mock_track.return_value = None + mock_req.return_value = (200, 'response') + self.assertEqual((500, 'urn:ietf:params:acme:error:serverInternal', 'Failed to get tracking id'), self.cahandler.revoke('csr')) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_094_certificates_get(self, mock_req): + """ test certificates_get() """ + mock_req.return_value = (500, 'response') + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertFalse(self.cahandler.certificates_get()) + self.assertIn('ERROR:test_a2c:CAhandler.certificates_get() failed with code: 500', lcm.output) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_095_certificates_get(self, mock_req): + """ test certificates_get() """ + content = {'certificates': [1, 2, 3, 4], 'summary': {'total': 4}} + mock_req.return_value = (200, content) + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual([1, 2, 3, 4], self.cahandler.certificates_get()) + self.assertIn('INFO:test_a2c:fetching certs offset: 0, limit: 200, total: 1, buffered: 0', lcm.output) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_096_certificates_get(self, mock_req): + """ test certificates_get() """ + response1 = (200, {'certificates': [1, 2, 3, 4], 'summary': {'total': 8}}) + response2 = (200, {'certificates': [5, 6, 7, 8]}) + mock_req.side_effect = [response1, response2] + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual([1, 2, 3, 4, 5, 6, 7, 8], self.cahandler.certificates_get()) + self.assertIn('INFO:test_a2c:fetching certs offset: 0, limit: 200, total: 1, buffered: 0', lcm.output) + self.assertIn('INFO:test_a2c:fetching certs offset: 200, limit: 200, total: 8, buffered: 4', lcm.output) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_097_certificates_get(self, mock_req): + """ test certificates_get() """ + response1 = (200, {'certificates': [1, 2, 3, 4]}) + response2 = (200, {'certificates': [5, 6, 7, 8]}) + mock_req.side_effect = [response1, response2] + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertFalse(self.cahandler.certificates_get()) + self.assertIn("ERROR:test_a2c:CAhandler.certificates_get() failed did not get any total value: {'certificates': [1, 2, 3, 4]}", lcm.output) + + @patch('examples.ca_handler.entrust_ca_handler.CAhandler._api_get') + def test_098_certificates_get(self, mock_req): + """ test certificates_get() """ + response1 = (200, {'certificates': [1, 2, 3, 4], 'summary': {'total': 9}}) + response2 = (200, {'certificates': [5, 6, 7, 8]}) + response3 = (200, {'certificates': [5, 6, 7, 8]}) + mock_req.side_effect = [response1, response2, response3] + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.assertEqual([1, 2, 3, 4, 5, 6, 7, 8], self.cahandler.certificates_get()) + self.assertIn('INFO:test_a2c:fetching certs offset: 0, limit: 200, total: 1, buffered: 0', lcm.output) + self.assertIn('INFO:test_a2c:fetching certs offset: 200, limit: 200, total: 9, buffered: 4', lcm.output) + self.assertIn('INFO:test_a2c:fetching certs offset: 400, limit: 200, total: 9, buffered: 8', lcm.output) + self.assertIn('ERROR:test_a2c:CAhandler.certificates_get() failed to get new data', lcm.output) + + +if __name__ == '__main__': + + unittest.main() diff --git a/test/test_helper.py b/test/test_helper.py index 8e6114eb..f278dd18 100644 --- a/test/test_helper.py +++ b/test/test_helper.py @@ -26,7 +26,7 @@ def setUp(self): """ setup unittest """ import logging logging.basicConfig(level=logging.CRITICAL) - from acme_srv.helper import b64decode_pad, b64_decode, b64_encode, b64_url_encode, b64_url_recode, convert_string_to_byte, convert_byte_to_string, decode_message, decode_deserialize, get_url, generate_random_string, signature_check, validate_email, uts_to_date_utc, date_to_uts_utc, load_config, cert_serial_get, cert_san_get, cert_san_pyopenssl_get, cert_dates_get, build_pem_file, date_to_datestr, datestr_to_date, dkeys_lower, csr_cn_get, cert_pubkey_get, csr_pubkey_get, url_get, url_get_with_own_dns, dns_server_list_load, csr_san_get, csr_san_byte_get, csr_extensions_get, fqdn_resolve, fqdn_in_san_check, sha256_hash, sha256_hash_hex, cert_der2pem, cert_pem2der, cert_extensions_get, csr_dn_get, logger_setup, logger_info, print_debug, jwk_thumbprint_get, allowed_gai_family, patched_create_connection, validate_csr, servercert_get, txt_get, proxystring_convert, proxy_check, handle_exception, ca_handler_load, eab_handler_load, hooks_load, error_dic_get, _logger_nonce_modify, _logger_certificate_modify, _logger_token_modify, _logger_challenges_modify, config_check, cert_issuer_get, cert_cn_get, string_sanitize, pembundle_to_list, certid_asn1_get, certid_check, certid_hex_get, v6_adjust, ipv6_chk, ip_validate, header_info_get, encode_url, uts_now, cert_ski_get, cert_ski_pyopenssl_get, cert_aki_get, cert_aki_pyopenssl_get, validate_fqdn, validate_ip, validate_identifier, header_info_field_validate, header_info_lookup, config_eab_profile_load, config_headerinfo_load, domainlist_check, allowed_domainlist_check, eab_profile_string_check, eab_profile_list_check, eab_profile_check, eab_profile_header_info_check, cert_extensions_py_openssl_get, cryptography_version_get + from acme_srv.helper import b64decode_pad, b64_decode, b64_encode, b64_url_encode, b64_url_recode, convert_string_to_byte, convert_byte_to_string, decode_message, decode_deserialize, get_url, generate_random_string, signature_check, validate_email, uts_to_date_utc, date_to_uts_utc, load_config, cert_serial_get, cert_san_get, cert_san_pyopenssl_get, cert_dates_get, build_pem_file, date_to_datestr, datestr_to_date, dkeys_lower, csr_cn_get, cert_pubkey_get, csr_pubkey_get, url_get, url_get_with_own_dns, dns_server_list_load, csr_san_get, csr_san_byte_get, csr_extensions_get, fqdn_resolve, fqdn_in_san_check, sha256_hash, sha256_hash_hex, cert_der2pem, cert_pem2der, cert_extensions_get, csr_dn_get, logger_setup, logger_info, print_debug, jwk_thumbprint_get, allowed_gai_family, patched_create_connection, validate_csr, servercert_get, txt_get, proxystring_convert, proxy_check, handle_exception, ca_handler_load, eab_handler_load, hooks_load, error_dic_get, _logger_nonce_modify, _logger_certificate_modify, _logger_token_modify, _logger_challenges_modify, config_check, cert_issuer_get, cert_cn_get, string_sanitize, pembundle_to_list, certid_asn1_get, certid_check, certid_hex_get, v6_adjust, ipv6_chk, ip_validate, header_info_get, encode_url, uts_now, cert_ski_get, cert_ski_pyopenssl_get, cert_aki_get, cert_aki_pyopenssl_get, validate_fqdn, validate_ip, validate_identifier, header_info_field_validate, header_info_lookup, config_eab_profile_load, config_headerinfo_load, domainlist_check, allowed_domainlist_check, eab_profile_string_check, eab_profile_list_check, eab_profile_check, eab_profile_header_info_check, cert_extensions_py_openssl_get, cryptography_version_get, cn_validate, csr_subject_get, eab_profile_subject_string_check, eab_profile_subject_check self.logger = logging.getLogger('test_a2c') self.allowed_gai_family = allowed_gai_family self.b64_decode = b64_decode @@ -122,6 +122,10 @@ def setUp(self): self.eab_profile_list_check = eab_profile_list_check self.eab_profile_check = eab_profile_check self.eab_profile_header_info_check = eab_profile_header_info_check + self.cn_validate = cn_validate + self.csr_subject_get = csr_subject_get + self.eab_profile_subject_string_check = eab_profile_subject_string_check + self.eab_profile_subject_check = eab_profile_subject_check def test_001_helper_b64decode_pad(self): """ test b64decode_pad() method with a regular base64 encoded string """ @@ -2905,6 +2909,22 @@ def test_362_eab_profile_check(self, mock_string, mock_list): self.assertFalse(mock_string.called) self.assertFalse(mock_list.called) + @patch('acme_srv.helper.eab_profile_subject_check') + @patch('acme_srv.helper.eab_profile_list_check') + @patch('acme_srv.helper.eab_profile_string_check') + def test_363_eab_profile_check(self, mock_string, mock_list, mock_subject): + self.cahandler = MagicMock() + self.csr = "testCSR" + self.handler_hifield = None + mock_subject.return_value = 'mock_subject' + self.cahandler.eab_handler.return_value.__enter__.return_value.eab_profile_get.return_value = {"subject": ["listValue"]} + self.cahandler.eab_profile_list_check.return_value = 'eab_list_check' + mock_list.return_value = None + self.assertEqual('mock_subject', self.eab_profile_check(self.logger, self.cahandler, self.csr, self.handler_hifield)) + self.assertFalse(mock_string.called) + self.assertFalse(mock_list.called) + self.assertTrue(mock_subject.called) + @patch('cryptography.__version__', '3.4.7') def test_363_cryptography_version_get_success(self): self.assertEqual(3, self.cryptography_version_get(self.logger)) @@ -2915,12 +2935,139 @@ def test_364_cryptography_version_get_success(self): self.assertEqual(36, self.cryptography_version_get(self.logger)) self.assertIn("ERROR:test_a2c:cryptography_version_get(): Error: 'NoneType' object has no attribute 'split'", lcm.output) + @patch('acme_srv.helper.validate_fqdn') + @patch('acme_srv.helper.validate_ip') + def test_365_cn_validate(self, mock_ip, mock_fqdn): + """ test cn_validate() """ + mock_ip.return_value = True + mock_fqdn.return_value = True + self.assertFalse(self.cn_validate(self.logger, 'foo.bar.com')) + self.assertFalse(mock_fqdn.called) - #@patch('cryptography.__version__', new_callable=lambda: None) - #def test_364_cryptography_version_get_missing_version(self): - # with self.assertRaises(AttributeError): - # cryptography_version_get() + @patch('acme_srv.helper.validate_fqdn') + @patch('acme_srv.helper.validate_ip') + def test_366_cn_validate(self, mock_ip, mock_fqdn): + """ test cn_validate() """ + mock_ip.return_value = False + mock_fqdn.return_value = True + self.assertFalse(self.cn_validate(self.logger, 'foo.bar.com')) + self.assertTrue(mock_fqdn.called) + + @patch('acme_srv.helper.validate_fqdn') + @patch('acme_srv.helper.validate_ip') + def test_367_cn_validate(self, mock_ip, mock_fqdn): + """ test cn_validate() """ + mock_ip.return_value = False + mock_fqdn.return_value = False + self.assertEqual('Profile subject check failed: CN validation failed', self.cn_validate(self.logger, 'foo.bar.com')) + self.assertTrue(mock_fqdn.called) + + @patch('acme_srv.helper.validate_fqdn') + @patch('acme_srv.helper.validate_ip') + def test_368_cn_validate(self, mock_ip, mock_fqdn): + """ test cn_validate() """ + mock_ip.return_value = False + mock_fqdn.return_value = False + self.assertEqual('Profile subject check failed: commonName missing', self.cn_validate(self.logger, None)) + self.assertFalse(mock_fqdn.called) + def test_369_csr_subject_get(self): + """ test csr_subject_get() """ + csr = 'MIICwDCCAagCAQAwVDESMBAGA1UEAwwJbGVnby5hY21lMQ0wCwYDVQQKDARhY21lMQwwCgYDVQQLDANmb28xCzAJBgNVBAYTAlVTMRQwEgYDVQQFEwswMC0xMS0yMi0zMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM5AKMmB3o8LLEEGuHo0Ipl4K8z9m3EyM9teSVocQz39DK8s2dKpx8MrsVkTg6M3fuL4yPlim8v0+unPtB18dFeThkijHetxL5x08pVvMVwa7Cjk/22e5IRgBGSQYCO6KCUsNh2vhH93r7x71wlTV3sYe2t0HaEdGqBxdct76J9kyeCY06Br+4PMR7afRvHv4vFH6Y2+hSD4oOd5cSTZXnNWcWRbjNFY7aytzl4JpJiEK0ealDMSf/ZP0n8Sdx1vCx8amaozrLg5z3eLULiAUUgCtqOWOgNLQFNSqjyhZmMTZGGJcTgb43KAKWsO3bfM6rvNTZRbrM7dAsg/bQsK6mMCAwEAAaAnMCUGCSqGSIb3DQEJDjEYMBYwFAYDVR0RBA0wC4IJbGVnby5hY21lMA0GCSqGSIb3DQEBCwUAA4IBAQA19j8Lge9Vqxc/hvWYcU1Kx3KBx5TN97PK0wQFPIIWX20/JRoodzfrMSqO0EgZWB+czoRi8G+2ezbK13sV02dKovo8ISoSvgSZtt53UKBz+JmQd7Q7G1vONZ7d2PT0nTUN4fTA5YQs5nys3O8/2oOxJiJO6IyhmpiVqUbrlU6Harb4MfjNTb+teSQRSCOAX/8U9TdPwuAi6rXdWjXAUxBDQySWkW/B3pd77Ztt5nDFP2DT+7f7mAoWG4+XY6iXcXs1GsDA4XRTx2rCvhQtQomVGAKFwd8aTpHL/ZwNt1GOw6oMZkKKf+axVA1pvAYGhey/4x3uwKf654VB3e2iOCea' + result_dic = {'commonName': 'lego.acme', 'organizationName': 'acme', 'organizationalUnitName': 'foo', 'countryName': 'US', 'serialNumber': '00-11-22-33'} + self.assertEqual(result_dic, self.csr_subject_get(self.logger, csr)) + + def test_370_csr_subject_get(self): + """ test csr_subject_get() """ + csr = 'MIICcDCCAVgCAQAwADCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOKk0E61QJ2K/NiGSO0aJyqrLfmHytPr35ptLwNdfKQ/8Vb2uoHYAvxVEO9weNTQVlZ9ApkJquBTRoSdqTy6p87inh8JwzFM/neJAsMg2ZiH3gRRRfmIb/4Kce0BUQ66DFSV8sWThyv13EcL+pZYdqRvONujVn7XVPbmB2ZI8qI4iXswRq45mFBW5Dyt3Rlw+KOBu1ejo0lqB2FGQiBONxQrFDyF4nVWN3R9BlhuybSF4Elhos7pkiEfrE+8EzYy+7yMEiDh1m+TmwZRNEdtSWNORF51CF3bYUz8pvpt66vKGi/F6k2iljelw1kNsswZAciNi2jG7S0M+MWMFi680sCAwEAAaArMCkGCSqGSIb3DQEJDjEcMBowGAYDVR0RBBEwD4INZm9vLmJhci5sb2NhbDANBgkqhkiG9w0BAQsFAAOCAQEAivCrcL+uVzDdykT87073atC4B2DHky5bzL+iI8C+BkPq0jRdcVkExMrUtTdtp8Ot1zQHtYc/c/Tj+aYDZ6SdMYtrtHUgxS5JyFh0p+MEvkgZHcWOVC+VlWA+lC9kdX3WetsGT6xqCG4l+BpgCUERghFJ5/+K0bbCI4jT/5ZCT7+pO0qZtw0eg6tQBLPSXzXN98x3nmuaw9PzO1rVG5IMItyU+TlX3pJRXKpqSOHEbeaGWHizMUlbDKzoIiUf+11I9RwTeLlp/HPG8uvRc/zZ1einZPLQgow5kU15jFQSgQtzFHV4ZxuYmWN7oMIruwBNP1hkoTNL1kJcPeOwtEdOMw==' + self.assertFalse(self.csr_subject_get(self.logger, csr)) + + @patch('acme_srv.helper.cn_validate') + def test_370_eab_profile_subjet_string_check(self, mock_validate): + """ test eab_profile_subject_string_check() """ + profile_dic = {'foo': 'bar1'} + self.assertEqual('Profile subject check failed for foo', self.eab_profile_subject_string_check(self.logger, profile_dic, 'foo', 'bar')) + self.assertFalse(mock_validate.called) + + @patch('acme_srv.helper.cn_validate') + def test_371_eab_profile_subjet_string_check(self, mock_validate): + """ test eab_profile_subject_string_check() """ + profile_dic = {'foo': '*'} + self.assertFalse(self.eab_profile_subject_string_check(self.logger, profile_dic, 'foo', 'bar')) + self.assertFalse(mock_validate.called) + + @patch('acme_srv.helper.cn_validate') + def test_372_eab_profile_subjet_string_check(self, mock_validate): + """ test eab_profile_subject_string_check() """ + profile_dic = {'foo': 'bar'} + self.assertFalse(self.eab_profile_subject_string_check(self.logger, profile_dic, 'foo', 'bar')) + self.assertFalse(mock_validate.called) + + @patch('acme_srv.helper.cn_validate') + def test_373_eab_profile_subjet_string_check(self, mock_validate): + """ test eab_profile_subject_string_check() """ + profile_dic = {'foo': ['bar1', 'bar2', 'bar3']} + self.assertEqual('Profile subject check failed for foo', self.eab_profile_subject_string_check(self.logger, profile_dic, 'foo', 'bar')) + self.assertFalse(mock_validate.called) + + @patch('acme_srv.helper.cn_validate') + def test_374_eab_profile_subjet_string_check(self, mock_validate): + """ test eab_profile_subject_string_check() """ + profile_dic = {'foo': ['bar1', 'bar2', 'bar3']} + self.assertFalse(self.eab_profile_subject_string_check(self.logger, profile_dic, 'foo', 'bar2')) + self.assertFalse(mock_validate.called) + + @patch('acme_srv.helper.cn_validate') + def test_375_eab_profile_subjet_string_check(self, mock_validate): + """ test eab_profile_subject_string_check() """ + profile_dic = {'foo': ['bar1', 'bar2', 'bar3']} + mock_validate.return_value = 'error' + self.assertEqual('error', self.eab_profile_subject_string_check(self.logger, profile_dic, 'commonName', 'bar')) + self.assertTrue(mock_validate.called) + + @patch('acme_srv.helper.cn_validate') + def test_376_eab_profile_subjet_string_check(self, mock_validate): + """ test eab_profile_subject_string_check() """ + profile_dic = {'foo': ['bar1', 'bar2', 'bar3']} + mock_validate.return_value = 'error' + self.assertEqual('Profile subject check failed for bar', self.eab_profile_subject_string_check(self.logger, profile_dic, 'bar', 'bar')) + self.assertFalse(mock_validate.called) + + @patch('acme_srv.helper.eab_profile_subject_string_check') + @patch('acme_srv.helper.csr_subject_get') + def test_377_eab_profile_subject_check(self, mock_cn, mock_strchk): + """ test eab_profile_subject_check() """ + profile_dic = {'foo': 'bar'} + mock_cn.return_value = {'o': 'o', 'ou': 'ou', 'cn': 'cn'} + mock_strchk.side_effect = ['o', 'ou', 'cn'] + self.assertEqual('o', self.eab_profile_subject_check(self.logger, 'csr', profile_dic)) + + @patch('acme_srv.helper.eab_profile_subject_string_check') + @patch('acme_srv.helper.csr_subject_get') + def test_378_eab_profile_subject_check(self, mock_cn, mock_strchk): + """ test eab_profile_subject_check() """ + profile_dic = {'foo': 'bar'} + mock_cn.return_value = {'o': 'o', 'ou': 'ou', 'cn': 'cn'} + mock_strchk.side_effect = [False, 'ou', 'cn'] + self.assertEqual('ou', self.eab_profile_subject_check(self.logger, 'csr', profile_dic)) + + @patch('acme_srv.helper.eab_profile_subject_string_check') + @patch('acme_srv.helper.csr_subject_get') + def test_379_eab_profile_subject_check(self, mock_cn, mock_strchk): + """ test eab_profile_subject_check() """ + profile_dic = {'foo': 'bar'} + mock_cn.return_value = {'o': 'o', 'ou': 'ou', 'cn': 'cn'} + mock_strchk.side_effect = [False, False, 'cn'] + self.assertEqual('cn', self.eab_profile_subject_check(self.logger, 'csr', profile_dic)) + + @patch('acme_srv.helper.eab_profile_subject_string_check') + @patch('acme_srv.helper.csr_subject_get') + def test_378_eab_profile_subject_check(self, mock_cn, mock_strchk): + """ test eab_profile_subject_check() """ + profile_dic = {'foo': 'bar'} + mock_cn.return_value = {'o': 'o', 'ou': 'ou', 'cn': 'cn'} + mock_strchk.side_effect = [False, False, False] + self.assertEqual('Profile subject check failed', self.eab_profile_subject_check(self.logger, 'csr', profile_dic)) if __name__ == '__main__': unittest.main() diff --git a/test/test_msca_handler.py b/test/test_msca_handler.py index 0c6090a3..e83a54b0 100644 --- a/test/test_msca_handler.py +++ b/test/test_msca_handler.py @@ -796,6 +796,34 @@ def test_058_config_headerinfo_load(self): self.assertFalse(self.cahandler.header_info_field) self.assertIn('WARNING:test_a2c:Order._config_orderconfig_load() header_info_list failed with error: Expecting value: line 1 column 1 (char 0)', lcm.output) + def test_059__config_url_load(self): + """ test _config_url_load()""" + config_dic = {'CAhandler': {'url': 'foo'}} + self.cahandler._config_url_load(config_dic) + self.assertEqual( 'foo', self.cahandler.url) + + @patch.dict('os.environ', {'url_variable': 'foo1'}) + def test_060__config_url_load(self): + """ test _config_url_load()""" + config_dic = {'CAhandler': {'url_variable': 'url_variable'}} + self.cahandler._config_url_load(config_dic) + self.assertEqual( 'foo1', self.cahandler.url) + + @patch.dict('os.environ', {'url_variable': 'foo1'}) + def test_061__config_url_load(self): + """ test _config_url_load()""" + config_dic = {'CAhandler': {'url_variable': 'url_variable', 'url': 'foo'}} + self.cahandler._config_url_load(config_dic) + self.assertEqual( 'foo', self.cahandler.url) + + @patch.dict('os.environ', {'url_variable': 'foo1'}) + def test_062__config_url_load(self): + """ test _config_url_load()""" + config_dic = {'CAhandler': {'url_variable': 'doesnotexist'}} + with self.assertLogs('test_a2c', level='INFO') as lcm: + self.cahandler._config_url_load(config_dic) + self.assertFalse(self.cahandler.url) + self.assertIn("ERROR:test_a2c:CAhandler._config_load() could not load url_variable:'doesnotexist'", lcm.output) if __name__ == '__main__': diff --git a/test/test_nclm_ca_handler.py b/test/test_nclm_ca_handler.py index 45e60148..acb2b990 100644 --- a/test/test_nclm_ca_handler.py +++ b/test/test_nclm_ca_handler.py @@ -46,8 +46,17 @@ def test_003__api_post(self, mock_post): self.assertEqual('exc_api_post', self.cahandler._api_post('url', 'data')) self.assertIn('ERROR:test_a2c:CAhandler._api_post() returned error: exc_api_post', lcm.output) + @patch.object(requests, 'post') + def test_004__api_post(self, mock_req): + """ test _api_post successful run """ + mockresponse = Mock() + mock_req.return_value = mockresponse + mockresponse.status_code = 'status_code' + mockresponse.json = Exception('json_exc') + self.assertEqual({'status': 'status_code'}, self.cahandler._api_post('url', 'data')) + @patch('requests.get') - def test_004_ca_id_lookup(self, mock_req): + def test_005_ca_id_lookup(self, mock_req): """ CAhandler._ca_id_lookup() returns nothing """ self.cahandler.api_host = 'api_host' self.cahandler.ca_name = 'ca_name' @@ -60,7 +69,7 @@ def test_004_ca_id_lookup(self, mock_req): self.assertIn('ERROR:test_a2c:ca_id.lookup() no CAs found in response ...', lcm.output) @patch('requests.get') - def test_005_ca_id_lookup(self, mock_req): + def test_006_ca_id_lookup(self, mock_req): """ CAhandler._ca_id_lookup() returns wrong data """ self.cahandler.api_host = 'api_host' self.cahandler.ca_name = 'ca_name' @@ -73,7 +82,7 @@ def test_005_ca_id_lookup(self, mock_req): self.assertIn('ERROR:test_a2c:ca_id.lookup() no CAs found in response ...', lcm.output) @patch('requests.get') - def test_006_ca_id_lookup(self, mock_req): + def test_007_ca_id_lookup(self, mock_req): """ CAhandler._ca_id_lookup() returns wrong data """ self.cahandler.api_host = 'api_host' self.cahandler.ca_name = 'ca_name' @@ -86,7 +95,7 @@ def test_006_ca_id_lookup(self, mock_req): self.assertIn('ERROR:test_a2c:ca_id.lookup() no CAs found in response ...', lcm.output) @patch('requests.get') - def test_007_ca_id_lookup(self, mock_req): + def test_008_ca_id_lookup(self, mock_req): """ CAhandler._ca_id_lookup() returns empty ca-list """ self.cahandler.api_host = 'api_host' self.cahandler.ca_name = 'ca_name' @@ -99,7 +108,7 @@ def test_007_ca_id_lookup(self, mock_req): self.assertIn('ERROR:test_a2c:_ca_id_lookup(): no ca id found for ca_name', lcm.output) @patch('requests.get') - def test_008_ca_id_lookup(self, mock_req): + def test_009_ca_id_lookup(self, mock_req): """ CAhandler._ca_id_lookup() returns wrong ca-list """ self.cahandler.api_host = 'api_host' self.cahandler.ca_name = 'ca_name' @@ -112,7 +121,7 @@ def test_008_ca_id_lookup(self, mock_req): self.assertIn('ERROR:test_a2c:_ca_id_lookup(): no ca id found for ca_name', lcm.output) @patch('requests.get') - def test_009_ca_id_lookup(self, mock_req): + def test_010_ca_id_lookup(self, mock_req): """ CAhandler._ca_id_lookup() returns ca-list with name not matching """ self.cahandler.api_host = 'api_host' self.cahandler.ca_name = 'ca_name' @@ -125,7 +134,7 @@ def test_009_ca_id_lookup(self, mock_req): self.assertIn('ERROR:test_a2c:_ca_id_lookup(): no ca id found for ca_name', lcm.output) @patch('requests.get') - def test_010_ca_id_lookup(self, mock_req): + def test_011_ca_id_lookup(self, mock_req): """ CAhandler._ca_id_lookup() returns ca-list with name matching but no id """ self.cahandler.api_host = 'api_host' self.cahandler.ca_name = 'ca_name' @@ -138,7 +147,7 @@ def test_010_ca_id_lookup(self, mock_req): self.assertIn('ERROR:test_a2c:_ca_id_lookup(): no ca id found for ca_name', lcm.output) @patch('requests.get') - def test_011_ca_id_lookup(self, mock_req): + def test_012_ca_id_lookup(self, mock_req): """ CAhandler._ca_id_lookup() returns ca-list with name matching and id """ self.cahandler.api_host = 'api_host' self.cahandler.ca_name = 'ca_name' @@ -149,7 +158,7 @@ def test_011_ca_id_lookup(self, mock_req): self.assertEqual('id', self.cahandler._ca_id_lookup()) @patch('requests.get') - def test_012_ca_id_lookup(self, mock_req): + def test_013_ca_id_lookup(self, mock_req): """ CAhandler._ca_id_lookup() returns ca-list with desc not matching """ self.cahandler.api_host = 'api_host' self.cahandler.ca_name = 'ca_name' @@ -162,7 +171,7 @@ def test_012_ca_id_lookup(self, mock_req): self.assertIn('ERROR:test_a2c:_ca_id_lookup(): no ca id found for ca_name', lcm.output) @patch('requests.get') - def test_013_ca_id_lookup(self, mock_req): + def test_014_ca_id_lookup(self, mock_req): """ CAhandler._ca_id_lookup() returns ca-list with desc matching but no id """ self.cahandler.api_host = 'api_host' self.cahandler.ca_name = 'ca_name' @@ -175,7 +184,7 @@ def test_013_ca_id_lookup(self, mock_req): self.assertIn('ERROR:test_a2c:_ca_id_lookup(): no ca id found for ca_name', lcm.output) @patch('requests.get') - def test_014_ca_id_lookup(self, mock_req): + def test_015_ca_id_lookup(self, mock_req): """ CAhandler._ca_id_lookup() returns ca-list with desc matching and id """ self.cahandler.api_host = 'api_host' self.cahandler.ca_name = 'ca_name' @@ -186,7 +195,7 @@ def test_014_ca_id_lookup(self, mock_req): self.assertEqual('id', self.cahandler._ca_id_lookup()) @patch('requests.get') - def test_015_ca_id_lookup(self, mock_get): + def test_016_ca_id_lookup(self, mock_get): """ CAhandler._cert_bundle_build() returns everything with one ca cert """ self.cahandler.api_host = 'api_host' mockresponse1 = Mock() @@ -197,7 +206,7 @@ def test_015_ca_id_lookup(self, mock_get): self.assertEqual((None, 'pempemca', 'der'), self.cahandler._cert_bundle_build('foo')) @patch('requests.get') - def test_016_ca_id_lookup(self, mock_get): + def test_017_ca_id_lookup(self, mock_get): """ CAhandler._cert_bundle_build() returns everything with two ca cert """ self.cahandler.api_host = 'api_host' mockresponse1 = Mock() @@ -210,7 +219,7 @@ def test_016_ca_id_lookup(self, mock_get): self.assertEqual((None, 'pempemca1pemca2', 'der'), self.cahandler._cert_bundle_build('foo')) @patch('requests.get') - def test_017_ca_id_lookup(self, mock_get): + def test_018_ca_id_lookup(self, mock_get): """ CAhandler._cert_bundle_build() returns everything without der in cert_dic """ self.cahandler.api_host = 'api_host' mockresponse1 = Mock() @@ -223,7 +232,7 @@ def test_017_ca_id_lookup(self, mock_get): self.assertIn('ERROR:test_a2c:CAhandler._cert_bundle_build(): no der certificate returned for id: foo', lcm.output) @patch('requests.get') - def test_018_ca_id_lookup(self, mock_get): + def test_019_ca_id_lookup(self, mock_get): """ CAhandler._cert_bundle_build() returns everything without pem in cert_dic """ self.cahandler.api_host = 'api_host' self.cahandler.ca_id_list = [1] @@ -237,7 +246,7 @@ def test_018_ca_id_lookup(self, mock_get): self.assertIn('ERROR:test_a2c:CAhandler._cert_bundle_build(): no pem certificate returned for id: foo', lcm.output) @patch('requests.get') - def test_019_ca_id_lookup(self, mock_get): + def test_020_ca_id_lookup(self, mock_get): """ CAhandler._cert_bundle_build() returns everything without pem in ca_dic """ self.cahandler.api_host = 'api_host' self.cahandler.ca_id_list = [1] @@ -251,7 +260,7 @@ def test_019_ca_id_lookup(self, mock_get): self.assertIn('ERROR:test_a2c:CAhandler._cert_bundle_build(): no pem certificate returned for id: id', lcm.output) @patch('requests.get') - def test_020_ca_id_lookup(self, mock_get): + def test_021_ca_id_lookup(self, mock_get): """ CAhandler._cert_bundle_build() returns wrong ca_dic """ self.cahandler.api_host = 'api_host' self.cahandler.ca_id_list = [1] @@ -265,7 +274,7 @@ def test_020_ca_id_lookup(self, mock_get): self.assertIn('ERROR:test_a2c:CAhandler._cert_bundle_build(): invalid reponse returned for id: id', lcm.output) @patch('requests.get') - def test_021_ca_id_lookup(self, mock_get): + def test_022_ca_id_lookup(self, mock_get): """ CAhandler._cert_bundle_build() returns wrong cert_dic """ self.cahandler.api_host = 'api_host' self.cahandler.ca_id_list = [1] @@ -280,7 +289,7 @@ def test_021_ca_id_lookup(self, mock_get): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._san_compare') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_list_fetch') - def test_022_cert_id_lookup(self, mock_fetch, mock_comp): + def test_023_cert_id_lookup(self, mock_fetch, mock_comp): """ CAhandler._cert_id_lookup() - one cert - ok """ self.cahandler.api_host = 'api_host' mock_fetch.return_value = [{'subjectAltName': 'subjectAltName', 'certificateId': 1}] @@ -289,7 +298,7 @@ def test_022_cert_id_lookup(self, mock_fetch, mock_comp): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._san_compare') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_list_fetch') - def test_023_cert_id_lookup(self, mock_fetch, mock_comp): + def test_024_cert_id_lookup(self, mock_fetch, mock_comp): """ CAhandler._cert_id_lookup() - two certs - match 2nd entry in list """ self.cahandler.api_host = 'api_host' mock_fetch.return_value = [{'subjectAltName': 'subjectAltName1', 'certificateId': 1}, {'subjectAltName': 'subjectAltName2', 'certificateId': 2}] @@ -298,7 +307,7 @@ def test_023_cert_id_lookup(self, mock_fetch, mock_comp): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._san_compare') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_list_fetch') - def test_024_cert_id_lookup(self, mock_fetch, mock_comp): + def test_025_cert_id_lookup(self, mock_fetch, mock_comp): """ CAhandler._cert_id_lookup() - no cn two certs - match 2nd entry in list """ self.cahandler.api_host = 'api_host' mock_fetch.return_value = [{'subjectAltName': 'subjectAltName1', 'certificateId': 1}, {'subjectAltName': 'subjectAltName2', 'certificateId': 2}] @@ -307,7 +316,7 @@ def test_024_cert_id_lookup(self, mock_fetch, mock_comp): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._san_compare') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_list_fetch') - def test_025_cert_id_lookup(self, mock_fetch, mock_comp): + def test_026_cert_id_lookup(self, mock_fetch, mock_comp): """ CAhandler._cert_id_lookup() - two certs - match 1st entry in list """ self.cahandler.api_host = 'api_host' mock_fetch.return_value = [{'subjectAltName': 'subjectAltName1', 'certificateId': 1}, {'subjectAltName': 'subjectAltName2', 'certificateId': 2}] @@ -316,7 +325,7 @@ def test_025_cert_id_lookup(self, mock_fetch, mock_comp): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._san_compare') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_list_fetch') - def test_026_cert_id_lookup(self, mock_fetch, mock_comp): + def test_027_cert_id_lookup(self, mock_fetch, mock_comp): """ CAhandler._cert_id_lookup() - no certificateid return from nclm """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -328,7 +337,7 @@ def test_026_cert_id_lookup(self, mock_fetch, mock_comp): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._san_compare') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_list_fetch') - def test_027_cert_id_lookup(self, mock_fetch, mock_comp): + def test_028_cert_id_lookup(self, mock_fetch, mock_comp): """ CAhandler._cert_id_lookup() - two certs match """ self.cahandler.api_host = 'api_host' mock_fetch.return_value = [{'subjectAltName': 'subjectAltName1', 'certificateId': 1}, {'subjectAltName': 'subjectAltName2', 'certificateId': 2}] @@ -337,7 +346,7 @@ def test_027_cert_id_lookup(self, mock_fetch, mock_comp): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._san_compare') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_list_fetch') - def test_028_cert_id_lookup(self, mock_fetch, mock_comp): + def test_029_cert_id_lookup(self, mock_fetch, mock_comp): """ CAhandler._cert_id_lookup() - one cert - no san in """ self.cahandler.api_host = 'api_host' mock_fetch.return_value = [{'foo': 'bar', 'certificateId': 'certificateId'}] @@ -346,7 +355,7 @@ def test_028_cert_id_lookup(self, mock_fetch, mock_comp): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._san_compare') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_list_fetch') - def test_029_cert_id_lookup(self, mock_req, mock_comp): + def test_030_cert_id_lookup(self, mock_req, mock_comp): """ CAhandler._cert_id_lookup() - no san_list in function """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -357,7 +366,7 @@ def test_029_cert_id_lookup(self, mock_req, mock_comp): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._san_compare') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_list_fetch') - def test_030_cert_id_lookup(self, mock_fetch, mock_comp,): + def test_031_cert_id_lookup(self, mock_fetch, mock_comp,): """ CAhandler._cert_id_lookup() - _cert_list_fetch() does not return anything """ self.cahandler.api_host = 'api_host' mock_fetch.return_value = None @@ -367,7 +376,7 @@ def test_030_cert_id_lookup(self, mock_fetch, mock_comp,): self.assertIn('ERROR:test_a2c:_cert_id_lookup(): no certificates found for csr_cn', lcm.output) @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_list_fetch') - def test_031_cert_id_lookup(self, mock_fetch): + def test_032_cert_id_lookup(self, mock_fetch): """ CAhandler._cert_id_lookup() - request raises exception """ self.cahandler.api_host = 'api_host' mock_fetch.side_effect = Exception('req_exc') @@ -375,14 +384,14 @@ def test_031_cert_id_lookup(self, mock_fetch): self.assertFalse(self.cahandler._cert_id_lookup('csr_cn', 'san_list')) self.assertIn('ERROR:test_a2c:CAhandler._cert_id_lookup() returned error: req_exc', lcm.output) - def test_032__config_check(self): + def test_033__config_check(self): """ CAhandler._config.check() no api_host """ with self.assertLogs('test_a2c', level='INFO') as lcm: self.cahandler._config_check() self.assertEqual('api_host to be set in config file', self.cahandler.error) self.assertIn('ERROR:test_a2c:"api_host" to be set in config file', lcm.output) - def test_033__config_check(self): + def test_034__config_check(self): """ CAhandler._config.check() no api_user """ self.cahandler.api_host = 'api_host' with self.assertLogs('test_a2c', level='INFO') as lcm: @@ -390,7 +399,7 @@ def test_033__config_check(self): self.assertEqual('api_user to be set in config file', self.cahandler.error) self.assertIn('ERROR:test_a2c:"api_user" to be set in config file', lcm.output) - def test_034__config_check(self): + def test_035__config_check(self): """ CAhandler._config.check() no api_user """ self.cahandler.api_host = 'api_host' self.cahandler.credential_dic = {'api_user': False} @@ -399,7 +408,7 @@ def test_034__config_check(self): self.assertEqual('api_user to be set in config file', self.cahandler.error) self.assertIn('ERROR:test_a2c:"api_user" to be set in config file', lcm.output) - def test_035__config_check(self): + def test_036__config_check(self): """ CAhandler._config.check() no api_password """ self.cahandler.api_host = 'api_host' self.cahandler.credential_dic = {'api_user': 'api_user'} @@ -408,7 +417,7 @@ def test_035__config_check(self): self.assertEqual('api_password to be set in config file', self.cahandler.error) self.assertIn('ERROR:test_a2c:"api_password" to be set in config file', lcm.output) - def test_036__config_check(self): + def test_037__config_check(self): """ CAhandler._config.check() no api_password """ self.cahandler.api_host = 'api_host' self.cahandler.credential_dic = {'api_user': 'api_user', 'api_password': False} @@ -417,7 +426,7 @@ def test_036__config_check(self): self.assertEqual('api_password to be set in config file', self.cahandler.error) self.assertIn('ERROR:test_a2c:"api_password" to be set in config file', lcm.output) - def test_037__config_check(self): + def test_038__config_check(self): """ CAhandler._config.check() no tsg_name """ self.cahandler.api_host = 'api_host' self.cahandler.credential_dic = {'api_user': 'api_user', 'api_password': 'api_password'} @@ -426,7 +435,7 @@ def test_037__config_check(self): self.assertEqual('tsg_name to be set in config file', self.cahandler.error) self.assertIn('ERROR:test_a2c:"tsg_name" to be set in config file', lcm.output) - def test_038__config_check(self): + def test_039__config_check(self): """ CAhandler._config.check() no tsg_name """ self.cahandler.api_host = 'api_host' self.cahandler.credential_dic = {'api_user': 'api_user', 'api_password': 'api_password'} @@ -436,7 +445,7 @@ def test_038__config_check(self): self.assertEqual('tsg_name to be set in config file', self.cahandler.error) self.assertIn('ERROR:test_a2c:"tsg_name" to be set in config file', lcm.output) - def test_039__config_check(self): + def test_040__config_check(self): """ CAhandler._config.check() no ca_name """ self.cahandler.api_host = 'api_host' self.cahandler.credential_dic = {'api_user': 'api_user', 'api_password': 'api_password'} @@ -446,7 +455,7 @@ def test_039__config_check(self): self.assertEqual('ca_name to be set in config file', self.cahandler.error) self.assertIn('ERROR:test_a2c:"ca_name" to be set in config file', lcm.output) - def test_040__config_check(self): + def test_041__config_check(self): """ CAhandler._config.check() ca_bundle False """ self.cahandler.api_host = 'api_host' self.cahandler.credential_dic = {'api_user': 'api_user', 'api_password': 'api_password'} @@ -460,7 +469,7 @@ def test_040__config_check(self): self.assertIn('WARNING:test_a2c:"ca_bundle" set to "False" - validation of server certificate disabled', lcm.output) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_041_config_load(self, mock_load_cfg): + def test_042_config_load(self, mock_load_cfg): """ CAhandler._config_load no cahandler section """ mock_load_cfg.return_value = {} self.cahandler._config_load() @@ -474,7 +483,7 @@ def test_041_config_load(self, mock_load_cfg): self.assertEqual(20, self.cahandler.request_timeout) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_042_config_load(self, mock_load_cfg): + def test_043_config_load(self, mock_load_cfg): """ CAhandler._config_load api_host """ mock_load_cfg.return_value = {'CAhandler': {'api_host': 'api_host'}} self.cahandler._config_load() @@ -488,7 +497,7 @@ def test_042_config_load(self, mock_load_cfg): self.assertEqual(20, self.cahandler.request_timeout) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_043_config_load(self, mock_load_cfg): + def test_044_config_load(self, mock_load_cfg): """ CAhandler._config_load api_user """ mock_load_cfg.return_value = {'CAhandler': {'api_user': 'api_user'}} self.cahandler._config_load() @@ -502,7 +511,7 @@ def test_043_config_load(self, mock_load_cfg): self.assertEqual(20, self.cahandler.request_timeout) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_044_config_load(self, mock_load_cfg): + def test_045_config_load(self, mock_load_cfg): """ CAhandler._config_load api_password """ mock_load_cfg.return_value = {'CAhandler': {'api_password': 'api_password'}} self.cahandler._config_load() @@ -516,7 +525,7 @@ def test_044_config_load(self, mock_load_cfg): self.assertEqual(20, self.cahandler.request_timeout) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_045_config_load(self, mock_load_cfg): + def test_046_config_load(self, mock_load_cfg): """ CAhandler._config_load ca_name """ mock_load_cfg.return_value = {'CAhandler': {'ca_name': 'ca_name'}} self.cahandler._config_load() @@ -530,7 +539,7 @@ def test_045_config_load(self, mock_load_cfg): self.assertEqual(20, self.cahandler.request_timeout) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_046_config_load(self, mock_load_cfg): + def test_047_config_load(self, mock_load_cfg): """ CAhandler._config_load tsg_name """ mock_load_cfg.return_value = {'CAhandler': {'tsg_name': 'tsg_name'}} self.cahandler._config_load() @@ -544,7 +553,7 @@ def test_046_config_load(self, mock_load_cfg): self.assertEqual(20, self.cahandler.request_timeout) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_047_config_load(self, mock_load_cfg): + def test_048_config_load(self, mock_load_cfg): """ CAhandler._config_load ca_bundle string """ mock_load_cfg.return_value = {'CAhandler': {'ca_bundle': 'ca_bundle'}} self.cahandler._config_load() @@ -558,7 +567,7 @@ def test_047_config_load(self, mock_load_cfg): self.assertEqual(20, self.cahandler.request_timeout) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_048_config_load(self, mock_load_cfg): + def test_049_config_load(self, mock_load_cfg): """ CAhandler._config_load ca_bundle False """ mock_load_cfg.return_value = {'CAhandler': {'ca_bundle': False}} self.cahandler._config_load() @@ -572,7 +581,7 @@ def test_048_config_load(self, mock_load_cfg): self.assertEqual(20, self.cahandler.request_timeout) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_049_config_load(self, mock_load_cfg): + def test_050_config_load(self, mock_load_cfg): """ CAhandler._config_load template_name """ mock_load_cfg.return_value = {'CAhandler': {'template_name': 'template_name'}} self.cahandler._config_load() @@ -586,7 +595,7 @@ def test_049_config_load(self, mock_load_cfg): @patch.dict('os.environ', {'api_user_var': 'user_var'}) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_050_config_load(self, mock_load_cfg): + def test_051_config_load(self, mock_load_cfg): """ CAhandler._config_load load username from variable """ mock_load_cfg.return_value = {'CAhandler': {'api_user_variable': 'api_user_var'}} self.cahandler._config_load() @@ -596,7 +605,7 @@ def test_050_config_load(self, mock_load_cfg): @patch.dict('os.environ', {'api_user_var': 'user_var'}) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_051_config_load(self, mock_load_cfg): + def test_052_config_load(self, mock_load_cfg): """ CAhandler._config_load load username from non existing """ mock_load_cfg.return_value = {'CAhandler': {'api_user_variable': 'does_not_exist'}} with self.assertLogs('test_a2c', level='INFO') as lcm: @@ -608,7 +617,7 @@ def test_051_config_load(self, mock_load_cfg): @patch.dict('os.environ', {'api_user_var': 'user_var'}) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_052_config_load(self, mock_load_cfg): + def test_053_config_load(self, mock_load_cfg): """ CAhandler._config_load load username from wich gets overwritten from cfg-file """ mock_load_cfg.return_value = {'CAhandler': {'api_user_variable': 'api_user_var', 'api_user': 'api_user'}} with self.assertLogs('test_a2c', level='INFO') as lcm: @@ -620,7 +629,7 @@ def test_052_config_load(self, mock_load_cfg): @patch.dict('os.environ', {'api_password_var': 'password_var'}) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_053_config_load(self, mock_load_cfg): + def test_054_config_load(self, mock_load_cfg): """ CAhandler._config_load load password from variable """ mock_load_cfg.return_value = {'CAhandler': {'api_password_variable': 'api_password_var'}} self.cahandler._config_load() @@ -630,7 +639,7 @@ def test_053_config_load(self, mock_load_cfg): @patch.dict('os.environ', {'api_password_var': 'password_var'}) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_054_config_load(self, mock_load_cfg): + def test_055_config_load(self, mock_load_cfg): """ CAhandler._config_load load password from non existing variable """ mock_load_cfg.return_value = {'CAhandler': {'api_password_variable': 'does_not_exist'}} with self.assertLogs('test_a2c', level='INFO') as lcm: @@ -642,7 +651,7 @@ def test_054_config_load(self, mock_load_cfg): @patch.dict('os.environ', {'api_password_var': 'password_var'}) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_055_config_load(self, mock_load_cfg): + def test_056_config_load(self, mock_load_cfg): """ CAhandler._config_load load password from variable which gets overwritten """ mock_load_cfg.return_value = {'CAhandler': {'api_password_variable': 'api_password_var', 'api_password': 'api_password'}} with self.assertLogs('test_a2c', level='INFO') as lcm: @@ -655,7 +664,7 @@ def test_055_config_load(self, mock_load_cfg): @patch('examples.ca_handler.nclm_ca_handler.parse_url') @patch('json.loads') @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_056_config_load(self, mock_load_cfg, mock_json, mock_url): + def test_057_config_load(self, mock_load_cfg, mock_json, mock_url): """ test _config_load ca_handler configured load proxies """ mock_load_cfg.return_value = {'DEFAULT': {'proxy_server_list': 'foo'}} mock_url.return_value = {'foo': 'bar'} @@ -669,7 +678,7 @@ def test_056_config_load(self, mock_load_cfg, mock_json, mock_url): @patch('examples.ca_handler.nclm_ca_handler.parse_url') @patch('json.loads') @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_057_config_load(self, mock_load_cfg, mock_json, mock_url, mock_chk): + def test_058_config_load(self, mock_load_cfg, mock_json, mock_url, mock_chk): """ test _config_load ca_handler configured load proxies """ mock_load_cfg.return_value = {'DEFAULT': {'proxy_server_list': 'foo'}} mock_url.return_value = {'host': 'bar:8888'} @@ -686,7 +695,7 @@ def test_057_config_load(self, mock_load_cfg, mock_json, mock_url, mock_chk): @patch('examples.ca_handler.nclm_ca_handler.parse_url') @patch('json.loads') @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_058_config_load(self, mock_load_cfg, mock_json, mock_url, mock_chk): + def test_059_config_load(self, mock_load_cfg, mock_json, mock_url, mock_chk): """ test _config_load ca_handler configured load proxies """ mock_load_cfg.return_value = {'DEFAULT': {'proxy_server_list': 'foo'}} mock_url.return_value = {'host': 'bar'} @@ -702,7 +711,7 @@ def test_058_config_load(self, mock_load_cfg, mock_json, mock_url, mock_chk): self.assertEqual(300, self.cahandler.request_delta_treshold) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_059_config_load(self, mock_load_cfg): + def test_060_config_load(self, mock_load_cfg): """ CAhandler._config_load request_delta_treshold """ mock_load_cfg.return_value = {'CAhandler': {'request_delta_treshold': 60}} self.cahandler._config_load() @@ -713,7 +722,7 @@ def test_059_config_load(self, mock_load_cfg): self.assertEqual(60, self.cahandler.request_delta_treshold) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_060_config_load(self, mock_load_cfg): + def test_061_config_load(self, mock_load_cfg): """ CAhandler._config_load request_delta_treshold string """ mock_load_cfg.return_value = {'CAhandler': {'request_delta_treshold': 'aaa'}} with self.assertLogs('test_a2c', level='INFO') as lcm: @@ -726,14 +735,14 @@ def test_060_config_load(self, mock_load_cfg): self.assertIn('ERROR:test_a2c:CAhandler._config_load() could not load request_delta_treshold:aaa', lcm.output) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_061_config_load(self, mock_load_cfg): + def test_062_config_load(self, mock_load_cfg): """ CAhandler._config_load request_delta_treshold """ mock_load_cfg.return_value = {'CAhandler': {'request_timeout': 10}} self.cahandler._config_load() self.assertEqual(10, self.cahandler.request_timeout) @patch('examples.ca_handler.nclm_ca_handler.load_config') - def test_062_config_load(self, mock_load_cfg): + def test_063_config_load(self, mock_load_cfg): """ CAhandler._config_load request_delta_treshold """ mock_load_cfg.return_value = {'CAhandler': {'request_timeout': 'aa'}} self.cahandler._config_load() @@ -743,7 +752,7 @@ def test_062_config_load(self, mock_load_cfg): @patch('examples.ca_handler.nclm_ca_handler.date_to_uts_utc') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._unusedrequests_get') @patch('examples.ca_handler.nclm_ca_handler.uts_now') - def test_063__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastreq): + def test_064__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastreq): """ CAhandler._csr_id_lookup - all ok """ mock_utsnow.return_value = 1000 mock_uts.return_value = 900 @@ -755,7 +764,7 @@ def test_063__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastr @patch('examples.ca_handler.nclm_ca_handler.date_to_uts_utc') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._unusedrequests_get') @patch('examples.ca_handler.nclm_ca_handler.uts_now') - def test_064__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastreq): + def test_065__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastreq): """ CAhandler._csr_id_lookup - no requestID in list exception triggered """ mock_utsnow.return_value = 1000 mock_uts.return_value = 900 @@ -769,7 +778,7 @@ def test_064__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastr @patch('examples.ca_handler.nclm_ca_handler.date_to_uts_utc') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._unusedrequests_get') @patch('examples.ca_handler.nclm_ca_handler.uts_now') - def test_065__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastreq): + def test_066__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastreq): """ CAhandler._csr_id_lookup - cn in mock_unureq not correctly ordered """ mock_utsnow.return_value = 1000 mock_uts.return_value = 900 @@ -781,7 +790,7 @@ def test_065__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastr @patch('examples.ca_handler.nclm_ca_handler.date_to_uts_utc') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._unusedrequests_get') @patch('examples.ca_handler.nclm_ca_handler.uts_now') - def test_066__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastreq): + def test_067__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastreq): """ CAhandler._csr_id_lookup - empty subjectName """ mock_utsnow.return_value = 1000 mock_uts.return_value = 900 @@ -793,7 +802,7 @@ def test_066__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastr @patch('examples.ca_handler.nclm_ca_handler.date_to_uts_utc') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._unusedrequests_get') @patch('examples.ca_handler.nclm_ca_handler.uts_now') - def test_067__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastreq): + def test_068__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastreq): """ CAhandler._csr_id_lookup - no subjectName """ mock_utsnow.return_value = 1000 mock_uts.return_value = 900 @@ -805,7 +814,7 @@ def test_067__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastr @patch('examples.ca_handler.nclm_ca_handler.date_to_uts_utc') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._unusedrequests_get') @patch('examples.ca_handler.nclm_ca_handler.uts_now') - def test_068__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastreq): + def test_069__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastreq): """ CAhandler._csr_id_lookup - requests to old """ mock_utsnow.return_value = 1000 mock_uts.return_value = 100 @@ -818,7 +827,7 @@ def test_068__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_lastr @patch('examples.ca_handler.nclm_ca_handler.date_to_uts_utc') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._unusedrequests_get') @patch('examples.ca_handler.nclm_ca_handler.uts_now') - def test_069__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): + def test_070__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): """ CAhandler._csr_id_lookup - no csr_cn one san """ self.cahandler.api_host = 'api_host' mock_utsnow.return_value = 1000 @@ -834,7 +843,7 @@ def test_069__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, @patch('examples.ca_handler.nclm_ca_handler.date_to_uts_utc') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._unusedrequests_get') @patch('examples.ca_handler.nclm_ca_handler.uts_now') - def test_070__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): + def test_071__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): """ CAhandler._csr_id_lookup - no csr_cn two sans """ self.cahandler.api_host = 'api_host' mock_utsnow.return_value = 1000 @@ -850,7 +859,7 @@ def test_070__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, @patch('examples.ca_handler.nclm_ca_handler.date_to_uts_utc') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._unusedrequests_get') @patch('examples.ca_handler.nclm_ca_handler.uts_now') - def test_071__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): + def test_072__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): """ CAhandler._csr_id_lookup - no csr_cn two sans to be reordered """ self.cahandler.api_host = 'api_host' mock_utsnow.return_value = 1000 @@ -866,7 +875,7 @@ def test_071__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, @patch('examples.ca_handler.nclm_ca_handler.date_to_uts_utc') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._unusedrequests_get') @patch('examples.ca_handler.nclm_ca_handler.uts_now') - def test_072__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): + def test_073__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): """ CAhandler._csr_id_lookup - no csr_cn no requestID """ self.cahandler.api_host = 'api_host' mock_utsnow.return_value = 1000 @@ -882,7 +891,7 @@ def test_072__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, @patch('examples.ca_handler.nclm_ca_handler.date_to_uts_utc') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._unusedrequests_get') @patch('examples.ca_handler.nclm_ca_handler.uts_now') - def test_073__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): + def test_074__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): """ CAhandler._csr_id_lookup - no csr_cn sans are not matching """ self.cahandler.api_host = 'api_host' mock_utsnow.return_value = 1000 @@ -898,7 +907,7 @@ def test_073__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, @patch('examples.ca_handler.nclm_ca_handler.date_to_uts_utc') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._unusedrequests_get') @patch('examples.ca_handler.nclm_ca_handler.uts_now') - def test_074__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): + def test_075__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): """ CAhandler._csr_id_lookup - no csr_cn no pkcs10 """ self.cahandler.api_host = 'api_host' mock_utsnow.return_value = 1000 @@ -914,7 +923,7 @@ def test_074__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, @patch('examples.ca_handler.nclm_ca_handler.date_to_uts_utc') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._unusedrequests_get') @patch('examples.ca_handler.nclm_ca_handler.uts_now') - def test_075__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): + def test_076__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, mock_lastreq): """ CAhandler._csr_id_lookup - no csr_cn trigger excption in loop """ self.cahandler.api_host = 'api_host' mock_utsnow.return_value = 1000 @@ -928,14 +937,14 @@ def test_075__csr_id_lookup(self, mock_utsnow, mock_unureq, mock_uts, mock_san, self.assertIn("ERROR:test_a2c:_csr_id_lookup(): response incomplete: 'requestId'", lcm.output) @patch('examples.ca_handler.nclm_ca_handler.CAhandler._api_post') - def test_076__request_import(self, mock_req): + def test_077__request_import(self, mock_req): """ CAhandler._request_import """ self.cahandler.api_host = 'api_host' mock_req.return_value = 'foo' self.assertEqual('foo', self.cahandler._request_import('csr')) @patch('examples.ca_handler.nclm_ca_handler.CAhandler._api_post') - def test_077__request_import(self, mock_req): + def test_078__request_import(self, mock_req): """ CAhandler._request_import - req raises an exception """ self.cahandler.api_host = 'api_host' mock_req.side_effect = Exception('exc_req_import') @@ -944,7 +953,7 @@ def test_077__request_import(self, mock_req): self.assertIn('ERROR:test_a2c:CAhandler._request_import() returned error: exc_req_import', lcm.output) @patch('requests.get') - def test_078__unusedrequests_get(self, mock_req): + def test_079__unusedrequests_get(self, mock_req): """ CAhandler._unusedrequests_get """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -953,7 +962,7 @@ def test_078__unusedrequests_get(self, mock_req): self.assertEqual({'foo': 'bar'}, self.cahandler._unusedrequests_get()) @patch('requests.get') - def test_079__unusedrequests_get(self, mock_req): + def test_080__unusedrequests_get(self, mock_req): """ CAhandler._unusedrequests_get """ self.cahandler.api_host = 'api_host' mock_req.side_effect = Exception('exc_req_unused') @@ -962,7 +971,7 @@ def test_079__unusedrequests_get(self, mock_req): self.assertIn('ERROR:test_a2c:CAhandler._unusedrequests_get() returned error: exc_req_unused', lcm.output) @patch('requests.get') - def test_080__login(self, mock_get): + def test_081__login(self, mock_get): """ CAhandler._unusedrequests_get """ self.cahandler.api_host = 'api_host' mockresponse1 = Mock() @@ -977,7 +986,7 @@ def test_080__login(self, mock_get): @patch('requests.post') @patch('requests.get') - def test_081__login(self, mock_get, mock_post): + def test_082__login(self, mock_get, mock_post): """ CAhandler._unusedrequests_get """ self.cahandler.api_host = 'api_host' mockresponse1 = Mock() @@ -991,7 +1000,7 @@ def test_081__login(self, mock_get, mock_post): @patch('requests.post') @patch('requests.get') - def test_082__login(self, mock_get, mock_post): + def test_083__login(self, mock_get, mock_post): """ CAhandler._unusedrequests_get mock_post without username""" self.cahandler.api_host = 'api_host' mockresponse1 = Mock() @@ -1005,7 +1014,7 @@ def test_082__login(self, mock_get, mock_post): @patch('requests.post') @patch('requests.get') - def test_083__login(self, mock_get, mock_post): + def test_084__login(self, mock_get, mock_post): """ CAhandler._unusedrequests_get mock_post without username""" self.cahandler.api_host = 'api_host' mockresponse1 = Mock() @@ -1022,7 +1031,7 @@ def test_083__login(self, mock_get, mock_post): @patch('requests.post') @patch('requests.get') - def test_084__login(self, mock_get, mock_post): + def test_085__login(self, mock_get, mock_post): """ CAhandler._unusedrequests_get mock_post without realms""" self.cahandler.api_host = 'api_host' mockresponse1 = Mock() @@ -1036,7 +1045,7 @@ def test_084__login(self, mock_get, mock_post): @patch('requests.post') @patch('requests.get') - def test_085__login(self, mock_get, mock_post): + def test_086__login(self, mock_get, mock_post): """ CAhandler._unusedrequests_get mock_post without access tooken""" self.cahandler.api_host = 'api_host' mockresponse1 = Mock() @@ -1051,41 +1060,41 @@ def test_085__login(self, mock_get, mock_post): self.assertFalse(self.cahandler.headers) self.assertIn('ERROR:test_a2c:CAhandler._login(): No token returned. Aborting...', lcm.output) - def test_086__san_compare(self): + def test_087__san_compare(self): """ CAhandler._san_compare all ok """ csr_san_list = ['foo:foo'] cert_san_list = {'foo': ['foo']} self.assertTrue(self.cahandler._san_compare(csr_san_list, cert_san_list)) - def test_087__san_compare(self): + def test_088__san_compare(self): """ CAhandler._san_compare multiple """ csr_san_list = ['foo:foo', 'foo:bar'] cert_san_list = {'foo': ['foo', 'bar']} self.assertTrue(self.cahandler._san_compare(csr_san_list, cert_san_list)) - def test_088__san_compare(self): + def test_089__san_compare(self): """ CAhandler._san_compare multiple """ csr_san_list = ['foo:foo,foo:bar'] cert_san_list = {'foo': ['foo', 'bar']} self.assertTrue(self.cahandler._san_compare(csr_san_list, cert_san_list)) - def test_089__san_compare(self): + def test_090__san_compare(self): """ CAhandler._san_compare multiple """ csr_san_list = ['foo:foo,foo:bar1'] cert_san_list = {'foo': ['foo', 'bar']} self.assertFalse(self.cahandler._san_compare(csr_san_list, cert_san_list)) - def test_090_poll(self): + def test_091_poll(self): """ CAhandler.poll() """ self.assertEqual(('Method not implemented.', None, None, 'poll_identifier', False), self.cahandler.poll('cert_name', 'poll_identifier', 'csr')) - def test_091_trigger(self): + def test_092_trigger(self): """ CAhandler.trigger() """ self.assertEqual(('Method not implemented.', None, None), self.cahandler.trigger('payload')) @patch('requests.get') - def test_092_container_id_lookup(self, mock_get): - """ CAhandler._container_id_lookup() - all ok """ + def test_093___tsg_id_lookup(self, mock_get): + """ CAhandler._tsg_id_lookup() - all ok """ self.cahandler.api_host = 'api_host' mockresponse = Mock() mockresponse.json = lambda: {'targetSystemGroups': [{'name': 'name', 'id': 'id'}]} @@ -1095,8 +1104,8 @@ def test_092_container_id_lookup(self, mock_get): self.assertEqual({'name': 'name', 'id': 'id'}, self.cahandler.tsg_info_dic) @patch('requests.get') - def test_093_container_id_lookup(self, mock_get): - """ CAhandler._container_id_lookup() - multipe returned 1st matches """ + def test_094___tsg_id_lookup(self, mock_get): + """ CAhandler._tsg_id_lookup() - multipe returned 1st matches """ self.cahandler.api_host = 'api_host' mockresponse = Mock() mockresponse.json = lambda: {'targetSystemGroups': [{'name': 'name', 'id': 'id'}, {'name': 'name1', 'id': 'id1'}]} @@ -1106,8 +1115,8 @@ def test_093_container_id_lookup(self, mock_get): self.assertEqual({'name': 'name', 'id': 'id'}, self.cahandler.tsg_info_dic) @patch('requests.get') - def test_094_container_id_lookup(self, mock_get): - """ CAhandler._container_id_lookup() - multipe returned 2nd matches """ + def test_095___tsg_id_lookup(self, mock_get): + """ CAhandler._tsg_id_lookup() - multipe returned 2nd matches """ self.cahandler.api_host = 'api_host' mockresponse = Mock() mockresponse.json = lambda: {'targetSystemGroups': [{'name': 'name1', 'id': 'id1'}, {'name': 'name', 'id': 'id'}]} @@ -1117,8 +1126,8 @@ def test_094_container_id_lookup(self, mock_get): self.assertEqual({'name': 'name', 'id': 'id'}, self.cahandler.tsg_info_dic) @patch('requests.get') - def test_095_container_id_lookup(self, mock_get): - """ CAhandler._container_id_lookup() - id is missing """ + def test_096___tsg_id_lookup(self, mock_get): + """ CAhandler._tsg_id_lookup() - id is missing """ self.cahandler.api_host = 'api_host' mockresponse = Mock() mockresponse.json = lambda: {'targetSystemGroups': [{'name': 'name'}]} @@ -1130,8 +1139,8 @@ def test_095_container_id_lookup(self, mock_get): self.assertIn("ERROR:test_a2c:CAhandler._container_id_lookup() incomplete response: {'name': 'name'}", lcm.output) @patch('requests.get') - def test_096_container_id_lookup(self, mock_get): - """ CAhandler._container_id_lookup() - name is missing """ + def test_097___tsg_id_lookup(self, mock_get): + """ CAhandler._tsg_id_lookup() - name is missing """ self.cahandler.api_host = 'api_host' mockresponse = Mock() mockresponse.json = lambda: {'targetSystemGroups': [{'foo': 'bar', 'id': 'id'}]} @@ -1143,8 +1152,8 @@ def test_096_container_id_lookup(self, mock_get): self.assertIn("ERROR:test_a2c:CAhandler._container_id_lookup() incomplete response: {'foo': 'bar', 'id': 'id'}", lcm.output) @patch('requests.get') - def test_097_container_id_lookup(self, mock_get): - """ CAhandler._container_id_lookup() - targetSystemGroups is missing """ + def test_098___tsg_id_lookup(self, mock_get): + """ CAhandler._tsg_id_lookup() - targetSystemGroups is missing """ self.cahandler.api_host = 'api_host' mockresponse = Mock() mockresponse.json = lambda: {'tsg': [{'foo': 'bar', 'id': 'id'}]} @@ -1156,7 +1165,7 @@ def test_097_container_id_lookup(self, mock_get): self.assertIn('ERROR:test_a2c:CAhandler._container_id_lookup() no target-system-groups found for filter: name...', lcm.output) @patch('requests.get') - def test_098_container_id_lookup(self, mock_req): + def test_099__tsg_id_lookup(self, mock_req): """ CAhandler._request_import - req raises an exception """ self.cahandler.api_host = 'api_host' mock_req.side_effect = Exception('exc_container_id_lookup') @@ -1165,7 +1174,7 @@ def test_098_container_id_lookup(self, mock_req): self.assertIn('ERROR:test_a2c:CAhandler._container_id_lookup() returned error: exc_container_id_lookup', lcm.output) @patch('requests.get') - def test_099__template_id_lookup(self, mock_get): + def test_100__template_id_lookup(self, mock_get): """ CAhandler._template_id_lookup() - all ok """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1176,7 +1185,7 @@ def test_099__template_id_lookup(self, mock_get): self.assertEqual({'name': 'template_name', 'id': 10}, self.cahandler.template_info_dic) @patch('requests.get') - def test_100__template_id_lookup(self, mock_get): + def test_101__template_id_lookup(self, mock_get): """ CAhandler._template_id_lookup() - linkId None """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1187,7 +1196,7 @@ def test_100__template_id_lookup(self, mock_get): self.assertEqual({'name': 'template_name', 'id': None}, self.cahandler.template_info_dic) @patch('requests.get') - def test_101__template_id_lookup(self, mock_get): + def test_102__template_id_lookup(self, mock_get): """ CAhandler._template_id_lookup() - No linkId """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1198,7 +1207,7 @@ def test_101__template_id_lookup(self, mock_get): self.assertEqual({'name': 'template_name', 'id': None}, self.cahandler.template_info_dic) @patch('requests.get') - def test_102__template_id_lookup(self, mock_get): + def test_103__template_id_lookup(self, mock_get): """ CAhandler._template_id_lookup() - no match in template names """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1209,7 +1218,7 @@ def test_102__template_id_lookup(self, mock_get): self.assertEqual({'name': 'template_name', 'id': None}, self.cahandler.template_info_dic) @patch('requests.get') - def test_103__template_id_lookup(self, mock_get): + def test_104__template_id_lookup(self, mock_get): """ CAhandler._template_id_lookup() - allowed false """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1220,7 +1229,7 @@ def test_103__template_id_lookup(self, mock_get): self.assertEqual({'name': 'template_name', 'id': None}, self.cahandler.template_info_dic) @patch('requests.get') - def test_104__template_id_lookup(self, mock_get): + def test_105__template_id_lookup(self, mock_get): """ CAhandler._template_id_lookup() - template in lower cases """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1231,7 +1240,7 @@ def test_104__template_id_lookup(self, mock_get): self.assertEqual({'name': 'template_name', 'id': 10}, self.cahandler.template_info_dic) @patch('requests.get') - def test_105__template_id_lookup(self, mock_get): + def test_106__template_id_lookup(self, mock_get): """ CAhandler._template_id_lookup() - no template """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1242,7 +1251,7 @@ def test_105__template_id_lookup(self, mock_get): self.assertEqual({'name': 'template_name', 'id': None}, self.cahandler.template_info_dic) @patch('requests.get') - def test_106__template_id_lookup(self, mock_get): + def test_107__template_id_lookup(self, mock_get): """ CAhandler._template_id_lookup() - no linktype """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1253,7 +1262,7 @@ def test_106__template_id_lookup(self, mock_get): self.assertEqual({'name': 'template_name', 'id': None}, self.cahandler.template_info_dic) @patch('requests.get') - def test_107__template_id_lookup(self, mock_get): + def test_108__template_id_lookup(self, mock_get): """ CAhandler._template_id_lookup() - empty list """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1264,7 +1273,7 @@ def test_107__template_id_lookup(self, mock_get): self.assertEqual({'name': 'template_name', 'id': None}, self.cahandler.template_info_dic) @patch('requests.get') - def test_108__template_id_lookup(self, mock_get): + def test_109__template_id_lookup(self, mock_get): """ CAhandler._template_id_lookup() - no items """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1275,7 +1284,7 @@ def test_108__template_id_lookup(self, mock_get): self.assertEqual({'name': 'template_name', 'id': None}, self.cahandler.template_info_dic) @patch('requests.get') - def test_109__template_id_lookup(self, mock_get): + def test_110__template_id_lookup(self, mock_get): """ CAhandler._template_id_lookup() - wrong dict """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1286,7 +1295,7 @@ def test_109__template_id_lookup(self, mock_get): self.assertEqual({'name': 'template_name', 'id': None}, self.cahandler.template_info_dic) @patch('requests.get') - def test_110__template_id_lookup(self, mock_get): + def test_111__template_id_lookup(self, mock_get): """ CAhandler._template_id_lookup() - wrong dict """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1297,7 +1306,7 @@ def test_110__template_id_lookup(self, mock_get): self.assertEqual({'name': 'template_name', 'id': None}, self.cahandler.template_info_dic) @patch('requests.get') - def test_111__template_id_lookup(self, mock_get): + def test_112__template_id_lookup(self, mock_get): """ CAhandler._template_id_lookup() - empty response """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1308,7 +1317,7 @@ def test_111__template_id_lookup(self, mock_get): self.assertEqual({'name': 'template_name', 'id': None}, self.cahandler.template_info_dic) @patch('requests.get') - def test_112__template_id_lookup(self, mock_req): + def test_113__template_id_lookup(self, mock_req): """ CAhandler._cert_id_lookup() - request raises exception """ self.cahandler.api_host = 'api_host' mock_req.side_effect = Exception('req_exc') @@ -1321,8 +1330,8 @@ def test_112__template_id_lookup(self, mock_req): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._config_load') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._config_check') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._login') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._container_id_lookup') - def test_113__enter__(self, mock_lookup, mock_login, mock_check, mock_load): + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._tsg_id_lookup') + def test_114__enter__(self, mock_lookup, mock_login, mock_check, mock_load): """ test enter """ self.cahandler.__enter__() self.assertTrue(mock_load.called) @@ -1333,8 +1342,8 @@ def test_113__enter__(self, mock_lookup, mock_login, mock_check, mock_load): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._config_load') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._config_check') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._login') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._container_id_lookup') - def test_114__enter__(self, mock_lookup, mock_login, mock_check, mock_load): + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._tsg_id_lookup') + def test_115__enter__(self, mock_lookup, mock_login, mock_check, mock_load): """ test enter with host already defined """ self.cahandler.api_host = 'api_host' self.cahandler.__enter__() @@ -1346,8 +1355,8 @@ def test_114__enter__(self, mock_lookup, mock_login, mock_check, mock_load): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._config_load') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._config_check') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._login') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._container_id_lookup') - def test_115__enter__(self, mock_lookup, mock_login, mock_check, mock_load): + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._tsg_id_lookup') + def test_116__enter__(self, mock_lookup, mock_login, mock_check, mock_load): """ test enter with header defined """ self.cahandler.headers = 'header' self.cahandler.__enter__() @@ -1359,8 +1368,8 @@ def test_115__enter__(self, mock_lookup, mock_login, mock_check, mock_load): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._config_load') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._config_check') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._login') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._container_id_lookup') - def test_116__enter__(self, mock_lookup, mock_login, mock_check, mock_load): + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._tsg_id_lookup') + def test_117__enter__(self, mock_lookup, mock_login, mock_check, mock_load): """ test enter with error defined """ self.cahandler.error = 'error' self.cahandler.__enter__() @@ -1372,8 +1381,8 @@ def test_116__enter__(self, mock_lookup, mock_login, mock_check, mock_load): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._config_load') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._config_check') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._login') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._container_id_lookup') - def test_117__enter__(self, mock_lookup, mock_login, mock_check, mock_load): + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._tsg_id_lookup') + def test_118__enter__(self, mock_lookup, mock_login, mock_check, mock_load): """ test enter with tst_info_dic defined """ self.cahandler.tsg_info_dic = {'id': 'foo'} self.cahandler.__enter__() @@ -1385,8 +1394,8 @@ def test_117__enter__(self, mock_lookup, mock_login, mock_check, mock_load): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._config_load') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._config_check') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._login') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._container_id_lookup') - def test_118__enter__(self, mock_lookup, mock_login, mock_check, mock_load): + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._tsg_id_lookup') + def test_119__enter__(self, mock_lookup, mock_login, mock_check, mock_load): """ test enter with error defined """ self.cahandler.tsg_info_dic = {'id': 'foo'} self.cahandler.error = 'error' @@ -1398,7 +1407,7 @@ def test_118__enter__(self, mock_lookup, mock_login, mock_check, mock_load): @patch('examples.ca_handler.nclm_ca_handler.cert_serial_get') @patch('requests.get') - def test_119_revoke(self, mock_get, mock_serial): + def test_120_revoke(self, mock_get, mock_serial): """ test revoke empty certificate list has been returned """ self.cahandler.api_host = 'api_host' mock_serial.return_value = 11 @@ -1409,7 +1418,7 @@ def test_119_revoke(self, mock_get, mock_serial): @patch('examples.ca_handler.nclm_ca_handler.cert_serial_get') @patch('requests.get') - def test_120_revoke(self, mock_get, mock_serial): + def test_121_revoke(self, mock_get, mock_serial): """ test revoke request get aborted with exception """ self.cahandler.api_host = 'api_host' mock_serial.return_value = 11 @@ -1420,7 +1429,7 @@ def test_120_revoke(self, mock_get, mock_serial): @patch('examples.ca_handler.nclm_ca_handler.cert_serial_get') @patch('requests.get') - def test_121_revoke(self, mock_get, mock_serial): + def test_122_revoke(self, mock_get, mock_serial): """ test revoke certificates in certificate_list but content is bogus """ self.cahandler.api_host = 'api_host' mock_serial.return_value = 11 @@ -1432,7 +1441,7 @@ def test_121_revoke(self, mock_get, mock_serial): @patch('requests.post') @patch('examples.ca_handler.nclm_ca_handler.cert_serial_get') @patch('requests.get') - def test_122_revoke(self, mock_get, mock_serial, mock_post): + def test_123_revoke(self, mock_get, mock_serial, mock_post): """ test revoke certificates in certificate_list all good """ self.cahandler.api_host = 'api_host' mock_serial.return_value = 11 @@ -1447,7 +1456,7 @@ def test_122_revoke(self, mock_get, mock_serial, mock_post): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._api_post') @patch('examples.ca_handler.nclm_ca_handler.cert_serial_get') @patch('requests.get') - def test_123_revoke(self, mock_get, mock_serial, mock_post): + def test_124_revoke(self, mock_get, mock_serial, mock_post): """ test revoke certificates in certificate_list but request.post returns execption """ self.cahandler.api_host = 'api_host' mock_serial.return_value = 11 @@ -1457,65 +1466,52 @@ def test_123_revoke(self, mock_get, mock_serial, mock_post): mock_post.side_effect = Exception('ex_req_post') self.assertEqual((500, 'urn:ietf:params:acme:error:serverInternal', 'Revocation operation failed'), self.cahandler.revoke('cert', 'rev_reason', 'rev_date')) - def test_124_enroll(self): + def test_125_enroll(self): """ enroll() if there is an error """ self.cahandler.error = 'foo' with self.assertLogs('test_a2c', level='INFO') as lcm: self.assertEqual((None, None, None, None), self.cahandler.enroll('csr')) self.assertIn('ERROR:test_a2c:foo', lcm.output) - def test_125_enroll(self): + def test_126_enroll(self): """ enroll() no target-system-id """ self.cahandler.tsg_info_dic = {'id': None, 'name': 'name'} self.assertEqual(('CAhandler.eroll(): ID lookup for targetSystemGroup "name" failed.', None, None, None), self.cahandler.enroll('csr')) - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._template_id_lookup') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_id_lookup') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._api_post') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._csr_id_lookup') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._request_import') + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_enroll') @patch('examples.ca_handler.nclm_ca_handler.csr_san_get') @patch('examples.ca_handler.nclm_ca_handler.csr_cn_get') + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._template_id_lookup') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._ca_policylink_id_lookup') - def test_126_enroll(self, mock_lookup, mock_cn_get, mock_san_get, mock_reqimp, mock_csr_lookup, mock_post, mock_cert_lookup, mock_tmpl_lookup): - """ enroll() without certid """ + def test_127_enroll(self, mock_lookup, mock_tmpl_lookup, mock_cn_get, mock_san_get, mock_enroll): + """ enroll() with certid """ self.cahandler.api_host = 'api_host' self.cahandler.tsg_info_dic = {'id': 10, 'name': 'name'} self.cahandler.wait_interval = 0 mock_lookup.return_value = 10 mock_cn_get.return_value = 'cn' mock_san_get.return_value = ['foo.bar.local'] - mock_reqimp.return_value = True - mock_csr_lookup.return_value = 10 - mock_post.return_value = True - mock_cert_lookup.return_value = None - self.assertEqual(("certifcate id lookup failed for: cn, ['foo.bar.local']", None, None, None), self.cahandler.enroll('csr')) + mock_enroll.return_value = ['error', 'cert_bundle', 'cert_raw'] + self.assertEqual(('error', 'cert_bundle', 'cert_raw', None), self.cahandler.enroll('csr')) self.assertFalse(mock_tmpl_lookup.called) - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_bundle_build') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._template_id_lookup') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_id_lookup') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._api_post') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._csr_id_lookup') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._request_import') + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_enroll') @patch('examples.ca_handler.nclm_ca_handler.csr_san_get') @patch('examples.ca_handler.nclm_ca_handler.csr_cn_get') + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._template_id_lookup') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._ca_policylink_id_lookup') - def test_127_enroll(self, mock_lookup, mock_cn_get, mock_san_get, mock_reqimp, mock_csr_lookup, mock_post, mock_cert_lookup, mock_tmpl_lookup, mock_bundle): + def test_128_enroll(self, mock_lookup, mock_tmpl_lookup, mock_cn_get, mock_san_get, mock_enroll): """ enroll() with certid """ self.cahandler.api_host = 'api_host' self.cahandler.tsg_info_dic = {'id': 10, 'name': 'name'} + self.cahandler.template_info_dic = {'name': 'name', 'id': None} self.cahandler.wait_interval = 0 mock_lookup.return_value = 10 mock_cn_get.return_value = 'cn' mock_san_get.return_value = ['foo.bar.local'] - mock_reqimp.return_value = True - mock_csr_lookup.return_value = 10 - mock_post.return_value = True - mock_cert_lookup.return_value = 10 - mock_bundle.return_value = ('error', 'cert_bundle', 'cert_raw') + mock_enroll.return_value = ['error', 'cert_bundle', 'cert_raw'] self.assertEqual(('error', 'cert_bundle', 'cert_raw', None), self.cahandler.enroll('csr')) - self.assertFalse(mock_tmpl_lookup.called) + self.assertTrue(mock_tmpl_lookup.called) @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_bundle_build') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._template_id_lookup') @@ -1526,13 +1522,13 @@ def test_127_enroll(self, mock_lookup, mock_cn_get, mock_san_get, mock_reqimp, m @patch('examples.ca_handler.nclm_ca_handler.csr_san_get') @patch('examples.ca_handler.nclm_ca_handler.csr_cn_get') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._ca_policylink_id_lookup') - def test_128_enroll(self, mock_lookup, mock_cn_get, mock_san_get, mock_reqimp, mock_csr_lookup, mock_post, mock_cert_lookup, mock_tmpl_lookup, mock_bundle): - """ enroll() no tmpload """ + def test_129_enroll(self, mock_lookup, mock_cn_get, mock_san_get, mock_reqimp, mock_csr_lookup, mock_post, mock_cert_lookup, mock_tmpl_lookup, mock_bundle): + """ enroll() tmpload """ self.cahandler.api_host = 'api_host' - self.cahandler.tsg_info_dic = {'id': 10, 'name': 'name'} + self.cahandler.tsg_info_dic = {'id': 'id', 'name': 'name'} self.cahandler.wait_interval = 0 - self.cahandler.template_info_dic = {'name': 'name', 'id': 'id'} - mock_lookup.return_value = 10 + self.cahandler.template_info_dic = {'name': 'name', 'id': None} + mock_lookup.return_value = 0 mock_cn_get.return_value = 'cn' mock_san_get.return_value = ['foo.bar.local'] mock_reqimp.return_value = True @@ -1540,63 +1536,133 @@ def test_128_enroll(self, mock_lookup, mock_cn_get, mock_san_get, mock_reqimp, m mock_post.return_value = True mock_cert_lookup.return_value = 10 mock_bundle.return_value = ('error', 'cert_bundle', 'cert_raw') - self.assertEqual(('error', 'cert_bundle', 'cert_raw', None), self.cahandler.enroll('csr')) + self.assertEqual(('enrollment aborted. policylink_id: 0, tsg_id: id', None, None, None), self.cahandler.enroll('csr')) self.assertFalse(mock_tmpl_lookup.called) @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_bundle_build') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._template_id_lookup') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_id_lookup') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._api_post') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._csr_id_lookup') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._request_import') - @patch('examples.ca_handler.nclm_ca_handler.csr_san_get') - @patch('examples.ca_handler.nclm_ca_handler.csr_cn_get') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._ca_policylink_id_lookup') - def test_129_enroll(self, mock_lookup, mock_cn_get, mock_san_get, mock_reqimp, mock_csr_lookup, mock_post, mock_cert_lookup, mock_tmpl_lookup, mock_bundle): - """ enroll() tmpload """ + @patch('examples.ca_handler.nclm_ca_handler.b64_encode') + @patch('examples.ca_handler.nclm_ca_handler.convert_string_to_byte') + @patch('examples.ca_handler.nclm_ca_handler.build_pem_file') + def test_130_cert_enroll(self, mock_build, mock_byte, mock_b64, mock_post, mock_cert_lookup, mock_bundle): + """ test cert_enroll() """ + self.cahandler.wait_interval = 0 self.cahandler.api_host = 'api_host' self.cahandler.tsg_info_dic = {'id': 10, 'name': 'name'} + mock_post.return_value = 'mock_post' + self.assertEqual(('enrollment failed: mock_post', None, None), self.cahandler._cert_enroll('csr', 'cn', ['san'], 'policylink_id'))# + self.assertTrue(mock_build.called) + self.assertTrue(mock_byte.called) + self.assertTrue(mock_b64.called) + self.assertFalse(mock_cert_lookup.called) + self.assertFalse(mock_bundle.called) + + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_bundle_build') + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_id_lookup') + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._api_post') + @patch('examples.ca_handler.nclm_ca_handler.b64_encode') + @patch('examples.ca_handler.nclm_ca_handler.convert_string_to_byte') + @patch('examples.ca_handler.nclm_ca_handler.build_pem_file') + def test_131_cert_enroll(self, mock_build, mock_byte, mock_b64, mock_post, mock_cert_lookup, mock_bundle): + """ test cert_enroll() """ self.cahandler.wait_interval = 0 - self.cahandler.template_info_dic = {'name': 'name', 'id': None} - mock_lookup.return_value = 10 - mock_cn_get.return_value = 'cn' - mock_san_get.return_value = ['foo.bar.local'] - mock_reqimp.return_value = True - mock_csr_lookup.return_value = 10 - mock_post.return_value = True - mock_cert_lookup.return_value = 10 - mock_bundle.return_value = ('error', 'cert_bundle', 'cert_raw') - self.assertEqual(('error', 'cert_bundle', 'cert_raw', None), self.cahandler.enroll('csr')) - self.assertTrue(mock_tmpl_lookup.called) + self.cahandler.api_host = 'api_host' + self.cahandler.tsg_info_dic = {'id': 10, 'name': 'name'} + self.cahandler.template_info_dic = {'name': 'name', 'id': 'id'} + mock_post.return_value = 'mock_post' + self.assertEqual(('enrollment failed: mock_post', None, None), self.cahandler._cert_enroll('csr', 'cn', ['san'], 'policylink_id'))# + self.assertTrue(mock_build.called) + self.assertTrue(mock_byte.called) + self.assertTrue(mock_b64.called) + self.assertFalse(mock_cert_lookup.called) + self.assertFalse(mock_bundle.called) @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_bundle_build') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._template_id_lookup') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_id_lookup') @patch('examples.ca_handler.nclm_ca_handler.CAhandler._api_post') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._csr_id_lookup') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._request_import') - @patch('examples.ca_handler.nclm_ca_handler.csr_san_get') - @patch('examples.ca_handler.nclm_ca_handler.csr_cn_get') - @patch('examples.ca_handler.nclm_ca_handler.CAhandler._ca_policylink_id_lookup') - def test_130_enroll(self, mock_lookup, mock_cn_get, mock_san_get, mock_reqimp, mock_csr_lookup, mock_post, mock_cert_lookup, mock_tmpl_lookup, mock_bundle): - """ enroll() tmpload """ + @patch('examples.ca_handler.nclm_ca_handler.b64_encode') + @patch('examples.ca_handler.nclm_ca_handler.convert_string_to_byte') + @patch('examples.ca_handler.nclm_ca_handler.build_pem_file') + def test_132_cert_enroll(self, mock_build, mock_byte, mock_b64, mock_post, mock_cert_lookup, mock_bundle): + """ test cert_enroll() """ + self.cahandler.wait_interval = 0 self.cahandler.api_host = 'api_host' - self.cahandler.tsg_info_dic = {'id': 'id', 'name': 'name'} + self.cahandler.tsg_info_dic = {'id': 10, 'name': 'name'} + self.cahandler.template_info_dic = {'name': 'name', 'id': 'id'} + mock_post.return_value = {'status': 400} + self.assertEqual(("enrollment failed: {'status': 400}", None, None), self.cahandler._cert_enroll('csr', 'cn', ['san'], 'policylink_id'))# + self.assertTrue(mock_build.called) + self.assertTrue(mock_byte.called) + self.assertTrue(mock_b64.called) + self.assertFalse(mock_cert_lookup.called) + self.assertFalse(mock_bundle.called) + + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_bundle_build') + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_id_lookup') + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._api_post') + @patch('examples.ca_handler.nclm_ca_handler.b64_encode') + @patch('examples.ca_handler.nclm_ca_handler.convert_string_to_byte') + @patch('examples.ca_handler.nclm_ca_handler.build_pem_file') + def test_133_cert_enroll(self, mock_build, mock_byte, mock_b64, mock_post, mock_cert_lookup, mock_bundle): + """ test cert_enroll() """ self.cahandler.wait_interval = 0 - self.cahandler.template_info_dic = {'name': 'name', 'id': None} - mock_lookup.return_value = 0 - mock_cn_get.return_value = 'cn' - mock_san_get.return_value = ['foo.bar.local'] - mock_reqimp.return_value = True - mock_csr_lookup.return_value = 10 - mock_post.return_value = True + self.cahandler.api_host = 'api_host' + self.cahandler.tsg_info_dic = {'id': 10, 'name': 'name'} + self.cahandler.template_info_dic = {'name': 'name', 'id': 'id'} + mock_post.return_value = {'status': 400, 'message': 'message'} + self.assertEqual(("enrollment failed: message", None, None), self.cahandler._cert_enroll('csr', 'cn', ['san'], 'policylink_id'))# + self.assertTrue(mock_build.called) + self.assertTrue(mock_byte.called) + self.assertTrue(mock_b64.called) + self.assertFalse(mock_cert_lookup.called) + self.assertFalse(mock_bundle.called) + + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_bundle_build') + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_id_lookup') + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._api_post') + @patch('examples.ca_handler.nclm_ca_handler.b64_encode') + @patch('examples.ca_handler.nclm_ca_handler.convert_string_to_byte') + @patch('examples.ca_handler.nclm_ca_handler.build_pem_file') + def test_134_cert_enroll(self, mock_build, mock_byte, mock_b64, mock_post, mock_cert_lookup, mock_bundle): + """ test cert_enroll() """ + self.cahandler.wait_interval = 0 + self.cahandler.api_host = 'api_host' + self.cahandler.tsg_info_dic = {'id': 10, 'name': 'name'} + self.cahandler.template_info_dic = {'name': 'name', 'id': 'id'} + mock_post.return_value = {'status': 200, 'message': None} + mock_cert_lookup.return_value = None + self.assertEqual(("certifcate id lookup failed for: cn, ['san']", None, None), self.cahandler._cert_enroll('csr', 'cn', ['san'], 'policylink_id'))# + self.assertTrue(mock_build.called) + self.assertTrue(mock_byte.called) + self.assertTrue(mock_b64.called) + self.assertTrue(mock_cert_lookup.called) + self.assertFalse(mock_bundle.called) + + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_bundle_build') + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._cert_id_lookup') + @patch('examples.ca_handler.nclm_ca_handler.CAhandler._api_post') + @patch('examples.ca_handler.nclm_ca_handler.b64_encode') + @patch('examples.ca_handler.nclm_ca_handler.convert_string_to_byte') + @patch('examples.ca_handler.nclm_ca_handler.build_pem_file') + def test_135_cert_enroll(self, mock_build, mock_byte, mock_b64, mock_post, mock_cert_lookup, mock_bundle): + """ test cert_enroll() """ + self.cahandler.wait_interval = 0 + self.cahandler.api_host = 'api_host' + self.cahandler.tsg_info_dic = {'id': 10, 'name': 'name'} + self.cahandler.template_info_dic = {'name': 'name', 'id': 'id'} + mock_post.return_value = {'status': 200, 'message': None} mock_cert_lookup.return_value = 10 mock_bundle.return_value = ('error', 'cert_bundle', 'cert_raw') - self.assertEqual(('enrollment aborted. policylink_id: 0, tsg_id: id', None, None, None), self.cahandler.enroll('csr')) - self.assertFalse(mock_tmpl_lookup.called) + self.assertEqual(('error', 'cert_bundle', 'cert_raw'), self.cahandler._cert_enroll('csr', 'cn', ['san'], 'policylink_id'))# + self.assertTrue(mock_build.called) + self.assertTrue(mock_byte.called) + self.assertTrue(mock_b64.called) + self.assertTrue(mock_cert_lookup.called) + self.assertTrue(mock_bundle.called) @patch('requests.get') - def test_131__cert_list_fetch(self, mock_req): + def test_136__cert_list_fetch(self, mock_req): """ _cert_list_fetch() - response without next """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1605,7 +1671,7 @@ def test_131__cert_list_fetch(self, mock_req): self.assertEqual(['foo', 'bar'], self.cahandler._cert_list_fetch('url')) @patch('requests.get') - def test_132__cert_list_fetch(self, mock_req): + def test_137__cert_list_fetch(self, mock_req): """ _cert_list_fetch() - response 1x pagination """ self.cahandler.api_host = 'api_host' mockresponse1 = Mock() @@ -1616,7 +1682,7 @@ def test_132__cert_list_fetch(self, mock_req): self.assertEqual(['foo1', 'bar1', 'foo2', 'bar2'], self.cahandler._cert_list_fetch('url')) @patch('requests.get') - def test_133__cert_list_fetch(self, mock_req): + def test_138__cert_list_fetch(self, mock_req): """ _cert_list_fetch() - response 2x pagination """ self.cahandler.api_host = 'api_host' mockresponse1 = Mock() @@ -1629,7 +1695,7 @@ def test_133__cert_list_fetch(self, mock_req): self.assertEqual(['foo1', 'bar1', 'foo2', 'bar2', 'foo3', 'bar3'], self.cahandler._cert_list_fetch('url')) @patch('requests.get') - def test_134__cert_list_fetch(self, mock_req): + def test_139__cert_list_fetch(self, mock_req): """ _cert_list_fetch() - empty response """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1638,7 +1704,7 @@ def test_134__cert_list_fetch(self, mock_req): self.assertFalse(self.cahandler._cert_list_fetch('url')) @patch('requests.get') - def test_135__cert_list_fetch(self, mock_req): + def test_140__cert_list_fetch(self, mock_req): """ _cert_list_fetch() - request.get triggers execption """ self.cahandler.api_host = 'api_host' mock_req.side_effect = Exception('foo') @@ -1647,7 +1713,7 @@ def test_135__cert_list_fetch(self, mock_req): self.assertIn('ERROR:test_a2c:CAhandler._cert_list_fetch() returned error: foo', lcm.output) @patch('requests.get') - def test_136__lastrequests_get(self, mock_req): + def test_141__lastrequests_get(self, mock_req): """ test_132__lastrequests_get() - all ok """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1656,7 +1722,7 @@ def test_136__lastrequests_get(self, mock_req): self.assertEqual(['foo', 'bar', 'foo', 'bar'], self.cahandler._lastrequests_get()) @patch('requests.get') - def test_137__lastrequests_get(self, mock_req): + def test_142__lastrequests_get(self, mock_req): """ test_132__lastrequests_get() - all ok """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1665,7 +1731,7 @@ def test_137__lastrequests_get(self, mock_req): self.assertEqual(['foo', 'bar', 'foo', 'bar'], self.cahandler._lastrequests_get()) @patch('requests.get') - def test_138__lastrequests_get(self, mock_req): + def test_143__lastrequests_get(self, mock_req): """ test_132__lastrequests_get() - no request list in response """ self.cahandler.api_host = 'api_host' mockresponse = Mock() @@ -1676,7 +1742,7 @@ def test_138__lastrequests_get(self, mock_req): self.assertIn('ERROR:test_a2c:_lastrequests_get(): response incomplete:', lcm.output) @patch('requests.get') - def test_139__cert_list_fetch(self, mock_req): + def test_144__cert_list_fetch(self, mock_req): """ _cert_list_fetch() - request.get triggers execption """ self.cahandler.api_host = 'api_host' mock_req.side_effect = Exception('foo') @@ -1684,33 +1750,33 @@ def test_139__cert_list_fetch(self, mock_req): self.assertFalse(self.cahandler._lastrequests_get()) self.assertIn('ERROR:test_a2c:CAhandler._lastrequests_get() returned error: foo', lcm.output) - def test_140__ca_id_get(self): + def test_145__ca_id_get(self): """ test _ca_id_get() """ ca_list = {} self.assertFalse(self.cahandler._ca_id_get(ca_list)) - def test_141__ca_id_get(self): + def test_146__ca_id_get(self): """ test _ca_id_get() """ ca_list = {'ca': {'foo': 'bar'}} self.assertFalse(self.cahandler._ca_id_get(ca_list)) - def test_142__ca_id_get(self): + def test_147__ca_id_get(self): """ test _ca_id_get() """ ca_list = {'ca': {'items': 'bar'}} self.assertFalse(self.cahandler._ca_id_get(ca_list)) - def test_143__ca_id_get(self): + def test_148__ca_id_get(self): """ test _ca_id_get() """ ca_list = {'ca': {'items': [{'foo': 'bar'}]}} self.assertFalse(self.cahandler._ca_id_get(ca_list)) - def test_144__ca_id_get(self): + def test_149__ca_id_get(self): """ test _ca_id_get() """ self.cahandler.ca_name = 'ca_name' ca_list = {'ca': {'items': [{'displayName': 'ca_name', 'policyLinkId': 'id'}]}} self.assertEqual('id', self.cahandler._ca_id_get(ca_list)) - def test_145__ca_id_get(self): + def test_150__ca_id_get(self): """ test _ca_id_get() """ self.cahandler.ca_name = 'ca_name' ca_list = {'ca': {'items': [{'displayName': 'ca_name', 'foo': 'id'}]}} @@ -1718,7 +1784,7 @@ def test_145__ca_id_get(self): self.assertFalse(self.cahandler._ca_id_get(ca_list)) self.assertIn('ERROR:test_a2c:ca_id.lookup() policyLinkId field is missing ...', lcm.output) - def test_146__ca_id_get(self): + def test_151__ca_id_get(self): """ test _ca_id_get() """ self.cahandler.ca_name = 'ca_name1' ca_list = {'ca': {'items': [{'displayName': 'ca_name', 'policyLinkId': 'id'}]}} @@ -1726,7 +1792,7 @@ def test_146__ca_id_get(self): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._ca_id_get') @patch('requests.get') - def test_147__ca_policylink_id_lookup(self, mock_req, mock_caid): + def test_152__ca_policylink_id_lookup(self, mock_req, mock_caid): """ test _ca_policylink_id_lookup() """ self.cahandler.api_host = 'api_host' self.cahandler.tsg_info_dic = {'id': 'id'} @@ -1739,7 +1805,7 @@ def test_147__ca_policylink_id_lookup(self, mock_req, mock_caid): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._ca_id_get') @patch('requests.get') - def test_148__ca_policylink_id_lookup(self, mock_req, mock_caid): + def test_153__ca_policylink_id_lookup(self, mock_req, mock_caid): """ test _ca_policylink_id_lookup() """ self.cahandler.api_host = 'api_host' self.cahandler.tsg_info_dic = {'id': 'id'} @@ -1754,7 +1820,7 @@ def test_148__ca_policylink_id_lookup(self, mock_req, mock_caid): @patch('examples.ca_handler.nclm_ca_handler.CAhandler._ca_id_get') @patch('requests.get') - def test_149__ca_policylink_id_lookup(self, mock_req, mock_caid): + def test_154__ca_policylink_id_lookup(self, mock_req, mock_caid): """ test _ca_policylink_id_lookup() """ self.cahandler.api_host = 'api_host' self.cahandler.tsg_info_dic = {'id': 'id'} diff --git a/test/test_openssl_ca_handler.py b/test/test_openssl_ca_handler.py index 5b3d809b..7c4632e4 100644 --- a/test/test_openssl_ca_handler.py +++ b/test/test_openssl_ca_handler.py @@ -1016,7 +1016,7 @@ def test_118__cert_extension_dic_parse(self, mock_bc, mock_ski, mock_aki, mock_ mock_ku.return_value = 'mock_ku' mock_eku.return_value = 'mock_eku' cert_extension_dic = {'subjectKeyIdentifier': {'critical': True, 'value': 'value'}} - result = [{'critical': True, 'name': 'mock_ski'}] + result = [{'critical': False, 'name': 'mock_ski'}] with self.assertLogs('test_a2c', level='INFO') as lcm: self.assertEqual(result, self.cahandler._cert_extension_dic_parse(cert_extension_dic, cert, cert)) self.assertIn('INFO:test_a2c:CAhandler.cert_extesion_dic_parse(): subjectKeyIdentifier', lcm.output) diff --git a/tools/entrust_mgr.py b/tools/entrust_mgr.py new file mode 100644 index 00000000..8feb358e --- /dev/null +++ b/tools/entrust_mgr.py @@ -0,0 +1,65 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +""" entrust manager """ +from __future__ import print_function +import sys +import os +import argparse +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir))) +sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, os.path.pardir))) +# pylint: disable=E0401, E0611, C0209, C0413 +from acme_srv.helper import logger_setup # nopep8 +from examples.ca_handler.entrust_ca_handler import CAhandler # nopep8 + + +def arg_parse(): + """ simple argparser """ + + parser = argparse.ArgumentParser(description='enturst_mgr.py - a simple enturst certificate mananger') + parser.add_argument('-d', '--debug', help='debug mode', action="store_true", default=False) + parser.add_argument('-p', '--pagination', help='amout of certificates to be fetch with a single rest-call', default=200) + parser.add_argument('-s', '--sortby', help='sortby fieldname [trackigId, status, serialNumber, expiresAfter]', default='trackingId') + clist = parser.add_mutually_exclusive_group() + clist.add_argument('-a', '--filteractive', help='filter output to active accounts', action="store_true", default=False) + clist.add_argument('-r', '--revoke', help='revoke ', default=None) + + args = parser.parse_args() + + debug = args.debug + config_dic = { + 'debug': args.debug, + 'filteractive': args.filteractive, + 'revoke': args.revoke, + 'pagination': int(args.pagination), + 'sortby': args.sortby + } + return (debug, config_dic) + + +if __name__ == '__main__': + + DEBUG, CONFIG_DIC = arg_parse() + + # initialize logger + LOGGER = logger_setup(DEBUG) + + with CAhandler(logger=LOGGER) as ca_handler: + result = ca_handler.credential_check() + if not result: + + if CONFIG_DIC['revoke']: + print("Revoking certificate with transaction_id: ", CONFIG_DIC['revoke']) + CODE, CONTENT = ca_handler.revoke_by_trackingid(CONFIG_DIC['revoke']) + if CODE == 200: + print("Revocation successful") + else: + print(f"Revocation failed with error: {CONTENT}") + else: + # get list of certificates + cert_list = ca_handler.certificates_get(limit=CONFIG_DIC['pagination']) + for cert in sorted(cert_list, key=lambda k: k[CONFIG_DIC['sortby']]): + if (CONFIG_DIC['filteractive'] and cert['status'] == 'ACTIVE') or not CONFIG_DIC['filteractive']: + print(cert) + else: + print("Credential check failed: ", result) + sys.exit(1)