diff --git a/api/envoy/config/filter/http/jwt_authn/v2alpha/config.proto b/api/envoy/config/filter/http/jwt_authn/v2alpha/config.proto index adab17168ddb8..d58e960c37f68 100644 --- a/api/envoy/config/filter/http/jwt_authn/v2alpha/config.proto +++ b/api/envoy/config/filter/http/jwt_authn/v2alpha/config.proto @@ -7,6 +7,7 @@ import "envoy/api/v2/core/base.proto"; import "envoy/api/v2/core/http_uri.proto"; import "envoy/api/v2/route/route.proto"; import "google/protobuf/duration.proto"; +import "google/protobuf/wrappers.proto"; import "validate/validate.proto"; // This message specifies how a JSON Web Token (JWT) can be verified. JWT format is defined @@ -30,7 +31,7 @@ import "validate/validate.proto"; // - seconds: 300 // // [#not-implemented-hide:] -message JwtRule { +message JwtProvider { // Identifies the principal that issued the JWT. See `here // `_. Usually a URL or an email address. // @@ -183,44 +184,219 @@ message JwtHeader { string value_prefix = 2; } -// This is the Envoy HTTP filter config for JWT authentication. -// [#not-implemented-hide:] -message JwtAuthentication { - // List of JWT rules to valide. - repeated JwtRule rules = 1; +// Specify a required provider with audiences. +message ProviderWithAudiences { + // Specify a required provider name. + string provider_name = 1; + + // This field overrides the one specified in the JwtProvider. + repeated string audiences = 2; +} + +// This message specifies a Jwt requirement. An empty message means JWT verification is not +// required. Here are some config examples: +// +// .. code-block:: yaml +// +// # Example 1: not required with an empty message +// +// # Example 2: require A +// provider_name: "provider-A" +// +// # Example 3: require A or B +// requires_any: +// requirements: +// - provider_name: "provider-A" +// - provider_name: "provider-B" +// +// # Example 4: require A and B +// requires_all: +// requirements: +// - provider_name: "provider-A" +// - provider_name: "provider-B" +// +// # Example 5: require A and (B or C) +// requires_all: +// requirements: +// - provider_name: "provider-A" +// - requires_any: +// requirements: +// - provider_name: "provider-B" +// - provider_name: "provider-C" +// +// # Example 6: require A or (B and C) +// requires_any: +// requirements: +// - provider_name: "provider-A" +// - requires_all: +// requirements: +// - provider_name: "provider-B" +// - provider_name: "provider-C" +// +message JwtRequirement { + oneof requires_type { + // Specify a required provider name. + string provider_name = 1; + + // Specify a required provider with audiences. + ProviderWithAudiences provider_and_audiences = 2; - // If true, the request is allowed if JWT is missing or JWT verification fails. - // Default is false, a request without JWT or failed JWT verification is not allowed. - bool allow_missing_or_failed = 2; + // Specify list of JwtRequirement. Their results are OR-ed. + // If any one of them passes, the result is passed. + JwtRequirementOrList requires_any = 3; - // This field lists the patterns allowed to bypass JWT verification. This only applies when - // `allow_missing_or_failed_jwt` is false. Under this config, if a request doesn't have JWT, it - // will be rejected. But some requests still needed to be forwarded without JWT, such as OPTIONS - // for CORS and some health checking paths. + // Specify list of JwtRequirement. Their results are AND-ed. + // All of them must pass, if one of them fails or missing, it fails. + JwtRequirementAndList requires_all = 4; + + // The requirement is always satisfied even if JWT is missing or the JWT + // verification fails. A typical usage is: this filter is used to only verify + // JWTs and pass the verified JWT payloads to another filter, the other filter + // will make decision. In this mode, all JWT tokens will be verified. + google.protobuf.BoolValue allow_missing_or_failed = 5; + } +} + +// This message specifies a list of RequiredProvider. +// Their results are OR-ed; if any one of them passes, the result is passed +message JwtRequirementOrList { + // Specify a list of JwtRequirement. + repeated JwtRequirement requirements = 1 [(validate.rules).repeated .min_items = 2]; +} + +// This message specifies a list of RequiredProvider. +// Their results are AND-ed; all of them must pass, if one of them fails or missing, it fails. +message JwtRequirementAndList { + // Specify a list of JwtRequirement. + repeated JwtRequirement requirements = 1 [(validate.rules).repeated .min_items = 2]; +} + +// This message specifies a Jwt requirement for a specific Route condition. +// Example 1: +// +// .. code-block:: yaml +// +// - match: +// prefix: "/healthz" +// +// In above example, "requires" field is empty for /healthz prefix match, +// it means that requests matching the path prefix don't require JWT authentication. +// +// Example 2: +// +// .. code-block:: yaml +// +// - match: +// prefix: "/" +// requires: { provider_name: "provider-A" } +// +// In above example, all requests matched the path prefix require jwt authentication +// from "provider-A". +message RequirementRule { + // The route matching parameter. Only when the match is satisfied, the "requires" field will + // apply. // - // Examples: bypass all CORS options requests + // For example: following match will match all requests. // // .. code-block:: yaml // - // bypass: - // - headers: - // - name: :method - // value: OPTIONS - // - headers: - // - name: :path - // regex_match: /.* + // match: + // prefix: "/" // - // Examples: bypass /healthz check + envoy.api.v2.route.RouteMatch match = 1 [(validate.rules).message.required = true]; + + // Specify a Jwt Requirement. Please detail comment in message JwtRequirement. + JwtRequirement requires = 2; +} + +// This is the Envoy HTTP filter config for JWT authentication. +// +// For example: +// +// .. code-block:: yaml +// +// providers: +// provider1: +// issuer: issuer1 +// audiences: +// - audience1 +// - audience2 +// remote_jwks: +// http_uri: +// uri: https://example.com/.well-known/jwks.json +// cluster: example_jwks_cluster +// provider2: +// issuer: issuer2 +// local_jwks: +// inline_string: jwks_string +// +// rules: +// # Not jwt verification is required for /health path +// - match: +// prefix: "/health" +// +// # Jwt verification for provider1 is required for path prefixed with "prefix" +// - match: +// prefix: "/prefix" +// requires: +// provider_name: "provider1" +// +// # Jwt verification for either provider1 or provider2 is required for all other requests. +// - match: +// prefix: "/" +// requires: +// requires_any: +// requirements: +// - provider_name: "provider1" +// - provider_name: "provider2" +// +//// [#not-implemented-hide:] +message JwtAuthentication { + // Map of provider names to JwtProviders. // // .. code-block:: yaml // - // bypass: - // - headers: - // - name: :method - // value: GET - // - headers: - // - name: :path - // exact_match: /healthz + // providers: + // provider1: + // issuer: issuer1 + // audiences: + // - audience1 + // - audience2 + // remote_jwks: + // http_uri: + // uri: https://example.com/.well-known/jwks.json + // cluster: example_jwks_cluster + // provider2: + // issuer: provider2 + // local_jwks: + // inline_string: jwks_string + // + map providers = 1; + + // Specifies requirements based on the route matches. The first matched requirement will be + // applied. If there are overlapped match conditions, please put the most specific match first. + // + // Examples + // + // .. code-block:: yaml // - repeated envoy.api.v2.route.RouteMatch bypass = 3; + // rules: + // - match: { prefix: "/healthz" } + // - match: { prefix: "/baz" } + // requires: + // provider_name: "provider1" + // - match: { prefix: "/foo" } + // requires: + // requires_any: + // requirements: + // - provider_name: "provider1" + // - provider_name: "provider2" + // - match: { prefix: "/bar" } + // requires: + // requires_all: + // requirements: + // - provider_name: "provider1" + // - provider_name: "provider2" + // + repeated RequirementRule rules = 2; } diff --git a/source/extensions/filters/http/jwt_authn/authenticator.cc b/source/extensions/filters/http/jwt_authn/authenticator.cc index 035d9ac1885c2..97293ed616e7c 100644 --- a/source/extensions/filters/http/jwt_authn/authenticator.cc +++ b/source/extensions/filters/http/jwt_authn/authenticator.cc @@ -75,9 +75,10 @@ class AuthenticatorImpl : public Logger::Loggable, }; void AuthenticatorImpl::sanitizePayloadHeaders(Http::HeaderMap& headers) const { - for (const auto& rule : config_->getProtoConfig().rules()) { - if (!rule.forward_payload_header().empty()) { - headers.remove(Http::LowerCaseString(rule.forward_payload_header())); + for (const auto& it : config_->getProtoConfig().providers()) { + const auto& provider = it.second; + if (!provider.forward_payload_header().empty()) { + headers.remove(Http::LowerCaseString(provider.forward_payload_header())); } } } @@ -147,7 +148,7 @@ void AuthenticatorImpl::verify(Http::HeaderMap& headers, Authenticator::Callback } void AuthenticatorImpl::fetchRemoteJwks() { - const auto& http_uri = jwks_data_->getJwtRule().remote_jwks().http_uri(); + const auto& http_uri = jwks_data_->getJwtProvider().remote_jwks().http_uri(); Http::MessagePtr message = Http::Utility::prepareHeaders(http_uri); message->headers().insertMethod().value().setReference(Http::Headers::get().MethodValues.Get); @@ -218,13 +219,13 @@ void AuthenticatorImpl::verifyKey() { } // Forward the payload - const auto& rule = jwks_data_->getJwtRule(); - if (!rule.forward_payload_header().empty()) { - headers_->addCopy(Http::LowerCaseString(rule.forward_payload_header()), + const auto& provider = jwks_data_->getJwtProvider(); + if (!provider.forward_payload_header().empty()) { + headers_->addCopy(Http::LowerCaseString(provider.forward_payload_header()), jwt_.payload_str_base64url_); } - if (!rule.forward()) { + if (!provider.forward()) { // Remove JWT from headers. token_->removeJwt(*headers_); } @@ -233,10 +234,6 @@ void AuthenticatorImpl::verifyKey() { } bool AuthenticatorImpl::okToBypass() const { - if (config_->getProtoConfig().allow_missing_or_failed()) { - return true; - } - // TODO(qiwzhang): use requirement field return false; } @@ -244,11 +241,7 @@ bool AuthenticatorImpl::okToBypass() const { void AuthenticatorImpl::doneWithStatus(const Status& status) { ENVOY_LOG(debug, "Jwt authentication completed with: {}", ::google::jwt_verify::getStatusString(status)); - if (status != Status::Ok && config_->getProtoConfig().allow_missing_or_failed()) { - callback_->onComplete(Status::Ok); - } else { - callback_->onComplete(status); - } + callback_->onComplete(status); callback_ = nullptr; } diff --git a/source/extensions/filters/http/jwt_authn/extractor.cc b/source/extensions/filters/http/jwt_authn/extractor.cc index 17a373fe710e3..6560a1a58a834 100644 --- a/source/extensions/filters/http/jwt_authn/extractor.cc +++ b/source/extensions/filters/http/jwt_authn/extractor.cc @@ -116,19 +116,20 @@ class ExtractorImpl : public Extractor { }; ExtractorImpl::ExtractorImpl(const JwtAuthentication& config) { - for (const auto& rule : config.rules()) { - for (const auto& header : rule.from_headers()) { - addHeaderConfig(rule.issuer(), LowerCaseString(header.name()), header.value_prefix()); + for (const auto& it : config.providers()) { + const auto& provider = it.second; + for (const auto& header : provider.from_headers()) { + addHeaderConfig(provider.issuer(), LowerCaseString(header.name()), header.value_prefix()); } - for (const std::string& param : rule.from_params()) { - addQueryParamConfig(rule.issuer(), param); + for (const std::string& param : provider.from_params()) { + addQueryParamConfig(provider.issuer(), param); } // If not specified, use default locations. - if (rule.from_headers().empty() && rule.from_params().empty()) { - addHeaderConfig(rule.issuer(), Http::Headers::get().Authorization, + if (provider.from_headers().empty() && provider.from_params().empty()) { + addHeaderConfig(provider.issuer(), Http::Headers::get().Authorization, JwtConstValues::get().BearerPrefix); - addQueryParamConfig(rule.issuer(), JwtConstValues::get().AccessTokenParam); + addQueryParamConfig(provider.issuer(), JwtConstValues::get().AccessTokenParam); } } } diff --git a/source/extensions/filters/http/jwt_authn/filter_factory.cc b/source/extensions/filters/http/jwt_authn/filter_factory.cc index 999c9ae343eac..4e7a7e622ca7e 100644 --- a/source/extensions/filters/http/jwt_authn/filter_factory.cc +++ b/source/extensions/filters/http/jwt_authn/filter_factory.cc @@ -23,14 +23,15 @@ namespace { * Validate inline jwks, make sure they are the valid */ void validateJwtConfig(const JwtAuthentication& proto_config) { - for (const auto& rule : proto_config.rules()) { - const auto inline_jwks = Config::DataSource::read(rule.local_jwks(), true); + for (const auto& it : proto_config.providers()) { + const auto& provider = it.second; + const auto inline_jwks = Config::DataSource::read(provider.local_jwks(), true); if (!inline_jwks.empty()) { auto jwks_obj = Jwks::createFrom(inline_jwks, Jwks::JWKS); if (jwks_obj->getStatus() != Status::Ok) { - throw EnvoyException( - fmt::format("Issuer '{}' in jwt_authn config has invalid local jwks: {}", rule.issuer(), - ::google::jwt_verify::getStatusString(jwks_obj->getStatus()))); + throw EnvoyException(fmt::format( + "Issuer '{}' in jwt_authn config has invalid local jwks: {}", provider.issuer(), + ::google::jwt_verify::getStatusString(jwks_obj->getStatus()))); } } } diff --git a/source/extensions/filters/http/jwt_authn/jwks_cache.cc b/source/extensions/filters/http/jwt_authn/jwks_cache.cc index 465b3a9010c7b..f26735c4f4186 100644 --- a/source/extensions/filters/http/jwt_authn/jwks_cache.cc +++ b/source/extensions/filters/http/jwt_authn/jwks_cache.cc @@ -9,6 +9,8 @@ #include "jwt_verify_lib/check_audience.h" +using ::envoy::config::filter::http::jwt_authn::v2alpha::JwtAuthentication; +using ::envoy::config::filter::http::jwt_authn::v2alpha::JwtProvider; using ::google::jwt_verify::Jwks; using ::google::jwt_verify::Status; @@ -23,29 +25,26 @@ constexpr int PubkeyCacheExpirationSec = 600; class JwksDataImpl : public JwksCache::JwksData, public Logger::Loggable { public: - JwksDataImpl(const ::envoy::config::filter::http::jwt_authn::v2alpha::JwtRule& jwt_rule) - : jwt_rule_(jwt_rule) { + JwksDataImpl(const JwtProvider& jwt_provider) : jwt_provider_(jwt_provider) { std::vector audiences; - for (const auto& aud : jwt_rule_.audiences()) { + for (const auto& aud : jwt_provider_.audiences()) { audiences.push_back(aud); } audiences_ = std::make_unique<::google::jwt_verify::CheckAudience>(audiences); - const auto inline_jwks = Config::DataSource::read(jwt_rule_.local_jwks(), true); + const auto inline_jwks = Config::DataSource::read(jwt_provider_.local_jwks(), true); if (!inline_jwks.empty()) { const Status status = setKey(inline_jwks, // inline jwks never expires. std::chrono::steady_clock::time_point::max()); if (status != Status::Ok) { - ENVOY_LOG(warn, "Invalid inline jwks for issuer: {}, jwks: {}", jwt_rule_.issuer(), + ENVOY_LOG(warn, "Invalid inline jwks for issuer: {}, jwks: {}", jwt_provider_.issuer(), inline_jwks); } } } - const ::envoy::config::filter::http::jwt_authn::v2alpha::JwtRule& getJwtRule() const override { - return jwt_rule_; - } + const JwtProvider& getJwtProvider() const override { return jwt_provider_; } bool areAudiencesAllowed(const std::vector& jwt_audiences) const override { return audiences_->areAudiencesAllowed(jwt_audiences); @@ -63,9 +62,9 @@ class JwksDataImpl : public JwksCache::JwksData, public Logger::Loggable& audiences) const PURE; diff --git a/test/extensions/filters/http/jwt_authn/authenticator_test.cc b/test/extensions/filters/http/jwt_authn/authenticator_test.cc index 99ad37a4c4707..e2c9b4d75d3ed 100644 --- a/test/extensions/filters/http/jwt_authn/authenticator_test.cc +++ b/test/extensions/filters/http/jwt_authn/authenticator_test.cc @@ -94,7 +94,7 @@ TEST_F(AuthenticatorTest, TestOkJWTandCache) { // This test verifies the Jwt is forwarded if "forward" flag is set. TEST_F(AuthenticatorTest, TestForwardJwt) { // Confit forward_jwt flag - proto_config_.mutable_rules(0)->set_forward(true); + (*proto_config_.mutable_providers())[std::string(ProviderName)].set_forward(true); CreateAuthenticator(); MockUpstream mock_pubkey(mock_factory_ctx_.cluster_manager_, PublicKey); @@ -141,41 +141,6 @@ TEST_F(AuthenticatorTest, TestMissedJWT) { auth_->verify(headers, &mock_cb_); } -// This test verifies if Jwt is missing but allow_missing_or_fail is true, Status::OK is returned. -TEST_F(AuthenticatorTest, TestMissingJwtWhenAllowMissingOrFailedIsTrue) { - // In this test, when JWT is missing, the status should still be OK - // because allow_missing_or_failed is true. - proto_config_.set_allow_missing_or_failed(true); - CreateAuthenticator(); - - EXPECT_CALL(mock_factory_ctx_.cluster_manager_, httpAsyncClientForCluster(_)).Times(0); - EXPECT_CALL(mock_cb_, onComplete(_)).WillOnce(Invoke([](const Status& status) { - ASSERT_EQ(status, Status::Ok); - })); - - // Empty headers. - auto headers = Http::TestHeaderMapImpl{}; - auth_->verify(headers, &mock_cb_); -} - -// This test verifies if Jwt verifiecation fails but allow_missing_or_fail is true, Status::OK is -// returned. -TEST_F(AuthenticatorTest, TestInValidJwtWhenAllowMissingOrFailedIsTrue) { - // In this test, when JWT is invalid, the status should still be OK - // because allow_missing_or_failed is true. - proto_config_.set_allow_missing_or_failed(true); - CreateAuthenticator(); - - EXPECT_CALL(mock_factory_ctx_.cluster_manager_, httpAsyncClientForCluster(_)).Times(0); - EXPECT_CALL(mock_cb_, onComplete(_)).WillOnce(Invoke([](const Status& status) { - ASSERT_EQ(status, Status::Ok); - })); - - std::string token = "invalidToken"; - auto headers = Http::TestHeaderMapImpl{{"Authorization", "Bearer " + token}}; - auth_->verify(headers, &mock_cb_); -} - // This test verifies if Jwt is invalid, JwtBadFormat status is returned. TEST_F(AuthenticatorTest, TestInvalidJWT) { EXPECT_CALL(mock_factory_ctx_.cluster_manager_, httpAsyncClientForCluster(_)).Times(0); @@ -243,7 +208,7 @@ TEST_F(AuthenticatorTest, TestWrongCluster) { // This test verifies when Jwt issuer is not configured, JwtUnknownIssuer is returned. TEST_F(AuthenticatorTest, TestIssuerNotFound) { // Create a config with an other issuer. - proto_config_.mutable_rules(0)->set_issuer("other_issuer"); + (*proto_config_.mutable_providers())[std::string(ProviderName)].set_issuer("other_issuer"); CreateAuthenticator(); EXPECT_CALL(mock_factory_ctx_.cluster_manager_, httpAsyncClientForCluster(_)).Times(0); @@ -419,8 +384,8 @@ TEST_F(AuthenticatorTest, TestOnDestroy) { // This test verifies if "forward_playload_header" is empty, payload is not forwarded. TEST_F(AuthenticatorTest, TestNoForwardPayloadHeader) { // In this config, there is no forward_payload_header - auto rule0 = proto_config_.mutable_rules(0); - rule0->clear_forward_payload_header(); + auto& provider0 = (*proto_config_.mutable_providers())[std::string(ProviderName)]; + provider0.clear_forward_payload_header(); CreateAuthenticator(); MockUpstream mock_pubkey(mock_factory_ctx_.cluster_manager_, PublicKey); diff --git a/test/extensions/filters/http/jwt_authn/extractor_test.cc b/test/extensions/filters/http/jwt_authn/extractor_test.cc index 2e964c1ee68e9..d58acd3542d99 100644 --- a/test/extensions/filters/http/jwt_authn/extractor_test.cc +++ b/test/extensions/filters/http/jwt_authn/extractor_test.cc @@ -18,24 +18,30 @@ namespace JwtAuthn { namespace { const char ExampleConfig[] = R"( -rules: - - issuer: issuer1 - - issuer: issuer2 +providers: + provider1: + issuer: issuer1 + provider2: + issuer: issuer2 from_headers: - name: token-header - - issuer: issuer3 + provider3: + issuer: issuer3 from_params: - token_param - - issuer: issuer4 + provider4: + issuer: issuer4 from_headers: - name: token-header from_params: - token_param - - issuer: issuer5 + provider5: + issuer: issuer5 from_headers: - name: prefix-header value_prefix: AAA - - issuer: issuer6 + provider6: + issuer: issuer6 from_headers: - name: prefix-header value_prefix: AAABBB diff --git a/test/extensions/filters/http/jwt_authn/filter_factory_test.cc b/test/extensions/filters/http/jwt_authn/filter_factory_test.cc index 92ead96db1379..de5071941e7e5 100644 --- a/test/extensions/filters/http/jwt_authn/filter_factory_test.cc +++ b/test/extensions/filters/http/jwt_authn/filter_factory_test.cc @@ -9,6 +9,7 @@ #include "gtest/gtest.h" using ::envoy::config::filter::http::jwt_authn::v2alpha::JwtAuthentication; +using ::envoy::config::filter::http::jwt_authn::v2alpha::JwtProvider; using testing::Invoke; using testing::_; @@ -30,22 +31,11 @@ TEST(HttpJwtAuthnFilterFactoryTest, GoodRemoteJwks) { cb(filter_callback); } -TEST(HttpJwtAuthnFilterFactoryTest, InvalidIssuerProto) { - FilterFactory factory; - JwtAuthentication proto_config; - // Add an empty rule with empty issuer - proto_config.add_rules(); - - NiceMock context; - EXPECT_THROW(factory.createFilterFactoryFromProto(proto_config, "stats", context), - ProtoValidationException); -} - TEST(HttpJwtAuthnFilterFactoryTest, GoodLocalJwks) { JwtAuthentication proto_config; - auto rule = proto_config.add_rules(); - rule->set_issuer("issuer"); - rule->mutable_local_jwks()->set_inline_string(PublicKey); + auto& provider = (*proto_config.mutable_providers())["provider"]; + provider.set_issuer("issuer"); + provider.mutable_local_jwks()->set_inline_string(PublicKey); NiceMock context; FilterFactory factory; @@ -57,9 +47,9 @@ TEST(HttpJwtAuthnFilterFactoryTest, GoodLocalJwks) { TEST(HttpJwtAuthnFilterFactoryTest, BadLocalJwks) { JwtAuthentication proto_config; - auto rule = proto_config.add_rules(); - rule->set_issuer("issuer"); - rule->mutable_local_jwks()->set_inline_string("A bad jwks"); + auto& provider = (*proto_config.mutable_providers())["provider"]; + provider.set_issuer("issuer"); + provider.mutable_local_jwks()->set_inline_string("A bad jwks"); NiceMock context; FilterFactory factory; diff --git a/test/extensions/filters/http/jwt_authn/filter_integration_test.cc b/test/extensions/filters/http/jwt_authn/filter_integration_test.cc index 881018edcc1c6..b6a2870014c20 100644 --- a/test/extensions/filters/http/jwt_authn/filter_integration_test.cc +++ b/test/extensions/filters/http/jwt_authn/filter_integration_test.cc @@ -19,9 +19,9 @@ std::string getFilterConfig(bool use_local_jwks) { MessageUtil::loadFromYaml(ExampleConfig, proto_config); if (use_local_jwks) { - auto rule0 = proto_config.mutable_rules(0); - rule0->clear_remote_jwks(); - auto local_jwks = rule0->mutable_local_jwks(); + auto& provider0 = (*proto_config.mutable_providers())[std::string(ProviderName)]; + provider0.clear_remote_jwks(); + auto local_jwks = provider0.mutable_local_jwks(); local_jwks->set_inline_string(PublicKey); } diff --git a/test/extensions/filters/http/jwt_authn/jwks_cache_test.cc b/test/extensions/filters/http/jwt_authn/jwks_cache_test.cc index a1a1e50d186f2..a679043628aaf 100644 --- a/test/extensions/filters/http/jwt_authn/jwks_cache_test.cc +++ b/test/extensions/filters/http/jwt_authn/jwks_cache_test.cc @@ -36,9 +36,9 @@ TEST_F(JwksCacheTest, TestFindByIssuer) { // Test setRemoteJwks and its expiration TEST_F(JwksCacheTest, TestSetRemoteJwks) { - auto rule0 = config_.mutable_rules(0); + auto& provider0 = (*config_.mutable_providers())[std::string(ProviderName)]; // Set cache_duration to 1 second to test expiration - rule0->mutable_remote_jwks()->mutable_cache_duration()->set_seconds(1); + provider0.mutable_remote_jwks()->mutable_cache_duration()->set_seconds(1); cache_ = JwksCache::create(config_); auto jwks = cache_->findByIssuer("https://example.com"); @@ -55,9 +55,9 @@ TEST_F(JwksCacheTest, TestSetRemoteJwks) { // Test setRemoteJwks and use default cache duration. TEST_F(JwksCacheTest, TestSetRemoteJwksWithDefaultCacheDuration) { - auto rule0 = config_.mutable_rules(0); + auto& provider0 = (*config_.mutable_providers())[std::string(ProviderName)]; // Clear cache_duration to use default one. - rule0->mutable_remote_jwks()->clear_cache_duration(); + provider0.mutable_remote_jwks()->clear_cache_duration(); cache_ = JwksCache::create(config_); auto jwks = cache_->findByIssuer("https://example.com"); @@ -70,9 +70,9 @@ TEST_F(JwksCacheTest, TestSetRemoteJwksWithDefaultCacheDuration) { // Test a good local jwks TEST_F(JwksCacheTest, TestGoodInlineJwks) { - auto rule0 = config_.mutable_rules(0); - rule0->clear_remote_jwks(); - auto local_jwks = rule0->mutable_local_jwks(); + auto& provider0 = (*config_.mutable_providers())[std::string(ProviderName)]; + provider0.clear_remote_jwks(); + auto local_jwks = provider0.mutable_local_jwks(); local_jwks->set_inline_string(PublicKey); cache_ = JwksCache::create(config_); @@ -84,9 +84,9 @@ TEST_F(JwksCacheTest, TestGoodInlineJwks) { // Test a bad local jwks TEST_F(JwksCacheTest, TestBadInlineJwks) { - auto rule0 = config_.mutable_rules(0); - rule0->clear_remote_jwks(); - auto local_jwks = rule0->mutable_local_jwks(); + auto& provider0 = (*config_.mutable_providers())[std::string(ProviderName)]; + provider0.clear_remote_jwks(); + auto local_jwks = provider0.mutable_local_jwks(); local_jwks->set_inline_string("BAD-JWKS"); cache_ = JwksCache::create(config_); diff --git a/test/extensions/filters/http/jwt_authn/test_common.h b/test/extensions/filters/http/jwt_authn/test_common.h index 04a36f07e41a3..86befa921b2ac 100644 --- a/test/extensions/filters/http/jwt_authn/test_common.h +++ b/test/extensions/filters/http/jwt_authn/test_common.h @@ -31,8 +31,9 @@ const char PublicKey[] = R"( // A good config. const char ExampleConfig[] = R"( -rules: - - issuer: https://example.com +providers: + example_provider: + issuer: https://example.com audiences: - example_service - http://example_service1 @@ -48,6 +49,9 @@ const char ExampleConfig[] = R"( forward_payload_header: sec-istio-auth-userinfo )"; +// The name of provider for above config. +const char ProviderName[] = "example_provider"; + // Payload: // {"iss":"https://example.com","sub":"test@example.com","aud":"example_service","exp":2001001001} const char GoodToken[] = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUu"