pie-frost/client-auth

dev-master 2022-06-04 06:15 UTC

This package is auto-updated.

Last update: 2024-09-04 11:24:45 UTC


README

Build Status Psalm Status Latest Stable Version Latest Unstable Version License Downloads

用于与Bifrost认证服务器进行身份验证的客户端库。

安装

使用Composer

composer require pie-frost/client-auth

配置

认证客户端的最小配置如下

  1. 认证服务器的公钥
    • 此外,还有URL,但默认值是正确的
  2. 您的服务器签名密钥对(应作为PASERK密封密钥加载)
  3. 您的服务器域名
<?php
declare(strict_types=1); // Recommended!

/* Namespace imports */
use PIEFrost\ClientAuth\AuthServer;
use PIEFrost\ClientAuth\Config;
use ParagonIE\Paserk\Operations\Key\SealingSecretKey;
use ParagonIE\Paseto\Keys\AsymmetricPublicKey;
use ParagonIE\Paseto\Protocol\Version4;

/* Get from Auth server; auto-discovery coming soon */
$serverPublicKey = new AsymmetricPublicKey(
    '',
    new Version4()
);

/* The defaults are fine. */
$authServer = new AuthServer($serverPublicKey);

/* Generate this once, then persist it.
 *
 * The corresponding Public Key needs to be added to the
 * authentication server.
 */
$mySecretKey = SealingSecretKey::generate(new Version4());
$myPublicKey = $mySecretKey->getPublicKey();
// To get a copy of this key in the format expected by the Auth Server:
// echo $myPublicKey->encode();

$config = (new Config())
    ->withAuthServer($authServer)
    ->withDomain('my-custom-service.foo.bar')
    ->withSecretKey($mySecretKey);

当然还有其他配置选项可用。

使用方法

一旦加载了配置对象,就可以加载并使用客户端。

<?php
declare(strict_types=1); // Recommended!

/* Namespace imports */
use PIEFrost\ClientAuth\AuthServer;
use PIEFrost\ClientAuth\Client;
use PIEFrost\ClientAuth\Config;
use ParagonIE\Paserk\Operations\Key\SealingSecretKey;
use ParagonIE\Paseto\Keys\AsymmetricPublicKey;
use ParagonIE\Paseto\Protocol\Version4;

/** @var Config $config */
$client = Client::fromConfig($config);

创建认证请求令牌

要开始认证请求工作流程,您必须在认证服务器中至少注册一个重定向URL。

您将执行以下步骤

  1. 生成(并持久化,最好在PHP会话中)一个256位的“挑战”秘密。挑战的主要目的是防止重放和混淆代理攻击。
  2. 创建请求令牌。
  3. 将用户重定向到认证服务器,确保指定返回URL和令牌(步骤2)。
<?php
declare(strict_types=1);

use PIEFrost\ClientAuth\Client;
use ParagonIE\ConstantTime\Base64UrlSafe;

/**
 * @var Client $client 
 */
 
$redirectURL = 'https://example.com/bifrost-callback';

// Step 1.
$_SESSION['challenges']['bifrost-auth'] = Base64UrlSafe::encodeUnpadded(random_bytes(32));

// Step 2.
$token = $client->createAuthRequestToken(
    $_SESSION['challenges']['bifrost-auth'],
    $redirectURL
);

// Step 3:
header('Location: ' . $client->getAuthServer()->getAuthUrl([
    'challenge' => 
        $_SESSION['challenges']['bifrost-auth'],
    'url' =>
        $redirectURL,
    'paseto' =>
        $token
]));
exit;

一旦您的用户到达认证服务器,他们将执行必要的步骤进行认证,然后返回到回调URL。

处理认证服务器响应

<?php
declare(strict_types=1); // Recommended!

use PIEFrost\ClientAuth\Client;

/**
 * @var Client $client
 */
if (!isset($_GET['paseto']) || !isset($_SESSION['challenges']['bifrost-auth'])) {
    // Invalid state, redirect user and terminate execution
    header('Location: /');
    exit;
}

$userInfo = $client->processAuthResponse(
    $_GET['paseto'], 
    $_SESSION['challenges']['bifrost-auth']
);
var_dump($userInfo);

成功后,var_dump()将返回以下信息

  1. 认证用户的用户名。
  2. 认证用户的唯一ID。
  3. 给定用户的域名。

您实际上如何使用这些信息由您自己决定。

实际上发生了什么?

PIE-Frost项目有一个实现了具有意见的单点登录协议的认证服务器。

工作流程看起来是这样的

  1. 客户端生成一个随机挑战,然后签署一个包含挑战和回调URL的v4.public PASETO
  2. 用户被重定向到认证服务器,带着步骤1中的PASETO。
    (您可以将这个初始令牌视为您应用的通行证。)
  3. 认证服务器验证PASETO。
    • 如果用户已经登录到服务器,他们将继续进行到步骤4。
    • 否则,他们需要在认证服务器上登录,该服务器只允许使用硬件密钥(WebAuthn)。
    • (涉及服务器端验证步骤,但这些对于客户端理解并不重要。)
  4. 服务器生成其响应令牌。
    1. 服务器使用随机的一次性密钥将用户信息和挑战加密到一个v4.local PASETO中。
    2. 然后使用PASERK k4.seal使用您的应用的公钥将这个随机的一次性密钥加密。
    3. 将上述两个元素打包在一起,并由服务器签名为一个v4.public PASETO。这被提供给用户。
  5. 用户被重定向到您的回调URL,带着步骤4中的令牌。
  6. 验证服务器响应并反序列化。
    1. 外部 v4.public PASETO 的签名已验证。
    2. 一次性密钥使用您的应用程序的秘密密钥解密。
    3. 内部 v4.local PASETO 已解密并验证。
      1. 与第 1 步中生成的 challenge 声明进行比较。
      2. 配置的域名 进行比较。

在第 6 步之后,您拥有一个包含由认证服务器提供的用户信息的密码学认证数据结构。

问答

为什么不直接使用 SAML、OAuth 或 OpenID Connect 呢?

我们希望完全避免 XML、X.509、ASN.1 以及 DER/BER 编码的复杂性。此外,我们还希望 避免使用 JWT

这使我们没有任何选择,因此我们决定构建一个最小化、有偏见的身份验证流程。

设计决策

  1. 在此工作流程中支持的唯一数字签名算法是 Ed25519(包括 WebAuthn)。
  2. 我们将令牌格式限制为 v4.public(Ed25519)和 v4.local(XChaCha20 + BLAKE2b-MAC)PASETO。
  3. 对于非对称加密(用于将用户信息从认证服务器发送到应用程序服务器),我们还允许一个 k4.seal PASERK(临时-静态 X25519 + XChaCha20 + BLAKE2b-MAC)。这可以防止恶意用户了解有关其用户帐户的任何有用信息(例如唯一 ID)。
  4. 我们将挑战放入 k4.seal 加密的 PASERK 中,以确保加密得到尊重,以便在客户端验证挑战。
  5. 所有算法实现均由 libsodium 提供。
  6. 不会进行任何算法选择的运行时协商。
  7. 从 Ed25519 密钥(通过双有理等价)导出 X25519 密钥,因此每个参与者只需管理一个密钥对。