Skip to content

EC-CUBE 4.3系 EcAuth B2Bパスキー認証プラグイン 実装 #1

@nanasess

Description

@nanasess

概要

EcAuthDocs PR #36 の実装計画に基づき、EC-CUBE 4.3系管理画面にB2Bパスキー認証を統合するプラグインを新規開発する。

Related: EcAuth/EcAuth#254

項目
プラグインコード EcAuthLogin43
初回リリーススコープ B2Bパスキー認証
Docker イメージ ghcr.io/ec-cube/ec-cube-php:8.3-apache-4.3
開発方式 Composer ローカルリポジトリ(symlink)
検証環境 EcAuth ステージング(organization_code: staging

Step 1: リポジトリ作成・Docker 開発環境

  • ディレクトリ構成の作成
  • composer.json 作成(type: eccube-plugin, code: EcAuthLogin43
  • Dockerfile(ghcr.io/ec-cube/ec-cube-php:8.3-apache-4.3 ベース)
  • docker-compose.yml(EC-CUBE 4.3 + PostgreSQL)
  • docker-compose.override.yml(Composer ローカルリポジトリ設定、symlink)
  • docker-entrypoint.sh(プラグインインストール・有効化の自動化)
  • .env.tpl(1Password テンプレート、EcAuth ステージング接続情報)
  • CLAUDE.md
  • docker compose up -d でプラグインが有効化された状態で起動できることを確認

Step 2: プラグイン骨格・設定画面

  • Entity/Config.php — plg_ecauth_login43_config テーブル
    • ecauth_base_url, client_id, client_secret, rp_id(nullable)
  • Entity/MemberTrait.php — @EntityExtension で dtb_member に ecauth_subject 追加(VARCHAR 255, nullable, unique)
  • Form/Type/Admin/ConfigType.php
  • Repository/ConfigRepository.php
  • Controller/Admin/ConfigController.php(/%eccube_admin_route%/ecauth_login43/config
  • Resource/template/admin/config.twig
  • EcAuthLoginNav.php(管理画面ナビゲーション:EcAuth 設定、パスキー管理)
  • PluginManager.php(enable() で Config デフォルト行作成)
  • Resource/config/services.yaml
  • Resource/locale/messages.ja.yaml

Step 3: EcAuth API 連携サービス

  • Service/EcAuthApiClient.php(Symfony HttpClient)
    • authenticateOptions(rpId, ?b2bSubject)POST /b2b/passkey/authenticate/options
    • authenticateVerify(sessionId, redirectUri, ?state, response)POST /b2b/passkey/authenticate/verify
    • registerOptions(rpId, b2bSubject, ?displayName, ?deviceName)POST /b2b/passkey/register/options
    • registerVerify(sessionId, response, ?deviceName)POST /b2b/passkey/register/verify
    • listPasskeys(accessToken)GET /b2b/passkey/list
    • deletePasskey(accessToken, credentialId)DELETE /b2b/passkey/{credentialId}
    • exchangeToken(code, redirectUri)POST /token
  • Service/PasskeyAuthService.php
    • ensureB2BUser(Member) — ecauth_subject 未設定なら UUID 生成・保存(JIT プロビジョニング)
    • handleCallback(code, state, session) — state 検証 → トークン交換 → Member 検索 → セッション確立
    • verifyPassword(Member, password) — 本人確認(UserPasswordHasherInterface)
    • getRpId(Request) — Config の rp_id またはリクエストホスト名

Step 4: 管理画面ログイン UI 拡張(パスキー認証)

ルーティング(認証不要、管理画面 firewall の外)

  • POST /ecauth/passkey/authenticate/options — PasskeyAuthController(チャレンジ取得)
  • POST /ecauth/passkey/authenticate/verify — PasskeyAuthController(署名検証→認可コード)

UI

  • EcAuthLoginEvent.php(@admin/login.twig イベントでスニペット注入)
  • Resource/template/admin/login_passkey.twig
    • ログインフォーム直後に「パスキーでログイン」ボタンを DOM 操作で挿入
    • HTTPS 環境 かつ window.PublicKeyCredential 対応時のみ表示
  • Resource/assets/js/webauthn.js
    • Base64URL エンコード/デコード
    • authenticate(optionsUrl, verifyUrl)navigator.credentials.get() ラッパー
    • register(optionsUrl, verifyUrl)navigator.credentials.create() ラッパー
    • CSRF トークン送信対応

Step 5: コールバック処理

  • Controller/EcAuthCallbackController.php(GET /ecauth/callback、認証不要)
    1. codestate パラメータ受信
    2. セッションの ecauth_statehash_equals() で検証(使い捨て)
    3. EcAuthApiClient::exchangeToken() でトークン交換
    4. ID Token の sub クレームから b2b_subject 取得
    5. ecauth_subjectdtb_member 検索
    6. Symfony security.token_storage で管理者セッション確立
    7. Access Token をセッションに保存(パスキー管理画面で使用)
    8. 管理画面ホームへリダイレクト

Step 6: パスキー管理画面

ルーティング(管理者ログイン必須)

  • POST /%admin%/ecauth/passkey/register/options — パスキー登録オプション
  • POST /%admin%/ecauth/passkey/register/verify — パスキー登録完了
  • GET /%admin%/ecauth/passkey/ — 一覧表示
  • DELETE /%admin%/ecauth/passkey/{id}/delete — 削除
  • POST /%admin%/ecauth/passkey/verify-password — 本人確認(パスワード再入力)

UI

  • Resource/template/admin/passkey_list.twig
    • @admin/default_frame.twig を extends
    • パスキー一覧テーブル(デバイス名、登録日時、最終使用日時)
    • 「パスキーを追加」ボタン → パスワード再入力モーダル → WebAuthn 登録
    • 各行に「削除」ボタン

Step 7: テスト・CI/CD

静的解析 (.github/workflows/ci.yml)

  • PHPStan Level 6(PHP 8.3)
  • Rector dry-run
  • PHP CS Fixer dry-run
  • .php-cs-fixer.dist.php
  • phpstan.neon.dist
  • rector.php

E2E テスト (.github/workflows/playwright.yml)

  • package.json / playwright.config.ts
  • tests/specs/passkey_auth.spec.ts(パスキーログインフロー全体)
  • tests/specs/passkey_register.spec.ts(登録・一覧・削除)
  • tests/specs/plugin_config.spec.ts(設定画面)
  • Playwright WebAuthn 仮想認証器を使用、EcAuth ステージング環境に接続

リリースパッケージ (.github/workflows/deploy.yml)

  • GitHub Release 公開時に tar.gz パッケージを自動ビルド
  • Release Asset に添付(ProductReview-plugin パターンを踏襲)

セキュリティ

項目 対策
CSRF Symfony CSRF トークン(フォーム + AJAX ヘッダー)
state 検証 セッション保存 + hash_equals() + 使い捨て
HTTPS WebAuthn は HTTPS 必須。HTTP 時はボタン非表示
client_secret サーバーサイドのみ。JS に渡さない
レートリミット EC-CUBE rate_limiter で認証 API 保護
WebAuthn RP ID/SignCount/チャレンジ期限は EcAuth 側で検証

将来の拡張(同一プラグイン内)

Phase 機能
Phase 2 B2C パスキー(フロント)
Phase 3 B2C ソーシャルログイン
Phase 4 B2B SSO(Azure Entra ID 等)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions