csrgen: Remove helper abstraction

All requests now use the OpenSSL formatter. However, we keep Formatter
a separate class so that it can be changed out for tests.

https://pagure.io/freeipa/issue/4899

Reviewed-By: Jan Cholasta <jcholast@redhat.com>
This commit is contained in:
Ben Lipton
2017-04-03 07:46:30 +00:00
committed by Jan Cholasta
parent 6c092c24b2
commit 5420e9cfbe
17 changed files with 75 additions and 253 deletions
+22 -45
View File
@@ -244,13 +244,6 @@ class OpenSSLFormatter(Formatter):
return self.SyntaxRule(prepared_template, is_extension)
class CertutilFormatter(Formatter):
base_template_name = 'certutil_base.tmpl'
def _get_template_params(self, syntax_rules):
return {'options': syntax_rules}
class FieldMapping(object):
"""Representation of the rules needed to construct a complete cert field.
@@ -279,13 +272,11 @@ class Rule(object):
class RuleProvider(object):
def rules_for_profile(self, profile_id, helper):
def rules_for_profile(self, profile_id):
"""
Return the rules needed to build a CSR using the given profile.
:param profile_id: str, name of the CSR generation profile to use
:param helper: str, name of tool (e.g. openssl, certutil) that will be
used to create CSR
:returns: list of FieldMapping, filled out with the appropriate rules
"""
@@ -321,40 +312,31 @@ class FileRuleProvider(RuleProvider):
)
)
def _rule(self, rule_name, helper):
if (rule_name, helper) not in self.rules:
def _rule(self, rule_name):
if rule_name not in self.rules:
try:
with self._open('rules', '%s.json' % rule_name) as f:
ruleset = json.load(f)
ruleconf = json.load(f)
except IOError:
raise errors.NotFound(
reason=_('Ruleset %(ruleset)s does not exist.') %
{'ruleset': rule_name})
reason=_('No generation rule %(rulename)s found.') %
{'rulename': rule_name})
matching_rules = [r for r in ruleset['rules']
if r['helper'] == helper]
if len(matching_rules) == 0:
try:
rule = ruleconf['rule']
except KeyError:
raise errors.EmptyResult(
reason=_('No transformation in "%(ruleset)s" rule supports'
' helper "%(helper)s"') %
{'ruleset': rule_name, 'helper': helper})
elif len(matching_rules) > 1:
raise errors.RedundantMappingRule(
ruleset=rule_name, helper=helper)
rule = matching_rules[0]
reason=_('Generation rule "%(rulename)s" is missing the'
' "rule" key') % {'rulename': rule_name})
options = {}
if 'options' in ruleset:
options.update(ruleset['options'])
if 'options' in rule:
options.update(rule['options'])
options = ruleconf.get('options', {})
self.rules[(rule_name, helper)] = Rule(
self.rules[rule_name] = Rule(
rule_name, rule['template'], options)
return self.rules[(rule_name, helper)]
return self.rules[rule_name]
def rules_for_profile(self, profile_id, helper):
def rules_for_profile(self, profile_id):
try:
with self._open('profiles', '%s.json' % profile_id) as f:
profile = json.load(f)
@@ -365,28 +347,23 @@ class FileRuleProvider(RuleProvider):
field_mappings = []
for field in profile:
syntax_rule = self._rule(field['syntax'], helper)
data_rules = [self._rule(name, helper) for name in field['data']]
syntax_rule = self._rule(field['syntax'])
data_rules = [self._rule(name) for name in field['data']]
field_mappings.append(FieldMapping(
syntax_rule.name, syntax_rule, data_rules))
return field_mappings
class CSRGenerator(object):
FORMATTERS = {
'openssl': OpenSSLFormatter,
'certutil': CertutilFormatter,
}
def __init__(self, rule_provider):
def __init__(self, rule_provider, formatter_class=OpenSSLFormatter):
self.rule_provider = rule_provider
self.formatter = formatter_class()
def csr_script(self, principal, config, profile_id, helper):
def csr_script(self, principal, config, profile_id):
render_data = {'subject': principal, 'config': config}
formatter = self.FORMATTERS[helper]()
rules = self.rule_provider.rules_for_profile(profile_id, helper)
template = formatter.build_template(rules)
rules = self.rule_provider.rules_for_profile(profile_id)
template = self.formatter.build_template(rules)
try:
script = template.render(render_data)
+3 -10
View File
@@ -1,14 +1,7 @@
{
"rules": [
{
"helper": "openssl",
"template": "DNS = {{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]}}"
},
{
"helper": "certutil",
"template": "dns:{{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]|quote}}"
}
],
"rule": {
"template": "DNS = {{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]}}"
},
"options": {
"data_source": "subject.krbprincipalname.0.partition('/')[2].partition('@')[0]"
}
+3 -10
View File
@@ -1,14 +1,7 @@
{
"rules": [
{
"helper": "openssl",
"template": "email = {{subject.mail.0}}"
},
{
"helper": "certutil",
"template": "email:{{subject.mail.0|quote}}"
}
],
"rule": {
"template": "email = {{subject.mail.0}}"
},
"options": {
"data_source": "subject.mail.0"
}
+3 -10
View File
@@ -1,14 +1,7 @@
{
"rules": [
{
"helper": "openssl",
"template": "CN={{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]}}"
},
{
"helper": "certutil",
"template": "CN={{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]|quote}}"
}
],
"rule": {
"template": "CN={{subject.krbprincipalname.0.partition('/')[2].partition('@')[0]}}"
},
"options": {
"data_source": "subject.krbprincipalname.0.partition('/')[2].partition('@')[0]"
}
+3 -10
View File
@@ -1,14 +1,7 @@
{
"rules": [
{
"helper": "openssl",
"template": "{{config.ipacertificatesubjectbase.0}}"
},
{
"helper": "certutil",
"template": "{{config.ipacertificatesubjectbase.0|quote}}"
}
],
"rule": {
"template": "{{config.ipacertificatesubjectbase.0}}"
},
"options": {
"data_source": "config.ipacertificatesubjectbase.0"
}
+3 -10
View File
@@ -1,14 +1,7 @@
{
"rules": [
{
"helper": "openssl",
"template": "CN={{subject.uid.0}}"
},
{
"helper": "certutil",
"template": "CN={{subject.uid.0|quote}}"
}
],
"rule": {
"template": "CN={{subject.uid.0}}"
},
"options": {
"data_source": "subject.uid.0"
}
+6 -13
View File
@@ -1,15 +1,8 @@
{
"rules": [
{
"helper": "openssl",
"template": "subjectAltName = @{% call openssl.section() %}{{ datarules|join('\n') }}{% endcall %}",
"options": {
"extension": true
}
},
{
"helper": "certutil",
"template": "--extSAN {{ datarules|join(',') }}"
}
]
"rule": {
"template": "subjectAltName = @{% call openssl.section() %}{{ datarules|join('\n') }}{% endcall %}"
},
"options": {
"extension": true
}
}
+3 -10
View File
@@ -1,14 +1,7 @@
{
"rules": [
{
"helper": "openssl",
"template": "distinguished_name = {% call openssl.section() %}{{ datarules|reverse|join('\n') }}{% endcall %}"
},
{
"helper": "certutil",
"template": "-s {{ datarules|join(',') }}"
}
],
"rule": {
"template": "distinguished_name = {% call openssl.section() %}{{ datarules|reverse|join('\n') }}{% endcall %}"
},
"options": {
"required": true,
"data_source_combinator": "and"
@@ -1,11 +0,0 @@
#!/bin/bash -e
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <outfile> [<any> <certutil> <args>]"
echo "Called as: $0 $@"
exit 1
fi
CSR="$1"
shift
certutil -R -a -z <(head -c 4096 /dev/urandom) -o "$CSR" {{ options|join(' ') }} "$@"
+1 -1
View File
@@ -106,7 +106,7 @@ class cert_get_requestdata(Local):
generator = CSRGenerator(FileRuleProvider())
script = generator.csr_script(
principal_obj, config, profile_id, helper)
principal_obj, config, profile_id)
result = {}
if 'out' in options: