Skip to content
This repository was archived by the owner on Mar 24, 2026. It is now read-only.

Commit 5e6dbd0

Browse files
committed
add accesstoken test
1 parent 766537f commit 5e6dbd0

4 files changed

Lines changed: 306 additions & 0 deletions

File tree

tools/aad_accesstoken/BUILD

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Copyright 2023 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+
# http://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+
load("@rules_cc//cc:defs.bzl", "cc_test")
16+
17+
package(
18+
default_visibility = [
19+
"//visibility:public",
20+
],
21+
licenses = ["notice"],
22+
)
23+
24+
cc_test(
25+
name = "aad_accesstoken",
26+
size = "large",
27+
srcs = ["aad_accesstoken.cc"],
28+
tags = [
29+
"flaky",
30+
],
31+
deps = [
32+
"@com_github_google_quiche//quiche:oblivious_http_unstable_api",
33+
"@com_google_absl//absl/flags:flag",
34+
"@com_google_absl//absl/flags:parse",
35+
"@com_google_absl//absl/strings",
36+
"@com_google_googletest//:gtest",
37+
"@com_google_googletest//:gtest_main",
38+
"@com_github_google_glog//:glog",
39+
"@google_privacysandbox_servers_common//scp/cc/core/utils/src:core_utils",
40+
"@google_privacysandbox_servers_common//scp/cc/public/cpio/interface:cpio",
41+
"@google_privacysandbox_servers_common//src/cpp/concurrent:executor",
42+
"@google_privacysandbox_servers_common//src/cpp/accesstoken/src:accesstoken_fetcher",
43+
],
44+
)

tools/aad_accesstoken/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Aad retrieve an access token test
2+
3+
4+
```bash
5+
# Inside privacy-sandbox-dev directory
6+
make accesstoken
7+
```
Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
// Copyright 2023 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+
// http://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 <cstdlib>
16+
#include <memory>
17+
#include <utility>
18+
19+
#include <gmock/gmock-matchers.h>
20+
#include <include/gmock/gmock-actions.h>
21+
22+
#include "absl/flags/flag.h"
23+
#include "absl/flags/parse.h"
24+
#include "absl/strings/escaping.h"
25+
#include "absl/synchronization/blocking_counter.h"
26+
#include "core/utils/src/base64.h"
27+
#include "glog/logging.h"
28+
#include "gtest/gtest.h"
29+
#include "public/cpio/interface/cpio.h"
30+
#include "quiche/common/quiche_random.h"
31+
#include "quiche/oblivious_http/oblivious_http_client.h"
32+
#include "src/core/lib/event_engine/default_event_engine.h"
33+
#include "src/cpp/accesstoken/src/accesstoken_fetcher_manager.h"
34+
#include "src/cpp/concurrent/event_engine_executor.h"
35+
36+
ABSL_FLAG(std::string, aad_endpoint,
37+
"https://login.microsoftonline.com/"
38+
"afcc81fd-382e-4c87-9f7e-9fdd934dfd9b/oauth2/v2.0/token",
39+
"URL of AAD tenant");
40+
41+
ABSL_FLAG(std::string, api_identifier_uri,
42+
"api://d538182b-fc13-4cf2-a5a5-946db26caef3", "API URI");
43+
44+
ABSL_FLAG(std::string, api_application_id,
45+
"d538182b-fc13-4cf2-a5a5-946db26caef3", "API client id");
46+
47+
ABSL_FLAG(std::string, client_application_id,
48+
"4dcf9615-265c-40e9-93d4-728fbe1d1857", "Application client id");
49+
50+
ABSL_FLAG(std::string, client_secret, "provide_client_secret", "Client secret");
51+
52+
namespace privacy_sandbox::aad_accesstoken {
53+
enum class CloudPlatform {
54+
LOCAL,
55+
GCP,
56+
AWS,
57+
AZURE,
58+
};
59+
namespace {
60+
61+
static constexpr char kPlaintextPayload[] = "plaintext";
62+
// 45 days. Value for private_key_cache_ttl_seconds in
63+
// services/common/constants/common_service_flags.cc
64+
static constexpr unsigned int kDefaultPrivateKeyCacheTtlSeconds = 3888000;
65+
// 3 hours. Value for key_refresh_flow_run_frequency_seconds in
66+
// services/common/constants/common_service_flags.cc
67+
static constexpr unsigned int kDefaultKeyRefreshFlowRunFrequencySeconds = 10800;
68+
69+
using google::scp::core::utils::Base64Decode;
70+
using ::google::scp::cpio::Cpio;
71+
using ::google::scp::cpio::CpioOptions;
72+
using ::google::scp::cpio::LogOption;
73+
using ::testing::HasSubstr;
74+
// using PlatformJwtServiceEndpointMap =
75+
// absl::flat_hash_map<CloudPlatform,
76+
// google::scp::cpio::AccessTokenServiceEndpoint>;
77+
/**
78+
std::unique_ptr<server_common::AccessTokenFetcherInterface>
79+
CreateKeyFetcherManager(
80+
std::unique_ptr<server_common::PublicKeyFetcherInterface>
81+
public_key_fetcher,
82+
const unsigned int private_key_cache_ttl_seconds =
83+
kDefaultPrivateKeyCacheTtlSeconds,
84+
const unsigned int key_refresh_flow_run_frequency_seconds =
85+
kDefaultKeyRefreshFlowRunFrequencySeconds) {
86+
google::scp::cpio::PrivateKeyVendingEndpoint primary, secondary;
87+
// AZURE_TODO: We might have to specify more fields for primary, secondary.
88+
// See services/common/encryption/key_fetcher_factory.cc for what
89+
// the original code does
90+
91+
primary.private_key_vending_service_endpoint =
92+
absl::GetFlag(FLAGS_client_secret);
93+
// AZURE_TODO: make it a command line option
94+
absl::Duration private_key_ttl = absl::Seconds(private_key_cache_ttl_seconds);
95+
std::unique_ptr<server_common::PrivateKeyFetcherInterface>
96+
private_key_fetcher = server_common::PrivateKeyFetcherFactory::Create(
97+
primary, {secondary}, private_key_ttl);
98+
99+
absl::Duration key_refresh_flow_run_freq =
100+
absl::Seconds(key_refresh_flow_run_frequency_seconds);
101+
102+
auto event_engine = std::make_unique<server_common::EventEngineExecutor>(
103+
grpc_event_engine::experimental::CreateEventEngine());
104+
std::unique_ptr<server_common::KeyFetcherManagerInterface> manager =
105+
server_common::KeyFetcherManagerFactory::Create(
106+
key_refresh_flow_run_freq, std::move(public_key_fetcher),
107+
std::move(private_key_fetcher), std::move(event_engine));
108+
manager->Start();
109+
110+
return manager;
111+
}
112+
*/
113+
/**
114+
// Based on services/common/encryption/key_fetcher_factory.cc
115+
std::unique_ptr<server_common::PublicKeyFetcherInterface>
116+
CreatePublicKeyFetcher() {
117+
std::vector<std::string> endpoint = {
118+
absl::GetFlag(FLAGS_aad_endpoint)};
119+
//"client_id=$ClientApplicationId&client_secret=$ClientSecret&scope=$ApiIdentifierUri/.default&grant_type=client_credentials"
120+
std::vector<std::string> clientId = {
121+
absl::GetFlag(FLAGS_client_application_id)};
122+
123+
std::vector<std::string> clientSecret = {
124+
absl::GetFlag(FLAGS_client_secret)};
125+
126+
std::vector<std::string> scope = {
127+
absl::GetFlag(FLAGS_api_identifier_uri)};
128+
129+
server_common::CloudPlatform cloud_platform =
130+
server_common::CloudPlatform::AZURE;
131+
132+
PlatformJwtServiceEndpointMap per_platform_endpoints = {
133+
{cloud_platform, endpoint}};
134+
return server_common::PublicKeyFetcherFactory::Create(per_platform_endpoints);
135+
}
136+
137+
138+
absl::StatusOr<quiche::ObliviousHttpRequest> EncryptAndDecrypt(
139+
std::unique_ptr<server_common::KeyFetcherManagerInterface>
140+
key_fetcher_manager,
141+
const std::string plaintext_payload) {
142+
// AZURE_TODO: There should be a function to select proper value. We can add
143+
// an assertion to check the value is AZURE.
144+
server_common::CloudPlatform cloud_platform =
145+
server_common::CloudPlatform::AZURE;
146+
auto public_key = key_fetcher_manager->GetPublicKey(cloud_platform);
147+
EXPECT_TRUE(public_key.ok());
148+
149+
const absl::StatusOr<uint8_t> key_id =
150+
ToIntKeyId(public_key.value().key_id());
151+
EXPECT_TRUE(key_id.ok());
152+
153+
const auto config =
154+
GetOhttpKeyConfig(key_id.value(), EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
155+
EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
156+
157+
std::string decoded_public_key;
158+
Base64Decode(public_key.value().public_key(), decoded_public_key);
159+
160+
const auto request =
161+
quiche::ObliviousHttpRequest::CreateClientObliviousRequest(
162+
plaintext_payload, decoded_public_key, config);
163+
const std::string payload_bytes = request->EncapsulateAndSerialize();
164+
165+
std::optional<server_common::PrivateKey> private_key =
166+
key_fetcher_manager->GetPrivateKey(std::to_string(key_id.value()));
167+
EXPECT_TRUE(private_key.has_value());
168+
169+
return server_common::DecryptEncapsulatedRequest(private_key.value(),
170+
payload_bytes);
171+
}
172+
173+
class KmsInstance {
174+
public:
175+
KmsInstance() {
176+
std::string aad_endpoint = absl::GetFlag(FLAGS_aad_endpoint);
177+
child_pid_ = fork();
178+
179+
CHECK(child_pid_ != -1) << "Fork failed.";
180+
181+
if (child_pid_ == 0) {
182+
setpgid(0, 0);
183+
int result = system(aad_endpoint.c_str());
184+
}
185+
}
186+
187+
~KmsInstance() {
188+
int result = kill(-child_pid_, SIGTERM);
189+
CHECK(result == 0) << "Failed to kill KMS.";
190+
}
191+
192+
void CreateKeyPair() {
193+
std::string api_identifier_uri =
194+
absl::GetFlag(FLAGS_api_identifier_uri);
195+
int result = system(api_identifier_uri.c_str());
196+
CHECK(result == 0) << "Failed to create a key pair.";
197+
}
198+
199+
private:
200+
pid_t child_pid_;
201+
};
202+
*/
203+
class AccessTokenTest : public testing::Test {
204+
protected:
205+
void SetUp() override {
206+
// Init Cpio
207+
cpio_options_.log_option = google::scp::cpio::LogOption::kConsoleLog;
208+
CHECK(google::scp::cpio::Cpio::InitCpio(cpio_options_).Successful())
209+
<< "Failed to initialize CPIO library";
210+
}
211+
void TearDown() override {
212+
google::scp::cpio::Cpio::ShutdownCpio(cpio_options_);
213+
}
214+
215+
google::scp::cpio::CpioOptions cpio_options_;
216+
// Initialize and shutdown gRPC client. DO NOT REMOVE.
217+
server_common::GrpcInit grpc_init_;
218+
};
219+
220+
TEST_F(AccessTokenTest, RetrieveAccessTokenSuccess) {
221+
// This test case is to demonstrate how to retrieve an accesstoken
222+
223+
privacy_sandbox::server_common::AccessTokenClientOptions tokenOptions;
224+
tokenOptions.endpoint = "your_endpoint";
225+
tokenOptions.clientid = "your_client_id";
226+
tokenOptions.clientSecret = "your_client_secret";
227+
tokenOptions.apiUri = "your_api_uri";
228+
229+
auto accesstoken_fetcher_manager =
230+
privacy_sandbox::server_common::AccessTokenClientFactory::Create(tokenOptions);
231+
}
232+
233+
} // namespace
234+
} // namespace privacy_sandbox::aad_accesstoken
235+
236+
int main(int argc, char** argv) {
237+
absl::ParseCommandLine(argc, argv);
238+
testing::InitGoogleTest(&argc, argv);
239+
return RUN_ALL_TESTS();
240+
}

tools/aad_accesstoken/test

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
3+
# Environment variables:
4+
# - NO_CBUILD: When the value is `1`, it doesn't use cbuild tool and use bazel directly.
5+
6+
set -ex
7+
DIR_OF_THIS_FILE=$(cd $(dirname $0); pwd)
8+
PROJECT_ROOT=$DIR_OF_THIS_FILE/../..
9+
cd $PROJECT_ROOT
10+
11+
PRIVACY_SANDBOX_DEV_DIR=$PROJECT_ROOT/..
12+
COMMAND="bazel"
13+
14+
$COMMAND build //tools/aad_accesstoken:aad_accesstoken --sandbox_debug --config=azure_azure --//:build_flavor=non_prod
15+
./bazel-bin/tools/aad_accesstoken/aad_accesstoken --client_secret=""

0 commit comments

Comments
 (0)