diff options
Diffstat (limited to 'macaroonbakery/tests/test_client.py')
-rw-r--r-- | macaroonbakery/tests/test_client.py | 130 |
1 files changed, 107 insertions, 23 deletions
diff --git a/macaroonbakery/tests/test_client.py b/macaroonbakery/tests/test_client.py index 8263f54..04e2f2b 100644 --- a/macaroonbakery/tests/test_client.py +++ b/macaroonbakery/tests/test_client.py @@ -4,23 +4,24 @@ import base64 import datetime import json import os -from unittest import TestCase -try: - from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler -except ImportError: - from http.server import HTTPServer, BaseHTTPRequestHandler import threading +from unittest import TestCase -from httmock import ( - HTTMock, - urlmatch -) +import macaroonbakery.bakery as bakery +import macaroonbakery.checkers as checkers +import macaroonbakery.httpbakery as httpbakery +import pymacaroons import requests +import macaroonbakery._utils as utils + +from httmock import HTTMock, urlmatch from six.moves.urllib.parse import parse_qs +from six.moves.urllib.request import Request -import macaroonbakery as bakery -import macaroonbakery.httpbakery as httpbakery -import macaroonbakery.checkers as checkers +try: + from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler +except ImportError: + from http.server import HTTPServer, BaseHTTPRequestHandler AGES = datetime.datetime.utcnow() + datetime.timedelta(days=1) TEST_OP = bakery.Op(entity='test', action='test') @@ -37,7 +38,7 @@ class TestClient(TestCase): b = new_bakery('loc', None, None) def handler(*args): - GetHandler(b, None, None, None, None, *args) + GetHandler(b, None, None, None, None, AGES, *args) try: httpd = HTTPServer(('', 0), handler) thread = threading.Thread(target=httpd.serve_forever) @@ -65,7 +66,7 @@ class TestClient(TestCase): b = new_bakery('loc', None, None) def handler(*args): - GetHandler(b, None, None, None, None, *args) + GetHandler(b, None, None, None, None, AGES, *args) try: httpd = HTTPServer(('', 0), handler) thread = threading.Thread(target=httpd.serve_forever) @@ -88,7 +89,7 @@ class TestClient(TestCase): finally: httpd.shutdown() - def test_repeated_request_with_body(self): + def test_expiry_cookie_is_set(self): class _DischargerLocator(bakery.ThirdPartyLocator): def __init__(self): self.key = bakery.generate_key() @@ -107,7 +108,8 @@ class TestClient(TestCase): 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) + m = httpbakery.discharge(checkers.AuthContext(), content, d.key, d, + alwaysOK3rd) return { 'status_code': 200, 'content': { @@ -115,8 +117,10 @@ class TestClient(TestCase): } } + ages = datetime.datetime.utcnow() + datetime.timedelta(days=1) + def handler(*args): - GetHandler(b, 'http://1.2.3.4', None, None, None, *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) @@ -129,10 +133,64 @@ class TestClient(TestCase): cookies=client.cookies, auth=client.auth()) resp.raise_for_status() + m = bakery.Macaroon.from_dict(json.loads( + 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') finally: httpd.shutdown() + def test_expiry_cookie_set_in_past(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() + } + } + + ages = datetime.datetime.utcnow() - datetime.timedelta(days=1) + + 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(httpbakery.BakeryException) as ctx: + requests.get( + url='http://' + httpd.server_address[0] + ':' + + str(httpd.server_address[1]), + cookies=client.cookies, + auth=client.auth()) + self.assertEqual(ctx.exception.args[0], + 'too many (3) discharge requests') + finally: + httpd.shutdown() + def test_too_many_discharge(self): class _DischargerLocator(bakery.ThirdPartyLocator): def __init__(self): @@ -162,7 +220,7 @@ class TestClient(TestCase): } def handler(*args): - GetHandler(b, 'http://1.2.3.4', None, None, None, *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) @@ -206,7 +264,7 @@ class TestClient(TestCase): ThirdPartyCaveatCheckerF(check)) def handler(*args): - GetHandler(b, 'http://1.2.3.4', None, None, None, *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) @@ -251,7 +309,7 @@ class TestClient(TestCase): } def handler(*args): - GetHandler(b, 'http://1.2.3.4', None, None, None, *args) + GetHandler(b, 'http://1.2.3.4', None, None, None, AGES, *args) try: httpd = HTTPServer(('', 0), handler) @@ -280,11 +338,34 @@ class TestClient(TestCase): finally: httpd.shutdown() + def test_extract_macaroons_from_request(self): + def encode_macaroon(m): + macaroons = '[' + utils.macaroon_to_json_string(m) + ']' + return base64.urlsafe_b64encode(utils.to_bytes(macaroons)).decode('ascii') + + req = Request('http://example.com') + m1 = pymacaroons.Macaroon(version=pymacaroons.MACAROON_V2, identifier='one') + req.add_header('Macaroons', encode_macaroon(m1)) + m2 = pymacaroons.Macaroon(version=pymacaroons.MACAROON_V2, identifier='two') + jar = requests.cookies.RequestsCookieJar() + jar.set_cookie(utils.cookie( + name='macaroon-auth', + value=encode_macaroon(m2), + url='http://example.com', + )) + jar.add_cookie_header(req) + + macaroons = httpbakery.extract_macaroons(req) + self.assertEquals(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) + class GetHandler(BaseHTTPRequestHandler): '''A mock HTTP server that serves a GET request''' def __init__(self, bakery, auth_location, mutate_error, - caveats, version, *args): + caveats, version, expiry, *args): ''' @param bakery used to check incoming requests and macaroons for discharge-required errors. @@ -295,14 +376,17 @@ class GetHandler(BaseHTTPRequestHandler): discharge-required error before responding to the client. @param caveats called to get caveats to add to the returned macaroon. - @param holds the version of the bakery that the + @param version holds the version of the bakery that the server will purport to serve. + @param expiry holds the expiry for the macaroon that will be created + in _write_discharge_error ''' self._bakery = bakery self._auth_location = auth_location self._mutate_error = mutate_error self._caveats = caveats self._server_version = version + self._expiry = expiry BaseHTTPRequestHandler.__init__(self, *args) def do_GET(self): @@ -340,7 +424,7 @@ class GetHandler(BaseHTTPRequestHandler): caveats.extend(self._caveats) m = self._bakery.oven.macaroon( - version=bakery.LATEST_VERSION, expiry=AGES, + version=bakery.LATEST_VERSION, expiry=self._expiry, caveats=caveats, ops=[TEST_OP]) content, headers = httpbakery.discharge_required_response( |