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 a362e622..3346d5e2 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 @@ -1265,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. diff --git a/httpie/cli.py b/httpie/cli.py index 321e452e..13fb158d 100644 --- a/httpie/cli.py +++ b/httpie/cli.py @@ -18,7 +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) + PRETTY_MAP, PRETTY_STDOUT_TTY_ONLY, SessionNameValidator, + readable_file_arg) class HTTPieHelpFormatter(RawDescriptionHelpFormatter): @@ -465,6 +466,29 @@ network.add_argument( """ ) +network.add_argument( + '--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 --certkey separately. + + """ +) + +network.add_argument( + '--certkey', + default=None, + type=readable_file_arg, + help=""" + The private key to use with SSL. Only needed if --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..cccaf4c8 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.cert: + cert = args.cert + if args.certkey: + cert = (cert, args.certkey) + 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), 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 fe721c4e..37ac745d 100644 --- a/httpie/utils.py +++ b/httpie/utils.py @@ -44,3 +44,4 @@ def humanize_bytes(n, precision=2): break return '%.*f %s' % (precision, n / factor, suffix) +