1# Copyright 2019 The gRPC Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14"""Client of the Python example of customizing authentication mechanism.""" 15 16from __future__ import absolute_import 17from __future__ import division 18from __future__ import print_function 19 20import argparse 21import contextlib 22import logging 23 24import grpc 25from examples import helloworld_pb2 26from examples import helloworld_pb2_grpc 27from examples.python.auth import _credentials 28 29_LOGGER = logging.getLogger(__name__) 30_LOGGER.setLevel(logging.INFO) 31 32_SERVER_ADDR_TEMPLATE = 'localhost:%d' 33_SIGNATURE_HEADER_KEY = 'x-signature' 34 35 36class AuthGateway(grpc.AuthMetadataPlugin): 37 38 def __call__(self, context, callback): 39 """Implements authentication by passing metadata to a callback. 40 41 Implementations of this method must not block. 42 43 Args: 44 context: An AuthMetadataContext providing information on the RPC that 45 the plugin is being called to authenticate. 46 callback: An AuthMetadataPluginCallback to be invoked either 47 synchronously or asynchronously. 48 """ 49 # Example AuthMetadataContext object: 50 # AuthMetadataContext( 51 # service_url=u'https://localhost:50051/helloworld.Greeter', 52 # method_name=u'SayHello') 53 signature = context.method_name[::-1] 54 callback(((_SIGNATURE_HEADER_KEY, signature),), None) 55 56 57@contextlib.contextmanager 58def create_client_channel(addr): 59 # Call credential object will be invoked for every single RPC 60 call_credentials = grpc.metadata_call_credentials(AuthGateway(), 61 name='auth gateway') 62 # Channel credential will be valid for the entire channel 63 channel_credential = grpc.ssl_channel_credentials( 64 _credentials.ROOT_CERTIFICATE) 65 # Combining channel credentials and call credentials together 66 composite_credentials = grpc.composite_channel_credentials( 67 channel_credential, 68 call_credentials, 69 ) 70 channel = grpc.secure_channel(addr, composite_credentials) 71 yield channel 72 73 74def send_rpc(channel): 75 stub = helloworld_pb2_grpc.GreeterStub(channel) 76 request = helloworld_pb2.HelloRequest(name='you') 77 try: 78 response = stub.SayHello(request) 79 except grpc.RpcError as rpc_error: 80 _LOGGER.error('Received error: %s', rpc_error) 81 return rpc_error 82 else: 83 _LOGGER.info('Received message: %s', response) 84 return response 85 86 87def main(): 88 parser = argparse.ArgumentParser() 89 parser.add_argument('--port', 90 nargs='?', 91 type=int, 92 default=50051, 93 help='the address of server') 94 args = parser.parse_args() 95 96 with create_client_channel(_SERVER_ADDR_TEMPLATE % args.port) as channel: 97 send_rpc(channel) 98 99 100if __name__ == '__main__': 101 logging.basicConfig(level=logging.INFO) 102 main() 103