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 0000000000000000000000000000000000000000..42f2bc1651c4ee5c84f1eb64e1e219994baf50e8 --- /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 0000000000000000000000000000000000000000..d81f574a000c65b56deaefd5b4d2aa4869f45e8a --- /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 0000000000000000000000000000000000000000..aa92e7d60aadbc1786907a10fd0e51313c3ad10c --- /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 0000000000000000000000000000000000000000..08b7fc706b14b504bfaf975f9ae4ef12864faea9 --- /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 0000000000000000000000000000000000000000..3960836eaaa59f299cc8d3f6e8db309328557d23 --- /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 0000000000000000000000000000000000000000..e44abacf7b6a0af976a10b6bff0a671fd2455280 --- /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 0000000000000000000000000000000000000000..9342d207c0ca36482d7e83102dd073f889449a36 --- /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 0000000000000000000000000000000000000000..bcaa2fe86004c8f8c75437a785dfb121fa69f1ff --- /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 0000000000000000000000000000000000000000..75204e30e4185b3b665b6c5e88fcb53284ea77aa --- /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 0000000000000000000000000000000000000000..ea5f94e65443a96a92dd4291570aea688b831790 --- /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 0000000000000000000000000000000000000000..74ed0594a448b14cec29522082cc6f4703cc70e3 --- /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 0000000000000000000000000000000000000000..607afa6289a3bc03cca7528f5f9367e8e6a5a3b1 --- /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 0000000000000000000000000000000000000000..5291cb4c27f7c056102df0d8c21726854de742ac --- /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 0000000000000000000000000000000000000000..1037d15c20e7753f9373ed1ccc68c378db21498d --- /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 0000000000000000000000000000000000000000..8622b0fefd4ac530decae4b209de3753ee641304 --- /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 0000000000000000000000000000000000000000..3a3e12bcad97e4b3bdd6a8bb499fd23a4bcb0819 --- /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 0000000000000000000000000000000000000000..d91e34ca851c4219fd0d1c71c1f295783573bbee --- /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 0000000000000000000000000000000000000000..e440e5c842586965a7fb77deda2eca68612b1f53 --- /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 0000000000000000000000000000000000000000..8416153fe400031b74108ca0feb7c1c4b4e100d6 --- /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 0000000000000000000000000000000000000000..8c10d71378b222efb5ed4c5190b27d5e38b0756e --- /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 0000000000000000000000000000000000000000..56a6051ca2b02b04ef92d5150c9ef600403cb1de --- /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 0000000000000000000000000000000000000000..8ddc575b32b39b185e50d96e2ffa53a14e500c9a --- /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 0000000000000000000000000000000000000000..cbf23ca962bcbca28f13575e04e8810807280e30 --- /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 0000000000000000000000000000000000000000..8ddc575b32b39b185e50d96e2ffa53a14e500c9a --- /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 0000000000000000000000000000000000000000..48360de846a2e022a0b981d250895f20d3480d34 --- /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 0000000000000000000000000000000000000000..2559d868a6bf7d17549d23c826c31f26e0966ef1 --- /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 60c5efd87ad86647f758dfd6608c2bcaf5441860..436894c78b71b3c035b67de24fde27ad81472992 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 0000000000000000000000000000000000000000..cdfa771ef48b83cb0b47ae212ba616e55b474fb1 --- /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 0000000000000000000000000000000000000000..2a6a1906ac2bacffb45014c42d5bcc5a9aa5fbfe --- /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>