Skip to content

Commit

Permalink
feat: Add public API load_credentials_from_dict to allow creating a d…
Browse files Browse the repository at this point in the history
…efault credential object from a dictionary.

This resolves googleapis#1313.
  • Loading branch information
clundin25 committed Jun 7, 2023
1 parent bcb85bf commit a3b073b
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 2 deletions.
4 changes: 2 additions & 2 deletions google/auth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
import logging

from google.auth import version as google_auth_version
from google.auth._default import default, load_credentials_from_file
from google.auth._default import default, load_credentials_from_file, load_credentials_from_dict


__version__ = google_auth_version.__version__


__all__ = ["default", "load_credentials_from_file"]
__all__ = ["default", "load_credentials_from_file", "load_credentials_from_dict"]

# Set default logging handler to avoid "No handler found" warnings.
logging.getLogger(__name__).addHandler(logging.NullHandler())
44 changes: 44 additions & 0 deletions google/auth/_default.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,50 @@ def load_credentials_from_file(
)


def load_credentials_from_dict(
info, scopes=None, default_scopes=None, quota_project_id=None, request=None
):
"""Loads Google credentials from a dict.
The credentials file must be a service account key, stored authorized
user credentials, external account credentials, or impersonated service
account credentials.
Args:
info (Dict[str, Any]): A dict object containing the credentials
scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
specified, the credentials will automatically be scoped if
necessary
default_scopes (Optional[Sequence[str]]): Default scopes passed by a
Google client library. Use 'scopes' for user-defined scopes.
quota_project_id (Optional[str]): The project ID used for
quota and billing.
request (Optional[google.auth.transport.Request]): An object used to make
HTTP requests. This is used to determine the associated project ID
for a workload identity pool resource (external account credentials).
If not specified, then it will use a
google.auth.transport.requests.Request client to make requests.
Returns:
Tuple[google.auth.credentials.Credentials, Optional[str]]: Loaded
credentials and the project ID. Authorized user credentials do not
have the project ID information. External account credentials project
IDs may not always be determined.
Raises:
google.auth.exceptions.DefaultCredentialsError: if the file is in the
wrong format or is missing.
"""
if not isinstance(info, dict):
raise exceptions.DefaultCredentialsError(
"info object was of type {} but dict type was expected.".format(type(info))
)

return _load_credentials_from_info(
"dict object", info, scopes, default_scopes, quota_project_id, request
)


def _load_credentials_from_info(
filename, info, scopes, default_scopes, quota_project_id, request
):
Expand Down
14 changes: 14 additions & 0 deletions tests/test__default.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,20 @@ def test_load_credentials_from_missing_file():
assert excinfo.match(r"not found")


def test_load_credentials_from_dict_non_dict_object():
with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
_default.load_credentials_from_dict("")
assert excinfo.match(r"dict type was expected")

with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
_default.load_credentials_from_dict(None)
assert excinfo.match(r"dict type was expected")

with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
_default.load_credentials_from_dict(1)
assert excinfo.match(r"dict type was expected")


def test_load_credentials_from_file_invalid_json(tmpdir):
jsonfile = tmpdir.join("invalid.json")
jsonfile.write("{")
Expand Down

0 comments on commit a3b073b

Please sign in to comment.