From 14583a2efa0a6a81627235ae4ae61ca056b0abb6 Mon Sep 17 00:00:00 2001 From: Matthias Lehmann Date: Tue, 28 Jan 2014 16:16:48 +0100 Subject: [PATCH 1/6] add support for client SSL certificate and key --- httpie/cli.py | 21 +++++++++++++++++++++ httpie/client.py | 7 +++++++ 2 files changed, 28 insertions(+) diff --git a/httpie/cli.py b/httpie/cli.py index 321e452e..5de07a37 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -465,6 +465,27 @@ network.add_argument( """ ) +network.add_argument( + '--ssl-cert', + default=None, + help=""" + You can specify a local cert to use as client side SSL certificate. + This file may either contain both private key and certificate or you may + specify --ssl-key separately. + + """ +) + +network.add_argument( + '--ssl-key', + default=None, + help=""" + The private key to use with SSL. Only needed if --ssl-cert is given and the + certificate file does not contain the private key. + + """ +) + network.add_argument( '--timeout', type=float, diff --git a/httpie/client.py b/httpie/client.py index 5f519515..8514ece2 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -73,6 +73,12 @@ def get_requests_kwargs(args): auth_plugin = plugin_manager.get_auth_plugin(args.auth_type)() credentials = auth_plugin.get_auth(args.auth.key, args.auth.value) + cert = None + if args.ssl_cert: + cert = args.ssl_cert + if args.ssl_key: + cert = (cert, args.ssl_key) + kwargs = { 'stream': True, 'method': args.method.lower(), @@ -83,6 +89,7 @@ def get_requests_kwargs(args): 'yes': True, 'no': False }.get(args.verify, args.verify), + 'cert': cert, 'timeout': args.timeout, 'auth': credentials, 'proxies': dict((p.key, p.value) for p in args.proxy), From b9d7220b102b56a8c6b85f82e548ba634699cacb Mon Sep 17 00:00:00 2001 From: Matthias Lehmann Date: Wed, 29 Jan 2014 15:54:19 +0100 Subject: [PATCH 2/6] check --ssl-cert and --ssl-key to be files --- httpie/cli.py | 3 +++ httpie/utils.py | 10 ++++++++++ 2 files changed, 13 insertions(+) diff --git a/httpie/cli.py b/httpie/cli.py index 5de07a37..229ac274 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -19,6 +19,7 @@ from .input import (Parser, AuthCredentialsArgType, KeyValueArgType, OUT_REQ_HEAD, OUT_REQ_BODY, OUT_RESP_HEAD, OUT_RESP_BODY, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, SessionNameValidator) +from .utils import existing_file class HTTPieHelpFormatter(RawDescriptionHelpFormatter): @@ -468,6 +469,7 @@ network.add_argument( network.add_argument( '--ssl-cert', default=None, + type=existing_file, help=""" You can specify a local cert to use as client side SSL certificate. This file may either contain both private key and certificate or you may @@ -479,6 +481,7 @@ network.add_argument( network.add_argument( '--ssl-key', default=None, + type=existing_file, help=""" The private key to use with SSL. Only needed if --ssl-cert is given and the certificate file does not contain the private key. diff --git a/httpie/utils.py b/httpie/utils.py index fe721c4e..3200cce2 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -1,4 +1,5 @@ from __future__ import division +import argparse def humanize_bytes(n, precision=2): @@ -44,3 +45,12 @@ def humanize_bytes(n, precision=2): break return '%.*f %s' % (precision, n / factor, suffix) + + +def existing_file(filename): + try: + open(filename, 'rb') + except IOError as ex: + raise argparse.ArgumentTypeError( + '%s: %s' % (filename, ex.args[1])) + return filename From d4363a560db2c1716a52373f9f1595aa95956e4f Mon Sep 17 00:00:00 2001 From: Matthias Lehmann Date: Wed, 29 Jan 2014 18:02:06 +0100 Subject: [PATCH 3/6] rename existing_file to readable_file_arg and move to input --- httpie/cli.py | 8 ++++---- httpie/input.py | 10 ++++++++++ httpie/utils.py | 9 --------- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index 229ac274..b087f783 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -18,8 +18,8 @@ from .input import (Parser, AuthCredentialsArgType, KeyValueArgType, SEP_PROXY, SEP_CREDENTIALS, SEP_GROUP_ALL_ITEMS, OUT_REQ_HEAD, OUT_REQ_BODY, OUT_RESP_HEAD, OUT_RESP_BODY, OUTPUT_OPTIONS, OUTPUT_OPTIONS_DEFAULT, - PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, SessionNameValidator) -from .utils import existing_file + PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, SessionNameValidator, + readable_file_arg) class HTTPieHelpFormatter(RawDescriptionHelpFormatter): @@ -469,7 +469,7 @@ network.add_argument( network.add_argument( '--ssl-cert', default=None, - type=existing_file, + type=readable_file_arg, help=""" You can specify a local cert to use as client side SSL certificate. This file may either contain both private key and certificate or you may @@ -481,7 +481,7 @@ network.add_argument( network.add_argument( '--ssl-key', default=None, - type=existing_file, + type=readable_file_arg, help=""" The private key to use with SSL. Only needed if --ssl-cert is given and the certificate file does not contain the private key. diff --git a/httpie/input.py b/httpie/input.py index 3c180129..24269db4 100644 --- a/httpie/input.py +++ b/httpie/input.py @@ -1,6 +1,7 @@ """Parsing and processing of CLI input (args, auth credentials, files, stdin). """ +import argparse import os import sys import re @@ -630,3 +631,12 @@ def parse_items(items, data=None, headers=None, files=None, params=None): target[item.key] = value return headers, data, files, params + + +def readable_file_arg(filename): + try: + open(filename, 'rb') + except IOError as ex: + raise argparse.ArgumentTypeError( + '%s: %s' % (filename, ex.args[1])) + return filename diff --git a/httpie/utils.py b/httpie/utils.py index 3200cce2..37ac745d 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -1,5 +1,4 @@ from __future__ import division -import argparse def humanize_bytes(n, precision=2): @@ -46,11 +45,3 @@ def humanize_bytes(n, precision=2): return '%.*f %s' % (precision, n / factor, suffix) - -def existing_file(filename): - try: - open(filename, 'rb') - except IOError as ex: - raise argparse.ArgumentTypeError( - '%s: %s' % (filename, ex.args[1])) - return filename From a3aae12d9c374189a8014f2f2506b83338e4b190 Mon Sep 17 00:00:00 2001 From: Matthias Lehmann Date: Wed, 5 Feb 2014 12:50:40 +0100 Subject: [PATCH 4/6] rename -ssl-cert and --ssl-key to --cert and --certkey --- httpie/cli.py | 8 ++++---- httpie/client.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/httpie/cli.py b/httpie/cli.py index b087f783..13fb158d 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -467,23 +467,23 @@ network.add_argument( ) network.add_argument( - '--ssl-cert', + '--cert', default=None, type=readable_file_arg, help=""" You can specify a local cert to use as client side SSL certificate. This file may either contain both private key and certificate or you may - specify --ssl-key separately. + specify --certkey separately. """ ) network.add_argument( - '--ssl-key', + '--certkey', default=None, type=readable_file_arg, help=""" - The private key to use with SSL. Only needed if --ssl-cert is given and the + The private key to use with SSL. Only needed if --cert is given and the certificate file does not contain the private key. """ diff --git a/httpie/client.py b/httpie/client.py index 8514ece2..cccaf4c8 100644 --- a/httpie/client.py +++ b/httpie/client.py @@ -74,10 +74,10 @@ def get_requests_kwargs(args): credentials = auth_plugin.get_auth(args.auth.key, args.auth.value) cert = None - if args.ssl_cert: - cert = args.ssl_cert - if args.ssl_key: - cert = (cert, args.ssl_key) + if args.cert: + cert = args.cert + if args.certkey: + cert = (cert, args.certkey) kwargs = { 'stream': True, From dd7197c60b97cbe70a49ffb2737f92ad2f538cfa Mon Sep 17 00:00:00 2001 From: Matthias Lehmann Date: Wed, 5 Feb 2014 12:51:05 +0100 Subject: [PATCH 5/6] document --cert and --certkey --- README.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.rst b/README.rst index a362e622..b5a50713 100644 --- a/README.rst +++ b/README.rst @@ -615,6 +615,10 @@ To skip the host's SSL certificate verification, you can pass ``--verify=no`` path. The path can also be configured via the environment variable ``REQUESTS_CA_BUNDLE``. +To use a client side certificate for the SSL communication, you can pass the +path of the cert file with ``--cert``. If the private key is not contained +in the cert file you may pass the path of the key file with ``--certkey``. + ============== Output Options From b3a34aba4471d479b52758ea9ea1aa0e1e94f741 Mon Sep 17 00:00:00 2001 From: Matthias Lehmann Date: Wed, 12 Feb 2014 11:23:31 +0100 Subject: [PATCH 6/6] added --cert to CHANGELOG and matleh to AUTHORS --- AUTHORS.rst | 1 + README.rst | 2 ++ 2 files changed, 3 insertions(+) diff --git a/AUTHORS.rst b/AUTHORS.rst index 126e6a7b..f17b336f 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -30,3 +30,4 @@ Patches and ideas * `cido `_ * `Justin Bonnar `_ * `Nathan LaFreniere `_ +* `Matthias Lehmann ` diff --git a/README.rst b/README.rst index b5a50713..3346d5e2 100644 --- a/README.rst +++ b/README.rst @@ -1269,6 +1269,8 @@ Changelog *You can click a version name to see a diff with the previous one.* * `0.9.0-dev`_ + * Added ``--cert`` and ``--certkey`` parameters to specify a client side + certificate and private key for SSL * `0.8.0`_ (2014-01-25) * Added ``field=@file.txt`` and ``field:=@file.json`` for embedding the contents of text and JSON files into request data.