更新
This commit is contained in:
@@ -215,21 +215,43 @@ def test_invalid_envelope_raises_protocol_error() -> None:
|
||||
client.get("broken")
|
||||
|
||||
|
||||
def test_token_store_file_fallback_never_persists_password(tmp_path: Path) -> None:
|
||||
"""The fallback contains only an access token and an optional account name."""
|
||||
def test_token_store_file_fallback_never_persists_plaintext_password(tmp_path: Path) -> None:
|
||||
"""The fallback may contain a Windows DPAPI blob, but never plaintext."""
|
||||
|
||||
path = tmp_path / "credentials.json"
|
||||
store = TokenStore(path, keyring_backend=None)
|
||||
store.save_token("token-value", account="doctor")
|
||||
password_saved = store.save_password(
|
||||
"must-not-reach-disk",
|
||||
account="doctor",
|
||||
scope="https://example.test/adminapi",
|
||||
)
|
||||
|
||||
assert store.load_token() == "token-value"
|
||||
assert store.load_account() == "doctor"
|
||||
restored = store.load_password(account="doctor", scope="https://example.test/adminapi")
|
||||
if password_saved:
|
||||
assert restored == "must-not-reach-disk"
|
||||
else:
|
||||
assert restored is None
|
||||
payload = json.loads(path.read_text(encoding="utf-8"))
|
||||
assert payload == {"token": "token-value", "account": "doctor"}
|
||||
assert payload["token"] == "token-value"
|
||||
assert payload["account"] == "doctor"
|
||||
assert "password" not in path.read_text(encoding="utf-8").lower()
|
||||
assert "must-not-reach-disk" not in path.read_text(encoding="utf-8")
|
||||
store.clear_token()
|
||||
assert store.load_token() is None
|
||||
assert store.load_account() == "doctor"
|
||||
after_logout = store.load_password(
|
||||
account="doctor",
|
||||
scope="https://example.test/adminapi",
|
||||
)
|
||||
if password_saved:
|
||||
assert after_logout == "must-not-reach-disk"
|
||||
else:
|
||||
assert after_logout is None
|
||||
store.clear_account()
|
||||
assert store.load_password(account="doctor", scope="https://example.test/adminapi") is None
|
||||
|
||||
|
||||
class _MemoryKeyring:
|
||||
@@ -267,6 +289,33 @@ def test_token_store_prefers_available_keyring(tmp_path: Path) -> None:
|
||||
assert json.loads(path.read_text(encoding="utf-8")) == {"account": "doctor"}
|
||||
|
||||
|
||||
def test_token_store_keeps_login_password_in_scoped_keyring_only(tmp_path: Path) -> None:
|
||||
backend = _MemoryKeyring()
|
||||
path = tmp_path / "credentials.json"
|
||||
store = TokenStore(path, keyring_backend=backend)
|
||||
scope = "https://example.test/adminapi/"
|
||||
|
||||
assert store.save_password("secret-value", account="doctor", scope=scope)
|
||||
assert (
|
||||
store.load_password(account="doctor", scope="https://example.test/adminapi")
|
||||
== "secret-value"
|
||||
)
|
||||
assert store.load_password(account="doctor", scope="https://other.test/adminapi") is None
|
||||
assert "secret-value" not in path.read_text(encoding="utf-8")
|
||||
assert json.loads(path.read_text(encoding="utf-8")) == {
|
||||
"account": "doctor",
|
||||
"scope": "https://example.test/adminapi",
|
||||
}
|
||||
|
||||
next_scope = "https://next.test/adminapi"
|
||||
assert store.save_password("next-secret", account="doctor", scope=next_scope)
|
||||
assert store.load_password(account="doctor", scope=scope) is None
|
||||
assert store.load_password(account="doctor", scope=next_scope) == "next-secret"
|
||||
|
||||
store.clear_password(account="doctor", scope=next_scope)
|
||||
assert store.load_password(account="doctor", scope=next_scope) is None
|
||||
|
||||
|
||||
def test_token_store_scopes_automatic_restore_and_forgets_account(tmp_path: Path) -> None:
|
||||
"""Automatic restore never returns a token issued for another API base."""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user