From bc16ccaef7075ecb057f6df943ceece5467083b9 Mon Sep 17 00:00:00 2001
From: Rafael Guterres Jeffman <rjeffman@redhat.com>
Date: Thu, 5 Dec 2024 15:33:30 -0300
Subject: [PATCH] ipacert: Revoking with  removeFromCRL should be handled as
 cert release

When a revoked certificate with reason 6 (certificateHold) is revoked
with reason 8 (removeFromCRL), the effect is that the certificate is
valid again, as it is the same procedure as 'state: release'.

This is, at least, the behavior with IPA CLI comands, which is
implemented by this patch.

A new test is added to verify this behavior:

    tests/cert/test_cert_remove_hold_with_removeFromCRL.yml
---
 plugins/modules/ipacert.py                    |  5 ++
 ...st_cert_remove_hold_with_removeFromCRL.yml | 65 +++++++++++++++++++
 2 files changed, 70 insertions(+)
 create mode 100644 tests/cert/test_cert_remove_hold_with_removeFromCRL.yml

diff --git a/plugins/modules/ipacert.py b/plugins/modules/ipacert.py
index 6c9b760..2aebc76 100644
--- a/plugins/modules/ipacert.py
+++ b/plugins/modules/ipacert.py
@@ -487,6 +487,8 @@ def main():
 
     # revoked
     reason = ansible_module.params_get("revocation_reason")
+    if reason is not None:
+        reason = get_revocation_reason(ansible_module, reason)
 
     # general
     serial_number = ansible_module.params.get("serial_number")
@@ -521,6 +523,9 @@ def main():
             invalid.append("revocation_reason")
         if state == "revoked":
             invalid.extend(["certificate_out", "chain"])
+            # Reason 8 (revomeFromCRL) is the same as release hold
+            if reason == 8:
+                state = "released"
         elif state == "held":
             reason = 6  # certificateHold
 
diff --git a/tests/cert/test_cert_remove_hold_with_removeFromCRL.yml b/tests/cert/test_cert_remove_hold_with_removeFromCRL.yml
new file mode 100644
index 0000000..3d2b087
--- /dev/null
+++ b/tests/cert/test_cert_remove_hold_with_removeFromCRL.yml
@@ -0,0 +1,65 @@
+---
+- name: Test remove certificate hold by removing it from CRL.
+  hosts: ipaserver
+  become: false
+  gather_facts: false
+  module_defaults:
+    ipauser:
+      ipaadmin_password: SomeADMINpassword
+    ipacert:
+      ipaadmin_password: SomeADMINpassword
+
+  tasks:
+  - name: Ensure test users are present
+    ipauser:
+      name: testuser
+      first: test
+      last: user
+
+  - name: Create user certificae CSR
+    ansible.builtin.shell:
+      cmd: |-
+        openssl req -newkey rsa:2048 -keyout /dev/null -nodes \
+        -subj /CN=testuser -reqexts IECUserRoles -config \
+            <(cat /etc/pki/tls/openssl.cnf; \
+              printf "[IECUserRoles]\n1.2.3.10.9.8=ASN1:UTF8String:Testing Cert")
+    args:
+      executable: /bin/bash
+    register: user_csr
+
+  - name: Request certificate with ipacert
+    ipacert:
+      csr: '{{ user_csr.stdout }}'
+      principal: testuser
+      state: requested
+    register: user_csr
+    failed_when: not user_csr.changed or user_csr.failed
+
+  - name: Revoke certifice with reason 6 (certificateHold)
+    ipacert:
+      serial_number: "{{ user_csr.certificate.serial_number }}"
+      revocation_reason: certificateHold
+      state: revoked
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Revoke certificate with reason 8 (removeFromCRL)
+    ipacert:
+      serial_number: "{{ user_csr.certificate.serial_number }}"
+      revocation_reason: removeFromCRL
+      state: revoked
+    register: result
+    failed_when: not result.changed or result.failed
+
+  - name: Revoke certificate with reason 8 (removeFromCRL), again
+    ipacert:
+      serial_number: "{{ user_csr.certificate.serial_number }}"
+      revocation_reason: removeFromCRL
+      state: revoked
+    register: result
+    failed_when: result.changed or result.failed
+
+  - name: Ensure test users are absent
+    ipauser:
+      name: testuser
+      state: absent
-- 
GitLab