2016-08-01 23 views
3

Ich versuche, ein Zertifikat mit einer CA-Bundle-Datei zu validieren. Der ursprüngliche Bash-Befehl benötigt zwei Dateiargumente wie diesen;Unterprozessbefehl mit zwei String-Eingaben ausführen

openssl verify -CAfile ca-ssl.ca cert-ssl.crt 

Ich versuche, herauszufinden, wie man den obigen Befehl in Python subprocess läuft ca-ssl.ca und cert-ssl.crt als variable Strings während mit (im Gegensatz zu Dateien im Gegensatz).

Wenn ich den Befehl mit Variablen (anstelle von Dateien) in bash ausgeführt würde, dann würde dies funktionieren;

ca_value=$(<ca-ssl.ca) 
cert_value=$(<cert-ssl.crt) 

openssl verify -CAfile <(echo "$ca_value") <(echo "$cert_value") 

Aber ich bin zu kämpfen, herauszufinden, wie mit Python die oben genannten zu tun, vorzugsweise ohne shell=True verwenden zu müssen. Ich habe folgendes versucht, funktioniert aber nicht und druckt stattdessen 'help' Befehle für openssl;

certificate = ''' cert string ''' 
ca_bundle = ''' ca bundle string ''' 

def ca_valid(cert, ca): 
    ca_validation = subprocess.Popen(['openssl', 'verify', '-CAfile', ca, cert], stdin=subprocess.PIPE, stdout=subprocess.PIPE, bufsize=1) 
    ca_validation_output = ca_validation.communicate()[0].strip() 
    ca_validation.wait() 

ca_valid(certificate, ca_bundle) 

Alle Hinweise/Hinweise zu dem, was ich weiter untersuchen muss, wären willkommen.

+0

Als einen einfachen Ausweg würden Sie in Betracht ziehen, das Modul [tempfile] (https://docs.python.org/3/library/tempfile.html) zu verwenden? – wim

+0

Vielleicht verwenden Sie stattdessen 'os.system()'? – baranskistad

+0

Sind Sie sicher, dass Sie den Befehl richtig haben? Wenn ich den Befehl ausführe, der von Ihrer Liste direkt in einem Terminal erstellt werden würde, erhalte ich auch die Verwendungshilfe-Zeichenfolge von openssl. – xgord

Antwort

-2

Wenn Sie die Prozesssubstitution verwenden möchten, verwenden Sie , um shell=True zu verwenden. Dies ist unvermeidlich. Die <(...) Prozesssubstitutionssyntax ist Bash-Syntax; Sie müssen einfach bash in Dienst nehmen, um solchen Code zu parsen und auszuführen.

Zusätzlich müssen Sie sicherstellen, dass bash aufgerufen wird, im Gegensatz zu sh. Auf einigen Systemen kann sich sh auf eine alte Bourne-Shell beziehen (im Gegensatz zur Bourne-again-Shell bash). In diesem Fall wird die Prozesssubstitution definitiv nicht funktionieren. Auf einigen Systemen ruft shbash auf, aber die Prozesssubstitution funktioniert immer noch nicht, da die Shell unter dem Namen sh in den sogenannten POSIX-Modus wechselt. Hier sind einige Auszüge aus dem bash Manpage:

...

INVOCATION

... Wenn sie als sh aufgerufen, bash tritt Posix-Modus, nachdem die Startdateien gelesen werden. ....

...

SIEHE AUCH

...

http://tiswww.case.edu/~chet/bash/POSIX - eine Beschreibung der Posix-Modus

...

Aus der obige Weblink:

  1. Prozesssubstitution ist nicht verfügbar.

/bin/sh scheint die Standard-Shell in Python zu sein, ob Sie os.system() oder subprocess.Popen() verwenden.Sie müssen also das Argument executable='bash' oder executable='/bin/bash' angeben, wenn Sie den vollständigen Pfad angeben möchten.

Dies ist für mich arbeiten:

subprocess.Popen('printf \'argument: "%s"\\n\' verify -CAfile <(echo ca_value) <(echo cert_value);',executable='bash',shell=True).wait(); 
## argument: "verify" 
## argument: "-CAfile" 
## argument: "/dev/fd/63" 
## argument: "/dev/fd/62" 
## 0 

Hier ist, wie Sie tatsächlich die String-Werte von Variablen einbetten können:

bashEsc = lambda s: "'"+s.replace("'","'\\''")+"'"; 
ca_value = 'x'; 
cert_value = 'y'; 
cmd = 'printf \'argument: "%%s"\\n\' verify -CAfile <(echo %s) <(echo %s);'%(bashEsc(ca_value),bashEsc(cert_value)); 
subprocess.Popen(cmd,executable='bash',shell=True).wait(); 
## argument: "verify" 
## argument: "-CAfile" 
## argument: "/dev/fd/63" 
## argument: "/dev/fd/62" 
## 0 
1

Bash Prozess Substitution <(...) am Ende einer Datei liefert Pfad als Argument zu openssl.

Sie eine Hilfsfunktion vornehmen müssen, um diese Funktionalität zu schaffen, da Python keine Operatoren hat, mit denen Sie Rohrdaten in eine Datei Inline und seinen Weg vorstellen:

import subprocess 
def validate_ca(cert, ca): 
    with filearg(ca) as ca_path, filearg(cert) as cert_path: 
     ca_validation = subprocess.Popen(
      ['openssl', 'verify', '-CAfile', ca_path, cert_path], 
      stdout=subprocess.PIPE, 
     ) 
     return ca_validation.communicate()[0].strip() 

Wo filearg ist ein Kontextmanager, der eine benannte temporäre Datei mit dem gewünschten Text erstellt, diesen schließt, den Pfad an Sie weitergibt und ihn dann entfernt, nachdem der Bereich with beendet ist.

import os 
import tempfile 
from contextlib import contextmanager 

@contextmanger 
def filearg(txt): 
    with tempfile.NamedTemporaryFile('w', delete=False) as fh: 
     fh.write(txt) 
    try: 
     yield fh.name 
    finally: 
     os.remove(fh.name) 

Alles, was auf diese temporäre Datei (wie den Subprozess) zugreift, muss innerhalb des Kontextmanagers funktionieren.

Übrigens ist die Popen.wait(self) redundant, da Popen.communicate(self) auf Beendigung wartet.