[Freeipa-devel] [freeipa PR#433][synchronized] csrgen: Allow some certificate fields to be specified by the user

2017-04-16 Thread LiptonB
   URL: https://github.com/freeipa/freeipa/pull/433
Author: LiptonB
 Title: #433: csrgen: Allow some certificate fields to be specified by the user
Action: synchronized

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/433/head:pr433
git checkout pr433
From bf80c8e7c5ae1e67a497b06819ef56bfedc4339a Mon Sep 17 00:00:00 2001
From: Ben Lipton 
Date: Thu, 28 Jul 2016 16:21:44 -0400
Subject: [PATCH 1/3] csrgen: Implement fields that prompt user for data

Allows some data to be user-specified rather than coming out of the
database. The provided data can be formatted with jinja2 rules just as
database values can.

https://fedorahosted.org/freeipa/ticket/4899
---
 ipaclient/csrgen.py| 35 --
 ipaclient/csrgen/rules/dataEmailUserSpecified.json | 16 ++
 ipaclient/plugins/csrgen.py| 10 +--
 ipatests/test_ipaclient/test_csrgen.py | 11 +++
 4 files changed, 63 insertions(+), 9 deletions(-)
 create mode 100644 ipaclient/csrgen/rules/dataEmailUserSpecified.json

diff --git a/ipaclient/csrgen.py b/ipaclient/csrgen.py
index 0f52a8b..67442f6 100644
--- a/ipaclient/csrgen.py
+++ b/ipaclient/csrgen.py
@@ -372,8 +372,9 @@ def __init__(self, rule_provider, formatter_class=OpenSSLFormatter):
 self.rule_provider = rule_provider
 self.formatter = formatter_class()
 
-def csr_config(self, principal, config, profile_id):
-render_data = {'subject': principal, 'config': config}
+def csr_config(self, principal, config, userdata, profile_id):
+render_data = {
+'subject': principal, 'config': config, 'userdata': userdata}
 
 rules = self.rule_provider.rules_for_profile(profile_id)
 template = self.formatter.build_template(rules)
@@ -387,6 +388,36 @@ def csr_config(self, principal, config, profile_id):
 
 return config
 
+def get_user_prompts(self, profile_id):
+prompts = {}
+rules = self.rule_provider.rules_for_profile(profile_id)
+
+for field_mapping in rules:
+for rule in field_mapping.data_rules:
+if 'prompt' in rule.options:
+try:
+var = rule.options['data_source']
+except KeyError:
+raise errors.CSRTemplateError(reason=_(
+'Certificate mapping rule %(rule)s has a prompt'
+' but no data_source set') % {'rule': rule.name})
+if var in prompts:
+raise errors.CSRTemplateError(reason=_(
+'More than one data rule in this profile prompts'
+' for the %(item)s data item') % {'item': var})
+var_parts = var.split('.')
+if len(var_parts) != 2 or var_parts[0] != 'userdata':
+raise errors.CSRTemplateError(
+reason=_(
+'Format of variable name in rule %(rule)s is'
+' incorrect. Rules that prompt for data must'
+' use a variable "userdata."') %
+{'rule': rule.name})
+
+prompts[var_parts[1]] = rule.options['prompt']
+
+return prompts
+
 
 class CSRLibraryAdaptor(object):
 def get_subject_public_key_info(self):
diff --git a/ipaclient/csrgen/rules/dataEmailUserSpecified.json b/ipaclient/csrgen/rules/dataEmailUserSpecified.json
new file mode 100644
index 000..3fb2fb1
--- /dev/null
+++ b/ipaclient/csrgen/rules/dataEmailUserSpecified.json
@@ -0,0 +1,16 @@
+{
+  "rules": [
+{
+  "helper": "openssl",
+  "template": "email = {{userdata.email}}"
+},
+{
+  "helper": "certutil",
+  "template": "email:{{userdata.email|quote}}"
+}
+  ],
+  "options": {
+"data_source": "userdata.email",
+"prompt": "Email address"
+  }
+}
diff --git a/ipaclient/plugins/csrgen.py b/ipaclient/plugins/csrgen.py
index 568a79f..6503f57 100644
--- a/ipaclient/plugins/csrgen.py
+++ b/ipaclient/plugins/csrgen.py
@@ -90,6 +90,9 @@ def execute(self, *args, **options):
 if not backend.isconnected():
 backend.connect()
 
+generator = csrgen.CSRGenerator(csrgen.FileRuleProvider())
+prompts = generator.get_user_prompts(profile_id, helper)
+
 try:
 if principal.is_host:
 principal_obj = api.Command.host_show(
@@ -106,9 +109,12 @@ def execute(self, *args, **options):
 principal_obj = principal_obj['result']
 config = api.Command.config_show()['result']
 
-generator = csrgen.CSRGenerator(csrgen.FileRuleProvider())
+userdata = {}
+for name, prompt in prompts.items():
+userdata[name] = self.Backend.textui.prompt(prompt)
 
-

[Freeipa-devel] [freeipa PR#433][synchronized] csrgen: Allow some certificate fields to be specified by the user

2017-03-15 Thread LiptonB
   URL: https://github.com/freeipa/freeipa/pull/433
Author: LiptonB
 Title: #433: csrgen: Allow some certificate fields to be specified by the user
Action: synchronized

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/433/head:pr433
git checkout pr433
From 61a825b57f923ca7b641bca5f436d4b41f3acfb8 Mon Sep 17 00:00:00 2001
From: Ben Lipton 
Date: Thu, 28 Jul 2016 16:21:44 -0400
Subject: [PATCH 1/3] csrgen: Implement fields that prompt user for data

Allows some data to be user-specified rather than coming out of the
database. The provided data can be formatted with jinja2 rules just as
database values can.

https://fedorahosted.org/freeipa/ticket/4899
---
 ipaclient/csrgen.py| 35 --
 ipaclient/csrgen/rules/dataEmailUserSpecified.json | 16 ++
 ipaclient/plugins/csrgen.py|  9 --
 ipatests/test_ipaclient/test_csrgen.py | 15 +-
 4 files changed, 64 insertions(+), 11 deletions(-)
 create mode 100644 ipaclient/csrgen/rules/dataEmailUserSpecified.json

diff --git a/ipaclient/csrgen.py b/ipaclient/csrgen.py
index 8fb0b32..41a4352 100644
--- a/ipaclient/csrgen.py
+++ b/ipaclient/csrgen.py
@@ -381,8 +381,9 @@ class CSRGenerator(object):
 def __init__(self, rule_provider):
 self.rule_provider = rule_provider
 
-def csr_script(self, principal, config, profile_id, helper):
-render_data = {'subject': principal, 'config': config}
+def csr_script(self, principal, config, userdata, profile_id, helper):
+render_data = {
+'subject': principal, 'config': config, 'userdata': userdata}
 
 formatter = self.FORMATTERS[helper]()
 rules = self.rule_provider.rules_for_profile(profile_id, helper)
@@ -396,3 +397,33 @@ def csr_script(self, principal, config, profile_id, helper):
 'Template error when formatting certificate data'))
 
 return script
+
+def get_user_prompts(self, profile_id, helper):
+prompts = {}
+rules = self.rule_provider.rules_for_profile(profile_id, helper)
+
+for field_mapping in rules:
+for rule in field_mapping.data_rules:
+if 'prompt' in rule.options:
+try:
+var = rule.options['data_source']
+except KeyError:
+raise errors.CSRTemplateError(reason=_(
+'Certificate mapping rule %(rule)s has a prompt'
+' but no data_source set') % {'rule': rule.name})
+if var in prompts:
+raise errors.CSRTemplateError(reason=_(
+'More than one data rule in this profile prompts'
+' for the %(item)s data item') % {'item': var})
+var_parts = var.split('.')
+if len(var_parts) != 2 or var_parts[0] != 'userdata':
+raise errors.CSRTemplateError(
+reason=_(
+'Format of variable name in rule %(rule)s is'
+' incorrect. Rules that prompt for data must'
+' use a variable "userdata."') %
+{'rule': rule.name})
+
+prompts[var_parts[1]] = rule.options['prompt']
+
+return prompts
diff --git a/ipaclient/csrgen/rules/dataEmailUserSpecified.json b/ipaclient/csrgen/rules/dataEmailUserSpecified.json
new file mode 100644
index 000..3fb2fb1
--- /dev/null
+++ b/ipaclient/csrgen/rules/dataEmailUserSpecified.json
@@ -0,0 +1,16 @@
+{
+  "rules": [
+{
+  "helper": "openssl",
+  "template": "email = {{userdata.email}}"
+},
+{
+  "helper": "certutil",
+  "template": "email:{{userdata.email|quote}}"
+}
+  ],
+  "options": {
+"data_source": "userdata.email",
+"prompt": "Email address"
+  }
+}
diff --git a/ipaclient/plugins/csrgen.py b/ipaclient/plugins/csrgen.py
index a0d99ef..0cc67f7 100644
--- a/ipaclient/plugins/csrgen.py
+++ b/ipaclient/plugins/csrgen.py
@@ -87,6 +87,9 @@ def execute(self, *args, **options):
 if not backend.isconnected():
 backend.connect()
 
+generator = CSRGenerator(FileRuleProvider())
+prompts = generator.get_user_prompts(profile_id, helper)
+
 try:
 if principal.is_host:
 principal_obj = api.Command.host_show(
@@ -103,10 +106,12 @@ def execute(self, *args, **options):
 principal_obj = principal_obj['result']
 config = api.Command.config_show()['result']
 
-generator = CSRGenerator(FileRuleProvider())
+userdata = {}
+for name, prompt in prompts.items():
+userdata[name] = self.Backend.textui.prompt(prompt)
 
 script = generator.csr_script(
-

[Freeipa-devel] [freeipa PR#433][synchronized] csrgen: Allow some certificate fields to be specified by the user

2017-03-06 Thread LiptonB
   URL: https://github.com/freeipa/freeipa/pull/433
Author: LiptonB
 Title: #433: csrgen: Allow some certificate fields to be specified by the user
Action: synchronized

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/433/head:pr433
git checkout pr433
From 3da67abcba6af0409a1195efd60581f6b28ad217 Mon Sep 17 00:00:00 2001
From: Ben Lipton 
Date: Thu, 28 Jul 2016 16:21:44 -0400
Subject: [PATCH 1/3] csrgen: Implement fields that prompt user for data

Allows some data to be user-specified rather than coming out of the
database. The provided data can be formatted with jinja2 rules just as
database values can.

https://fedorahosted.org/freeipa/ticket/4899
---
 install/share/csrgen/Makefile.am   |  1 +
 .../share/csrgen/rules/dataEmailUserSpecified.json | 16 ++
 ipaclient/csrgen.py| 35 --
 ipaclient/plugins/csrgen.py|  9 --
 ipatests/test_ipaclient/test_csrgen.py | 15 +-
 5 files changed, 65 insertions(+), 11 deletions(-)
 create mode 100644 install/share/csrgen/rules/dataEmailUserSpecified.json

diff --git a/install/share/csrgen/Makefile.am b/install/share/csrgen/Makefile.am
index 12c62c4..ad4412e 100644
--- a/install/share/csrgen/Makefile.am
+++ b/install/share/csrgen/Makefile.am
@@ -10,6 +10,7 @@ ruledir = $(IPA_DATA_DIR)/csrgen/rules
 rule_DATA =\
 	rules/dataDNS.json		\
 	rules/dataEmail.json		\
+	rules/dataEmailUserSpecified.json	\
 	rules/dataHostCN.json		\
 	rules/dataUsernameCN.json	\
 	rules/dataSubjectBase.json	\
diff --git a/install/share/csrgen/rules/dataEmailUserSpecified.json b/install/share/csrgen/rules/dataEmailUserSpecified.json
new file mode 100644
index 000..3fb2fb1
--- /dev/null
+++ b/install/share/csrgen/rules/dataEmailUserSpecified.json
@@ -0,0 +1,16 @@
+{
+  "rules": [
+{
+  "helper": "openssl",
+  "template": "email = {{userdata.email}}"
+},
+{
+  "helper": "certutil",
+  "template": "email:{{userdata.email|quote}}"
+}
+  ],
+  "options": {
+"data_source": "userdata.email",
+"prompt": "Email address"
+  }
+}
diff --git a/ipaclient/csrgen.py b/ipaclient/csrgen.py
index 96100ae..f00cc10 100644
--- a/ipaclient/csrgen.py
+++ b/ipaclient/csrgen.py
@@ -345,8 +345,9 @@ class CSRGenerator(object):
 def __init__(self, rule_provider):
 self.rule_provider = rule_provider
 
-def csr_script(self, principal, config, profile_id, helper):
-render_data = {'subject': principal, 'config': config}
+def csr_script(self, principal, config, userdata, profile_id, helper):
+render_data = {
+'subject': principal, 'config': config, 'userdata': userdata}
 
 formatter = self.FORMATTERS[helper]()
 rules = self.rule_provider.rules_for_profile(profile_id, helper)
@@ -360,3 +361,33 @@ def csr_script(self, principal, config, profile_id, helper):
 'Template error when formatting certificate data'))
 
 return script
+
+def get_user_prompts(self, profile_id, helper):
+prompts = {}
+rules = self.rule_provider.rules_for_profile(profile_id, helper)
+
+for field_mapping in rules:
+for rule in field_mapping.data_rules:
+if 'prompt' in rule.options:
+try:
+var = rule.options['data_source']
+except KeyError:
+raise errors.CSRTemplateError(reason=_(
+'Certificate mapping rule %(rule)s has a prompt'
+' but no data_source set') % {'rule': rule.name})
+if var in prompts:
+raise errors.CSRTemplateError(reason=_(
+'More than one data rule in this profile prompts'
+' for the %(item)s data item') % {'item': var})
+var_parts = var.split('.')
+if len(var_parts) != 2 or var_parts[0] != 'userdata':
+raise errors.CSRTemplateError(
+reason=_(
+'Format of variable name in rule %(rule)s is'
+' incorrect. Rules that prompt for data must'
+' use a variable "userdata."') %
+{'rule': rule.name})
+
+prompts[var_parts[1]] = rule.options['prompt']
+
+return prompts
diff --git a/ipaclient/plugins/csrgen.py b/ipaclient/plugins/csrgen.py
index 0d6eca0..e8563e5 100644
--- a/ipaclient/plugins/csrgen.py
+++ b/ipaclient/plugins/csrgen.py
@@ -85,6 +85,9 @@ def execute(self, *args, **options):
 if not backend.isconnected():
 backend.connect()
 
+generator = CSRGenerator(FileRuleProvider())
+prompts = generator.get_user_prompts(profile_id, helper)
+
 

[Freeipa-devel] [freeipa PR#433][synchronized] csrgen: Allow some certificate fields to be specified by the user

2017-02-08 Thread LiptonB
   URL: https://github.com/freeipa/freeipa/pull/433
Author: LiptonB
 Title: #433: csrgen: Allow some certificate fields to be specified by the user
Action: synchronized

To pull the PR as Git branch:
git remote add ghfreeipa https://github.com/freeipa/freeipa
git fetch ghfreeipa pull/433/head:pr433
git checkout pr433
From 96f4e25a4770bd2076390301adcee53d55086fa2 Mon Sep 17 00:00:00 2001
From: Ben Lipton 
Date: Thu, 28 Jul 2016 16:21:44 -0400
Subject: [PATCH 1/5] csrgen: Implement fields that prompt user for data

Allows some data to be user-specified rather than coming out of the
database. The provided data can be formatted with jinja2 rules just as
database values can.

https://fedorahosted.org/freeipa/ticket/4899
---
 install/share/csrgen/Makefile.am   |  1 +
 .../share/csrgen/rules/dataEmailUserSpecified.json | 16 ++
 ipaclient/csrgen.py| 36 --
 ipaclient/plugins/csrgen.py|  9 --
 ipatests/test_ipaclient/test_csrgen.py | 15 -
 5 files changed, 66 insertions(+), 11 deletions(-)
 create mode 100644 install/share/csrgen/rules/dataEmailUserSpecified.json

diff --git a/install/share/csrgen/Makefile.am b/install/share/csrgen/Makefile.am
index 12c62c4..ad4412e 100644
--- a/install/share/csrgen/Makefile.am
+++ b/install/share/csrgen/Makefile.am
@@ -10,6 +10,7 @@ ruledir = $(IPA_DATA_DIR)/csrgen/rules
 rule_DATA =\
 	rules/dataDNS.json		\
 	rules/dataEmail.json		\
+	rules/dataEmailUserSpecified.json	\
 	rules/dataHostCN.json		\
 	rules/dataUsernameCN.json	\
 	rules/dataSubjectBase.json	\
diff --git a/install/share/csrgen/rules/dataEmailUserSpecified.json b/install/share/csrgen/rules/dataEmailUserSpecified.json
new file mode 100644
index 000..3fb2fb1
--- /dev/null
+++ b/install/share/csrgen/rules/dataEmailUserSpecified.json
@@ -0,0 +1,16 @@
+{
+  "rules": [
+{
+  "helper": "openssl",
+  "template": "email = {{userdata.email}}"
+},
+{
+  "helper": "certutil",
+  "template": "email:{{userdata.email|quote}}"
+}
+  ],
+  "options": {
+"data_source": "userdata.email",
+"prompt": "Email address"
+  }
+}
diff --git a/ipaclient/csrgen.py b/ipaclient/csrgen.py
index 96100ae..2c1c5fc 100644
--- a/ipaclient/csrgen.py
+++ b/ipaclient/csrgen.py
@@ -345,8 +345,9 @@ class CSRGenerator(object):
 def __init__(self, rule_provider):
 self.rule_provider = rule_provider
 
-def csr_script(self, principal, config, profile_id, helper):
-render_data = {'subject': principal, 'config': config}
+def csr_script(self, principal, config, userdata, profile_id, helper):
+render_data = {
+'subject': principal, 'config': config, 'userdata': userdata}
 
 formatter = self.FORMATTERS[helper]()
 rules = self.rule_provider.rules_for_profile(profile_id, helper)
@@ -360,3 +361,34 @@ def csr_script(self, principal, config, profile_id, helper):
 'Template error when formatting certificate data'))
 
 return script
+
+def get_user_prompts(self, profile_id, helper):
+prompts = {}
+syntax_rules = []
+rules = self.rule_provider.rules_for_profile(profile_id, helper)
+
+for field_mapping in rules:
+for rule in field_mapping.data_rules:
+if 'prompt' in rule.options:
+try:
+var = rule.options['data_source']
+except KeyError:
+raise errors.CertificateMappingError(reason=_(
+'Certificate mapping rule %(rule)s has a prompt'
+' but no data_source set') % {'rule': rule.name})
+if var in prompts:
+raise errors.CertificateMappingError(reason=_(
+'More than one data rule in this profile prompts'
+' for the %(item)s data item') % {'item': var})
+var_parts = var.split('.')
+if len(var_parts) != 2 or var_parts[0] != 'userdata':
+raise errors.CertificateMappingError(
+reason=_(
+'Format of variable name in rule %(rule)s is'
+' incorrect. Rules that prompt for data must'
+' use a variable "userdata."') %
+{'rule': rule.name})
+
+prompts[var_parts[1]] = rule.options['prompt']
+
+return prompts
diff --git a/ipaclient/plugins/csrgen.py b/ipaclient/plugins/csrgen.py
index 0669a47..d480946 100644
--- a/ipaclient/plugins/csrgen.py
+++ b/ipaclient/plugins/csrgen.py
@@ -82,6 +82,9 @@ def execute(self, *args, **options):
 if not backend.isconnected():
 backend.connect()
 
+generator = CSRGenerator(FileRuleProvider())
+prompts =