Skip to content

Commit 29ffdb9

Browse files
authored
impl(common): a wrapper for subject tokens (#10267)
1 parent 3455b82 commit 29ffdb9

File tree

6 files changed

+153
-0
lines changed

6 files changed

+153
-0
lines changed

google/cloud/google_cloud_cpp_common.bzl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ google_cloud_cpp_common_hdrs = [
6868
"internal/sha256_hash.h",
6969
"internal/status_payload_keys.h",
7070
"internal/strerror.h",
71+
"internal/subject_token.h",
7172
"internal/throw_delegate.h",
7273
"internal/tuple.h",
7374
"internal/type_list.h",
@@ -112,6 +113,7 @@ google_cloud_cpp_common_srcs = [
112113
"internal/sha256_hash.cc",
113114
"internal/status_payload_keys.cc",
114115
"internal/strerror.cc",
116+
"internal/subject_token.cc",
115117
"internal/throw_delegate.cc",
116118
"internal/user_agent_prefix.cc",
117119
"kms_key_name.cc",

google/cloud/google_cloud_cpp_common.cmake

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ add_library(
102102
internal/status_payload_keys.h
103103
internal/strerror.cc
104104
internal/strerror.h
105+
internal/subject_token.cc
106+
internal/subject_token.h
105107
internal/throw_delegate.cc
106108
internal/throw_delegate.h
107109
internal/tuple.h
@@ -308,6 +310,7 @@ if (BUILD_TESTING)
308310
internal/sha256_hash_test.cc
309311
internal/status_payload_keys_test.cc
310312
internal/strerror_test.cc
313+
internal/subject_token_test.cc
311314
internal/throw_delegate_test.cc
312315
internal/tuple_test.cc
313316
internal/type_list_test.cc

google/cloud/google_cloud_cpp_common_unit_tests.bzl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ google_cloud_cpp_common_unit_tests = [
4747
"internal/sha256_hash_test.cc",
4848
"internal/status_payload_keys_test.cc",
4949
"internal/strerror_test.cc",
50+
"internal/subject_token_test.cc",
5051
"internal/throw_delegate_test.cc",
5152
"internal/tuple_test.cc",
5253
"internal/type_list_test.cc",
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "google/cloud/internal/subject_token.h"
16+
#include <ostream>
17+
18+
namespace google {
19+
namespace cloud {
20+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
21+
namespace internal {
22+
23+
std::ostream& operator<<(std::ostream& os, SubjectToken const& rhs) {
24+
// Tokens are truncated because they contain security secrets.
25+
return os << "token=<" << rhs.token.substr(0, 32) << ">";
26+
}
27+
28+
bool operator==(SubjectToken const& lhs, SubjectToken const& rhs) {
29+
return lhs.token == rhs.token;
30+
}
31+
32+
} // namespace internal
33+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
34+
} // namespace cloud
35+
} // namespace google
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_SUBJECT_TOKEN_H
16+
#define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_SUBJECT_TOKEN_H
17+
18+
#include "google/cloud/version.h"
19+
#include <chrono>
20+
#include <iosfwd>
21+
#include <string>
22+
23+
namespace google {
24+
namespace cloud {
25+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
26+
namespace internal {
27+
28+
/**
29+
* A slightly more type-safe representation for subject tokens.
30+
*
31+
* External accounts credentials use [OAuth 2.0 Token Exchange][RFC 8693] to
32+
* convert a "subject token" into an "access token". The latter is used (as one
33+
* would expect) to access GCP services. Tokens are just strings. It is too easy
34+
* to confuse their roles. A struct to wrap them provides enough type
35+
* annotations to avoid most mistakes.
36+
*
37+
* [RFC 8693]: https://www.rfc-editor.org/rfc/rfc8693.html
38+
*/
39+
struct SubjectToken {
40+
std::string token;
41+
};
42+
43+
std::ostream& operator<<(std::ostream& os, SubjectToken const& rhs);
44+
45+
bool operator==(SubjectToken const& lhs, SubjectToken const& rhs);
46+
47+
inline bool operator!=(SubjectToken const& lhs, SubjectToken const& rhs) {
48+
return !(lhs == rhs);
49+
}
50+
51+
} // namespace internal
52+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
53+
} // namespace cloud
54+
} // namespace google
55+
56+
#endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_INTERNAL_SUBJECT_TOKEN_H
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#include "google/cloud/internal/subject_token.h"
16+
#include <gmock/gmock.h>
17+
#include <sstream>
18+
19+
namespace google {
20+
namespace cloud {
21+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
22+
namespace internal {
23+
24+
using ::testing::HasSubstr;
25+
26+
TEST(SubjectToken, Compare) {
27+
auto const a = SubjectToken{"a"};
28+
auto const b = SubjectToken{"b"};
29+
auto const c = SubjectToken{"b"};
30+
EXPECT_EQ(a, a);
31+
EXPECT_EQ(b, c);
32+
EXPECT_NE(a, b);
33+
EXPECT_NE(a, c);
34+
}
35+
36+
TEST(SubjectToken, Stream) {
37+
auto const token = std::string{
38+
"123456789a"
39+
"123456789b"
40+
"123456789c"
41+
"123456789d"};
42+
auto const input = SubjectToken{token};
43+
std::ostringstream os;
44+
os << input;
45+
auto const actual = std::move(os).str();
46+
EXPECT_THAT(actual, HasSubstr("token=<"
47+
"123456789a"
48+
"123456789b"
49+
"123456789c"
50+
"12>"));
51+
}
52+
53+
} // namespace internal
54+
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
55+
} // namespace cloud
56+
} // namespace google

0 commit comments

Comments
 (0)