1*e7b1675dSTing-Kang Chang // Copyright 2021 Google LLC
2*e7b1675dSTing-Kang Chang //
3*e7b1675dSTing-Kang Chang // Licensed under the Apache License, Version 2.0 (the "License");
4*e7b1675dSTing-Kang Chang // you may not use this file except in compliance with the License.
5*e7b1675dSTing-Kang Chang // You may obtain a copy of the License at
6*e7b1675dSTing-Kang Chang //
7*e7b1675dSTing-Kang Chang // http://www.apache.org/licenses/LICENSE-2.0
8*e7b1675dSTing-Kang Chang //
9*e7b1675dSTing-Kang Chang // Unless required by applicable law or agreed to in writing, software
10*e7b1675dSTing-Kang Chang // distributed under the License is distributed on an "AS IS" BASIS,
11*e7b1675dSTing-Kang Chang // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e7b1675dSTing-Kang Chang // See the License for the specific language governing permissions and
13*e7b1675dSTing-Kang Chang // limitations under the License.
14*e7b1675dSTing-Kang Chang //
15*e7b1675dSTing-Kang Chang ///////////////////////////////////////////////////////////////////////////////
16*e7b1675dSTing-Kang Chang
17*e7b1675dSTing-Kang Chang #include "tink/jwt/raw_jwt.h"
18*e7b1675dSTing-Kang Chang
19*e7b1675dSTing-Kang Chang #include <string>
20*e7b1675dSTing-Kang Chang #include <utility>
21*e7b1675dSTing-Kang Chang #include <vector>
22*e7b1675dSTing-Kang Chang
23*e7b1675dSTing-Kang Chang #include "absl/status/status.h"
24*e7b1675dSTing-Kang Chang #include "absl/strings/numbers.h"
25*e7b1675dSTing-Kang Chang #include "absl/strings/str_format.h"
26*e7b1675dSTing-Kang Chang #include "absl/strings/substitute.h"
27*e7b1675dSTing-Kang Chang #include "absl/time/time.h"
28*e7b1675dSTing-Kang Chang #include "tink/jwt/internal/json_util.h"
29*e7b1675dSTing-Kang Chang
30*e7b1675dSTing-Kang Chang namespace crypto {
31*e7b1675dSTing-Kang Chang namespace tink {
32*e7b1675dSTing-Kang Chang
33*e7b1675dSTing-Kang Chang namespace {
34*e7b1675dSTing-Kang Chang
35*e7b1675dSTing-Kang Chang using ::google::protobuf::Struct;
36*e7b1675dSTing-Kang Chang using ::google::protobuf::Value;
37*e7b1675dSTing-Kang Chang
38*e7b1675dSTing-Kang Chang // Registered claim names, as defined in
39*e7b1675dSTing-Kang Chang // https://tools.ietf.org/html/rfc7519#section-4.1.
40*e7b1675dSTing-Kang Chang constexpr absl::string_view kJwtClaimIssuer = "iss";
41*e7b1675dSTing-Kang Chang constexpr absl::string_view kJwtClaimSubject = "sub";
42*e7b1675dSTing-Kang Chang constexpr absl::string_view kJwtClaimAudience = "aud";
43*e7b1675dSTing-Kang Chang constexpr absl::string_view kJwtClaimExpiration = "exp";
44*e7b1675dSTing-Kang Chang constexpr absl::string_view kJwtClaimNotBefore = "nbf";
45*e7b1675dSTing-Kang Chang constexpr absl::string_view kJwtClaimIssuedAt = "iat";
46*e7b1675dSTing-Kang Chang constexpr absl::string_view kJwtClaimJwtId = "jti";
47*e7b1675dSTing-Kang Chang
48*e7b1675dSTing-Kang Chang constexpr int64_t kJwtTimestampMax = 253402300799; // 31 Dec 9999, 23:59:59 GMT
49*e7b1675dSTing-Kang Chang
IsRegisteredClaimName(absl::string_view name)50*e7b1675dSTing-Kang Chang bool IsRegisteredClaimName(absl::string_view name) {
51*e7b1675dSTing-Kang Chang return name == kJwtClaimIssuer || name == kJwtClaimSubject ||
52*e7b1675dSTing-Kang Chang name == kJwtClaimAudience || name == kJwtClaimExpiration ||
53*e7b1675dSTing-Kang Chang name == kJwtClaimNotBefore || name == kJwtClaimIssuedAt ||
54*e7b1675dSTing-Kang Chang name == kJwtClaimJwtId;
55*e7b1675dSTing-Kang Chang }
56*e7b1675dSTing-Kang Chang
ValidatePayloadName(absl::string_view name)57*e7b1675dSTing-Kang Chang util::Status ValidatePayloadName(absl::string_view name) {
58*e7b1675dSTing-Kang Chang if (IsRegisteredClaimName(name)) {
59*e7b1675dSTing-Kang Chang return absl::InvalidArgumentError(absl::Substitute(
60*e7b1675dSTing-Kang Chang "claim '$0' is invalid because it's a registered name; "
61*e7b1675dSTing-Kang Chang "use the corresponding getter or setter method.",
62*e7b1675dSTing-Kang Chang name));
63*e7b1675dSTing-Kang Chang }
64*e7b1675dSTing-Kang Chang return util::OkStatus();
65*e7b1675dSTing-Kang Chang }
66*e7b1675dSTing-Kang Chang
HasClaimOfKind(const google::protobuf::Struct & json_proto,absl::string_view name,Value::KindCase kind)67*e7b1675dSTing-Kang Chang bool HasClaimOfKind(const google::protobuf::Struct& json_proto,
68*e7b1675dSTing-Kang Chang absl::string_view name, Value::KindCase kind) {
69*e7b1675dSTing-Kang Chang if (IsRegisteredClaimName(name)) {
70*e7b1675dSTing-Kang Chang return false;
71*e7b1675dSTing-Kang Chang }
72*e7b1675dSTing-Kang Chang const auto& fields = json_proto.fields();
73*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(name));
74*e7b1675dSTing-Kang Chang if (it == fields.end()) {
75*e7b1675dSTing-Kang Chang return false;
76*e7b1675dSTing-Kang Chang }
77*e7b1675dSTing-Kang Chang const Value& value = it->second;
78*e7b1675dSTing-Kang Chang return value.kind_case() == kind;
79*e7b1675dSTing-Kang Chang }
80*e7b1675dSTing-Kang Chang
81*e7b1675dSTing-Kang Chang // Returns true if the claim is present but not a string.
ClaimIsNotAString(const google::protobuf::Struct & json_proto,absl::string_view name)82*e7b1675dSTing-Kang Chang bool ClaimIsNotAString(const google::protobuf::Struct& json_proto,
83*e7b1675dSTing-Kang Chang absl::string_view name) {
84*e7b1675dSTing-Kang Chang const auto& fields = json_proto.fields();
85*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(name));
86*e7b1675dSTing-Kang Chang if (it == fields.end()) {
87*e7b1675dSTing-Kang Chang return false;
88*e7b1675dSTing-Kang Chang }
89*e7b1675dSTing-Kang Chang const Value& value = it->second;
90*e7b1675dSTing-Kang Chang return value.kind_case() != Value::kStringValue;
91*e7b1675dSTing-Kang Chang }
92*e7b1675dSTing-Kang Chang
93*e7b1675dSTing-Kang Chang // Returns true if the claim is present but not a list.
ClaimIsNotAList(google::protobuf::Struct & json_proto,absl::string_view name)94*e7b1675dSTing-Kang Chang bool ClaimIsNotAList(google::protobuf::Struct& json_proto,
95*e7b1675dSTing-Kang Chang absl::string_view name) {
96*e7b1675dSTing-Kang Chang const auto& fields = json_proto.fields();
97*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(name));
98*e7b1675dSTing-Kang Chang if (it == fields.end()) {
99*e7b1675dSTing-Kang Chang return false;
100*e7b1675dSTing-Kang Chang }
101*e7b1675dSTing-Kang Chang const Value& value = it->second;
102*e7b1675dSTing-Kang Chang return value.kind_case() != Value::kListValue;
103*e7b1675dSTing-Kang Chang }
104*e7b1675dSTing-Kang Chang
105*e7b1675dSTing-Kang Chang // Returns true if the claim is present but not a timestamp.
ClaimIsNotATimestamp(const google::protobuf::Struct & json_proto,absl::string_view name)106*e7b1675dSTing-Kang Chang bool ClaimIsNotATimestamp(const google::protobuf::Struct& json_proto,
107*e7b1675dSTing-Kang Chang absl::string_view name) {
108*e7b1675dSTing-Kang Chang const auto& fields = json_proto.fields();
109*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(name));
110*e7b1675dSTing-Kang Chang if (it == fields.end()) {
111*e7b1675dSTing-Kang Chang return false;
112*e7b1675dSTing-Kang Chang }
113*e7b1675dSTing-Kang Chang const Value& value = it->second;
114*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kNumberValue) {
115*e7b1675dSTing-Kang Chang return true;
116*e7b1675dSTing-Kang Chang }
117*e7b1675dSTing-Kang Chang double timestamp = value.number_value();
118*e7b1675dSTing-Kang Chang return (timestamp > kJwtTimestampMax) || (timestamp < 0);
119*e7b1675dSTing-Kang Chang }
120*e7b1675dSTing-Kang Chang
TimeToTimestamp(absl::Time time)121*e7b1675dSTing-Kang Chang int64_t TimeToTimestamp(absl::Time time) {
122*e7b1675dSTing-Kang Chang // We round the timestamp to a whole number. We always round down.
123*e7b1675dSTing-Kang Chang return absl::ToUnixSeconds(time);
124*e7b1675dSTing-Kang Chang }
125*e7b1675dSTing-Kang Chang
TimestampToTime(double timestamp)126*e7b1675dSTing-Kang Chang absl::Time TimestampToTime(double timestamp) {
127*e7b1675dSTing-Kang Chang if (timestamp > kJwtTimestampMax) {
128*e7b1675dSTing-Kang Chang return absl::FromUnixSeconds(kJwtTimestampMax);
129*e7b1675dSTing-Kang Chang }
130*e7b1675dSTing-Kang Chang return absl::FromUnixSeconds(timestamp);
131*e7b1675dSTing-Kang Chang }
132*e7b1675dSTing-Kang Chang
ValidateAudienceClaim(const google::protobuf::Struct & json_proto)133*e7b1675dSTing-Kang Chang util::Status ValidateAudienceClaim(const google::protobuf::Struct& json_proto) {
134*e7b1675dSTing-Kang Chang const auto& fields = json_proto.fields();
135*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(kJwtClaimAudience));
136*e7b1675dSTing-Kang Chang if (it == fields.end()) {
137*e7b1675dSTing-Kang Chang return util::OkStatus();
138*e7b1675dSTing-Kang Chang }
139*e7b1675dSTing-Kang Chang const Value& value = it->second;
140*e7b1675dSTing-Kang Chang if (value.kind_case() == Value::kStringValue) {
141*e7b1675dSTing-Kang Chang return util::OkStatus();
142*e7b1675dSTing-Kang Chang }
143*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kListValue) {
144*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
145*e7b1675dSTing-Kang Chang "aud claim is not a list");
146*e7b1675dSTing-Kang Chang }
147*e7b1675dSTing-Kang Chang if (value.list_value().values_size() < 1) {
148*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
149*e7b1675dSTing-Kang Chang "aud claim is present but empty");
150*e7b1675dSTing-Kang Chang }
151*e7b1675dSTing-Kang Chang for (const Value& v : value.list_value().values()) {
152*e7b1675dSTing-Kang Chang if (v.kind_case() != Value::kStringValue) {
153*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
154*e7b1675dSTing-Kang Chang "aud claim is not a list of strings");
155*e7b1675dSTing-Kang Chang }
156*e7b1675dSTing-Kang Chang }
157*e7b1675dSTing-Kang Chang return util::OkStatus();
158*e7b1675dSTing-Kang Chang }
159*e7b1675dSTing-Kang Chang
160*e7b1675dSTing-Kang Chang } // namespace
161*e7b1675dSTing-Kang Chang
FromJson(absl::optional<std::string> type_header,absl::string_view json_payload)162*e7b1675dSTing-Kang Chang util::StatusOr<RawJwt> RawJwt::FromJson(absl::optional<std::string> type_header,
163*e7b1675dSTing-Kang Chang absl::string_view json_payload) {
164*e7b1675dSTing-Kang Chang util::StatusOr<google::protobuf::Struct> proto =
165*e7b1675dSTing-Kang Chang jwt_internal::JsonStringToProtoStruct(json_payload);
166*e7b1675dSTing-Kang Chang if (!proto.ok()) {
167*e7b1675dSTing-Kang Chang return proto.status();
168*e7b1675dSTing-Kang Chang }
169*e7b1675dSTing-Kang Chang if (ClaimIsNotAString(*proto, kJwtClaimIssuer) ||
170*e7b1675dSTing-Kang Chang ClaimIsNotAString(*proto, kJwtClaimSubject) ||
171*e7b1675dSTing-Kang Chang ClaimIsNotATimestamp(*proto, kJwtClaimExpiration) ||
172*e7b1675dSTing-Kang Chang ClaimIsNotATimestamp(*proto, kJwtClaimNotBefore) ||
173*e7b1675dSTing-Kang Chang ClaimIsNotATimestamp(*proto, kJwtClaimIssuedAt)) {
174*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
175*e7b1675dSTing-Kang Chang "contains an invalid registered claim");
176*e7b1675dSTing-Kang Chang }
177*e7b1675dSTing-Kang Chang util::Status aud_status = ValidateAudienceClaim(*proto);
178*e7b1675dSTing-Kang Chang if (!aud_status.ok()) {
179*e7b1675dSTing-Kang Chang return aud_status;
180*e7b1675dSTing-Kang Chang }
181*e7b1675dSTing-Kang Chang RawJwt token(type_header, *std::move(proto));
182*e7b1675dSTing-Kang Chang return token;
183*e7b1675dSTing-Kang Chang }
184*e7b1675dSTing-Kang Chang
GetJsonPayload() const185*e7b1675dSTing-Kang Chang util::StatusOr<std::string> RawJwt::GetJsonPayload() const {
186*e7b1675dSTing-Kang Chang return jwt_internal::ProtoStructToJsonString(json_proto_);
187*e7b1675dSTing-Kang Chang }
188*e7b1675dSTing-Kang Chang
189*e7b1675dSTing-Kang Chang RawJwt::RawJwt() = default;
190*e7b1675dSTing-Kang Chang
RawJwt(absl::optional<std::string> type_header,google::protobuf::Struct json_proto)191*e7b1675dSTing-Kang Chang RawJwt::RawJwt(absl::optional<std::string> type_header,
192*e7b1675dSTing-Kang Chang google::protobuf::Struct json_proto) {
193*e7b1675dSTing-Kang Chang type_header_ = type_header;
194*e7b1675dSTing-Kang Chang json_proto_ = json_proto;
195*e7b1675dSTing-Kang Chang }
196*e7b1675dSTing-Kang Chang
HasTypeHeader() const197*e7b1675dSTing-Kang Chang bool RawJwt::HasTypeHeader() const { return type_header_.has_value(); }
198*e7b1675dSTing-Kang Chang
GetTypeHeader() const199*e7b1675dSTing-Kang Chang util::StatusOr<std::string> RawJwt::GetTypeHeader() const {
200*e7b1675dSTing-Kang Chang if (!type_header_.has_value()) {
201*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
202*e7b1675dSTing-Kang Chang "No type header found");
203*e7b1675dSTing-Kang Chang }
204*e7b1675dSTing-Kang Chang return *type_header_;
205*e7b1675dSTing-Kang Chang }
206*e7b1675dSTing-Kang Chang
HasIssuer() const207*e7b1675dSTing-Kang Chang bool RawJwt::HasIssuer() const {
208*e7b1675dSTing-Kang Chang return json_proto_.fields().contains(std::string(kJwtClaimIssuer));
209*e7b1675dSTing-Kang Chang }
210*e7b1675dSTing-Kang Chang
GetIssuer() const211*e7b1675dSTing-Kang Chang util::StatusOr<std::string> RawJwt::GetIssuer() const {
212*e7b1675dSTing-Kang Chang const auto& fields = json_proto_.fields();
213*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(kJwtClaimIssuer));
214*e7b1675dSTing-Kang Chang if (it == fields.end()) {
215*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument, "No Issuer found");
216*e7b1675dSTing-Kang Chang }
217*e7b1675dSTing-Kang Chang const Value& value = it->second;
218*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kStringValue) {
219*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
220*e7b1675dSTing-Kang Chang "Issuer is not a string");
221*e7b1675dSTing-Kang Chang }
222*e7b1675dSTing-Kang Chang return value.string_value();
223*e7b1675dSTing-Kang Chang }
224*e7b1675dSTing-Kang Chang
HasSubject() const225*e7b1675dSTing-Kang Chang bool RawJwt::HasSubject() const {
226*e7b1675dSTing-Kang Chang return json_proto_.fields().contains(std::string(kJwtClaimSubject));
227*e7b1675dSTing-Kang Chang }
228*e7b1675dSTing-Kang Chang
GetSubject() const229*e7b1675dSTing-Kang Chang util::StatusOr<std::string> RawJwt::GetSubject() const {
230*e7b1675dSTing-Kang Chang const auto& fields = json_proto_.fields();
231*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(kJwtClaimSubject));
232*e7b1675dSTing-Kang Chang if (it == fields.end()) {
233*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument, "No Subject found");
234*e7b1675dSTing-Kang Chang }
235*e7b1675dSTing-Kang Chang const Value& value = it->second;
236*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kStringValue) {
237*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
238*e7b1675dSTing-Kang Chang "Subject is not a string");
239*e7b1675dSTing-Kang Chang }
240*e7b1675dSTing-Kang Chang return value.string_value();
241*e7b1675dSTing-Kang Chang }
242*e7b1675dSTing-Kang Chang
HasAudiences() const243*e7b1675dSTing-Kang Chang bool RawJwt::HasAudiences() const {
244*e7b1675dSTing-Kang Chang return json_proto_.fields().contains(std::string(kJwtClaimAudience));
245*e7b1675dSTing-Kang Chang }
246*e7b1675dSTing-Kang Chang
GetAudiences() const247*e7b1675dSTing-Kang Chang util::StatusOr<std::vector<std::string>> RawJwt::GetAudiences() const {
248*e7b1675dSTing-Kang Chang const auto& fields = json_proto_.fields();
249*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(kJwtClaimAudience));
250*e7b1675dSTing-Kang Chang if (it == fields.end()) {
251*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kNotFound, "No Audiences found");
252*e7b1675dSTing-Kang Chang }
253*e7b1675dSTing-Kang Chang Value list = it->second;
254*e7b1675dSTing-Kang Chang if (list.kind_case() != Value::kListValue) {
255*e7b1675dSTing-Kang Chang std::vector<std::string> audiences;
256*e7b1675dSTing-Kang Chang audiences.push_back(list.string_value());
257*e7b1675dSTing-Kang Chang return audiences;
258*e7b1675dSTing-Kang Chang }
259*e7b1675dSTing-Kang Chang if (list.kind_case() != Value::kListValue) {
260*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
261*e7b1675dSTing-Kang Chang "Audiences is not a list");
262*e7b1675dSTing-Kang Chang }
263*e7b1675dSTing-Kang Chang std::vector<std::string> audiences;
264*e7b1675dSTing-Kang Chang for (const auto& value : list.list_value().values()) {
265*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kStringValue) {
266*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
267*e7b1675dSTing-Kang Chang "Audiences is not a list of strings");
268*e7b1675dSTing-Kang Chang }
269*e7b1675dSTing-Kang Chang audiences.push_back(value.string_value());
270*e7b1675dSTing-Kang Chang }
271*e7b1675dSTing-Kang Chang return audiences;
272*e7b1675dSTing-Kang Chang }
273*e7b1675dSTing-Kang Chang
HasJwtId() const274*e7b1675dSTing-Kang Chang bool RawJwt::HasJwtId() const {
275*e7b1675dSTing-Kang Chang return json_proto_.fields().contains(std::string(kJwtClaimJwtId));
276*e7b1675dSTing-Kang Chang }
277*e7b1675dSTing-Kang Chang
GetJwtId() const278*e7b1675dSTing-Kang Chang util::StatusOr<std::string> RawJwt::GetJwtId() const {
279*e7b1675dSTing-Kang Chang const auto& fields = json_proto_.fields();
280*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(kJwtClaimJwtId));
281*e7b1675dSTing-Kang Chang if (it == fields.end()) {
282*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kNotFound, "No JwtId found");
283*e7b1675dSTing-Kang Chang }
284*e7b1675dSTing-Kang Chang const Value& value = it->second;
285*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kStringValue) {
286*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
287*e7b1675dSTing-Kang Chang "JwtId is not a string");
288*e7b1675dSTing-Kang Chang }
289*e7b1675dSTing-Kang Chang return value.string_value();
290*e7b1675dSTing-Kang Chang }
291*e7b1675dSTing-Kang Chang
HasExpiration() const292*e7b1675dSTing-Kang Chang bool RawJwt::HasExpiration() const {
293*e7b1675dSTing-Kang Chang return json_proto_.fields().contains(std::string(kJwtClaimExpiration));
294*e7b1675dSTing-Kang Chang }
295*e7b1675dSTing-Kang Chang
GetExpiration() const296*e7b1675dSTing-Kang Chang util::StatusOr<absl::Time> RawJwt::GetExpiration() const {
297*e7b1675dSTing-Kang Chang const auto& fields = json_proto_.fields();
298*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(kJwtClaimExpiration));
299*e7b1675dSTing-Kang Chang if (it == fields.end()) {
300*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kNotFound, "No Expiration found");
301*e7b1675dSTing-Kang Chang }
302*e7b1675dSTing-Kang Chang const Value& value = it->second;
303*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kNumberValue) {
304*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
305*e7b1675dSTing-Kang Chang "Expiration is not a number");
306*e7b1675dSTing-Kang Chang }
307*e7b1675dSTing-Kang Chang return TimestampToTime(value.number_value());
308*e7b1675dSTing-Kang Chang }
309*e7b1675dSTing-Kang Chang
HasNotBefore() const310*e7b1675dSTing-Kang Chang bool RawJwt::HasNotBefore() const {
311*e7b1675dSTing-Kang Chang return json_proto_.fields().contains(std::string(kJwtClaimNotBefore));
312*e7b1675dSTing-Kang Chang }
313*e7b1675dSTing-Kang Chang
GetNotBefore() const314*e7b1675dSTing-Kang Chang util::StatusOr<absl::Time> RawJwt::GetNotBefore() const {
315*e7b1675dSTing-Kang Chang const auto& fields = json_proto_.fields();
316*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(kJwtClaimNotBefore));
317*e7b1675dSTing-Kang Chang if (it == fields.end()) {
318*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kNotFound, "No NotBefore found");
319*e7b1675dSTing-Kang Chang }
320*e7b1675dSTing-Kang Chang const Value& value = it->second;
321*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kNumberValue) {
322*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
323*e7b1675dSTing-Kang Chang "NotBefore is not a number");
324*e7b1675dSTing-Kang Chang }
325*e7b1675dSTing-Kang Chang return TimestampToTime(value.number_value());
326*e7b1675dSTing-Kang Chang }
327*e7b1675dSTing-Kang Chang
HasIssuedAt() const328*e7b1675dSTing-Kang Chang bool RawJwt::HasIssuedAt() const {
329*e7b1675dSTing-Kang Chang return json_proto_.fields().contains(std::string(kJwtClaimIssuedAt));
330*e7b1675dSTing-Kang Chang }
331*e7b1675dSTing-Kang Chang
GetIssuedAt() const332*e7b1675dSTing-Kang Chang util::StatusOr<absl::Time> RawJwt::GetIssuedAt() const {
333*e7b1675dSTing-Kang Chang const auto& fields = json_proto_.fields();
334*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(kJwtClaimIssuedAt));
335*e7b1675dSTing-Kang Chang if (it == fields.end()) {
336*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kNotFound, "No IssuedAt found");
337*e7b1675dSTing-Kang Chang }
338*e7b1675dSTing-Kang Chang const Value& value = it->second;
339*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kNumberValue) {
340*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
341*e7b1675dSTing-Kang Chang "IssuedAt is not a number");
342*e7b1675dSTing-Kang Chang }
343*e7b1675dSTing-Kang Chang return TimestampToTime(value.number_value());
344*e7b1675dSTing-Kang Chang }
345*e7b1675dSTing-Kang Chang
IsNullClaim(absl::string_view name) const346*e7b1675dSTing-Kang Chang bool RawJwt::IsNullClaim(absl::string_view name) const {
347*e7b1675dSTing-Kang Chang return HasClaimOfKind(json_proto_, name, Value::kNullValue);
348*e7b1675dSTing-Kang Chang }
349*e7b1675dSTing-Kang Chang
HasBooleanClaim(absl::string_view name) const350*e7b1675dSTing-Kang Chang bool RawJwt::HasBooleanClaim(absl::string_view name) const {
351*e7b1675dSTing-Kang Chang return HasClaimOfKind(json_proto_, name, Value::kBoolValue);
352*e7b1675dSTing-Kang Chang }
353*e7b1675dSTing-Kang Chang
GetBooleanClaim(absl::string_view name) const354*e7b1675dSTing-Kang Chang util::StatusOr<bool> RawJwt::GetBooleanClaim(
355*e7b1675dSTing-Kang Chang absl::string_view name) const {
356*e7b1675dSTing-Kang Chang util::Status status = ValidatePayloadName(name);
357*e7b1675dSTing-Kang Chang if (!status.ok()) {
358*e7b1675dSTing-Kang Chang return status;
359*e7b1675dSTing-Kang Chang }
360*e7b1675dSTing-Kang Chang const auto& fields = json_proto_.fields();
361*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(name));
362*e7b1675dSTing-Kang Chang if (it == fields.end()) {
363*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kNotFound,
364*e7b1675dSTing-Kang Chang absl::Substitute("claim '$0' not found", name));
365*e7b1675dSTing-Kang Chang }
366*e7b1675dSTing-Kang Chang const Value& value = it->second;
367*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kBoolValue) {
368*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
369*e7b1675dSTing-Kang Chang absl::Substitute("claim '$0' is not a bool", name));
370*e7b1675dSTing-Kang Chang }
371*e7b1675dSTing-Kang Chang return value.bool_value();
372*e7b1675dSTing-Kang Chang }
373*e7b1675dSTing-Kang Chang
HasStringClaim(absl::string_view name) const374*e7b1675dSTing-Kang Chang bool RawJwt::HasStringClaim(absl::string_view name) const {
375*e7b1675dSTing-Kang Chang return HasClaimOfKind(json_proto_, name, Value::kStringValue);
376*e7b1675dSTing-Kang Chang }
377*e7b1675dSTing-Kang Chang
GetStringClaim(absl::string_view name) const378*e7b1675dSTing-Kang Chang util::StatusOr<std::string> RawJwt::GetStringClaim(
379*e7b1675dSTing-Kang Chang absl::string_view name) const {
380*e7b1675dSTing-Kang Chang util::Status status = ValidatePayloadName(name);
381*e7b1675dSTing-Kang Chang if (!status.ok()) {
382*e7b1675dSTing-Kang Chang return status;
383*e7b1675dSTing-Kang Chang }
384*e7b1675dSTing-Kang Chang const auto& fields = json_proto_.fields();
385*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(name));
386*e7b1675dSTing-Kang Chang if (it == fields.end()) {
387*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kNotFound,
388*e7b1675dSTing-Kang Chang absl::Substitute("claim '$0' not found", name));
389*e7b1675dSTing-Kang Chang }
390*e7b1675dSTing-Kang Chang const Value& value = it->second;
391*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kStringValue) {
392*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
393*e7b1675dSTing-Kang Chang absl::Substitute("claim '$0' is not a string", name));
394*e7b1675dSTing-Kang Chang }
395*e7b1675dSTing-Kang Chang return value.string_value();
396*e7b1675dSTing-Kang Chang }
397*e7b1675dSTing-Kang Chang
HasNumberClaim(absl::string_view name) const398*e7b1675dSTing-Kang Chang bool RawJwt::HasNumberClaim(absl::string_view name) const {
399*e7b1675dSTing-Kang Chang return HasClaimOfKind(json_proto_, name, Value::kNumberValue);
400*e7b1675dSTing-Kang Chang }
401*e7b1675dSTing-Kang Chang
GetNumberClaim(absl::string_view name) const402*e7b1675dSTing-Kang Chang util::StatusOr<double> RawJwt::GetNumberClaim(absl::string_view name) const {
403*e7b1675dSTing-Kang Chang util::Status status = ValidatePayloadName(name);
404*e7b1675dSTing-Kang Chang if (!status.ok()) {
405*e7b1675dSTing-Kang Chang return status;
406*e7b1675dSTing-Kang Chang }
407*e7b1675dSTing-Kang Chang const auto& fields = json_proto_.fields();
408*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(name));
409*e7b1675dSTing-Kang Chang if (it == fields.end()) {
410*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kNotFound,
411*e7b1675dSTing-Kang Chang absl::Substitute("claim '$0' not found", name));
412*e7b1675dSTing-Kang Chang }
413*e7b1675dSTing-Kang Chang const Value& value = it->second;
414*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kNumberValue) {
415*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument,
416*e7b1675dSTing-Kang Chang absl::Substitute("claim '$0' is not a number", name));
417*e7b1675dSTing-Kang Chang }
418*e7b1675dSTing-Kang Chang return value.number_value();
419*e7b1675dSTing-Kang Chang }
420*e7b1675dSTing-Kang Chang
HasJsonObjectClaim(absl::string_view name) const421*e7b1675dSTing-Kang Chang bool RawJwt::HasJsonObjectClaim(absl::string_view name) const {
422*e7b1675dSTing-Kang Chang return HasClaimOfKind(json_proto_, name, Value::kStructValue);
423*e7b1675dSTing-Kang Chang }
424*e7b1675dSTing-Kang Chang
GetJsonObjectClaim(absl::string_view name) const425*e7b1675dSTing-Kang Chang util::StatusOr<std::string> RawJwt::GetJsonObjectClaim(
426*e7b1675dSTing-Kang Chang absl::string_view name) const {
427*e7b1675dSTing-Kang Chang util::Status status = ValidatePayloadName(name);
428*e7b1675dSTing-Kang Chang if (!status.ok()) {
429*e7b1675dSTing-Kang Chang return status;
430*e7b1675dSTing-Kang Chang }
431*e7b1675dSTing-Kang Chang const auto& fields = json_proto_.fields();
432*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(name));
433*e7b1675dSTing-Kang Chang if (it == fields.end()) {
434*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kNotFound,
435*e7b1675dSTing-Kang Chang absl::Substitute("claim '$0' not found", name));
436*e7b1675dSTing-Kang Chang }
437*e7b1675dSTing-Kang Chang const Value& value = it->second;
438*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kStructValue) {
439*e7b1675dSTing-Kang Chang return util::Status(
440*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
441*e7b1675dSTing-Kang Chang absl::Substitute("claim '$0' is not a JSON object", name));
442*e7b1675dSTing-Kang Chang }
443*e7b1675dSTing-Kang Chang return jwt_internal::ProtoStructToJsonString(value.struct_value());
444*e7b1675dSTing-Kang Chang }
445*e7b1675dSTing-Kang Chang
HasJsonArrayClaim(absl::string_view name) const446*e7b1675dSTing-Kang Chang bool RawJwt::HasJsonArrayClaim(absl::string_view name) const {
447*e7b1675dSTing-Kang Chang return HasClaimOfKind(json_proto_, name, Value::kListValue);
448*e7b1675dSTing-Kang Chang }
449*e7b1675dSTing-Kang Chang
GetJsonArrayClaim(absl::string_view name) const450*e7b1675dSTing-Kang Chang util::StatusOr<std::string> RawJwt::GetJsonArrayClaim(
451*e7b1675dSTing-Kang Chang absl::string_view name) const {
452*e7b1675dSTing-Kang Chang util::Status status = ValidatePayloadName(name);
453*e7b1675dSTing-Kang Chang if (!status.ok()) {
454*e7b1675dSTing-Kang Chang return status;
455*e7b1675dSTing-Kang Chang }
456*e7b1675dSTing-Kang Chang const auto& fields = json_proto_.fields();
457*e7b1675dSTing-Kang Chang auto it = fields.find(std::string(name));
458*e7b1675dSTing-Kang Chang if (it == fields.end()) {
459*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kNotFound,
460*e7b1675dSTing-Kang Chang absl::Substitute("claim '$0' not found", name));
461*e7b1675dSTing-Kang Chang }
462*e7b1675dSTing-Kang Chang const Value& value = it->second;
463*e7b1675dSTing-Kang Chang if (value.kind_case() != Value::kListValue) {
464*e7b1675dSTing-Kang Chang return util::Status(
465*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
466*e7b1675dSTing-Kang Chang absl::Substitute("claim '$0' is not a JSON array", name));
467*e7b1675dSTing-Kang Chang }
468*e7b1675dSTing-Kang Chang return jwt_internal::ProtoListToJsonString(value.list_value());
469*e7b1675dSTing-Kang Chang }
470*e7b1675dSTing-Kang Chang
CustomClaimNames() const471*e7b1675dSTing-Kang Chang std::vector<std::string> RawJwt::CustomClaimNames() const {
472*e7b1675dSTing-Kang Chang const auto& fields = json_proto_.fields();
473*e7b1675dSTing-Kang Chang std::vector<std::string> values;
474*e7b1675dSTing-Kang Chang for (auto it = fields.begin(); it != fields.end(); it++) {
475*e7b1675dSTing-Kang Chang if (!IsRegisteredClaimName(it->first)) {
476*e7b1675dSTing-Kang Chang values.push_back(it->first);
477*e7b1675dSTing-Kang Chang }
478*e7b1675dSTing-Kang Chang }
479*e7b1675dSTing-Kang Chang return values;
480*e7b1675dSTing-Kang Chang }
481*e7b1675dSTing-Kang Chang
RawJwtBuilder()482*e7b1675dSTing-Kang Chang RawJwtBuilder::RawJwtBuilder() { without_expiration_ = false; }
483*e7b1675dSTing-Kang Chang
SetTypeHeader(absl::string_view type_header)484*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::SetTypeHeader(absl::string_view type_header) {
485*e7b1675dSTing-Kang Chang type_header_ = std::string(type_header);
486*e7b1675dSTing-Kang Chang return *this;
487*e7b1675dSTing-Kang Chang }
488*e7b1675dSTing-Kang Chang
SetIssuer(absl::string_view issuer)489*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::SetIssuer(absl::string_view issuer) {
490*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
491*e7b1675dSTing-Kang Chang Value value;
492*e7b1675dSTing-Kang Chang value.set_string_value(std::string(issuer));
493*e7b1675dSTing-Kang Chang (*fields)[std::string(kJwtClaimIssuer)] = value;
494*e7b1675dSTing-Kang Chang return *this;
495*e7b1675dSTing-Kang Chang }
496*e7b1675dSTing-Kang Chang
SetSubject(absl::string_view subject)497*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::SetSubject(absl::string_view subject) {
498*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
499*e7b1675dSTing-Kang Chang Value value;
500*e7b1675dSTing-Kang Chang value.set_string_value(std::string(subject));
501*e7b1675dSTing-Kang Chang (*fields)[std::string(kJwtClaimSubject)] = value;
502*e7b1675dSTing-Kang Chang return *this;
503*e7b1675dSTing-Kang Chang }
504*e7b1675dSTing-Kang Chang
SetAudience(absl::string_view audience)505*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::SetAudience(absl::string_view audience) {
506*e7b1675dSTing-Kang Chang // Make sure that "aud" is not already a list by a call to SetAudiences or
507*e7b1675dSTing-Kang Chang // AddAudience.
508*e7b1675dSTing-Kang Chang if (ClaimIsNotAString(json_proto_, kJwtClaimAudience)) {
509*e7b1675dSTing-Kang Chang error_ = util::Status(absl::StatusCode::kInvalidArgument,
510*e7b1675dSTing-Kang Chang "SetAudience() must not be called together with "
511*e7b1675dSTing-Kang Chang "SetAudiences() or AddAudience");
512*e7b1675dSTing-Kang Chang return *this;
513*e7b1675dSTing-Kang Chang }
514*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
515*e7b1675dSTing-Kang Chang Value value;
516*e7b1675dSTing-Kang Chang value.set_string_value(std::string(audience));
517*e7b1675dSTing-Kang Chang (*fields)[std::string(kJwtClaimAudience)] = value;
518*e7b1675dSTing-Kang Chang return *this;
519*e7b1675dSTing-Kang Chang }
520*e7b1675dSTing-Kang Chang
SetAudiences(std::vector<std::string> audiences)521*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::SetAudiences(std::vector<std::string> audiences) {
522*e7b1675dSTing-Kang Chang // Make sure that "aud" is not already a string by a call to SetAudience.
523*e7b1675dSTing-Kang Chang if (ClaimIsNotAList(json_proto_, kJwtClaimAudience)) {
524*e7b1675dSTing-Kang Chang error_ = util::Status(
525*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
526*e7b1675dSTing-Kang Chang "SetAudiences() and SetAudience() must not be called together");
527*e7b1675dSTing-Kang Chang return *this;
528*e7b1675dSTing-Kang Chang }
529*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
530*e7b1675dSTing-Kang Chang Value value;
531*e7b1675dSTing-Kang Chang for (const auto& audience : audiences) {
532*e7b1675dSTing-Kang Chang value.mutable_list_value()->add_values()->set_string_value(audience);
533*e7b1675dSTing-Kang Chang }
534*e7b1675dSTing-Kang Chang (*fields)[std::string(kJwtClaimAudience)] = value;
535*e7b1675dSTing-Kang Chang return *this;
536*e7b1675dSTing-Kang Chang }
537*e7b1675dSTing-Kang Chang
AddAudience(absl::string_view audience)538*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::AddAudience(absl::string_view audience) {
539*e7b1675dSTing-Kang Chang // Make sure that "aud" is not already a string by a call to SetAudience.
540*e7b1675dSTing-Kang Chang if (ClaimIsNotAList(json_proto_, kJwtClaimAudience)) {
541*e7b1675dSTing-Kang Chang error_ = util::Status(
542*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
543*e7b1675dSTing-Kang Chang "AddAudience() and SetAudience() must not be called together");
544*e7b1675dSTing-Kang Chang return *this;
545*e7b1675dSTing-Kang Chang }
546*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
547*e7b1675dSTing-Kang Chang auto insertion_result =
548*e7b1675dSTing-Kang Chang fields->insert({std::string(kJwtClaimAudience), Value()});
549*e7b1675dSTing-Kang Chang google::protobuf::ListValue* list_value =
550*e7b1675dSTing-Kang Chang insertion_result.first->second.mutable_list_value();
551*e7b1675dSTing-Kang Chang list_value->add_values()->set_string_value(std::string(audience));
552*e7b1675dSTing-Kang Chang return *this;
553*e7b1675dSTing-Kang Chang }
554*e7b1675dSTing-Kang Chang
SetJwtId(absl::string_view jwid)555*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::SetJwtId(absl::string_view jwid) {
556*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
557*e7b1675dSTing-Kang Chang Value value;
558*e7b1675dSTing-Kang Chang value.set_string_value(std::string(jwid));
559*e7b1675dSTing-Kang Chang (*fields)[std::string(kJwtClaimJwtId)] = value;
560*e7b1675dSTing-Kang Chang return *this;
561*e7b1675dSTing-Kang Chang }
562*e7b1675dSTing-Kang Chang
WithoutExpiration()563*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::WithoutExpiration() {
564*e7b1675dSTing-Kang Chang without_expiration_ = true;
565*e7b1675dSTing-Kang Chang return *this;
566*e7b1675dSTing-Kang Chang }
567*e7b1675dSTing-Kang Chang
SetExpiration(absl::Time expiration)568*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::SetExpiration(absl::Time expiration) {
569*e7b1675dSTing-Kang Chang int64_t exp_timestamp = TimeToTimestamp(expiration);
570*e7b1675dSTing-Kang Chang if ((exp_timestamp > kJwtTimestampMax) || (exp_timestamp < 0)) {
571*e7b1675dSTing-Kang Chang if (!error_.has_value()) {
572*e7b1675dSTing-Kang Chang error_ = util::Status(absl::StatusCode::kInvalidArgument,
573*e7b1675dSTing-Kang Chang "invalid expiration timestamp");
574*e7b1675dSTing-Kang Chang }
575*e7b1675dSTing-Kang Chang return *this;
576*e7b1675dSTing-Kang Chang }
577*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
578*e7b1675dSTing-Kang Chang Value value;
579*e7b1675dSTing-Kang Chang value.set_number_value(exp_timestamp);
580*e7b1675dSTing-Kang Chang (*fields)[std::string(kJwtClaimExpiration)] = value;
581*e7b1675dSTing-Kang Chang return *this;
582*e7b1675dSTing-Kang Chang }
583*e7b1675dSTing-Kang Chang
SetNotBefore(absl::Time not_before)584*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::SetNotBefore(absl::Time not_before) {
585*e7b1675dSTing-Kang Chang int64_t nbf_timestamp = TimeToTimestamp(not_before);
586*e7b1675dSTing-Kang Chang if ((nbf_timestamp > kJwtTimestampMax) || (nbf_timestamp < 0)) {
587*e7b1675dSTing-Kang Chang if (!error_.has_value()) {
588*e7b1675dSTing-Kang Chang error_ = util::Status(absl::StatusCode::kInvalidArgument,
589*e7b1675dSTing-Kang Chang "invalid not_before timestamp");
590*e7b1675dSTing-Kang Chang }
591*e7b1675dSTing-Kang Chang return *this;
592*e7b1675dSTing-Kang Chang }
593*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
594*e7b1675dSTing-Kang Chang Value value;
595*e7b1675dSTing-Kang Chang value.set_number_value(nbf_timestamp);
596*e7b1675dSTing-Kang Chang (*fields)[std::string(kJwtClaimNotBefore)] = value;
597*e7b1675dSTing-Kang Chang return *this;
598*e7b1675dSTing-Kang Chang }
599*e7b1675dSTing-Kang Chang
SetIssuedAt(absl::Time issued_at)600*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::SetIssuedAt(absl::Time issued_at) {
601*e7b1675dSTing-Kang Chang int64_t iat_timestamp = TimeToTimestamp(issued_at);
602*e7b1675dSTing-Kang Chang if ((iat_timestamp > kJwtTimestampMax) || (iat_timestamp < 0)) {
603*e7b1675dSTing-Kang Chang if (!error_.has_value()) {
604*e7b1675dSTing-Kang Chang error_ = util::Status(absl::StatusCode::kInvalidArgument,
605*e7b1675dSTing-Kang Chang "invalid issued_at timestamp");
606*e7b1675dSTing-Kang Chang }
607*e7b1675dSTing-Kang Chang return *this;
608*e7b1675dSTing-Kang Chang }
609*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
610*e7b1675dSTing-Kang Chang Value value;
611*e7b1675dSTing-Kang Chang value.set_number_value(iat_timestamp);
612*e7b1675dSTing-Kang Chang (*fields)[std::string(kJwtClaimIssuedAt)] = value;
613*e7b1675dSTing-Kang Chang return *this;
614*e7b1675dSTing-Kang Chang }
615*e7b1675dSTing-Kang Chang
AddNullClaim(absl::string_view name)616*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::AddNullClaim(absl::string_view name) {
617*e7b1675dSTing-Kang Chang util::Status status = ValidatePayloadName(name);
618*e7b1675dSTing-Kang Chang if (!status.ok()) {
619*e7b1675dSTing-Kang Chang if (!error_.has_value()) {
620*e7b1675dSTing-Kang Chang error_ = status;
621*e7b1675dSTing-Kang Chang }
622*e7b1675dSTing-Kang Chang return *this;
623*e7b1675dSTing-Kang Chang }
624*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
625*e7b1675dSTing-Kang Chang Value value;
626*e7b1675dSTing-Kang Chang value.set_null_value(google::protobuf::NULL_VALUE);
627*e7b1675dSTing-Kang Chang (*fields)[std::string(name)] = value;
628*e7b1675dSTing-Kang Chang return *this;
629*e7b1675dSTing-Kang Chang }
630*e7b1675dSTing-Kang Chang
AddBooleanClaim(absl::string_view name,bool bool_value)631*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::AddBooleanClaim(absl::string_view name,
632*e7b1675dSTing-Kang Chang bool bool_value) {
633*e7b1675dSTing-Kang Chang util::Status status = ValidatePayloadName(name);
634*e7b1675dSTing-Kang Chang if (!status.ok()) {
635*e7b1675dSTing-Kang Chang if (!error_.has_value()) {
636*e7b1675dSTing-Kang Chang error_ = status;
637*e7b1675dSTing-Kang Chang }
638*e7b1675dSTing-Kang Chang return *this;
639*e7b1675dSTing-Kang Chang }
640*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
641*e7b1675dSTing-Kang Chang Value value;
642*e7b1675dSTing-Kang Chang value.set_bool_value(bool_value);
643*e7b1675dSTing-Kang Chang (*fields)[std::string(name)] = value;
644*e7b1675dSTing-Kang Chang return *this;
645*e7b1675dSTing-Kang Chang }
646*e7b1675dSTing-Kang Chang
AddStringClaim(absl::string_view name,absl::string_view string_value)647*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::AddStringClaim(absl::string_view name,
648*e7b1675dSTing-Kang Chang absl::string_view string_value) {
649*e7b1675dSTing-Kang Chang util::Status status = ValidatePayloadName(name);
650*e7b1675dSTing-Kang Chang if (!status.ok()) {
651*e7b1675dSTing-Kang Chang if (!error_.has_value()) {
652*e7b1675dSTing-Kang Chang error_ = status;
653*e7b1675dSTing-Kang Chang }
654*e7b1675dSTing-Kang Chang return *this;
655*e7b1675dSTing-Kang Chang }
656*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
657*e7b1675dSTing-Kang Chang Value value;
658*e7b1675dSTing-Kang Chang value.set_string_value(std::string(string_value));
659*e7b1675dSTing-Kang Chang (*fields)[std::string(name)] = value;
660*e7b1675dSTing-Kang Chang return *this;
661*e7b1675dSTing-Kang Chang }
662*e7b1675dSTing-Kang Chang
AddNumberClaim(absl::string_view name,double double_value)663*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::AddNumberClaim(absl::string_view name,
664*e7b1675dSTing-Kang Chang double double_value) {
665*e7b1675dSTing-Kang Chang util::Status status = ValidatePayloadName(name);
666*e7b1675dSTing-Kang Chang if (!status.ok()) {
667*e7b1675dSTing-Kang Chang if (!error_.has_value()) {
668*e7b1675dSTing-Kang Chang error_ = status;
669*e7b1675dSTing-Kang Chang }
670*e7b1675dSTing-Kang Chang return *this;
671*e7b1675dSTing-Kang Chang }
672*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
673*e7b1675dSTing-Kang Chang Value value;
674*e7b1675dSTing-Kang Chang value.set_number_value(double_value);
675*e7b1675dSTing-Kang Chang (*fields)[std::string(name)] = value;
676*e7b1675dSTing-Kang Chang return *this;
677*e7b1675dSTing-Kang Chang }
678*e7b1675dSTing-Kang Chang
AddJsonObjectClaim(absl::string_view name,absl::string_view object_value)679*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::AddJsonObjectClaim(
680*e7b1675dSTing-Kang Chang absl::string_view name, absl::string_view object_value) {
681*e7b1675dSTing-Kang Chang util::Status status = ValidatePayloadName(name);
682*e7b1675dSTing-Kang Chang if (!status.ok()) {
683*e7b1675dSTing-Kang Chang if (!error_.has_value()) {
684*e7b1675dSTing-Kang Chang error_ = status;
685*e7b1675dSTing-Kang Chang }
686*e7b1675dSTing-Kang Chang return *this;
687*e7b1675dSTing-Kang Chang }
688*e7b1675dSTing-Kang Chang util::StatusOr<google::protobuf::Struct> proto =
689*e7b1675dSTing-Kang Chang jwt_internal::JsonStringToProtoStruct(object_value);
690*e7b1675dSTing-Kang Chang if (!proto.ok()) {
691*e7b1675dSTing-Kang Chang if (!error_.has_value()) {
692*e7b1675dSTing-Kang Chang error_ = proto.status();
693*e7b1675dSTing-Kang Chang }
694*e7b1675dSTing-Kang Chang return *this;
695*e7b1675dSTing-Kang Chang }
696*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
697*e7b1675dSTing-Kang Chang Value value;
698*e7b1675dSTing-Kang Chang *value.mutable_struct_value() = *std::move(proto);
699*e7b1675dSTing-Kang Chang (*fields)[std::string(name)] = value;
700*e7b1675dSTing-Kang Chang return *this;
701*e7b1675dSTing-Kang Chang }
702*e7b1675dSTing-Kang Chang
AddJsonArrayClaim(absl::string_view name,absl::string_view array_value)703*e7b1675dSTing-Kang Chang RawJwtBuilder& RawJwtBuilder::AddJsonArrayClaim(absl::string_view name,
704*e7b1675dSTing-Kang Chang absl::string_view array_value) {
705*e7b1675dSTing-Kang Chang util::Status status = ValidatePayloadName(name);
706*e7b1675dSTing-Kang Chang if (!status.ok()) {
707*e7b1675dSTing-Kang Chang if (!error_.has_value()) {
708*e7b1675dSTing-Kang Chang error_ = status;
709*e7b1675dSTing-Kang Chang }
710*e7b1675dSTing-Kang Chang return *this;
711*e7b1675dSTing-Kang Chang }
712*e7b1675dSTing-Kang Chang util::StatusOr<google::protobuf::ListValue> list =
713*e7b1675dSTing-Kang Chang jwt_internal::JsonStringToProtoList(array_value);
714*e7b1675dSTing-Kang Chang if (!list.ok()) {
715*e7b1675dSTing-Kang Chang if (!error_.has_value()) {
716*e7b1675dSTing-Kang Chang error_ = list.status();
717*e7b1675dSTing-Kang Chang }
718*e7b1675dSTing-Kang Chang return *this;
719*e7b1675dSTing-Kang Chang }
720*e7b1675dSTing-Kang Chang auto fields = json_proto_.mutable_fields();
721*e7b1675dSTing-Kang Chang Value value;
722*e7b1675dSTing-Kang Chang *value.mutable_list_value() = *list;
723*e7b1675dSTing-Kang Chang (*fields)[std::string(name)] = value;
724*e7b1675dSTing-Kang Chang return *this;
725*e7b1675dSTing-Kang Chang }
726*e7b1675dSTing-Kang Chang
Build()727*e7b1675dSTing-Kang Chang util::StatusOr<RawJwt> RawJwtBuilder::Build() {
728*e7b1675dSTing-Kang Chang if (error_.has_value()) {
729*e7b1675dSTing-Kang Chang return *error_;
730*e7b1675dSTing-Kang Chang }
731*e7b1675dSTing-Kang Chang if (!json_proto_.fields().contains(std::string(kJwtClaimExpiration)) &&
732*e7b1675dSTing-Kang Chang !without_expiration_) {
733*e7b1675dSTing-Kang Chang return util::Status(
734*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
735*e7b1675dSTing-Kang Chang "neither SetExpiration() nor WithoutExpiration() was called");
736*e7b1675dSTing-Kang Chang }
737*e7b1675dSTing-Kang Chang if (json_proto_.fields().contains(std::string(kJwtClaimExpiration)) &&
738*e7b1675dSTing-Kang Chang without_expiration_) {
739*e7b1675dSTing-Kang Chang return util::Status(
740*e7b1675dSTing-Kang Chang absl::StatusCode::kInvalidArgument,
741*e7b1675dSTing-Kang Chang "SetExpiration() and WithoutExpiration() must not be called together");
742*e7b1675dSTing-Kang Chang }
743*e7b1675dSTing-Kang Chang RawJwt token(type_header_, json_proto_);
744*e7b1675dSTing-Kang Chang return token;
745*e7b1675dSTing-Kang Chang }
746*e7b1675dSTing-Kang Chang
747*e7b1675dSTing-Kang Chang } // namespace tink
748*e7b1675dSTing-Kang Chang } // namespace crypto
749