【问题标题】:'oneOf' not working as expected - json validation must fail but it is passing'oneOf' 未按预期工作 - json 验证必须失败,但它正在通过
【发布时间】:2017-02-14 14:27:17
【问题描述】:

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

toPort22 时,ipRanges 的值为0.0.0.0/0

以下 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
            }
          }
        }
      }
    }
  }
}

【问题讨论】:

  • 我无法弄清楚您要表达什么。您能否扩展您的描述和/或添加更多应该通过和应该失败的示例?
  • @Json 我提供了更多示例。

标签: json schema jsonschema


【解决方案1】:

您需要在架构中添加“必需”节点。但是,在这种情况下,它还需要指定 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"
        }
    ]
}

【讨论】:

  • 感谢您的帮助,我使用以下 JSON { "ipPermissions": [ { "toPort": 22, "fromPort": -1 }, { "fromPort": 53, " ipRanges": [ "0.0.0.0/0" ], "ipProtocol": "tcp" } ] } 但它通过了验证,但它不应该通过。
  • @user375868 只允许 toPortipProtocol 之一。这是我对您的要求的理解。如果不是这种情况,请准确说明您的要求是什么。您在评论中提供的不应验证的 JSON 是什么?
  • 请查看更新后的问题。我提供了更多示例
【解决方案2】:

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

#/definitions/ipPermission

一般策略是先定义属性,然后使用anyOfoneOfallOfnot 和/或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\0”不在数组中,那么这样的模式是有效的,那么任何不验证的 JSON 都必须包含至少一个“0.0.0.0/0”的实例。

#/definitions/array-without-0.0.0.0-0

这描述了用于实现contains约束的禁止“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"] }
      }
    }
  }
}

【讨论】:

  • 实际上我用文档 { "ipPermissions": [ { "toPort": 22, "fromPort": -1 }, { "fromPort": 53, "ipRanges": [ "0.0.0.0/0" ], "ipProtocol": "tcp" } ] } 但它通过了验证
  • 这部分应该失败?第一项没有“ipRanges”,所以我希望它通过。第二项没有“toPort”属性,所以我希望它也能通过。我错过了什么?
  • 我的错。我使用不正确的 json 进行测试。我会做更多的测试,很快就会给你+100的赏金!非常感谢您的帮助。
  • 太棒了!很高兴我能帮上忙。
猜你喜欢
  • 2020-04-10
  • 2013-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-27
  • 2012-09-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多