Simone Tiraboschi has uploaded a new change for review.

Change subject: packaging: setup: Use common code for remote wsp pki
......................................................................

packaging: setup: Use common code for remote wsp pki

Code to handle PKI stuff with remote engine has been moved
to a common place to be shared between different plugins.
Using it.

Change-Id: Id72711fb1577d5ee97454a36650456c2675206be
Bug-Url: https://bugzilla.redhat.com/1125188
Signed-off-by: Simone Tiraboschi <stira...@redhat.com>
---
M packaging/setup/ovirt_engine_setup/websocket_proxy/constants.py
M packaging/setup/plugins/ovirt-engine-setup/websocket_proxy/config.py
M packaging/setup/plugins/ovirt-engine-setup/websocket_proxy/pki.py
3 files changed, 200 insertions(+), 282 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/ovirt-engine refs/changes/41/33941/1

diff --git a/packaging/setup/ovirt_engine_setup/websocket_proxy/constants.py 
b/packaging/setup/ovirt_engine_setup/websocket_proxy/constants.py
index b655f4f..82370ef 100644
--- a/packaging/setup/ovirt_engine_setup/websocket_proxy/constants.py
+++ b/packaging/setup/ovirt_engine_setup/websocket_proxy/constants.py
@@ -65,6 +65,10 @@
         OVIRT_ENGINE_PKIDIR,
         'certs',
     )
+    OVIRT_ENGINE_PKIREQUESTSDIR = os.path.join(
+        OVIRT_ENGINE_PKIDIR,
+        'requests',
+    )
 
     OVIRT_ENGINE_PKI_WEBSOCKET_PROXY_KEY = os.path.join(
         OVIRT_ENGINE_PKIKEYSDIR,
@@ -94,6 +98,9 @@
         'setup.config.websocket-proxy.customization'
 
     REMOTE_VDC = 'setup.config.websocket-proxy.remote_vdc'
+
+    # sync with engine
+    ENGINE_CORE_ENABLE = 'osetup.engine.core.enable'
 
 
 @util.export
@@ -128,6 +135,16 @@
     WSP_CERTIFICATE_CHAIN = 'OVESETUP_CONFIG/wspCertificateChain'
     REMOTE_ENGINE_CER = 'OVESETUP_CONFIG/remoteEngineCer'
 
+    PKI_WSP_CSR_FILENAME = 'OVESETUP_CONFIG/pkiWSPCSRFilename'
+
+
+@util.export
+@util.codegen
+@osetupattrsclass
+class EngineCoreEnv(object):
+    """Sync with ovirt-engine"""
+    ENABLE = 'OVESETUP_ENGINE_CORE/enable'
+
 
 @util.export
 @util.codegen
@@ -146,4 +163,20 @@
     CERTIFICATE_REQUEST = 'WSP_CERTIFICATE_REQUEST'
 
 
+@util.export
+@util.codegen
+@osetupattrsclass
+class EngineConfigEnv(object):
+    """Sync with ovirt-engine"""
+
+    @osetupattrs(
+        answerfile=True,
+        summary=True,
+        description=_('Engine Host FQDN'),
+        postinstallfile=True,
+    )
+    def ENGINE_FQDN(self):
+        return 'OVESETUP_ENGINE_CONFIG/fqdn'
+
+
 # vim: expandtab tabstop=4 shiftwidth=4
diff --git 
a/packaging/setup/plugins/ovirt-engine-setup/websocket_proxy/config.py 
b/packaging/setup/plugins/ovirt-engine-setup/websocket_proxy/config.py
index 4950bf2..7591b89 100644
--- a/packaging/setup/plugins/ovirt-engine-setup/websocket_proxy/config.py
+++ b/packaging/setup/plugins/ovirt-engine-setup/websocket_proxy/config.py
@@ -33,8 +33,10 @@
 
 
 from ovirt_engine_setup import constants as osetupcons
+from ovirt_engine_setup.engine_common import constants as oengcommcons
 from ovirt_engine_setup.websocket_proxy import constants as owspcons
 from ovirt_engine_setup import dialog
+from ovirt_engine_setup import hostname as osetuphostname
 
 
 @util.export
@@ -61,6 +63,14 @@
         self.environment.setdefault(
             owspcons.ConfigEnv.WEBSOCKET_PROXY_HOST,
             'localhost'
+        )
+        self.environment.setdefault(
+            owspcons.EngineConfigEnv.ENGINE_FQDN,
+            None
+        )
+        self.environment.setdefault(
+            owspcons.EngineCoreEnv.ENABLE,
+            None
         )
 
     @plugin.event(
@@ -116,6 +126,28 @@
 
     @plugin.event(
         stage=plugin.Stages.STAGE_CUSTOMIZATION,
+        after=(
+            osetupcons.Stages.DIALOG_TITLES_S_NETWORK,
+            oengcommcons.Stages.NETWORK_OWNERS_CONFIG_CUSTOMIZED,
+        ),
+        before=(
+            osetupcons.Stages.DIALOG_TITLES_E_NETWORK,
+        ),
+        condition=lambda self: self.environment[
+            owspcons.ConfigEnv.WEBSOCKET_PROXY_CONFIG
+        ],
+    )
+    def _customization_network(self):
+        osetuphostname.Hostname(
+            plugin=self,
+        ).getHostname(
+            envkey=owspcons.EngineConfigEnv.ENGINE_FQDN,
+            whichhost=_('the engine'),
+            supply_default=False,
+        )
+
+    @plugin.event(
+        stage=plugin.Stages.STAGE_CUSTOMIZATION,
         condition=lambda self: self.environment[
             owspcons.ConfigEnv.WEBSOCKET_PROXY_CONFIG
         ],
diff --git a/packaging/setup/plugins/ovirt-engine-setup/websocket_proxy/pki.py 
b/packaging/setup/plugins/ovirt-engine-setup/websocket_proxy/pki.py
index a8d9216..d7bae33 100644
--- a/packaging/setup/plugins/ovirt-engine-setup/websocket_proxy/pki.py
+++ b/packaging/setup/plugins/ovirt-engine-setup/websocket_proxy/pki.py
@@ -22,16 +22,11 @@
 import contextlib
 import os
 import urllib2
-import tempfile
+import time
 
 
 import gettext
 _ = lambda m: gettext.dgettext(message=m, domain='ovirt-engine-setup')
-
-
-from M2Crypto import X509
-from M2Crypto import EVP
-from M2Crypto import RSA
 
 
 from otopi import constants as otopicons
@@ -41,47 +36,28 @@
 
 
 from ovirt_engine_setup import constants as osetupcons
+from ovirt_engine_setup import remote_engine
+from ovirt_engine_setup.engine_common import constants as oengcommcons
 from ovirt_engine_setup.websocket_proxy import constants as owspcons
-from ovirt_engine_setup import dialog
 
 
 @util.export
 class Plugin(plugin.PluginBase):
     """websocket proxy plugin."""
 
-    def _genReq(self):
-
-        rsa = RSA.gen_key(
-            self.environment[owspcons.ConfigEnv.KEY_SIZE],
-            65537,
-        )
-        rsapem = rsa.as_pem(cipher=None)
-        evp = EVP.PKey()
-        evp.assign_rsa(rsa)
-        rsa = None  # should not be freed here
-        req = X509.Request()
-        req.set_pubkey(evp)
-        req.sign(evp, 'sha1')
-        return rsapem, req.as_pem(), req.get_pubkey().as_pem(cipher=None)
-
     def __init__(self, context):
         super(Plugin, self).__init__(context=context)
         self._enabled = False
-        self._need_key = False
-        self._need_cert = False
-        self._on_separate_h = False
-        self._csr_file = None
+        self._enrolldata = None
+        self._need_eng_cert = False
+        self._engine_cert = None
 
     @plugin.event(
         stage=plugin.Stages.STAGE_INIT,
     )
     def _init(self):
         self.environment.setdefault(
-            owspcons.ConfigEnv.WSP_CERTIFICATE_CHAIN,
-            None
-        )
-        self.environment.setdefault(
-            owspcons.ConfigEnv.REMOTE_ENGINE_CER,
+            owspcons.ConfigEnv.PKI_WSP_CSR_FILENAME,
             None
         )
         self.environment.setdefault(
@@ -90,12 +66,111 @@
         )
 
     @plugin.event(
-        stage=plugin.Stages.STAGE_VALIDATION,
+        stage=plugin.Stages.STAGE_CUSTOMIZATION,
+        before=(
+            oengcommcons.Stages.DIALOG_TITLES_E_PKI,
+        ),
+        after=(
+            owspcons.Stages.CONFIG_WEBSOCKET_PROXY_CUSTOMIZATION,
+            owspcons.Stages.ENGINE_CORE_ENABLE,
+            oengcommcons.Stages.DIALOG_TITLES_S_PKI,
+        ),
+        condition=lambda self: (
+            self.environment[
+                owspcons.ConfigEnv.WEBSOCKET_PROXY_CONFIG
+            ] and
+            # If on same host as engine, engine setup code creates pki for us
+            not self.environment[
+                owspcons.EngineCoreEnv.ENABLE
+            ]
+        ),
     )
-    def _validate(self):
-        self._enabled = self.environment[
-            owspcons.ConfigEnv.WEBSOCKET_PROXY_CONFIG
-        ]
+    def _customization(self):
+        self._enabled = True
+
+        engine_wsp_pki_found = (
+            os.path.exists(
+                owspcons.FileLocations.OVIRT_ENGINE_PKI_WEBSOCKET_PROXY_KEY
+            ) and os.path.exists(
+                owspcons.FileLocations.OVIRT_ENGINE_PKI_WEBSOCKET_PROXY_CERT
+            ) and os.path.exists(
+                owspcons.FileLocations.OVIRT_ENGINE_PKI_ENGINE_CERT
+            )
+        )
+
+        if not engine_wsp_pki_found:
+            self._enrolldata = remote_engine.EnrollCert(
+                remote_engine=self.environment[
+                    osetupcons.CoreEnv.REMOTE_ENGINE
+                ],
+                engine_fqdn=self.environment[
+                    owspcons.EngineConfigEnv.ENGINE_FQDN
+                ],
+                base_name=owspcons.Const.WEBSOCKET_PROXY_CERT_NAME,
+                base_touser=_('WebSocket Proxy'),
+                key_file=owspcons.FileLocations.
+                OVIRT_ENGINE_PKI_WEBSOCKET_PROXY_KEY,
+                cert_file=owspcons.FileLocations.
+                OVIRT_ENGINE_PKI_WEBSOCKET_PROXY_CERT,
+                csr_fname_envkey=owspcons.ConfigEnv.
+                PKI_WSP_CSR_FILENAME,
+                engine_ca_cert_file=os.path.join(
+                    owspcons.FileLocations.OVIRT_ENGINE_PKIDIR,
+                    'ca.pem'
+                ),
+                engine_pki_requests_dir=owspcons.FileLocations.
+                OVIRT_ENGINE_PKIREQUESTSDIR,
+                engine_pki_certs_dir=owspcons.FileLocations.
+                OVIRT_ENGINE_PKICERTSDIR,
+                key_size=self.environment[owspcons.ConfigEnv.KEY_SIZE],
+                url="http://http://www.ovirt.org/Features/";
+                    "WebSocketProxy_on_a_separate_host",
+            )
+            self._enrolldata.enroll_cert()
+
+            self._need_eng_cert = not os.path.exists(
+                owspcons.FileLocations.
+                OVIRT_ENGINE_PKI_ENGINE_CERT
+            )
+        else:
+            self._enabled = False
+
+        tries_left = 30
+        while (
+            self._need_eng_cert and
+            self._engine_cert is None and
+            tries_left > 0
+        ):
+            remote_engine_host = self.environment[
+                owspcons.EngineConfigEnv.ENGINE_FQDN
+            ]
+
+            with contextlib.closing(
+                urllib2.urlopen(
+                    'http://{engine_fqdn}/ovirt-engine/services/'
+                    'pki-resource?resource=engine-certificate&'
+                    'format=X509-PEM'.format(
+                        engine_fqdn=remote_engine_host
+                    )
+                )
+            ) as urlObj:
+                engine_ca_cert = urlObj.read()
+                if engine_ca_cert:
+                    self._engine_cert = engine_ca_cert
+                else:
+                    self.logger.error(
+                        _(
+                            'Failed to get the engine certificate '
+                            'from the engine host. '
+                            'Please check access to the engine and its '
+                            'status.'
+                        )
+                    )
+                    time.sleep(10)
+                    tries_left -= 1
+        if self._need_eng_cert and self._engine_cert is None:
+            raise RuntimeError(_('Failed to get the engine certificate from '
+                                 'the engine host'))
 
     @plugin.event(
         stage=plugin.Stages.STAGE_MISC,
@@ -107,246 +182,24 @@
         ),
     )
     def _misc_pki(self):
-
-        self._need_cert = not os.path.exists(
-            owspcons.FileLocations.
-            OVIRT_ENGINE_PKI_WEBSOCKET_PROXY_CERT
+        self._enrolldata.add_to_transaction(
+            uninstall_group_name='ca_pki_wsp',
+            uninstall_group_desc='WSP PKI keys',
+        )
+        uninstall_files = []
+        self.environment[
+            osetupcons.CoreEnv.REGISTER_UNINSTALL_GROUPS
+        ].createGroup(
+            group='ca_pki_wsp',
+            description='WSP PKI keys',
+            optional=True,
+        ).addFiles(
+            group='ca_pki_wsp',
+            fileList=uninstall_files,
         )
 
-        self._need_key = not os.path.exists(
-            owspcons.FileLocations.
-            OVIRT_ENGINE_PKI_WEBSOCKET_PROXY_KEY
-        )
-
-        self._on_separate_h = not os.path.exists(
-            owspcons.FileLocations.
-            OVIRT_ENGINE_PKI_ENGINE_CERT
-        )
-
-        inline = True
-        my_pubk = None
-        if self._need_key:
-            wspkey, req, my_pubk = self._genReq()
-
-            inline = dialog.queryBoolean(
-                dialog=self.dialog,
-                name='OVESETUP_CSR_INLINE',
-                note=_(
-                    '\nDo you prefer to manage certificate signing request '
-                    'and response\n'
-                    'inline or thought support files? '
-                    '(@VALUES@) [@DEFAULT@]: '
-                ),
-                prompt=True,
-                true=_('Inline'),
-                false=_('Files'),
-                default=True,
-            )
-
-            if inline:
-                self.dialog.displayMultiString(
-                    name=owspcons.Displays.CERTIFICATE_REQUEST,
-                    value=req.splitlines(),
-                    note=_(
-                        '\nPlease issue WebSocket Proxy certificate based '
-                        'on this certificate request\n\n'
-                    ),
-                )
-            else:
-                self._csr_file = tempfile.NamedTemporaryFile(
-                    mode='w',
-                    delete=False,
-                )
-                self._csr_file.write(req)
-                self._csr_file.close()
-                self.dialog.note(
-                    text=_(
-                        "\nThe certificate signing request is available at:\n"
-                        "{fname}\n\n"
-                    ).format(
-                        fname=self._csr_file.name,
-                    ),
-                )
+        if self._need_eng_cert:
             self.environment[otopicons.CoreEnv.MAIN_TRANSACTION].append(
-                filetransaction.FileTransaction(
-                    name=owspcons.FileLocations.
-                    OVIRT_ENGINE_PKI_WEBSOCKET_PROXY_KEY,
-                    mode=0o600,
-                    owner=self.environment[osetupcons.SystemEnv.USER_ENGINE],
-                    enforcePermissions=True,
-                    content=wspkey,
-                    modifiedList=self.environment[
-                        otopicons.CoreEnv.MODIFIED_FILES
-                    ],
-                )
-            )
-
-        if self._need_cert:
-            self.dialog.note(
-                text=_(
-                    "\nEnroll SSL certificate for the websocket proxy "
-                    "service.\n"
-                    "It can be done using engine internal CA, if no 3rd "
-                    "party CA is available,\n"
-                    "with this sequence:\n\n"
-                    "1. Copy and save certificate request at\n"
-                    "    /etc/pki/ovirt-engine/requests/{name}-{fqdn}.req\n"
-                    "on the engine host\n\n"
-                    "2. execute, on the engine host, this command "
-                    "to enroll the cert:\n"
-                    " /usr/share/ovirt-engine/bin/pki-enroll-request.sh \\\n"
-                    "     --name={name}-{fqdn} \\\n"
-                    "     --subject=\"/C=<country>/O=<organization>/"
-                    "CN={fqdn}\"\n"
-                    "Substitute <country>, <organization> to suite your "
-                    "environment\n"
-                    "(i.e. the values must match values in the "
-                    "certificate authority of your engine)\n\n"
-                ).format(
-                    fqdn=self.environment[osetupcons.ConfigEnv.FQDN],
-                    name=owspcons.Const.WEBSOCKET_PROXY_CERT_NAME,
-                ),
-            )
-
-            if inline:
-                self.dialog.note(
-                    text=_(
-                        "3. Certificate will be available at\n"
-                        "    /etc/pki/ovirt-engine/certs/{name}-{fqdn}.cer\n"
-                        "on the engine host, please paste that content here "
-                        "when required\n"
-                    ).format(
-                        fqdn=self.environment[osetupcons.ConfigEnv.FQDN],
-                        name=owspcons.Const.WEBSOCKET_PROXY_CERT_NAME,
-                    ),
-                )
-            else:
-                self.dialog.note(
-                    text=_(
-                        "3. Certificate will be available at\n"
-                        "    /etc/pki/ovirt-engine/certs/{name}-{fqdn}.cer\n"
-                        "on the engine host, please copy that file here "
-                        "and provide its location when required\n"
-                    ).format(
-                        fqdn=self.environment[osetupcons.ConfigEnv.FQDN],
-                        name=owspcons.Const.WEBSOCKET_PROXY_CERT_NAME,
-                    ),
-                )
-
-            goodcert = False
-            while not goodcert:
-                if inline:
-                    self.environment[
-                        owspcons.ConfigEnv.WSP_CERTIFICATE_CHAIN
-                    ] = '\n'.join(
-                        self.dialog.queryMultiString(
-                            name=owspcons.ConfigEnv.WSP_CERTIFICATE_CHAIN,
-                            note=_(
-                                '\nPlease input WSP certificate chain that '
-                                'matches certificate request,\n'
-                                '(issuer is not mandatory, from intermediate'
-                                ' and upper)\n\n'
-                            ),
-                        )
-                    )
-                else:
-                    goodfile = False
-                    while not goodfile:
-                        filename = self.dialog.queryString(
-                            name='WSP_T_CERT_FILENAME',
-                            note=_(
-                                '\nPlease input the location of the file '
-                                'where you copied\n'
-                                'back the signed cert on this host: '
-                            ),
-                            prompt=True,
-                        )
-                        try:
-                            with open(filename) as f:
-                                self.environment[
-                                    owspcons.ConfigEnv.WSP_CERTIFICATE_CHAIN
-                                ] = f.read()
-                                goodfile = True
-                        except EnvironmentError:
-                            self.logger.error(
-                                _(
-                                    'Error reading {fname}, '
-                                    'please try again'
-                                ).format(
-                                    fname=filename,
-                                )
-                            )
-                try:
-                    if my_pubk == X509.load_cert_string(
-                        self.environment[
-                            owspcons.ConfigEnv.WSP_CERTIFICATE_CHAIN
-                        ]
-                    ).get_pubkey().as_pem(cipher=None):
-                        goodcert = True
-                    else:
-                        self.logger.error(
-                            _(
-                                'The cert you provided doesn\'t '
-                                'match the required CSR.\n'
-                                'Please try again'
-                            )
-                        )
-                except X509.X509Error:
-                    self.logger.error(
-                        _(
-                            'The cert you provided is invalid.\n'
-                            'Please try again'
-                        )
-                    )
-
-            self.environment[otopicons.CoreEnv.MAIN_TRANSACTION].append(
-                filetransaction.FileTransaction(
-                    name=owspcons.FileLocations.
-                    OVIRT_ENGINE_PKI_WEBSOCKET_PROXY_CERT,
-                    mode=0o600,
-                    owner=self.environment[osetupcons.SystemEnv.USER_ENGINE],
-                    enforcePermissions=True,
-                    content=self.environment[
-                        owspcons.ConfigEnv.WSP_CERTIFICATE_CHAIN
-                    ],
-                    modifiedList=self.environment[
-                        otopicons.CoreEnv.MODIFIED_FILES
-                    ],
-                )
-            )
-
-        if self._on_separate_h:
-            self.logger.debug('Acquiring engine.crt from the engine')
-            while not self.environment[
-                owspcons.ConfigEnv.REMOTE_ENGINE_CER
-            ]:
-                remote_engine_host = self.dialog.queryString(
-                    name='REMOTE_ENGINE_HOST',
-                    note=_(
-                        'Please provide the FQDN or IP '
-                        'of the remote engine host: '
-                    ),
-                    prompt=True,
-                )
-
-                with contextlib.closing(
-                    urllib2.urlopen(
-                        'http://{engine_fqdn}/ovirt-engine/services/'
-                        'pki-resource?resource=engine-certificate&'
-                        'format=X509-PEM'.format(
-                            engine_fqdn=remote_engine_host
-                        )
-                    )
-                ) as urlObj:
-                    engine_cer = urlObj.read()
-                    if engine_cer:
-                        self.environment[
-                            owspcons.ConfigEnv.REMOTE_ENGINE_CER
-                        ] = engine_cer
-
-            self.environment[
-                otopicons.CoreEnv.MAIN_TRANSACTION
-            ].append(
                 filetransaction.FileTransaction(
                     name=owspcons.FileLocations.
                     OVIRT_ENGINE_PKI_ENGINE_CERT,
@@ -355,22 +208,22 @@
                         osetupcons.SystemEnv.USER_ENGINE
                     ],
                     enforcePermissions=True,
-                    content=self.environment[
-                        owspcons.ConfigEnv.REMOTE_ENGINE_CER
-                    ],
-                    modifiedList=self.environment[
-                        otopicons.CoreEnv.MODIFIED_FILES
-                    ],
+                    content=self._engine_cert,
+                    modifiedList=uninstall_files,
                 )
+            )
+            uninstall_files.append(
+                owspcons.FileLocations.OVIRT_ENGINE_PKI_ENGINE_CERT
             )
 
     @plugin.event(
         stage=plugin.Stages.STAGE_CLEANUP,
+        condition=lambda self: (
+            self._enabled
+        ),
     )
     def _cleanup(self):
-        if self._csr_file is not None:
-            if os.path.exists(self._csr_file.name):
-                os.unlink(self._csr_file.name)
+        self._enrolldata.cleanup()
 
 
 # vim: expandtab tabstop=4 shiftwidth=4


-- 
To view, visit http://gerrit.ovirt.org/33941
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Id72711fb1577d5ee97454a36650456c2675206be
Gerrit-PatchSet: 1
Gerrit-Project: ovirt-engine
Gerrit-Branch: ovirt-engine-3.5
Gerrit-Owner: Simone Tiraboschi <stira...@redhat.com>
_______________________________________________
Engine-patches mailing list
Engine-patches@ovirt.org
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to