• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2016 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"""GRPCAuthMetadataPlugins for standard authentication."""
15
16import inspect
17from concurrent import futures
18
19import grpc
20
21
22def _sign_request(callback, token, error):
23    metadata = (('authorization', 'Bearer {}'.format(token)),)
24    callback(metadata, error)
25
26
27def _create_get_token_callback(callback):
28
29    def get_token_callback(future):
30        try:
31            access_token = future.result().access_token
32        except Exception as exception:  # pylint: disable=broad-except
33            _sign_request(callback, None, exception)
34        else:
35            _sign_request(callback, access_token, None)
36
37    return get_token_callback
38
39
40class GoogleCallCredentials(grpc.AuthMetadataPlugin):
41    """Metadata wrapper for GoogleCredentials from the oauth2client library."""
42
43    def __init__(self, credentials):
44        self._credentials = credentials
45        self._pool = futures.ThreadPoolExecutor(max_workers=1)
46
47        # Hack to determine if these are JWT creds and we need to pass
48        # additional_claims when getting a token
49        self._is_jwt = 'additional_claims' in inspect.getargspec(
50            credentials.get_access_token).args
51
52    def __call__(self, context, callback):
53        # MetadataPlugins cannot block (see grpc.beta.interfaces.py)
54        if self._is_jwt:
55            future = self._pool.submit(
56                self._credentials.get_access_token,
57                additional_claims={
58                    'aud': context.service_url
59                })
60        else:
61            future = self._pool.submit(self._credentials.get_access_token)
62        future.add_done_callback(_create_get_token_callback(callback))
63
64    def __del__(self):
65        self._pool.shutdown(wait=False)
66
67
68class AccessTokenAuthMetadataPlugin(grpc.AuthMetadataPlugin):
69    """Metadata wrapper for raw access token credentials."""
70
71    def __init__(self, access_token):
72        self._access_token = access_token
73
74    def __call__(self, context, callback):
75        _sign_request(callback, self._access_token, None)
76