blob: da8f132bad11b784b03d98d2cde87e2d80205421 [file] [log] [blame]
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////
#include "tink/jwt/jwt_validator.h"
namespace crypto {
namespace tink {
namespace {
static constexpr absl::Duration kJwtMaxClockSkew = absl::Minutes(10);
}
JwtValidator::JwtValidator(absl::optional<absl::string_view> issuer,
absl::optional<absl::string_view> subject,
absl::optional<absl::string_view> audience,
absl::Duration clock_skew,
absl::optional<absl::Time> fixed_now) {
if (issuer.has_value()) {
issuer_ = std::string(issuer.value());
}
if (subject.has_value()) {
subject_ = std::string(subject.value());
}
if (audience.has_value()) {
audience_ = std::string(audience.value());
}
clock_skew_ = clock_skew;
fixed_now_ = fixed_now;
}
util::Status JwtValidator::Validate(RawJwt const& raw_jwt) const {
absl::Time now;
if (fixed_now_.has_value()) {
now = fixed_now_.value();
} else {
now = absl::Now();
}
if (raw_jwt.HasExpiration()) {
auto expiration_or = raw_jwt.GetExpiration();
if (!expiration_or.ok()) {
return expiration_or.status();
}
if (expiration_or.ValueOrDie() <= now - clock_skew_) {
return util::Status(util::error::INVALID_ARGUMENT, "token has expired");
}
}
if (raw_jwt.HasNotBefore()) {
auto not_before_or = raw_jwt.GetNotBefore();
if (!not_before_or.ok()) {
return not_before_or.status();
}
if (not_before_or.ValueOrDie() > now + clock_skew_) {
return util::Status(util::error::INVALID_ARGUMENT,
"token cannot yet be used");
}
}
if (issuer_.has_value()){
if (!raw_jwt.HasIssuer()) {
return util::Status(util::error::INVALID_ARGUMENT,
"missing expected issuer");
}
auto issuer_or = raw_jwt.GetIssuer();
if (!issuer_or.ok()) {
return issuer_or.status();
}
if (issuer_.value() != issuer_or.ValueOrDie()) {
return util::Status(util::error::INVALID_ARGUMENT, "wrong issuer");
}
}
if (subject_.has_value()) {
if (!raw_jwt.HasSubject()) {
return util::Status(util::error::INVALID_ARGUMENT,
"missing expected subject");
}
auto subject_or = raw_jwt.GetSubject();
if (!subject_or.ok()) {
return subject_or.status();
}
if (subject_.value() != subject_or.ValueOrDie()) {
return util::Status(util::error::INVALID_ARGUMENT, "wrong subject");
}
}
if (audience_.has_value()) {
if (!raw_jwt.HasAudiences()) {
return util::Status(util::error::INVALID_ARGUMENT,
"missing expected audiences");
}
auto audiences_or = raw_jwt.GetAudiences();
if (!audiences_or.ok()) {
return audiences_or.status();
}
std::vector<std::string> audiences = audiences_or.ValueOrDie();
auto it = std::find(audiences.begin(), audiences.end(), audience_);
if (it == audiences.end()) {
return util::Status(util::error::INVALID_ARGUMENT, "audience not found");
}
} else {
if (raw_jwt.HasAudiences()) {
return util::Status(
util::error::INVALID_ARGUMENT,
"invalid JWT; token has audience set, but validator not");
}
}
return util::OkStatus();
}
JwtValidatorBuilder::JwtValidatorBuilder() {
clock_skew_ = absl::ZeroDuration();
}
JwtValidatorBuilder& JwtValidatorBuilder::SetIssuer(absl::string_view issuer) {
issuer_ = std::string(issuer);
return *this;
}
JwtValidatorBuilder& JwtValidatorBuilder::SetSubject(
absl::string_view subject) {
subject_ = std::string(subject);
return *this;
}
JwtValidatorBuilder& JwtValidatorBuilder::SetAudience(
absl::string_view audience) {
audience_ = std::string(audience);
return *this;
}
util::Status JwtValidatorBuilder::SetClockSkew(
absl::Duration clock_skew) {
if (clock_skew > kJwtMaxClockSkew) {
return util::Status(util::error::INVALID_ARGUMENT,
"clock skew too large, max is 10 minutes");
}
clock_skew_ = clock_skew;
return util::OkStatus();
}
JwtValidatorBuilder& JwtValidatorBuilder::SetFixedNow(absl::Time fixed_now) {
fixed_now_ = fixed_now;
return *this;
}
JwtValidator JwtValidatorBuilder::Build() {
JwtValidator validator(issuer_, subject_, audience_, clock_skew_, fixed_now_);
return validator;
}
} // namespace tink
} // namespace crypto