API 验证

bp api-validation

目前,Keystone 有不同的实现方式来验证请求体。此蓝图的目的是跟踪验证发送到 Keystone 服务器的请求体的进度,接受符合资源模式的请求,并拒绝不符合模式的请求。 无论请求针对哪个资源,根据请求体的内容,请求应该始终如一地被接受或拒绝。

问题描述

目前 Keystone 没有一致的请求验证层。 有些资源在资源控制器处验证输入,有些则在后端失败。 理想情况下,Keystone 应该有一些验证机制来捕获不允许的参数,并向用户返回验证错误。

最终用户将受益于一致且有用的反馈,无论他们正在与哪个资源交互。

用例:作为最终用户,我希望无论使用的后端和传递给 Keystone 服务器的值如何,都能观察到一致的 API 验证。

提议的变更

验证 Keystone API 的一种可能方法是使用 jsonschema (https://pypi.python.org/pypi/jsonschema)。 可以使用 jsonschema 验证器对象来检查每个资源是否符合该资源的适当模式。 如果验证通过,则请求可以按照现有的控制流到达资源管理器和后端。 如果请求体参数未通过资源模式指定的验证,则服务器将返回验证错误。

示例:“字段‘email’的输入无效。该值为‘some invalid email value’。

如果属性的值过长,我们可以构建某种截断检查。 例如,如果有人尝试传递 200 个字符的电子邮件地址,我们应该检查这种情况,然后仅返回有用的消息,而不是刷屏日志。 截断非常长的电子邮件地址可能不会提高用户的可读性,因此向用户返回验证失败的消息。

示例:“字段‘email’的输入无效”。

关于执行此实现的一些说明

  • 可以在所有 Keystone 资源中利用常见的参数类型。 一个例子如下

    from keystone.common.validation import parameter_types
    <snip>
    CREATE = {
        'type': 'object',
        'properties': {
            'name': parameter_types.name,
            'description': parameter_types.description,
            'enabled': parameter_types.boolean,
            'url': parameter_types.url
        },
        'required': ['name'],
        'additionalProperties': True,
    }
    
  • 验证可以在控制器层进行。

  • 初始工作将包括捕获现有资源的 Identity API 规范到模式中。 这应该针对 API 的每个主要版本执行一次操作。 这将应用于 Identity V3 API。

  • 当前用于审查的实现方式在资源控制器中使用方法装饰器 [1]。 这是一个相当简单的更改,不会使现有的控制器代码混乱。

  • 在向 Keystone 添加新的扩展时,必须提出新的扩展及其适当的模式。

关于如何处理不同的后端约束,有一些注意事项。 验证器必须遵守 Identity API 规范,但它还必须考虑到特定于后端的案例。 例如,SQL 后端允许 255 个字符的用户名称,但 LDAP 后端对用户名称的长度没有限制。 在这种情况下,我们可以执行以下操作

  • 在控制器层针对最常见的公分母进行验证,在本例中为无限制。

  • 让后端回调验证器,向其提供要验证的值。 例如,SQL 后端了解模式,因此在询问用户名称的限制时,它可以返回 255。

备选方案

另一种选择是将传入请求的属性映射到 Python 对象,并以这种方式强制执行契约。 这可能是一个更艰难的选择,因为 Python 不是严格类型的。

目前,jsonschema 将满足此要求。 如果在某个时候 jsonschema 不再满足验证请求的需求,我们可以研究另一个框架,或者考虑构建我们自己的验证框架,专门针对我们需要的用例。

Voluptuous 可能是另一个用于输入验证的选项。

已经讨论过将 Pecan 作为 Keystone 的 Web 框架。 Pecan 结合 WSME 提供输入验证。 如果/当 Keystone 迁移到使用 Pecan 时,验证层可能会被重构。 此实现应该足够且与 Pecan 兼容,直到决定验证是否与 Pecan 一起存在为止。

数据模型影响

传入请求可以表示为一个对象,在这种情况下,请求对象将具有 jsonschema 验证器作为属性。

此蓝图不应需要数据库迁移或模式更改。

关于将请求实现为对象,jamielennox 在 review 中发布了讨论。

REST API 影响

此蓝图不应影响现有的 API。 如果有影响,它将尽可能地更正 API 以遵循 Identity API 规范。 请参阅 API 变更指南。 如果在已发布的稳定版本中发现错误,我们需要逐个案例地解决,并相应地更新 API 规范。

安全影响

请求验证层输出不应损害数据或向外部用户暴露私有数据。 请求验证不应在验证成功时返回信息。 如果请求体无效,验证层应返回无效值和/或请求所需的值,最终用户应了解这些值。 被验证的资源的参数是公共信息,在 Identity API 规范中描述,不包括私有数据。 如果用户的私有数据验证失败,可以在验证器的错误处理中构建一个检查,以不返回私有数据的实际值。

jsonschema 文档说明了模式和实例的安全注意事项:https://schema.json.js.cn/latest/json-schema-core.html#anchor21

通知影响

其他最终用户影响

性能影响

请求验证所需的更改不需要任何锁定机制。

其他部署者影响

开发人员影响

这将要求向 Keystone 贡献新扩展的开发人员提供表示扩展 API 的适当模式。

实现

负责人

主要负责人:ldbragst (Lance Bragstad <ldbragst@us.ibm.com> <lbragstad@gmail.com>)

其他贡献者:jamielennox (Jamie Lennox <jamielennox@redhat.com>)

工作项

  1. 初始验证器实现,它将包含通用的验证器代码,旨在在验证请求体的所有资源控制器之间共享。

  2. 引入现有核心 API 资源的验证模式。

  3. 引入现有 API 扩展的验证模式。

  4. 强制对提议的核心 API 添加项和扩展进行验证。

依赖项

测试

可以像 Nova V3 API 一样,在每个资源针对其模式进行验证时添加 Tempest 测试。这些测试应该遍历无效的请求类型。

我们可以遵循 Nova V3 API 中已经完成的一些验证工作

负面验证测试应使用 tempest.test.NegativeAutoTest

文档影响

参考资料

[1] [现有工作] (https://review.openstack.org/#/q/status:open+project:openstack/keystone+branch:master+topic:validator,n,z)

有用的链接