diff --git a/backend/app/core/security.py b/backend/app/core/security.py index 75b70e4..24f24cd 100644 --- a/backend/app/core/security.py +++ b/backend/app/core/security.py @@ -37,7 +37,7 @@ def verify_casdoor_token(token: str) -> dict: header = pyjwt.get_unverified_header(token) algorithm = header.get("alg") if algorithm not in {"RS256", "RS384", "RS512"}: - raise ValueError("Unsupported Casdoor token algorithm") + raise ValueError(f"Unsupported Casdoor token algorithm: {algorithm}") return pyjwt.decode( token, diff --git a/backend/app/services/imc_service.py b/backend/app/services/imc_service.py index 61f7201..1b36e0b 100644 --- a/backend/app/services/imc_service.py +++ b/backend/app/services/imc_service.py @@ -39,16 +39,52 @@ class IMCService: """iMC REST API 服务封装""" def __init__(self): + import os + import tempfile + import certifi + from requests.adapters import HTTPAdapter + self.base_url = settings.IMC_API_URL.rstrip('/') self.username = settings.IMC_API_USERNAME self.password = settings.IMC_API_PASSWORD - self.verify_ssl = settings.IMC_API_VERIFY_SSL self.connect_timeout = settings.IMC_CONNECT_TIMEOUT self.read_timeout = settings.IMC_READ_TIMEOUT self.session = requests.Session() self.realm = "iMC RESTful Web Services" self.nonce = None self.nc = 1 + self._ca_bundle_file = None # temp file for certifi + iMC CA + + if settings.IMC_API_VERIFY_SSL: + imc_ca_path = os.path.join(os.path.dirname(__file__), "..", "..", "imc_ca.pem") + if os.path.isfile(imc_ca_path): + # The iMC self-signed cert uses a non-DNS CN and zero SAN entries, + # so hostname matching is impossible. We still enforce full + # certificate-chain verification via a combined CA bundle, then + # tell urllib3 to skip its own hostname check. + with open(imc_ca_path, "rb") as fh: + imc_pem = fh.read() + self._ca_bundle_file = tempfile.NamedTemporaryFile(suffix=".pem", delete=False) + with open(certifi.where(), "rb") as fh: + self._ca_bundle_file.write(fh.read()) + self._ca_bundle_file.write(b"\n") + self._ca_bundle_file.write(imc_pem) + self._ca_bundle_file.flush() + + _ca_bundle = self._ca_bundle_file.name + + class _IMCAdapter(HTTPAdapter): + def cert_verify(self, conn, url, verify, cert): + super().cert_verify(conn, url, verify=_ca_bundle, cert=cert) + conn.assert_hostname = False + + self.session.mount("https://", _IMCAdapter()) + self.verify_ssl = True + logger.info("iMC TLS verification enabled (hostname check relaxed)") + else: + self.verify_ssl = True + else: + self.verify_ssl = False # ── Digest 认证 ────────────────────────────────────────────────────────── diff --git a/backend/imc_ca.pem b/backend/imc_ca.pem new file mode 100644 index 0000000..e9b71d7 --- /dev/null +++ b/backend/imc_ca.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC+TCCAeGgAwIBAgIEHno+KjANBgkqhkiG9w0BAQsFADAtMQwwCgYDVQQLDANS +JkQxHTAbBgNVBAMTFGlNQyBEZXZlbG9wbWVudCBUZWFtMB4XDTE5MDExOTA2Mzkx +OVoXDTM5MDExNDA2MzkxOVowLTEMMAoGA1UECwwDUiZEMR0wGwYDVQQDExRpTUMg +RGV2ZWxvcG1lbnQgVGVhbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AIVGUvmtUD6Gx0AQLi+/voDIuSERGLyTLcQQOBmWVWLfxr0i1PGxuGODylN+30Ud +pBY1faRijvUZUWN51dxjXMRLnHUecBuPVyWOv1jPFMd1jcc7KmQ4KY6s43t1cC2R +pBcfyBhVmN+tArhcbDJb6MUuN1P5ZGi3E1vor9EY0Gt8TvJ/GgmqgWwlveAC0soH +yTTk8UU9m2OikbaZ0dKgQbshna4wrSWw9iyJ5Bao4rZgus3hGZUnznWpPD0/jHC4 +lI3znCKQPAsnJculZcK/8dm1UYKFx7C3L5z4SnzsLY+rTYXvmGfb2x06wKkkJTIt +oepc1U5U/jNlUVbNdA9yhP0CAwEAAaMhMB8wHQYDVR0OBBYEFGErff6AvZVRmgqK +DLQxMBGOr0ObMA0GCSqGSIb3DQEBCwUAA4IBAQA9HhuDvrVI4ICyddy5g4DM+bv4 +NaKoBS0Y5nhANbN/0f0J0Zj32OYtbsJlUZViFQ42LIR7b37x6OgMXRjHJIDg3q+9 +tkH5S8Q5xmb5Tqq0WcOWQmg0o1OjW5iJNAfKiTffGtc5DjmrOBuCf1P23G3polRB +34QxGgnRygEDKy5aYumaXyiL1yMgDLkZ2adg2lWvsBSpvmgzMF5H75Spq4WvK60Z +o3EyCpB5ZS4SxwF3JH+LdpsyCc+UsyYW4/v/FVidtCp+nNTgsTA1yI8vcPVyPxPQ +SvVFIvuLYpo9cbHLcmQ95LBKjMbhPVHMzsBRVd85xKVjBspRMWeUp7F94W8V +-----END CERTIFICATE----- diff --git a/backend/token_jwt_key.pem b/backend/token_jwt_key.pem new file mode 100644 index 0000000..0a33e36 --- /dev/null +++ b/backend/token_jwt_key.pem @@ -0,0 +1,14 @@ +-----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEArvxqOc2fCe611njyX3aG +aprZzyU/UhynIHsJhVMq6tDFLPmJCitg5WFHVTOW5KlTzKI894XJNEPSkf4POoai +1z4CW/GeRrkN8/XP8/RqyiCQAslei5FH5i1RjqLWijm0qUNsgYk07ZpBw45qT1ti +ipJF33L+mr9s+O17ujDDb2EZBzTcuBs1eYhv2fk0bOdYK17Vzzw1StPP0OWmfYev +edw6YemqnODk21e6CGcewXhgIX6k8iBaULQLoy0qTR+4nKwJjnCm4DrbSkYvjM7p +AW/3bQyJax1VbFw2jRo1CRcoaMRzLcutpe7HaT+wf4TR7cZFcaFZieSsruLySD5X +42bVgWDIZtjtXfJnSZc/Fv6IyUi/PzzlWIaxGcqqVHSk3W/w1ubNc+70SQA7fCJP +8vh/GcRNbWF3+mH4B1DSMSl7IAxGNyXeQyNq44Gp9T9MeXsvppQxcHd3Tn4krRi5 +NzWetnRCOH/kQblfK9FK4o1XGkIHVdwCUBoFO4Tlqu3qNCQIkg28Wg6OgdkHrkoc +lW98y0y5Wvt0tJtg48cfpgkHZ9SKM0qhedyUBvGV1fd8QAuwL9JbvMwUX7cVOGBJ +6rc4Sk11uRGVCnmw5Ed5ORa0w70DrQYe9OoNqYiqmkLh+TvXMhGmYQ+V8aw6ejmA +2Efz40ofkK+Z+Pizv9L3wP8CAwEAAQ== +-----END PUBLIC KEY----- diff --git a/frontend/src/views/OltManage.vue b/frontend/src/views/OltManage.vue index 590f1d2..ea8aa98 100644 --- a/frontend/src/views/OltManage.vue +++ b/frontend/src/views/OltManage.vue @@ -8,31 +8,22 @@