Skip to content

Commit 939375c

Browse files
authored
fix: Using alg=none header for custom tokens in emulator mode (#541)
* fix(auth): Using alg=none header for custom tokens in emulator mode * fix: Dropping google-auth explicit dependency; Temp test skip for Py 3.5 * chore: Removed py35 hack
1 parent 44ae038 commit 939375c

File tree

2 files changed

+19
-6
lines changed

2 files changed

+19
-6
lines changed

firebase_admin/_token_gen.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
])
5454
METADATA_SERVICE_URL = ('http://metadata.google.internal/computeMetadata/v1/instance/'
5555
'service-accounts/default/email')
56+
ALGORITHM_RS256 = 'RS256'
57+
ALGORITHM_NONE = 'none'
5658

5759
# Emulator fake account
5860
AUTH_EMULATOR_EMAIL = '[email protected]'
@@ -71,9 +73,10 @@ def sign(self, message):
7173
class _SigningProvider:
7274
"""Stores a reference to a google.auth.crypto.Signer."""
7375

74-
def __init__(self, signer, signer_email):
76+
def __init__(self, signer, signer_email, alg=ALGORITHM_RS256):
7577
self._signer = signer
7678
self._signer_email = signer_email
79+
self._alg = alg
7780

7881
@property
7982
def signer(self):
@@ -83,6 +86,10 @@ def signer(self):
8386
def signer_email(self):
8487
return self._signer_email
8588

89+
@property
90+
def alg(self):
91+
return self._alg
92+
8693
@classmethod
8794
def from_credential(cls, google_cred):
8895
return _SigningProvider(google_cred.signer, google_cred.signer_email)
@@ -94,7 +101,7 @@ def from_iam(cls, request, google_cred, service_account):
94101

95102
@classmethod
96103
def for_emulator(cls):
97-
return _SigningProvider(_EmulatedSigner(), AUTH_EMULATOR_EMAIL)
104+
return _SigningProvider(_EmulatedSigner(), AUTH_EMULATOR_EMAIL, ALGORITHM_NONE)
98105

99106

100107
class TokenGenerator:
@@ -190,8 +197,10 @@ def create_custom_token(self, uid, developer_claims=None, tenant_id=None):
190197

191198
if developer_claims is not None:
192199
payload['claims'] = developer_claims
200+
201+
header = {'alg': signing_provider.alg}
193202
try:
194-
return jwt.encode(signing_provider.signer, payload)
203+
return jwt.encode(signing_provider.signer, payload, header=header)
195204
except google.auth.exceptions.TransportError as error:
196205
msg = 'Failed to sign custom token. {0}'.format(error)
197206
raise TokenSignError(msg, error)

tests/test_token_gen.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,17 +75,24 @@ def _merge_jwt_claims(defaults, overrides):
7575
del defaults[key]
7676
return defaults
7777

78+
7879
def verify_custom_token(custom_token, expected_claims, tenant_id=None):
7980
assert isinstance(custom_token, bytes)
8081
expected_email = MOCK_SERVICE_ACCOUNT_EMAIL
82+
header = jwt.decode_header(custom_token)
83+
assert header.get('typ') == 'JWT'
8184
if _is_emulated():
85+
assert header.get('alg') == 'none'
86+
assert custom_token.split(b'.')[2] == b''
8287
expected_email = _token_gen.AUTH_EMULATOR_EMAIL
8388
token = jwt.decode(custom_token, verify=False)
8489
else:
90+
assert header.get('alg') == 'RS256'
8591
token = google.oauth2.id_token.verify_token(
8692
custom_token,
8793
testutils.MockRequest(200, MOCK_PUBLIC_CERTS),
8894
_token_gen.FIREBASE_AUDIENCE)
95+
8996
assert token['uid'] == MOCK_UID
9097
assert token['iss'] == expected_email
9198
assert token['sub'] == expected_email
@@ -94,9 +101,6 @@ def verify_custom_token(custom_token, expected_claims, tenant_id=None):
94101
else:
95102
assert token['tenant_id'] == tenant_id
96103

97-
header = jwt.decode_header(custom_token)
98-
assert header.get('typ') == 'JWT'
99-
assert header.get('alg') == 'RS256'
100104
if expected_claims:
101105
for key, value in expected_claims.items():
102106
assert value == token['claims'][key]

0 commit comments

Comments
 (0)