1# Copyright 2020 Google LLC
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
15
16"""Interfaces for credentials."""
17
18import abc
19import inspect
20
21import six
22
23from google.auth import credentials
24
25
26@six.add_metaclass(abc.ABCMeta)
27class Credentials(credentials.Credentials):
28    """Async inherited credentials class from google.auth.credentials.
29    The added functionality is the before_request call which requires
30    async/await syntax.
31    All credentials have a :attr:`token` that is used for authentication and
32    may also optionally set an :attr:`expiry` to indicate when the token will
33    no longer be valid.
34
35    Most credentials will be :attr:`invalid` until :meth:`refresh` is called.
36    Credentials can do this automatically before the first HTTP request in
37    :meth:`before_request`.
38
39    Although the token and expiration will change as the credentials are
40    :meth:`refreshed <refresh>` and used, credentials should be considered
41    immutable. Various credentials will accept configuration such as private
42    keys, scopes, and other options. These options are not changeable after
43    construction. Some classes will provide mechanisms to copy the credentials
44    with modifications such as :meth:`ScopedCredentials.with_scopes`.
45    """
46
47    async def before_request(self, request, method, url, headers):
48        """Performs credential-specific before request logic.
49
50        Refreshes the credentials if necessary, then calls :meth:`apply` to
51        apply the token to the authentication header.
52
53        Args:
54            request (google.auth.transport.Request): The object used to make
55                HTTP requests.
56            method (str): The request's HTTP method or the RPC method being
57                invoked.
58            url (str): The request's URI or the RPC service's URI.
59            headers (Mapping): The request's headers.
60        """
61        # pylint: disable=unused-argument
62        # (Subclasses may use these arguments to ascertain information about
63        # the http request.)
64
65        if not self.valid:
66            if inspect.iscoroutinefunction(self.refresh):
67                await self.refresh(request)
68            else:
69                self.refresh(request)
70        self.apply(headers)
71
72
73class CredentialsWithQuotaProject(credentials.CredentialsWithQuotaProject):
74    """Abstract base for credentials supporting ``with_quota_project`` factory"""
75
76
77class AnonymousCredentials(credentials.AnonymousCredentials, Credentials):
78    """Credentials that do not provide any authentication information.
79
80    These are useful in the case of services that support anonymous access or
81    local service emulators that do not use credentials. This class inherits
82    from the sync anonymous credentials file, but is kept if async credentials
83    is initialized and we would like anonymous credentials.
84    """
85
86
87@six.add_metaclass(abc.ABCMeta)
88class ReadOnlyScoped(credentials.ReadOnlyScoped):
89    """Interface for credentials whose scopes can be queried.
90
91    OAuth 2.0-based credentials allow limiting access using scopes as described
92    in `RFC6749 Section 3.3`_.
93    If a credential class implements this interface then the credentials either
94    use scopes in their implementation.
95
96    Some credentials require scopes in order to obtain a token. You can check
97    if scoping is necessary with :attr:`requires_scopes`::
98
99        if credentials.requires_scopes:
100            # Scoping is required.
101            credentials = _credentials_async.with_scopes(scopes=['one', 'two'])
102
103    Credentials that require scopes must either be constructed with scopes::
104
105        credentials = SomeScopedCredentials(scopes=['one', 'two'])
106
107    Or must copy an existing instance using :meth:`with_scopes`::
108
109        scoped_credentials = _credentials_async.with_scopes(scopes=['one', 'two'])
110
111    Some credentials have scopes but do not allow or require scopes to be set,
112    these credentials can be used as-is.
113
114    .. _RFC6749 Section 3.3: https://tools.ietf.org/html/rfc6749#section-3.3
115    """
116
117
118class Scoped(credentials.Scoped):
119    """Interface for credentials whose scopes can be replaced while copying.
120
121    OAuth 2.0-based credentials allow limiting access using scopes as described
122    in `RFC6749 Section 3.3`_.
123    If a credential class implements this interface then the credentials either
124    use scopes in their implementation.
125
126    Some credentials require scopes in order to obtain a token. You can check
127    if scoping is necessary with :attr:`requires_scopes`::
128
129        if credentials.requires_scopes:
130            # Scoping is required.
131            credentials = _credentials_async.create_scoped(['one', 'two'])
132
133    Credentials that require scopes must either be constructed with scopes::
134
135        credentials = SomeScopedCredentials(scopes=['one', 'two'])
136
137    Or must copy an existing instance using :meth:`with_scopes`::
138
139        scoped_credentials = credentials.with_scopes(scopes=['one', 'two'])
140
141    Some credentials have scopes but do not allow or require scopes to be set,
142    these credentials can be used as-is.
143
144    .. _RFC6749 Section 3.3: https://tools.ietf.org/html/rfc6749#section-3.3
145    """
146
147
148def with_scopes_if_required(credentials, scopes):
149    """Creates a copy of the credentials with scopes if scoping is required.
150
151    This helper function is useful when you do not know (or care to know) the
152    specific type of credentials you are using (such as when you use
153    :func:`google.auth.default`). This function will call
154    :meth:`Scoped.with_scopes` if the credentials are scoped credentials and if
155    the credentials require scoping. Otherwise, it will return the credentials
156    as-is.
157
158    Args:
159        credentials (google.auth.credentials.Credentials): The credentials to
160            scope if necessary.
161        scopes (Sequence[str]): The list of scopes to use.
162
163    Returns:
164        google.auth._credentials_async.Credentials: Either a new set of scoped
165            credentials, or the passed in credentials instance if no scoping
166            was required.
167    """
168    if isinstance(credentials, Scoped) and credentials.requires_scopes:
169        return credentials.with_scopes(scopes)
170    else:
171        return credentials
172
173
174@six.add_metaclass(abc.ABCMeta)
175class Signing(credentials.Signing):
176    """Interface for credentials that can cryptographically sign messages."""
177