'oneOf' 未按预期工作 - json 验证必须失败但它正在通过

'oneOf' not working as expected - json validation must fail but it is passing

我正在尝试编写一个架构来验证 AWS IAM 安全组绝不能指定传入 IP 地址“0.0.0.0/0”可以连接到端口 22。

我正在使用 oneOf 运算符并定义两组属性,我的直觉是如果这两个属性都满足,JSON 模式应该会失败,但事实并非如此。

示例 JSON -

{
  "ipPermissions": [
    {
      "toPort": -1,
      "fromPort": -1,
      "ipRanges": [
        "10.0.0.0/16"
      ]
    },
    {
      "toPort": 22,
      "fromPort": 53,
      "ipRanges": [
        "0.0.0.0/0"
      ],
      "ipProtocol": "tcp"
    }
  ]
}

上面的 JSON 应该失败 因为 ipPermission[1] 对象是-

{
      "toPort": 22,
      "fromPort": 53,
      "ipRanges": [
        "0.0.0.0/0"
      ],
      "ipProtocol": "tcp"
}

因为 ipRanges 的值是 0.0.0.0/0toPort22

以下 JSON 文档应通过验证-

{
      "ipPermissions": [
        {
          "toPort": 22,
          "fromPort": -1,
          "ipRanges": [
            "10.0.0.0/16"
          ]
        },
        {
          "toPort": 22,
          "fromPort": 53,
          "ipRanges": [
            "somethingElse"
          ],
          "ipProtocol": "tcp"
        }
      ]
    }

因为 ipPermissions index[0] 对象的 toPort 值为 22ipRanges[0] 的值为 10.0.0.0/16 而不是 0.0.0.0/0

以下 JSON 不应通过验证 -

{
  "ipPermissions": [
    {
      "toPort": 22,
      "fromPort": -1,
      "ipRanges": [
        "10.0.0.0/16"
      ]
    },
    {
      "toPort": 22,
      "fromPort": 53,
      "ipRanges": [
        "somethingElse",
        "0.0.0.0/0"
      ],
      "ipProtocol": "tcp"
    }
  ]
}

因为 ipPermissions[1].ipRanges[1] 值是 0.0.0.0/0

我的 JSON 架构-

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "required": [
    "ipPermissions"
  ],
  "properties": {
    "ipPermissions": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "oneOf": {
            "ipRanges": {
              "type": "array",
              "items": {
                "type": "string",
                "value": "0.0.0.0/0"
              }
            },
            "toPort": {
              "type": "integer",
              "minimum": 23
            }
          }
        }
      }
    }
  }
}

您需要向架构中添加一个 "required" 节点。但是,在这种情况下,它还需要指定 N 个允许的节点之一:

{
    "$schema":"http://json-schema.org/draft-04/schema#",
    "required":[
        "ipPermissions"
    ],
    "properties":{
        "ipPermissions":{
            "type":"array",
            "items":{
                "type":"object",
                "properties":{
                    "oneOf":{
                        "ipRanges":{
                            "type":"array",
                            "items":{
                                "type":"string",
                                "value":"0.0.0.0/0"
                            }
                        },
                        "toPort":{
                            "type":"integer",
                            "minimum":23
                        }
                    }
                },
                "oneOf":[
                    {
                        "required":[
                            "ipRanges"
                        ]
                    },
                    {
                        "required":[
                            "toPort"
                        ]
                    }
                ]
            }
        }
    }
}

这将验证具有 ipRanges 节点或 toPort 节点的实例,但不会同时验证两者,例如:

{
    "ipPermissions":[
        {
            "toPort":-1,
            "fromPort":-1
        },
        {
            "fromPort":53,
            "ipRanges":[
                "0.0.0.0/0"
            ],
            "ipProtocol":"tcp"
        }
    ]
}

这个有点复杂,所以我用 definitions 分解了它,希望它更容易理解。

#/definitions/ipPermission

一般策略是先定义属性,然后分别使用 anyOfoneOfallOfnot、[=41= 添加复杂的约束条件] dependencies。在这种情况下,我采用的方法是定义一个与您要禁止的情况相匹配的模式,如果该模式匹配,则使用 not 使验证失败。

#/definitions/port-22-and-0.0.0.0-0

这是验证 "toPort" 是否为“22”且 "ipRanges" 数组是否包含“0.0.0.0/0”的模式。不幸的是,JSON Schema 还没有 contains 关键字,因此我们必须做一些布尔逻辑体操来表达该约束。

#/definitions/array-contains-0.0.0.0-0

我们不能直接限制数组包含“0.0.0.0/0”,但我们可以创建一个架构来禁止“0.0.0.0/0”出现在数组中。如果“0.0.0.0[=45=]”不在数组中,则给出这样一个有效的架构,那么任何未验证的 JSON 必须至少包含一个“0.0.0.0/0”的实例".

#/definitions/array-without-0.0.0.0-0

这描述了禁止“0.0.0.0/0”的数组,用于实现contains约束。

{
  "type": "object",
  "required": ["ipPermissions"],
  "properties": {
    "ipPermissions": {
      "type": "array",
      "items": { "$ref": "#/definitions/ipPermission" }
    }
  },
  "definitions": {
    "ipPermission": {
      "type": "object",
      "properties": {
        "toPort": { ... },
        "fromPort": { ... },
        "ipRanges": { ... },
        "ipProtocol": { ... }
      }
      "not": { "$ref": "#/definitions/port-22-and-0.0.0.0-0"}
    },
    "port-22-and-0.0.0.0-0": {
      "type": "object",
      "properties": {
        "toPort": { "enum": [22] },
        "ipRanges": { "$ref": "#/definitions/array-contains-0.0.0.0-0" }
      },
      "required": ["toPort", "ipRanges"]
    },
    "array-contains-0.0.0.0-0": {
      "not": { "$ref": "#/definitions/array-without-0.0.0.0-0" }
    },
    "array-without-0.0.0.0-0": {
      "type": "array",
      "items": {
        "not": { "enum": ["0.0.0.0/0"] }
      }
    }
  }
}