101 lines
4.8 KiB
Python
101 lines
4.8 KiB
Python
"""跨服务器桌面认证:只在路由缺失时兼容,拒绝结果不能降级。"""
|
|
import io
|
|
import json
|
|
import unittest
|
|
import urllib.error
|
|
from unittest import mock
|
|
|
|
import zyt_auth
|
|
|
|
|
|
class DesktopVerificationRegressionTest(unittest.TestCase):
|
|
def response(self, payload):
|
|
return io.BytesIO(json.dumps(payload).encode("utf-8"))
|
|
|
|
def session(self, **updates):
|
|
data = {"user_id": "admin:9", "terminal": 7, "status": "active",
|
|
"root": False, "role_ids": [2], "permissions": ["tcm.diagnosis/lists"]}
|
|
data.update(updates)
|
|
return {"code": 1, "data": data}
|
|
|
|
def verify(self):
|
|
return zyt_auth.verify_desktop_token("test-token", api_url="https://identity.example.test")
|
|
|
|
def missing(self, status=404):
|
|
return urllib.error.HTTPError("https://identity.example.test", status, "test", None, None)
|
|
|
|
def test_success_never_requests_ip_bound_web_profile(self):
|
|
with mock.patch.object(zyt_auth.urllib.request, "urlopen", side_effect=[
|
|
self.response(self.session(root=True, permissions=["*"])),
|
|
self.response({"code": -1, "msg": "ip地址发生变化,请重新登录"}),
|
|
]) as opened:
|
|
identity = self.verify()
|
|
self.assertEqual(opened.call_count, 1)
|
|
self.assertTrue(identity["root"])
|
|
self.assertEqual(identity["role_ids"], [2])
|
|
self.assertEqual(identity["permissions"], ["*"])
|
|
self.assertTrue(identity["permissions_known"])
|
|
|
|
def test_missing_permissions_do_not_trigger_profile_request(self):
|
|
payload = self.session()
|
|
del payload["data"]["permissions"]
|
|
with mock.patch.object(zyt_auth.urllib.request, "urlopen", return_value=self.response(payload)) as opened:
|
|
identity = self.verify()
|
|
self.assertEqual(opened.call_count, 1)
|
|
self.assertEqual(identity["permissions"], [])
|
|
self.assertFalse(identity["permissions_known"])
|
|
|
|
def test_empty_permissions_are_known(self):
|
|
with mock.patch.object(zyt_auth.urllib.request, "urlopen", return_value=self.response(self.session(permissions=[]))):
|
|
identity = self.verify()
|
|
self.assertTrue(identity["permissions_known"])
|
|
self.assertEqual(identity["permissions"], [])
|
|
|
|
def test_only_missing_routes_allow_legacy_verification(self):
|
|
for status in (404, 405):
|
|
with self.subTest(status=status), mock.patch.object(zyt_auth.urllib.request, "urlopen", side_effect=[
|
|
self.missing(status), self.response({"code": 1, "data": {
|
|
"user": {"id": 9, "disable": 0, "role_ids": [2]}, "permissions": []}}),
|
|
]) as opened:
|
|
identity = self.verify()
|
|
self.assertEqual(identity["user_id"], "admin:9")
|
|
self.assertEqual(opened.call_count, 2)
|
|
|
|
def test_http_rejections_do_not_fall_back(self):
|
|
for status in (401, 403, 500, 502):
|
|
with self.subTest(status=status), mock.patch.object(zyt_auth.urllib.request, "urlopen", side_effect=self.missing(status)) as opened:
|
|
with self.assertRaises(zyt_auth.ZytAuthError):
|
|
self.verify()
|
|
self.assertEqual(opened.call_count, 1)
|
|
|
|
def test_invalid_identity_cannot_be_accepted_through_web_fallback(self):
|
|
failures = [{"code": -1, "msg": "登录已失效"}, {"code": "bad"}, [],
|
|
{"code": 1, "data": []}, self.session(user_id=""),
|
|
self.session(terminal=1), self.session(terminal="bad"),
|
|
self.session(status="disabled")]
|
|
for payload in failures:
|
|
with self.subTest(payload=payload), mock.patch.object(zyt_auth.urllib.request, "urlopen", side_effect=[
|
|
self.response(payload), self.response({"code": 1, "data": {"user": {"id": 9}}}),
|
|
]) as opened:
|
|
with self.assertRaises(zyt_auth.ZytAuthError):
|
|
self.verify()
|
|
self.assertEqual(opened.call_count, 1)
|
|
|
|
def test_bad_json_and_network_failure_do_not_fall_back(self):
|
|
for result in (io.BytesIO(b"<html>error</html>"), urllib.error.URLError("offline")):
|
|
with self.subTest(result=result), mock.patch.object(zyt_auth.urllib.request, "urlopen", side_effect=[result]) as opened:
|
|
with self.assertRaises(zyt_auth.ZytAuthError):
|
|
self.verify()
|
|
self.assertEqual(opened.call_count, 1)
|
|
|
|
def test_legacy_ip_error_identifies_missing_server_deployment(self):
|
|
with mock.patch.object(zyt_auth.urllib.request, "urlopen", side_effect=[
|
|
self.missing(), self.response({"code": -1, "msg": "ip地址发生变化,请重新登录"}),
|
|
]):
|
|
with self.assertRaisesRegex(zyt_auth.ZytAuthError, "/adminapi/desktop/session"):
|
|
self.verify()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|