Browse files

Added support for auth plugins.

  • Loading branch information...
1 parent f7b703b commit 2acb30355200369137643fdc4d7e1bb11572fa42 @jkbrzt committed Sep 21, 2013
Showing with 159 additions and 25 deletions.
  1. +8 −0 README.rst
  2. +1 −1 httpie/__init__.py
  3. +23 −3 httpie/cli.py
  4. +10 −4 httpie/client.py
  5. +4 −1 httpie/core.py
  6. +1 −1 httpie/input.py
  7. +9 −0 httpie/plugins/__init__.py
  8. +28 −0 httpie/plugins/base.py
  9. +26 −0 httpie/plugins/builtin.py
  10. +35 −0 httpie/plugins/manager.py
  11. +14 −15 httpie/sessions.py
View
8 README.rst
@@ -514,6 +514,13 @@ Authorization information from your ``.netrc`` file is honored as well:
[...]
+-------
+Plugins
+-------
+
+* `httpie-ntlm <https://github.com/jkbr/httpie-ntlm>`_
+
+
=======
Proxies
=======
@@ -1206,6 +1213,7 @@ Changelog
* `0.7.0-dev`_
* Added ``--ignore-stdin``.
+ * Added support for auth plugins.
* `0.6.0`_ (2013-06-03)
* XML data is now formatted.

looking good

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
* ``--session`` and ``--session-read-only`` now also accept paths to
View
2 httpie/__init__.py
@@ -3,7 +3,7 @@
"""

hay

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
__author__ = 'Jakub Roztocil'
-__version__ = '0.6.0'
+__version__ = '0.7.0'
__licence__ = 'BSD'
View
26 httpie/cli.py
@@ -10,6 +10,8 @@
from . import __doc__
from . import __version__
+from .plugins.builtin import BuiltinAuthPlugin
+from .plugins import plugin_manager
from .sessions import DEFAULT_SESSIONS_DIR
from .output import AVAILABLE_STYLES, DEFAULT_STYLE
from .input import (Parser, AuthCredentialsArgType, KeyValueArgType,
@@ -381,14 +383,32 @@ def _split_lines(self, text, width):
""",
)
+_auth_plugins = plugin_manager.get_auth_plugins()
auth.add_argument(
'--auth-type',
- choices=['basic', 'digest'],
- default='basic',
+ choices=[plugin.auth_type for plugin in _auth_plugins],
+ default=_auth_plugins[0].auth_type,
help="""
- The authentication mechanism to be used. Defaults to "basic".
+ The authentication mechanism to be used. Defaults to "{default}".
+
+ {types}
"""
+ .format(default=_auth_plugins[0].auth_type, types='\n '.join(
+ '"{type}": {name}{package}{description}'.format(
+ type=plugin.auth_type,
+ name=plugin.name,
+ package=(
+ '' if issubclass(plugin, BuiltinAuthPlugin)
+ else ' (provided by %s)' % plugin.package_name
+ ),
+ description=(
+ '' if not plugin.description else
+ '\n ' + ('\n '.join(wrap(plugin.description)))
+ )
+ )
+ for plugin in _auth_plugins
+ )),
)
View
14 httpie/client.py
@@ -7,13 +7,20 @@
from . import sessions
from . import __version__
+from .plugins import plugin_manager
FORM = 'application/x-www-form-urlencoded; charset=utf-8'
JSON = 'application/json; charset=utf-8'
DEFAULT_UA = 'HTTPie/%s' % __version__
+class HTTPie(object):
+
+ def __init__(self, env, plugin_manager):
+ pass
+
+
def get_response(args, config_dir):
"""Send the request and return a `request.Response`."""
@@ -27,6 +34,7 @@ def get_response(args, config_dir):
response = requests.request(**requests_kwargs)
else:
response = sessions.get_response(
+ args=args,
config_dir=config_dir,
session_name=args.session or args.session_read_only,
requests_kwargs=requests_kwargs,
@@ -69,10 +77,8 @@ def get_requests_kwargs(args):
credentials = None
if args.auth:
- credentials = {
- 'basic': requests.auth.HTTPBasicAuth,
- 'digest': requests.auth.HTTPDigestAuth,
- }[args.auth_type](args.auth.key, args.auth.value)
+ auth_plugin = plugin_manager.get_auth_plugin(args.auth_type)()
+ credentials = auth_plugin.get_auth(args.auth.key, args.auth.value)
kwargs = {
'stream': True,
View
5 httpie/core.py
@@ -18,13 +18,13 @@
from requests import __version__ as requests_version
from pygments import __version__ as pygments_version
-from .cli import parser
from .compat import str, is_py3
from .client import get_response
from .downloads import Download
from .models import Environment
from .output import build_output_stream, write, write_with_colors_win_py3
from . import ExitStatus
+from .plugins import plugin_manager
def get_exit_status(http_status, follow=False):
@@ -58,6 +58,9 @@ def main(args=sys.argv[1:], env=Environment()):
Return exit status code.
"""
+ plugin_manager.load_installed_plugins()
+ from .cli import parser
+
if env.config.default_options:
args = env.config.default_options + args
View
2 httpie/input.py
@@ -6,7 +6,7 @@
import re
import json
import mimetypes
-import getpass
+from getpass import getpass
from io import BytesIO
#noinspection PyCompatibility
from argparse import ArgumentParser, ArgumentTypeError, ArgumentError
View
9 httpie/plugins/__init__.py
@@ -0,0 +1,9 @@
+from .base import AuthPlugin
+from .manager import PluginManager
+from .builtin import BasicAuthPlugin, DigestAuthPlugin
+
+
+plugin_manager = PluginManager()
+plugin_manager.register(BasicAuthPlugin)
+plugin_manager.register(DigestAuthPlugin)
+
View
28 httpie/plugins/base.py
@@ -0,0 +1,28 @@
+class AuthPlugin(object):
+ """
+ Base auth plugin class.
+
+ See <https://github.com/jkbr/httpie-ntlm> for an example auth plugin.
+
+ """
+
+ # The value that should be passed to --auth-type
+ # to use this auth plugin. Eg. "my-auth"
+ auth_type = None
+
+ # The name of the plugin, eg. "My auth".
+ name = None
+
+ # Optional short description. Will be be shown in the help
+ # under --auth-type.
+ description = None
+
+ # This be set automatically once the plugin has been loaded.
+ package_name = None
+
+ def get_auth(self, username, password):
+ """
+ Return a ``requests.auth.AuthBase`` subclass instance.
+
+ """
+ raise NotImplementedError()
View
26 httpie/plugins/builtin.py
@@ -0,0 +1,26 @@
+import requests.auth
+
+from .base import AuthPlugin
+
+
+class BuiltinAuthPlugin(AuthPlugin):
+
+ package_name = '(builtin)'
+
+
+class BasicAuthPlugin(BuiltinAuthPlugin):
+
+ name = 'Basic HTTP auth'
+ auth_type = 'basic'
+
+ def get_auth(self, username, password):
+ return requests.auth.HTTPBasicAuth(username, password)
+
+
+class DigestAuthPlugin(BuiltinAuthPlugin):
+
+ name = 'Digest HTTP auth'
+ auth_type = 'digest'
+
+ def get_auth(self, username, password):
+ return requests.auth.HTTPDigestAuth(username, password)
View
35 httpie/plugins/manager.py
@@ -0,0 +1,35 @@
+from pkg_resources import iter_entry_points
+
+
+ENTRY_POINT_NAMES = [
+ 'httpie.plugins.auth.v1'
+]
+
+
+class PluginManager(object):
+
+ def __init__(self):
+ self._plugins = []
+
+ def __iter__(self):
+ return iter(self._plugins)
+
+ def register(self, plugin):
+ self._plugins.append(plugin)
+
+ def get_auth_plugins(self):
+ return list(self._plugins)
+
+ def get_auth_plugin_mapping(self):
+ return dict((plugin.auth_type, plugin) for plugin in self)
+
+ def get_auth_plugin(self, auth_type):
+ return self.get_auth_plugin_mapping()[auth_type]
+
+ def load_installed_plugins(self):
+
+ for entry_point_name in ENTRY_POINT_NAMES:
+ for entry_point in iter_entry_points(entry_point_name):
+ plugin = entry_point.load()
+ plugin.package_name = entry_point.dist.key
+ self.register(entry_point.load())
View
29 httpie/sessions.py
@@ -6,10 +6,10 @@
import requests
from requests.cookies import RequestsCookieJar, create_cookie
-from requests.auth import HTTPBasicAuth, HTTPDigestAuth
from .compat import urlsplit
from .config import BaseConfigDict, DEFAULT_CONFIG_DIR
+from httpie.plugins import plugin_manager
SESSIONS_DIR_NAME = 'sessions'
@@ -21,7 +21,8 @@
SESSION_IGNORED_HEADER_PREFIXES = ['Content-', 'If-']
-def get_response(session_name, requests_kwargs, config_dir, read_only=False):
+def get_response(session_name, requests_kwargs, config_dir, args,
+ read_only=False):
"""Like `client.get_response`, but applies permanent
aspects of the session to the request.
@@ -50,9 +51,12 @@ def get_response(session_name, requests_kwargs, config_dir, read_only=False):
requests_kwargs['headers'] = dict(session.headers, **request_headers)
session.update_headers(request_headers)
- auth = requests_kwargs.get('auth', None)
- if auth:
- session.auth = auth
+ if args.auth:
+ session.auth = {
+ 'type': args.auth_type,
+ 'username': args.auth.key,
+ 'password': args.auth.value,
+ }
elif session.auth:
requests_kwargs['auth'] = session.auth
@@ -140,15 +144,10 @@ def auth(self):
auth = self.get('auth', None)
if not auth or not auth['type']:
return
- Auth = {'basic': HTTPBasicAuth,
- 'digest': HTTPDigestAuth}[auth['type']]
- return Auth(auth['username'], auth['password'])
+ auth_plugin = plugin_manager.get_auth_plugin(auth['type'])()
+ return auth_plugin.get_auth(auth['username'], auth['password'])
@auth.setter
- def auth(self, cred):
- self['auth'] = {
- 'type': {HTTPBasicAuth: 'basic',
- HTTPDigestAuth: 'digest'}[type(cred)],
- 'username': cred.username,
- 'password': cred.password,
- }
+ def auth(self, auth):
+ assert set(['type', 'username', 'password']) == set(auth.keys())
+ self['auth'] = auth

0 comments on commit 2acb303

Please sign in to comment.