Commit 5c0400bc authored by Rafael Monnerat's avatar Rafael Monnerat

slapos_cloud: Use erp5_certificate_authority bt5

   Move code related to Certificate Authorithy to generic bt5
   Certificate authority is installed via erp5_certificate_authority bt5
   Person re-definition was moved into erp5_certificate_authority business templates

   extra:
      slapos_configurator: Update test to include new dependency
parent 5fcfcdbd
from AccessControl import ClassSecurityInfo, Unauthorized, getSecurityManager
from Products.ERP5.Document.Person import Person as ERP5Person
from Products.ERP5Type import Permissions
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
user_id = self.getUserId()
if not user_id:
raise
if getSecurityManager().getUser().getId() != user_id:
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()
security.declareProtected(Permissions.AccessContentsInformation,
'getTitle')
def getTitle(self, **kw):
"""
Returns the title if it exists or a combination of
first name and last name
"""
title = ERP5Person.getTitle(self, **kw)
test_title = title.replace(' ', '')
if test_title == '':
return self.getDefaultEmailCoordinateText(test_title)
else:
return title
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="Document Component" module="erp5.portal_type"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_recorded_property_dict</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAI=</string> </persistent>
</value>
</item>
<item>
<key> <string>default_reference</string> </key>
<value> <string>Person</string> </value>
</item>
<item>
<key> <string>description</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>document.erp5.Person</string> </value>
</item>
<item>
<key> <string>portal_type</string> </key>
<value> <string>Document Component</string> </value>
</item>
<item>
<key> <string>sid</string> </key>
<value>
<none/>
</value>
</item>
<item>
<key> <string>text_content_error_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>text_content_warning_message</string> </key>
<value>
<tuple/>
</value>
</item>
<item>
<key> <string>version</string> </key>
<value> <string>erp5</string> </value>
</item>
<item>
<key> <string>workflow_history</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAM=</string> </persistent>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="2" aka="AAAAAAAAAAI=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary/>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="3" aka="AAAAAAAAAAM=">
<pickle>
<global name="PersistentMapping" module="Persistence.mapping"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>data</string> </key>
<value>
<dictionary>
<item>
<key> <string>component_validation_workflow</string> </key>
<value>
<persistent> <string encoding="base64">AAAAAAAAAAQ=</string> </persistent>
</value>
</item>
</dictionary>
</value>
</item>
</dictionary>
</pickle>
</record>
<record id="4" aka="AAAAAAAAAAQ=">
<pickle>
<global name="WorkflowHistoryList" module="Products.ERP5Type.patches.WorkflowTool"/>
</pickle>
<pickle>
<tuple>
<none/>
<list>
<dictionary>
<item>
<key> <string>action</string> </key>
<value> <string>validate</string> </value>
</item>
<item>
<key> <string>validation_state</string> </key>
<value> <string>validated</string> </value>
</item>
</dictionary>
</list>
</tuple>
</pickle>
</record>
</ZopeData>
...@@ -60,7 +60,7 @@ class TestSlapOSSecurityMixin(SlapOSTestCaseMixin): ...@@ -60,7 +60,7 @@ class TestSlapOSSecurityMixin(SlapOSTestCaseMixin):
for _, plugin in uf._getOb('plugins').listPlugins( for _, plugin in uf._getOb('plugins').listPlugins(
IAuthenticationPlugin ): IAuthenticationPlugin ):
if plugin.authenticateCredentials( if plugin.authenticateCredentials(
{'login_portal_type': 'ERP5 Login', {'login_portal_type': ('ERP5 Login', 'Certificate Login'),
'external_login': login}) is not None: 'external_login': login}) is not None:
break break
else: else:
...@@ -75,14 +75,14 @@ class TestSlapOSSecurityMixin(SlapOSTestCaseMixin): ...@@ -75,14 +75,14 @@ class TestSlapOSSecurityMixin(SlapOSTestCaseMixin):
for plugin_name, plugin in uf._getOb('plugins').listPlugins( for plugin_name, plugin in uf._getOb('plugins').listPlugins(
IAuthenticationPlugin ): IAuthenticationPlugin ):
if plugin.authenticateCredentials( if plugin.authenticateCredentials(
{'login_portal_type': 'ERP5 Login', {'login_portal_type': ('ERP5 Login', 'Certificate Login'),
'external_login': login}) is not None: 'external_login': login}) is not None:
self.fail( self.fail(
"Plugin %s should not have authenticated '%s' with password '%s'" % "Plugin %s should not have authenticated '%s' with password '%s'" %
(plugin_name, login, password)) (plugin_name, login, password))
class TestSlapOSComputerSecurity(TestSlapOSSecurityMixin): class TestSlapOSComputerSecurity(TestSlapOSSecurityMixin):
def test_active(self): def test_active(self, login_portal_type="Certificate Login"):
user_id = self._generateRandomUniqueUserId('Computer') user_id = self._generateRandomUniqueUserId('Computer')
reference = self._generateRandomUniqueReference('Computer') reference = self._generateRandomUniqueReference('Computer')
...@@ -90,7 +90,7 @@ class TestSlapOSComputerSecurity(TestSlapOSSecurityMixin): ...@@ -90,7 +90,7 @@ class TestSlapOSComputerSecurity(TestSlapOSSecurityMixin):
portal_type='Computer', reference=reference) portal_type='Computer', reference=reference)
computer.setUserId(user_id) computer.setUserId(user_id)
computer.validate() computer.validate()
computer.newContent(portal_type='ERP5 Login', computer.newContent(portal_type=login_portal_type,
reference=reference).validate() reference=reference).validate()
self.tic() self.tic()
...@@ -103,22 +103,28 @@ class TestSlapOSComputerSecurity(TestSlapOSSecurityMixin): ...@@ -103,22 +103,28 @@ class TestSlapOSComputerSecurity(TestSlapOSSecurityMixin):
self.assertSameSet(['R-COMPUTER'], self.assertSameSet(['R-COMPUTER'],
user.getGroups()) user.getGroups())
def test_inactive(self): def test_inactive(self, login_portal_type="Certificate Login"):
user_id = self._generateRandomUniqueUserId('Computer') user_id = self._generateRandomUniqueUserId('Computer')
reference = self._generateRandomUniqueReference('Computer') reference = self._generateRandomUniqueReference('Computer')
computer = self.portal.computer_module.newContent( computer = self.portal.computer_module.newContent(
portal_type='Computer', reference=reference) portal_type='Computer', reference=reference)
computer.setUserId(user_id) computer.setUserId(user_id)
computer.newContent(portal_type='ERP5 Login', computer.newContent(portal_type=login_portal_type,
reference=reference) reference=reference)
self.tic() self.tic()
self._assertUserDoesNotExists(user_id, reference, None) self._assertUserDoesNotExists(user_id, reference, None)
def test_active_backward_compatibility_with_erp5_login(self):
self.test_active(login_portal_type="ERP5 Login")
def test_inactive_backward_compatibility_with_erp5_login(self):
self.test_inactive(login_portal_type="ERP5 Login")
class TestSlapOSSoftwareInstanceSecurity(TestSlapOSSecurityMixin): class TestSlapOSSoftwareInstanceSecurity(TestSlapOSSecurityMixin):
portal_type = 'Software Instance' portal_type = 'Software Instance'
def test_active(self): def test_active(self, login_portal_type="Certificate Login"):
user_id = self._generateRandomUniqueUserId(self.portal_type) user_id = self._generateRandomUniqueUserId(self.portal_type)
reference = self._generateRandomUniqueReference(self.portal_type) reference = self._generateRandomUniqueReference(self.portal_type)
...@@ -126,7 +132,7 @@ class TestSlapOSSoftwareInstanceSecurity(TestSlapOSSecurityMixin): ...@@ -126,7 +132,7 @@ class TestSlapOSSoftwareInstanceSecurity(TestSlapOSSecurityMixin):
.newContent(portal_type=self.portal_type, reference=reference) .newContent(portal_type=self.portal_type, reference=reference)
instance.setUserId(user_id) instance.setUserId(user_id)
instance.validate() instance.validate()
instance.newContent(portal_type='ERP5 Login', instance.newContent(portal_type=login_portal_type,
reference=reference).validate() reference=reference).validate()
self.tic() self.tic()
...@@ -157,7 +163,7 @@ class TestSlapOSSoftwareInstanceSecurity(TestSlapOSSecurityMixin): ...@@ -157,7 +163,7 @@ class TestSlapOSSoftwareInstanceSecurity(TestSlapOSSecurityMixin):
self.assertSameSet(['R-INSTANCE', subscription_reference], self.assertSameSet(['R-INSTANCE', subscription_reference],
user.getGroups()) user.getGroups())
def test_inactive(self): def test_inactive(self, login_portal_type="Certificate Login"):
user_id = self._generateRandomUniqueUserId(self.portal_type) user_id = self._generateRandomUniqueUserId(self.portal_type)
reference = self._generateRandomUniqueReference(self.portal_type) reference = self._generateRandomUniqueReference(self.portal_type)
...@@ -168,8 +174,14 @@ class TestSlapOSSoftwareInstanceSecurity(TestSlapOSSecurityMixin): ...@@ -168,8 +174,14 @@ class TestSlapOSSoftwareInstanceSecurity(TestSlapOSSecurityMixin):
self._assertUserDoesNotExists(user_id, reference, None) self._assertUserDoesNotExists(user_id, reference, None)
def test_active_backward_compatibility_with_erp5_login(self):
self.test_active(login_portal_type="ERP5 Login")
def test_inactive_backward_compatibility_with_erp5_login(self):
self.test_inactive(login_portal_type="ERP5 Login")
class TestSlapOSPersonSecurity(TestSlapOSSecurityMixin): class TestSlapOSPersonSecurity(TestSlapOSSecurityMixin):
def test_active(self): def test_active(self, login_portal_type="Certificate Login"):
password = str(random.random()) password = str(random.random())
reference = self._generateRandomUniqueReference('Person') reference = self._generateRandomUniqueReference('Person')
user_id = self._generateRandomUniqueUserId('Person') user_id = self._generateRandomUniqueUserId('Person')
...@@ -180,7 +192,7 @@ class TestSlapOSPersonSecurity(TestSlapOSSecurityMixin): ...@@ -180,7 +192,7 @@ class TestSlapOSPersonSecurity(TestSlapOSSecurityMixin):
person.setUserId(user_id) person.setUserId(user_id)
person.newContent(portal_type='Assignment').open() person.newContent(portal_type='Assignment').open()
person.newContent(portal_type='ERP5 Login', person.newContent(portal_type=login_portal_type,
reference=reference, password=password).validate() reference=reference, password=password).validate()
self.tic() self.tic()
...@@ -216,7 +228,7 @@ class TestSlapOSPersonSecurity(TestSlapOSSecurityMixin): ...@@ -216,7 +228,7 @@ class TestSlapOSPersonSecurity(TestSlapOSSecurityMixin):
self.assertTrue('Authenticated' in user.getRoles()) self.assertTrue('Authenticated' in user.getRoles())
self.assertSameSet(['R-MEMBER', 'G-COMPANY'], user.getGroups()) self.assertSameSet(['R-MEMBER', 'G-COMPANY'], user.getGroups())
def test_inactive(self): def test_inactive(self, login_portal_type="Certificate Login"):
password = str(random.random()) password = str(random.random())
reference = self._generateRandomUniqueReference('Person') reference = self._generateRandomUniqueReference('Person')
user_id = self._generateRandomUniqueReference('Person') user_id = self._generateRandomUniqueReference('Person')
...@@ -228,6 +240,22 @@ class TestSlapOSPersonSecurity(TestSlapOSSecurityMixin): ...@@ -228,6 +240,22 @@ class TestSlapOSPersonSecurity(TestSlapOSSecurityMixin):
self._assertUserDoesNotExists(user_id, reference, password) self._assertUserDoesNotExists(user_id, reference, password)
person.newContent(portal_type=login_portal_type,
reference=reference).validate()
self.tic()
self._assertUserDoesNotExists(user_id, reference, password)
def test_active_erp5_login(self):
self.test_active(login_portal_type="ERP5 Login")
def test_inactive_erp5_login(self):
self.test_inactive(login_portal_type="ERP5 Login")
def test_suite(): def test_suite():
suite = unittest.TestSuite() suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestSlapOSComputerSecurity)) suite.addTest(unittest.makeSuite(TestSlapOSComputerSecurity))
......
erp5_item erp5_item
erp5_computer_immobilisation erp5_computer_immobilisation
erp5_software_pdm erp5_software_pdm
erp5_security_uid_innodb_catalog erp5_security_uid_innodb_catalog
\ No newline at end of file erp5_certificate_authority
\ No newline at end of file
document.erp5.Person
document.erp5.SoftwareInstance document.erp5.SoftwareInstance
\ No newline at end of file
...@@ -304,6 +304,7 @@ class TestSlapOSConfigurator(SlapOSTestCaseMixin): ...@@ -304,6 +304,7 @@ class TestSlapOSConfigurator(SlapOSTestCaseMixin):
'slapos_l10n_zh', 'slapos_l10n_zh',
'slapos_subscription_request', 'slapos_subscription_request',
'erp5_bearer_token', 'erp5_bearer_token',
'erp5_certificate_authority',
'erp5_access_token', 'erp5_access_token',
'erp5_project', 'erp5_project',
'erp5_oauth', 'erp5_oauth',
......
...@@ -147,6 +147,7 @@ erp5_simulation ...@@ -147,6 +147,7 @@ erp5_simulation
erp5_dms_base erp5_dms_base
erp5_dms_web erp5_dms_web
erp5_accounting_l10n_fr erp5_accounting_l10n_fr
erp5_certificate_authority
erp5_item erp5_item
erp5_item_trade erp5_item_trade
erp5_upgrader erp5_upgrader
...@@ -157,6 +158,7 @@ erp5_administration ...@@ -157,6 +158,7 @@ erp5_administration
erp5_auto_logout erp5_auto_logout
erp5_base erp5_base
erp5_bearer_token erp5_bearer_token
erp5_certificate_authority
erp5_ckeditor erp5_ckeditor
erp5_code_mirror erp5_code_mirror
erp5_commerce erp5_commerce
...@@ -258,6 +260,7 @@ erp5_simulation ...@@ -258,6 +260,7 @@ erp5_simulation
erp5_dms_base erp5_dms_base
erp5_dms_web erp5_dms_web
erp5_accounting_l10n_fr erp5_accounting_l10n_fr
erp5_certificate_authority
erp5_item erp5_item
erp5_item_trade erp5_item_trade
erp5_upgrader erp5_upgrader
...@@ -268,6 +271,7 @@ erp5_administration ...@@ -268,6 +271,7 @@ erp5_administration
erp5_auto_logout erp5_auto_logout
erp5_base erp5_base
erp5_bearer_token erp5_bearer_token
erp5_certificate_authority
erp5_ckeditor erp5_ckeditor
erp5_code_mirror erp5_code_mirror
erp5_commerce erp5_commerce
...@@ -370,6 +374,7 @@ erp5_simulation ...@@ -370,6 +374,7 @@ erp5_simulation
erp5_dms_base erp5_dms_base
erp5_dms_web erp5_dms_web
erp5_accounting_l10n_fr erp5_accounting_l10n_fr
erp5_certificate_authority
erp5_item erp5_item
erp5_item_trade erp5_item_trade
erp5_upgrader erp5_upgrader
...@@ -380,6 +385,7 @@ erp5_administration ...@@ -380,6 +385,7 @@ erp5_administration
erp5_auto_logout erp5_auto_logout
erp5_base erp5_base
erp5_bearer_token erp5_bearer_token
erp5_certificate_authority
erp5_ckeditor erp5_ckeditor
erp5_code_mirror erp5_code_mirror
erp5_commerce erp5_commerce
...@@ -478,6 +484,7 @@ erp5_simulation ...@@ -478,6 +484,7 @@ erp5_simulation
erp5_dms_base erp5_dms_base
erp5_dms_web erp5_dms_web
erp5_accounting_l10n_fr erp5_accounting_l10n_fr
erp5_certificate_authority
erp5_item erp5_item
erp5_item_trade erp5_item_trade
erp5_upgrader erp5_upgrader
...@@ -488,6 +495,7 @@ erp5_administration ...@@ -488,6 +495,7 @@ erp5_administration
erp5_auto_logout erp5_auto_logout
erp5_base erp5_base
erp5_bearer_token erp5_bearer_token
erp5_certificate_authority
erp5_ckeditor erp5_ckeditor
erp5_code_mirror erp5_code_mirror
erp5_commerce erp5_commerce
...@@ -590,6 +598,7 @@ erp5_simulation ...@@ -590,6 +598,7 @@ erp5_simulation
erp5_dms_base erp5_dms_base
erp5_dms_web erp5_dms_web
erp5_accounting_l10n_fr erp5_accounting_l10n_fr
erp5_certificate_authority
erp5_item erp5_item
erp5_item_trade erp5_item_trade
erp5_upgrader erp5_upgrader
...@@ -600,6 +609,7 @@ erp5_administration ...@@ -600,6 +609,7 @@ erp5_administration
erp5_auto_logout erp5_auto_logout
erp5_base erp5_base
erp5_bearer_token erp5_bearer_token
erp5_certificate_authority
erp5_ckeditor erp5_ckeditor
erp5_code_mirror erp5_code_mirror
erp5_commerce erp5_commerce
...@@ -702,6 +712,7 @@ erp5_simulation ...@@ -702,6 +712,7 @@ erp5_simulation
erp5_dms_base erp5_dms_base
erp5_dms_web erp5_dms_web
erp5_accounting_l10n_fr erp5_accounting_l10n_fr
erp5_certificate_authority
erp5_item erp5_item
erp5_item_trade erp5_item_trade
erp5_upgrader erp5_upgrader
...@@ -712,6 +723,7 @@ erp5_administration ...@@ -712,6 +723,7 @@ erp5_administration
erp5_auto_logout erp5_auto_logout
erp5_base erp5_base
erp5_bearer_token erp5_bearer_token
erp5_certificate_authority
erp5_ckeditor erp5_ckeditor
erp5_code_mirror erp5_code_mirror
erp5_commerce erp5_commerce
...@@ -811,6 +823,7 @@ erp5_simulation ...@@ -811,6 +823,7 @@ erp5_simulation
erp5_dms_base erp5_dms_base
erp5_dms_web erp5_dms_web
erp5_accounting_l10n_fr erp5_accounting_l10n_fr
erp5_certificate_authority
erp5_item erp5_item
erp5_item_trade erp5_item_trade
erp5_upgrader erp5_upgrader
...@@ -821,6 +834,7 @@ erp5_administration ...@@ -821,6 +834,7 @@ erp5_administration
erp5_auto_logout erp5_auto_logout
erp5_base erp5_base
erp5_bearer_token erp5_bearer_token
erp5_certificate_authority
erp5_ckeditor erp5_ckeditor
erp5_code_mirror erp5_code_mirror
erp5_commerce erp5_commerce
...@@ -921,6 +935,7 @@ erp5_dms_base ...@@ -921,6 +935,7 @@ erp5_dms_base
erp5_dms_web erp5_dms_web
erp5_ods_style erp5_ods_style
erp5_accounting_l10n_fr erp5_accounting_l10n_fr
erp5_certificate_authority
erp5_item erp5_item
erp5_item_trade erp5_item_trade
erp5_upgrader erp5_upgrader
...@@ -931,6 +946,7 @@ erp5_administration ...@@ -931,6 +946,7 @@ erp5_administration
erp5_auto_logout erp5_auto_logout
erp5_base erp5_base
erp5_bearer_token erp5_bearer_token
erp5_certificate_authority
erp5_ckeditor erp5_ckeditor
erp5_code_mirror erp5_code_mirror
erp5_commerce erp5_commerce
...@@ -1030,6 +1046,7 @@ erp5_dms_base ...@@ -1030,6 +1046,7 @@ erp5_dms_base
erp5_dms_web erp5_dms_web
erp5_odt_style erp5_odt_style
erp5_accounting_l10n_fr erp5_accounting_l10n_fr
erp5_certificate_authority
erp5_item erp5_item
erp5_item_trade erp5_item_trade
erp5_upgrader erp5_upgrader
...@@ -1040,6 +1057,7 @@ erp5_administration ...@@ -1040,6 +1057,7 @@ erp5_administration
erp5_auto_logout erp5_auto_logout
erp5_base erp5_base
erp5_bearer_token erp5_bearer_token
erp5_certificate_authority
erp5_ckeditor erp5_ckeditor
erp5_code_mirror erp5_code_mirror
erp5_commerce erp5_commerce
...@@ -1140,6 +1158,7 @@ erp5_simulation ...@@ -1140,6 +1158,7 @@ erp5_simulation
erp5_dms_base erp5_dms_base
erp5_dms_web erp5_dms_web
erp5_accounting_l10n_fr erp5_accounting_l10n_fr
erp5_certificate_authority
erp5_item erp5_item
erp5_item_trade erp5_item_trade
erp5_upgrader erp5_upgrader
...@@ -1150,6 +1169,7 @@ erp5_administration ...@@ -1150,6 +1169,7 @@ erp5_administration
erp5_auto_logout erp5_auto_logout
erp5_base erp5_base
erp5_bearer_token erp5_bearer_token
erp5_certificate_authority
erp5_ckeditor erp5_ckeditor
erp5_code_mirror erp5_code_mirror
erp5_commerce erp5_commerce
...@@ -1250,6 +1270,7 @@ erp5_simulation ...@@ -1250,6 +1270,7 @@ erp5_simulation
erp5_dms_base erp5_dms_base
erp5_dms_web erp5_dms_web
erp5_accounting_l10n_fr erp5_accounting_l10n_fr
erp5_certificate_authority
erp5_item erp5_item
erp5_item_trade erp5_item_trade
erp5_upgrader erp5_upgrader
...@@ -1260,6 +1281,7 @@ erp5_administration ...@@ -1260,6 +1281,7 @@ erp5_administration
erp5_auto_logout erp5_auto_logout
erp5_base erp5_base
erp5_bearer_token erp5_bearer_token
erp5_certificate_authority
erp5_ckeditor erp5_ckeditor
erp5_code_mirror erp5_code_mirror
erp5_commerce erp5_commerce
...@@ -1361,6 +1383,7 @@ erp5_simulation ...@@ -1361,6 +1383,7 @@ erp5_simulation
erp5_dms_base erp5_dms_base
erp5_dms_web erp5_dms_web
erp5_accounting_l10n_fr erp5_accounting_l10n_fr
erp5_certificate_authority
erp5_item erp5_item
erp5_item_trade erp5_item_trade
erp5_upgrader erp5_upgrader
...@@ -1371,6 +1394,7 @@ erp5_administration ...@@ -1371,6 +1394,7 @@ erp5_administration
erp5_auto_logout erp5_auto_logout
erp5_base erp5_base
erp5_bearer_token erp5_bearer_token
erp5_certificate_authority
erp5_ckeditor erp5_ckeditor
erp5_code_mirror erp5_code_mirror
erp5_commerce erp5_commerce
...@@ -1472,6 +1496,7 @@ erp5_simulation ...@@ -1472,6 +1496,7 @@ erp5_simulation
erp5_dms_base erp5_dms_base
erp5_dms_web erp5_dms_web
erp5_accounting_l10n_fr erp5_accounting_l10n_fr
erp5_certificate_authority
erp5_item erp5_item
erp5_item_trade erp5_item_trade
erp5_upgrader erp5_upgrader
...@@ -1482,6 +1507,7 @@ erp5_administration ...@@ -1482,6 +1507,7 @@ erp5_administration
erp5_auto_logout erp5_auto_logout
erp5_base erp5_base
erp5_bearer_token erp5_bearer_token
erp5_certificate_authority
erp5_ckeditor erp5_ckeditor
erp5_code_mirror erp5_code_mirror
erp5_commerce erp5_commerce
......
portal_certificate_authority
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment