diff options
26 files changed, 378 insertions, 422 deletions
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 2993720..d0489a0 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -101,4 +101,4 @@ Tips To run a subset of tests:: - $ devenv/bin/nosetests macaroonbakery/tests/... + $ devenv/bin/nose2 macaroonbakery/tests/... @@ -1,47 +1,11 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: macaroonbakery -Version: 1.2.3 +Version: 1.3.4 Summary: A Python library port for bakery, higher level operation to work with macaroons Home-page: https://github.com/go-macaroon-bakery/py-macaroon-bakery Author: Juju UI Team Author-email: juju-gui@lists.ubuntu.com License: LGPL3 -Description: =============== - Macaroon Bakery - =============== - - A Python library for working with macaroons. - - - Installation - ------------ - The easiest way to install macaroonbakery is via pip:: - - $ pip install macaroonbakery - - macaroonbakery was developed around pymacaroons. On ubuntu, you - can get libsodium from a ppa:: - - $ sudo add-apt-repository ppa:yellow/ppa -y - $ apt-get install libsodium13 - - Usage - ----- - Interacting with a protected url, you can use the BakeryAuth provided to deal - with the macaroon bakery - - >>> from macaroonbakery import httpbakery - >>> jar = requests.cookies.RequestsCookieJar() - >>> resp = requests.get('some protected url', - cookies=jar, - auth=httpbakery.BakeryAuth(cookies=jar)) - >>> resp.raise_for_status() - - - You can use any cookie storage you'd like so next subsequent calls the macaroon - saved in the cookie jar will be directly used and will not require - any other authentication (for example, cookielib.FileCookieJar). - Keywords: macaroon cookie Platform: UNKNOWN Classifier: Development Status :: 2 - Pre-Alpha @@ -52,3 +16,43 @@ Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 +License-File: LICENSE +License-File: AUTHORS.rst + +=============== +Macaroon Bakery +=============== + +A Python library for working with macaroons. + + +Installation +------------ +The easiest way to install macaroonbakery is via pip:: + + $ pip install macaroonbakery + +macaroonbakery was developed around pymacaroons. On ubuntu, you +can get libsodium from a ppa:: + + $ sudo add-apt-repository ppa:yellow/ppa -y + $ apt-get install libsodium13 + +Usage +----- +Interacting with a protected url, you can use the BakeryAuth provided to deal +with the macaroon bakery + + >>> from macaroonbakery import httpbakery + >>> jar = requests.cookies.RequestsCookieJar() + >>> resp = requests.get('some protected url', + cookies=jar, + auth=httpbakery.BakeryAuth(cookies=jar)) + >>> resp.raise_for_status() + + +You can use any cookie storage you'd like so next subsequent calls the macaroon +saved in the cookie jar will be directly used and will not require +any other authentication (for example, cookielib.FileCookieJar). + + diff --git a/debian/.gitignore b/debian/.gitignore new file mode 100644 index 0000000..2c8afeb --- /dev/null +++ b/debian/.gitignore @@ -0,0 +1 @@ +/files diff --git a/debian/changelog b/debian/changelog index a7f8010..3757cd6 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,82 @@ +py-macaroon-bakery (1.3.4-1) unstable; urgency=medium + + * New upstream release. + - Modernize unittest method spelling (closes: #1058354). + + -- Colin Watson <cjwatson@debian.org> Sun, 17 Dec 2023 16:02:56 +0000 + +py-macaroon-bakery (1.3.1-5) unstable; urgency=medium + + [ Colin Watson ] + * Set upstream metadata fields: Repository. + + [ Steve Beattie ] + * Fix saving macaroons to MozillaCookieJar() on Python 3.10 + (LP: #1970267). + + -- Colin Watson <cjwatson@debian.org> Tue, 28 Feb 2023 09:35:23 +0000 + +py-macaroon-bakery (1.3.1-4) unstable; urgency=medium + + [ Debian Janitor ] + * Set upstream metadata fields: Repository-Browse. + + -- Jelmer Vernooij <jelmer@debian.org> Sun, 16 Oct 2022 18:08:31 +0100 + +py-macaroon-bakery (1.3.1-3) unstable; urgency=medium + + * Switch from nose to pytest. + + -- Colin Watson <cjwatson@debian.org> Mon, 22 Aug 2022 11:51:37 +0100 + +py-macaroon-bakery (1.3.1-2) unstable; urgency=medium + + [ Debian Janitor ] + * Bump debhelper from old 9 to 12. + * Set upstream metadata fields: Bug-Database, Bug-Submit. + + [ Ondřej Nový ] + * d/control: Update Maintainer field with new Debian Python Team + contact address. + * d/control: Update Vcs-* fields with new Debian Python Team Salsa + layout. + + [ Debian Janitor ] + * Bump debhelper from old 12 to 13. + * Remove constraints unnecessary since buster: + + Build-Depends: Drop versioned constraint on python3-nacl, + python3-protobuf, python3-pymacaroons, python3-requests, python3-rfc3339 + and python3-six. + + -- Colin Watson <cjwatson@debian.org> Sun, 26 Dec 2021 13:20:06 +0000 + +py-macaroon-bakery (1.3.1-1) unstable; urgency=medium + + * New upstream release. + + -- Colin Watson <cjwatson@debian.org> Fri, 14 Feb 2020 11:22:12 +0000 + +py-macaroon-bakery (1.3.0-1) unstable; urgency=medium + + * New upstream release. + + -- Colin Watson <cjwatson@debian.org> Wed, 29 Jan 2020 17:25:18 +0000 + +py-macaroon-bakery (1.2.3-3) unstable; urgency=medium + + * Cherry-pick from upstream: + - Avoid using deprecated platform.dist() in setup.py. + + -- Colin Watson <cjwatson@debian.org> Thu, 26 Dec 2019 22:46:22 +0000 + +py-macaroon-bakery (1.2.3-2) unstable; urgency=medium + + [ Ondřej Nový ] + * Use debhelper-compat instead of debian/compat. + * d/control: Remove ancient X-Python3-Version field. + + -- Colin Watson <cjwatson@debian.org> Thu, 26 Dec 2019 02:13:31 +0000 + py-macaroon-bakery (1.2.3-1) unstable; urgency=medium [ Ondřej Nový ] diff --git a/debian/compat b/debian/compat deleted file mode 100644 index ec63514..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/debian/control b/debian/control index 445bb38..466239c 100644 --- a/debian/control +++ b/debian/control @@ -1,25 +1,25 @@ Source: py-macaroon-bakery Section: python Priority: optional -Maintainer: Debian Python Modules Team <python-modules-team@lists.alioth.debian.org> +Maintainer: Debian Python Team <team+python@tracker.debian.org> Uploaders: Colin Watson <cjwatson@debian.org> -Build-Depends: debhelper (>= 9~), +Build-Depends: debhelper-compat (= 13), dh-python, python3-all, + python3-fixtures, python3-httmock, python3-mock, - python3-nacl (>= 1.1.2), - python3-nose, - python3-protobuf (>= 3.0.0), - python3-pymacaroons (>= 0.12.0), - python3-requests (>= 2.18.1), - python3-rfc3339 (>= 1.0), + python3-nacl, + python3-protobuf, + python3-pymacaroons, + python3-pytest, + python3-requests, + python3-rfc3339, python3-setuptools, - python3-six (>= 1.11.0), + python3-six, Standards-Version: 4.1.1 -X-Python3-Version: >= 3.5 -Vcs-Git: https://salsa.debian.org/python-team/modules/py-macaroon-bakery.git -Vcs-Browser: https://salsa.debian.org/python-team/modules/py-macaroon-bakery +Vcs-Git: https://salsa.debian.org/python-team/packages/py-macaroon-bakery.git +Vcs-Browser: https://salsa.debian.org/python-team/packages/py-macaroon-bakery Homepage: https://github.com/go-macaroon-bakery/py-macaroon-bakery Rules-Requires-Root: no diff --git a/debian/patches/fix-saving-macaroons-in-mozillacookiejar.patch b/debian/patches/fix-saving-macaroons-in-mozillacookiejar.patch new file mode 100644 index 0000000..f4deb3b --- /dev/null +++ b/debian/patches/fix-saving-macaroons-in-mozillacookiejar.patch @@ -0,0 +1,25 @@ +From: Steve Beattie <steve.beattie@canonical.com> +Date: Tue, 28 Feb 2023 09:27:58 +0000 +Subject: Fix saving macaroons in MozillaCookieJar() on Python 3.10 + +Origin: other, https://github.com/go-macaroon-bakery/py-macaroon-bakery/issues/88#issue-1214739879 +Bug: https://github.com/go-macaroon-bakery/py-macaroon-bakery/issues/88 +Reviewed-by: Alex Murray <alex.murray@canonical.com> +Last-Update: 2023-02-28 +--- + macaroonbakery/_utils/__init__.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/macaroonbakery/_utils/__init__.py b/macaroonbakery/_utils/__init__.py +index 977cdbe..d1afe31 100644 +--- a/macaroonbakery/_utils/__init__.py ++++ b/macaroonbakery/_utils/__init__.py +@@ -160,7 +160,7 @@ def cookie( + discard=False, + comment=None, + comment_url=None, +- rest=None, ++ rest={}, + rfc2109=False, + ) + diff --git a/debian/patches/improve-unknown-interaction-mock.patch b/debian/patches/improve-unknown-interaction-mock.patch deleted file mode 100644 index b09b3a2..0000000 --- a/debian/patches/improve-unknown-interaction-mock.patch +++ /dev/null @@ -1,56 +0,0 @@ -From: Colin Watson <cjwatson@debian.org> -Date: Fri, 9 Feb 2018 21:54:21 +0000 -Subject: Improve mock setup for 407-then-unknown test - -`test_407_then_unknown_interaction_methods` causes the client to fetch -the possible methods supported by the discharger (because it's told that -it only supports a non-window method). This is currently unmocked, -which causes the client to actually contact `http://example.com/visit`. -This fails in Launchpad builds because they run with a restrictive -network setup that doesn't even expose DNS lookups for non-permitted -hosts. - -There isn't really a good way to simulate this without setting up a -similar stunt DNS server (though perhaps installing an -`httmock.all_requests` fallback mock that raises an exception would be a -good idea?), but this seems to be the only failure at the moment. - -Forwarded: https://github.com/go-macaroon-bakery/py-macaroon-bakery/pull/45 -Last-Update: 2018-02-09 - -Patch-Name: improve-unknown-interaction-mock.patch ---- - macaroonbakery/tests/test_bakery.py | 13 ++++++++++++- - 1 file changed, 12 insertions(+), 1 deletion(-) - -diff --git a/macaroonbakery/tests/test_bakery.py b/macaroonbakery/tests/test_bakery.py -index 72a6928..1883987 100644 ---- a/macaroonbakery/tests/test_bakery.py -+++ b/macaroonbakery/tests/test_bakery.py -@@ -146,6 +146,16 @@ def discharge_401(url, request): - } - - -+@urlmatch(path='.*/visit') -+def visit_200(url, request): -+ return { -+ 'status_code': 200, -+ 'content': { -+ 'interactive': '/visit' -+ } -+ } -+ -+ - @urlmatch(path='.*/wait') - def wait_after_401(url, request): - if request.url != 'http://example.com/wait': -@@ -245,7 +255,8 @@ class TestBakery(TestCase): - def kind(self): - return 'unknown' - client = httpbakery.Client(interaction_methods=[UnknownInteractor()]) -- with HTTMock(first_407_then_200), HTTMock(discharge_401): -+ with HTTMock(first_407_then_200), HTTMock(discharge_401),\ -+ HTTMock(visit_200): - with self.assertRaises(httpbakery.InteractionError) as exc: - requests.get( - ID_PATH, diff --git a/debian/patches/isolate-from-proxy.patch b/debian/patches/isolate-from-proxy.patch deleted file mode 100644 index 06cc402..0000000 --- a/debian/patches/isolate-from-proxy.patch +++ /dev/null @@ -1,66 +0,0 @@ -From: Colin Watson <cjwatson@debian.org> -Date: Mon, 6 Nov 2017 10:27:10 +0000 -Subject: Isolate client tests from any HTTP proxy - -Debian's Python packaging tools set http_proxy to a non-existent proxy -to help flush out packages that try to talk to the network during build, -but these tests could previously fail in more normal development -environments too. - -Forwarded: https://github.com/go-macaroon-bakery/py-macaroon-bakery/pull/28 -Last-Update: 2018-02-05 - -Patch-Name: isolate-from-proxy.patch ---- - macaroonbakery/tests/test_bakery.py | 6 ++++++ - macaroonbakery/tests/test_client.py | 7 +++++++ - 2 files changed, 13 insertions(+) - -diff --git a/macaroonbakery/tests/test_bakery.py b/macaroonbakery/tests/test_bakery.py -index a6c3e58..72a6928 100644 ---- a/macaroonbakery/tests/test_bakery.py -+++ b/macaroonbakery/tests/test_bakery.py -@@ -1,5 +1,6 @@ - # Copyright 2017 Canonical Ltd. - # Licensed under the LGPLv3, see LICENCE file for details. -+import os - from unittest import TestCase - - import macaroonbakery.httpbakery as httpbakery -@@ -171,6 +172,11 @@ def wait_on_error(url, request): - - - class TestBakery(TestCase): -+ def setUp(self): -+ super(TestBakery, self).setUp() -+ # http_proxy would cause requests to talk to the proxy, which is -+ # unlikely to know how to talk to the test server. -+ os.environ.pop('http_proxy', None) - - def assert_cookie_security(self, cookies, name, secure): - for cookie in cookies: -diff --git a/macaroonbakery/tests/test_client.py b/macaroonbakery/tests/test_client.py -index b03bafa..2ae08d3 100644 ---- a/macaroonbakery/tests/test_client.py -+++ b/macaroonbakery/tests/test_client.py -@@ -3,6 +3,7 @@ - import base64 - import datetime - import json -+import os - import threading - from unittest import TestCase - -@@ -27,6 +28,12 @@ TEST_OP = bakery.Op(entity='test', action='test') - - - class TestClient(TestCase): -+ def setUp(self): -+ super(TestClient, self).setUp() -+ # http_proxy would cause requests to talk to the proxy, which is -+ # unlikely to know how to talk to the test server. -+ os.environ.pop('http_proxy', None) -+ - def test_single_service_first_party(self): - b = new_bakery('loc', None, None) - diff --git a/debian/patches/series b/debian/patches/series index f8e7d6e..a66820f 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -1,2 +1 @@ -isolate-from-proxy.patch -improve-unknown-interaction-mock.patch +fix-saving-macaroons-in-mozillacookiejar.patch diff --git a/debian/rules b/debian/rules index d01c6c6..f3204a6 100755 --- a/debian/rules +++ b/debian/rules @@ -1,7 +1,7 @@ #! /usr/bin/make -f export PYBUILD_NAME := macaroonbakery -export PYBUILD_TEST_NOSE := 1 +export PYBUILD_TEST_PYTEST := 1 %: dh $@ --with python3 --buildsystem=pybuild diff --git a/debian/upstream/metadata b/debian/upstream/metadata new file mode 100644 index 0000000..628873d --- /dev/null +++ b/debian/upstream/metadata @@ -0,0 +1,4 @@ +Bug-Database: https://github.com/go-macaroon-bakery/py-macaroon-bakery/issues +Bug-Submit: https://github.com/go-macaroon-bakery/py-macaroon-bakery/issues/new +Repository: https://github.com/go-macaroon-bakery/py-macaroon-bakery.git +Repository-Browse: https://github.com/go-macaroon-bakery/py-macaroon-bakery diff --git a/macaroonbakery.egg-info/PKG-INFO b/macaroonbakery.egg-info/PKG-INFO index c0150fc..2a03d29 100644 --- a/macaroonbakery.egg-info/PKG-INFO +++ b/macaroonbakery.egg-info/PKG-INFO @@ -1,47 +1,11 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: macaroonbakery -Version: 1.2.3 +Version: 1.3.4 Summary: A Python library port for bakery, higher level operation to work with macaroons Home-page: https://github.com/go-macaroon-bakery/py-macaroon-bakery Author: Juju UI Team Author-email: juju-gui@lists.ubuntu.com License: LGPL3 -Description: =============== - Macaroon Bakery - =============== - - A Python library for working with macaroons. - - - Installation - ------------ - The easiest way to install macaroonbakery is via pip:: - - $ pip install macaroonbakery - - macaroonbakery was developed around pymacaroons. On ubuntu, you - can get libsodium from a ppa:: - - $ sudo add-apt-repository ppa:yellow/ppa -y - $ apt-get install libsodium13 - - Usage - ----- - Interacting with a protected url, you can use the BakeryAuth provided to deal - with the macaroon bakery - - >>> from macaroonbakery import httpbakery - >>> jar = requests.cookies.RequestsCookieJar() - >>> resp = requests.get('some protected url', - cookies=jar, - auth=httpbakery.BakeryAuth(cookies=jar)) - >>> resp.raise_for_status() - - - You can use any cookie storage you'd like so next subsequent calls the macaroon - saved in the cookie jar will be directly used and will not require - any other authentication (for example, cookielib.FileCookieJar). - Keywords: macaroon cookie Platform: UNKNOWN Classifier: Development Status :: 2 - Pre-Alpha @@ -52,3 +16,43 @@ Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.5 +License-File: LICENSE +License-File: AUTHORS.rst + +=============== +Macaroon Bakery +=============== + +A Python library for working with macaroons. + + +Installation +------------ +The easiest way to install macaroonbakery is via pip:: + + $ pip install macaroonbakery + +macaroonbakery was developed around pymacaroons. On ubuntu, you +can get libsodium from a ppa:: + + $ sudo add-apt-repository ppa:yellow/ppa -y + $ apt-get install libsodium13 + +Usage +----- +Interacting with a protected url, you can use the BakeryAuth provided to deal +with the macaroon bakery + + >>> from macaroonbakery import httpbakery + >>> jar = requests.cookies.RequestsCookieJar() + >>> resp = requests.get('some protected url', + cookies=jar, + auth=httpbakery.BakeryAuth(cookies=jar)) + >>> resp.raise_for_status() + + +You can use any cookie storage you'd like so next subsequent calls the macaroon +saved in the cookie jar will be directly used and will not require +any other authentication (for example, cookielib.FileCookieJar). + + diff --git a/macaroonbakery.egg-info/requires.txt b/macaroonbakery.egg-info/requires.txt index e715881..c663b20 100644 --- a/macaroonbakery.egg-info/requires.txt +++ b/macaroonbakery.egg-info/requires.txt @@ -1,7 +1,15 @@ -requests<3.0,>=2.18.1 PyNaCl<2.0,>=1.1.2 +protobuf>=3.20.0 +pyRFC3339<2.0,>=1.0 pymacaroons<1.0,>=0.12.0 +requests<3.0,>=2.18.1 six<2.0,>=1.11.0 -protobuf<4.0,>=3.0.0 -pyRFC3339<2.0,>=1.0 + +[:python_full_version < "2.7.9"] +cryptography==1.3.2 +ndg_httpsclient==0.3.3 +pyOpenSSL==16.0.0 +pyasn1==0.1.9 + +[:python_version < "3"] ipaddress diff --git a/macaroonbakery/_utils/__init__.py b/macaroonbakery/_utils/__init__.py index 977cdbe..d1afe31 100644 --- a/macaroonbakery/_utils/__init__.py +++ b/macaroonbakery/_utils/__init__.py @@ -160,7 +160,7 @@ def cookie( discard=False, comment=None, comment_url=None, - rest=None, + rest={}, rfc2109=False, ) diff --git a/macaroonbakery/bakery/_internal/id_pb2.py b/macaroonbakery/bakery/_internal/id_pb2.py index 0fd54c0..1b4ca02 100644 --- a/macaroonbakery/bakery/_internal/id_pb2.py +++ b/macaroonbakery/bakery/_internal/id_pb2.py @@ -1,13 +1,12 @@ +# -*- coding: utf-8 -*- # Generated by the protocol buffer compiler. DO NOT EDIT! -# source: macaroonbakery/internal/id.proto - -import sys -_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +# source: id.proto +# Protobuf Python Version: 4.25.1 +"""Generated protocol buffer code.""" from google.protobuf import descriptor as _descriptor -from google.protobuf import message as _message -from google.protobuf import reflection as _reflection +from google.protobuf import descriptor_pool as _descriptor_pool from google.protobuf import symbol_database as _symbol_database -from google.protobuf import descriptor_pb2 +from google.protobuf.internal import builder as _builder # @@protoc_insertion_point(imports) _sym_db = _symbol_database.Default() @@ -15,118 +14,16 @@ _sym_db = _symbol_database.Default() -DESCRIPTOR = _descriptor.FileDescriptor( - name='macaroonbakery/internal/id.proto', - package='', - syntax='proto3', - serialized_pb=_b('\n macaroonbakery/internal/id.proto\"@\n\nMacaroonId\x12\r\n\x05nonce\x18\x01 \x01(\x0c\x12\x11\n\tstorageId\x18\x02 \x01(\x0c\x12\x10\n\x03ops\x18\x03 \x03(\x0b\x32\x03.Op\"%\n\x02Op\x12\x0e\n\x06\x65ntity\x18\x01 \x01(\t\x12\x0f\n\x07\x61\x63tions\x18\x02 \x03(\tB\x0cZ\nmacaroonpbb\x06proto3') -) - - - - -_MACAROONID = _descriptor.Descriptor( - name='MacaroonId', - full_name='MacaroonId', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='nonce', full_name='MacaroonId.nonce', index=0, - number=1, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='storageId', full_name='MacaroonId.storageId', index=1, - number=2, type=12, cpp_type=9, label=1, - has_default_value=False, default_value=_b(""), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='ops', full_name='MacaroonId.ops', index=2, - number=3, type=11, cpp_type=10, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=36, - serialized_end=100, -) - - -_OP = _descriptor.Descriptor( - name='Op', - full_name='Op', - filename=None, - file=DESCRIPTOR, - containing_type=None, - fields=[ - _descriptor.FieldDescriptor( - name='entity', full_name='Op.entity', index=0, - number=1, type=9, cpp_type=9, label=1, - has_default_value=False, default_value=_b("").decode('utf-8'), - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - _descriptor.FieldDescriptor( - name='actions', full_name='Op.actions', index=1, - number=2, type=9, cpp_type=9, label=3, - has_default_value=False, default_value=[], - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - options=None), - ], - extensions=[ - ], - nested_types=[], - enum_types=[ - ], - options=None, - is_extendable=False, - syntax='proto3', - extension_ranges=[], - oneofs=[ - ], - serialized_start=102, - serialized_end=139, -) - -_MACAROONID.fields_by_name['ops'].message_type = _OP -DESCRIPTOR.message_types_by_name['MacaroonId'] = _MACAROONID -DESCRIPTOR.message_types_by_name['Op'] = _OP -_sym_db.RegisterFileDescriptor(DESCRIPTOR) - -MacaroonId = _reflection.GeneratedProtocolMessageType('MacaroonId', (_message.Message,), dict( - DESCRIPTOR = _MACAROONID, - __module__ = 'macaroonbakery.internal.id_pb2' - # @@protoc_insertion_point(class_scope:MacaroonId) - )) -_sym_db.RegisterMessage(MacaroonId) - -Op = _reflection.GeneratedProtocolMessageType('Op', (_message.Message,), dict( - DESCRIPTOR = _OP, - __module__ = 'macaroonbakery.internal.id_pb2' - # @@protoc_insertion_point(class_scope:Op) - )) -_sym_db.RegisterMessage(Op) - +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x08id.proto\"@\n\nMacaroonId\x12\r\n\x05nonce\x18\x01 \x01(\x0c\x12\x11\n\tstorageId\x18\x02 \x01(\x0c\x12\x10\n\x03ops\x18\x03 \x03(\x0b\x32\x03.Op\"%\n\x02Op\x12\x0e\n\x06\x65ntity\x18\x01 \x01(\t\x12\x0f\n\x07\x61\x63tions\x18\x02 \x03(\tB\x0cZ\nmacaroonpbb\x06proto3') -DESCRIPTOR.has_options = True -DESCRIPTOR._options = _descriptor._ParseOptions(descriptor_pb2.FileOptions(), _b('Z\nmacaroonpb')) +_globals = globals() +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'id_pb2', _globals) +if _descriptor._USE_C_DESCRIPTORS == False: + _globals['DESCRIPTOR']._options = None + _globals['DESCRIPTOR']._serialized_options = b'Z\nmacaroonpb' + _globals['_MACAROONID']._serialized_start=12 + _globals['_MACAROONID']._serialized_end=76 + _globals['_OP']._serialized_start=78 + _globals['_OP']._serialized_end=115 # @@protoc_insertion_point(module_scope) diff --git a/macaroonbakery/bakery/_macaroon.py b/macaroonbakery/bakery/_macaroon.py index 63091f6..1438ab1 100644 --- a/macaroonbakery/bakery/_macaroon.py +++ b/macaroonbakery/bakery/_macaroon.py @@ -115,11 +115,11 @@ class Macaroon(object): 'no private key to encrypt third party caveat') local_info = _parse_local_location(cav.location) if local_info is not None: - info = local_info - if cav.condition is not '': + if cav.condition: raise ValueError( 'cannot specify caveat condition in ' 'local third-party caveat') + info = local_info cav = checkers.Caveat(location='local', condition='true') else: if loc is None: diff --git a/macaroonbakery/checkers/_auth_context.py b/macaroonbakery/checkers/_auth_context.py index dceb015..2ca5168 100644 --- a/macaroonbakery/checkers/_auth_context.py +++ b/macaroonbakery/checkers/_auth_context.py @@ -1,9 +1,12 @@ # Copyright 2017 Canonical Ltd. # Licensed under the LGPLv3, see LICENCE file for details. -import collections +try: + from collections.abc import Mapping +except ImportError: + from collections import Mapping -class AuthContext(collections.Mapping): +class AuthContext(Mapping): ''' Holds a set of keys and values relevant to authorization. It is passed as an argument to authorization checkers, so that the checkers diff --git a/macaroonbakery/httpbakery/_client.py b/macaroonbakery/httpbakery/_client.py index 326c33d..230531d 100644 --- a/macaroonbakery/httpbakery/_client.py +++ b/macaroonbakery/httpbakery/_client.py @@ -131,7 +131,13 @@ class Client: # TODO Fabrice what is the other http response possible ?? if resp.status_code == 200: return bakery.Macaroon.from_dict(resp.json().get('Macaroon')) - cause = Error.from_dict(resp.json()) + # A 5xx error might not return json. + try: + cause = Error.from_dict(resp.json()) + except ValueError: + raise DischargeError( + 'unexpected response: [{}] {!r}'.format(resp.status_code, resp.content) + ) if cause.code != ERR_INTERACTION_REQUIRED: raise DischargeError(cause.message) if cause.info is None: diff --git a/macaroonbakery/tests/test_bakery.py b/macaroonbakery/tests/test_bakery.py index 72a6928..d242b2a 100644 --- a/macaroonbakery/tests/test_bakery.py +++ b/macaroonbakery/tests/test_bakery.py @@ -1,6 +1,5 @@ # Copyright 2017 Canonical Ltd. # Licensed under the LGPLv3, see LICENCE file for details. -import os from unittest import TestCase import macaroonbakery.httpbakery as httpbakery @@ -146,6 +145,16 @@ def discharge_401(url, request): } +@urlmatch(path='.*/visit') +def visit_200(url, request): + return { + 'status_code': 200, + 'content': { + 'interactive': '/visit' + } + } + + @urlmatch(path='.*/wait') def wait_after_401(url, request): if request.url != 'http://example.com/wait': @@ -172,11 +181,6 @@ def wait_on_error(url, request): class TestBakery(TestCase): - def setUp(self): - super(TestBakery, self).setUp() - # http_proxy would cause requests to talk to the proxy, which is - # unlikely to know how to talk to the test server. - os.environ.pop('http_proxy', None) def assert_cookie_security(self, cookies, name, secure): for cookie in cookies: @@ -245,7 +249,8 @@ class TestBakery(TestCase): def kind(self): return 'unknown' client = httpbakery.Client(interaction_methods=[UnknownInteractor()]) - with HTTMock(first_407_then_200), HTTMock(discharge_401): + with HTTMock(first_407_then_200), HTTMock(discharge_401),\ + HTTMock(visit_200): with self.assertRaises(httpbakery.InteractionError) as exc: requests.get( ID_PATH, diff --git a/macaroonbakery/tests/test_client.py b/macaroonbakery/tests/test_client.py index 2ae08d3..4bccb20 100644 --- a/macaroonbakery/tests/test_client.py +++ b/macaroonbakery/tests/test_client.py @@ -3,9 +3,8 @@ import base64 import datetime import json -import os +import platform import threading -from unittest import TestCase import macaroonbakery.bakery as bakery import macaroonbakery.checkers as checkers @@ -13,7 +12,12 @@ import macaroonbakery.httpbakery as httpbakery import pymacaroons import requests import macaroonbakery._utils as utils +from macaroonbakery.httpbakery._error import DischargeError +from fixtures import ( + EnvironmentVariable, + TestWithFixtures, +) from httmock import HTTMock, urlmatch from six.moves.urllib.parse import parse_qs from six.moves.urllib.request import Request @@ -27,12 +31,13 @@ AGES = datetime.datetime.utcnow() + datetime.timedelta(days=1) TEST_OP = bakery.Op(entity='test', action='test') -class TestClient(TestCase): +class TestClient(TestWithFixtures): def setUp(self): super(TestClient, self).setUp() # http_proxy would cause requests to talk to the proxy, which is # unlikely to know how to talk to the test server. - os.environ.pop('http_proxy', None) + self.useFixture(EnvironmentVariable('http_proxy')) + self.useFixture(EnvironmentVariable('HTTP_PROXY')) def test_single_service_first_party(self): b = new_bakery('loc', None, None) @@ -46,7 +51,7 @@ class TestClient(TestCase): srv_macaroon = b.oven.macaroon( version=bakery.LATEST_VERSION, expiry=AGES, caveats=None, ops=[TEST_OP]) - self.assertEquals(srv_macaroon.macaroon.location, 'loc') + self.assertEqual(srv_macaroon.macaroon.location, 'loc') client = httpbakery.Client() client.cookies.set_cookie(requests.cookies.create_cookie( 'macaroon-test', base64.b64encode(json.dumps([ @@ -58,7 +63,7 @@ class TestClient(TestCase): str(httpd.server_address[1]), cookies=client.cookies, auth=client.auth()) resp.raise_for_status() - self.assertEquals(resp.text, 'done') + self.assertEqual(resp.text, 'done') finally: httpd.shutdown() @@ -105,7 +110,7 @@ class TestClient(TestCase): cookies=client.cookies, auth=client.auth()) resp.raise_for_status() - self.assertEquals(resp.text, 'done') + self.assertEqual(resp.text, 'done') finally: httpd.shutdown() @@ -152,7 +157,7 @@ class TestClient(TestCase): cookies=client.cookies, auth=client.auth()) resp.raise_for_status() - self.assertEquals(resp.text, 'done') + self.assertEqual(resp.text, 'done') finally: httpd.shutdown() @@ -198,7 +203,7 @@ class TestClient(TestCase): cookies=client.cookies, auth=client.auth()) resp.raise_for_status() - self.assertEquals(resp.text, 'done') + self.assertEqual(resp.text, 'done') finally: httpd.shutdown() @@ -217,7 +222,7 @@ class TestClient(TestCase): srv_macaroon = b.oven.macaroon( version=bakery.LATEST_VERSION, expiry=AGES, caveats=None, ops=[TEST_OP]) - self.assertEquals(srv_macaroon.macaroon.location, 'loc') + self.assertEqual(srv_macaroon.macaroon.location, 'loc') client = httpbakery.Client() # Note: by using "localhost" instead of the presumably numeric address held # in httpd.server_address, we're triggering the no-FQDN logic in the cookie @@ -226,7 +231,7 @@ class TestClient(TestCase): url='http://localhost:' + str(httpd.server_address[1]), cookies=client.cookies, auth=client.auth()) resp.raise_for_status() - self.assertEquals(resp.text, 'done') + self.assertEqual(resp.text, 'done') except httpbakery.BakeryException: pass # interacion required exception is expected finally: @@ -249,7 +254,7 @@ class TestClient(TestCase): srv_macaroon = b.oven.macaroon( version=bakery.LATEST_VERSION, expiry=AGES, caveats=None, ops=[TEST_OP]) - self.assertEquals(srv_macaroon.macaroon.location, 'loc') + self.assertEqual(srv_macaroon.macaroon.location, 'loc') headers = { 'Macaroons': base64.b64encode(json.dumps([ srv_macaroon.to_dict().get('m') @@ -260,7 +265,7 @@ class TestClient(TestCase): str(httpd.server_address[1]), headers=headers) resp.raise_for_status() - self.assertEquals(resp.text, 'done') + self.assertEqual(resp.text, 'done') finally: httpd.shutdown() @@ -312,8 +317,8 @@ class TestClient(TestCase): base64.b64decode(client.cookies.get('macaroon-test')).decode('utf-8'))[0]) t = checkers.macaroons_expiry_time( checkers.Namespace(), [m.macaroon]) - self.assertEquals(ages, t) - self.assertEquals(resp.text, 'done') + self.assertEqual(ages, t) + self.assertEqual(resp.text, 'done') finally: httpd.shutdown() @@ -513,6 +518,56 @@ class TestClient(TestCase): finally: httpd.shutdown() + def test_discharge_jsondecodeerror(self): + class _DischargerLocator(bakery.ThirdPartyLocator): + def __init__(self): + self.key = bakery.generate_key() + + def third_party_info(self, loc): + if loc == 'http://1.2.3.4': + return bakery.ThirdPartyInfo( + public_key=self.key.public_key, + version=bakery.LATEST_VERSION, + ) + d = _DischargerLocator() + b = new_bakery('loc', d, None) + + @urlmatch(path='.*/discharge') + def discharge(url, request): + return { + 'status_code': 503, + 'content': 'bad system', + } + + def handler(*args): + GetHandler(b, 'http://1.2.3.4', None, None, None, AGES, *args) + + try: + httpd = HTTPServer(('', 0), handler) + thread = threading.Thread(target=httpd.serve_forever) + thread.start() + + client = httpbakery.Client() + + with HTTMock(discharge): + with self.assertRaises(DischargeError) as discharge_error: + requests.get( + 'http://' + httpd.server_address[0] + ':' + str( + httpd.server_address[1]), + cookies=client.cookies, + auth=client.auth()) + if platform.python_version_tuple()[0] == '2': + self.assertEqual(str(discharge_error.exception), + 'third party refused dischargex: unexpected response: ' + "[503] 'bad system'") + else: + self.assertEqual(str(discharge_error.exception), + 'third party refused dischargex: unexpected response: ' + "[503] b'bad system'") + + finally: + httpd.shutdown() + def test_extract_macaroons_from_request(self): def encode_macaroon(m): macaroons = '[' + utils.macaroon_to_json_string(m) + ']' @@ -536,10 +591,10 @@ class TestClient(TestCase): jar.add_cookie_header(req) macaroons = httpbakery.extract_macaroons(req) - self.assertEquals(len(macaroons), 2) + self.assertEqual(len(macaroons), 2) macaroons.sort(key=lambda ms: ms[0].identifier) - self.assertEquals(macaroons[0][0].identifier, m1.identifier) - self.assertEquals(macaroons[1][0].identifier, m2.identifier) + self.assertEqual(macaroons[0][0].identifier, m1.identifier) + self.assertEqual(macaroons[1][0].identifier, m2.identifier) def test_handle_error_cookie_path(self): macaroon = bakery.Macaroon( diff --git a/macaroonbakery/tests/test_codec.py b/macaroonbakery/tests/test_codec.py index d82a794..11e62ec 100644 --- a/macaroonbakery/tests/test_codec.py +++ b/macaroonbakery/tests/test_codec.py @@ -26,7 +26,7 @@ class TestCodec(TestCase): self.fp_key, None) res = bakery.decode_caveat(self.tp_key, cid) - self.assertEquals(res, bakery.ThirdPartyCaveatInfo( + self.assertEqual(res, bakery.ThirdPartyCaveatInfo( first_party_public_key=self.fp_key.public_key, root_key=b'a random string', condition='is-authenticated-user', @@ -48,7 +48,7 @@ class TestCodec(TestCase): self.fp_key, None) res = bakery.decode_caveat(self.tp_key, cid) - self.assertEquals(res, bakery.ThirdPartyCaveatInfo( + self.assertEqual(res, bakery.ThirdPartyCaveatInfo( first_party_public_key=self.fp_key.public_key, root_key=b'a random string', condition='is-authenticated-user', @@ -72,7 +72,7 @@ class TestCodec(TestCase): self.fp_key, ns) res = bakery.decode_caveat(self.tp_key, cid) - self.assertEquals(res, bakery.ThirdPartyCaveatInfo( + self.assertEqual(res, bakery.ThirdPartyCaveatInfo( first_party_public_key=self.fp_key.public_key, root_key=b'a random string', condition='is-authenticated-user', @@ -110,7 +110,7 @@ class TestCodec(TestCase): '0V2lEOHhRUWdjU3ljOHY4eUt4dEhxejVEczJOYmh1ZDJhUFdt' 'UTVMcVlNWitmZ2FNaTAxdE9DIn0=') cav = bakery.decode_caveat(tp_key, encrypted_cav) - self.assertEquals(cav, bakery.ThirdPartyCaveatInfo( + self.assertEqual(cav, bakery.ThirdPartyCaveatInfo( condition='caveat condition', first_party_public_key=fp_key.public_key, third_party_key_pair=tp_key, @@ -164,7 +164,7 @@ class TestCodec(TestCase): '1LX4VKxymqG62UGPo78wOv0_fKjr3OI6PPJOYOQgBMclemlRF2', ) cav = bakery.decode_caveat(tp_key, encrypted_cav) - self.assertEquals(cav, bakery.ThirdPartyCaveatInfo( + self.assertEqual(cav, bakery.ThirdPartyCaveatInfo( condition='third party condition', first_party_public_key=fp_key.public_key, third_party_key_pair=tp_key, @@ -190,7 +190,7 @@ class TestCodec(TestCase): bakery.encode_uvarint(test[0], data) for v in test[1]: expected.append(v) - self.assertEquals(data, expected) + self.assertEqual(data, expected) val = codec.decode_uvarint(bytes(data)) - self.assertEquals(test[0], val[0]) - self.assertEquals(len(test[1]), val[1]) + self.assertEqual(test[0], val[0]) + self.assertEqual(len(test[1]), val[1]) diff --git a/macaroonbakery/tests/test_macaroon.py b/macaroonbakery/tests/test_macaroon.py index bcbbf80..ab0cbe0 100644 --- a/macaroonbakery/tests/test_macaroon.py +++ b/macaroonbakery/tests/test_macaroon.py @@ -19,17 +19,17 @@ class TestMacaroon(TestCase): 'here', bakery.LATEST_VERSION) self.assertIsNotNone(m) - self.assertEquals(m._macaroon.identifier, b'some id') - self.assertEquals(m._macaroon.location, 'here') - self.assertEquals(m.version, bakery.LATEST_VERSION) + self.assertEqual(m._macaroon.identifier, b'some id') + self.assertEqual(m._macaroon.location, 'here') + self.assertEqual(m.version, bakery.LATEST_VERSION) def test_add_first_party_caveat(self): m = bakery.Macaroon('rootkey', 'some id', 'here', bakery.LATEST_VERSION) m.add_caveat(checkers.Caveat('test_condition')) caveats = m.first_party_caveats() - self.assertEquals(len(caveats), 1) - self.assertEquals(caveats[0].caveat_id, b'test_condition') + self.assertEqual(len(caveats), 1) + self.assertEqual(caveats[0].caveat_id, b'test_condition') def test_add_third_party_caveat(self): locator = bakery.ThirdPartyStore() diff --git a/macaroonbakery/tests/test_namespace.py b/macaroonbakery/tests/test_namespace.py index 8a821e5..11d8795 100644 --- a/macaroonbakery/tests/test_namespace.py +++ b/macaroonbakery/tests/test_namespace.py @@ -24,12 +24,12 @@ class TestNamespace(TestCase): for test in tests: ns = checkers.Namespace(test[1]) data = ns.serialize_text() - self.assertEquals(data, test[2]) - self.assertEquals(str(ns), test[2].decode('utf-8')) + self.assertEqual(data, test[2]) + self.assertEqual(str(ns), test[2].decode('utf-8')) # Check that it can be deserialize to the same thing: ns1 = checkers.deserialize_namespace(data) - self.assertEquals(ns1, ns) + self.assertEqual(ns1, ns) # TODO(rogpeppe) add resolve tests @@ -37,16 +37,16 @@ class TestNamespace(TestCase): ns = checkers.Namespace(None) ns.register('testns', 't') prefix = ns.resolve('testns') - self.assertEquals(prefix, 't') + self.assertEqual(prefix, 't') ns.register('other', 'o') prefix = ns.resolve('other') - self.assertEquals(prefix, 'o') + self.assertEqual(prefix, 'o') # If we re-register the same URL, it does nothing. ns.register('other', 'p') prefix = ns.resolve('other') - self.assertEquals(prefix, 'o') + self.assertEqual(prefix, 'o') def test_register_bad_uri(self): ns = checkers.Namespace(None) diff --git a/macaroonbakery/tests/test_oven.py b/macaroonbakery/tests/test_oven.py index 3c29767..a06fbf5 100644 --- a/macaroonbakery/tests/test_oven.py +++ b/macaroonbakery/tests/test_oven.py @@ -45,9 +45,9 @@ class TestOven(TestCase): for about, ops, expected in canonical_ops_tests: new_ops = copy.copy(ops) canonical_ops = bakery.canonical_ops(new_ops) - self.assertEquals(canonical_ops, expected) + self.assertEqual(canonical_ops, expected) # Verify that the original array isn't changed. - self.assertEquals(new_ops, ops) + self.assertEqual(new_ops, ops) def test_multiple_ops(self): test_oven = bakery.Oven( @@ -58,8 +58,8 @@ class TestOven(TestCase): m = test_oven.macaroon(bakery.LATEST_VERSION, AGES, None, ops) got_ops, conds = test_oven.macaroon_ops([m.macaroon]) - self.assertEquals(len(conds), 1) # time-before caveat. - self.assertEquals(bakery.canonical_ops(got_ops), ops) + self.assertEqual(len(conds), 1) # time-before caveat. + self.assertEqual(bakery.canonical_ops(got_ops), ops) def test_multiple_ops_in_id(self): test_oven = bakery.Oven() @@ -69,8 +69,8 @@ class TestOven(TestCase): m = test_oven.macaroon(bakery.LATEST_VERSION, AGES, None, ops) got_ops, conds = test_oven.macaroon_ops([m.macaroon]) - self.assertEquals(len(conds), 1) # time-before caveat. - self.assertEquals(bakery.canonical_ops(got_ops), ops) + self.assertEqual(len(conds), 1) # time-before caveat. + self.assertEqual(bakery.canonical_ops(got_ops), ops) def test_multiple_ops_in_id_with_version1(self): test_oven = bakery.Oven() @@ -79,8 +79,8 @@ class TestOven(TestCase): bakery.Op('two', 'read')] m = test_oven.macaroon(bakery.VERSION_1, AGES, None, ops) got_ops, conds = test_oven.macaroon_ops([m.macaroon]) - self.assertEquals(len(conds), 1) # time-before caveat. - self.assertEquals(bakery.canonical_ops(got_ops), ops) + self.assertEqual(len(conds), 1) # time-before caveat. + self.assertEqual(bakery.canonical_ops(got_ops), ops) def test_huge_number_of_ops_gives_small_macaroon(self): test_oven = bakery.Oven( @@ -93,9 +93,9 @@ class TestOven(TestCase): m = test_oven.macaroon(bakery.LATEST_VERSION, AGES, None, ops) got_ops, conds = test_oven.macaroon_ops([m.macaroon]) - self.assertEquals(len(conds), 1) # time-before caveat. - self.assertEquals(bakery.canonical_ops(got_ops), - bakery.canonical_ops(ops)) + self.assertEqual(len(conds), 1) # time-before caveat. + self.assertEqual(bakery.canonical_ops(got_ops), + bakery.canonical_ops(ops)) data = m.serialize_json() self.assertLess(len(data), 300) @@ -111,8 +111,8 @@ class TestOven(TestCase): m = test_oven.macaroon(bakery.LATEST_VERSION, AGES, None, ops) got_ops, conds = test_oven.macaroon_ops([m.macaroon]) - self.assertEquals(bakery.canonical_ops(got_ops), - bakery.canonical_ops(ops)) + self.assertEqual(bakery.canonical_ops(got_ops), + bakery.canonical_ops(ops)) # Make another macaroon containing the same ops in a different order. ops = [bakery.Op('one', 'write'), @@ -121,4 +121,4 @@ class TestOven(TestCase): bakery.Op('two', 'read')] test_oven.macaroon(bakery.LATEST_VERSION, AGES, None, ops) - self.assertEquals(len(st._store), 1) + self.assertEqual(len(st._store), 1) @@ -2,9 +2,6 @@ # Copyright 2017 Canonical Ltd. # Licensed under the LGPLv3, see LICENCE file for details. -import sys -import platform - from setuptools import ( find_packages, setup, @@ -13,8 +10,8 @@ from setuptools import ( PROJECT_NAME = 'macaroonbakery' -# version 1.2.3 -VERSION = (1, 2, 3) +# version 1.3.4 +VERSION = (1, 3, 4) def get_version(): @@ -30,29 +27,21 @@ requirements = [ 'PyNaCl>=1.1.2,<2.0', 'pymacaroons>=0.12.0,<1.0', 'six>=1.11.0,<2.0', - 'protobuf>=3.0.0,<4.0', + 'protobuf>=3.20.0', 'pyRFC3339>=1.0,<2.0', + 'ipaddress;python_version<"3"', + 'cryptography==1.3.2;python_full_version<"2.7.9"', + 'ndg_httpsclient==0.3.3;python_full_version<"2.7.9"', + 'pyasn1==0.1.9;python_full_version<"2.7.9"', + 'pyOpenSSL==16.0.0;python_full_version<"2.7.9"', ] test_requirements = [ 'tox', + 'fixtures', 'httmock==1.2.5', ] -distribution = platform.dist() -if len(distribution) == 3 and distribution[2] == 'trusty': - # Injected into urllib3 to fix insecure Python 2. - requirements.extend([ - 'cryptography==1.3.2', - 'pyOpenSSL==16.0.0', - 'pyasn1==0.1.9', - 'ndg_httpsclient==0.3.3', - ]) - -if sys.version_info.major == 2: - requirements.append('ipaddress') - - setup( name=PROJECT_NAME, version=get_version(), |