True passkey implement
This commit is contained in:
195
PASSKEY.md
Normal file
195
PASSKEY.md
Normal file
@@ -0,0 +1,195 @@
|
||||
# MCPletA2A Passkey 認証
|
||||
|
||||
真正の WebAuthn/FIDO2 Passkey 認証。外部 amiPro FIDO2 サーバーと連携。
|
||||
|
||||
## アーキテクチャ
|
||||
|
||||
```
|
||||
Host (Node.js)
|
||||
│
|
||||
├── PasskeyServer ──→ ブラウザページ起動(自己完結型フロー)
|
||||
│ │
|
||||
│ ├── userId 入力
|
||||
│ ├── FIDO2 サーバーにユーザー確認
|
||||
│ ├── 未登録 → 自動で Passkey 登録(Touch ID 等)
|
||||
│ ├── 認証(Touch ID 等)
|
||||
│ └── 結果を Host に HTTP callback
|
||||
│
|
||||
├── PasskeyPlatformService ──→ AmiProFIDO2Client ──→ FIDO2 Server
|
||||
│ (統一管理: 登録/認証/セッション) (https://fido2.epk.amipro.me)
|
||||
│
|
||||
└── PasskeyAPIServer (REST proxy, port 8443)
|
||||
/api/passkey/attestation/options
|
||||
/api/passkey/attestation/result
|
||||
/api/passkey/assertion/options
|
||||
/api/passkey/assertion/result
|
||||
```
|
||||
|
||||
## ファイル構成
|
||||
|
||||
```
|
||||
platform_impl/src/passkey/
|
||||
├── amipro-fido2-client.ts # amiPro FIDO2 サーバー REST クライアント
|
||||
├── platform-service.ts # 統一 Passkey 管理サービス
|
||||
├── passkey-server.ts # ブラウザ WebAuthn 式典サーバー(自己完結型ページ)
|
||||
├── api-server.ts # REST API プロキシ
|
||||
├── index.ts # エクスポート
|
||||
├── storage.ts # IPasskeyStorage インターフェース (ローカル用、予備)
|
||||
├── challenge-manager.ts # チャレンジ管理 (ローカル用、予備)
|
||||
├── fido2-backend.ts # FIDO2 検証 (ローカル用、予備)
|
||||
├── client.ts # ブラウザ側 WebAuthn クライアント
|
||||
└── mcplet-helper.ts # MCPlet ツール統合ヘルパー
|
||||
```
|
||||
|
||||
## 設定
|
||||
|
||||
```yaml
|
||||
# reference_impl/config/reference.yaml
|
||||
passkey:
|
||||
mode: https # localhost | https
|
||||
rpId: a2a-demo.mcplet.ai # WebAuthn Relying Party ID
|
||||
fido2ServerUrl: https://fido2.epk.amipro.me # 外部 FIDO2 サーバー
|
||||
apiPort: 8443 # REST API ポート
|
||||
```
|
||||
|
||||
## ユーザーフロー
|
||||
|
||||
### 新規ユーザー(未登録)
|
||||
|
||||
```
|
||||
ブラウザページ起動
|
||||
↓
|
||||
1. userId 入力(または自動入力)
|
||||
↓
|
||||
2. FIDO2 サーバーに問い合わせ → "ユーザーが存在しません"
|
||||
↓
|
||||
3. 自動で登録モードに切替 → Touch ID 等で Passkey 登録
|
||||
↓
|
||||
4. 登録成功 → 自動で認証に進む
|
||||
↓
|
||||
5. Touch ID 等で認証
|
||||
↓
|
||||
6. session + username を Host に返却
|
||||
```
|
||||
|
||||
### 既存ユーザー(登録済み)
|
||||
|
||||
```
|
||||
ブラウザページ起動
|
||||
↓
|
||||
1. userId 入力(または自動入力)
|
||||
↓
|
||||
2. FIDO2 サーバーに問い合わせ → OK(allowCredentials 返却)
|
||||
↓
|
||||
3. Touch ID 等で認証
|
||||
↓
|
||||
4. session + username を Host に返却
|
||||
```
|
||||
|
||||
## amiPro FIDO2 Server API
|
||||
|
||||
| エンドポイント | 説明 |
|
||||
|--------------|------|
|
||||
| `POST /attestation/options` | 登録オプション取得(challenge + publicKey params) |
|
||||
| `POST /attestation/result` | 登録結果送信(attestationObject 検証) |
|
||||
| `POST /assertion/options` | 認証オプション取得(challenge + allowCredentials) |
|
||||
| `POST /assertion/result` | 認証結果送信(signature 検証) |
|
||||
| `POST /usr/validsession` | セッション検証 |
|
||||
| `POST /usr/delsession` | ログアウト |
|
||||
|
||||
エンコーディング: Base64URL(dfido2-lib.js 互換)
|
||||
|
||||
## 開発環境セットアップ
|
||||
|
||||
### 1. /etc/hosts
|
||||
|
||||
```
|
||||
127.0.0.1 a2a-demo.mcplet.ai
|
||||
```
|
||||
|
||||
### 2. 自己署名証明書の生成
|
||||
|
||||
```bash
|
||||
cd platform_impl
|
||||
mkdir -p certs
|
||||
openssl req -x509 -newkey rsa:2048 \
|
||||
-keyout certs/key.pem -out certs/cert.pem \
|
||||
-days 365 -nodes -subj "/CN=a2a-demo.mcplet.ai" \
|
||||
-addext "subjectAltName=DNS:a2a-demo.mcplet.ai,IP:127.0.0.1"
|
||||
```
|
||||
|
||||
### 3. 証明書の信頼(macOS)
|
||||
|
||||
```bash
|
||||
# Admin 権限あり
|
||||
sudo security add-trusted-cert -d -r trustRoot \
|
||||
-k /Library/Keychains/System.keychain certs/cert.pem
|
||||
|
||||
# Admin 権限なし(Edge で有効、Chrome は完全再起動が必要)
|
||||
security add-trusted-cert -r trustRoot \
|
||||
-k ~/Library/Keychains/login.keychain-db certs/cert.pem
|
||||
```
|
||||
|
||||
### 4. テスト
|
||||
|
||||
```bash
|
||||
cd platform_impl
|
||||
|
||||
# API 接続テストのみ
|
||||
npx tsx test-passkey.ts
|
||||
|
||||
# 統一フロー(自動登録+認証)
|
||||
npx tsx test-passkey.ts test a2a-test-user
|
||||
|
||||
# 新規ユーザー(userId 手入力)
|
||||
npx tsx test-passkey.ts new
|
||||
```
|
||||
|
||||
## 重要な注意事項
|
||||
|
||||
### WebAuthn rpId とドメインの一致
|
||||
|
||||
WebAuthn は rpId がブラウザページのドメインと一致することを要求する。
|
||||
`http://127.0.0.1` のページでは rpId `a2a-demo.mcplet.ai` は使用不可。
|
||||
必ず /etc/hosts + HTTPS(または Chrome flag)で一致させること。
|
||||
|
||||
### Passkey のブラウザ間共有
|
||||
|
||||
macOS の Touch ID / iCloud キーチェーンで作成された Passkey はブラウザ間で共有される。
|
||||
ただし Chrome の `--user-data-dir=tmp` で起動すると隔離プロファイルとなり、
|
||||
プラットフォーム Passkey にアクセスできない。常にデフォルトブラウザを使用すること。
|
||||
|
||||
### 本番環境 vs 開発環境
|
||||
|
||||
| 項目 | 開発環境 | 本番環境 |
|
||||
|------|---------|---------|
|
||||
| 証明書 | 自己署名 + キーチェーン信頼 | 正規 SSL 証明書 |
|
||||
| rpId | a2a-demo.mcplet.ai (hosts) | 実ドメイン (DNS) |
|
||||
| FIDO2 server | fido2.epk.amipro.me | 同 or 専用サーバー |
|
||||
| `PASSKEY_DEV_HTTP` | 設定可(Chrome flag 必要) | 不使用 |
|
||||
|
||||
## Platform 統合
|
||||
|
||||
### base-agent.ts での Passkey 呼び出し
|
||||
|
||||
```typescript
|
||||
// action 型ツールで auth.required === 'passkey' の場合、自動で仪式を開始
|
||||
if (tool.meta.mcpletType === 'action' && tool.meta.auth?.required === 'passkey') {
|
||||
const assertion = await this.performPasskeyCeremony(tool);
|
||||
if (!assertion) {
|
||||
return this.errorResult(toolName, 'Passkey authentication failed', 'AUTH_FAILED');
|
||||
}
|
||||
callParams = { ...args, _mcplet_auth: assertion };
|
||||
}
|
||||
```
|
||||
|
||||
### MCPletHost 初期化
|
||||
|
||||
```typescript
|
||||
if (config.passkey) {
|
||||
this.passkeyPlatformService = new PasskeyPlatformService(rpId, fido2ServerUrl);
|
||||
this.passkeyAPIServer = new PasskeyAPIServer(platformService, rpId, origin);
|
||||
this.passkeyAPIServer.start(config.passkey.apiPort || 8443);
|
||||
this.passkeyServer = new PasskeyServer(rpId, fido2ServerUrl);
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user