Skip to content

Commit

Permalink
feat: Support passing google.auth typed credentials in `initialize_…
Browse files Browse the repository at this point in the history
…app()` (#821)

* feat: Support passing `google.auth` typed credentials in `initialize_app()`

* Refactor and add unit test
  • Loading branch information
jonathanedey authored Nov 4, 2024
1 parent d8d6aea commit 32e8dd2
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 2 deletions.
8 changes: 6 additions & 2 deletions firebase_admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__
Expand Down Expand Up @@ -208,10 +209,13 @@ def __init__(self, name, credential, options):
'non-empty string.'.format(name))
self._name = name

if not isinstance(credential, credentials.Base):
if isinstance(credential, GoogleAuthCredentials):
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 = {}
Expand Down
14 changes: 14 additions & 0 deletions firebase_admin/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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."""
Expand Down
10 changes: 10 additions & 0 deletions tests/test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down

0 comments on commit 32e8dd2

Please sign in to comment.