diff --git a/configure.ac b/configure.ac index 31bfa8aafce..4a3ba15a5c1 100644 --- a/configure.ac +++ b/configure.ac @@ -463,7 +463,6 @@ AC_CONFIG_FILES([ install/share/Makefile install/share/advise/Makefile install/share/advise/legacy/Makefile - install/share/csrgen/Makefile install/share/profiles/Makefile install/share/schema.d/Makefile install/ui/Makefile diff --git a/freeipa.spec.in b/freeipa.spec.in index d8602c905a5..2eadb7c8778 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -1229,13 +1229,6 @@ fi %{_usr}/share/ipa/advise/legacy/*.template %dir %{_usr}/share/ipa/profiles %{_usr}/share/ipa/profiles/*.cfg -%dir %{_usr}/share/ipa/csrgen -%dir %{_usr}/share/ipa/csrgen/templates -%{_usr}/share/ipa/csrgen/templates/*.tmpl -%dir %{_usr}/share/ipa/csrgen/profiles -%{_usr}/share/ipa/csrgen/profiles/*.json -%dir %{_usr}/share/ipa/csrgen/rules -%{_usr}/share/ipa/csrgen/rules/*.json %dir %{_usr}/share/ipa/html %{_usr}/share/ipa/html/ffconfig.js %{_usr}/share/ipa/html/ffconfig_page.js @@ -1362,6 +1355,9 @@ fi %{python_sitelib}/ipaclient/plugins/*.py* %{python_sitelib}/ipaclient/remote_plugins/*.py* %{python_sitelib}/ipaclient/remote_plugins/2_*/*.py* +%{python_sitelib}/ipaclient/csrgen/profiles/*.json +%{python_sitelib}/ipaclient/csrgen/rules/*.json +%{python_sitelib}/ipaclient/csrgen/templates/*.tmpl %{python_sitelib}/ipaclient-*.egg-info @@ -1382,6 +1378,9 @@ fi %{python3_sitelib}/ipaclient/remote_plugins/__pycache__/*.py* %{python3_sitelib}/ipaclient/remote_plugins/2_*/*.py %{python3_sitelib}/ipaclient/remote_plugins/2_*/__pycache__/*.py* +%{python3_sitelib}/ipaclient/csrgen/profiles/*.json +%{python3_sitelib}/ipaclient/csrgen/rules/*.json +%{python3_sitelib}/ipaclient/csrgen/templates/*.tmpl %{python3_sitelib}/ipaclient-*.egg-info %endif # with_python3 diff --git a/install/share/Makefile.am b/install/share/Makefile.am index bbf6ce10a15..1e8f0d57205 100644 --- a/install/share/Makefile.am +++ b/install/share/Makefile.am @@ -2,7 +2,6 @@ NULL = SUBDIRS = \ advise \ - csrgen \ profiles \ schema.d \ $(NULL) diff --git a/install/share/csrgen/Makefile.am b/install/share/csrgen/Makefile.am deleted file mode 100644 index 12c62c4d9d2..00000000000 --- a/install/share/csrgen/Makefile.am +++ /dev/null @@ -1,35 +0,0 @@ -NULL = - -profiledir = $(IPA_DATA_DIR)/csrgen/profiles -profile_DATA = \ - profiles/caIPAserviceCert.json \ - profiles/userCert.json \ - $(NULL) - -ruledir = $(IPA_DATA_DIR)/csrgen/rules -rule_DATA = \ - rules/dataDNS.json \ - rules/dataEmail.json \ - rules/dataHostCN.json \ - rules/dataUsernameCN.json \ - rules/dataSubjectBase.json \ - rules/syntaxSAN.json \ - rules/syntaxSubject.json \ - $(NULL) - -templatedir = $(IPA_DATA_DIR)/csrgen/templates -template_DATA = \ - templates/certutil_base.tmpl \ - templates/openssl_base.tmpl \ - templates/openssl_macros.tmpl \ - $(NULL) - -EXTRA_DIST = \ - $(profile_DATA) \ - $(rule_DATA) \ - $(template_DATA) \ - $(NULL) - -MAINTAINERCLEANFILES = \ - *~ \ - Makefile.in diff --git a/ipaclient/csrgen.py b/ipaclient/csrgen.py index 96100ae82f6..8fb0b32c054 100644 --- a/ipaclient/csrgen.py +++ b/ipaclient/csrgen.py @@ -3,19 +3,22 @@ # import collections +import errno import json import os.path import pipes import traceback +import pkg_resources + import jinja2 import jinja2.ext import jinja2.sandbox import six +from ipalib import api from ipalib import errors from ipalib.text import _ -from ipaplatform.paths import paths from ipapython.ipa_log_manager import log_mgr if six.PY3: @@ -72,10 +75,23 @@ class Formatter(object): """ base_template_name = None - def __init__(self, csr_data_dir=paths.CSR_DATA_DIR): + def __init__(self, csr_data_dir=None): + # chain loaders: + # 1) csr_data_dir/templates + # 2) /etc/ipa/csrgen/templates + # 3) ipaclient/csrgen/templates + loaders = [] + if csr_data_dir is not None: + loaders.append(jinja2.FileSystemLoader( + os.path.join(csr_data_dir, 'templates')) + ) + loaders.append(jinja2.FileSystemLoader( + os.path.join(api.env.confdir, 'csrgen/templates')) + ) + loaders.append(jinja2.PackageLoader('ipaclient', 'csrgen/templates')) + self.jinja2 = jinja2.sandbox.SandboxedEnvironment( - loader=jinja2.FileSystemLoader( - os.path.join(csr_data_dir, 'templates')), + loader=jinja2.ChoiceLoader(loaders), extensions=[jinja2.ext.ExprStmtExtension, IPAExtension], keep_trailing_newline=True, undefined=IndexableUndefined) @@ -277,17 +293,39 @@ def rules_for_profile(self, profile_id, helper): class FileRuleProvider(RuleProvider): - def __init__(self, csr_data_dir=paths.CSR_DATA_DIR): + def __init__(self, csr_data_dir=None): self.rules = {} - self.csr_data_dir = csr_data_dir + self._csrgen_data_dirs = [] + if csr_data_dir is not None: + self._csrgen_data_dirs.append(csr_data_dir) + self._csrgen_data_dirs.append( + os.path.join(api.env.confdir, 'csrgen') + ) + self._csrgen_data_dirs.append( + pkg_resources.resource_filename('ipaclient', 'csrgen') + ) + + def _open(self, subdir, filename): + for data_dir in self._csrgen_data_dirs: + path = os.path.join(data_dir, subdir, filename) + try: + return open(path) + except IOError as e: + if e.errno != errno.ENOENT: + raise + raise IOError( + errno.ENOENT, + "'{}' not found in {}".format( + os.path.join(subdir, filename), + ", ".join(self._csrgen_data_dirs) + ) + ) def _rule(self, rule_name, helper): if (rule_name, helper) not in self.rules: - rule_path = os.path.join(self.csr_data_dir, 'rules', - '%s.json' % rule_name) try: - with open(rule_path) as rule_file: - ruleset = json.load(rule_file) + with self._open('rules', '%s.json' % rule_name) as f: + ruleset = json.load(f) except IOError: raise errors.NotFound( reason=_('Ruleset %(ruleset)s does not exist.') % @@ -317,11 +355,9 @@ def _rule(self, rule_name, helper): return self.rules[(rule_name, helper)] def rules_for_profile(self, profile_id, helper): - profile_path = os.path.join(self.csr_data_dir, 'profiles', - '%s.json' % profile_id) try: - with open(profile_path) as profile_file: - profile = json.load(profile_file) + with self._open('profiles', '%s.json' % profile_id) as f: + profile = json.load(f) except IOError: raise errors.NotFound( reason=_('No CSR generation rules are defined for profile' diff --git a/install/share/csrgen/profiles/caIPAserviceCert.json b/ipaclient/csrgen/profiles/caIPAserviceCert.json similarity index 100% rename from install/share/csrgen/profiles/caIPAserviceCert.json rename to ipaclient/csrgen/profiles/caIPAserviceCert.json diff --git a/install/share/csrgen/profiles/userCert.json b/ipaclient/csrgen/profiles/userCert.json similarity index 100% rename from install/share/csrgen/profiles/userCert.json rename to ipaclient/csrgen/profiles/userCert.json diff --git a/install/share/csrgen/rules/dataDNS.json b/ipaclient/csrgen/rules/dataDNS.json similarity index 100% rename from install/share/csrgen/rules/dataDNS.json rename to ipaclient/csrgen/rules/dataDNS.json diff --git a/install/share/csrgen/rules/dataEmail.json b/ipaclient/csrgen/rules/dataEmail.json similarity index 100% rename from install/share/csrgen/rules/dataEmail.json rename to ipaclient/csrgen/rules/dataEmail.json diff --git a/install/share/csrgen/rules/dataHostCN.json b/ipaclient/csrgen/rules/dataHostCN.json similarity index 100% rename from install/share/csrgen/rules/dataHostCN.json rename to ipaclient/csrgen/rules/dataHostCN.json diff --git a/install/share/csrgen/rules/dataSubjectBase.json b/ipaclient/csrgen/rules/dataSubjectBase.json similarity index 100% rename from install/share/csrgen/rules/dataSubjectBase.json rename to ipaclient/csrgen/rules/dataSubjectBase.json diff --git a/install/share/csrgen/rules/dataUsernameCN.json b/ipaclient/csrgen/rules/dataUsernameCN.json similarity index 100% rename from install/share/csrgen/rules/dataUsernameCN.json rename to ipaclient/csrgen/rules/dataUsernameCN.json diff --git a/install/share/csrgen/rules/syntaxSAN.json b/ipaclient/csrgen/rules/syntaxSAN.json similarity index 100% rename from install/share/csrgen/rules/syntaxSAN.json rename to ipaclient/csrgen/rules/syntaxSAN.json diff --git a/install/share/csrgen/rules/syntaxSubject.json b/ipaclient/csrgen/rules/syntaxSubject.json similarity index 100% rename from install/share/csrgen/rules/syntaxSubject.json rename to ipaclient/csrgen/rules/syntaxSubject.json diff --git a/install/share/csrgen/templates/certutil_base.tmpl b/ipaclient/csrgen/templates/certutil_base.tmpl similarity index 100% rename from install/share/csrgen/templates/certutil_base.tmpl rename to ipaclient/csrgen/templates/certutil_base.tmpl diff --git a/install/share/csrgen/templates/openssl_base.tmpl b/ipaclient/csrgen/templates/openssl_base.tmpl similarity index 100% rename from install/share/csrgen/templates/openssl_base.tmpl rename to ipaclient/csrgen/templates/openssl_base.tmpl diff --git a/install/share/csrgen/templates/openssl_macros.tmpl b/ipaclient/csrgen/templates/openssl_macros.tmpl similarity index 100% rename from install/share/csrgen/templates/openssl_macros.tmpl rename to ipaclient/csrgen/templates/openssl_macros.tmpl diff --git a/ipaclient/setup.py b/ipaclient/setup.py index 93cb1e8fbfb..f5be7ea61f5 100644 --- a/ipaclient/setup.py +++ b/ipaclient/setup.py @@ -43,6 +43,13 @@ "ipaclient.remote_plugins.2_156", "ipaclient.remote_plugins.2_164", ], + package_data={ + 'ipaclient': [ + 'csrgen/profiles/*.json', + 'csrgen/rules/*.json', + 'csrgen/templates/*.tmpl', + ], + }, install_requires=[ "cryptography", "ipalib", @@ -56,5 +63,6 @@ extras_require={ "install": ["ipaplatform"], "otptoken_yubikey": ["yubico", "usb"] - } + }, + zip_safe=False, ) diff --git a/ipaplatform/base/paths.py b/ipaplatform/base/paths.py index e4d4f2edc76..de4ea23d3d0 100644 --- a/ipaplatform/base/paths.py +++ b/ipaplatform/base/paths.py @@ -238,7 +238,6 @@ class BasePathNamespace(object): SCHEMA_COMPAT_ULDIF = "/usr/share/ipa/schema_compat.uldif" IPA_JS_PLUGINS_DIR = "/usr/share/ipa/ui/js/plugins" UPDATES_DIR = "/usr/share/ipa/updates/" - CSR_DATA_DIR = "/usr/share/ipa/csrgen" DICT_WORDS = "/usr/share/dict/words" CACHE_IPA_SESSIONS = "/var/cache/ipa/sessions" VAR_KERBEROS_KRB5KDC_DIR = "/var/kerberos/krb5kdc/"