-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix bug determining jwt validity due to incorrect computation of system timestamp and provide configuration option to allow for timely slack in token validity #10753
Changes from 3 commits
488f1ae
4b973ea
6d27fff
c2f082c
e1f734e
0fc50c9
e1c7689
662d7d9
829a14a
f45601f
da966bb
0ce07e5
056b6fc
abf60db
39e6dc0
3263dbe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,8 @@ | |
#include "jwt_verify_lib/jwt.h" | ||
#include "jwt_verify_lib/verify.h" | ||
|
||
#include "absl/time/clock.h" | ||
|
||
using ::google::jwt_verify::CheckAudience; | ||
using ::google::jwt_verify::Status; | ||
|
||
|
@@ -98,6 +100,10 @@ class AuthenticatorImpl : public Logger::Loggable<Logger::Id::jwt>, | |
const bool is_allow_failed_; | ||
const bool is_allow_missing_; | ||
TimeSource& time_source_; | ||
|
||
// allow 5 seconds of slack when determining token expery | ||
const uint64_t jwt_exp_slack = 5; | ||
uint64_t now; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not need to add anything to class members. |
||
}; | ||
|
||
std::string AuthenticatorImpl::name() const { | ||
|
@@ -153,23 +159,23 @@ void AuthenticatorImpl::startVerify() { | |
return; | ||
} | ||
|
||
// TODO(qiwzhang): Cross-platform-wise the below unix_timestamp code is wrong as the | ||
// epoch is not guaranteed to be defined as the unix epoch. We should use | ||
// the abseil time functionality instead or use the jwt_verify_lib to check | ||
// the validity of a JWT. | ||
// Check "exp" claim. | ||
const uint64_t unix_timestamp = | ||
std::chrono::duration_cast<std::chrono::seconds>(timeSource().systemTime().time_since_epoch()) | ||
.count(); | ||
// We use the current system time and allow for up to 5 seconds of slack. | ||
// Consider the following case: | ||
// AWS ALB receives a request and determines that the existing access token is valid | ||
// (for another 1 seconds), forwards the request to Istio Ingressgateway and subsequently | ||
// to some pod with an envoy sidecar. Meanwhile, 0.1 seconds have passed and when envoy checks | ||
// the token it finds that it has expired. | ||
now = absl::ToUnixSeconds(absl::Now()); | ||
// If the nbf claim does *not* appear in the JWT, then the nbf field is defaulted | ||
// to 0. | ||
if (jwt_->nbf_ > unix_timestamp) { | ||
if (jwt_->nbf_ > now) { | ||
doneWithStatus(Status::JwtNotYetValid); | ||
return; | ||
} | ||
// If the exp claim does *not* appear in the JWT then the exp field is defaulted | ||
// to 0. | ||
if (jwt_->exp_ > 0 && jwt_->exp_ < unix_timestamp) { | ||
if (jwt_->exp_ > 0 && jwt_->exp_ < now - jwt_exp_slack) { | ||
doneWithStatus(Status::JwtExpired); | ||
return; | ||
} | ||
|
@@ -237,7 +243,7 @@ void AuthenticatorImpl::onDestroy() { | |
|
||
// Verify with a specific public key. | ||
void AuthenticatorImpl::verifyKey() { | ||
const Status status = ::google::jwt_verify::verifyJwt(*jwt_, *jwks_data_->getJwksObj()); | ||
const Status status = ::google::jwt_verify::verifyJwt(*jwt_, *jwks_data_->getJwksObj(), now - jwt_exp_slack); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't need to double check the exp an bnf here. My suggestion is:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Err. Are you sure? jwt_verify_lib isn't an Istio thing, is it? |
||
if (status != Status::Ok) { | ||
doneWithStatus(status); | ||
return; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,8 @@ | |
#include "jwt_verify_lib/check_audience.h" | ||
#include "jwt_verify_lib/status.h" | ||
|
||
#include "absl/time/clock.h" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we have any regression or unit/integration tests for this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Tests? Jeeze. What roughnecked thinking. No, seriously. This is my first contribution here and I wasn't actually planning on going through by myself. Anyways, I don't mind at all doing it but need to get set up with a proper build environment to do real work. The coming weekend seems a good time to do so. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah heck, here I am working already. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This header is not needed any more. please remove it |
||
|
||
namespace Envoy { | ||
namespace Extensions { | ||
namespace HttpFilters { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is better to config this slack time from filter config. If default is 0, it will not change existing behaviors.
We can add two fields:
exp_slack: // now <= exp + exp_slack
bnf_slack: // now >= bnf - bnf_slack
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do I use filter config?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add new fields in Provider
you can get provider() as
jwks_data_->getJwtProvider()
as in line
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Working on it. Think I need a proper build environment. Is there some documentation to set it up?
Can't find it in https://github.com/envoyproxy/envoy/
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can check out this developer doc
The easiest way is to use docker
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah. Good. Will do the docker thingy.