1871d3
Addtional patches that need to be partly reverted that are touching csrgen
1871d3
related files:
1871d3
1871d3
7b8a2af2197381058ca532d1ae206defb16fac88
1871d3
ac6568dcf58ec8d06df5493d14a28aa41845d4ef
1871d3
9c86d35a3f0af4a793fada7dfe726e9cc66782ea
1871d3
9836511a2b6d7cf48b1a54cb3158e5eac674081a
1871d3
b431e9b684df11c811892bd9d2a5711355f0076e
1871d3
1871d3
This is a collection of an existing patch to remove csrgen for 4.7.1 and
1871d3
additional patches that have been added for 4.7.90 pre1.
1871d3
1871d3
Additional reverted csrgen patches:
1871d3
1871d3
852618fd6529fbdd7b03077fae37c6fbbe45b51b
1871d3
0ac1d3ea62efd9751fcc59cea46bcdafe1f11c37
1871d3
7633d62d858c14523a99143aa0ff36f76bb4ff68
1871d3
53f87ee5cd9d19f6fb91a9a1eafc8ea798095954
1871d3
395a68d20887d0ac010e480e68b225d6dfeff726
1871d3
03786ad9f3bd5edc351040847b8a49c9cd9288b2
1871d3
c9d710a446d10aad72795e15bf041b87102628c1
1871d3
2b90c8a20e45ade9bfd27731cccc94a34cf3f61e
1871d3
61dde27f70b9f8dd1b57ad1fbc3744f3c380613a
1871d3
806784dbd9e69a89c7a705c89bf42ba1fd4265c9
1871d3
79378c90512a1cdd5f3d5ec6482e434caea06e01
1871d3
bd5a5012d24820b54cdca2955f5405b84de1178c
1871d3
26ab51ddf47f421f3404709052db89f08c05adaa
1871d3
a53e17830c3d4fd59a62248d4447491675c6a80e
1871d3
e7588ab2dc73e7f66ebc6cdcfb99470540e37731
1871d3
136c6c3e2a4f77a27f435efd4a1cd95c9e089314
1871d3
5420e9cfbe7803808b6e26d2dae64f2a6a50149a
1871d3
1871d3
Original patch from 4.7.1:
1871d3
1871d3
From 468bcf90cb985e2b1eb394bd752dc39aa4b75582 Mon Sep 17 00:00:00 2001
1871d3
From: Rob Crittenden <rcritten@redhat.com>
1871d3
Date: Thu, 19 Jul 2018 18:37:18 -0400
1871d3
Subject: [PATCH] Remove csrgen
1871d3
1871d3
This reverts commits:
1871d3
* 72de679eb445c975ec70cd265d37d4927823ce5b
1871d3
* 177f07e163d6d591a1e609d35e0a6f6f5347551e
1871d3
* 80be18162921268be9c8981495c9e8a4de0c85cd
1871d3
* 83e2c2b65eeb5a3aa4a59c0535e9177aac5e4637
1871d3
* ada91c20588046bb147fc701718d3da4d2c080ca
1871d3
* 4350dcdea22fd2284836315d0ae7d38733a7620e
1871d3
* 39a5d9c5aae77687f67d9be02457733bdfb99ead
1871d3
* a26cf0d7910dd4c0a4da08682b4be8d3d94ba520
1871d3
* afd7c05d11432304bfdf183832a21d419f363689
1871d3
* f1a1c6eca1b294f24174d7b0e1f78de46d9d5b05
1871d3
* fc58eff6a3d7fe805e612b8b002304d8b9cd4ba9
1871d3
* 10ef5947860f5098182b1f95c08c1158e2da15f9
1871d3
1871d3
https://bugzilla.redhat.com/show_bug.cgi?id=1432630
1871d3
---
1871d3
 freeipa.spec.in                                    |  14 -
1871d3
 ipaclient/csrgen.py                                | 488 ---------------------
1871d3
 ipaclient/csrgen/profiles/caIPAserviceCert.json    |  15 -
1871d3
 ipaclient/csrgen/profiles/userCert.json            |  15 -
1871d3
 ipaclient/csrgen/rules/dataDNS.json                |   8 -
1871d3
 ipaclient/csrgen/rules/dataEmail.json              |   8 -
1871d3
 ipaclient/csrgen/rules/dataHostCN.json             |   8 -
1871d3
 ipaclient/csrgen/rules/dataSubjectBase.json        |   8 -
1871d3
 ipaclient/csrgen/rules/dataUsernameCN.json         |   8 -
1871d3
 ipaclient/csrgen/rules/syntaxSAN.json              |   8 -
1871d3
 ipaclient/csrgen/rules/syntaxSubject.json          |   9 -
1871d3
 ipaclient/csrgen/templates/openssl_base.tmpl       |  17 -
1871d3
 ipaclient/csrgen/templates/openssl_macros.tmpl     |  29 --
1871d3
 ipaclient/csrgen_ffi.py                            | 331 --------------
1871d3
 ipaclient/plugins/cert.py                          |  80 ----
1871d3
 ipaclient/plugins/csrgen.py                        | 128 ------
1871d3
 ipaclient/setup.py                                 |   8 -
1871d3
 .../data/test_csrgen/configs/caIPAserviceCert.conf |  16 -
1871d3
 .../data/test_csrgen/configs/userCert.conf         |  16 -
1871d3
 .../data/test_csrgen/profiles/profile.json         |   8 -
1871d3
 .../data/test_csrgen/rules/basic.json              |   5 -
1871d3
 .../data/test_csrgen/rules/options.json            |   8 -
1871d3
 .../data/test_csrgen/templates/identity_base.tmpl  |   1 -
1871d3
 ipatests/test_ipaclient/test_csrgen.py             | 304 -------------
1871d3
 24 files changed, 1540 deletions(-)
1871d3
 delete mode 100644 ipaclient/csrgen.py
1871d3
 delete mode 100644 ipaclient/csrgen/profiles/caIPAserviceCert.json
1871d3
 delete mode 100644 ipaclient/csrgen/profiles/userCert.json
1871d3
 delete mode 100644 ipaclient/csrgen/rules/dataDNS.json
1871d3
 delete mode 100644 ipaclient/csrgen/rules/dataEmail.json
1871d3
 delete mode 100644 ipaclient/csrgen/rules/dataHostCN.json
1871d3
 delete mode 100644 ipaclient/csrgen/rules/dataSubjectBase.json
1871d3
 delete mode 100644 ipaclient/csrgen/rules/dataUsernameCN.json
1871d3
 delete mode 100644 ipaclient/csrgen/rules/syntaxSAN.json
1871d3
 delete mode 100644 ipaclient/csrgen/rules/syntaxSubject.json
1871d3
 delete mode 100644 ipaclient/csrgen/templates/openssl_base.tmpl
1871d3
 delete mode 100644 ipaclient/csrgen/templates/openssl_macros.tmpl
1871d3
 delete mode 100644 ipaclient/csrgen_ffi.py
1871d3
 delete mode 100644 ipaclient/plugins/csrgen.py
1871d3
 delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/configs/caIPAserviceCert.conf
1871d3
 delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/configs/userCert.conf
1871d3
 delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/profiles/profile.json
1871d3
 delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/rules/basic.json
1871d3
 delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/rules/options.json
1871d3
 delete mode 100644 ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl
1871d3
 delete mode 100644 ipatests/test_ipaclient/test_csrgen.py
1871d3
1871d3
diff -urN freeipa-4.8.0/freeipa.spec.in freeipa-4.8.0.removed_csrgen/freeipa.spec.in
1871d3
--- freeipa-4.8.0/freeipa.spec.in	2019-06-29 10:01:30.458735813 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/freeipa.spec.in	2019-07-03 13:24:38.471222723 +0200
1871d3
@@ -1247,13 +1247,6 @@
1871d3
 %dir %{python3_sitelib}/ipaclient/remote_plugins/2_*
1871d3
 %{python3_sitelib}/ipaclient/remote_plugins/2_*/*.py
1871d3
 %{python3_sitelib}/ipaclient/remote_plugins/2_*/__pycache__/*.py*
1871d3
-%dir %{python3_sitelib}/ipaclient/csrgen
1871d3
-%dir %{python3_sitelib}/ipaclient/csrgen/profiles
1871d3
-%{python3_sitelib}/ipaclient/csrgen/profiles/*.json
1871d3
-%dir %{python3_sitelib}/ipaclient/csrgen/rules
1871d3
-%{python3_sitelib}/ipaclient/csrgen/rules/*.json
1871d3
-%dir %{python3_sitelib}/ipaclient/csrgen/templates
1871d3
-%{python3_sitelib}/ipaclient/csrgen/templates/*.tmpl
1871d3
 %{python3_sitelib}/ipaclient-*.egg-info
1871d3
 
1871d3
 
1871d3
diff -urN freeipa-4.8.0/ipaclient/csrgen/profiles/caIPAserviceCert.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/profiles/caIPAserviceCert.json
1871d3
--- freeipa-4.8.0/ipaclient/csrgen/profiles/caIPAserviceCert.json	2019-07-03 08:42:41.844539797 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/profiles/caIPAserviceCert.json	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,15 +0,0 @@
1871d3
-[
1871d3
-    {
1871d3
-        "syntax": "syntaxSubject",
1871d3
-        "data": [
1871d3
-            "dataHostCN",
1871d3
-            "dataSubjectBase"
1871d3
-        ]
1871d3
-    },
1871d3
-    {
1871d3
-        "syntax": "syntaxSAN",
1871d3
-        "data": [
1871d3
-            "dataDNS"
1871d3
-        ]
1871d3
-    }
1871d3
-]
1871d3
diff -urN freeipa-4.8.0/ipaclient/csrgen/profiles/userCert.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/profiles/userCert.json
1871d3
--- freeipa-4.8.0/ipaclient/csrgen/profiles/userCert.json	2019-07-03 08:42:41.848539737 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/profiles/userCert.json	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,15 +0,0 @@
1871d3
-[
1871d3
-    {
1871d3
-        "syntax": "syntaxSubject",
1871d3
-        "data": [
1871d3
-            "dataUsernameCN",
1871d3
-            "dataSubjectBase"
1871d3
-        ]
1871d3
-    },
1871d3
-    {
1871d3
-        "syntax": "syntaxSAN",
1871d3
-        "data": [
1871d3
-            "dataEmail"
1871d3
-        ]
1871d3
-    }
1871d3
-]
1871d3
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/dataDNS.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataDNS.json
1871d3
--- freeipa-4.8.0/ipaclient/csrgen/rules/dataDNS.json	2019-07-03 08:42:41.853539663 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataDNS.json	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,8 +0,0 @@
1871d3
-{
1871d3
-  "rule": {
1871d3
-    "template": "DNS = {{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]}}"
1871d3
-  },
1871d3
-  "options": {
1871d3
-    "data_source": "subject.krbprincipalname.0.partition('/')[2].partition('@')[0]"
1871d3
-  }
1871d3
-}
1871d3
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/dataEmail.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataEmail.json
1871d3
--- freeipa-4.8.0/ipaclient/csrgen/rules/dataEmail.json	2019-07-03 08:42:41.857539603 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataEmail.json	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,8 +0,0 @@
1871d3
-{
1871d3
-  "rule": {
1871d3
-    "template": "email = {{subject.mail.0}}"
1871d3
-  },
1871d3
-  "options": {
1871d3
-    "data_source": "subject.mail.0"
1871d3
-  }
1871d3
-}
1871d3
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/dataHostCN.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataHostCN.json
1871d3
--- freeipa-4.8.0/ipaclient/csrgen/rules/dataHostCN.json	2019-07-03 08:42:41.861539544 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataHostCN.json	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,8 +0,0 @@
1871d3
-{
1871d3
-  "rule": {
1871d3
-    "template": "CN={{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]}}"
1871d3
-  },
1871d3
-  "options": {
1871d3
-    "data_source": "subject.krbprincipalname.0.partition('/')[2].partition('@')[0]"
1871d3
-  }
1871d3
-}
1871d3
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/dataSubjectBase.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataSubjectBase.json
1871d3
--- freeipa-4.8.0/ipaclient/csrgen/rules/dataSubjectBase.json	2019-07-03 08:42:41.865539484 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataSubjectBase.json	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,8 +0,0 @@
1871d3
-{
1871d3
-  "rule": {
1871d3
-    "template": "{{config.ipacertificatesubjectbase.0}}"
1871d3
-  },
1871d3
-  "options": {
1871d3
-    "data_source": "config.ipacertificatesubjectbase.0"
1871d3
-  }
1871d3
-}
1871d3
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/dataUsernameCN.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataUsernameCN.json
1871d3
--- freeipa-4.8.0/ipaclient/csrgen/rules/dataUsernameCN.json	2019-07-03 08:42:41.869539424 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/dataUsernameCN.json	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,8 +0,0 @@
1871d3
-{
1871d3
-  "rule": {
1871d3
-    "template": "CN={{subject.uid.0}}"
1871d3
-  },
1871d3
-  "options": {
1871d3
-    "data_source": "subject.uid.0"
1871d3
-  }
1871d3
-}
1871d3
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/syntaxSAN.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/syntaxSAN.json
1871d3
--- freeipa-4.8.0/ipaclient/csrgen/rules/syntaxSAN.json	2019-07-03 08:42:41.874539350 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/syntaxSAN.json	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,8 +0,0 @@
1871d3
-{
1871d3
-  "rule": {
1871d3
-    "template": "subjectAltName = @{% call openssl.section() %}{{ datarules|join('\n') }}{% endcall %}"
1871d3
-  },
1871d3
-  "options": {
1871d3
-    "extension": true
1871d3
-  }
1871d3
-}
1871d3
diff -urN freeipa-4.8.0/ipaclient/csrgen/rules/syntaxSubject.json freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/syntaxSubject.json
1871d3
--- freeipa-4.8.0/ipaclient/csrgen/rules/syntaxSubject.json	2019-07-03 08:42:41.878539290 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/rules/syntaxSubject.json	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,9 +0,0 @@
1871d3
-{
1871d3
-  "rule": {
1871d3
-    "template": "distinguished_name = {% call openssl.section() %}{{ datarules|reverse|join('\n') }}{% endcall %}"
1871d3
-  },
1871d3
-  "options": {
1871d3
-    "required": true,
1871d3
-    "data_source_combinator": "and"
1871d3
-  }
1871d3
-}
1871d3
diff -urN freeipa-4.8.0/ipaclient/csrgen/templates/openssl_base.tmpl freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/templates/openssl_base.tmpl
1871d3
--- freeipa-4.8.0/ipaclient/csrgen/templates/openssl_base.tmpl	2019-07-03 08:42:41.882539231 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/templates/openssl_base.tmpl	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,17 +0,0 @@
1871d3
-{% raw -%}
1871d3
-{% import "openssl_macros.tmpl" as openssl -%}
1871d3
-{% endraw -%}
1871d3
-[ req ]
1871d3
-prompt = no
1871d3
-encrypt_key = no
1871d3
-
1871d3
-{{ parameters|join('\n') }}
1871d3
-{% raw %}{% set rendered_extensions -%}{% endraw %}
1871d3
-{{ extensions|join('\n') }}
1871d3
-{% raw -%}
1871d3
-{%- endset -%}
1871d3
-{% if rendered_extensions -%}
1871d3
-req_extensions = {% call openssl.section() %}{{ rendered_extensions }}{% endcall %}
1871d3
-{% endif %}
1871d3
-{{ openssl.openssl_sections|join('\n\n') }}
1871d3
-{%- endraw %}
1871d3
diff -urN freeipa-4.8.0/ipaclient/csrgen/templates/openssl_macros.tmpl freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/templates/openssl_macros.tmpl
1871d3
--- freeipa-4.8.0/ipaclient/csrgen/templates/openssl_macros.tmpl	2019-07-03 08:42:41.886539171 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen/templates/openssl_macros.tmpl	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,29 +0,0 @@
1871d3
-{# List containing rendered sections to be included at end #}
1871d3
-{% set openssl_sections = [] %}
1871d3
-
1871d3
-{#
1871d3
-List containing one entry for each section name allocated. Because of
1871d3
-scoping rules, we need to use a list so that it can be a "per-render global"
1871d3
-that gets updated in place. Real globals are shared by all templates with the
1871d3
-same environment, and variables defined in the macro don't persist after the
1871d3
-macro invocation ends.
1871d3
-#}
1871d3
-{% set openssl_section_num = [] %}
1871d3
-
1871d3
-{% macro section() -%}
1871d3
-{% set name -%}
1871d3
-sec{{ openssl_section_num|length -}}
1871d3
-{% endset -%}
1871d3
-{% do openssl_section_num.append('') -%}
1871d3
-{% set contents %}{{ caller() }}{% endset -%}
1871d3
-{% if contents -%}
1871d3
-{% set sectiondata = formatsection(name, contents) -%}
1871d3
-{% do openssl_sections.append(sectiondata) -%}
1871d3
-{% endif -%}
1871d3
-{{ name -}}
1871d3
-{% endmacro %}
1871d3
-
1871d3
-{% macro formatsection(name, contents) -%}
1871d3
-[ {{ name }} ]
1871d3
-{{ contents -}}
1871d3
-{% endmacro %}
1871d3
diff -urN freeipa-4.8.0/ipaclient/csrgen_ffi.py freeipa-4.8.0.removed_csrgen/ipaclient/csrgen_ffi.py
1871d3
--- freeipa-4.8.0/ipaclient/csrgen_ffi.py	2019-07-03 08:42:41.816540214 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen_ffi.py	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,387 +0,0 @@
1871d3
-from cffi import FFI
1871d3
-import ctypes.util
1871d3
-
1871d3
-from ipalib import errors
1871d3
-
1871d3
-_ffi = FFI()
1871d3
-
1871d3
-_ffi.cdef('''
1871d3
-/* libcrypto/crypto.h */
1871d3
-unsigned long OpenSSL_version_num(void);
1871d3
-unsigned long SSLeay(void);
1871d3
-const char * OpenSSL_version(int t);
1871d3
-const char * SSLeay_version(int t);
1871d3
-
1871d3
-#define OPENSSL_VERSION 0
1871d3
-''')
1871d3
-
1871d3
-_libcrypto = _ffi.dlopen(ctypes.util.find_library('crypto'))
1871d3
-
1871d3
-# SSLeay_version has been renamed with OpenSSL_version in OpenSSL 1.1.0
1871d3
-# LibreSSL has OpenSSL_version since 2.7.0
1871d3
-try:
1871d3
-    OpenSSL_version = _libcrypto.OpenSSL_version
1871d3
-except AttributeError:
1871d3
-    OpenSSL_version = _libcrypto.SSLeay_version
1871d3
-
1871d3
-_version = OpenSSL_version(_libcrypto.OPENSSL_VERSION)
1871d3
-_version = _ffi.string(_version).decode('utf-8')
1871d3
-LIBRESSL = _version.startswith('LibreSSL')
1871d3
-if not _version.startswith("OpenSSL") and not LIBRESSL:
1871d3
-    raise ImportError("Only LibreSSL and OpenSSL are supported")
1871d3
-
1871d3
-# SSLeay has been renamed with OpenSSL_version_num in OpenSSL 1.1.0
1871d3
-# LibreSSL has OpenSSL_version_num since 2.7.0
1871d3
-try:
1871d3
-    OpenSSL_version_num = _libcrypto.OpenSSL_version_num
1871d3
-except AttributeError:
1871d3
-    OpenSSL_version_num = _libcrypto.SSLeay
1871d3
-
1871d3
-# OpenSSL_version_num()/SSLeay() returns the value of OPENSSL_VERSION_NUMBER
1871d3
-#
1871d3
-# OPENSSL_VERSION_NUMBER is a numeric release version identifier:
1871d3
-# MNNFFPPS: major minor fix patch status
1871d3
-# For example,
1871d3
-# 0x000906000 == 0.9.6 dev
1871d3
-# 0x000906023 == 0.9.6b beta 3
1871d3
-# 0x00090605f == 0.9.6e release
1871d3
-_openssl_version = OpenSSL_version_num()
1871d3
-
1871d3
-_ffi.cdef('''
1871d3
-typedef ... CONF;
1871d3
-typedef ... CONF_METHOD;
1871d3
-typedef ... BIO;
1871d3
-typedef ... ipa_STACK_OF_CONF_VALUE;
1871d3
-
1871d3
-/* openssl/conf.h */
1871d3
-typedef struct {
1871d3
-    char *section;
1871d3
-    char *name;
1871d3
-    char *value;
1871d3
-} CONF_VALUE;
1871d3
-
1871d3
-CONF *NCONF_new(CONF_METHOD *meth);
1871d3
-void NCONF_free(CONF *conf);
1871d3
-int NCONF_load_bio(CONF *conf, BIO *bp, long *eline);
1871d3
-ipa_STACK_OF_CONF_VALUE *NCONF_get_section(const CONF *conf,
1871d3
-                                        const char *section);
1871d3
-char *NCONF_get_string(const CONF *conf, const char *group, const char *name);
1871d3
-
1871d3
-/* openssl/safestack.h */
1871d3
-// int sk_CONF_VALUE_num(ipa_STACK_OF_CONF_VALUE *);
1871d3
-// CONF_VALUE *sk_CONF_VALUE_value(ipa_STACK_OF_CONF_VALUE *, int);
1871d3
-
1871d3
-/* openssl/stack.h */
1871d3
-typedef ... _STACK;
1871d3
-
1871d3
-int OPENSSL_sk_num(const _STACK *);
1871d3
-void *OPENSSL_sk_value(const _STACK *, int);
1871d3
-
1871d3
-int sk_num(const _STACK *);
1871d3
-void *sk_value(const _STACK *, int);
1871d3
-
1871d3
-/* openssl/bio.h */
1871d3
-BIO *BIO_new_mem_buf(const void *buf, int len);
1871d3
-int BIO_free(BIO *a);
1871d3
-
1871d3
-/* openssl/asn1.h */
1871d3
-typedef struct ASN1_ENCODING_st {
1871d3
-    unsigned char *enc;         /* DER encoding */
1871d3
-    long len;                   /* Length of encoding */
1871d3
-    int modified;               /* set to 1 if 'enc' is invalid */
1871d3
-} ASN1_ENCODING;
1871d3
-
1871d3
-/* openssl/evp.h */
1871d3
-typedef ... EVP_PKEY;
1871d3
-
1871d3
-void EVP_PKEY_free(EVP_PKEY *pkey);
1871d3
-
1871d3
-/* openssl/x509.h */
1871d3
-typedef ... ASN1_INTEGER;
1871d3
-typedef ... ASN1_BIT_STRING;
1871d3
-typedef ... ASN1_OBJECT;
1871d3
-typedef ... X509;
1871d3
-typedef ... X509_CRL;
1871d3
-typedef ... X509_NAME;
1871d3
-typedef ... X509_PUBKEY;
1871d3
-typedef ... ipa_STACK_OF_X509_ATTRIBUTE;
1871d3
-
1871d3
-typedef struct X509_req_info_st {
1871d3
-    ASN1_ENCODING enc;
1871d3
-    ASN1_INTEGER *version;
1871d3
-    X509_NAME *subject;
1871d3
-    X509_PUBKEY *pubkey;
1871d3
-    /*  d=2 hl=2 l=  0 cons: cont: 00 */
1871d3
-    ipa_STACK_OF_X509_ATTRIBUTE *attributes; /* [ 0 ] */
1871d3
-} X509_REQ_INFO;
1871d3
-''')
1871d3
-
1871d3
-# since OpenSSL 1.1.0 req_info field is no longer pointer to X509_REQ_INFO
1871d3
-if _openssl_version >= 0x10100000 and not LIBRESSL:
1871d3
-    _ffi.cdef('''
1871d3
-    typedef struct X509_req_st {
1871d3
-        X509_REQ_INFO req_info;
1871d3
-    } X509_REQ;
1871d3
-    ''')
1871d3
-else:
1871d3
-    _ffi.cdef('''
1871d3
-    typedef struct X509_req_st {
1871d3
-        X509_REQ_INFO *req_info;
1871d3
-    } X509_REQ;
1871d3
-    ''')
1871d3
-
1871d3
-_ffi.cdef('''
1871d3
-X509_REQ *X509_REQ_new(void);
1871d3
-void X509_REQ_free(X509_REQ *);
1871d3
-EVP_PKEY *d2i_PUBKEY_bio(BIO *bp, EVP_PKEY **a);
1871d3
-int X509_REQ_set_pubkey(X509_REQ *x, EVP_PKEY *pkey);
1871d3
-int X509_NAME_add_entry_by_OBJ(X509_NAME *name, const ASN1_OBJECT *obj, int type,
1871d3
-                               const unsigned char *bytes, int len, int loc,
1871d3
-                               int set);
1871d3
-int X509_NAME_entry_count(X509_NAME *name);
1871d3
-int i2d_X509_REQ_INFO(X509_REQ_INFO *a, unsigned char **out);
1871d3
-
1871d3
-/* openssl/objects.h */
1871d3
-ASN1_OBJECT *OBJ_txt2obj(const char *s, int no_name);
1871d3
-
1871d3
-/* openssl/x509v3.h */
1871d3
-typedef ... X509V3_CONF_METHOD;
1871d3
-
1871d3
-typedef struct v3_ext_ctx {
1871d3
-    int flags;
1871d3
-    X509 *issuer_cert;
1871d3
-    X509 *subject_cert;
1871d3
-    X509_REQ *subject_req;
1871d3
-    X509_CRL *crl;
1871d3
-    X509V3_CONF_METHOD *db_meth;
1871d3
-    void *db;
1871d3
-} X509V3_CTX;
1871d3
-
1871d3
-void X509V3_set_ctx(X509V3_CTX *ctx, X509 *issuer, X509 *subject,
1871d3
-                    X509_REQ *req, X509_CRL *crl, int flags);
1871d3
-void X509V3_set_nconf(X509V3_CTX *ctx, CONF *conf);
1871d3
-int X509V3_EXT_REQ_add_nconf(CONF *conf, X509V3_CTX *ctx, char *section,
1871d3
-                             X509_REQ *req);
1871d3
-
1871d3
-/* openssl/x509v3.h */
1871d3
-unsigned long ERR_get_error(void);
1871d3
-char *ERR_error_string(unsigned long e, char *buf);
1871d3
-''')  # noqa: E501
1871d3
-
1871d3
-NULL = _ffi.NULL
1871d3
-# openssl/conf.h
1871d3
-NCONF_new = _libcrypto.NCONF_new
1871d3
-NCONF_free = _libcrypto.NCONF_free
1871d3
-NCONF_load_bio = _libcrypto.NCONF_load_bio
1871d3
-NCONF_get_section = _libcrypto.NCONF_get_section
1871d3
-NCONF_get_string = _libcrypto.NCONF_get_string
1871d3
-
1871d3
-# openssl/stack.h
1871d3
-try:
1871d3
-    sk_num = _libcrypto.OPENSSL_sk_num
1871d3
-    sk_value = _libcrypto.OPENSSL_sk_value
1871d3
-except AttributeError:
1871d3
-    sk_num = _libcrypto.sk_num
1871d3
-    sk_value = _libcrypto.sk_value
1871d3
-
1871d3
-
1871d3
-def sk_CONF_VALUE_num(sk):
1871d3
-    return sk_num(_ffi.cast("_STACK *", sk))
1871d3
-
1871d3
-
1871d3
-def sk_CONF_VALUE_value(sk, i):
1871d3
-    return _ffi.cast("CONF_VALUE *", sk_value(_ffi.cast("_STACK *", sk), i))
1871d3
-
1871d3
-
1871d3
-# openssl/bio.h
1871d3
-BIO_new_mem_buf = _libcrypto.BIO_new_mem_buf
1871d3
-BIO_free = _libcrypto.BIO_free
1871d3
-
1871d3
-# openssl/x509.h
1871d3
-X509_REQ_new = _libcrypto.X509_REQ_new
1871d3
-X509_REQ_free = _libcrypto.X509_REQ_free
1871d3
-X509_REQ_set_pubkey = _libcrypto.X509_REQ_set_pubkey
1871d3
-d2i_PUBKEY_bio = _libcrypto.d2i_PUBKEY_bio
1871d3
-i2d_X509_REQ_INFO = _libcrypto.i2d_X509_REQ_INFO
1871d3
-X509_NAME_add_entry_by_OBJ = _libcrypto.X509_NAME_add_entry_by_OBJ
1871d3
-X509_NAME_entry_count = _libcrypto.X509_NAME_entry_count
1871d3
-
1871d3
-
1871d3
-def X509_REQ_get_subject_name(req):
1871d3
-    return req.req_info.subject
1871d3
-
1871d3
-
1871d3
-# openssl/objects.h
1871d3
-OBJ_txt2obj = _libcrypto.OBJ_txt2obj
1871d3
-
1871d3
-# openssl/evp.h
1871d3
-EVP_PKEY_free = _libcrypto.EVP_PKEY_free
1871d3
-
1871d3
-# openssl/asn1.h
1871d3
-MBSTRING_UTF8 = 0x1000
1871d3
-
1871d3
-# openssl/x509v3.h
1871d3
-X509V3_set_ctx = _libcrypto.X509V3_set_ctx
1871d3
-X509V3_set_nconf = _libcrypto.X509V3_set_nconf
1871d3
-X509V3_EXT_REQ_add_nconf = _libcrypto.X509V3_EXT_REQ_add_nconf
1871d3
-
1871d3
-# openssl/err.h
1871d3
-ERR_get_error = _libcrypto.ERR_get_error
1871d3
-ERR_error_string = _libcrypto.ERR_error_string
1871d3
-
1871d3
-
1871d3
-def _raise_openssl_errors():
1871d3
-    msgs = []
1871d3
-
1871d3
-    code = ERR_get_error()
1871d3
-    while code != 0:
1871d3
-        msg = _ffi.string(ERR_error_string(code, NULL))
1871d3
-        try:
1871d3
-            strmsg = msg.decode('utf-8')
1871d3
-        except UnicodeDecodeError:
1871d3
-            strmsg = repr(msg)
1871d3
-        msgs.append(strmsg)
1871d3
-        code = ERR_get_error()
1871d3
-
1871d3
-    raise errors.CSRTemplateError(reason='\n'.join(msgs))
1871d3
-
1871d3
-
1871d3
-def _parse_dn_section(subj, dn_sk):
1871d3
-    for i in range(sk_CONF_VALUE_num(dn_sk)):
1871d3
-        v = sk_CONF_VALUE_value(dn_sk, i)
1871d3
-        rdn_type = _ffi.string(v.name)
1871d3
-
1871d3
-        # Skip past any leading X. X: X, etc to allow for multiple instances
1871d3
-        for idx, c in enumerate(rdn_type):
1871d3
-            if c in b':,.':
1871d3
-                if idx+1 < len(rdn_type):
1871d3
-                    rdn_type = rdn_type[idx+1:]
1871d3
-                break
1871d3
-        if rdn_type.startswith(b'+'):
1871d3
-            rdn_type = rdn_type[1:]
1871d3
-            mval = -1
1871d3
-        else:
1871d3
-            mval = 0
1871d3
-
1871d3
-        # convert rdn_type to an OID
1871d3
-        #
1871d3
-        # OpenSSL is fussy about the case of the string.  For example,
1871d3
-        # lower-case 'o' (for "organization name") is not recognised.
1871d3
-        # Therefore, try to convert the given string into an OID.  If
1871d3
-        # that fails, convert it upper case and try again.
1871d3
-        #
1871d3
-        oid = OBJ_txt2obj(rdn_type, 0)
1871d3
-        if oid == NULL:
1871d3
-            oid = OBJ_txt2obj(rdn_type.upper(), 0)
1871d3
-        if oid == NULL:
1871d3
-            raise errors.CSRTemplateError(
1871d3
-                reason='unrecognised attribute type: {}'
1871d3
-                .format(rdn_type.decode('utf-8')))
1871d3
-
1871d3
-        if not X509_NAME_add_entry_by_OBJ(
1871d3
-                subj, oid, MBSTRING_UTF8,
1871d3
-                _ffi.cast("unsigned char *", v.value), -1, -1, mval):
1871d3
-            _raise_openssl_errors()
1871d3
-
1871d3
-    if not X509_NAME_entry_count(subj):
1871d3
-        raise errors.CSRTemplateError(
1871d3
-            reason='error, subject in config file is empty')
1871d3
-
1871d3
-
1871d3
-def build_requestinfo(config, public_key_info):
1871d3
-    '''
1871d3
-    Return a cffi buffer containing a DER-encoded CertificationRequestInfo.
1871d3
-
1871d3
-    The returned object implements the buffer protocol.
1871d3
-
1871d3
-    '''
1871d3
-    reqdata = NULL
1871d3
-    req = NULL
1871d3
-    nconf_bio = NULL
1871d3
-    pubkey_bio = NULL
1871d3
-    pubkey = NULL
1871d3
-
1871d3
-    try:
1871d3
-        reqdata = NCONF_new(NULL)
1871d3
-        if reqdata == NULL:
1871d3
-            _raise_openssl_errors()
1871d3
-
1871d3
-        nconf_bio = BIO_new_mem_buf(config, len(config))
1871d3
-        errorline = _ffi.new('long[1]', [-1])
1871d3
-        i = NCONF_load_bio(reqdata, nconf_bio, errorline)
1871d3
-        if i < 0:
1871d3
-            if errorline[0] < 0:
1871d3
-                raise errors.CSRTemplateError(reason="Can't load config file")
1871d3
-            else:
1871d3
-                raise errors.CSRTemplateError(
1871d3
-                    reason='Error on line %d of config file' % errorline[0])
1871d3
-
1871d3
-        dn_sect = NCONF_get_string(reqdata, b'req', b'distinguished_name')
1871d3
-        if dn_sect == NULL:
1871d3
-            raise errors.CSRTemplateError(
1871d3
-                reason='Unable to find "distinguished_name" key in config')
1871d3
-
1871d3
-        dn_sk = NCONF_get_section(reqdata, dn_sect)
1871d3
-        if dn_sk == NULL:
1871d3
-            raise errors.CSRTemplateError(
1871d3
-                reason='Unable to find "%s" section in config' %
1871d3
-                _ffi.string(dn_sect))
1871d3
-
1871d3
-        pubkey_bio = BIO_new_mem_buf(public_key_info, len(public_key_info))
1871d3
-        pubkey = d2i_PUBKEY_bio(pubkey_bio, NULL)
1871d3
-        if pubkey == NULL:
1871d3
-            _raise_openssl_errors()
1871d3
-
1871d3
-        req = X509_REQ_new()
1871d3
-        if req == NULL:
1871d3
-            _raise_openssl_errors()
1871d3
-
1871d3
-        subject = X509_REQ_get_subject_name(req)
1871d3
-
1871d3
-        _parse_dn_section(subject, dn_sk)
1871d3
-
1871d3
-        if not X509_REQ_set_pubkey(req, pubkey):
1871d3
-            _raise_openssl_errors()
1871d3
-
1871d3
-        ext_ctx = _ffi.new("X509V3_CTX[1]")
1871d3
-        X509V3_set_ctx(ext_ctx, NULL, NULL, req, NULL, 0)
1871d3
-        X509V3_set_nconf(ext_ctx, reqdata)
1871d3
-
1871d3
-        extn_section = NCONF_get_string(reqdata, b"req", b"req_extensions")
1871d3
-        if extn_section != NULL:
1871d3
-            if not X509V3_EXT_REQ_add_nconf(
1871d3
-                    reqdata, ext_ctx, extn_section, req):
1871d3
-                _raise_openssl_errors()
1871d3
-
1871d3
-        if _openssl_version < 0x10100000 or LIBRESSL:
1871d3
-            der_len = i2d_X509_REQ_INFO(req.req_info, NULL)
1871d3
-        else:
1871d3
-            req_info = _ffi.new("X509_REQ_INFO *", req.req_info)
1871d3
-            der_len = i2d_X509_REQ_INFO(req_info, NULL)
1871d3
-            req.req_info = req_info[0]
1871d3
-        if der_len < 0:
1871d3
-            _raise_openssl_errors()
1871d3
-
1871d3
-        der_buf = _ffi.new("unsigned char[%d]" % der_len)
1871d3
-        der_out = _ffi.new("unsigned char **", der_buf)
1871d3
-        if _openssl_version < 0x10100000 or LIBRESSL:
1871d3
-            der_len = i2d_X509_REQ_INFO(req.req_info, der_out)
1871d3
-        else:
1871d3
-            der_len = i2d_X509_REQ_INFO(req_info, der_out)
1871d3
-            req.req_info = req_info[0]
1871d3
-        if der_len < 0:
1871d3
-            _raise_openssl_errors()
1871d3
-
1871d3
-        return _ffi.buffer(der_buf, der_len)
1871d3
-
1871d3
-    finally:
1871d3
-        if reqdata != NULL:
1871d3
-            NCONF_free(reqdata)
1871d3
-        if req != NULL:
1871d3
-            X509_REQ_free(req)
1871d3
-        if nconf_bio != NULL:
1871d3
-            BIO_free(nconf_bio)
1871d3
-        if pubkey_bio != NULL:
1871d3
-            BIO_free(pubkey_bio)
1871d3
-        if pubkey != NULL:
1871d3
-            EVP_PKEY_free(pubkey)
1871d3
diff -urN freeipa-4.8.0/ipaclient/csrgen.py freeipa-4.8.0.removed_csrgen/ipaclient/csrgen.py
1871d3
--- freeipa-4.8.0/ipaclient/csrgen.py	2019-07-03 08:42:41.811540288 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/csrgen.py	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,488 +0,0 @@
1871d3
-#
1871d3
-# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
1871d3
-#
1871d3
-
1871d3
-import base64
1871d3
-import collections
1871d3
-import errno
1871d3
-import json
1871d3
-import logging
1871d3
-import os
1871d3
-import os.path
1871d3
-import pipes
1871d3
-import subprocess
1871d3
-import traceback
1871d3
-import codecs
1871d3
-
1871d3
-import pkg_resources
1871d3
-
1871d3
-from cryptography.hazmat.backends import default_backend
1871d3
-from cryptography.hazmat.primitives.asymmetric import padding
1871d3
-from cryptography.hazmat.primitives import hashes
1871d3
-from cryptography.hazmat.primitives.serialization import (
1871d3
-    load_pem_private_key, Encoding, PublicFormat)
1871d3
-from cryptography.x509 import load_pem_x509_certificate
1871d3
-import jinja2
1871d3
-import jinja2.ext
1871d3
-import jinja2.sandbox
1871d3
-from pyasn1.codec.der import decoder, encoder
1871d3
-from pyasn1.type import univ
1871d3
-from pyasn1_modules import rfc2314
1871d3
-import six
1871d3
-
1871d3
-from ipalib import api
1871d3
-from ipalib import errors
1871d3
-from ipalib.text import _
1871d3
-
1871d3
-if six.PY3:
1871d3
-    unicode = str
1871d3
-
1871d3
-__doc__ = _("""
1871d3
-Routines for constructing certificate signing requests using IPA data and
1871d3
-stored templates.
1871d3
-""")
1871d3
-
1871d3
-logger = logging.getLogger(__name__)
1871d3
-
1871d3
-
1871d3
-class IndexableUndefined(jinja2.Undefined):
1871d3
-    def __getitem__(self, key):
1871d3
-        return jinja2.Undefined(
1871d3
-            hint=self._undefined_hint, obj=self._undefined_obj,
1871d3
-            name=self._undefined_name, exc=self._undefined_exception)
1871d3
-
1871d3
-
1871d3
-class IPAExtension(jinja2.ext.Extension):
1871d3
-    """Jinja2 extension providing useful features for CSR generation rules."""
1871d3
-
1871d3
-    def __init__(self, environment):
1871d3
-        super(IPAExtension, self).__init__(environment)
1871d3
-
1871d3
-        environment.filters.update(
1871d3
-            quote=self.quote,
1871d3
-            required=self.required,
1871d3
-        )
1871d3
-
1871d3
-    def quote(self, data):
1871d3
-        return pipes.quote(data)
1871d3
-
1871d3
-    def required(self, data, name):
1871d3
-        if not data:
1871d3
-            raise errors.CSRTemplateError(
1871d3
-                reason=_(
1871d3
-                    'Required CSR generation rule %(name)s is missing data') %
1871d3
-                {'name': name})
1871d3
-        return data
1871d3
-
1871d3
-
1871d3
-class Formatter:
1871d3
-    """
1871d3
-    Class for processing a set of CSR generation rules into a template.
1871d3
-
1871d3
-    The template can be rendered with user and database data to produce a
1871d3
-    config, which specifies how to build a CSR.
1871d3
-
1871d3
-    Subclasses of Formatter should set the value of base_template_name to the
1871d3
-    filename of a base template with spaces for the processed rules.
1871d3
-    Additionally, they should override the _get_template_params method to
1871d3
-    produce the correct output for the base template.
1871d3
-    """
1871d3
-    base_template_name = None
1871d3
-
1871d3
-    def __init__(self, csr_data_dir=None):
1871d3
-        # chain loaders:
1871d3
-        # 1) csr_data_dir/templates
1871d3
-        # 2) /etc/ipa/csrgen/templates
1871d3
-        # 3) ipaclient/csrgen/templates
1871d3
-        loaders = []
1871d3
-        if csr_data_dir is not None:
1871d3
-            loaders.append(jinja2.FileSystemLoader(
1871d3
-                os.path.join(csr_data_dir, 'templates'))
1871d3
-            )
1871d3
-        loaders.append(jinja2.FileSystemLoader(
1871d3
-            os.path.join(api.env.confdir, 'csrgen/templates'))
1871d3
-        )
1871d3
-        loaders.append(jinja2.PackageLoader('ipaclient', 'csrgen/templates'))
1871d3
-
1871d3
-        self.jinja2 = jinja2.sandbox.SandboxedEnvironment(
1871d3
-            loader=jinja2.ChoiceLoader(loaders),
1871d3
-            extensions=[jinja2.ext.ExprStmtExtension, IPAExtension],
1871d3
-            keep_trailing_newline=True, undefined=IndexableUndefined)
1871d3
-
1871d3
-        self.passthrough_globals = {}
1871d3
-
1871d3
-    def _define_passthrough(self, call):
1871d3
-        """Some macros are meant to be interpreted during the final render, not
1871d3
-        when data rules are interpolated into syntax rules. This method allows
1871d3
-        those macros to be registered so that calls to them are passed through
1871d3
-        to the prepared rule rather than interpreted.
1871d3
-        """
1871d3
-
1871d3
-        def passthrough(caller):
1871d3
-            return u'{%% call %s() %%}%s{%% endcall %%}' % (call, caller())
1871d3
-
1871d3
-        parts = call.split('.')
1871d3
-        current_level = self.passthrough_globals
1871d3
-        for part in parts[:-1]:
1871d3
-            if part not in current_level:
1871d3
-                current_level[part] = {}
1871d3
-            current_level = current_level[part]
1871d3
-        current_level[parts[-1]] = passthrough
1871d3
-
1871d3
-    def build_template(self, rules):
1871d3
-        """
1871d3
-        Construct a template that can produce CSR generator strings.
1871d3
-
1871d3
-        :param rules: list of FieldMapping to use to populate the template.
1871d3
-
1871d3
-        :returns: jinja2.Template that can be rendered to produce the CSR data.
1871d3
-        """
1871d3
-        syntax_rules = []
1871d3
-        for field_mapping in rules:
1871d3
-            data_rules_prepared = [
1871d3
-                self._prepare_data_rule(rule)
1871d3
-                for rule in field_mapping.data_rules]
1871d3
-
1871d3
-            data_sources = []
1871d3
-            for xrule in field_mapping.data_rules:
1871d3
-                data_source = xrule.options.get('data_source')
1871d3
-                if data_source:
1871d3
-                    data_sources.append(data_source)
1871d3
-
1871d3
-            syntax_rules.append(self._prepare_syntax_rule(
1871d3
-                field_mapping.syntax_rule, data_rules_prepared,
1871d3
-                field_mapping.description, data_sources))
1871d3
-
1871d3
-        template_params = self._get_template_params(syntax_rules)
1871d3
-        base_template = self.jinja2.get_template(
1871d3
-            self.base_template_name, globals=self.passthrough_globals)
1871d3
-
1871d3
-        try:
1871d3
-            combined_template_source = base_template.render(**template_params)
1871d3
-        except jinja2.UndefinedError:
1871d3
-            logger.debug(traceback.format_exc())
1871d3
-            raise errors.CSRTemplateError(reason=_(
1871d3
-                'Template error when formatting certificate data'))
1871d3
-
1871d3
-        logger.debug(
1871d3
-            'Formatting with template: %s', combined_template_source)
1871d3
-        combined_template = self.jinja2.from_string(combined_template_source)
1871d3
-
1871d3
-        return combined_template
1871d3
-
1871d3
-    def _wrap_conditional(self, rule, condition):
1871d3
-        rule = '{%% if %s %%}%s{%% endif %%}' % (condition, rule)
1871d3
-        return rule
1871d3
-
1871d3
-    def _wrap_required(self, rule, description):
1871d3
-        template = '{%% filter required("%s") %%}%s{%% endfilter %%}' % (
1871d3
-            description, rule)
1871d3
-
1871d3
-        return template
1871d3
-
1871d3
-    def _prepare_data_rule(self, data_rule):
1871d3
-        template = data_rule.template
1871d3
-
1871d3
-        data_source = data_rule.options.get('data_source')
1871d3
-        if data_source:
1871d3
-            template = self._wrap_conditional(template, data_source)
1871d3
-
1871d3
-        return template
1871d3
-
1871d3
-    def _prepare_syntax_rule(
1871d3
-            self, syntax_rule, data_rules, description, data_sources):
1871d3
-        logger.debug('Syntax rule template: %s', syntax_rule.template)
1871d3
-        template = self.jinja2.from_string(
1871d3
-            syntax_rule.template, globals=self.passthrough_globals)
1871d3
-        is_required = syntax_rule.options.get('required', False)
1871d3
-        try:
1871d3
-            prepared_template = template.render(datarules=data_rules)
1871d3
-        except jinja2.UndefinedError:
1871d3
-            logger.debug(traceback.format_exc())
1871d3
-            raise errors.CSRTemplateError(reason=_(
1871d3
-                'Template error when formatting certificate data'))
1871d3
-
1871d3
-        if data_sources:
1871d3
-            combinator = ' %s ' % syntax_rule.options.get(
1871d3
-                'data_source_combinator', 'or')
1871d3
-            condition = combinator.join(data_sources)
1871d3
-            prepared_template = self._wrap_conditional(
1871d3
-                prepared_template, condition)
1871d3
-
1871d3
-        if is_required:
1871d3
-            prepared_template = self._wrap_required(
1871d3
-                prepared_template, description)
1871d3
-
1871d3
-        return prepared_template
1871d3
-
1871d3
-    def _get_template_params(self, syntax_rules):
1871d3
-        """
1871d3
-        Package the syntax rules into fields expected by the base template.
1871d3
-
1871d3
-        :param syntax_rules: list of prepared syntax rules to be included in
1871d3
-            the template.
1871d3
-
1871d3
-        :returns: dict of values needed to render the base template.
1871d3
-        """
1871d3
-        raise NotImplementedError('Formatter class must be subclassed')
1871d3
-
1871d3
-
1871d3
-class OpenSSLFormatter(Formatter):
1871d3
-    """Formatter class generating the openssl config-file format."""
1871d3
-
1871d3
-    base_template_name = 'openssl_base.tmpl'
1871d3
-
1871d3
-    # Syntax rules are wrapped in this data structure, to keep track of whether
1871d3
-    # each goes in the extension or the root section
1871d3
-    SyntaxRule = collections.namedtuple(
1871d3
-        'SyntaxRule', ['template', 'is_extension'])
1871d3
-
1871d3
-    def __init__(self, *args, **kwargs):
1871d3
-        super(OpenSSLFormatter, self).__init__(*args, **kwargs)
1871d3
-        self._define_passthrough('openssl.section')
1871d3
-
1871d3
-    def _get_template_params(self, syntax_rules):
1871d3
-        parameters = [rule.template for rule in syntax_rules
1871d3
-                      if not rule.is_extension]
1871d3
-        extensions = [rule.template for rule in syntax_rules
1871d3
-                      if rule.is_extension]
1871d3
-
1871d3
-        return {'parameters': parameters, 'extensions': extensions}
1871d3
-
1871d3
-    def _prepare_syntax_rule(
1871d3
-            self, syntax_rule, data_rules, description, data_sources):
1871d3
-        """Overrides method to pull out whether rule is an extension or not."""
1871d3
-        prepared_template = super(OpenSSLFormatter, self)._prepare_syntax_rule(
1871d3
-            syntax_rule, data_rules, description, data_sources)
1871d3
-        is_extension = syntax_rule.options.get('extension', False)
1871d3
-        return self.SyntaxRule(prepared_template, is_extension)
1871d3
-
1871d3
-
1871d3
-class FieldMapping:
1871d3
-    """Representation of the rules needed to construct a complete cert field.
1871d3
-
1871d3
-    Attributes:
1871d3
-        description: str, a name or description of this field, to be used in
1871d3
-            messages
1871d3
-        syntax_rule: Rule, the rule defining the syntax of this field
1871d3
-        data_rules: list of Rule, the rules that produce data to be stored in
1871d3
-            this field
1871d3
-    """
1871d3
-    __slots__ = ['description', 'syntax_rule', 'data_rules']
1871d3
-
1871d3
-    def __init__(self, description, syntax_rule, data_rules):
1871d3
-        self.description = description
1871d3
-        self.syntax_rule = syntax_rule
1871d3
-        self.data_rules = data_rules
1871d3
-
1871d3
-
1871d3
-class Rule:
1871d3
-    __slots__ = ['name', 'template', 'options']
1871d3
-
1871d3
-    def __init__(self, name, template, options):
1871d3
-        self.name = name
1871d3
-        self.template = template
1871d3
-        self.options = options
1871d3
-
1871d3
-
1871d3
-class RuleProvider:
1871d3
-    def rules_for_profile(self, profile_id):
1871d3
-        """
1871d3
-        Return the rules needed to build a CSR using the given profile.
1871d3
-
1871d3
-        :param profile_id: str, name of the CSR generation profile to use
1871d3
-
1871d3
-        :returns: list of FieldMapping, filled out with the appropriate rules
1871d3
-        """
1871d3
-        raise NotImplementedError('RuleProvider class must be subclassed')
1871d3
-
1871d3
-
1871d3
-class FileRuleProvider(RuleProvider):
1871d3
-    def __init__(self, csr_data_dir=None):
1871d3
-        self.rules = {}
1871d3
-        self._csrgen_data_dirs = []
1871d3
-        if csr_data_dir is not None:
1871d3
-            self._csrgen_data_dirs.append(csr_data_dir)
1871d3
-        self._csrgen_data_dirs.append(
1871d3
-            os.path.join(api.env.confdir, 'csrgen')
1871d3
-        )
1871d3
-        self._csrgen_data_dirs.append(
1871d3
-            pkg_resources.resource_filename('ipaclient', 'csrgen')
1871d3
-        )
1871d3
-
1871d3
-    def _open(self, subdir, filename):
1871d3
-        for data_dir in self._csrgen_data_dirs:
1871d3
-            path = os.path.join(data_dir, subdir, filename)
1871d3
-            try:
1871d3
-                return open(path)
1871d3
-            except IOError as e:
1871d3
-                if e.errno != errno.ENOENT:
1871d3
-                    raise
1871d3
-        raise IOError(
1871d3
-            errno.ENOENT,
1871d3
-            "'{}' not found in {}".format(
1871d3
-                os.path.join(subdir, filename),
1871d3
-                ", ".join(self._csrgen_data_dirs)
1871d3
-            )
1871d3
-        )
1871d3
-
1871d3
-    def _rule(self, rule_name):
1871d3
-        if rule_name not in self.rules:
1871d3
-            try:
1871d3
-                with self._open('rules', '%s.json' % rule_name) as f:
1871d3
-                    ruleconf = json.load(f)
1871d3
-            except IOError:
1871d3
-                raise errors.NotFound(
1871d3
-                    reason=_('No generation rule %(rulename)s found.') %
1871d3
-                    {'rulename': rule_name})
1871d3
-
1871d3
-            try:
1871d3
-                rule = ruleconf['rule']
1871d3
-            except KeyError:
1871d3
-                raise errors.EmptyResult(
1871d3
-                    reason=_('Generation rule "%(rulename)s" is missing the'
1871d3
-                             ' "rule" key') % {'rulename': rule_name})
1871d3
-
1871d3
-            options = ruleconf.get('options', {})
1871d3
-
1871d3
-            self.rules[rule_name] = Rule(
1871d3
-                rule_name, rule['template'], options)
1871d3
-
1871d3
-        return self.rules[rule_name]
1871d3
-
1871d3
-    def rules_for_profile(self, profile_id):
1871d3
-        try:
1871d3
-            with self._open('profiles', '%s.json' % profile_id) as f:
1871d3
-                profile = json.load(f)
1871d3
-        except IOError:
1871d3
-            raise errors.NotFound(
1871d3
-                reason=_('No CSR generation rules are defined for profile'
1871d3
-                         ' %(profile_id)s') % {'profile_id': profile_id})
1871d3
-
1871d3
-        field_mappings = []
1871d3
-        for field in profile:
1871d3
-            syntax_rule = self._rule(field['syntax'])
1871d3
-            data_rules = [self._rule(name) for name in field['data']]
1871d3
-            field_mappings.append(FieldMapping(
1871d3
-                syntax_rule.name, syntax_rule, data_rules))
1871d3
-        return field_mappings
1871d3
-
1871d3
-
1871d3
-class CSRGenerator:
1871d3
-    def __init__(self, rule_provider, formatter_class=OpenSSLFormatter):
1871d3
-        self.rule_provider = rule_provider
1871d3
-        self.formatter = formatter_class()
1871d3
-
1871d3
-    def csr_config(self, principal, config, profile_id):
1871d3
-        render_data = {'subject': principal, 'config': config}
1871d3
-
1871d3
-        rules = self.rule_provider.rules_for_profile(profile_id)
1871d3
-        template = self.formatter.build_template(rules)
1871d3
-
1871d3
-        try:
1871d3
-            config = template.render(render_data)
1871d3
-        except jinja2.UndefinedError:
1871d3
-            logger.debug(traceback.format_exc())
1871d3
-            raise errors.CSRTemplateError(reason=_(
1871d3
-                'Template error when formatting certificate data'))
1871d3
-
1871d3
-        return config
1871d3
-
1871d3
-
1871d3
-class CSRLibraryAdaptor:
1871d3
-    def get_subject_public_key_info(self):
1871d3
-        raise NotImplementedError('Use a subclass of CSRLibraryAdaptor')
1871d3
-
1871d3
-    def sign_csr(self, certification_request_info):
1871d3
-        """Sign a CertificationRequestInfo.
1871d3
-
1871d3
-        :returns: bytes, a DER-encoded signed CSR.
1871d3
-        """
1871d3
-        raise NotImplementedError('Use a subclass of CSRLibraryAdaptor')
1871d3
-
1871d3
-
1871d3
-class OpenSSLAdaptor:
1871d3
-    def __init__(self, key=None, key_filename=None, password_filename=None):
1871d3
-        """
1871d3
-        Must provide either ``key_filename`` or ``key``.
1871d3
-
1871d3
-        """
1871d3
-        if key_filename is not None:
1871d3
-            with open(key_filename, 'rb') as key_file:
1871d3
-                key_bytes = key_file.read()
1871d3
-
1871d3
-            password = None
1871d3
-            if password_filename is not None:
1871d3
-                with open(password_filename, 'rb') as password_file:
1871d3
-                    password = password_file.read().strip()
1871d3
-
1871d3
-            self._key = load_pem_private_key(
1871d3
-                key_bytes, password, default_backend())
1871d3
-
1871d3
-        elif key is not None:
1871d3
-            self._key = key
1871d3
-
1871d3
-        else:
1871d3
-            raise ValueError("Must provide 'key' or 'key_filename'")
1871d3
-
1871d3
-    def key(self):
1871d3
-        return self._key
1871d3
-
1871d3
-    def get_subject_public_key_info(self):
1871d3
-        pubkey_info = self.key().public_key().public_bytes(
1871d3
-            Encoding.DER, PublicFormat.SubjectPublicKeyInfo)
1871d3
-        return pubkey_info
1871d3
-
1871d3
-    def sign_csr(self, certification_request_info):
1871d3
-        reqinfo = decoder.decode(
1871d3
-            certification_request_info, rfc2314.CertificationRequestInfo())[0]
1871d3
-        csr = rfc2314.CertificationRequest()
1871d3
-        csr.setComponentByName('certificationRequestInfo', reqinfo)
1871d3
-
1871d3
-        algorithm = rfc2314.SignatureAlgorithmIdentifier()
1871d3
-        algorithm.setComponentByName(
1871d3
-            'algorithm', univ.ObjectIdentifier(
1871d3
-                '1.2.840.113549.1.1.11'))  # sha256WithRSAEncryption
1871d3
-        csr.setComponentByName('signatureAlgorithm', algorithm)
1871d3
-
1871d3
-        signature = self.key().sign(
1871d3
-            certification_request_info,
1871d3
-            padding.PKCS1v15(),
1871d3
-            hashes.SHA256()
1871d3
-        )
1871d3
-        asn1sig = univ.BitString("'{sig}'H".format(
1871d3
-                                    sig=codecs.encode(signature, 'hex')
1871d3
-                                    .decode('ascii'))
1871d3
-                                 )
1871d3
-        csr.setComponentByName('signature', asn1sig)
1871d3
-        return encoder.encode(csr)
1871d3
-
1871d3
-
1871d3
-class NSSAdaptor:
1871d3
-    def __init__(self, database, password_filename):
1871d3
-        self.database = database
1871d3
-        self.password_filename = password_filename
1871d3
-        self.nickname = base64.b32encode(os.urandom(40))
1871d3
-
1871d3
-    def get_subject_public_key_info(self):
1871d3
-        temp_cn = base64.b32encode(os.urandom(40)).decode('ascii')
1871d3
-
1871d3
-        password_args = []
1871d3
-        if self.password_filename is not None:
1871d3
-            password_args = ['-f', self.password_filename]
1871d3
-
1871d3
-        subprocess.check_call(
1871d3
-            ['certutil', '-S', '-n', self.nickname, '-s', 'CN=%s' % temp_cn,
1871d3
-             '-x', '-t', ',,', '-d', self.database] + password_args)
1871d3
-        cert_pem = subprocess.check_output(
1871d3
-            ['certutil', '-L', '-n', self.nickname, '-a',
1871d3
-             '-d', self.database] + password_args)
1871d3
-
1871d3
-        cert = load_pem_x509_certificate(cert_pem, default_backend())
1871d3
-        pubkey_info = cert.public_key().public_bytes(
1871d3
-            Encoding.DER, PublicFormat.SubjectPublicKeyInfo)
1871d3
-
1871d3
-        return pubkey_info
1871d3
-
1871d3
-    def sign_csr(self, certification_request_info):
1871d3
-        raise NotImplementedError('NSS is not yet supported')
1871d3
diff -urN freeipa-4.8.0/ipaclient/plugins/cert.py freeipa-4.8.0.removed_csrgen/ipaclient/plugins/cert.py
1871d3
--- freeipa-4.8.0/ipaclient/plugins/cert.py	2019-07-03 08:42:41.978537802 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/plugins/cert.py	2019-07-03 13:24:38.477222594 +0200
1871d3
@@ -21,8 +21,6 @@
1871d3
 
1871d3
 import base64
1871d3
 
1871d3
-import six
1871d3
-
1871d3
 from ipaclient.frontend import MethodOverride
1871d3
 from ipalib import errors
1871d3
 from ipalib import x509
1871d3
@@ -31,9 +29,6 @@
1871d3
 from ipalib.plugable import Registry
1871d3
 from ipalib.text import _
1871d3
 
1871d3
-if six.PY3:
1871d3
-    unicode = str
1871d3
-
1871d3
 register = Registry()
1871d3
 
1871d3
 
1871d3
@@ -73,87 +68,12 @@
1871d3
 
1871d3
 @register(override=True, no_fail=True)
1871d3
 class cert_request(CertRetrieveOverride):
1871d3
-    takes_options = CertRetrieveOverride.takes_options + (
1871d3
-        Str(
1871d3
-            'database?',
1871d3
-            label=_('Path to NSS database'),
1871d3
-            doc=_('Path to NSS database to use for private key'),
1871d3
-        ),
1871d3
-        Str(
1871d3
-            'private_key?',
1871d3
-            label=_('Path to private key file'),
1871d3
-            doc=_('Path to PEM file containing a private key'),
1871d3
-        ),
1871d3
-        Str(
1871d3
-            'password_file?',
1871d3
-            label=_(
1871d3
-                'File containing a password for the private key or database'),
1871d3
-        ),
1871d3
-        Str(
1871d3
-            'csr_profile_id?',
1871d3
-            label=_('Name of CSR generation profile (if not the same as'
1871d3
-                    ' profile_id)'),
1871d3
-        ),
1871d3
-    )
1871d3
-
1871d3
     def get_args(self):
1871d3
         for arg in super(cert_request, self).get_args():
1871d3
             if arg.name == 'csr':
1871d3
                 arg = arg.clone_retype(arg.name, File, required=False)
1871d3
             yield arg
1871d3
 
1871d3
-    def forward(self, csr=None, **options):
1871d3
-        database = options.pop('database', None)
1871d3
-        private_key = options.pop('private_key', None)
1871d3
-        csr_profile_id = options.pop('csr_profile_id', None)
1871d3
-        password_file = options.pop('password_file', None)
1871d3
-
1871d3
-        if csr is None:
1871d3
-            # Deferred import, ipaclient.csrgen is expensive to load.
1871d3
-            # see https://pagure.io/freeipa/issue/7484
1871d3
-            from ipaclient import csrgen
1871d3
-
1871d3
-            if database:
1871d3
-                adaptor = csrgen.NSSAdaptor(database, password_file)
1871d3
-            elif private_key:
1871d3
-                adaptor = csrgen.OpenSSLAdaptor(
1871d3
-                    key_filename=private_key, password_filename=password_file)
1871d3
-            else:
1871d3
-                raise errors.InvocationError(
1871d3
-                    message=u"One of 'database' or 'private_key' is required")
1871d3
-
1871d3
-            pubkey_info = adaptor.get_subject_public_key_info()
1871d3
-            pubkey_info_b64 = base64.b64encode(pubkey_info)
1871d3
-
1871d3
-            # If csr_profile_id is passed, that takes precedence.
1871d3
-            # Otherwise, use profile_id. If neither are passed, the default
1871d3
-            # in cert_get_requestdata will be used.
1871d3
-            profile_id = csr_profile_id
1871d3
-            if profile_id is None:
1871d3
-                profile_id = options.get('profile_id')
1871d3
-
1871d3
-            response = self.api.Command.cert_get_requestdata(
1871d3
-                profile_id=profile_id,
1871d3
-                principal=options.get('principal'),
1871d3
-                public_key_info=pubkey_info_b64)
1871d3
-
1871d3
-            req_info_b64 = response['result']['request_info']
1871d3
-            req_info = base64.b64decode(req_info_b64)
1871d3
-
1871d3
-            csr = adaptor.sign_csr(req_info)
1871d3
-
1871d3
-            if not csr:
1871d3
-                raise errors.CertificateOperationError(
1871d3
-                    error=(_('Generated CSR was empty')))
1871d3
-
1871d3
-        else:
1871d3
-            if database is not None or private_key is not None:
1871d3
-                raise errors.MutuallyExclusiveError(reason=_(
1871d3
-                    "Options 'database' and 'private_key' are not compatible"
1871d3
-                    " with 'csr'"))
1871d3
-
1871d3
-        return super(cert_request, self).forward(csr, **options)
1871d3
-
1871d3
 
1871d3
 @register(override=True, no_fail=True)
1871d3
 class cert_show(CertRetrieveOverride):
1871d3
diff -urN freeipa-4.8.0/ipaclient/plugins/cert.py.orig freeipa-4.8.0.removed_csrgen/ipaclient/plugins/cert.py.orig
1871d3
--- freeipa-4.8.0/ipaclient/plugins/cert.py.orig	1970-01-01 01:00:00.000000000 +0100
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/plugins/cert.py.orig	2019-07-03 13:24:38.478222573 +0200
1871d3
@@ -0,0 +1,215 @@
1871d3
+# Authors:
1871d3
+#   Andrew Wnuk <awnuk@redhat.com>
1871d3
+#   Jason Gerard DeRose <jderose@redhat.com>
1871d3
+#   John Dennis <jdennis@redhat.com>
1871d3
+#
1871d3
+# Copyright (C) 2009  Red Hat
1871d3
+# see file 'COPYING' for use and warranty information
1871d3
+#
1871d3
+# This program is free software; you can redistribute it and/or modify
1871d3
+# it under the terms of the GNU General Public License as published by
1871d3
+# the Free Software Foundation, either version 3 of the License, or
1871d3
+# (at your option) any later version.
1871d3
+#
1871d3
+# This program is distributed in the hope that it will be useful,
1871d3
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1871d3
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1871d3
+# GNU General Public License for more details.
1871d3
+#
1871d3
+# You should have received a copy of the GNU General Public License
1871d3
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
1871d3
+
1871d3
+import base64
1871d3
+
1871d3
+import six
1871d3
+
1871d3
+from ipaclient.frontend import MethodOverride
1871d3
+from ipalib import errors
1871d3
+from ipalib import x509
1871d3
+from ipalib import util
1871d3
+from ipalib.parameters import BinaryFile, File, Flag, Str
1871d3
+from ipalib.plugable import Registry
1871d3
+from ipalib.text import _
1871d3
+
1871d3
+if six.PY3:
1871d3
+    unicode = str
1871d3
+
1871d3
+register = Registry()
1871d3
+
1871d3
+
1871d3
+class CertRetrieveOverride(MethodOverride):
1871d3
+    takes_options = (
1871d3
+        Str(
1871d3
+            'certificate_out?',
1871d3
+            doc=_('Write certificate (chain if --chain used) to file'),
1871d3
+            include='cli',
1871d3
+            cli_metavar='FILE',
1871d3
+        ),
1871d3
+    )
1871d3
+
1871d3
+    def forward(self, *args, **options):
1871d3
+        if 'certificate_out' in options:
1871d3
+            certificate_out = options.pop('certificate_out')
1871d3
+            try:
1871d3
+                util.check_writable_file(certificate_out)
1871d3
+            except errors.FileError as e:
1871d3
+                raise errors.ValidationError(name='certificate-out',
1871d3
+                                             error=str(e))
1871d3
+        else:
1871d3
+            certificate_out = None
1871d3
+
1871d3
+        result = super(CertRetrieveOverride, self).forward(*args, **options)
1871d3
+
1871d3
+        if certificate_out is not None:
1871d3
+            if options.get('chain', False):
1871d3
+                certs = result['result']['certificate_chain']
1871d3
+            else:
1871d3
+                certs = [base64.b64decode(result['result']['certificate'])]
1871d3
+            certs = (x509.load_der_x509_certificate(cert) for cert in certs)
1871d3
+            x509.write_certificate_list(certs, certificate_out)
1871d3
+
1871d3
+        return result
1871d3
+
1871d3
+
1871d3
+@register(override=True, no_fail=True)
1871d3
+class cert_request(CertRetrieveOverride):
1871d3
+    takes_options = CertRetrieveOverride.takes_options + (
1871d3
+        Str(
1871d3
+            'database?',
1871d3
+            label=_('Path to NSS database'),
1871d3
+            doc=_('Path to NSS database to use for private key'),
1871d3
+        ),
1871d3
+        Str(
1871d3
+            'private_key?',
1871d3
+            label=_('Path to private key file'),
1871d3
+            doc=_('Path to PEM file containing a private key'),
1871d3
+        ),
1871d3
+        Str(
1871d3
+            'password_file?',
1871d3
+            label=_(
1871d3
+                'File containing a password for the private key or database'),
1871d3
+        ),
1871d3
+        Str(
1871d3
+            'csr_profile_id?',
1871d3
+            label=_('Name of CSR generation profile (if not the same as'
1871d3
+                    ' profile_id)'),
1871d3
+        ),
1871d3
+    )
1871d3
+
1871d3
+    def get_args(self):
1871d3
+        for arg in super(cert_request, self).get_args():
1871d3
+            if arg.name == 'csr':
1871d3
+                arg = arg.clone_retype(arg.name, File, required=False)
1871d3
+            yield arg
1871d3
+
1871d3
+    def forward(self, csr=None, **options):
1871d3
+        database = options.pop('database', None)
1871d3
+        private_key = options.pop('private_key', None)
1871d3
+        csr_profile_id = options.pop('csr_profile_id', None)
1871d3
+        password_file = options.pop('password_file', None)
1871d3
+
1871d3
+        if csr is None:
1871d3
+            # Deferred import, ipaclient.csrgen is expensive to load.
1871d3
+            # see https://pagure.io/freeipa/issue/7484
1871d3
+            from ipaclient import csrgen
1871d3
+
1871d3
+            if database:
1871d3
+                adaptor = csrgen.NSSAdaptor(database, password_file)
1871d3
+            elif private_key:
1871d3
+                adaptor = csrgen.OpenSSLAdaptor(
1871d3
+                    key_filename=private_key, password_filename=password_file)
1871d3
+            else:
1871d3
+                raise errors.InvocationError(
1871d3
+                    message=u"One of 'database' or 'private_key' is required")
1871d3
+
1871d3
+            pubkey_info = adaptor.get_subject_public_key_info()
1871d3
+            pubkey_info_b64 = base64.b64encode(pubkey_info)
1871d3
+
1871d3
+            # If csr_profile_id is passed, that takes precedence.
1871d3
+            # Otherwise, use profile_id. If neither are passed, the default
1871d3
+            # in cert_get_requestdata will be used.
1871d3
+            profile_id = csr_profile_id
1871d3
+            if profile_id is None:
1871d3
+                profile_id = options.get('profile_id')
1871d3
+
1871d3
+            response = self.api.Command.cert_get_requestdata(
1871d3
+                profile_id=profile_id,
1871d3
+                principal=options.get('principal'),
1871d3
+                public_key_info=pubkey_info_b64)
1871d3
+
1871d3
+            req_info_b64 = response['result']['request_info']
1871d3
+            req_info = base64.b64decode(req_info_b64)
1871d3
+
1871d3
+            csr = adaptor.sign_csr(req_info)
1871d3
+
1871d3
+            if not csr:
1871d3
+                raise errors.CertificateOperationError(
1871d3
+                    error=(_('Generated CSR was empty')))
1871d3
+
1871d3
+        else:
1871d3
+            if database is not None or private_key is not None:
1871d3
+                raise errors.MutuallyExclusiveError(reason=_(
1871d3
+                    "Options 'database' and 'private_key' are not compatible"
1871d3
+                    " with 'csr'"))
1871d3
+
1871d3
+        return super(cert_request, self).forward(csr, **options)
1871d3
+
1871d3
+
1871d3
+@register(override=True, no_fail=True)
1871d3
+class cert_show(CertRetrieveOverride):
1871d3
+    def get_options(self):
1871d3
+        for option in super(cert_show, self).get_options():
1871d3
+            if option.name == 'out':
1871d3
+                # skip server-defined --out
1871d3
+                continue
1871d3
+            if option.name == 'certificate_out':
1871d3
+                # add --out as a deprecated alias of --certificate-out
1871d3
+                option = option.clone_rename(
1871d3
+                    'out',
1871d3
+                    cli_name='certificate_out',
1871d3
+                    deprecated_cli_aliases={'out'},
1871d3
+                )
1871d3
+            yield option
1871d3
+
1871d3
+    def forward(self, *args, **options):
1871d3
+        try:
1871d3
+            options['certificate_out'] = options.pop('out')
1871d3
+        except KeyError:
1871d3
+            pass
1871d3
+
1871d3
+        return super(cert_show, self).forward(*args, **options)
1871d3
+
1871d3
+
1871d3
+@register(override=True, no_fail=True)
1871d3
+class cert_remove_hold(MethodOverride):
1871d3
+    has_output_params = (
1871d3
+        Flag('unrevoked',
1871d3
+            label=_('Unrevoked'),
1871d3
+        ),
1871d3
+        Str('error_string',
1871d3
+            label=_('Error'),
1871d3
+        ),
1871d3
+    )
1871d3
+
1871d3
+
1871d3
+@register(override=True, no_fail=True)
1871d3
+class cert_find(MethodOverride):
1871d3
+    takes_options = (
1871d3
+        BinaryFile(
1871d3
+            'file?',
1871d3
+            label=_("Input filename"),
1871d3
+            doc=_('File to load the certificate from.'),
1871d3
+            include='cli',
1871d3
+        ),
1871d3
+    )
1871d3
+
1871d3
+    def forward(self, *args, **options):
1871d3
+        if self.api.env.context == 'cli':
1871d3
+            if 'certificate' in options and 'file' in options:
1871d3
+                raise errors.MutuallyExclusiveError(
1871d3
+                    reason=_("cannot specify both raw certificate and file"))
1871d3
+            if 'certificate' not in options and 'file' in options:
1871d3
+                options['certificate'] = x509.load_unknown_x509_certificate(
1871d3
+                                            options.pop('file'))
1871d3
+
1871d3
+        return super(cert_find, self).forward(*args, **options)
1871d3
diff -urN freeipa-4.8.0/ipaclient/plugins/csrgen.py freeipa-4.8.0.removed_csrgen/ipaclient/plugins/csrgen.py
1871d3
--- freeipa-4.8.0/ipaclient/plugins/csrgen.py	2019-07-03 08:42:41.990537623 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/plugins/csrgen.py	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,128 +0,0 @@
1871d3
-#
1871d3
-# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
1871d3
-#
1871d3
-
1871d3
-import base64
1871d3
-
1871d3
-import six
1871d3
-
1871d3
-from ipalib import api
1871d3
-from ipalib import errors
1871d3
-from ipalib import output
1871d3
-from ipalib import util
1871d3
-from ipalib.frontend import Local, Str
1871d3
-from ipalib.parameters import Bytes, Principal
1871d3
-from ipalib.plugable import Registry
1871d3
-from ipalib.text import _
1871d3
-from ipapython import dogtag
1871d3
-
1871d3
-
1871d3
-if six.PY3:
1871d3
-    unicode = str
1871d3
-
1871d3
-register = Registry()
1871d3
-
1871d3
-__doc__ = _("""
1871d3
-Commands to build certificate requests automatically
1871d3
-""")
1871d3
-
1871d3
-
1871d3
-@register()
1871d3
-class cert_get_requestdata(Local):
1871d3
-    __doc__ = _('Gather data for a certificate signing request.')
1871d3
-
1871d3
-    NO_CLI = True
1871d3
-
1871d3
-    takes_options = (
1871d3
-        Principal(
1871d3
-            'principal',
1871d3
-            label=_('Principal'),
1871d3
-            doc=_('Principal for this certificate (e.g.'
1871d3
-                  ' HTTP/test.example.com)'),
1871d3
-        ),
1871d3
-        Str(
1871d3
-            'profile_id?',
1871d3
-            label=_('Profile ID'),
1871d3
-            doc=_('CSR Generation Profile to use'),
1871d3
-        ),
1871d3
-        Bytes(
1871d3
-            'public_key_info',
1871d3
-            label=_('Subject Public Key Info'),
1871d3
-            doc=_('DER-encoded SubjectPublicKeyInfo structure'),
1871d3
-        ),
1871d3
-        Str(
1871d3
-            'out?',
1871d3
-            doc=_('Write CertificationRequestInfo to file'),
1871d3
-        ),
1871d3
-    )
1871d3
-
1871d3
-    has_output = (
1871d3
-        output.Output(
1871d3
-            'result',
1871d3
-            type=dict,
1871d3
-            doc=_('Dictionary mapping variable name to value'),
1871d3
-        ),
1871d3
-    )
1871d3
-
1871d3
-    has_output_params = (
1871d3
-        Str(
1871d3
-            'request_info',
1871d3
-            label=_('CertificationRequestInfo structure'),
1871d3
-        )
1871d3
-    )
1871d3
-
1871d3
-    def execute(self, *args, **options):
1871d3
-        # Deferred import, ipaclient.csrgen is expensive to load.
1871d3
-        # see https://pagure.io/freeipa/issue/7484
1871d3
-        from ipaclient import csrgen
1871d3
-        from ipaclient import csrgen_ffi
1871d3
-
1871d3
-        if 'out' in options:
1871d3
-            util.check_writable_file(options['out'])
1871d3
-
1871d3
-        principal = options.get('principal')
1871d3
-        profile_id = options.get('profile_id')
1871d3
-        if profile_id is None:
1871d3
-            profile_id = dogtag.DEFAULT_PROFILE
1871d3
-        public_key_info = options.get('public_key_info')
1871d3
-        public_key_info = base64.b64decode(public_key_info)
1871d3
-
1871d3
-        if self.api.env.in_server:
1871d3
-            backend = self.api.Backend.ldap2
1871d3
-        else:
1871d3
-            backend = self.api.Backend.rpcclient
1871d3
-        if not backend.isconnected():
1871d3
-            backend.connect()
1871d3
-
1871d3
-        try:
1871d3
-            if principal.is_host:
1871d3
-                principal_obj = api.Command.host_show(
1871d3
-                    principal.hostname, all=True)
1871d3
-            elif principal.is_service:
1871d3
-                principal_obj = api.Command.service_show(
1871d3
-                    unicode(principal), all=True)
1871d3
-            elif principal.is_user:
1871d3
-                principal_obj = api.Command.user_show(
1871d3
-                    principal.username, all=True)
1871d3
-        except errors.NotFound:
1871d3
-            raise errors.NotFound(
1871d3
-                reason=_("The principal for this request doesn't exist."))
1871d3
-        principal_obj = principal_obj['result']
1871d3
-        config = api.Command.config_show()['result']
1871d3
-
1871d3
-        generator = csrgen.CSRGenerator(csrgen.FileRuleProvider())
1871d3
-
1871d3
-        csr_config = generator.csr_config(principal_obj, config, profile_id)
1871d3
-        request_info = base64.b64encode(csrgen_ffi.build_requestinfo(
1871d3
-            csr_config.encode('utf8'), public_key_info))
1871d3
-
1871d3
-        result = {}
1871d3
-        if 'out' in options:
1871d3
-            with open(options['out'], 'wb') as f:
1871d3
-                f.write(request_info)
1871d3
-        else:
1871d3
-            result = dict(request_info=request_info)
1871d3
-
1871d3
-        return dict(
1871d3
-            result=result
1871d3
-        )
1871d3
diff -urN freeipa-4.8.0/ipaclient/setup.py freeipa-4.8.0.removed_csrgen/ipaclient/setup.py
1871d3
--- freeipa-4.8.0/ipaclient/setup.py	2019-07-03 08:42:41.836539916 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipaclient/setup.py	2019-07-03 13:24:38.479222551 +0200
1871d3
@@ -41,13 +41,6 @@
1871d3
             "ipaclient.remote_plugins.2_156",
1871d3
             "ipaclient.remote_plugins.2_164",
1871d3
         ],
1871d3
-        package_data={
1871d3
-            'ipaclient': [
1871d3
-                'csrgen/profiles/*.json',
1871d3
-                'csrgen/rules/*.json',
1871d3
-                'csrgen/templates/*.tmpl',
1871d3
-            ],
1871d3
-        },
1871d3
         install_requires=[
1871d3
             "cryptography",
1871d3
             "ipalib",
1871d3
@@ -63,7 +56,6 @@
1871d3
         extras_require={
1871d3
             "install": ["ipaplatform"],
1871d3
             "otptoken_yubikey": ["python-yubico", "pyusb"],
1871d3
-            "csrgen": ["cffi", "jinja2"],
1871d3
             "ldap": ["python-ldap"],  # ipapython.ipaldap
1871d3
         },
1871d3
         zip_safe=False,
1871d3
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/configs/caIPAserviceCert.conf freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/configs/caIPAserviceCert.conf
1871d3
--- freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/configs/caIPAserviceCert.conf	2019-07-03 08:42:45.972478335 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/configs/caIPAserviceCert.conf	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,16 +0,0 @@
1871d3
-[ req ]
1871d3
-prompt = no
1871d3
-encrypt_key = no
1871d3
-
1871d3
-distinguished_name = sec0
1871d3
-req_extensions = sec2
1871d3
-
1871d3
-[ sec0 ]
1871d3
-O=DOMAIN.EXAMPLE.COM
1871d3
-CN=machine.example.com
1871d3
-
1871d3
-[ sec1 ]
1871d3
-DNS = machine.example.com
1871d3
-
1871d3
-[ sec2 ]
1871d3
-subjectAltName = @sec1
1871d3
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/configs/userCert.conf freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/configs/userCert.conf
1871d3
--- freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/configs/userCert.conf	2019-07-03 08:42:45.976478276 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/configs/userCert.conf	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,16 +0,0 @@
1871d3
-[ req ]
1871d3
-prompt = no
1871d3
-encrypt_key = no
1871d3
-
1871d3
-distinguished_name = sec0
1871d3
-req_extensions = sec2
1871d3
-
1871d3
-[ sec0 ]
1871d3
-O=DOMAIN.EXAMPLE.COM
1871d3
-CN=testuser
1871d3
-
1871d3
-[ sec1 ]
1871d3
-email = testuser@example.com
1871d3
-
1871d3
-[ sec2 ]
1871d3
-subjectAltName = @sec1
1871d3
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/profiles/profile.json freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/profiles/profile.json
1871d3
--- freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/profiles/profile.json	2019-07-03 08:42:45.980478216 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/profiles/profile.json	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,8 +0,0 @@
1871d3
-[
1871d3
-    {
1871d3
-        "syntax": "basic",
1871d3
-        "data": [
1871d3
-            "options"
1871d3
-        ]
1871d3
-    }
1871d3
-]
1871d3
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/rules/basic.json freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/rules/basic.json
1871d3
--- freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/rules/basic.json	2019-07-03 08:42:45.984478157 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/rules/basic.json	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,5 +0,0 @@
1871d3
-{
1871d3
-  "rule": {
1871d3
-    "template": "openssl_rule"
1871d3
-  }
1871d3
-}
1871d3
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/rules/options.json freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/rules/options.json
1871d3
--- freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/rules/options.json	2019-07-03 08:42:45.988478097 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/rules/options.json	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,8 +0,0 @@
1871d3
-{
1871d3
-  "rule": {
1871d3
-    "template": "openssl_rule"
1871d3
-  },
1871d3
-  "options": {
1871d3
-    "rule_option": true
1871d3
-  }
1871d3
-}
1871d3
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl
1871d3
--- freeipa-4.8.0/ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl	2019-07-03 08:42:45.993478023 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/data/test_csrgen/templates/identity_base.tmpl	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1 +0,0 @@
1871d3
-{{ options|join(";") }}
1871d3
diff -urN freeipa-4.8.0/ipatests/test_ipaclient/test_csrgen.py freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/test_csrgen.py
1871d3
--- freeipa-4.8.0/ipatests/test_ipaclient/test_csrgen.py	2019-07-03 08:42:45.963478469 +0200
1871d3
+++ freeipa-4.8.0.removed_csrgen/ipatests/test_ipaclient/test_csrgen.py	1970-01-01 01:00:00.000000000 +0100
1871d3
@@ -1,304 +0,0 @@
1871d3
-#
1871d3
-# Copyright (C) 2016  FreeIPA Contributors see COPYING for license
1871d3
-#
1871d3
-
1871d3
-import os
1871d3
-import pytest
1871d3
-
1871d3
-from cryptography.hazmat.backends import default_backend
1871d3
-from cryptography.hazmat.primitives.asymmetric import rsa
1871d3
-from cryptography import x509
1871d3
-
1871d3
-from ipaclient import csrgen, csrgen_ffi
1871d3
-from ipalib import errors
1871d3
-
1871d3
-BASE_DIR = os.path.dirname(__file__)
1871d3
-CSR_DATA_DIR = os.path.join(BASE_DIR, 'data', 'test_csrgen')
1871d3
-
1871d3
-
1871d3
-@pytest.fixture
1871d3
-def formatter():
1871d3
-    return csrgen.Formatter(csr_data_dir=CSR_DATA_DIR)
1871d3
-
1871d3
-
1871d3
-@pytest.fixture
1871d3
-def rule_provider():
1871d3
-    return csrgen.FileRuleProvider(csr_data_dir=CSR_DATA_DIR)
1871d3
-
1871d3
-
1871d3
-@pytest.fixture
1871d3
-def generator():
1871d3
-    return csrgen.CSRGenerator(csrgen.FileRuleProvider())
1871d3
-
1871d3
-
1871d3
-class StubRuleProvider(csrgen.RuleProvider):
1871d3
-    def __init__(self):
1871d3
-        self.syntax_rule = csrgen.Rule(
1871d3
-            'syntax', '{{datarules|join(",")}}', {})
1871d3
-        self.data_rule = csrgen.Rule('data', 'data_template', {})
1871d3
-        self.field_mapping = csrgen.FieldMapping(
1871d3
-            'example', self.syntax_rule, [self.data_rule])
1871d3
-        self.rules = [self.field_mapping]
1871d3
-
1871d3
-    def rules_for_profile(self, profile_id):
1871d3
-        return self.rules
1871d3
-
1871d3
-
1871d3
-class IdentityFormatter(csrgen.Formatter):
1871d3
-    base_template_name = 'identity_base.tmpl'
1871d3
-
1871d3
-    def __init__(self):
1871d3
-        super(IdentityFormatter, self).__init__(csr_data_dir=CSR_DATA_DIR)
1871d3
-
1871d3
-    def _get_template_params(self, syntax_rules):
1871d3
-        return {'options': syntax_rules}
1871d3
-
1871d3
-
1871d3
-class test_Formatter:
1871d3
-    def test_prepare_data_rule_with_data_source(self, formatter):
1871d3
-        data_rule = csrgen.Rule('uid', '{{subject.uid.0}}',
1871d3
-                                {'data_source': 'subject.uid.0'})
1871d3
-        prepared = formatter._prepare_data_rule(data_rule)
1871d3
-        assert prepared == '{% if subject.uid.0 %}{{subject.uid.0}}{% endif %}'
1871d3
-
1871d3
-    def test_prepare_data_rule_no_data_source(self, formatter):
1871d3
-        """Not a normal case, but we should handle it anyway"""
1871d3
-        data_rule = csrgen.Rule('uid', 'static_text', {})
1871d3
-        prepared = formatter._prepare_data_rule(data_rule)
1871d3
-        assert prepared == 'static_text'
1871d3
-
1871d3
-    def test_prepare_syntax_rule_with_data_sources(self, formatter):
1871d3
-        syntax_rule = csrgen.Rule(
1871d3
-            'example', '{{datarules|join(",")}}', {})
1871d3
-        data_rules = ['{{subject.field1}}', '{{subject.field2}}']
1871d3
-        data_sources = ['subject.field1', 'subject.field2']
1871d3
-        prepared = formatter._prepare_syntax_rule(
1871d3
-            syntax_rule, data_rules, 'example', data_sources)
1871d3
-
1871d3
-        assert prepared == (
1871d3
-            '{% if subject.field1 or subject.field2 %}{{subject.field1}},'
1871d3
-            '{{subject.field2}}{% endif %}')
1871d3
-
1871d3
-    def test_prepare_syntax_rule_with_combinator(self, formatter):
1871d3
-        syntax_rule = csrgen.Rule('example', '{{datarules|join(",")}}',
1871d3
-                                  {'data_source_combinator': 'and'})
1871d3
-        data_rules = ['{{subject.field1}}', '{{subject.field2}}']
1871d3
-        data_sources = ['subject.field1', 'subject.field2']
1871d3
-        prepared = formatter._prepare_syntax_rule(
1871d3
-            syntax_rule, data_rules, 'example', data_sources)
1871d3
-
1871d3
-        assert prepared == (
1871d3
-            '{% if subject.field1 and subject.field2 %}{{subject.field1}},'
1871d3
-            '{{subject.field2}}{% endif %}')
1871d3
-
1871d3
-    def test_prepare_syntax_rule_required(self, formatter):
1871d3
-        syntax_rule = csrgen.Rule('example', '{{datarules|join(",")}}',
1871d3
-                                  {'required': True})
1871d3
-        data_rules = ['{{subject.field1}}']
1871d3
-        data_sources = ['subject.field1']
1871d3
-        prepared = formatter._prepare_syntax_rule(
1871d3
-            syntax_rule, data_rules, 'example', data_sources)
1871d3
-
1871d3
-        assert prepared == (
1871d3
-            '{% filter required("example") %}{% if subject.field1 %}'
1871d3
-            '{{subject.field1}}{% endif %}{% endfilter %}')
1871d3
-
1871d3
-    def test_prepare_syntax_rule_passthrough(self, formatter):
1871d3
-        """
1871d3
-        Calls to macros defined as passthrough are still call tags in the final
1871d3
-        template.
1871d3
-        """
1871d3
-        formatter._define_passthrough('example.macro')
1871d3
-
1871d3
-        syntax_rule = csrgen.Rule(
1871d3
-            'example',
1871d3
-            '{% call example.macro() %}{{datarules|join(",")}}{% endcall %}',
1871d3
-            {})
1871d3
-        data_rules = ['{{subject.field1}}']
1871d3
-        data_sources = ['subject.field1']
1871d3
-        prepared = formatter._prepare_syntax_rule(
1871d3
-            syntax_rule, data_rules, 'example', data_sources)
1871d3
-
1871d3
-        assert prepared == (
1871d3
-            '{% if subject.field1 %}{% call example.macro() %}'
1871d3
-            '{{subject.field1}}{% endcall %}{% endif %}')
1871d3
-
1871d3
-    def test_prepare_syntax_rule_no_data_sources(self, formatter):
1871d3
-        """Not a normal case, but we should handle it anyway"""
1871d3
-        syntax_rule = csrgen.Rule(
1871d3
-            'example', '{{datarules|join(",")}}', {})
1871d3
-        data_rules = ['rule1', 'rule2']
1871d3
-        data_sources = []
1871d3
-        prepared = formatter._prepare_syntax_rule(
1871d3
-            syntax_rule, data_rules, 'example', data_sources)
1871d3
-
1871d3
-        assert prepared == 'rule1,rule2'
1871d3
-
1871d3
-
1871d3
-class test_FileRuleProvider:
1871d3
-    def test_rule_basic(self, rule_provider):
1871d3
-        rule_name = 'basic'
1871d3
-
1871d3
-        rule = rule_provider._rule(rule_name)
1871d3
-
1871d3
-        assert rule.template == 'openssl_rule'
1871d3
-
1871d3
-    def test_rule_global_options(self, rule_provider):
1871d3
-        rule_name = 'options'
1871d3
-
1871d3
-        rule = rule_provider._rule(rule_name)
1871d3
-
1871d3
-        assert rule.options['rule_option'] is True
1871d3
-
1871d3
-    def test_rule_nosuchrule(self, rule_provider):
1871d3
-        with pytest.raises(errors.NotFound):
1871d3
-            rule_provider._rule('nosuchrule')
1871d3
-
1871d3
-    def test_rules_for_profile_success(self, rule_provider):
1871d3
-        rules = rule_provider.rules_for_profile('profile')
1871d3
-
1871d3
-        assert len(rules) == 1
1871d3
-        field_mapping = rules[0]
1871d3
-        assert field_mapping.syntax_rule.name == 'basic'
1871d3
-        assert len(field_mapping.data_rules) == 1
1871d3
-        assert field_mapping.data_rules[0].name == 'options'
1871d3
-
1871d3
-    def test_rules_for_profile_nosuchprofile(self, rule_provider):
1871d3
-        with pytest.raises(errors.NotFound):
1871d3
-            rule_provider.rules_for_profile('nosuchprofile')
1871d3
-
1871d3
-
1871d3
-class test_CSRGenerator:
1871d3
-    def test_userCert_OpenSSL(self, generator):
1871d3
-        principal = {
1871d3
-            'uid': ['testuser'],
1871d3
-            'mail': ['testuser@example.com'],
1871d3
-        }
1871d3
-        config = {
1871d3
-            'ipacertificatesubjectbase': [
1871d3
-                'O=DOMAIN.EXAMPLE.COM'
1871d3
-            ],
1871d3
-        }
1871d3
-
1871d3
-        script = generator.csr_config(principal, config, 'userCert')
1871d3
-        with open(os.path.join(
1871d3
-                CSR_DATA_DIR, 'configs', 'userCert.conf')) as f:
1871d3
-            expected_script = f.read()
1871d3
-        assert script == expected_script
1871d3
-
1871d3
-    def test_caIPAserviceCert_OpenSSL(self, generator):
1871d3
-        principal = {
1871d3
-            'krbprincipalname': [
1871d3
-                'HTTP/machine.example.com@DOMAIN.EXAMPLE.COM'
1871d3
-            ],
1871d3
-        }
1871d3
-        config = {
1871d3
-            'ipacertificatesubjectbase': [
1871d3
-                'O=DOMAIN.EXAMPLE.COM'
1871d3
-            ],
1871d3
-        }
1871d3
-
1871d3
-        script = generator.csr_config(
1871d3
-            principal, config, 'caIPAserviceCert')
1871d3
-        with open(os.path.join(
1871d3
-                CSR_DATA_DIR, 'configs', 'caIPAserviceCert.conf')) as f:
1871d3
-            expected_script = f.read()
1871d3
-        assert script == expected_script
1871d3
-
1871d3
-    def test_works_with_lowercase_attr_type_shortname(self, generator):
1871d3
-        principal = {
1871d3
-            'uid': ['testuser'],
1871d3
-            'mail': ['testuser@example.com'],
1871d3
-        }
1871d3
-        template_env = {
1871d3
-            'ipacertificatesubjectbase': [
1871d3
-                'o=DOMAIN.EXAMPLE.COM'  # lower-case attr type shortname
1871d3
-            ],
1871d3
-        }
1871d3
-        config = generator.csr_config(principal, template_env, 'userCert')
1871d3
-
1871d3
-        key = rsa.generate_private_key(
1871d3
-            public_exponent=65537,
1871d3
-            key_size=2048,
1871d3
-            backend=default_backend(),
1871d3
-        )
1871d3
-        adaptor = csrgen.OpenSSLAdaptor(key=key)
1871d3
-
1871d3
-        reqinfo = bytes(csrgen_ffi.build_requestinfo(
1871d3
-            config.encode('utf-8'), adaptor.get_subject_public_key_info()))
1871d3
-        csr_der = adaptor.sign_csr(reqinfo)
1871d3
-        csr = x509.load_der_x509_csr(csr_der, default_backend())
1871d3
-        assert (
1871d3
-            csr.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)
1871d3
-            == [x509.NameAttribute(x509.NameOID.COMMON_NAME, u'testuser')]
1871d3
-        )
1871d3
-        assert (
1871d3
-            csr.subject.get_attributes_for_oid(x509.NameOID.ORGANIZATION_NAME)
1871d3
-            == [x509.NameAttribute(
1871d3
-                x509.NameOID.ORGANIZATION_NAME, u'DOMAIN.EXAMPLE.COM')]
1871d3
-        )
1871d3
-
1871d3
-    def test_unrecognised_attr_type_raises(self, generator):
1871d3
-        principal = {
1871d3
-            'uid': ['testuser'],
1871d3
-            'mail': ['testuser@example.com'],
1871d3
-        }
1871d3
-        template_env = {
1871d3
-            'ipacertificatesubjectbase': [
1871d3
-                'X=DOMAIN.EXAMPLE.COM'  # unrecognised attr type
1871d3
-            ],
1871d3
-        }
1871d3
-        config = generator.csr_config(principal, template_env, 'userCert')
1871d3
-
1871d3
-        key = rsa.generate_private_key(
1871d3
-            public_exponent=65537,
1871d3
-            key_size=2048,
1871d3
-            backend=default_backend(),
1871d3
-        )
1871d3
-        adaptor = csrgen.OpenSSLAdaptor(key=key)
1871d3
-
1871d3
-        with pytest.raises(
1871d3
-                errors.CSRTemplateError,
1871d3
-                match=r'^unrecognised attribute type: X$'):
1871d3
-            csrgen_ffi.build_requestinfo(
1871d3
-                config.encode('utf-8'), adaptor.get_subject_public_key_info())
1871d3
-
1871d3
-
1871d3
-class test_rule_handling:
1871d3
-    def test_optionalAttributeMissing(self, generator):
1871d3
-        principal = {'uid': 'testuser'}
1871d3
-        rule_provider = StubRuleProvider()
1871d3
-        rule_provider.data_rule.template = '{{subject.mail}}'
1871d3
-        rule_provider.data_rule.options = {'data_source': 'subject.mail'}
1871d3
-        generator = csrgen.CSRGenerator(
1871d3
-            rule_provider, formatter_class=IdentityFormatter)
1871d3
-
1871d3
-        script = generator.csr_config(
1871d3
-            principal, {}, 'example')
1871d3
-        assert script == '\n'
1871d3
-
1871d3
-    def test_twoDataRulesOneMissing(self, generator):
1871d3
-        principal = {'uid': 'testuser'}
1871d3
-        rule_provider = StubRuleProvider()
1871d3
-        rule_provider.data_rule.template = '{{subject.mail}}'
1871d3
-        rule_provider.data_rule.options = {'data_source': 'subject.mail'}
1871d3
-        rule_provider.field_mapping.data_rules.append(csrgen.Rule(
1871d3
-            'data2', '{{subject.uid}}', {'data_source': 'subject.uid'}))
1871d3
-        generator = csrgen.CSRGenerator(
1871d3
-            rule_provider, formatter_class=IdentityFormatter)
1871d3
-
1871d3
-        script = generator.csr_config(principal, {}, 'example')
1871d3
-        assert script == ',testuser\n'
1871d3
-
1871d3
-    def test_requiredAttributeMissing(self):
1871d3
-        principal = {'uid': 'testuser'}
1871d3
-        rule_provider = StubRuleProvider()
1871d3
-        rule_provider.data_rule.template = '{{subject.mail}}'
1871d3
-        rule_provider.data_rule.options = {'data_source': 'subject.mail'}
1871d3
-        rule_provider.syntax_rule.options = {'required': True}
1871d3
-        generator = csrgen.CSRGenerator(
1871d3
-            rule_provider, formatter_class=IdentityFormatter)
1871d3
-
1871d3
-        with pytest.raises(errors.CSRTemplateError):
1871d3
-            _script = generator.csr_config(
1871d3
-                principal, {}, 'example')