Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
4bf0213
Add Jwt cache.
Dec 9, 2020
07e3923
Fixed comments and updated config proto.
Dec 13, 2020
e89cf2c
Suppressed unused parameter.
Dec 13, 2020
6c5e822
Fixed CI.
Dec 13, 2020
23d6b6b
Merge remote-tracking branch 'upstream/master' into jwt-cache
Dec 14, 2020
0d70dd7
Updated jwt_verify_lib release.
Dec 17, 2020
433e4c8
Merge remote-tracking branch 'upstream/master' into jwt-cache
Dec 23, 2020
35383c3
Resolved comments.
Dec 25, 2020
4d92197
Added token_cache_size.
Jan 8, 2021
6d9cbac
Updated config for JwtProvider
Feb 2, 2021
4d27b57
Fixed comments.
Feb 18, 2021
742220e
Fix.
Feb 25, 2021
883de98
Merge remote-tracking branch 'upstream/main' into jwt-cache
Mar 1, 2021
ac891a6
Fixed CI.
Mar 2, 2021
d69df58
Fix comments.
Mar 3, 2021
eacfbc3
Fixed release call.
Mar 4, 2021
1335cf6
Fixed memory release.
Mar 5, 2021
c8efe0e
Fixed windows CI.
Mar 5, 2021
9875c74
Fixed release metadata.
Mar 24, 2021
26b94cb
Redesigned Jwt Cache.
Mar 24, 2021
11e4057
fix
Mar 24, 2021
1f36422
fix
Mar 25, 2021
8964983
fix
Mar 25, 2021
8a3cb9c
fix
Mar 26, 2021
a2a31e5
fix.
Mar 31, 2021
a52ec67
Merge remote-tracking branch 'upstream/main' into jwt-cache
Mar 31, 2021
bb42b8d
Added release docs.
Apr 1, 2021
04335c7
fix
Apr 1, 2021
cfcd530
fix docs warning
Apr 1, 2021
f33850d
fix clang-tidy
Apr 1, 2021
e11c695
Update tests
qiwzhang Apr 20, 2021
c18856c
Merge remote-tracking branch 'upstream/main' into jwt-cache
Apr 20, 2021
b986895
fix docs.
Apr 20, 2021
3460ec0
fix format
Apr 20, 2021
ef3ad74
fix clang-tidy
Apr 20, 2021
3b95eee
Moved JwtCache in ThreadLocalCache
Apr 26, 2021
ca3cbee
fix
Apr 26, 2021
3d47511
fix
Apr 26, 2021
e13209e
Merge branch 'main' into jwt-cache
Apr 27, 2021
b96dc33
Merge remote-tracking branch 'upstream/main' into jwt-cache
Apr 27, 2021
8a175d5
fix
May 6, 2021
9419ddf
Merge remote-tracking branch 'upstream/main' into jwt-cache
May 6, 2021
7ac42c0
Merge branch 'main' into jwt-cache
May 20, 2021
07d45bb
Merge branch 'main' into jwt-cache
May 27, 2021
d0e83f2
Removed new line.
May 27, 2021
3f7c0c4
Resolved merge conflict.
Jun 1, 2021
45d3132
fixed CI.
Jun 1, 2021
13cb2b5
Merge remote-tracking branch 'upstream/main' into jwt-cache
Jun 7, 2021
f5fb8a4
fixed CI.
Jun 7, 2021
3e7768d
fix
Jun 9, 2021
17fe231
fix api docs
Jun 16, 2021
5372efd
Added 4KiB limit for JWT size
Jun 16, 2021
a1d3c72
fix style.
Jun 16, 2021
4f7caeb
Added JwtCacheConfig.
Jun 21, 2021
e4ceaac
Improve api
Jun 21, 2021
783c207
Merge remote-tracking branch 'upstream/main' into jwt-cache
Jun 28, 2021
a583ba7
fix
Jun 28, 2021
1de642f
Merge branch 'main' into jwt-cache
Jul 14, 2021
45f7298
fix rst
Jul 14, 2021
fd2f636
fix protos
Jul 14, 2021
a23bf86
fix test
Jul 14, 2021
4989b45
fix
Jul 15, 2021
25f366a
Merge remote-tracking branch 'upstream/main' into jwt-cache
Jul 15, 2021
efb4bb6
fix
Jul 15, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion api/envoy/extensions/filters/http/jwt_authn/v3/config.proto
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ option (udpa.annotations.file_status).package_version_status = ACTIVE;
// cache_duration:
// seconds: 300
//
// [#next-free-field: 12]
// [#next-free-field: 13]
message JwtProvider {
option (udpa.annotations.versioning).previous_message_type =
"envoy.config.filter.http.jwt_authn.v2alpha.JwtProvider";
Expand Down Expand Up @@ -220,6 +220,16 @@ message JwtProvider {
// Specify the clock skew in seconds when verifying JWT time constraint,
// such as `exp`, and `nbf`. If not specified, default is 60 seconds.
uint32 clock_skew_seconds = 10;

// Enables JWT cache, its size is specified by *jwt_cache_size*.
// Only valid JWT tokens are cached.
JwtCacheConfig jwt_cache_config = 12;
}

// This message specifies JWT Cache configuration.
message JwtCacheConfig {
// The unit is number of JWT tokens, default to 100.
uint32 jwt_cache_size = 1;
}

// This message specifies how to fetch JWKS from remote and how to cache it.
Expand Down
15 changes: 14 additions & 1 deletion api/envoy/extensions/filters/http/jwt_authn/v4alpha/config.proto

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions bazel/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,11 @@ def _com_github_google_jwt_verify():
actual = "@com_github_google_jwt_verify//:jwt_verify_lib",
)

native.bind(
name = "simple_lru_cache_lib",
actual = "@com_github_google_jwt_verify//:simple_lru_cache_lib",
)

def _com_github_luajit_luajit():
external_http_archive(
name = "com_github_luajit_luajit",
Expand Down
6 changes: 3 additions & 3 deletions bazel/repository_locations.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -467,13 +467,13 @@ REPOSITORY_LOCATIONS_SPEC = dict(
project_name = "jwt_verify_lib",
project_desc = "JWT verification library for C++",
project_url = "https://github.com/google/jwt_verify_lib",
version = "28efec2e4df1072db0ed03597591360ec9f80aac",
sha256 = "7a5c35b7cbf633398503ae12cad8c2833e92b3a796eed68b6256d22d51ace5e1",
version = "e5d6cf7067495b0868787e1fd1e75cef3242a840",
sha256 = "0d294dc8697049a0d7f2aaa81d08713fea581061c5359d6edb229b3e7c6cf58e",
strip_prefix = "jwt_verify_lib-{version}",
urls = ["https://github.com/google/jwt_verify_lib/archive/{version}.tar.gz"],
use_category = ["dataplane_ext"],
extensions = ["envoy.filters.http.jwt_authn"],
release_date = "2020-11-05",
release_date = "2021-03-05",
cpe = "N/A",
),
com_github_nodejs_http_parser = dict(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ JwtProvider
* *from_headers*: extract JWT from HTTP headers.
* *from_params*: extract JWT from query parameters.
* *forward_payload_header*: forward the JWT payload in the specified HTTP header.
* *jwt_cache_config*: Enables JWT cache, its size can be specified by *jwt_cache_size*. Only valid JWT tokens are cached.

Default Extract Location
~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
2 changes: 2 additions & 0 deletions docs/root/version_history/current.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,7 @@ Removed Config or Runtime
New Features
------------

* jwt_authn: added support for :ref:`Jwt Cache <envoy_v3_api_field_extensions.filters.http.jwt_authn.v3.JwtProvider.jwt_cache_config>` and its size can be specified by :ref:`jwt_cache_size <envoy_v3_api_field_extensions.filters.http.jwt_authn.v3.JwtCacheConfig.jwt_cache_size>`.

Deprecated
----------

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 15 additions & 0 deletions source/extensions/filters/http/jwt_authn/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ envoy_cc_library(
],
deps = [
"jwks_async_fetcher_lib",
":jwt_cache_lib",
"//source/common/config:datasource_lib",
"@envoy_api//envoy/extensions/filters/http/jwt_authn/v3:pkg_cc_proto",
],
Expand Down Expand Up @@ -143,3 +144,17 @@ envoy_cc_library(
"@envoy_api//envoy/extensions/filters/http/jwt_authn/v3:pkg_cc_proto",
],
)

envoy_cc_library(
name = "jwt_cache_lib",
srcs = ["jwt_cache.cc"],
hdrs = ["jwt_cache.h"],
external_deps = [
"jwt_verify_lib",
"simple_lru_cache_lib",
],
deps = [
"//source/common/protobuf:utility_lib",
"@envoy_api//envoy/extensions/filters/http/jwt_authn/v3:pkg_cc_proto",
],
)
40 changes: 32 additions & 8 deletions source/extensions/filters/http/jwt_authn/authenticator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class AuthenticatorImpl : public Logger::Loggable<Logger::Id::jwt>,
// Verify with a specific public key.
void verifyKey();

// Handle Good Jwt either Cache JWT or verified public key.
void handleGoodJwt(bool cache_hit);

// Calls the callback with status.
void doneWithStatus(const Status& status);

Expand All @@ -80,10 +83,9 @@ class AuthenticatorImpl : public Logger::Loggable<Logger::Id::jwt>,
std::vector<JwtLocationConstPtr> tokens_;
JwtLocationConstPtr curr_token_;
// The JWT object.
std::unique_ptr<::google::jwt_verify::Jwt> jwt_;
std::unique_ptr<::google::jwt_verify::Jwt> owned_jwt_;
// The JWKS data object
JwksCache::JwksData* jwks_data_{};

// The HTTP request headers
Http::HeaderMap* headers_{};
// The active span for the request
Expand All @@ -99,6 +101,7 @@ class AuthenticatorImpl : public Logger::Loggable<Logger::Id::jwt>,
const bool is_allow_failed_;
const bool is_allow_missing_;
TimeSource& time_source_;
::google::jwt_verify::Jwt* jwt_{};
};

std::string AuthenticatorImpl::name() const {
Expand Down Expand Up @@ -140,9 +143,20 @@ void AuthenticatorImpl::startVerify() {
curr_token_ = std::move(tokens_.back());
tokens_.pop_back();

jwt_ = std::make_unique<::google::jwt_verify::Jwt>();
if (provider_ != absl::nullopt) {
jwks_data_ = jwks_cache_.findByProvider(provider_.value());
jwt_ = jwks_data_->getJwtCache().lookup(curr_token_->token());
if (jwt_ != nullptr) {
handleGoodJwt(/*cache_hit=*/true);
return;
}
}

ENVOY_LOG(debug, "{}: Parse Jwt {}", name(), curr_token_->token());
Status status = jwt_->parseFromString(curr_token_->token());
owned_jwt_ = std::make_unique<::google::jwt_verify::Jwt>();
Status status = owned_jwt_->parseFromString(curr_token_->token());
jwt_ = owned_jwt_.get();

if (status != Status::Ok) {
doneWithStatus(status);
return;
Expand All @@ -157,9 +171,10 @@ void AuthenticatorImpl::startVerify() {
}
}

// Check the issuer is configured or not.
jwks_data_ = provider_ ? jwks_cache_.findByProvider(provider_.value())
: jwks_cache_.findByIssuer(jwt_->iss_);
// Issuer is configured
if (!provider_) {
jwks_data_ = jwks_cache_.findByIssuer(jwt_->iss_);
}
// When `provider` is valid, findByProvider should never return nullptr.
// Only when `allow_missing` or `allow_failed` is used, `provider` is invalid,
// and this authenticator is checking tokens from all providers. In this case,
Expand Down Expand Up @@ -200,6 +215,7 @@ void AuthenticatorImpl::startVerify() {
// the key cached, if we do proceed to verify else try a new JWKS retrieval.
// JWTs without a kid header field in the JWS we might be best to get each
// time? This all only matters for remote JWKS.

verifyKey();
return;
}
Expand Down Expand Up @@ -246,11 +262,15 @@ void AuthenticatorImpl::onDestroy() {
void AuthenticatorImpl::verifyKey() {
const Status status =
::google::jwt_verify::verifyJwtWithoutTimeChecking(*jwt_, *jwks_data_->getJwksObj());

if (status != Status::Ok) {
doneWithStatus(status);
return;
}
handleGoodJwt(/*cache_hit=*/false);
}

void AuthenticatorImpl::handleGoodJwt(bool cache_hit) {
// Forward the payload
const auto& provider = jwks_data_->getJwtProvider();

Expand All @@ -274,7 +294,10 @@ void AuthenticatorImpl::verifyKey() {
if (set_payload_cb_ && !provider.payload_in_metadata().empty()) {
set_payload_cb_(provider.payload_in_metadata(), jwt_->payload_pb_);
}

if (provider_ && !cache_hit) {
// move the ownership of "owned_jwt_" into the function.
jwks_data_->getJwtCache().insert(curr_token_->token(), std::move(owned_jwt_));
}
doneWithStatus(Status::Ok);
}

Expand All @@ -301,6 +324,7 @@ void AuthenticatorImpl::doneWithStatus(const Status& status) {
callback_ = nullptr;
return;
}

startVerify();
}

Expand Down
1 change: 1 addition & 0 deletions source/extensions/filters/http/jwt_authn/authenticator.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "source/extensions/filters/http/jwt_authn/extractor.h"
#include "source/extensions/filters/http/jwt_authn/jwks_cache.h"
#include "source/extensions/filters/http/jwt_authn/jwt_cache.h"

#include "jwt_verify_lib/check_audience.h"
#include "jwt_verify_lib/status.h"
Expand Down
17 changes: 15 additions & 2 deletions source/extensions/filters/http/jwt_authn/jwks_cache.cc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "source/extensions/filters/http/jwt_authn/jwks_cache.h"

#include <chrono>
#include <memory>

#include "envoy/common/time.h"
#include "envoy/extensions/filters/http/jwt_authn/v3/config.pb.h"
Expand Down Expand Up @@ -34,8 +35,11 @@ class JwksDataImpl : public JwksCache::JwksData, public Logger::Loggable<Logger:
audiences.push_back(aud);
}
audiences_ = std::make_unique<::google::jwt_verify::CheckAudience>(audiences);

tls_.set([](Envoy::Event::Dispatcher&) { return std::make_shared<ThreadLocalCache>(); });
bool enable_jwt_cache = jwt_provider_.has_jwt_cache_config();
const auto& config = jwt_provider_.jwt_cache_config();
tls_.set([enable_jwt_cache, config](Envoy::Event::Dispatcher& dispatcher) {
return std::make_shared<ThreadLocalCache>(enable_jwt_cache, config, dispatcher.timeSource());
});

const auto inline_jwks =
Config::DataSource::read(jwt_provider_.local_jwks(), true, context.api());
Expand Down Expand Up @@ -77,10 +81,19 @@ class JwksDataImpl : public JwksCache::JwksData, public Logger::Loggable<Logger:
return shared_jwks.get();
}

JwtCache& getJwtCache() override { return *tls_->jwt_cache_; }

private:
struct ThreadLocalCache : public ThreadLocal::ThreadLocalObject {
ThreadLocalCache(bool enable_jwt_cache,
const envoy::extensions::filters::http::jwt_authn::v3::JwtCacheConfig& config,
TimeSource& time_source)
: jwt_cache_(JwtCache::create(enable_jwt_cache, config, time_source)) {}

// The jwks object.
JwksConstSharedPtr jwks_;
// The JwtCache object
const JwtCachePtr jwt_cache_;
// The pubkey expiration time.
MonotonicTime expire_;
};
Expand Down
6 changes: 6 additions & 0 deletions source/extensions/filters/http/jwt_authn/jwks_cache.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#pragma once

#include <memory>

#include "envoy/api/api.h"
#include "envoy/common/pure.h"
#include "envoy/common/time.h"
Expand All @@ -8,6 +10,7 @@

#include "source/extensions/filters/http/common/jwks_fetcher.h"
#include "source/extensions/filters/http/jwt_authn/jwks_async_fetcher.h"
#include "source/extensions/filters/http/jwt_authn/jwt_cache.h"
#include "source/extensions/filters/http/jwt_authn/stats.h"

#include "jwt_verify_lib/jwks.h"
Expand Down Expand Up @@ -65,6 +68,9 @@ class JwksCache {

// Set a remote Jwks.
virtual const ::google::jwt_verify::Jwks* setRemoteJwks(JwksConstPtr&& jwks) PURE;

// Get Token Cache
virtual JwtCache& getJwtCache() PURE;
};

// Lookup issuer cache map. The cache only stores Jwks specified in the config.
Expand Down
Loading