'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/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] 对象的 toPort
值为 22
但 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
}
}
}
}
}
}
}
您需要向架构中添加一个 "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
一般策略是先定义属性,然后分别使用 anyOf
、oneOf
、allOf
、not
、[=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"] }
}
}
}
}
我正在尝试编写一个架构来验证 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/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] 对象的 toPort
值为 22
但 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
}
}
}
}
}
}
}
您需要向架构中添加一个 "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
一般策略是先定义属性,然后分别使用 anyOf
、oneOf
、allOf
、not
、[=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"] }
}
}
}
}