summaryrefslogtreecommitdiffstats
path: root/vespalib/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'vespalib/src/tests')
-rw-r--r--vespalib/src/tests/datastore/buffer_type/buffer_type_test.cpp4
-rw-r--r--vespalib/src/tests/net/tls/capabilities/CMakeLists.txt10
-rw-r--r--vespalib/src/tests/net/tls/capabilities/capabilities_test.cpp196
-rw-r--r--vespalib/src/tests/net/tls/openssl_impl/openssl_impl_test.cpp27
-rw-r--r--vespalib/src/tests/net/tls/policy_checking_certificate_verifier/policy_checking_certificate_verifier_test.cpp111
-rw-r--r--vespalib/src/tests/net/tls/transport_options/transport_options_reading_test.cpp62
-rw-r--r--vespalib/src/tests/util/generationhandler_stress/generation_handler_stress_test.cpp4
7 files changed, 341 insertions, 73 deletions
diff --git a/vespalib/src/tests/datastore/buffer_type/buffer_type_test.cpp b/vespalib/src/tests/datastore/buffer_type/buffer_type_test.cpp
index 6988e41add1..de7d899e68a 100644
--- a/vespalib/src/tests/datastore/buffer_type/buffer_type_test.cpp
+++ b/vespalib/src/tests/datastore/buffer_type/buffer_type_test.cpp
@@ -27,7 +27,7 @@ struct Setup {
_allocGrowFactor(0.5),
_resizing(false)
{}
- Setup(const Setup& rhs);
+ Setup(const Setup& rhs) noexcept;
Setup &minArrays(uint32_t value) { _minArrays = value; return *this; }
Setup &used(size_t value) { _usedElems = value; return *this; }
Setup &needed(size_t value) { _neededElems = value; return *this; }
@@ -36,7 +36,7 @@ struct Setup {
Setup &resizing(bool value) { _resizing = value; return *this; }
};
-Setup::Setup(const Setup& rhs)
+Setup::Setup(const Setup& rhs) noexcept
: _minArrays(rhs._minArrays),
_usedElems(rhs._usedElems.load(std::memory_order_relaxed)),
_neededElems(rhs._neededElems),
diff --git a/vespalib/src/tests/net/tls/capabilities/CMakeLists.txt b/vespalib/src/tests/net/tls/capabilities/CMakeLists.txt
new file mode 100644
index 00000000000..4e366674d36
--- /dev/null
+++ b/vespalib/src/tests/net/tls/capabilities/CMakeLists.txt
@@ -0,0 +1,10 @@
+# Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+vespa_add_executable(vespalib_net_tls_capabilities_test_app TEST
+ SOURCES
+ capabilities_test.cpp
+ DEPENDS
+ vespalib
+)
+vespa_add_test(NAME vespalib_net_tls_capabilities_test_app
+ COMMAND vespalib_net_tls_capabilities_test_app)
+
diff --git a/vespalib/src/tests/net/tls/capabilities/capabilities_test.cpp b/vespalib/src/tests/net/tls/capabilities/capabilities_test.cpp
new file mode 100644
index 00000000000..4a20200c631
--- /dev/null
+++ b/vespalib/src/tests/net/tls/capabilities/capabilities_test.cpp
@@ -0,0 +1,196 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/vespalib/net/tls/capability_set.h>
+#include <vespa/vespalib/testkit/test_kit.h>
+
+using namespace vespalib;
+using namespace vespalib::net::tls;
+using namespace std::string_view_literals;
+
+TEST("Capability instances are equality comparable") {
+ auto cap1 = Capability::content_document_api();
+ auto cap2 = Capability::content_document_api();
+ auto cap3 = Capability::content_storage_api();
+ EXPECT_EQUAL(cap1, cap2);
+ EXPECT_EQUAL(cap2, cap1);
+ EXPECT_NOT_EQUAL(cap1, cap3);
+}
+
+TEST("CapabilitySet instances are equality comparable") {
+ const auto cap1 = Capability::content_document_api();
+ const auto cap2 = Capability::content_search_api();
+
+ const auto all_caps = CapabilitySet::make_with_all_capabilities();
+ const auto set_12_a = CapabilitySet::of({cap1, cap2});
+ const auto set_12_b = CapabilitySet::of({cap1, cap2});
+ const auto set_1 = CapabilitySet::of({cap1});
+ const auto empty = CapabilitySet::make_empty();
+
+ EXPECT_EQUAL(all_caps, all_caps);
+ EXPECT_EQUAL(empty, empty);
+ EXPECT_EQUAL(set_12_a, set_12_b);
+ EXPECT_EQUAL(set_12_b, set_12_a);
+
+ EXPECT_NOT_EQUAL(all_caps, empty);
+ EXPECT_NOT_EQUAL(set_12_a, set_1);
+ EXPECT_NOT_EQUAL(set_12_a, all_caps);
+ EXPECT_NOT_EQUAL(set_1, empty);
+}
+
+TEST("Can get underlying name of all Capability instances") {
+ EXPECT_EQUAL(Capability::content_storage_api().name(), "vespa.content.storage_api"sv);
+ EXPECT_EQUAL(Capability::content_document_api().name(), "vespa.content.document_api"sv);
+ EXPECT_EQUAL(Capability::content_search_api().name(), "vespa.content.search_api"sv);
+ EXPECT_EQUAL(Capability::slobrok_api().name(), "vespa.slobrok.api"sv);
+ EXPECT_EQUAL(Capability::content_status_pages().name(), "vespa.content.status_pages"sv);
+ EXPECT_EQUAL(Capability::content_metrics_api().name(), "vespa.content.metrics_api"sv);
+ EXPECT_EQUAL(Capability::content_cluster_controller_internal_state_api().name(),
+ "vespa.content.cluster_controller.internal_state_api"sv);
+}
+
+TEST("Capability instances can be stringified") {
+ EXPECT_EQUAL(Capability::content_storage_api().to_string(), "Capability(vespa.content.storage_api)");
+}
+
+namespace {
+
+void check_capability_mapping(const std::string& name, Capability expected) {
+ auto cap = Capability::find_capability(name);
+ ASSERT_TRUE(cap.has_value());
+ EXPECT_EQUAL(*cap, expected);
+}
+
+void check_capability_set_mapping(const std::string& name, CapabilitySet expected) {
+ auto caps = CapabilitySet::find_capability_set(name);
+ ASSERT_TRUE(caps.has_value());
+ EXPECT_EQUAL(*caps, expected);
+}
+
+}
+
+TEST("All known capabilities can be looked up by name") {
+ check_capability_mapping("vespa.content.storage_api", Capability::content_storage_api());
+ check_capability_mapping("vespa.content.document_api", Capability::content_document_api());
+ check_capability_mapping("vespa.content.search_api", Capability::content_search_api());
+ check_capability_mapping("vespa.slobrok.api", Capability::slobrok_api());
+ check_capability_mapping("vespa.content.status_pages", Capability::content_status_pages());
+ check_capability_mapping("vespa.content.metrics_api", Capability::content_metrics_api());
+ check_capability_mapping("vespa.content.cluster_controller.internal_state_api",
+ Capability::content_cluster_controller_internal_state_api());
+}
+
+TEST("Unknown capability name returns nullopt") {
+ EXPECT_FALSE(Capability::find_capability("vespa.content.stale_cat_memes").has_value());
+}
+
+TEST("CapabilitySet instances can be stringified") {
+ EXPECT_EQUAL(CapabilitySet::content_node().to_string(),
+ "CapabilitySet({vespa.content.storage_api, vespa.content.document_api, vespa.slobrok.api})");
+}
+
+TEST("All known capability sets can be looked up by name") {
+ check_capability_set_mapping("vespa.content_node", CapabilitySet::content_node());
+ check_capability_set_mapping("vespa.container_node", CapabilitySet::container_node());
+ check_capability_set_mapping("vespa.telemetry", CapabilitySet::telemetry());
+ check_capability_set_mapping("vespa.cluster_controller_node", CapabilitySet::cluster_controller_node());
+ check_capability_set_mapping("vespa.config_server", CapabilitySet::config_server());
+}
+
+TEST("Unknown capability set name returns nullopt") {
+ EXPECT_FALSE(CapabilitySet::find_capability_set("vespa.unicorn_launcher").has_value());
+}
+
+TEST("Resolving a capability set adds all its underlying capabilities") {
+ CapabilitySet caps;
+ EXPECT_TRUE(caps.resolve_and_add("vespa.content_node"));
+ // Slightly suboptimal; this test will fail if the default set of capabilities for vespa.content_node changes.
+ EXPECT_EQUAL(caps.count(), 3u);
+ EXPECT_FALSE(caps.empty());
+ EXPECT_TRUE(caps.contains(Capability::content_storage_api()));
+ EXPECT_TRUE(caps.contains(Capability::content_document_api()));
+ EXPECT_TRUE(caps.contains(Capability::slobrok_api()));
+ EXPECT_FALSE(caps.contains(Capability::content_search_api()));
+}
+
+TEST("Resolving a single capability adds it to the underlying capabilities") {
+ CapabilitySet caps;
+ EXPECT_TRUE(caps.resolve_and_add("vespa.slobrok.api"));
+ EXPECT_EQUAL(caps.count(), 1u);
+ EXPECT_FALSE(caps.empty());
+ EXPECT_TRUE(caps.contains(Capability::slobrok_api()));
+ EXPECT_FALSE(caps.contains(Capability::content_storage_api()));
+}
+
+TEST("Resolving an unknown capability set returns false and does not add anything") {
+ CapabilitySet caps;
+ EXPECT_FALSE(caps.resolve_and_add("vespa.distributors_evil_twin_with_an_evil_goatee"));
+ EXPECT_EQUAL(caps.count(), 0u);
+ EXPECT_TRUE(caps.empty());
+}
+
+TEST("Resolving multiple capabilities/sets adds union of capabilities") {
+ CapabilitySet caps;
+ EXPECT_TRUE(caps.resolve_and_add("vespa.content_node")); // CapabilitySet
+ EXPECT_TRUE(caps.resolve_and_add("vespa.container_node")); // ditto
+ EXPECT_EQUAL(caps, CapabilitySet::of({Capability::content_storage_api(), Capability::content_document_api(),
+ Capability::slobrok_api(), Capability::content_search_api()}));
+ EXPECT_TRUE(caps.resolve_and_add("vespa.content.metrics_api")); // Capability (single)
+ EXPECT_EQUAL(caps, CapabilitySet::of({Capability::content_storage_api(), Capability::content_document_api(),
+ Capability::slobrok_api(), Capability::content_search_api(),
+ Capability::content_metrics_api()}));
+}
+
+TEST("Default-constructed CapabilitySet has no capabilities") {
+ CapabilitySet caps;
+ EXPECT_EQUAL(caps.count(), 0u);
+ EXPECT_TRUE(caps.empty());
+ EXPECT_FALSE(caps.contains(Capability::content_storage_api()));
+}
+
+TEST("CapabilitySet can be created with all capabilities") {
+ auto caps = CapabilitySet::make_with_all_capabilities();
+ EXPECT_EQUAL(caps.count(), CapabilitySet::max_count());
+ EXPECT_TRUE(caps.contains(Capability::content_storage_api()));
+ EXPECT_TRUE(caps.contains(Capability::content_metrics_api()));
+ // ... we just assume the rest are present as well.
+}
+
+TEST("CapabilitySet::contains_all() requires an intersection of capabilities") {
+ auto cap1 = Capability::content_document_api();
+ auto cap2 = Capability::content_search_api();
+ auto cap3 = Capability::content_storage_api();
+
+ const auto all_caps = CapabilitySet::make_with_all_capabilities();
+ auto set_123 = CapabilitySet::of({cap1, cap2, cap3});
+ auto set_13 = CapabilitySet::of({cap1, cap3});
+ auto set_2 = CapabilitySet::of({cap2});
+ auto set_23 = CapabilitySet::of({cap2, cap3});
+ auto empty = CapabilitySet::make_empty();
+
+ // Sets contain themselves
+ EXPECT_TRUE(all_caps.contains_all(all_caps));
+ EXPECT_TRUE(set_13.contains_all(set_13));
+ EXPECT_TRUE(set_2.contains_all(set_2));
+ EXPECT_TRUE(empty.contains_all(empty));
+
+ // Supersets contain subsets
+ EXPECT_TRUE(all_caps.contains_all(set_123));
+ EXPECT_TRUE(all_caps.contains_all(set_13));
+ EXPECT_TRUE(set_123.contains_all(set_13));
+ EXPECT_TRUE(set_2.contains_all(empty));
+
+ // Subsets do not contain supersets
+ EXPECT_FALSE(set_123.contains_all(all_caps));
+ EXPECT_FALSE(set_13.contains_all(set_123));
+ EXPECT_FALSE(empty.contains_all(set_2));
+
+ // Partially overlapping sets are not contained in each other
+ EXPECT_FALSE(set_13.contains_all(set_23));
+ EXPECT_FALSE(set_23.contains_all(set_13));
+
+ // Fully disjoint sets are not contained in each other
+ EXPECT_FALSE(set_2.contains_all(set_13));
+ EXPECT_FALSE(set_13.contains_all(set_2));
+}
+
+TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/net/tls/openssl_impl/openssl_impl_test.cpp b/vespalib/src/tests/net/tls/openssl_impl/openssl_impl_test.cpp
index 1de10939bea..3d19c335c19 100644
--- a/vespalib/src/tests/net/tls/openssl_impl/openssl_impl_test.cpp
+++ b/vespalib/src/tests/net/tls/openssl_impl/openssl_impl_test.cpp
@@ -542,7 +542,7 @@ struct PrintingCertificateCallback : CertificateVerificationCallback {
for (auto& dns : peer_creds.dns_sans) {
fprintf(stderr, "Got a DNS SAN entry: %s\n", dns.c_str());
}
- return VerificationResult::make_authorized_for_all_roles();
+ return VerificationResult::make_authorized_with_all_capabilities();
}
};
@@ -551,7 +551,7 @@ struct MockCertificateCallback : CertificateVerificationCallback {
mutable PeerCredentials creds; // only used in single thread testing context
VerificationResult verify(const PeerCredentials& peer_creds) const override {
creds = peer_creds;
- return VerificationResult::make_authorized_for_all_roles();
+ return VerificationResult::make_authorized_with_all_capabilities();
}
};
@@ -712,6 +712,29 @@ TEST_F("Server allows client with certificate that DOES match peer policy", Cert
EXPECT_TRUE(f.handshake());
}
+TEST_F("Authz policy-derived peer capabilities are propagated to CryptoCodec", CertFixture) {
+ auto server_ck = f.create_ca_issued_peer_cert({}, {{"DNS:hello.world.example.com"}});
+ auto authorized = authorized_peers({policy_with({required_san_dns("stale.memes.example.com")},
+ CapabilitySet::of({Capability::content_search_api(),
+ Capability::content_status_pages()})),
+ policy_with({required_san_dns("fresh.memes.example.com")},
+ CapabilitySet::make_with_all_capabilities())});
+ f.reset_server_with_cert_opts(server_ck, std::move(authorized));
+ auto client_ck = f.create_ca_issued_peer_cert({}, {{"DNS:stale.memes.example.com"}});
+ f.reset_client_with_cert_opts(client_ck, AuthorizedPeers::allow_all_authenticated());
+
+ ASSERT_TRUE(f.handshake());
+
+ // Note: "inversion" of client <-> server is because the capabilities are that of the _peer_.
+ auto client_caps = f.server->granted_capabilities();
+ auto server_caps = f.client->granted_capabilities();
+ // Server (from client's PoV) implicitly has all capabilities since client doesn't specify any policies
+ EXPECT_EQUAL(server_caps, CapabilitySet::make_with_all_capabilities());
+ // Client (from server's PoV) only has capabilities for the rule matching its DNS SAN entry
+ EXPECT_EQUAL(client_caps, CapabilitySet::of({Capability::content_search_api(),
+ Capability::content_status_pages()}));
+}
+
void reset_peers_with_server_authz_mode(CertFixture& f, AuthorizationMode authz_mode) {
auto ck = f.create_ca_issued_peer_cert({"hello.world.example.com"}, {});
diff --git a/vespalib/src/tests/net/tls/policy_checking_certificate_verifier/policy_checking_certificate_verifier_test.cpp b/vespalib/src/tests/net/tls/policy_checking_certificate_verifier/policy_checking_certificate_verifier_test.cpp
index fa2bc1a2eaf..c456d7e2a5c 100644
--- a/vespalib/src/tests/net/tls/policy_checking_certificate_verifier/policy_checking_certificate_verifier_test.cpp
+++ b/vespalib/src/tests/net/tls/policy_checking_certificate_verifier/policy_checking_certificate_verifier_test.cpp
@@ -127,9 +127,9 @@ bool verify(AuthorizedPeers authorized_peers, const PeerCredentials& peer_creds)
return verifier->verify(peer_creds).success();
}
-AssumedRoles verify_roles(AuthorizedPeers authorized_peers, const PeerCredentials& peer_creds) {
+CapabilitySet verify_capabilities(AuthorizedPeers authorized_peers, const PeerCredentials& peer_creds) {
auto verifier = create_verify_callback_from(std::move(authorized_peers));
- return verifier->verify(peer_creds).steal_assumed_roles();
+ return verifier->verify(peer_creds).granted_capabilities();
}
TEST("Default-constructed AuthorizedPeers does not allow all authenticated peers") {
@@ -142,14 +142,16 @@ TEST("Specially constructed set of policies allows all authenticated peers") {
EXPECT_TRUE(verify(allow_all, creds_with_dns_sans({{"anything.goes"}})));
}
-TEST("specially constructed set of policies returns wildcard role set") {
+TEST("specially constructed set of policies returns full capability set") {
auto allow_all = AuthorizedPeers::allow_all_authenticated();
- EXPECT_EQUAL(verify_roles(allow_all, creds_with_dns_sans({{"anything.goes"}})), AssumedRoles::make_wildcard_role());
+ EXPECT_EQUAL(verify_capabilities(allow_all, creds_with_dns_sans({{"anything.goes"}})),
+ CapabilitySet::make_with_all_capabilities());
}
-TEST("policy without explicit role set implicitly returns wildcard role set") {
+TEST("policy without explicit capability set implicitly returns full capability set") {
auto authorized = authorized_peers({policy_with({required_san_dns("yolo.swag")})});
- EXPECT_EQUAL(verify_roles(authorized, creds_with_dns_sans({{"yolo.swag"}})), AssumedRoles::make_wildcard_role());
+ EXPECT_EQUAL(verify_capabilities(authorized, creds_with_dns_sans({{"yolo.swag"}})),
+ CapabilitySet::make_with_all_capabilities());
}
TEST("Non-empty policies do not allow all authenticated peers") {
@@ -246,11 +248,11 @@ struct MultiPolicyMatchFixture {
};
MultiPolicyMatchFixture::MultiPolicyMatchFixture()
- : authorized(authorized_peers({policy_with({required_san_dns("hello.world")}, assumed_roles({"r1"})),
- policy_with({required_san_dns("foo.bar")}, assumed_roles({"r2"})),
- policy_with({required_san_dns("zoid.berg")}, assumed_roles({"r2", "r3"})),
- policy_with({required_san_dns("secret.sauce")}, AssumedRoles::make_wildcard_role()),
- policy_with({required_san_uri("zoid://be.rg/")}, assumed_roles({"r4"}))}))
+ : authorized(authorized_peers({policy_with({required_san_dns("hello.world")}, CapabilitySet::of({cap_1()})),
+ policy_with({required_san_dns("foo.bar")}, CapabilitySet::of({cap_2()})),
+ policy_with({required_san_dns("zoid.berg")}, CapabilitySet::of({cap_2(), cap_3()})),
+ policy_with({required_san_dns("secret.sauce")}, CapabilitySet::make_with_all_capabilities()),
+ policy_with({required_san_uri("zoid://be.rg/")}, CapabilitySet::of({cap_4()}))}))
{}
MultiPolicyMatchFixture::~MultiPolicyMatchFixture() = default;
@@ -262,32 +264,37 @@ TEST_F("peer verifies if it matches at least 1 policy of multiple", MultiPolicyM
EXPECT_TRUE(verify(f.authorized, creds_with_uri_sans({{"zoid://be.rg/"}})));
}
-TEST_F("role set is returned for single matched policy", MultiPolicyMatchFixture) {
- EXPECT_EQUAL(verify_roles(f.authorized, creds_with_dns_sans({{"hello.world"}})), assumed_roles({"r1"}));
- EXPECT_EQUAL(verify_roles(f.authorized, creds_with_dns_sans({{"foo.bar"}})), assumed_roles({"r2"}));
- EXPECT_EQUAL(verify_roles(f.authorized, creds_with_dns_sans({{"zoid.berg"}})), assumed_roles({"r2", "r3"}));
- EXPECT_EQUAL(verify_roles(f.authorized, creds_with_dns_sans({{"secret.sauce"}})), AssumedRoles::make_wildcard_role());
- EXPECT_EQUAL(verify_roles(f.authorized, creds_with_uri_sans({{"zoid://be.rg/"}})), assumed_roles({"r4"}));
+TEST_F("capability set is returned for single matched policy", MultiPolicyMatchFixture) {
+ EXPECT_EQUAL(verify_capabilities(f.authorized, creds_with_dns_sans({{"hello.world"}})),
+ CapabilitySet::of({cap_1()}));
+ EXPECT_EQUAL(verify_capabilities(f.authorized, creds_with_dns_sans({{"foo.bar"}})),
+ CapabilitySet::of({cap_2()}));
+ EXPECT_EQUAL(verify_capabilities(f.authorized, creds_with_dns_sans({{"zoid.berg"}})),
+ CapabilitySet::of({cap_2(), cap_3()}));
+ EXPECT_EQUAL(verify_capabilities(f.authorized, creds_with_dns_sans({{"secret.sauce"}})),
+ CapabilitySet::make_with_all_capabilities());
+ EXPECT_EQUAL(verify_capabilities(f.authorized, creds_with_uri_sans({{"zoid://be.rg/"}})),
+ CapabilitySet::of({cap_4()}));
}
TEST_F("peer verifies if it matches multiple policies", MultiPolicyMatchFixture) {
EXPECT_TRUE(verify(f.authorized, creds_with_dns_sans({{"hello.world"}, {"zoid.berg"}})));
}
-TEST_F("union role set is returned if multiple policies match", MultiPolicyMatchFixture) {
- EXPECT_EQUAL(verify_roles(f.authorized, creds_with_dns_sans({{"hello.world"}, {"foo.bar"}, {"zoid.berg"}})),
- assumed_roles({"r1", "r2", "r3"}));
- // Wildcard role is tracked as a distinct role string
- EXPECT_EQUAL(verify_roles(f.authorized, creds_with_dns_sans({{"hello.world"}, {"foo.bar"}, {"secret.sauce"}})),
- assumed_roles({"r1", "r2", "*"}));
+TEST_F("union capability set is returned if multiple policies match", MultiPolicyMatchFixture) {
+ EXPECT_EQUAL(verify_capabilities(f.authorized, creds_with_dns_sans({{"hello.world"}, {"foo.bar"}, {"zoid.berg"}})),
+ CapabilitySet::of({cap_1(), cap_2(), cap_3()}));
+ EXPECT_EQUAL(verify_capabilities(f.authorized, creds_with_dns_sans({{"hello.world"}, {"foo.bar"}, {"secret.sauce"}})),
+ CapabilitySet::make_with_all_capabilities());
}
TEST_F("peer must match at least 1 of multiple policies", MultiPolicyMatchFixture) {
EXPECT_FALSE(verify(f.authorized, creds_with_dns_sans({{"does.not.exist"}})));
}
-TEST_F("empty role set is returned if no policies match", MultiPolicyMatchFixture) {
- EXPECT_EQUAL(verify_roles(f.authorized, creds_with_dns_sans({{"does.not.exist"}})), AssumedRoles::make_empty());
+TEST_F("empty capability set is returned if no policies match", MultiPolicyMatchFixture) {
+ EXPECT_EQUAL(verify_capabilities(f.authorized, creds_with_dns_sans({{"does.not.exist"}})),
+ CapabilitySet::make_empty());
}
TEST("CN requirement without glob pattern is matched as exact string") {
@@ -308,62 +315,32 @@ TEST("CN requirement can include glob wildcards") {
EXPECT_FALSE(verify(authorized, creds_with_cn("world")));
}
-TEST("AssumedRoles by default contains no roles") {
- AssumedRoles roles;
- EXPECT_TRUE(roles.empty());
- EXPECT_FALSE(roles.can_assume_role("foo"));
- auto empty = AssumedRoles::make_empty();
- EXPECT_EQUAL(roles, empty);
-}
-
-TEST("AssumedRoles can be constructed with an explicit set of roles") {
- auto roles = AssumedRoles::make_for_roles({"foo", "bar"});
- EXPECT_TRUE(roles.can_assume_role("foo"));
- EXPECT_TRUE(roles.can_assume_role("bar"));
- EXPECT_FALSE(roles.can_assume_role("baz"));
-}
-
-TEST("AssumedRoles wildcard role can assume any role") {
- auto roles = AssumedRoles::make_wildcard_role();
- EXPECT_TRUE(roles.can_assume_role("foo"));
- EXPECT_TRUE(roles.can_assume_role("bar"));
-}
-
-TEST("AssumedRolesBuilder builds union set of added roles") {
- AssumedRolesBuilder builder;
- builder.add_union(AssumedRoles::make_for_roles({"hello", "world"}));
- builder.add_union(AssumedRoles::make_for_roles({"hello", "moon"}));
- builder.add_union(AssumedRoles::make_for_roles({"goodbye", "moon"}));
- auto roles = builder.build_with_move();
- EXPECT_EQUAL(roles, AssumedRoles::make_for_roles({"hello", "goodbye", "moon", "world"}));
-}
-
TEST("VerificationResult is not authorized by default") {
VerificationResult result;
EXPECT_FALSE(result.success());
- EXPECT_TRUE(result.assumed_roles().empty());
+ EXPECT_TRUE(result.granted_capabilities().empty());
}
TEST("VerificationResult can be explicitly created as not authorized") {
auto result = VerificationResult::make_not_authorized();
EXPECT_FALSE(result.success());
- EXPECT_TRUE(result.assumed_roles().empty());
+ EXPECT_TRUE(result.granted_capabilities().empty());
}
-TEST("VerificationResult can be pre-authorized for all roles") {
- auto result = VerificationResult::make_authorized_for_all_roles();
+TEST("VerificationResult can be pre-authorized with all capabilities") {
+ auto result = VerificationResult::make_authorized_with_all_capabilities();
EXPECT_TRUE(result.success());
- EXPECT_FALSE(result.assumed_roles().empty());
- EXPECT_TRUE(result.assumed_roles().can_assume_role("foo"));
+ EXPECT_FALSE(result.granted_capabilities().empty());
+ EXPECT_EQUAL(result.granted_capabilities(), CapabilitySet::make_with_all_capabilities());
}
-TEST("VerificationResult can be pre-authorized for an explicit set of roles") {
- auto result = VerificationResult::make_authorized_for_roles(AssumedRoles::make_for_roles({"elden", "ring"}));
+TEST("VerificationResult can be pre-authorized for an explicit set of capabilities") {
+ auto result = VerificationResult::make_authorized_with_capabilities(CapabilitySet::of({cap_2(), cap_3()}));
EXPECT_TRUE(result.success());
- EXPECT_FALSE(result.assumed_roles().empty());
- EXPECT_TRUE(result.assumed_roles().can_assume_role("elden"));
- EXPECT_TRUE(result.assumed_roles().can_assume_role("ring"));
- EXPECT_FALSE(result.assumed_roles().can_assume_role("O you don't have the right"));
+ EXPECT_FALSE(result.granted_capabilities().empty());
+ EXPECT_TRUE(result.granted_capabilities().contains(cap_2()));
+ EXPECT_TRUE(result.granted_capabilities().contains(cap_3()));
+ EXPECT_FALSE(result.granted_capabilities().contains(cap_1()));
}
// TODO test CN _and_ SAN
diff --git a/vespalib/src/tests/net/tls/transport_options/transport_options_reading_test.cpp b/vespalib/src/tests/net/tls/transport_options/transport_options_reading_test.cpp
index be2c63b03f2..8d49bdbf73d 100644
--- a/vespalib/src/tests/net/tls/transport_options/transport_options_reading_test.cpp
+++ b/vespalib/src/tests/net/tls/transport_options/transport_options_reading_test.cpp
@@ -198,6 +198,68 @@ TEST("unknown fields are ignored at parse-time") {
EXPECT_TRUE(read_options_from_json_string(json).get() != nullptr); // And no exception thrown.
}
+TEST("policy without explicit capabilities implicitly get all capabilities") {
+ const char* json = R"({
+ "required-credentials":[
+ {"field": "SAN_DNS", "must-match": "hello.world"}
+ ]
+ })";
+ EXPECT_EQUAL(authorized_peers({policy_with({required_san_dns("hello.world")},
+ CapabilitySet::make_with_all_capabilities())}),
+ parse_policies(json).authorized_peers());
+}
+
+TEST("specifying a capability set adds all its underlying capabilities") {
+ const char* json = R"({
+ "required-credentials":[
+ {"field": "SAN_DNS", "must-match": "*.cool-content-clusters.example" }
+ ],
+ "capabilities": ["vespa.content_node"]
+ })";
+ EXPECT_EQUAL(authorized_peers({policy_with({required_san_dns("*.cool-content-clusters.example")},
+ CapabilitySet::content_node())}),
+ parse_policies(json).authorized_peers());
+}
+
+TEST("can specify single leaf capabilities") {
+ const char* json = R"({
+ "required-credentials":[
+ {"field": "SAN_DNS", "must-match": "*.cool-content-clusters.example" }
+ ],
+ "capabilities": ["vespa.content.metrics_api", "vespa.slobrok.api"]
+ })";
+ EXPECT_EQUAL(authorized_peers({policy_with({required_san_dns("*.cool-content-clusters.example")},
+ CapabilitySet::of({Capability::content_metrics_api(),
+ Capability::slobrok_api()}))}),
+ parse_policies(json).authorized_peers());
+}
+
+TEST("specifying multiple capability sets adds union of underlying capabilities") {
+ const char* json = R"({
+ "required-credentials":[
+ {"field": "SAN_DNS", "must-match": "*.cool-content-clusters.example" }
+ ],
+ "capabilities": ["vespa.content_node", "vespa.container_node"]
+ })";
+ CapabilitySet caps;
+ caps.add_all(CapabilitySet::content_node());
+ caps.add_all(CapabilitySet::container_node());
+ EXPECT_EQUAL(authorized_peers({policy_with({required_san_dns("*.cool-content-clusters.example")}, caps)}),
+ parse_policies(json).authorized_peers());
+}
+
+TEST("empty capabilities array is not allowed") {
+ const char* json = R"({
+ "required-credentials":[
+ {"field": "SAN_DNS", "must-match": "*.cool-content-clusters.example" }
+ ],
+ "capabilities": []
+ })";
+ EXPECT_EXCEPTION(parse_policies(json), vespalib::IllegalArgumentException,
+ "\"capabilities\" array must either be not present (implies "
+ "all capabilities) or contain at least one capability name");
+}
+
// TODO test parsing of multiple policies
TEST_MAIN() { TEST_RUN_ALL(); }
diff --git a/vespalib/src/tests/util/generationhandler_stress/generation_handler_stress_test.cpp b/vespalib/src/tests/util/generationhandler_stress/generation_handler_stress_test.cpp
index 57c765b8e44..74af25b54a8 100644
--- a/vespalib/src/tests/util/generationhandler_stress/generation_handler_stress_test.cpp
+++ b/vespalib/src/tests/util/generationhandler_stress/generation_handler_stress_test.cpp
@@ -48,11 +48,11 @@ struct IndirectContext {
static constexpr size_t values_size = 65536;
uint64_t _values[values_size];
- IndirectContext();
+ IndirectContext() noexcept;
uint64_t* calc_value_ptr(uint64_t idx) { return &_values[(idx & (values_size - 1))]; }
};
-IndirectContext::IndirectContext()
+IndirectContext::IndirectContext() noexcept
: _value_ptr(nullptr),
_pad(),
_values()