def test_negative_validatity_duration(self): toks = delegation_pb2.SubtokenList(subtokens=[ fake_subtoken_proto('user:[email protected]', validity_duration=-3600), ]) with self.assertRaises(delegation.BadTokenError): delegation.check_subtoken_list(toks, FAKE_IDENT)
def test_not_active_yet(self): now = int(utils.time_time()) toks = delegation_pb2.SubtokenList(subtokens=[ fake_subtoken_proto('user:[email protected]', creation_time=now + 120), ]) with self.assertRaises(delegation.BadTokenError): delegation.check_subtoken_list(toks, FAKE_IDENT)
def test_delegation_token(self): peer_ident = model.Identity.from_bytes('user:[email protected]') class Handler(handler.AuthenticatingHandler): @classmethod def get_auth_methods(cls, conf): return [lambda _request: peer_ident] @api.public def get(self): self.response.write( json.dumps({ 'peer_id': api.get_peer_identity().to_bytes(), 'cur_id': api.get_current_identity().to_bytes(), })) app = self.make_test_app('/request', Handler) def call(headers=None): return json.loads(app.get('/request', headers=headers).body) # No delegation. self.assertEqual( { u'cur_id': u'user:[email protected]', u'peer_id': u'user:[email protected]' }, call()) # TODO(vadimsh): Mint token via some high-level function call. subtokens = delegation_pb2.SubtokenList(subtokens=[ delegation_pb2.Subtoken(issuer_id='user:[email protected]', creation_time=int(utils.time_time()), validity_duration=3600), ]) tok = delegation.serialize_token(delegation.seal_token(subtokens)) # With valid delegation token. self.assertEqual( { u'cur_id': u'user:[email protected]', u'peer_id': u'user:[email protected]' }, call({'X-Delegation-Token-V1': tok})) # With invalid delegation token. r = app.get('/request', headers={'X-Delegation-Token-V1': tok + 'blah'}, expect_errors=True) self.assertEqual(403, r.status_int) # Transient error. def mocked_check(*_args): raise delegation.TransientError('Blah') self.mock(delegation, 'check_delegation_token', mocked_check) r = app.get('/request', headers={'X-Delegation-Token-V1': tok}, expect_errors=True) self.assertEqual(500, r.status_int)
def test_expired(self): now = int(utils.time_time()) toks = delegation_pb2.SubtokenList(subtokens=[ fake_subtoken_proto('user:[email protected]', creation_time=now - 120, validity_duration=60), ]) with self.assertRaises(delegation.BadTokenError): delegation.check_subtoken_list(toks, FAKE_IDENT)
def test_token_chain(self): toks = delegation_pb2.SubtokenList(subtokens=[ fake_subtoken_proto('user:[email protected]', audience=['user:[email protected]']), fake_subtoken_proto('user:[email protected]', audience=['user:[email protected]']), ]) make_id = model.Identity.from_bytes ident = delegation.check_subtoken_list(toks, make_id('user:[email protected]')) self.assertEqual(make_id('user:[email protected]'), ident)
def test_allowed_clock_drift(self): now = utils.utcnow() self.mock_now(now) toks = delegation_pb2.SubtokenList(subtokens=[ fake_subtoken_proto('user:[email protected]'), ]) # Works -29 sec before activation. self.mock_now(now, -29) self.assertTrue(delegation.check_subtoken_list(toks, FAKE_IDENT)) # Doesn't work before that. self.mock_now(now, -31) with self.assertRaises(delegation.BadTokenError): delegation.check_subtoken_list(toks, FAKE_IDENT)
def test_subtoken_services(self): toks = delegation_pb2.SubtokenList(subtokens=[ fake_subtoken_proto('user:[email protected]', services=['service:app-id']), ]) # Passes. self.mock(model, 'get_service_self_identity', lambda: model.Identity.from_bytes('service:app-id')) self.assertTrue(delegation.check_subtoken_list(toks, FAKE_IDENT)) # Fails. self.mock(model, 'get_service_self_identity', lambda: model.Identity.from_bytes('service:another-app-id')) with self.assertRaises(delegation.BadTokenError): delegation.check_subtoken_list(toks, FAKE_IDENT)
def test_expiration_moment(self): now = utils.utcnow() self.mock_now(now) toks = delegation_pb2.SubtokenList(subtokens=[ fake_subtoken_proto('user:[email protected]', validity_duration=3600), ]) # Active at now + 3599. self.mock_now(now, 3599) self.assertTrue(delegation.check_subtoken_list(toks, FAKE_IDENT)) # Expired at now + 3601. self.mock_now(now, 3601) with self.assertRaises(delegation.BadTokenError): delegation.check_subtoken_list(toks, FAKE_IDENT)
def test_works(self): # Subtoken list proto. toks = delegation_pb2.SubtokenList(subtokens=[ fake_subtoken_proto('user:[email protected]', audience=['user:[email protected]']), fake_subtoken_proto('user:[email protected]', audience=['user:[email protected]']), ]) # Sign, serialize. blob = delegation.serialize_token(delegation.seal_token(toks)) # Deserialize, check sig, validate. make_id = model.Identity.from_bytes ident = delegation.check_delegation_token(blob, make_id('user:[email protected]')) self.assertEqual(make_id('user:[email protected]'), ident)
def test_subtoken_audience(self): groups = {'abc': ['user:[email protected]']} self.mock(api, 'is_group_member', lambda g, i: i.to_bytes() in groups.get(g, [])) toks = delegation_pb2.SubtokenList(subtokens=[ fake_subtoken_proto('user:[email protected]', audience=['user:[email protected]', 'group:abc']), ]) # Works. make_id = model.Identity.from_bytes self.assertTrue( delegation.check_subtoken_list(toks, make_id('user:[email protected]'))) self.assertTrue( delegation.check_subtoken_list(toks, make_id('user:[email protected]'))) # Other ids are rejected. with self.assertRaises(delegation.BadTokenError): delegation.check_subtoken_list(toks, make_id('user:[email protected]'))
def post(self): # Forbid usage of delegation tokens for this particular call. Using # delegation when creating delegation tokens is too deep. Redelegation will # be done as separate explicit API call that accept existing delegation # token via request body, not via headers. if auth.get_current_identity() != auth.get_peer_identity(): raise auth.AuthorizationError( 'This API call must not be used with active delegation token') # Convert request body to proto (with validation). try: subtoken = subtoken_from_jsonish(self.parse_body()) except (TypeError, ValueError) as exc: self.abort_with_error(400, text=str(exc)) # Fill in defaults. assert not subtoken.impersonator_id user_id = auth.get_current_identity().to_bytes() if not subtoken.issuer_id: subtoken.issuer_id = user_id if subtoken.issuer_id != user_id: subtoken.impersonator_id = user_id subtoken.creation_time = int(utils.time_time()) if not subtoken.validity_duration: subtoken.validity_duration = DEF_VALIDITY_DURATION_SEC if not subtoken.services or '*' in subtoken.services: subtoken.services[:] = get_default_allowed_services(user_id) # Check ACL (raises auth.AuthorizationError on errors). check_can_create_token(user_id, subtoken) # Create and sign the token. try: token = delegation.serialize_token( delegation.seal_token( delegation_pb2.SubtokenList(subtokens=[subtoken]))) except delegation.BadTokenError as exc: # This happens if resulting token is too large. self.abort_with_error(400, text=str(exc)) self.send_response(response={ 'delegation_token': token, 'validity_duration': subtoken.validity_duration, }, http_code=201)
def test_delegation_token(self): def call(tok=None): headers = {'X-Delegation-Token-V1': tok} if tok else None self.call('127.0.0.1', '*****@*****.**', headers) return { 'cur_id': api.get_current_identity().to_bytes(), 'peer_id': api.get_current_identity().to_bytes(), } # No delegation. self.assertEqual( { 'cur_id': 'user:[email protected]', 'peer_id': 'user:[email protected]' }, call()) # TODO(vadimsh): Mint token via some high-level function call. subtokens = delegation_pb2.SubtokenList(subtokens=[ delegation_pb2.Subtoken(issuer_id='user:[email protected]', creation_time=int(utils.time_time()), validity_duration=3600), ]) tok = delegation.serialize_token(delegation.seal_token(subtokens)) # Valid delegation token. self.assertEqual( { 'cur_id': 'user:[email protected]', 'peer_id': 'user:[email protected]' }, call(tok)) # Invalid delegation token. with self.assertRaises(api.AuthorizationError): call(tok + 'blah') # Transient error. def mocked_check(*_args): raise delegation.TransientError('Blah') self.mock(delegation, 'check_delegation_token', mocked_check) with self.assertRaises(endpoints.InternalServerErrorException): call(tok)
def fake_subtoken_list_proto(): return delegation_pb2.SubtokenList(subtokens=[ fake_subtoken_proto('user:[email protected]'), fake_subtoken_proto('user:[email protected]'), ])
def test_passes_validation(self): toks = delegation_pb2.SubtokenList(subtokens=[ fake_subtoken_proto('user:[email protected]'), ]) ident = delegation.check_subtoken_list(toks, FAKE_IDENT) self.assertEqual('user:[email protected]', ident.to_bytes())