Skip to content

Commit 4969580

Browse files
author
Jon Wayne Parrott
authored
Implement application default credentials (#32)
1 parent 6e7f0d9 commit 4969580

File tree

10 files changed

+863
-0
lines changed

10 files changed

+863
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
google.auth.environment_vars module
2+
===================================
3+
4+
.. automodule:: google.auth.environment_vars
5+
:members:
6+
:inherited-members:
7+
:show-inheritance:

packages/google-auth/docs/reference/google.auth.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Submodules
2121

2222
google.auth.credentials
2323
google.auth.crypt
24+
google.auth.environment_vars
2425
google.auth.exceptions
2526
google.auth.jwt
2627

packages/google-auth/google/auth/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@
1616

1717
import logging
1818

19+
from google.auth._default import default
20+
21+
22+
__all__ = [
23+
'default',
24+
]
25+
1926

2027
# Set default logging handler to avoid "No handler found" warnings.
2128
logging.getLogger(__name__).addHandler(logging.NullHandler())
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
# Copyright 2015 Google Inc.
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 reading the Google Cloud SDK's configuration."""
16+
17+
import os
18+
19+
import six
20+
from six.moves import configparser
21+
22+
from google.auth import environment_vars
23+
import google.oauth2.credentials
24+
25+
# The Google OAuth 2.0 token endpoint. Used for authorized user credentials.
26+
_GOOGLE_OAUTH2_TOKEN_ENDPOINT = 'https://accounts.google.com/o/oauth2/token'
27+
28+
# The ~/.config subdirectory containing gcloud credentials.
29+
_CONFIG_DIRECTORY = 'gcloud'
30+
# Windows systems store config at %APPDATA%\gcloud
31+
_WINDOWS_CONFIG_ROOT_ENV_VAR = 'APPDATA'
32+
# The name of the file in the Cloud SDK config that contains default
33+
# credentials.
34+
_CREDENTIALS_FILENAME = 'application_default_credentials.json'
35+
# The name of the file in the Cloud SDK config that contains the
36+
# active configuration.
37+
_ACTIVE_CONFIG_FILENAME = os.path.join(
38+
'configurations', 'config_default')
39+
# The config section and key for the project ID in the cloud SDK config.
40+
_PROJECT_CONFIG_SECTION = 'core'
41+
_PROJECT_CONFIG_KEY = 'project'
42+
43+
44+
def get_config_path():
45+
"""Returns the absolute path the the Cloud SDK's configuration directory.
46+
47+
Returns:
48+
str: The Cloud SDK config path.
49+
"""
50+
# If the path is explicitly set, return that.
51+
try:
52+
return os.environ[environment_vars.CLOUD_SDK_CONFIG_DIR]
53+
except KeyError:
54+
pass
55+
56+
# Non-windows systems store this at ~/.config/gcloud
57+
if os.name != 'nt':
58+
return os.path.join(
59+
os.path.expanduser('~'), '.config', _CONFIG_DIRECTORY)
60+
# Windows systems store config at %APPDATA%\gcloud
61+
else:
62+
try:
63+
return os.path.join(
64+
os.environ[_WINDOWS_CONFIG_ROOT_ENV_VAR],
65+
_CONFIG_DIRECTORY)
66+
except KeyError:
67+
# This should never happen unless someone is really
68+
# messing with things, but we'll cover the case anyway.
69+
drive = os.environ.get('SystemDrive', 'C:')
70+
return os.path.join(
71+
drive, '\\', _CONFIG_DIRECTORY)
72+
73+
74+
def get_application_default_credentials_path():
75+
"""Gets the path to the application default credentials file.
76+
77+
The path may or may not exist.
78+
79+
Returns:
80+
str: The full path to application default credentials.
81+
"""
82+
config_path = get_config_path()
83+
return os.path.join(config_path, _CREDENTIALS_FILENAME)
84+
85+
86+
def get_project_id():
87+
"""Gets the project ID from the Cloud SDK's configuration.
88+
89+
Returns:
90+
Optional[str]: The project ID.
91+
"""
92+
config_path = get_config_path()
93+
config_file = os.path.join(config_path, _ACTIVE_CONFIG_FILENAME)
94+
95+
if not os.path.isfile(config_file):
96+
return None
97+
98+
config = configparser.RawConfigParser()
99+
100+
try:
101+
config.read(config_file)
102+
except configparser.Error:
103+
return None
104+
105+
if config.has_section(_PROJECT_CONFIG_SECTION):
106+
return config.get(
107+
_PROJECT_CONFIG_SECTION, _PROJECT_CONFIG_KEY)
108+
109+
110+
def load_authorized_user_credentials(info):
111+
"""Loads an authorized user credential.
112+
113+
Args:
114+
info (Mapping[str, str]): The loaded file's data.
115+
116+
Returns:
117+
google.oauth2.credentials.Credentials: The constructed credentials.
118+
119+
Raises:
120+
ValueError: if the info is in the wrong format or missing data.
121+
"""
122+
keys_needed = set(('refresh_token', 'client_id', 'client_secret'))
123+
missing = keys_needed.difference(six.iterkeys(info))
124+
125+
if missing:
126+
raise ValueError(
127+
'Authorized user info was not in the expected format, missing '
128+
'fields {}.'.format(', '.join(missing)))
129+
130+
return google.oauth2.credentials.Credentials(
131+
None, # No access token, must be refreshed.
132+
refresh_token=info['refresh_token'],
133+
token_uri=_GOOGLE_OAUTH2_TOKEN_ENDPOINT,
134+
client_id=info['client_id'],
135+
client_secret=info['client_secret'])

0 commit comments

Comments
 (0)