def test_delegation_token(self): # No delegation. self.assertEqual( { 'cur_id': 'user:[email protected]', 'peer_id': 'user:[email protected]' }, self.call_with_tokens()) # Grab a fake-signed delegation token. subtoken = delegation_pb2.Subtoken( delegated_identity='user:[email protected]', kind=delegation_pb2.Subtoken.BEARER_DELEGATION_TOKEN, audience=['*'], services=['*'], creation_time=int(utils.time_time()), validity_duration=3600) tok_pb = delegation_pb2.DelegationToken( serialized_subtoken=subtoken.SerializeToString(), signer_id='user:[email protected]', signing_key_id='signing-key', pkcs1_sha256_sig='fake-signature') tok = b64.encode(tok_pb.SerializeToString()) # Valid delegation token. self.assertEqual( { 'cur_id': 'user:[email protected]', 'peer_id': 'user:[email protected]' }, self.call_with_tokens(delegation_tok=tok)) # Invalid delegation token. with self.assertRaises(api.AuthorizationError): self.call_with_tokens(delegation_tok=tok + 'blah')
def test_works(self): # Note: we can't use verify_jwt in this test because tokens produced by # sign_jwt do not have 'kid' header field which is required by verify_jwt. expected_hdr = b64.encode('{"alg":"RS256","typ":"JWT"}') expected_claims = b64.encode( utils.encode_to_json({ 'aud': 'some audience', 'email': '*****@*****.**', 'exp': 1514772061, # matches NOW+1h 'iat': 1514768461, # matches NOW 'iss': '*****@*****.**', 'sub': '*****@*****.**', })) expected_sig = b64.encode('signature') self.assertEqual( tokens.sign_jwt(u'some audience'), '.'.join( (expected_hdr, expected_claims, expected_sig))) self.assertEqual(self.signed[0], '.'.join( (expected_hdr, expected_claims)))
def test_delegation_token(self): call = self.make_test_app_with_peer('user:[email protected]') # No delegation. self.assertEqual( { 'status': 200, 'body': { u'cur_id': u'user:[email protected]', u'peer_id': u'user:[email protected]', }, }, call()) # Grab a fake-signed delegation token. subtoken = delegation_pb2.Subtoken( delegated_identity='user:[email protected]', kind=delegation_pb2.Subtoken.BEARER_DELEGATION_TOKEN, audience=['*'], services=['*'], creation_time=int(utils.time_time()), validity_duration=3600) tok_pb = delegation_pb2.DelegationToken( serialized_subtoken=subtoken.SerializeToString(), signer_id='user:[email protected]', signing_key_id='signing-key', pkcs1_sha256_sig='fake-signature') tok = b64.encode(tok_pb.SerializeToString()) # With valid delegation token. self.assertEqual( { 'status': 200, 'body': { u'cur_id': u'user:[email protected]', u'peer_id': u'user:[email protected]', }, }, call({'X-Delegation-Token-V1': tok})) # With invalid delegation token. resp = call({'X-Delegation-Token-V1': tok + 'blah'}) self.assertEqual(403, resp['status']) self.assertIn('Bad delegation token', resp['body']) # Transient error. def mocked_check(*_args): raise delegation.TransientError('Blah') self.mock(delegation, 'check_bearer_delegation_token', mocked_check) resp = call({'X-Delegation-Token-V1': tok}) self.assertEqual(500, resp['status']) self.assertIn('Blah', resp['body'])
def post(self, app_id): # On local dev server |app_id| may use @localhost:8080 to specify where # app is running. custom_host = None if utils.is_local_dev_server(): app_id, _, custom_host = app_id.partition('@') # Generate an opaque ticket that would be passed back to /link_replica. # /link_replica will verify HMAC tag and will ensure the request came from # application with ID |app_id|. ticket = LinkTicketToken.generate([], {'app_id': app_id}) # ServiceLinkTicket contains information that is needed for Replica # to figure out how to contact Primary. link_msg = replication_pb2.ServiceLinkTicket() link_msg.primary_id = app_identity.get_application_id() link_msg.primary_url = self.request.host_url link_msg.generated_by = auth.get_current_identity().to_bytes() link_msg.ticket = ticket # Special case for dev server to simplify local development. if custom_host: assert utils.is_local_dev_server() host = 'http://%s' % custom_host else: # Use same domain as auth_service. Usually it's just appspot.com. current_hostname = app_identity.get_default_version_hostname() domain = current_hostname.partition('.')[2] naked_app_id = app_id if ':' in app_id: naked_app_id = app_id[app_id.find(':') + 1:] host = 'https://%s.%s' % (naked_app_id, domain) # URL to a handler on Replica that initiates Replica <-> Primary handshake. url = '%s/auth/link?t=%s' % (host, b64.encode(link_msg.SerializeToString())) self.send_response({'url': url}, http_code=201)
def test_base64_encode_decode(self): # Encode a bunch of strings of different lengths to test all # possible paddings (to see how padding stripping works). msg = 'somewhat long message with binary \x00\x01\x02\x03 inside' for i in range(len(msg)): self.assertEqual(msg[:i], b64.decode(b64.encode(msg[:i])))
def test_base64_encode_is_url_safe(self): for a in range(255): original = chr(a) encoded = b64.encode(original) self.assertEqual(original, b64.decode(encoded)) self.assertTrue(URL_SAFE_ALPHABET.issuperset(encoded), encoded)
def test_base64_encode_types(self): with self.assertRaises(TypeError): b64.encode(None) with self.assertRaises(TypeError): b64.encode(u'unicode')
def test_deserialize_bad_proto(self): tok = b64.encode('not a proto') with self.assertRaises(exceptions.BadTokenError): delegation.deserialize_token(tok)
def test_deserialize_huge(self): msg = fake_token_proto() msg.serialized_subtoken = 'huge' * 10000 tok = b64.encode(msg.SerializeToString()) with self.assertRaises(exceptions.BadTokenError): delegation.deserialize_token(tok)
def serialize_token(tok): return b64.encode(tok.SerializeToString())
def make_jwt(self, hdr, payload, sig=SIG): return '%s.%s.%s' % (to_json_b64(hdr), to_json_b64(payload), b64.encode(sig))
def to_json_b64(d): return b64.encode(json.dumps(d, sort_keys=True))