From 499da29e27fdf7f4ab414352df63c770b40ce6fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Nowak?= <luke@nexedi.com> Date: Mon, 29 Aug 2011 16:33:42 +0200 Subject: [PATCH] Implement ERP5 Certificate Authority. ERP5 Certificate Authority is simple tool to manage SSL certificates related with various documents. By default it provides user interface for Person getting and revocation of certificates. It comes from Vifib project code. --- .../portal_types/Person/get_certificate.xml | 85 ++++++ .../Person/revoke_certificate.xml | 85 ++++++ .../DocumentTemplateItem/Person.py | 38 +++ .../erp5_certificate_authority.xml | 32 ++ .../Person_getCertificate.xml | 71 +++++ .../Person_getCertificateForm.xml | 155 ++++++++++ .../your_certificate.xml | 280 +++++++++++++++++ .../Person_getCertificateForm/your_key.xml | 280 +++++++++++++++++ .../Person_getCertificateForm/your_tip.xml | 282 ++++++++++++++++++ .../Person_revokeCertificate.xml | 68 +++++ .../portal_certificate_authority.xml | 41 +++ bt5/erp5_certificate_authority/bt/change_log | 2 + .../bt/copyright_list | 1 + .../bt/dependency_list | 1 + bt5/erp5_certificate_authority/bt/description | 1 + bt5/erp5_certificate_authority/bt/license | 1 + .../bt/maintainer_list | 1 + bt5/erp5_certificate_authority/bt/revision | 1 + .../bt/template_action_path_list | 2 + .../bt/template_document_id_list | 1 + .../bt/template_format_version | 1 + .../bt/template_skin_id_list | 1 + .../bt/template_tool_id_list | 1 + bt5/erp5_certificate_authority/bt/title | 1 + bt5/erp5_certificate_authority/bt/version | 1 + product/ERP5/Tool/CertificateAuthorityTool.py | 280 +++++++++++++++++ product/ERP5/__init__.py | 4 +- .../tests/testCertificateAuthorityTool.py | 107 +++++++ ...tificateAuthorityTool_editPropertyList.zpt | 37 +++ 29 files changed, 1860 insertions(+), 1 deletion(-) create mode 100644 bt5/erp5_certificate_authority/ActionTemplateItem/portal_types/Person/get_certificate.xml create mode 100644 bt5/erp5_certificate_authority/ActionTemplateItem/portal_types/Person/revoke_certificate.xml create mode 100644 bt5/erp5_certificate_authority/DocumentTemplateItem/Person.py create mode 100644 bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority.xml create mode 100644 bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificate.xml create mode 100644 bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm.xml create mode 100644 bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm/your_certificate.xml create mode 100644 bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm/your_key.xml create mode 100644 bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm/your_tip.xml create mode 100644 bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_revokeCertificate.xml create mode 100644 bt5/erp5_certificate_authority/ToolTemplateItem/portal_certificate_authority.xml create mode 100644 bt5/erp5_certificate_authority/bt/change_log create mode 100644 bt5/erp5_certificate_authority/bt/copyright_list create mode 100644 bt5/erp5_certificate_authority/bt/dependency_list create mode 100644 bt5/erp5_certificate_authority/bt/description create mode 100644 bt5/erp5_certificate_authority/bt/license create mode 100644 bt5/erp5_certificate_authority/bt/maintainer_list create mode 100644 bt5/erp5_certificate_authority/bt/revision create mode 100644 bt5/erp5_certificate_authority/bt/template_action_path_list create mode 100644 bt5/erp5_certificate_authority/bt/template_document_id_list create mode 100644 bt5/erp5_certificate_authority/bt/template_format_version create mode 100644 bt5/erp5_certificate_authority/bt/template_skin_id_list create mode 100644 bt5/erp5_certificate_authority/bt/template_tool_id_list create mode 100644 bt5/erp5_certificate_authority/bt/title create mode 100644 bt5/erp5_certificate_authority/bt/version create mode 100644 product/ERP5/Tool/CertificateAuthorityTool.py create mode 100644 product/ERP5/tests/testCertificateAuthorityTool.py create mode 100644 product/ERP5/www/CertificateAuthorityTool_editPropertyList.zpt diff --git a/bt5/erp5_certificate_authority/ActionTemplateItem/portal_types/Person/get_certificate.xml b/bt5/erp5_certificate_authority/ActionTemplateItem/portal_types/Person/get_certificate.xml new file mode 100644 index 0000000000..42f2bc1651 --- /dev/null +++ b/bt5/erp5_certificate_authority/ActionTemplateItem/portal_types/Person/get_certificate.xml @@ -0,0 +1,85 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="ActionInformation" module="Products.CMFCore.ActionInformation"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>action</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> + </value> + </item> + <item> + <key> <string>categories</string> </key> + <value> + <tuple> + <string>action_type/object_action</string> + </tuple> + </value> + </item> + <item> + <key> <string>category</string> </key> + <value> <string>object_action</string> </value> + </item> + <item> + <key> <string>condition</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>icon</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>get_certificate</string> </value> + </item> + <item> + <key> <string>permissions</string> </key> + <value> + <tuple> + <string>Modify portal content</string> + </tuple> + </value> + </item> + <item> + <key> <string>portal_type</string> </key> + <value> <string>Action Information</string> </value> + </item> + <item> + <key> <string>priority</string> </key> + <value> <float>10.0</float> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string>Get Certificate</string> </value> + </item> + <item> + <key> <string>visible</string> </key> + <value> <int>1</int> </value> + </item> + </dictionary> + </pickle> + </record> + <record id="2" aka="AAAAAAAAAAI="> + <pickle> + <global name="Expression" module="Products.CMFCore.Expression"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>text</string> </key> + <value> <string>string:${object_url}/Person_getCertificate</string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_certificate_authority/ActionTemplateItem/portal_types/Person/revoke_certificate.xml b/bt5/erp5_certificate_authority/ActionTemplateItem/portal_types/Person/revoke_certificate.xml new file mode 100644 index 0000000000..d81f574a00 --- /dev/null +++ b/bt5/erp5_certificate_authority/ActionTemplateItem/portal_types/Person/revoke_certificate.xml @@ -0,0 +1,85 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="ActionInformation" module="Products.CMFCore.ActionInformation"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>action</string> </key> + <value> + <persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent> + </value> + </item> + <item> + <key> <string>categories</string> </key> + <value> + <tuple> + <string>action_type/object_action</string> + </tuple> + </value> + </item> + <item> + <key> <string>category</string> </key> + <value> <string>object_action</string> </value> + </item> + <item> + <key> <string>condition</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> + <none/> + </value> + </item> + <item> + <key> <string>icon</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>revoke_certificate</string> </value> + </item> + <item> + <key> <string>permissions</string> </key> + <value> + <tuple> + <string>Modify portal content</string> + </tuple> + </value> + </item> + <item> + <key> <string>portal_type</string> </key> + <value> <string>Action Information</string> </value> + </item> + <item> + <key> <string>priority</string> </key> + <value> <float>11.0</float> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string>Revoke Certificate</string> </value> + </item> + <item> + <key> <string>visible</string> </key> + <value> <int>1</int> </value> + </item> + </dictionary> + </pickle> + </record> + <record id="2" aka="AAAAAAAAAAI="> + <pickle> + <global name="Expression" module="Products.CMFCore.Expression"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>text</string> </key> + <value> <string>string:${object_url}/Person_revokeCertificate</string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_certificate_authority/DocumentTemplateItem/Person.py b/bt5/erp5_certificate_authority/DocumentTemplateItem/Person.py new file mode 100644 index 0000000000..aa92e7d60a --- /dev/null +++ b/bt5/erp5_certificate_authority/DocumentTemplateItem/Person.py @@ -0,0 +1,38 @@ +from AccessControl import ClassSecurityInfo, Unauthorized, getSecurityManager +from Products.ERP5.Document.Person import Person as ERP5Person + +class Person(ERP5Person): + security = ClassSecurityInfo() + security.declarePublic('getCertificate') + + def _checkCertificateRequest(self): + try: + self.checkUserCanChangePassword() + except Unauthorized: + # in ERP5 user has no SetOwnPassword permission on Person document + # referring himself, so implement "security" by checking that currently + # logged in user is trying to get/revoke his own certificate + reference = self.getReference() + if not reference: + raise + if getSecurityManager().getUser().getId() != reference: + raise + + def _getCertificate(self): + return self.getPortalObject().portal_certificate_authority\ + .getNewCertificate(self.getReference()) + + def _revokeCertificate(self): + return self.getPortalObject().portal_certificate_authority\ + .revokeCertificateByCommonName(self.getReference()) + + def getCertificate(self): + """Returns new SSL certificate""" + self._checkCertificateRequest() + return self._getCertificate() + + security.declarePublic('revokeCertificate') + def revokeCertificate(self): + """Revokes existing certificate""" + self._checkCertificateRequest() + self._revokeCertificate() diff --git a/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority.xml b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority.xml new file mode 100644 index 0000000000..08b7fc706b --- /dev/null +++ b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority.xml @@ -0,0 +1,32 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="Folder" module="OFS.Folder"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_local_properties</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>_objects</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>erp5_certificate_authority</string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificate.xml b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificate.xml new file mode 100644 index 0000000000..3960836eaa --- /dev/null +++ b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificate.xml @@ -0,0 +1,71 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="PythonScript" module="Products.PythonScripts.PythonScript"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>Script_magic</string> </key> + <value> <int>3</int> </value> + </item> + <item> + <key> <string>_bind_names</string> </key> + <value> + <object> + <klass> + <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/> + </klass> + <tuple/> + <state> + <dictionary> + <item> + <key> <string>_asgns</string> </key> + <value> + <dictionary> + <item> + <key> <string>name_container</string> </key> + <value> <string>container</string> </value> + </item> + <item> + <key> <string>name_context</string> </key> + <value> <string>context</string> </value> + </item> + <item> + <key> <string>name_m_self</string> </key> + <value> <string>script</string> </value> + </item> + <item> + <key> <string>name_subpath</string> </key> + <value> <string>traverse_subpath</string> </value> + </item> + </dictionary> + </value> + </item> + </dictionary> + </state> + </object> + </value> + </item> + <item> + <key> <string>_body</string> </key> + <value> <string>certificate = context.getCertificate()\n +request = context.REQUEST\n +request.set(\'your_certificate\', certificate[\'certificate\'])\n +request.set(\'your_key\', certificate[\'key\'])\n +return context.Person_getCertificateForm()\n +</string> </value> + </item> + <item> + <key> <string>_params</string> </key> + <value> <string>dialog_id=None, form_id=None, **kw</string> </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>Person_getCertificate</string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm.xml b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm.xml new file mode 100644 index 0000000000..e44abacf7b --- /dev/null +++ b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm.xml @@ -0,0 +1,155 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="ERP5Form" module="Products.ERP5Form.Form"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_bind_names</string> </key> + <value> + <object> + <klass> + <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/> + </klass> + <tuple/> + <state> + <dictionary> + <item> + <key> <string>_asgns</string> </key> + <value> + <dictionary/> + </value> + </item> + </dictionary> + </state> + </object> + </value> + </item> + <item> + <key> <string>_objects</string> </key> + <value> + <tuple/> + </value> + </item> + <item> + <key> <string>action</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>edit_order</string> </key> + <value> + <list/> + </value> + </item> + <item> + <key> <string>encoding</string> </key> + <value> <string>UTF-8</string> </value> + </item> + <item> + <key> <string>enctype</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>group_list</string> </key> + <value> + <list> + <string>left</string> + <string>right</string> + <string>center</string> + <string>bottom</string> + <string>hidden</string> + </list> + </value> + </item> + <item> + <key> <string>groups</string> </key> + <value> + <dictionary> + <item> + <key> <string>bottom</string> </key> + <value> + <list/> + </value> + </item> + <item> + <key> <string>center</string> </key> + <value> + <list> + <string>your_certificate</string> + <string>your_key</string> + </list> + </value> + </item> + <item> + <key> <string>hidden</string> </key> + <value> + <list/> + </value> + </item> + <item> + <key> <string>left</string> </key> + <value> + <list> + <string>your_tip</string> + </list> + </value> + </item> + <item> + <key> <string>right</string> </key> + <value> + <list/> + </value> + </item> + </dictionary> + </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>Person_getCertificateForm</string> </value> + </item> + <item> + <key> <string>method</string> </key> + <value> <string>POST</string> </value> + </item> + <item> + <key> <string>name</string> </key> + <value> <string>Person_getCertificateForm</string> </value> + </item> + <item> + <key> <string>pt</string> </key> + <value> <string>form_dialog</string> </value> + </item> + <item> + <key> <string>row_length</string> </key> + <value> <int>4</int> </value> + </item> + <item> + <key> <string>stored_encoding</string> </key> + <value> <string>UTF-8</string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string>Certificate Request</string> </value> + </item> + <item> + <key> <string>unicode_mode</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>update_action</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>update_action_title</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm/your_certificate.xml b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm/your_certificate.xml new file mode 100644 index 0000000000..9342d207c0 --- /dev/null +++ b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm/your_certificate.xml @@ -0,0 +1,280 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="TextAreaField" module="Products.Formulator.StandardFields"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>id</string> </key> + <value> <string>your_certificate</string> </value> + </item> + <item> + <key> <string>message_values</string> </key> + <value> + <dictionary> + <item> + <key> <string>external_validator_failed</string> </key> + <value> <string>The input failed the external validator.</string> </value> + </item> + <item> + <key> <string>line_too_long</string> </key> + <value> <string>A line was too long.</string> </value> + </item> + <item> + <key> <string>required_not_found</string> </key> + <value> <string>Input is required but no input given.</string> </value> + </item> + <item> + <key> <string>too_long</string> </key> + <value> <string>You entered too many characters.</string> </value> + </item> + <item> + <key> <string>too_many_lines</string> </key> + <value> <string>You entered too many lines.</string> </value> + </item> + </dictionary> + </value> + </item> + <item> + <key> <string>overrides</string> </key> + <value> + <dictionary> + <item> + <key> <string>alternate_name</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>css_class</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>default</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>editable</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>enabled</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>external_validator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>extra</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>hidden</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_length</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_linelength</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_lines</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>required</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>unicode</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>whitespace_preserve</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </value> + </item> + <item> + <key> <string>tales</string> </key> + <value> + <dictionary> + <item> + <key> <string>alternate_name</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>css_class</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>default</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>editable</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>enabled</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>external_validator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>extra</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>hidden</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_length</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_linelength</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_lines</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>required</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>unicode</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>whitespace_preserve</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </value> + </item> + <item> + <key> <string>values</string> </key> + <value> + <dictionary> + <item> + <key> <string>alternate_name</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>css_class</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>default</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>editable</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>enabled</string> </key> + <value> <int>1</int> </value> + </item> + <item> + <key> <string>external_validator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>extra</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <int>5</int> </value> + </item> + <item> + <key> <string>hidden</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>max_length</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_linelength</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_lines</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>required</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string>Certificate</string> </value> + </item> + <item> + <key> <string>unicode</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>whitespace_preserve</string> </key> + <value> <int>1</int> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <int>40</int> </value> + </item> + </dictionary> + </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm/your_key.xml b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm/your_key.xml new file mode 100644 index 0000000000..bcaa2fe860 --- /dev/null +++ b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm/your_key.xml @@ -0,0 +1,280 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="TextAreaField" module="Products.Formulator.StandardFields"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>id</string> </key> + <value> <string>your_key</string> </value> + </item> + <item> + <key> <string>message_values</string> </key> + <value> + <dictionary> + <item> + <key> <string>external_validator_failed</string> </key> + <value> <string>The input failed the external validator.</string> </value> + </item> + <item> + <key> <string>line_too_long</string> </key> + <value> <string>A line was too long.</string> </value> + </item> + <item> + <key> <string>required_not_found</string> </key> + <value> <string>Input is required but no input given.</string> </value> + </item> + <item> + <key> <string>too_long</string> </key> + <value> <string>You entered too many characters.</string> </value> + </item> + <item> + <key> <string>too_many_lines</string> </key> + <value> <string>You entered too many lines.</string> </value> + </item> + </dictionary> + </value> + </item> + <item> + <key> <string>overrides</string> </key> + <value> + <dictionary> + <item> + <key> <string>alternate_name</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>css_class</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>default</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>editable</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>enabled</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>external_validator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>extra</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>hidden</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_length</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_linelength</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_lines</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>required</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>unicode</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>whitespace_preserve</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </value> + </item> + <item> + <key> <string>tales</string> </key> + <value> + <dictionary> + <item> + <key> <string>alternate_name</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>css_class</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>default</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>editable</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>enabled</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>external_validator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>extra</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>hidden</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_length</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_linelength</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_lines</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>required</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>unicode</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>whitespace_preserve</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </value> + </item> + <item> + <key> <string>values</string> </key> + <value> + <dictionary> + <item> + <key> <string>alternate_name</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>css_class</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>default</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>editable</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>enabled</string> </key> + <value> <int>1</int> </value> + </item> + <item> + <key> <string>external_validator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>extra</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <int>5</int> </value> + </item> + <item> + <key> <string>hidden</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>max_length</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_linelength</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_lines</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>required</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string>Key</string> </value> + </item> + <item> + <key> <string>unicode</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>whitespace_preserve</string> </key> + <value> <int>1</int> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <int>40</int> </value> + </item> + </dictionary> + </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm/your_tip.xml b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm/your_tip.xml new file mode 100644 index 0000000000..75204e30e4 --- /dev/null +++ b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_getCertificateForm/your_tip.xml @@ -0,0 +1,282 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="TextAreaField" module="Products.Formulator.StandardFields"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>id</string> </key> + <value> <string>your_tip</string> </value> + </item> + <item> + <key> <string>message_values</string> </key> + <value> + <dictionary> + <item> + <key> <string>external_validator_failed</string> </key> + <value> <string>The input failed the external validator.</string> </value> + </item> + <item> + <key> <string>line_too_long</string> </key> + <value> <string>A line was too long.</string> </value> + </item> + <item> + <key> <string>required_not_found</string> </key> + <value> <string>Input is required but no input given.</string> </value> + </item> + <item> + <key> <string>too_long</string> </key> + <value> <string>You entered too many characters.</string> </value> + </item> + <item> + <key> <string>too_many_lines</string> </key> + <value> <string>You entered too many lines.</string> </value> + </item> + </dictionary> + </value> + </item> + <item> + <key> <string>overrides</string> </key> + <value> + <dictionary> + <item> + <key> <string>alternate_name</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>css_class</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>default</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>editable</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>enabled</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>external_validator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>extra</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>hidden</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_length</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_linelength</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_lines</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>required</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>unicode</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>whitespace_preserve</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </value> + </item> + <item> + <key> <string>tales</string> </key> + <value> + <dictionary> + <item> + <key> <string>alternate_name</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>css_class</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>default</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>editable</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>enabled</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>external_validator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>extra</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>hidden</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_length</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_linelength</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_lines</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>required</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>unicode</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>whitespace_preserve</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <string></string> </value> + </item> + </dictionary> + </value> + </item> + <item> + <key> <string>values</string> </key> + <value> + <dictionary> + <item> + <key> <string>alternate_name</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>css_class</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>default</string> </key> + <value> <string>Please copy both key and certificate.\n +\n +They are NOT stored anywhere for security reason.</string> </value> + </item> + <item> + <key> <string>description</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>editable</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>enabled</string> </key> + <value> <int>1</int> </value> + </item> + <item> + <key> <string>external_validator</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>extra</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>height</string> </key> + <value> <int>5</int> </value> + </item> + <item> + <key> <string>hidden</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>max_length</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_linelength</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>max_lines</string> </key> + <value> <string></string> </value> + </item> + <item> + <key> <string>required</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>title</string> </key> + <value> <string>Information</string> </value> + </item> + <item> + <key> <string>unicode</string> </key> + <value> <int>0</int> </value> + </item> + <item> + <key> <string>whitespace_preserve</string> </key> + <value> <int>1</int> </value> + </item> + <item> + <key> <string>width</string> </key> + <value> <int>40</int> </value> + </item> + </dictionary> + </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_revokeCertificate.xml b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_revokeCertificate.xml new file mode 100644 index 0000000000..ea5f94e654 --- /dev/null +++ b/bt5/erp5_certificate_authority/SkinTemplateItem/portal_skins/erp5_certificate_authority/Person_revokeCertificate.xml @@ -0,0 +1,68 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="PythonScript" module="Products.PythonScripts.PythonScript"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>Script_magic</string> </key> + <value> <int>3</int> </value> + </item> + <item> + <key> <string>_bind_names</string> </key> + <value> + <object> + <klass> + <global name="NameAssignments" module="Shared.DC.Scripts.Bindings"/> + </klass> + <tuple/> + <state> + <dictionary> + <item> + <key> <string>_asgns</string> </key> + <value> + <dictionary> + <item> + <key> <string>name_container</string> </key> + <value> <string>container</string> </value> + </item> + <item> + <key> <string>name_context</string> </key> + <value> <string>context</string> </value> + </item> + <item> + <key> <string>name_m_self</string> </key> + <value> <string>script</string> </value> + </item> + <item> + <key> <string>name_subpath</string> </key> + <value> <string>traverse_subpath</string> </value> + </item> + </dictionary> + </value> + </item> + </dictionary> + </state> + </object> + </value> + </item> + <item> + <key> <string>_body</string> </key> + <value> <string>context.revokeCertificate()\n +return context.Base_redirect(form_id, keep_items = {\'portal_status_message\' : \'Certificate revoked.\'}, **kw)\n +</string> </value> + </item> + <item> + <key> <string>_params</string> </key> + <value> <string>dialog_id=None, form_id=None, **kw</string> </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>Person_revokeCertificate</string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_certificate_authority/ToolTemplateItem/portal_certificate_authority.xml b/bt5/erp5_certificate_authority/ToolTemplateItem/portal_certificate_authority.xml new file mode 100644 index 0000000000..74ed0594a4 --- /dev/null +++ b/bt5/erp5_certificate_authority/ToolTemplateItem/portal_certificate_authority.xml @@ -0,0 +1,41 @@ +<?xml version="1.0"?> +<ZopeData> + <record id="1" aka="AAAAAAAAAAE="> + <pickle> + <global name="Certificate Authority Tool" module="erp5.portal_type"/> + </pickle> + <pickle> + <dictionary> + <item> + <key> <string>_Access_contents_information_Permission</string> </key> + <value> + <tuple> + <string>Member</string> + <string>Manager</string> + </tuple> + </value> + </item> + <item> + <key> <string>_Add_portal_content_Permission</string> </key> + <value> + <tuple> + <string>Manager</string> + </tuple> + </value> + </item> + <item> + <key> <string>_View_Permission</string> </key> + <value> + <tuple> + <string>Manager</string> + </tuple> + </value> + </item> + <item> + <key> <string>id</string> </key> + <value> <string>portal_certificate_authority</string> </value> + </item> + </dictionary> + </pickle> + </record> +</ZopeData> diff --git a/bt5/erp5_certificate_authority/bt/change_log b/bt5/erp5_certificate_authority/bt/change_log new file mode 100644 index 0000000000..607afa6289 --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/change_log @@ -0,0 +1,2 @@ +2011-07-25 Lucas +* Initial version. \ No newline at end of file diff --git a/bt5/erp5_certificate_authority/bt/copyright_list b/bt5/erp5_certificate_authority/bt/copyright_list new file mode 100644 index 0000000000..5291cb4c27 --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/copyright_list @@ -0,0 +1 @@ +Nexedi 2011 \ No newline at end of file diff --git a/bt5/erp5_certificate_authority/bt/dependency_list b/bt5/erp5_certificate_authority/bt/dependency_list new file mode 100644 index 0000000000..1037d15c20 --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/dependency_list @@ -0,0 +1 @@ +erp5_base \ No newline at end of file diff --git a/bt5/erp5_certificate_authority/bt/description b/bt5/erp5_certificate_authority/bt/description new file mode 100644 index 0000000000..8622b0fefd --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/description @@ -0,0 +1 @@ +This bt5 aims to provide the tool to create certificates for a given ERP5 user, based on the keys provided by a service (i.e. Apache). \ No newline at end of file diff --git a/bt5/erp5_certificate_authority/bt/license b/bt5/erp5_certificate_authority/bt/license new file mode 100644 index 0000000000..3a3e12bcad --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/license @@ -0,0 +1 @@ +GPL \ No newline at end of file diff --git a/bt5/erp5_certificate_authority/bt/maintainer_list b/bt5/erp5_certificate_authority/bt/maintainer_list new file mode 100644 index 0000000000..d91e34ca85 --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/maintainer_list @@ -0,0 +1 @@ +lucas \ No newline at end of file diff --git a/bt5/erp5_certificate_authority/bt/revision b/bt5/erp5_certificate_authority/bt/revision new file mode 100644 index 0000000000..e440e5c842 --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/revision @@ -0,0 +1 @@ +3 \ No newline at end of file diff --git a/bt5/erp5_certificate_authority/bt/template_action_path_list b/bt5/erp5_certificate_authority/bt/template_action_path_list new file mode 100644 index 0000000000..8416153fe4 --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/template_action_path_list @@ -0,0 +1,2 @@ +Person | get_certificate +Person | revoke_certificate \ No newline at end of file diff --git a/bt5/erp5_certificate_authority/bt/template_document_id_list b/bt5/erp5_certificate_authority/bt/template_document_id_list new file mode 100644 index 0000000000..8c10d71378 --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/template_document_id_list @@ -0,0 +1 @@ +Person \ No newline at end of file diff --git a/bt5/erp5_certificate_authority/bt/template_format_version b/bt5/erp5_certificate_authority/bt/template_format_version new file mode 100644 index 0000000000..56a6051ca2 --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/template_format_version @@ -0,0 +1 @@ +1 \ No newline at end of file diff --git a/bt5/erp5_certificate_authority/bt/template_skin_id_list b/bt5/erp5_certificate_authority/bt/template_skin_id_list new file mode 100644 index 0000000000..8ddc575b32 --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/template_skin_id_list @@ -0,0 +1 @@ +erp5_certificate_authority \ No newline at end of file diff --git a/bt5/erp5_certificate_authority/bt/template_tool_id_list b/bt5/erp5_certificate_authority/bt/template_tool_id_list new file mode 100644 index 0000000000..cbf23ca962 --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/template_tool_id_list @@ -0,0 +1 @@ +portal_certificate_authority \ No newline at end of file diff --git a/bt5/erp5_certificate_authority/bt/title b/bt5/erp5_certificate_authority/bt/title new file mode 100644 index 0000000000..8ddc575b32 --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/title @@ -0,0 +1 @@ +erp5_certificate_authority \ No newline at end of file diff --git a/bt5/erp5_certificate_authority/bt/version b/bt5/erp5_certificate_authority/bt/version new file mode 100644 index 0000000000..48360de846 --- /dev/null +++ b/bt5/erp5_certificate_authority/bt/version @@ -0,0 +1 @@ +5.4.7 \ No newline at end of file diff --git a/product/ERP5/Tool/CertificateAuthorityTool.py b/product/ERP5/Tool/CertificateAuthorityTool.py new file mode 100644 index 0000000000..2559d868a6 --- /dev/null +++ b/product/ERP5/Tool/CertificateAuthorityTool.py @@ -0,0 +1,280 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2010 Nexedi SA and Contributors. All Rights Reserved. +# Åukasz Nowak <luke@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsibility of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# guarantees and support are strongly advised to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +from AccessControl import ClassSecurityInfo +from Products.ERP5Type.Globals import InitializeClass +from Products.ERP5Type.Tool.BaseTool import BaseTool +from Products.ERP5Type import Permissions +from Products.PageTemplates.PageTemplateFile import PageTemplateFile +from zLOG import LOG, INFO + +import os +import subprocess + +def popenCommunicate(command_list, input=None, **kwargs): + kwargs.update(stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + popen = subprocess.Popen(command_list, **kwargs) + result = popen.communicate(input)[0] + if popen.returncode is None: + popen.kill() + if popen.returncode != 0: + raise ValueError('Issue during calling %r, result was:\n%s' % ( + command_list, result)) + return result + +class CertificateAuthorityBusy(Exception): + """Exception raised when certificate authority is busy""" + pass + +class CertificateAuthorityDamaged(Exception): + """Exception raised when certificate authority is damaged""" + pass + +class CertificateAuthorityTool(BaseTool): + """CertificateAuthorityTool + + This tool assumes that in certificate_authority_path openssl configuration + is ready. + """ + + id = 'portal_certificate_authority' + meta_type = 'ERP5 Certificate Authority Tool' + portal_type = 'Certificate Authority Tool' + security = ClassSecurityInfo() + allowed_types = () + isIndexable = 0 + + certificate_authority_path = os.environ.get('CA_PATH', '') + openssl_binary = os.environ.get('OPENSSL_BINARY', '') + + manage_options = (({'label': 'Edit', + 'action': 'manage_editCertificateAuthorityToolForm',}, + ) + ) + BaseTool.manage_options + + _properties = (({'id':'certificate_authority_path', + 'type':'string', + 'mode':'w', + 'label':'Absolute path to certificate authority', + }, + {'id':'openssl_binary', + 'type':'string', + 'mode':'w', + 'label':'Absolute path to OpenSSL binary' + }, + ) + ) + + def _lockCertificateAuthority(self): + """Checks lock and locks Certificate Authority tool + + Raises CertificateAuthorityBusy""" + if os.path.exists(self.lock): + raise CertificateAuthorityBusy + open(self.lock, 'w').write('locked') + + def _unlockCertificateAuthority(self): + """Checks lock and locks Certificate Authority tool""" + if os.path.exists(self.lock): + os.unlink(self.lock) + else: + LOG('CertificateAuthorityTool', INFO, 'Lock file %r did not existed ' + 'during unlocking' % self.lock) + + def _checkCertificateAuthority(self): + """Checks Certificate Authority configuration + + Raises CertificateAuthorityDamaged""" + if not self.certificate_authority_path: + raise CertificateAuthorityDamaged('Certificate authority path is not ' + 'configured') + if not os.path.isdir(self.certificate_authority_path): + raise CertificateAuthorityDamaged('Path to Certificate Authority %r is ' + 'wrong' % self.certificate_authority_path) + if not self.openssl_binary: + raise CertificateAuthorityDamaged('OpenSSL binary path is not ' + 'configured' % self.certificate_authority_path) + if not os.path.isfile(self.openssl_binary): + raise CertificateAuthorityDamaged('OpenSSL binary %r does not exists' % + self.openssl_binary) + self.serial = os.path.join(self.certificate_authority_path, 'serial') + self.crl = os.path.join(self.certificate_authority_path, 'crlnumber') + self.index = os.path.join(self.certificate_authority_path, 'index.txt') + self.openssl_config = os.path.join(self.certificate_authority_path, + 'openssl.cnf') + self.lock = os.path.join(self.certificate_authority_path, 'lock') + for f in [self.serial, self.crl, self.index]: + if not os.path.isfile(f): + raise CertificateAuthorityDamaged('File %r does not exists.' % f) + + security.declarePrivate('manage_afterAdd') + def manage_afterAdd(self, item, container) : + """Init permissions right after creation. + + Permissions in tool are simple: + o Each member can access the tool. + o Only manager can view and create. + o Anonymous can not access + """ + item.manage_permission(Permissions.AddPortalContent, + ['Manager']) + item.manage_permission(Permissions.AccessContentsInformation, + ['Member', 'Manager']) + item.manage_permission(Permissions.View, + ['Manager',]) + BaseTool.inheritedAttribute('manage_afterAdd')(self, item, container) + + #'Edit' option form + manage_editCertificateAuthorityToolForm = PageTemplateFile( + '../www/CertificateAuthorityTool_editPropertyList', + globals(), + __name__='manage_editCertificateAuthorityToolForm') + + security.declareProtected(Permissions.ManageProperties, + 'manage_editCertificateAuthorityTool') + def manage_editCertificateAuthorityTool(self, certificate_authority_path, + openssl_binary, RESPONSE=None): + """Edit the object""" + error_message = '' + + if certificate_authority_path == '' or certificate_authority_path is None: + error_message += 'Invalid Certificate Authority' + else: + self.certificate_authority_path = certificate_authority_path + + if openssl_binary == '' or openssl_binary is None: + error_message += 'Invalid OpenSSL binary' + else: + self.openssl_binary = openssl_binary + + #Redirect + if RESPONSE is not None: + if error_message != '': + self.REQUEST.form['manage_tabs_message'] = error_message + return self.manage_editCertificateAuthorityToolForm(RESPONSE) + else: + message = "Updated" + RESPONSE.redirect('%s/manage_editCertificateAuthorityToolForm' + '?manage_tabs_message=%s' + % (self.absolute_url(), message) + ) + + security.declareProtected(Permissions.AccessContentsInformation, + 'getNewCertificate') + def getNewCertificate(self, common_name): + # No docstring in order to make this method non publishable + # Returns certificate for passed common name, as dictionary of + # {key, certificate, id, common_name} + self._checkCertificateAuthority() + self._lockCertificateAuthority() + try: + new_id = open(self.serial, 'r').read().strip().lower() + key = os.path.join(self.certificate_authority_path, 'private', + new_id+'.key') + csr = os.path.join(self.certificate_authority_path, new_id + '.csr') + cert = os.path.join(self.certificate_authority_path, 'certs', + new_id + '.crt') + try: + popenCommunicate([self.openssl_binary, 'req', '-nodes', '-config', + self.openssl_config, '-new', '-keyout', key, '-out', csr, '-days', + '3650'], '%s\n' % common_name, stdin=subprocess.PIPE) + popenCommunicate([self.openssl_binary, 'ca', '-days', '3650', + '-batch', '-config', self.openssl_config, '-out', cert, '-infiles', + csr]) + os.unlink(csr) + return dict( + key=open(key).read(), + certificate=open(cert).read(), + id=new_id, + common_name=common_name) + except: + try: + for p in [key, csr, cert]: + if os.path.exists(p): + os.unlink(p) + except: + # do not raise during cleanup + pass + raise + finally: + self._unlockCertificateAuthority() + + security.declareProtected(Permissions.AccessContentsInformation, + 'revokeCertificate') + def revokeCertificate(self, serial): + # No docstring in order to make this method non publishable + # Revokes certificate with serial, returns dictionary {crl} + self._checkCertificateAuthority() + self._lockCertificateAuthority() + try: + new_id = open(self.crl, 'r').read().strip().lower() + crl_path = os.path.join(self.certificate_authority_path, 'crl') + crl = os.path.join(crl_path, new_id + '.crl') + cert = os.path.join(self.certificate_authority_path, 'certs', + serial.lower() + '.crt') + if not os.path.exists(cert): + raise ValueError('Certificate with serial %r does not exists' % serial) + try: + popenCommunicate([self.openssl_binary, 'ca', '-config', + self.openssl_config, '-revoke', cert]) + popenCommunicate([self.openssl_binary, 'ca', '-config', + self.openssl_config, '-gencrl', '-out', crl]) + hash = popenCommunicate([self.openssl_binary, 'crl', '-noout', + '-hash', '-in', crl]).strip() + previous_id = int(len([q for q in os.listdir(crl_path) if hash in q])) + os.symlink(crl, os.path.join(crl_path, '%s.%s' % (hash, previous_id))) + return dict(crl=open(crl).read()) + except: + try: + for p in [crl]: + if os.path.exists(p): + os.unlink(p) + except: + # do not raise during cleanup + pass + raise + finally: + self._unlockCertificateAuthority() + + def _getValidSerial(self, common_name): + index = open(self.index).read().splitlines() + valid_line_list = [q for q in index if q.startswith('V') and + ('CN=%s' % common_name in q)] + if len(valid_line_list) != 1: + raise ValueError('No certificate for %r' % common_name) + return valid_line_list[0].split('\t')[3] + + security.declareProtected(Permissions.AccessContentsInformation, + 'revokeCertificate') + def revokeCertificateByCommonName(self, common_name): + self._checkCertificateAuthority() + serial = self._getValidSerial(common_name) + self.revokeCertificate(serial) + +InitializeClass(CertificateAuthorityTool) diff --git a/product/ERP5/__init__.py b/product/ERP5/__init__.py index 60c5efd87a..436894c78b 100644 --- a/product/ERP5/__init__.py +++ b/product/ERP5/__init__.py @@ -50,7 +50,8 @@ from Tool import CategoryTool, SimulationTool, RuleTool, IdTool, TemplateTool,\ TrashTool, ContributionTool, NotificationTool, PasswordTool,\ GadgetTool, ContributionRegistryTool, IntrospectionTool,\ AcknowledgementTool, SolverTool, SolverProcessTool,\ - ConversionTool, RoundingTool, UrlRegistryTool + ConversionTool, RoundingTool, UrlRegistryTool,\ + CertificateAuthorityTool import ERP5Site from Document import PythonScript object_classes = ( ERP5Site.ERP5Site, @@ -79,6 +80,7 @@ portal_tools = ( CategoryTool.CategoryTool, ConversionTool.ConversionTool, RoundingTool.RoundingTool, UrlRegistryTool.UrlRegistryTool, + CertificateAuthorityTool.CertificateAuthorityTool, ) content_classes = () content_constructors = () diff --git a/product/ERP5/tests/testCertificateAuthorityTool.py b/product/ERP5/tests/testCertificateAuthorityTool.py new file mode 100644 index 0000000000..cdfa771ef4 --- /dev/null +++ b/product/ERP5/tests/testCertificateAuthorityTool.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Copyright (c) 2005 Nexedi SARL and Contributors. All Rights Reserved. +# Ivan Tyagov <ivan@nexedi.com> +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsability of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# garantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +import os +import random +import unittest +from Products.ERP5Type.tests.ERP5TypeTestCase import ERP5TypeTestCase +from AccessControl import Unauthorized + +class TestCertificateAuthority(ERP5TypeTestCase): + + def getTitle(self): + return "Test Certificate Authority" + + def afterSetUp(self): + self.portal.portal_certificate_authority.certificate_authority_path = \ + os.environ['TEST_CA_PATH'] + self.portal.portal_certificate_authority.openssl_binary = \ + os.environ['OPENSSL_BINARY'] + + def getBusinessTemplateList(self): + return ('erp5_base', 'erp5_certificate_authority') + + def _createPerson(self): + login = str(random.random()) + person = self.portal.person_module.newContent(portal_type='Person', + reference=login, password=login) + person.newContent(portal_type='Assignment').open() + self.stepTic() + return login + + def test_person_request_certificate(self): + login = self._createPerson() + person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login) + self.login(login) + certificate = person.getCertificate() + self.assertTrue('CN=%s' % login in certificate['certificate']) + + def test_person_revoke_certificate(self): + login = self._createPerson() + person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login) + self.login(login) + self.assertRaises(ValueError, person.revokeCertificate) + + def test_person_request_revoke_certificate(self): + login = self._createPerson() + person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login) + self.login(login) + certificate = person.getCertificate() + self.assertTrue('CN=%s' % login in certificate['certificate']) + person.revokeCertificate() + + def test_person_request_certificate_twice(self): + login = self._createPerson() + person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login) + self.login(login) + certificate = person.getCertificate() + self.assertTrue('CN=%s' % login in certificate['certificate']) + self.assertRaises(ValueError, person.getCertificate) + + def test_person_request_certificate_for_another(self): + login = self._createPerson() + login2 = self._createPerson() + person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login) + self.login(login2) + self.assertRaises(Unauthorized, person.getCertificate) + + def test_person_revoke_certificate_for_another(self): + login = self._createPerson() + login2 = self._createPerson() + person = self.portal.ERP5Site_getAuthenticatedMemberPersonValue(login) + self.login(login) + certificate = person.getCertificate() + self.assertTrue('CN=%s' % login in certificate['certificate']) + self.login(login2) + self.assertRaises(Unauthorized, person.revokeCertificate) + +def test_suite(): + suite = unittest.TestSuite() + suite.addTest(unittest.makeSuite(TestCertificateAuthority)) + return suite diff --git a/product/ERP5/www/CertificateAuthorityTool_editPropertyList.zpt b/product/ERP5/www/CertificateAuthorityTool_editPropertyList.zpt new file mode 100644 index 0000000000..2a6a1906ac --- /dev/null +++ b/product/ERP5/www/CertificateAuthorityTool_editPropertyList.zpt @@ -0,0 +1,37 @@ +<h1 tal:replace="structure context/manage_page_header">PAGE HEADER</h1> +<h2 tal:replace="structure here/manage_tabs"> TABS </h2> +<h2 tal:define="form_title string:Edit ERP5 Certificate Authority Tool" + tal:replace="structure context/manage_form_title">FORM TITLE</h2> + +<p class="form-help">Please input the Certificate Authority path</p> + +<form action="manage_editCertificateAuthorityTool" method="POST"> + +<table + tal:define="certificate_authority_path request/certificate_authority_path|context/certificate_authority_path|string:; openssl_binary request/openssl_binary|context/openssl_binary|string:;"> + +<tr> + <td>Absolute path to configured Certificate Authority</td> + <td> + <input type="text" name="certificate_authority_path" value="" + tal:attributes="value certificate_authority_path;" /> + </td> +</tr> +<tr> + <td>Absolute path to OpenSSL binary</td> + <td> + <input type="text" name="openssl_binary" value="" + tal:attributes="value openssl_binary;" /> + </td> +</tr> +<tr> + <td colspan="2"> + <input type="submit" value="save"/> + </td> +</tr> + +</table> + +</form> + +<h1 tal:replace="structure context/manage_page_footer">PAGE FOOTER</h1> -- 2.30.9