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 """OAuth 2.0 Async Credentials.
16 
17 This module provides credentials based on OAuth 2.0 access and refresh tokens.
18 These credentials usually access resources on behalf of a user (resource
19 owner).
20 
21 Specifically, this is intended to use access tokens acquired using the
22 `Authorization Code grant`_ and can refresh those tokens using a
23 optional `refresh token`_.
24 
25 Obtaining the initial access and refresh token is outside of the scope of this
26 module. Consult `rfc6749 section 4.1`_ for complete details on the
27 Authorization Code grant flow.
28 
29 .. _Authorization Code grant: https://tools.ietf.org/html/rfc6749#section-1.3.1
30 .. _refresh token: https://tools.ietf.org/html/rfc6749#section-6
31 .. _rfc6749 section 4.1: https://tools.ietf.org/html/rfc6749#section-4.1
32 """
33 
34 from google.auth import _credentials_async as credentials
35 from google.auth import _helpers
36 from google.auth import exceptions
37 from google.oauth2 import _reauth_async as reauth
38 from google.oauth2 import credentials as oauth2_credentials
39 
40 
41 class Credentials(oauth2_credentials.Credentials):
42     """Credentials using OAuth 2.0 access and refresh tokens.
43 
44     The credentials are considered immutable. If you want to modify the
45     quota project, use :meth:`with_quota_project` or ::
46 
47         credentials = credentials.with_quota_project('myproject-123)
48     """
49 
50     @_helpers.copy_docstring(credentials.Credentials)
51     async def refresh(self, request):
52         if (
53             self._refresh_token is None
54             or self._token_uri is None
55             or self._client_id is None
56             or self._client_secret is None
57         ):
58             raise exceptions.RefreshError(
59                 "The credentials do not contain the necessary fields need to "
60                 "refresh the access token. You must specify refresh_token, "
61                 "token_uri, client_id, and client_secret."
62             )
63 
64         (
65             access_token,
66             refresh_token,
67             expiry,
68             grant_response,
69             rapt_token,
70         ) = await reauth.refresh_grant(
71             request,
72             self._token_uri,
73             self._refresh_token,
74             self._client_id,
75             self._client_secret,
76             scopes=self._scopes,
77             rapt_token=self._rapt_token,
78             enable_reauth_refresh=self._enable_reauth_refresh,
79         )
80 
81         self.token = access_token
82         self.expiry = expiry
83         self._refresh_token = refresh_token
84         self._id_token = grant_response.get("id_token")
85         self._rapt_token = rapt_token
86 
87         if self._scopes and "scope" in grant_response:
88             requested_scopes = frozenset(self._scopes)
89             granted_scopes = frozenset(grant_response["scope"].split())
90             scopes_requested_but_not_granted = requested_scopes - granted_scopes
91             if scopes_requested_but_not_granted:
92                 raise exceptions.RefreshError(
93                     "Not all requested scopes were granted by the "
94                     "authorization server, missing scopes {}.".format(
95                         ", ".join(scopes_requested_but_not_granted)
96                     )
97                 )
98 
99 
100 class UserAccessTokenCredentials(oauth2_credentials.UserAccessTokenCredentials):
101     """Access token credentials for user account.
102 
103     Obtain the access token for a given user account or the current active
104     user account with the ``gcloud auth print-access-token`` command.
105 
106     Args:
107         account (Optional[str]): Account to get the access token for. If not
108             specified, the current active account will be used.
109         quota_project_id (Optional[str]): The project ID used for quota
110             and billing.
111 
112     """
113