def __init__(self, name, auth, idm, locator): self._name = name self._store = _MacaroonStore(macaroonbakery.generate_key(), locator) self._checker = macaroonbakery.Checker(checker=test_checker(), authorizer=auth, identity_client=idm, macaroon_opstore=self._store)
def test_fallback(self): key = macaroonbakery.generate_key() @urlmatch(path='.*/discharge/info') def discharge_info(url, request): return { 'status_code': 404, } @urlmatch(path='.*/publickey') def public_key(url, request): return { 'status_code': 200, 'content': { 'PublicKey': key.public_key.encode().decode('utf-8') } } expectInfo = macaroonbakery.ThirdPartyInfo( public_key=key.public_key, version=macaroonbakery.BAKERY_V1) kr = httpbakery.ThirdPartyLocator(allow_insecure=True) with HTTMock(discharge_info): with HTTMock(public_key): info = kr.third_party_info('http://0.1.2.3/') self.assertEqual(info, expectInfo)
def __init__(self, name, auth, idm, locator): self._name = name self._store = _MacaroonStore(bakery.generate_key(), locator) self._checker = bakery.Checker( checker=test_checker(), authorizer=auth, identity_client=idm, macaroon_opstore=self._store)
def test_discharge_all_local_discharge_version1(self): oc = common.new_bakery('ts', None) client_key = bakery.generate_key() m = oc.oven.macaroon(bakery.VERSION_1, common.ages, [ bakery.local_third_party_caveat(client_key.public_key, bakery.VERSION_1) ], [bakery.LOGIN_OP]) ms = bakery.discharge_all(m, no_discharge(self), client_key) oc.checker.auth([ms]).allow(common.test_context, [bakery.LOGIN_OP])
def test_discharge_all_local_discharge_version1(self): oc = common.new_bakery('ts', None) client_key = bakery.generate_key() m = oc.oven.macaroon(bakery.VERSION_1, common.ages, [ bakery.local_third_party_caveat( client_key.public_key, bakery.VERSION_1) ], [bakery.LOGIN_OP]) ms = bakery.discharge_all(m, no_discharge(self), client_key) oc.checker.auth([ms]).allow(common.test_context, [bakery.LOGIN_OP])
def test_discharge_all_local_discharge(self): oc = common.new_bakery('ts', None) client_key = macaroonbakery.generate_key() m = oc.oven.macaroon(macaroonbakery.LATEST_BAKERY_VERSION, common.ages, [ macaroonbakery.local_third_party_caveat( client_key.public_key, macaroonbakery.LATEST_BAKERY_VERSION) ], [macaroonbakery.LOGIN_OP]) ms = macaroonbakery.discharge_all(common.test_context, m, no_discharge(self), client_key) oc.checker.auth([ms]).allow(common.test_context, [macaroonbakery.LOGIN_OP])
def new_bakery(location, locator=None): # Returns a new Bakery instance using a new # key pair, and registers the key with the given locator if provided. # # It uses test_checker to check first party caveats. key = bakery.generate_key() if locator is not None: locator.add_info(location, bakery.ThirdPartyInfo( public_key=key.public_key, version=bakery.LATEST_VERSION)) return bakery.Bakery( key=key, checker=test_checker(), location=location, identity_client=OneIdentity(), locator=locator, )
def new_bakery(location, locator=None): # Returns a new Bakery instance using a new # key pair, and registers the key with the given locator if provided. # # It uses test_checker to check first party caveats. key = bakery.generate_key() if locator is not None: locator.add_info( location, bakery.ThirdPartyInfo(public_key=key.public_key, version=bakery.LATEST_VERSION)) return bakery.Bakery( key=key, checker=test_checker(), location=location, identity_client=OneIdentity(), locator=locator, )
def new_bakery(location, locator, checker): '''Return a new bakery instance. @param location Location of the bakery {str}. @param locator Locator for third parties {ThirdPartyLocator or None} @param checker Caveat checker {FirstPartyCaveatChecker or None} @return {Bakery} ''' if checker is None: c = checkers.Checker() c.namespace().register('testns', '') c.register('is', 'testns', check_is_something) checker = c key = bakery.generate_key() return bakery.Bakery( location=location, locator=locator, key=key, checker=checker, )
def test_auth_with_third_party_caveats(self): locator = _DischargerLocator() ids = _IdService('ids', locator, self) # We make an authorizer that requires a third party discharge # when authorizing. def authorize_with_tp_discharge(ctx, id, op): if (id is not None and id.id() == 'bob' and op == macaroonbakery.Op(entity='something', action='read')): return True, [ checkers.Caveat(condition='question', location='other third party') ] return False, None auth = macaroonbakery.AuthorizerFunc(authorize_with_tp_discharge) ts = _Service('myservice', auth, ids, locator) class _LocalDischargeChecker(macaroonbakery.ThirdPartyCaveatChecker): def check_third_party_caveat(_, ctx, info): if info.condition != 'question': raise ValueError('third party condition not recognized') self._discharges.append( _DischargeRecord(location='other third party', user=ctx.get(_DISCHARGE_USER_KEY))) return [] locator['other third party'] = _Discharger( key=macaroonbakery.generate_key(), checker=_LocalDischargeChecker(), locator=locator, ) client = _Client(locator) ctx = test_context.with_value(_DISCHARGE_USER_KEY, 'bob') client.do(ctx, ts, [macaroonbakery.Op(entity='something', action='read')]) self.assertEqual(self._discharges, [ _DischargeRecord(location='ids', user='******'), _DischargeRecord(location='other third party', user='******') ])
def test_auth_with_third_party_caveats(self): locator = _DischargerLocator() ids = _IdService('ids', locator, self) # We make an authorizer that requires a third party discharge # when authorizing. def authorize_with_tp_discharge(ctx, id, op): if (id is not None and id.id() == 'bob' and op == bakery.Op(entity='something', action='read')): return True, [checkers.Caveat(condition='question', location='other third party')] return False, None auth = bakery.AuthorizerFunc(authorize_with_tp_discharge) ts = _Service('myservice', auth, ids, locator) class _LocalDischargeChecker(bakery.ThirdPartyCaveatChecker): def check_third_party_caveat(_, ctx, info): if info.condition != 'question': raise ValueError('third party condition not recognized') self._discharges.append(_DischargeRecord( location='other third party', user=ctx.get(_DISCHARGE_USER_KEY) )) return [] locator['other third party'] = _Discharger( key=bakery.generate_key(), checker=_LocalDischargeChecker(), locator=locator, ) client = _Client(locator) ctx = test_context.with_value(_DISCHARGE_USER_KEY, 'bob') client.do(ctx, ts, [bakery.Op(entity='something', action='read')]) self.assertEqual(self._discharges, [ _DischargeRecord(location='ids', user='******'), _DischargeRecord(location='other third party', user='******') ])
def __init__(self, dischargers): self._key = bakery.generate_key() self._macaroons = {} self._dischargers = dischargers
def setUp(self): self.fp_key = bakery.generate_key() self.tp_key = bakery.generate_key()
def __init__(self, location, locator, test_class): self._location = location self._test = test_class key = bakery.generate_key() self._discharger = _Discharger(key=key, checker=self, locator=locator) locator[location] = self._discharger
def test_agent_login(self): discharge_key = bakery.generate_key() class _DischargerLocator(bakery.ThirdPartyLocator): def third_party_info(self, loc): if loc == 'http://0.3.2.1': return bakery.ThirdPartyInfo( public_key=discharge_key.public_key, version=bakery.LATEST_VERSION, ) d = _DischargerLocator() server_key = bakery.generate_key() server_bakery = bakery.Bakery(key=server_key, locator=d) @urlmatch(path='.*/here') def server_get(url, request): ctx = checkers.AuthContext() test_ops = [bakery.Op(entity='test-op', action='read')] auth_checker = server_bakery.checker.auth( httpbakery.extract_macaroons(request.headers)) try: auth_checker.allow(ctx, test_ops) resp = response(status_code=200, content='done') except bakery.PermissionDenied: caveats = [ checkers.Caveat(location='http://0.3.2.1', condition='is-ok') ] m = server_bakery.oven.macaroon(version=bakery.LATEST_VERSION, expiry=datetime.utcnow() + timedelta(days=1), caveats=caveats, ops=test_ops) content, headers = httpbakery.discharge_required_response( m, '/', 'test', 'message') resp = response(status_code=401, content=content, headers=headers) return request.hooks['response'][0](resp) @urlmatch(path='.*/discharge') def discharge(url, request): qs = parse_qs(request.body) if qs.get('token64') is None: return response(status_code=401, content={ 'Code': httpbakery.ERR_INTERACTION_REQUIRED, 'Message': 'interaction required', 'Info': { 'InteractionMethods': { 'agent': { 'login-url': '/login' }, }, }, }, headers={'Content-Type': 'application/json'}) else: qs = parse_qs(request.body) content = {q: qs[q][0] for q in qs} m = httpbakery.discharge(checkers.AuthContext(), content, discharge_key, None, alwaysOK3rd) return { 'status_code': 200, 'content': { 'Macaroon': m.serialize_json() } } key = bakery.generate_key() @urlmatch(path='.*/login') def login(url, request): b = bakery.Bakery(key=discharge_key) m = b.oven.macaroon( version=bakery.LATEST_VERSION, expiry=datetime.utcnow() + timedelta(days=1), caveats=[ bakery.local_third_party_caveat( key.public_key, version=httpbakery.request_version(request.headers)) ], ops=[bakery.Op(entity='agent', action='login')]) return {'status_code': 200, 'content': {'macaroon': m.to_dict()}} with HTTMock(server_get), \ HTTMock(discharge), \ HTTMock(login): client = httpbakery.Client(interaction_methods=[ agent.AgentInteractor( agent.AuthInfo( key=key, agents=[ agent.Agent(username='******', url=u'http://0.3.2.1') ], ), ), ]) resp = requests.get('http://0.1.2.3/here', cookies=client.cookies, auth=client.auth()) self.assertEquals(resp.content, b'done')
def test_agent_legacy(self): discharge_key = bakery.generate_key() class _DischargerLocator(bakery.ThirdPartyLocator): def third_party_info(self, loc): if loc == 'http://0.3.2.1': return bakery.ThirdPartyInfo( public_key=discharge_key.public_key, version=bakery.LATEST_VERSION, ) d = _DischargerLocator() server_key = bakery.generate_key() server_bakery = bakery.Bakery(key=server_key, locator=d) @urlmatch(path='.*/here') def server_get(url, request): ctx = checkers.AuthContext() test_ops = [bakery.Op(entity='test-op', action='read')] auth_checker = server_bakery.checker.auth( httpbakery.extract_macaroons(request.headers)) try: auth_checker.allow(ctx, test_ops) resp = response(status_code=200, content='done') except bakery.PermissionDenied: caveats = [ checkers.Caveat(location='http://0.3.2.1', condition='is-ok') ] m = server_bakery.oven.macaroon(version=bakery.LATEST_VERSION, expiry=datetime.utcnow() + timedelta(days=1), caveats=caveats, ops=test_ops) content, headers = httpbakery.discharge_required_response( m, '/', 'test', 'message') resp = response( status_code=401, content=content, headers=headers, ) return request.hooks['response'][0](resp) class InfoStorage: info = None @urlmatch(path='.*/discharge') def discharge(url, request): qs = parse_qs(request.body) if qs.get('caveat64') is not None: content = {q: qs[q][0] for q in qs} class InteractionRequiredError(Exception): def __init__(self, error): self.error = error class CheckerInError(bakery.ThirdPartyCaveatChecker): def check_third_party_caveat(self, ctx, info): InfoStorage.info = info raise InteractionRequiredError( httpbakery.Error( code=httpbakery.ERR_INTERACTION_REQUIRED, version=httpbakery.request_version( request.headers), message='interaction required', info=httpbakery.ErrorInfo( wait_url='http://0.3.2.1/wait?' 'dischargeid=1', visit_url='http://0.3.2.1/visit?' 'dischargeid=1'), ), ) try: httpbakery.discharge(checkers.AuthContext(), content, discharge_key, None, CheckerInError()) except InteractionRequiredError as exc: return response( status_code=401, content={ 'Code': exc.error.code, 'Message': exc.error.message, 'Info': { 'WaitURL': exc.error.info.wait_url, 'VisitURL': exc.error.info.visit_url, }, }, headers={'Content-Type': 'application/json'}) key = bakery.generate_key() @urlmatch(path='.*/visit?$') def visit(url, request): if request.headers.get('Accept') == 'application/json': return {'status_code': 200, 'content': {'agent': request.url}} cs = SimpleCookie() cookies = request.headers.get('Cookie') if cookies is not None: cs.load(str(cookies)) public_key = None for c in cs: if c == 'agent-login': json_cookie = json.loads( base64.b64decode(cs[c].value).decode('utf-8')) public_key = bakery.PublicKey.deserialize( json_cookie.get('public_key')) ms = httpbakery.extract_macaroons(request.headers) if len(ms) == 0: b = bakery.Bakery(key=discharge_key) m = b.oven.macaroon( version=bakery.LATEST_VERSION, expiry=datetime.utcnow() + timedelta(days=1), caveats=[ bakery.local_third_party_caveat( public_key, version=httpbakery.request_version( request.headers)) ], ops=[bakery.Op(entity='agent', action='login')]) content, headers = httpbakery.discharge_required_response( m, '/', 'test', 'message') resp = response(status_code=401, content=content, headers=headers) return request.hooks['response'][0](resp) return {'status_code': 200, 'content': {'agent-login': True}} @urlmatch(path='.*/wait?$') def wait(url, request): class EmptyChecker(bakery.ThirdPartyCaveatChecker): def check_third_party_caveat(self, ctx, info): return [] if InfoStorage.info is None: self.fail('visit url has not been visited') m = bakery.discharge( checkers.AuthContext(), InfoStorage.info.id, InfoStorage.info.caveat, discharge_key, EmptyChecker(), _DischargerLocator(), ) return {'status_code': 200, 'content': {'Macaroon': m.to_dict()}} with HTTMock(server_get), \ HTTMock(discharge), \ HTTMock(visit), \ HTTMock(wait): client = httpbakery.Client(interaction_methods=[ agent.AgentInteractor( agent.AuthInfo( key=key, agents=[ agent.Agent(username='******', url=u'http://0.3.2.1') ], ), ), ]) resp = requests.get( 'http://0.1.2.3/here', cookies=client.cookies, auth=client.auth(), ) self.assertEquals(resp.content, b'done')
def __init__(self, dischargers): self._key = macaroonbakery.generate_key() self._macaroons = {} self._dischargers = dischargers
def setUp(self): self.fp_key = bakery.generate_key() self.tp_key = bakery.generate_key()
def __init__(self, location, locator, test_class): self._location = location self._test = test_class key = macaroonbakery.generate_key() self._discharger = _Discharger(key=key, checker=self, locator=locator) locator[location] = self._discharger
def __init__(self): self.key = bakery.generate_key()
def setUp(self): self.fp_key = macaroonbakery.generate_key() self.tp_key = macaroonbakery.generate_key()