feat(V2): IBKR live session token mint via DH key exchange

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
root
2026-05-03 20:15:17 +00:00
parent a90c5c4d6f
commit 92da6aa842
2 changed files with 132 additions and 2 deletions
+48
View File
@@ -1,13 +1,17 @@
from __future__ import annotations
import base64 as _b64
import re
import time
import pytest
from cerbero_mcp.exchanges.ibkr.oauth import (
OAuth1aSigner,
build_signature_base_string,
)
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa
from pytest_httpx import HTTPXMock
def test_signature_base_string_canonical_order():
@@ -83,3 +87,47 @@ def test_oauth_signer_signs_with_rsa(tmp_path):
padding.PKCS1v15(),
hashes.SHA256(),
)
@pytest.mark.asyncio
async def test_live_session_token_mint(httpx_mock: HTTPXMock, tmp_path):
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
pem = key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.TraditionalOpenSSL,
encryption_algorithm=serialization.NoEncryption(),
)
(tmp_path / "sig.pem").write_bytes(pem)
(tmp_path / "enc.pem").write_bytes(pem)
# Encrypt fake "real" secret with our public key
raw_secret = b"my_real_token_secret"
encrypted = key.public_key().encrypt(raw_secret, padding.PKCS1v15())
encrypted_hex = encrypted.hex()
httpx_mock.add_response(
url=re.compile(r".*/oauth/live_session_token"),
json={
"diffie_hellman_response": "ff",
"live_session_token_signature": "00" * 20,
"live_session_token_expiration": int(time.time() * 1000) + 86400000,
},
)
from cerbero_mcp.exchanges.ibkr.oauth import OAuth1aSigner
signer = OAuth1aSigner(
consumer_key="TEST_CK",
access_token="TEST_AT",
access_token_secret=encrypted_hex,
signature_key_path=str(tmp_path / "sig.pem"),
encryption_key_path=str(tmp_path / "enc.pem"),
dh_prime="ff",
)
lst = await signer.get_live_session_token(
base_url="https://api.ibkr.com/v1/api"
)
assert isinstance(lst, str) and len(lst) > 0
lst2 = await signer.get_live_session_token(
base_url="https://api.ibkr.com/v1/api"
)
assert lst == lst2 # cached