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 xrange(len(msg)): self.assertEqual( msg[:i], tokens.base64_decode(tokens.base64_encode(msg[:i])))
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 = tokens.base64_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_delegation_token(self): # 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 = tokens.base64_encode(tok_pb.SerializeToString()) # Valid delegation token. state, ctx = self.call( 'ipv4:127.0.0.1', '*****@*****.**', {'X-Delegation-Token-V1': tok}) self.assertEqual(state, CapturedState( current_identity='user:[email protected]', is_superuser=False, peer_identity='user:[email protected]', peer_ip=ipaddr.ip_from_string('127.0.0.1'), delegation_token=subtoken, )) # Invalid delegation token. state, ctx = self.call( 'ipv4:127.0.0.1', '*****@*****.**', {'X-Delegation-Token-V1': tok + 'blah'}) self.assertIsNone(state) self.assertEqual(ctx.code, prpclib.StatusCode.PERMISSION_DENIED) self.assertEqual( ctx.details, 'Bad delegation token: Bad proto: Truncated message.')
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 = tokens.base64_encode('{"alg":"RS256","typ":"JWT"}') expected_claims = tokens.base64_encode( utils.encode_to_json({ 'aud': 'some audience', 'email': '*****@*****.**', 'exp': 1514772061, # matches NOW+1h 'iat': 1514768461, # matches NOW 'iss': '*****@*****.**', 'sub': '*****@*****.**', })) expected_sig = tokens.base64_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 = tokens.base64_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 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()) # 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 = tokens.base64_encode(tok_pb.SerializeToString()) # 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')
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, tokens.base64_encode(link_msg.SerializeToString())) self.send_response({'url': url}, http_code=201)
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, tokens.base64_encode(link_msg.SerializeToString())) self.send_response({'url': url}, http_code=201)
def test_deserialize_huge(self): msg = fake_token_proto() msg.serialized_subtoken_list = 'huge' * 10000 tok = tokens.base64_encode(msg.SerializeToString()) with self.assertRaises(delegation.BadTokenError): delegation.deserialize_token(tok)
def make_jwt(self, hdr, payload, sig=SIG): return '%s.%s.%s' % (to_json_b64(hdr), to_json_b64(payload), tokens.base64_encode(sig))
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, False)] @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()) # 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 = tokens.base64_encode(tok_pb.SerializeToString()) # 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_bearer_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_base64_encode_types(self): with self.assertRaises(TypeError): tokens.base64_encode(None) with self.assertRaises(TypeError): tokens.base64_encode(u'unicode')
def test_base64_encode_is_url_safe(self): for a in xrange(255): original = chr(a) encoded = tokens.base64_encode(original) self.assertEqual(original, tokens.base64_decode(encoded)) self.assertTrue(URL_SAFE_ALPHABET.issuperset(encoded), encoded)
def test_deserialize_bad_proto(self): tok = tokens.base64_encode('not a proto') with self.assertRaises(delegation.BadTokenError): delegation.deserialize_token(tok)
def serialize_token(tok): return tokens.base64_encode(tok.SerializeToString())
def test_deserialize_huge(self): msg = fake_token_proto() msg.serialized_subtoken = 'huge' * 10000 tok = tokens.base64_encode(msg.SerializeToString()) with self.assertRaises(delegation.BadTokenError): delegation.deserialize_token(tok)
def to_json_b64(d): return tokens.base64_encode(json.dumps(d, sort_keys=True))