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