From a96edc85d3ccf67cb539dc55c36b27d38b95572f Mon Sep 17 00:00:00 2001 From: Jonathan Edey Date: Thu, 24 Oct 2024 15:27:55 -0400 Subject: [PATCH 1/2] feat: Support passing `google.auth` typed credentials in `initialize_app()` --- firebase_admin/__init__.py | 3 +++ firebase_admin/credentials.py | 14 ++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/firebase_admin/__init__.py b/firebase_admin/__init__.py index 0ca82ec5e..2a669ccc0 100644 --- a/firebase_admin/__init__.py +++ b/firebase_admin/__init__.py @@ -18,6 +18,7 @@ import os import threading +from google.auth.credentials import Credentials as GoogleAuthCredentials from google.auth.exceptions import DefaultCredentialsError from firebase_admin import credentials from firebase_admin.__about__ import __version__ @@ -208,6 +209,8 @@ def __init__(self, name, credential, options): 'non-empty string.'.format(name)) self._name = name + if isinstance(credential, GoogleAuthCredentials): + credential = credentials._ExternalCredentials(credential) if not isinstance(credential, credentials.Base): raise ValueError('Illegal Firebase credential provided. App must be initialized ' 'with a valid credential instance.') diff --git a/firebase_admin/credentials.py b/firebase_admin/credentials.py index 5477e1cf7..750600280 100644 --- a/firebase_admin/credentials.py +++ b/firebase_admin/credentials.py @@ -18,6 +18,7 @@ import pathlib import google.auth +from google.auth.credentials import Credentials as GoogleAuthCredentials from google.auth.transport import requests from google.oauth2 import credentials from google.oauth2 import service_account @@ -58,6 +59,19 @@ def get_credential(self): """Returns the Google credential instance used for authentication.""" raise NotImplementedError +class _ExternalCredentials(Base): + """A wrapper for google.auth.credentials.Credentials typed credential instances""" + + def __init__(self, credential: GoogleAuthCredentials): + super(_ExternalCredentials, self).__init__() + self._g_credential = credential + + def get_credential(self): + """Returns the underlying Google Credential + + Returns: + google.auth.credentials.Credentials: A Google Auth credential instance.""" + return self._g_credential class Certificate(Base): """A credential initialized from a JSON certificate keyfile.""" From fc8b8d451de53b06edd80649d5bd5d7e9b2cbe3e Mon Sep 17 00:00:00 2001 From: Jonathan Edey Date: Mon, 28 Oct 2024 11:18:38 -0400 Subject: [PATCH 2/2] Refactor and add unit test --- firebase_admin/__init__.py | 7 ++++--- tests/test_app.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/firebase_admin/__init__.py b/firebase_admin/__init__.py index 2a669ccc0..7bb9c59c2 100644 --- a/firebase_admin/__init__.py +++ b/firebase_admin/__init__.py @@ -210,11 +210,12 @@ def __init__(self, name, credential, options): self._name = name if isinstance(credential, GoogleAuthCredentials): - credential = credentials._ExternalCredentials(credential) - if not isinstance(credential, credentials.Base): + self._credential = credentials._ExternalCredentials(credential) # pylint: disable=protected-access + elif isinstance(credential, credentials.Base): + self._credential = credential + else: raise ValueError('Illegal Firebase credential provided. App must be initialized ' 'with a valid credential instance.') - self._credential = credential self._options = _AppOptions(options) self._lock = threading.RLock() self._services = {} diff --git a/tests/test_app.py b/tests/test_app.py index 4233d5849..5b203661f 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -246,6 +246,16 @@ def test_non_default_app_init(self, app_credential): with pytest.raises(ValueError): firebase_admin.initialize_app(app_credential, name='myApp') + def test_app_init_with_google_auth_cred(self): + cred = testutils.MockGoogleCredential() + assert isinstance(cred, credentials.GoogleAuthCredentials) + app = firebase_admin.initialize_app(cred) + assert cred is app.credential.get_credential() + assert isinstance(app.credential, credentials.Base) + assert isinstance(app.credential, credentials._ExternalCredentials) + with pytest.raises(ValueError): + firebase_admin.initialize_app(app_credential) + @pytest.mark.parametrize('cred', invalid_credentials) def test_app_init_with_invalid_credential(self, cred): with pytest.raises(ValueError):