身份验证

客户端登录策略

我们的身份验证方法是通过客户端代码中的「策略」定义的。这些策略是:

  • 密码登录策略:使用电子邮件地址和主密码进行身份验证。

  • 无密码登录策略:使用一次性访问代码的设备登录进行身份验证。

  • API 登录策略:使用 API 密钥和机密进行身份验证。

  • SSO 登录策略:通过 SAML 或 OpenIDConnect 使用 SSO IdP 进行身份验证。

无论采用哪种策略,「登录」Bitwarden 都需要向我们的身份服务器上的 /connect/token 端点 POST 请求。该请求的内容因多种因素而各不相同,但最重要的是登录策略。

客户端请求令牌

对于每一种策略,客户端都会通过其子类形成 TokenRequest

这些请求中的每一个都会重写 toIdentityToken() 方法,该方法负责将 TokenRequest 中的信息转换为将发送到我们的身份服务器上的 /connect/token 端点的有效负载。

所有身份验证请求的公共属性

以下属性是从所有登录策略生成的身份验证请求的公共属性:

特定于类型的身份验证请求属性

密码令牌请求

  • 授权类型password

  • 标头Auth-Email 标头被设置为用户电子邮件地址的 base-64 编码

API 令牌请求

  • 授权类型client_credentials

  • 标头:无

SSO 令牌请求

  • 授权类型authorization_code

  • 标头:无

身份 API 授予访问权限

当身份服务在 /connect/token 端点接收到令牌请求时,两个类之一将根据身份验证请求中指定的授权类型进行接管。

有关每个验证器职责的更多信息,请参阅 IdentityServer4 文档

验证请求

密码令牌验证 (ResourceOwnerPasswordValidator)

哪种授权类型?

该验证器负责颁发 password 授权类型的令牌。

为了使请求得到验证,以下必须为真:

  • Auth-Email 标头必须存在且正确。

  • 该请求不需要 Captcha,或者如果需要,则提供有效的 captchaResponse(详细信息,请参阅 Captcha 文档)。

  • 该请求不需要 2FA,或者如果需要,则提供有效的 twoFactorToken(请参阅 2FA 文档

  • 如果该请求具有 authRequest 属性(即无密码请求),则访问代码有效并且请求尚未过期。

  • 该密码是正确的。这可以是:

    • 主密码哈希与用户的数据库记录匹配,或者

    • 设备登录访问代码尚未过期,并且与客户端提供的 authRequest 上的服务器端代码匹配。

  • 用户不属于要求 SSO 的组织。

API 令牌验证 (CustomTokenRequestValidator)

哪种授权类型?

该验证器负责颁发 client_credential 授权类型的令牌。

有不同类型的客户端可以使用 client_credential 授权类型请求访问权限:

不同的 API 客户端类型都有不同的验证。client_credentials 授权类型验证的关键是内置于 IdentityServer 中的 ClientStore(并在我们的代码中重写)。.NET 请求中间件管道中的每个请求都会查询 ClientStore,以从请求中查找给定了 client_id 的客户端。

SSO 令牌验证 (CustomTokenRequestValidator)

哪种授权类型?

该验证器负责颁发 authorization_code 授权类型的令牌。

请求中的 authorization_code 中的代码验证由 IdentityServer 完成(请参阅此处的文档)。该代码已通过 SSO 流获取,现在被提交给 IdentityServer 以交换 access_token

生成响应

通过给定授权类型的适当逻辑验证了请求后,身份 API 将生成响应。在 Bitwarden,此响应包含一个带有声明的 access_token 以及一个自定义 JSON 对象,其中包含启动密码库解密过程的基本信息。

已知设备

此时,当令牌请求已被验证时,请求设备将被存储并作为「已知设备」与用户关联。

身份验证信息

对于经过验证的密码和 SSO 令牌请求(授予类型为 passwordauthorization_code ),响应将包含 access_token,它是具有以下声明的 JWT:

  • device - 设备标识符。

  • premium - 一个布尔值,指示他们是否有权访问高级功能。

  • email - 用户的电子邮件地址。

  • email_verified - 用户是否已验证其电子邮件地址。

  • sstamp - 用户的安全标记(存储在 User 表中的用户的唯一 GUID,并在生成新密码或密钥时重新生成)。sstamp 改变表示用户需要重新进行身份验证。

  • name - 用户名。

  • 组织声明

    • orgowner - 用户是其所有者的任何组织的 ID

    • orgadmin - 用户是其管理员的任何组织的 ID

    • orgmanager - 用户是其经理的组织的 ID

    • orguser - 用户是其普通用户的组织的 ID

    • orgcustom - 用户拥有自定义权限的组织的 ID。在这种情况下,用户还将按照为该组织定义的方式添加自定义声明。

  • 提供商声明

    • providerprovideradmin - 用户是其管理员的提供商的 ID

    • providerserviceuser - 用户是其普通用户的提供商的 ID

对于 API 令牌请求(授权类型为 client_credentials ),响应因客户端类型而异,如下所示:

解密信息

该响应还将包含一个自定义 JSON 响应对象,该对象包含以下属性:

对于 API 令牌请求,以下附加属性将添加到响应中:

  • ApiUseKeyConnector - 如果用户设置为使用 Key Connector 进行主密码检索,则设置为 true

客户端处理响应

当令牌请求经过验证并将其发送回客户端时,客户端负责将结果数据正确存储在状态中,以便用户可以进行身份​​验证然后可以解密其密码库。

处理令牌响应的核心逻辑位于我们的基础 LoginStrategyprocessTokenResponse() 方法中,我们在其中执行以下操作:

使用身份验证信息来设置用户账户

响应包含一个 JWT access_token,其中包含用户声明,可以在后续 API 请求中提供以对用户进行身份验证,以及一个 refresh_token,可用于请求新的 access_token 而不提示用户再次进行身份验证。

access_token 上的声明用于在状态中初始化用户的 AccountProfileaccess_tokenrefresh_token 在状态中存储在 AccountTokens 中,用于后续 API 请求。

使用解密信息准备解密

AccountKeys (在状态中存储在 account.keys 中)也使用令牌响应中提供的信息在用户账户中设置。

此时设置的关键点是:

设备密钥 (deviceKey)

设备密钥是存储在用户受信任设备上的对称加密密钥,用于在使用受信任设备加密时解密用户的对称加密密钥。

它不会在请求时返回(因为它永远不会离开设备),但此时会在经过身份验证的用户的账户状态上设置它。

用户密钥 (userKey)

用户密钥是用于解密用户密码库的对称加密密钥。

每个登录策略中定义了如何设置用户密钥的具体细节:

  • 密码和设备登录策略

    • 令牌响应中的 Key 存储在帐户状态的 userKeyMasterKey 中,用户输入主密码时已处于状态的 masterKey 用于解密并存储 userKey

  • API策略

    • 令牌响应中的 Key 存储在账户状态的 userKeyMasterKey 中。

    • 如果在令牌响应上设置了 ApiUseKeyConnector 属性,我们将从状态中检索 masterKey 并使用它来解密和存储 userKey

  • 单点登录策略

    • 受信任设备加密为我们提供了多种获取用户密钥的方法,这些方法都在 SSO 登录策略中进行处理。

    • 这些包括:

      • 如果用户处于受信任设备上,则使用设备密钥

      • 使用已批准的管理员批准请求来接收密钥

      • 如果用户有主密码,则使用主密钥

用户私钥 (privateKey)

如果响应中提供了 PrivateKey,它将存储在用户账户状态的 privateKey.encrypted 中。

附录:UserDecryptionOptions

令牌响应将包含 UserDecryptionOptions 的实例。该对象包含以下属性,这些属性描述用户如何解密其密码库。

  • HasMasterPassword - 如果用户在数据库中有主密码,则为 true

  • TrustedDeviceOption - 包含了定义用户是否可以使用受信任设备加密解密其对称密钥的属性。

    • HasAdminApproval - 如果用户可以使用管理员批准来请求批准新的受信任设备,则为 true

    • HasLoginApprovingDevice - 如果用户拥有任何可用于请求批准新的受信任设备的合格设备,则为 true

    • HasManageResetPasswordPermission - 如果用户拥有 ManageResetPassword 权限,则为 true 。这是必需的,以便接收客户端可以知道是否要求用户设置主密码。

    • EncryptedPrivateKey - 如果发出请求的设备是可信的,则这将包含设备特定的私钥,并使用仅存在于受信任设备上的设备密钥进行加密。

    • EncryptedUserKey - 如果发出请求的设备是可信的,则这将包含用户的对称加密密钥,并使用与上面 EncryptedPrivateKey 中的私钥相对应的公钥进行加密。

  • KeyConnectorOption - 包含用户是否可以使用 Key Connector 解密其对称密钥的属性定义。

    • KeyConnectorUrl - Key Connector 实例的 URL。

最后更新于