From 883e591e1e08c13d1a8e909a113a621552ae4b55 Mon Sep 17 00:00:00 2001 From: Colin Watson Date: Fri, 12 Oct 2018 13:08:30 +0100 Subject: New upstream version 1.2.0 --- macaroonbakery/bakery/_checker.py | 25 ++++----- macaroonbakery/bakery/_internal/id.proto | 14 ----- macaroonbakery/httpbakery/_discharge.py | 5 +- macaroonbakery/tests/test_client.py | 92 ++++++++++++++++++++++++++++++++ macaroonbakery/tests/test_discharge.py | 10 ++-- 5 files changed, 114 insertions(+), 32 deletions(-) delete mode 100644 macaroonbakery/bakery/_internal/id.proto (limited to 'macaroonbakery') diff --git a/macaroonbakery/bakery/_checker.py b/macaroonbakery/bakery/_checker.py index b796502..88560cc 100644 --- a/macaroonbakery/bakery/_checker.py +++ b/macaroonbakery/bakery/_checker.py @@ -111,21 +111,18 @@ class AuthChecker(object): if not self._executed: self._init_once(ctx) self._executed = True - if self._init_errors: - raise AuthInitError(self._init_errors[0]) def _init_once(self, ctx): self._auth_indexes = {} self._conditions = [None] * len(self._macaroons) for i, ms in enumerate(self._macaroons): try: - ops, conditions = self.parent._macaroon_opstore.macaroon_ops( - ms) - except VerificationError: - raise - except Exception as exc: - self._init_errors.append(exc.args[0]) + ops, conditions = self.parent._macaroon_opstore.macaroon_ops(ms) + except VerificationError as e: + self._init_errors.append(str(e)) continue + except Exception as exc: + raise AuthInitError(str(exc)) # It's a valid macaroon (in principle - we haven't checked first # party caveats). @@ -152,8 +149,7 @@ class AuthChecker(object): # other operations if the conditions succeed for those. declared, err = self._check_conditions(ctx, LOGIN_OP, conditions) if err is not None: - self._init_errors.append('cannot authorize login macaroon: ' + - err) + self._init_errors.append('cannot authorize login macaroon: ' + err) continue if self._identity is not None: # We've already found a login macaroon so ignore this one @@ -201,8 +197,13 @@ class AuthChecker(object): authorization requests. If an operation was not allowed, an exception will be raised which may - be DischargeRequiredError holding the operations that remain to - be authorized in order to allow authorization to proceed. + be: + + - DischargeRequiredError holding the operations that remain to + be authorized in order to allow authorization to proceed + - PermissionDenied when no operations can be authorized and there's + no third party to discharge macaroons for. + @param ctx AuthContext @param ops an array of Op :return: an AuthInfo object. diff --git a/macaroonbakery/bakery/_internal/id.proto b/macaroonbakery/bakery/_internal/id.proto deleted file mode 100644 index eb3d614..0000000 --- a/macaroonbakery/bakery/_internal/id.proto +++ /dev/null @@ -1,14 +0,0 @@ -syntax="proto3"; - -option go_package = "macaroonpb"; - -message MacaroonId { - bytes nonce = 1; - bytes storageId = 2; - repeated Op ops = 3; -} - -message Op { - string entity = 1; - repeated string actions = 2; -} diff --git a/macaroonbakery/httpbakery/_discharge.py b/macaroonbakery/httpbakery/_discharge.py index f868d23..1873850 100644 --- a/macaroonbakery/httpbakery/_discharge.py +++ b/macaroonbakery/httpbakery/_discharge.py @@ -16,10 +16,13 @@ def discharge(ctx, content, key, locator, checker): @return The discharge macaroon {macaroonbakery.Macaroon} ''' id = content.get('id') - if id is None: + if id is not None: + id = id.encode('utf-8') + else: id = content.get('id64') if id is not None: id = utils.b64decode(id) + caveat = content.get('caveat64') if caveat is not None: caveat = utils.b64decode(caveat) diff --git a/macaroonbakery/tests/test_client.py b/macaroonbakery/tests/test_client.py index 4061a8a..9c57b78 100644 --- a/macaroonbakery/tests/test_client.py +++ b/macaroonbakery/tests/test_client.py @@ -55,6 +55,98 @@ class TestClient(TestCase): finally: httpd.shutdown() + def test_single_service_third_party(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): + qs = parse_qs(request.body) + content = {q: qs[q][0] for q in qs} + m = httpbakery.discharge(checkers.AuthContext(), content, d.key, d, + alwaysOK3rd) + return { + 'status_code': 200, + 'content': { + 'Macaroon': m.to_dict() + } + } + + def handler(*args): + GetHandler(b, 'http://1.2.3.4', None, None, None, AGES, *args) + try: + httpd = HTTPServer(('', 0), handler) + server_url = 'http://' + httpd.server_address[0] + ':' + str(httpd.server_address[1]) + thread = threading.Thread(target=httpd.serve_forever) + thread.start() + client = httpbakery.Client() + with HTTMock(discharge): + resp = requests.get( + url=server_url, + cookies=client.cookies, + auth=client.auth()) + resp.raise_for_status() + self.assertEquals(resp.text, 'done') + finally: + httpd.shutdown() + + def test_single_service_third_party_version_1_caveat(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.VERSION_1, + ) + + d = _DischargerLocator() + b = new_bakery('loc', d, None) + + @urlmatch(path='.*/discharge') + def discharge(url, request): + qs = parse_qs(request.body) + content = {q: qs[q][0] for q in qs} + m = httpbakery.discharge(checkers.AuthContext(), content, d.key, d, + alwaysOK3rd) + return { + 'status_code': 200, + 'content': { + 'Macaroon': m.to_dict() + } + } + + def handler(*args): + GetHandler(b, 'http://1.2.3.4', None, None, None, AGES, *args) + try: + httpd = HTTPServer(('', 0), handler) + server_url = 'http://' + httpd.server_address[0] + ':' + str(httpd.server_address[1]) + thread = threading.Thread(target=httpd.serve_forever) + thread.start() + client = httpbakery.Client() + with HTTMock(discharge): + resp = requests.get( + url=server_url, + cookies=client.cookies, + auth=client.auth()) + resp.raise_for_status() + self.assertEquals(resp.text, 'done') + finally: + httpd.shutdown() + def test_cookie_domain_host_not_fqdn(self): # See # https://github.com/go-macaroon-bakery/py-macaroon-bakery/issues/53 diff --git a/macaroonbakery/tests/test_discharge.py b/macaroonbakery/tests/test_discharge.py index 27bae63..0802070 100644 --- a/macaroonbakery/tests/test_discharge.py +++ b/macaroonbakery/tests/test_discharge.py @@ -153,7 +153,7 @@ class TestDischarge(unittest.TestCase): bakery.LOGIN_OP ) self.fail('macaroon unmet should be raised') - except bakery.VerificationError: + except bakery.PermissionDenied: pass def test_macaroon_paper_fig6_fails_with_binding_on_tampered_sig(self): @@ -194,7 +194,7 @@ class TestDischarge(unittest.TestCase): d[i + 1] = tampered_macaroon.prepare_for_request(dm) # client makes request to ts. - with self.assertRaises(bakery.VerificationError) as exc: + with self.assertRaises(bakery.PermissionDenied) as exc: ts.checker.auth([d]).allow(common.test_context, bakery.LOGIN_OP) self.assertEqual('verification failed: Signatures do not match', @@ -298,7 +298,7 @@ class TestDischarge(unittest.TestCase): 'arble': 'b', }) - with self.assertRaises(bakery.AuthInitError) as exc: + with self.assertRaises(bakery.PermissionDenied) as exc: first_party.checker.auth([d]).allow(common.test_context, bakery.LOGIN_OP) self.assertEqual('cannot authorize login macaroon: caveat ' @@ -377,7 +377,7 @@ class TestDischarge(unittest.TestCase): 'bar': '', 'baz': 'bazval', }) - with self.assertRaises(bakery.AuthInitError) as exc: + with self.assertRaises(bakery.PermissionDenied) as exc: first_party.checker.auth([d]).allow(common.test_context, bakery.LOGIN_OP) self.assertEqual('cannot authorize login macaroon: caveat "declared ' @@ -416,7 +416,7 @@ class TestDischarge(unittest.TestCase): self.assertIsNotNone(M.unbound) # Make sure it cannot be used as a normal macaroon in the third party. - with self.assertRaises(bakery.VerificationError) as exc: + with self.assertRaises(bakery.PermissionDenied) as exc: third_party.checker.auth([[M.unbound]]).allow( common.test_context, [bakery.LOGIN_OP]) self.assertEqual('no operations found in macaroon', -- cgit v1.2.3