-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
概要
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/optionsauthenticateVerify(sessionId, redirectUri, ?state, response)→POST /b2b/passkey/authenticate/verifyregisterOptions(rpId, b2bSubject, ?displayName, ?deviceName)→POST /b2b/passkey/register/optionsregisterVerify(sessionId, response, ?deviceName)→POST /b2b/passkey/register/verifylistPasskeys(accessToken)→GET /b2b/passkey/listdeletePasskey(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、認証不要)codeとstateパラメータ受信- セッションの
ecauth_stateとhash_equals()で検証(使い捨て) EcAuthApiClient::exchangeToken()でトークン交換- ID Token の
subクレームから b2b_subject 取得 ecauth_subjectでdtb_member検索- Symfony
security.token_storageで管理者セッション確立 - Access Token をセッションに保存(パスキー管理画面で使用)
- 管理画面ホームへリダイレクト
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 等) |
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels