blob: 9d6d363fdbc8921134554cd2a565a7add944efa1 [file] [log] [blame]
Jon Wayne Parrott85c2c6d2017-01-05 12:34:49 -08001# Copyright 2016 Google Inc. All Rights Reserved.
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"""Helpers for authentication using oauth2client or google-auth."""
16
Jon Wayne Parrottd3a5cf42017-06-19 17:55:04 -070017import httplib2
18
Jon Wayne Parrott85c2c6d2017-01-05 12:34:49 -080019try:
20 import google.auth
Wilson Lian09527302017-01-11 14:38:18 -080021 import google.auth.credentials
Jon Wayne Parrott85c2c6d2017-01-05 12:34:49 -080022 HAS_GOOGLE_AUTH = True
23except ImportError: # pragma: NO COVER
24 HAS_GOOGLE_AUTH = False
25
26try:
Jon Wayne Parrott401e8862017-09-19 18:36:35 -070027 import google_auth_httplib2
28except ImportError: # pragma: NO COVER
29 google_auth_httplib2 = None
30
31try:
Jon Wayne Parrott85c2c6d2017-01-05 12:34:49 -080032 import oauth2client
33 import oauth2client.client
34 HAS_OAUTH2CLIENT = True
35except ImportError: # pragma: NO COVER
36 HAS_OAUTH2CLIENT = False
37
38
39def default_credentials():
40 """Returns Application Default Credentials."""
41 if HAS_GOOGLE_AUTH:
42 credentials, _ = google.auth.default()
43 return credentials
44 elif HAS_OAUTH2CLIENT:
45 return oauth2client.client.GoogleCredentials.get_application_default()
46 else:
47 raise EnvironmentError(
48 'No authentication library is available. Please install either '
49 'google-auth or oauth2client.')
50
51
52def with_scopes(credentials, scopes):
53 """Scopes the credentials if necessary.
54
55 Args:
56 credentials (Union[
57 google.auth.credentials.Credentials,
58 oauth2client.client.Credentials]): The credentials to scope.
59 scopes (Sequence[str]): The list of scopes.
60
61 Returns:
62 Union[google.auth.credentials.Credentials,
63 oauth2client.client.Credentials]: The scoped credentials.
64 """
65 if HAS_GOOGLE_AUTH and isinstance(
66 credentials, google.auth.credentials.Credentials):
67 return google.auth.credentials.with_scopes_if_required(
68 credentials, scopes)
69 else:
70 try:
71 if credentials.create_scoped_required():
72 return credentials.create_scoped(scopes)
73 else:
74 return credentials
75 except AttributeError:
76 return credentials
77
78
79def authorized_http(credentials):
80 """Returns an http client that is authorized with the given credentials.
81
82 Args:
83 credentials (Union[
84 google.auth.credentials.Credentials,
85 oauth2client.client.Credentials]): The credentials to use.
86
87 Returns:
88 Union[httplib2.Http, google_auth_httplib2.AuthorizedHttp]: An
89 authorized http client.
90 """
Jon Wayne Parrottd3a5cf42017-06-19 17:55:04 -070091 from googleapiclient.http import build_http
92
Jon Wayne Parrott85c2c6d2017-01-05 12:34:49 -080093 if HAS_GOOGLE_AUTH and isinstance(
94 credentials, google.auth.credentials.Credentials):
Jon Wayne Parrott401e8862017-09-19 18:36:35 -070095 if google_auth_httplib2 is None:
96 raise ValueError(
97 'Credentials from google.auth specified, but '
98 'google-api-python-client is unable to use these credentials '
99 'unless google-auth-httplib2 is installed. Please install '
100 'google-auth-httplib2.')
Igor Maravić22435292017-01-19 22:28:22 +0100101 return google_auth_httplib2.AuthorizedHttp(credentials,
102 http=build_http())
Jon Wayne Parrott85c2c6d2017-01-05 12:34:49 -0800103 else:
Igor Maravić22435292017-01-19 22:28:22 +0100104 return credentials.authorize(build_http())
Jon Wayne Parrottd3a5cf42017-06-19 17:55:04 -0700105
106
107def refresh_credentials(credentials):
108 # Refresh must use a new http instance, as the one associated with the
109 # credentials could be a AuthorizedHttp or an oauth2client-decorated
110 # Http instance which would cause a weird recursive loop of refreshing
111 # and likely tear a hole in spacetime.
112 refresh_http = httplib2.Http()
113 if HAS_GOOGLE_AUTH and isinstance(
114 credentials, google.auth.credentials.Credentials):
115 request = google_auth_httplib2.Request(refresh_http)
116 return credentials.refresh(request)
117 else:
118 return credentials.refresh(refresh_http)
119
120
121def apply_credentials(credentials, headers):
122 # oauth2client and google-auth have the same interface for this.
Jon Wayne Parrott20e61352018-01-18 09:16:37 -0800123 if not is_valid(credentials):
124 refresh_credentials(credentials)
Jon Wayne Parrottd3a5cf42017-06-19 17:55:04 -0700125 return credentials.apply(headers)
126
127
128def is_valid(credentials):
129 if HAS_GOOGLE_AUTH and isinstance(
130 credentials, google.auth.credentials.Credentials):
131 return credentials.valid
132 else:
Jon Wayne Parrott20e61352018-01-18 09:16:37 -0800133 return (
134 credentials.access_token is not None and
135 not credentials.access_token_expired)
Jon Wayne Parrottd3a5cf42017-06-19 17:55:04 -0700136
137
138def get_credentials_from_http(http):
139 if http is None:
140 return None
141 elif hasattr(http.request, 'credentials'):
142 return http.request.credentials
Jon Wayne Parrott3fb2a382017-08-02 13:04:30 -0700143 elif (hasattr(http, 'credentials')
144 and not isinstance(http.credentials, httplib2.Credentials)):
Jon Wayne Parrottd3a5cf42017-06-19 17:55:04 -0700145 return http.credentials
146 else:
147 return None