Эх сурвалжийг харах

Hue [py3] Enable SAML certificate creation with passphrase support.

Prakash Ranade 3 жил өмнө
parent
commit
107cafa187

+ 38 - 11
desktop/core/ext-py3/pysaml2-5.0.0/src/saml2/sigver.py

@@ -457,9 +457,10 @@ def pem_format(key):
     ]).encode('ascii')
 
 
-def import_rsa_key_from_file(filename):
+def import_rsa_key_from_file(filename, passphrase=None):
     data = read_file(filename, 'rb')
-    key = saml2.cryptography.asymmetric.load_pem_private_key(data, None)
+    passphrase = bytes(passphrase) if passphrase else None
+    key = saml2.cryptography.asymmetric.load_pem_private_key(data, passphrase)
     return key
 
 
@@ -771,7 +772,7 @@ class CryptoBackendXmlSec1(CryptoBackend):
 
         return output.decode('utf-8')
 
-    def decrypt(self, enctext, key_file, id_attr):
+    def decrypt(self, enctext, key_file, id_attr, passphrase=None):
         """
 
         :param enctext: XML document containing an encrypted part
@@ -785,19 +786,20 @@ class CryptoBackendXmlSec1(CryptoBackend):
         com_list = [
             self.xmlsec,
             '--decrypt',
-            '--privkey-pem', key_file,
             '--id-attr:{id_attr}'.format(id_attr=id_attr),
             ENC_KEY_CLASS,
         ]
 
         try:
-            (_stdout, _stderr, output) = self._run_xmlsec(com_list, [tmp.name])
+            (_stdout, _stderr, output) = self._run_xmlsec(com_list, [tmp.name],
+                                                         key_file=key_file,
+                                                         passphrase=passphrase)
         except XmlsecError as e:
             six.raise_from(DecryptError(com_list), e)
 
         return output.decode('utf-8')
 
-    def sign_statement(self, statement, node_name, key_file, node_id, id_attr):
+    def sign_statement(self, statement, node_name, key_file, node_id, id_attr, passphrase=None):
         """
         Sign an XML statement.
 
@@ -820,7 +822,6 @@ class CryptoBackendXmlSec1(CryptoBackend):
         com_list = [
             self.xmlsec,
             '--sign',
-            '--privkey-pem', key_file,
             '--id-attr:{id_attr_name}'.format(id_attr_name=id_attr),
             node_name,
         ]
@@ -829,7 +830,9 @@ class CryptoBackendXmlSec1(CryptoBackend):
             com_list.extend(['--node-id', node_id])
 
         try:
-            (stdout, stderr, output) = self._run_xmlsec(com_list, [tmp.name])
+            (stdout, stderr, output) = self._run_xmlsec(com_list, [tmp.name],
+                                                       key_file=key_file,
+                                                       passphrase=passphrase)
         except XmlsecError as e:
             raise SignatureError(com_list)
 
@@ -880,7 +883,7 @@ class CryptoBackendXmlSec1(CryptoBackend):
 
         return parse_xmlsec_output(stderr)
 
-    def _run_xmlsec(self, com_list, extra_args):
+    def _run_xmlsec(self, com_list, extra_args, key_file=None, passphrase=None):
         """
         Common code to invoke xmlsec and parse the output.
         :param com_list: Key-value parameter list for xmlsec
@@ -890,6 +893,25 @@ class CryptoBackendXmlSec1(CryptoBackend):
         """
         with NamedTemporaryFile(suffix='.xml') as ntf:
             com_list.extend(['--output', ntf.name])
+
+            # Unfortunately there's no safe way to pass a password to xmlsec1.
+            # Instead, we'll decrypt the certificate and write it into a named pipe,
+            # which we'll pass to xmlsec1.
+            named_pipe = None
+            if key_file is not None:
+                if passphrase is not None:
+                    named_pipe = NamedPipe()
+
+                    # Decrypt the certificate, but don't write it into the FIFO
+                    # until after we've started xmlsec1.
+                    key_content = ''
+                    with open(key_file, 'r') as f:
+                        key_content = f.read()
+                    key = crypto.load_privatekey(crypto.FILETYPE_PEM, key_content, passphrase=str(passphrase))
+                    key_file = named_pipe.name
+
+                com_list.extend(["--privkey-pem", key_file])
+
             com_list += extra_args
 
             logger.debug('xmlsec command: %s', ' '.join(com_list))
@@ -1023,7 +1045,7 @@ def security_context(conf):
         _file_name = conf.getattr('key_file', '')
         if _file_name:
             try:
-                rsa_key = import_rsa_key_from_file(_file_name)
+                rsa_key = import_rsa_key_from_file(_file_name, passphrase=conf.key_file_passphrase)
             except Exception as err:
                 logger.error('Cannot import key from {file}: {err_msg}'.format(
                     file=_file_name, err_msg=err))
@@ -1371,12 +1393,17 @@ class SecurityContext(object):
         else:
             return dectext
 
-    def decrypt(self, enctext, key_file=None, id_attr=''):
+    def decrypt(self, enctext, key_file=None, id_attr='', passphrase=None):
         """ Decrypting an encrypted text by the use of a private key.
 
         :param enctext: The encrypted text as a string
         :return: The decrypted text
         """
+        if key_file is None or len(key_file) == 0:
+            key_file = self.key_file
+        if passphrase is None:
+            passphrase = self.key_file_passphrase
+
         if not id_attr:
             id_attr = self.id_attr