From: Casey Bodley Date: Tue, 3 Feb 2026 16:44:45 +0000 (-0500) Subject: rgw/iam: match value of Null condition X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=1d0c8c286ccb39ca1afd809dec7669001853e4b2;p=ceph.git rgw/iam: match value of Null condition quoting https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html#Conditions_Null: > Use a Null condition operator to check if a condition key is absent at the time of authorization. In the policy statement, use either true (the key doesn't exist — it is null) or false (the key exists and its value is not null). previously, this check acted as if it was always given a value of "true". instead, convert this decision to a "true"/"false" string and use `typed_any()` to match that against the parsed `vals` `runtime_vals` are ignored here because the same document says: > You can not use a policy variable with the Null condition operator. Fixes: https://tracker.ceph.com/issues/74736 Signed-off-by: Casey Bodley --- diff --git a/src/rgw/rgw_iam_policy.cc b/src/rgw/rgw_iam_policy.cc index ecd704da78ed..5ef051c7a977 100644 --- a/src/rgw/rgw_iam_policy.cc +++ b/src/rgw/rgw_iam_policy.cc @@ -875,7 +875,8 @@ bool Condition::eval(const Environment& env) const { std::vector runtime_vals; auto i = env.find(key); if (op == TokenID::Null) { - return i == env.end() ? true : false; + const std::string value = (i == env.end() ? "true" : "false"); + return typed_any(std::equal_to{}, as_bool, value, vals); } if (i == env.end()) { diff --git a/src/test/rgw/test_rgw_iam_policy.cc b/src/test/rgw/test_rgw_iam_policy.cc index c67f92582bd9..956db92c1443 100644 --- a/src/test/rgw/test_rgw_iam_policy.cc +++ b/src/test/rgw/test_rgw_iam_policy.cc @@ -1763,3 +1763,26 @@ TEST_F(ConditionTest, StringNotLikeLogic) EXPECT_TRUE(stringNotLike.eval({{key, "public/document.pdf"}})); } } + +TEST_F(ConditionTest, Null) +{ + const std::string key = "s3:prefix"; + + { + // "Null": {"s3:prefix": "true"} + Condition isNull{TokenID::Null, key.data(), key.size(), false}; + isNull.vals.push_back("true"); + + EXPECT_TRUE(isNull.eval({})); + EXPECT_FALSE(isNull.eval({{key, "admin/config.txt"}})); + } + + { + // "Null": {"s3:prefix": "false"} + Condition notNull{TokenID::Null, key.data(), key.size(), false}; + notNull.vals.push_back("false"); + + EXPECT_FALSE(notNull.eval({})); + EXPECT_TRUE(notNull.eval({{key, "admin/config.txt"}})); + } +}