pgreco / rpms / ipa

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