diff --git a/source/extensions/filters/http/jwt_authn/authenticator.cc b/source/extensions/filters/http/jwt_authn/authenticator.cc index 97293ed616e7c..4dc5ee50e22f2 100644 --- a/source/extensions/filters/http/jwt_authn/authenticator.cc +++ b/source/extensions/filters/http/jwt_authn/authenticator.cc @@ -119,7 +119,9 @@ void AuthenticatorImpl::verify(Http::HeaderMap& headers, Authenticator::Callback const auto unix_timestamp = std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) .count(); - if (jwt_.exp_ < unix_timestamp) { + // NOTE: Service account tokens generally don't have an expiration time (due to being long lived) + // and defaulted to 0 by google::jwt_verify library but are still valid. + if (jwt_.exp_ > 0 && jwt_.exp_ < unix_timestamp) { doneWithStatus(Status::JwtExpired); return; } diff --git a/test/extensions/filters/http/jwt_authn/authenticator_test.cc b/test/extensions/filters/http/jwt_authn/authenticator_test.cc index e2c9b4d75d3ed..db411c32603d6 100644 --- a/test/extensions/filters/http/jwt_authn/authenticator_test.cc +++ b/test/extensions/filters/http/jwt_authn/authenticator_test.cc @@ -164,6 +164,19 @@ TEST_F(AuthenticatorTest, TestInvalidPrefix) { auth_->verify(headers, &mock_cb_); } +// This test verifies when a JWT is non-expiring without audience specified, JwtAudienceNotAllowed +// is returned. +TEST_F(AuthenticatorTest, TestNonExpiringJWT) { + EXPECT_CALL(mock_factory_ctx_.cluster_manager_, httpAsyncClientForCluster(_)).Times(0); + EXPECT_CALL(mock_cb_, onComplete(_)).WillOnce(Invoke([](const Status& status) { + ASSERT_EQ(status, Status::JwtAudienceNotAllowed); + })); + + auto headers = + Http::TestHeaderMapImpl{{"Authorization", "Bearer " + std::string(NonExpiringToken)}}; + auth_->verify(headers, &mock_cb_); +} + // This test verifies when a JWT is expired, JwtExpired status is returned. TEST_F(AuthenticatorTest, TestExpiredJWT) { EXPECT_CALL(mock_factory_ctx_.cluster_manager_, httpAsyncClientForCluster(_)).Times(0); diff --git a/test/extensions/filters/http/jwt_authn/test_common.h b/test/extensions/filters/http/jwt_authn/test_common.h index 86befa921b2ac..3568d4ef68d6f 100644 --- a/test/extensions/filters/http/jwt_authn/test_common.h +++ b/test/extensions/filters/http/jwt_authn/test_common.h @@ -63,6 +63,17 @@ const char GoodToken[] = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwc "EprqSZUzi_ZzzYzqBNVhIJujcNWij7JRra2sXXiSAfKjtxHQoxrX8n4V1ySWJ3_1T" "H_cJcdfS_RKP7YgXRWC0L16PNF5K7iqRqmjKALNe83ZFnFIw"; +// Payload: +// {"iss":"https://example.com","sub":"test@example.com","exp":null} +const char NonExpiringToken[] = + "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUu" + "Y29tIiwic3ViIjoidGVzdEBleGFtcGxlLmNvbSIsImlhdCI6MTUzMzE3NTk0Mn0.OSh-" + "AcY9dCUibXiIZzPlTdEsYH8xP3QkCJDesO3LVu4ndgTrxDnNuR3I4_oV4tjtirmLZD3sx" + "96wmLiIhOyqj3nipIdf_aQWcmET0XoRqGixOKse5FlHyU_VC1Jj9AlMvSz9zyCvKxMyP0" + "CeA-bhI_Qs-I9vBPK8pd-EUOespUqWMQwNdtrOdXLcvF8EA5BV5G2qRGzCU0QJaW0Dpyj" + "YF7ZCswRGorc2oMt5duXSp3-L1b9dDrnLwroxUrmQIZz9qvfwdDR-guyYSjKVQu5NJAyy" + "sd8XKNzmHqJ2fYhRjc5s7l5nIWTDyBXSdPKQ8cBnfFKoxaRhmMBjdEn9RB7r6A"; + // An expired token // {"iss":"https://example.com","sub":"test@example.com","aud":"example_service","exp":1205005587} const char ExpiredToken[] = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUu"