tiqr/tiqr-server-libphp

tiqr认证的PHP库。

4.3.1 2024-08-06 10:46 UTC

README

主分支 test-integration workflow Scrutinizer Code Quality
开发分支 test-integration workflow Scrutinizer Code Quality

用于实现Tiqr认证服务器的PHP库

该库包含一个测试服务器,有关详细信息,请参阅其README。阅读包含的SECURITY.md,了解使用此库时的安全考虑。

介绍

此项目是Tiqr服务器实现库的PHP实现。此库本身不是一个服务器,而是包含帮助Tiqr服务器实现执行多个任务的功能。您需要编写代码以提供Tiqr客户端的HTTP API,并创建用户用于注册和认证的Web界面。此库帮助完成大部分工作,包括

  1. 处理Tiqr协议(OCRA)的认证和注册流程
  2. 存储用户认证和用户密钥数据
  3. 发送推送通知(Firebase云消息,Apple推送通知)
  4. 存储应用程序状态(在注册和认证流程中的状态持久化)

实现Tiqr时,您需要了解Tiqr协议。这在Tiqr协议文档中有记录。

谁应该使用此库?

基本上是任何想要为其Tiqr客户端应用程序(Android和iOS)实现Tiqr服务器的人。

历史

此项目在时间线上的重要点概述

  • 2010年:此项目最初于2010年创建
  • 2012年:该项目从本地SVN迁移到GitHub
  • 2014年:创建了UserSecretStorage和Ocra实现
  • 2015年:添加了GCM推送消息支持,并执行了多项清理任务
  • 2019年:添加了FCM推送消息支持
  • 2020年:删除了对PHP 5的支持
  • 2022年:添加了单元测试和集成测试覆盖率,添加了TestServer
  • 2022年:3.3:对UserStorage和UserSecretStorage类进行重大重构,添加PSR日志记录,删除已弃用功能,加强安全性
  • 2023年:4.0:切换到composer自动加载器,添加PHP 8支持,删除APNS v1和Zend库依赖
  • 2024年:4.1:将FCM更新为使用HTTP v1 API以获取Google PN,为UserSecretStorage添加openssl加密类型

生态系统

tiqr-server-libphp对外部库的使用非常谨慎。它使用库来发送推送通知和生成QR代码图像。

库的其他代码是纯PHP代码。

为了测试目的,我们使用了额外的开发依赖项。它们包括像PHPUnit和Mockery这样的知名测试工具。

TestServer

该库包含一个针对tiqr客户端的开发者和测试人员的Tiqr TestServer。有关更多信息,请参阅TestServer README

未来策略

  • 在代码上拥有稳健的测试覆盖率应该在每个新功能创建或错误修复中具有高优先级。

使用库

如果您想自己实现Tiqr服务器,可以查看Tiqr GSSP如何使用这个库。Tiqr是OpenConext Stepup生态系统中的一个重要第二因素身份验证方法,这个库被Tiqr GSSP使用。

使用这个库的另一个示例是库中包含的Tiqr TestServer

tiqr-server-libphp的API可以在library/tiqr/Tiqr中以Tiqr_开头的类中找到。这里找到的显著类包括

安全性

请阅读包含的SECURITY.md,了解使用Tiqr和此库时的安全注意事项。

创建服务

如何配置、创建和使用Tiqr Service的示例。

配置

要创建Tiqr服务,您需要为其提供Tiqr_Service的配置选项以及Tiqr_StateStorage的配置。Tiqr_StateStorage用于将tiqr客户端的API调用与您的tiqr服务器web界面的API调用链接起来。您必须选择并配置您想要使用的类型 - 例如,(例如pdo)对应于类(例如,类型pdo将使用Tiqr_StateStorage_PDO)。

所有配置选项的文档可以在Tiqr_Service类中找到。

APNS和FCM配置以及令牌交换配置仅适用于向iOS和Android客户端发送推送通知。这些推送通知是启动已知用户身份验证的替代方法之一,您需要发布自己的应用程序,以自己的名义。如果不使用推送通知,则用户必须始终扫描QR码。

// Options for Tiqr_Service
$options = [
    // General settings
    'auth.protocol' => 'tiqrauth',
    'enroll.protocol' => 'tiqrenroll',
    'ocra.suite' => 'OCRA-1:HOTP-SHA1-6:QH10-S',
    'identifier' => 'tiqr.example.com',
    'name' => "TestServerController https://tiqr.example.com",
    'logoUrl' => "https://tiqr.example.com/logoUrl",
    'infoUrl' => "https://tiqr.example.com/infoUrl",

    // APNS configuration, required for sending push notifications to iOS devices
    'apns.certificate' => 'files/apns.pem',
    'apns.environment' => 'production',
    
    //FCM configuration, required for sending push notifications to Android devices
    'firebase.projectId' => '12345-abcde',
    'firebase.credentialsFile' => 'google.json',    

    // Session storage
    'statestorage' => [
        'type' => 'pdo',
        'dsn' => 'mysql:host=localhost;dbname=state_store'
        'username' => 'state_rw'
        'password' => 'secret'
        'cleanup_probability' => 0.75
    ],

    // Token exchange configuration (deprecated)
    'devicestorage' => [
        'type' => 'tokenexchange',
        'url' => 'tx://tiqr.example.com',
        'appid' => 'app_id',
    ],
]

请参阅此说明以生成firebase.projectIdfirebase.credentialsFile

自动加载和composer

使用composer将库添加到您的项目中。例如:

$ composer require tiqr/tiqr-server-libphp

并包含由composer生成的vendor/autoload.php

<?php
# Include the composer autoloader
require_once 'vendor/autoload.php';

创建

创建Tiqr_Service现在只需使用配置创建一个新实例即可

# Create the Tiqr_Service
$service = new Tiqr_Service($options)

示例用法

该服务有22个公开方法,用于注册新用户,同时也用于运行身份验证。本节的目的不是编写API文档。而是展示服务方法的行为示例。

关于如何使用Tiqr库的更详细的示例,请查看Tiqr TestServer实现。您可以在这里找到它。或者查看我们的Stepup-tiqr项目中的实际应用。一个好的入口点是TiqrServerTiqrFactory

日志记录

我们在库中添加了大量相关的日志记录。日志记录遵循PSR-3日志标准。当库中的服务、仓库和其他辅助类被实例化时,它们配置了一个LoggerInterface实例。您的应用程序应该有一个可以适应这一点的日志解决方案。否则,我们建议查看Monolog,它是一个非常灵活的日志解决方案,并且遵循PSR-3标准。

在实际应用中,当创建Tiqr_Service时,您需要在构造函数中注入您的Logger。工厂类也要求一个logger实例,例如:在创建用户秘密存储时。

使用Monolog的示例(您的框架将允许您将logger注入到自己的tiqr服务实现中)

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

// Create a log channel that logs alle messages of level DEBUG and above to a file
$logger = new Logger('name');
$logger->pushHandler(new StreamHandler('path/to/your.log', Logger::DEBUG));

$this->tiqrService = new Tiqr_Service($logger, $options);

UserStorage和UserSecretStorage

UserStorage.phpUserSecretStorage.php用于存储Tiqr用户账户数据(UserStorage)和用户的OCRA秘密(UserSecretStorage)。您可以选择使用这两个类,因为您提供Tiqr_Service()的userid和secret,这些可以来自任何地方。'file'类型更适合测试和开发。'pdo'类型旨在用于生产。

UserSecretStorage支持使用例如AES密钥加密用户秘密。您也可以提供自己的加密实现。有关更多信息,请参阅UserSecretStorage.php

示例UserStorage和UserSecretStorage使用

示例使用单个mysql 'user'表进行用户和用户秘密存储,用户的秘密使用AES密钥加密存储。

在MySQL中创建用户存储表

CREATE TABLE IF NOT EXISTS user (
  id integer NOT NULL PRIMARY KEY AUTO_INCREMENT,
  userid varchar(30) NOT NULL UNIQUE,
  displayname varchar(30) NOT NULL,
  secret varchar(128),
  loginattempts integer,
  tmpblocktimestamp BIGINT,
  tmpblockattempts integer,
  blocked tinyint(1),
  notificationtype varchar(10),
  notificationaddress varchar(64)
);

创建和配置UserStorage和UserSecretStorage类

$user_storage = Tiqr_UserStorage::getUserStorage(
    'pdo',
    $logger,
    array(
        'dsn' => 'mysql:host=mysql.example.com;dbname=tiqr',
        'username' => 'tiqr_rw',
        'password' => 'secret',
        'table' => 'user'
    )
);

$secret_storage = Tiqr_UserSecretStorage::getSecretStorage(
    'pdo',
    $logger,
    array(
        'dsn' => 'mysql:host=mysql.example.com;dbname=tiqr',
        'username' => 'tiqr_rw',
        'password' => 'secret',
        'table' => 'user',
        
        // Encrypt the secret using an AES key
        'encryption' => [
            'type' => 'openssl',
            'cipher' => 'aes-256-cbc', // Cypher to use for encryption
            'key_id' => 'key_2024',    // ID of the key to use for encryption
            'keys' => [
                'key_2024' => '0102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20', // Key used for encryption
                'key_2015' => '303132333435363738393a3b3c3d3e3f303132333435363738393a3b3c3d3e3f', // A (old) key that can be used for decryption
            ],
        ],
    )
);

$user_storage->createUser('jdoe', 'John Doe');  // Create user with id 'jdoe' and displayname 'John Doe'. 'jdoe' is the user's unique identifier.
$secret_storage->setSecret('jdoe', '4B7AD80B70FC758C99EFDD7E93932EEE43B9378A1AE5E26098B912C2ECA91828'); // Set the user's secret
// Set some other data that is associated with the user
$user_storage->setNotificationType('jdoe', 'APNS');
$user_storage->setNotificationAddress('jdoe', '251afb4304140542c15252e4a07c4211b441ece5');

运行测试

当开发tiqr-server-libphp项目时,可以并且应该使用日益增长的单元测试集。

运行所有QA测试

composer install
composer test

在执行composer install之后,您可以从/qa/ci/目录运行单个测试。例如,仅运行phpunit测试

./ci/qa/phpunit