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

时间:2016-10-06 00:58:23

标签: json schema jsonschema

我正在尝试编写架构以验证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"
}

ipRanges0.0.0.0/0时,toPort的值为22

以下JSON文档应通过验证 -

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

因为ipPermissions index [0]对象的toPort22,但ipRanges[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
            }
          }
        }
      }
    }
  }
}

2 个答案:

答案 0 :(得分:3)

这个有点复杂,所以我使用oneOf将其分解,以便更容易理解。

#/定义/ ipPermission

一般策略是首先定义属性,然后使用allOfnotdependenciesnot和/或{{1分别添加复杂约束}}。在这种情况下,我采用的方法是定义一个匹配您要禁止的情况的模式,如果该模式匹配则使用contains验证失败。

#/定义/端口22 - 和 - 0.0.0.0-0

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

#/定义/阵列包含-0.0.0.0-0

我们不能直接约束数组包含“0.0.0.0/0”,但是我们可以创建一个禁止“0.0.0.0/0”在数组中的模式。如果这样的模式在数组中不存在“0.0.0.0 \ 0”时有效,那么任何未验证的JSON必须至少包含一个“0.0.0.0/0”的实例。

#/定义/阵列而不-0.0.0.0-0

这描述了禁止用于实现{ "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"] } } } } } 约束的“0.0.0.0/0”的数组。

{{1}}

答案 1 :(得分:0)

您需要添加" 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"
        }
    ]
}