summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoromnom62 <omnom62@outlook.com>2026-09-22 06:37:12 +1000
committeromnom62 <omnom62@outlook.com>2026-09-29 06:58:05 +1000
commitf75c7b74dc4c2f38ad9e61e08dfe9fd1fc0686f9 (patch)
tree93db5dffca052d4bec4ada58c730915bdf255efd /src
parented218c254d964775ddf24158ac6520972d575faf (diff)
downloadvyos-1x-f75c7b74dc4c2f38ad9e61e08dfe9fd1fc0686f9.tar.gz
vyos-1x-f75c7b74dc4c2f38ad9e61e08dfe9fd1fc0686f9.zip
https: T8989: Hotfix to enforce audience settings with OIDC is configured
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/service_https.py26
-rw-r--r--src/services/api/rest/libs/token_auth.py14
2 files changed, 34 insertions, 6 deletions
diff --git a/src/conf_mode/service_https.py b/src/conf_mode/service_https.py
index d10825ab5..10e0afe49 100755
--- a/src/conf_mode/service_https.py
+++ b/src/conf_mode/service_https.py
@@ -121,6 +121,15 @@ def verify(https):
if dict_search('api.rest.authentication.oidc.issuer', https) is None:
raise ConfigError('OIDC issuer must be configured when jwks-url is set')
+ if dict_search('api.rest.authentication.oidc.issuer', https) is not None:
+ if dict_search('api.rest.authentication.oidc.audience', https) is None:
+ raise ConfigError(
+ 'OIDC audience must be configured when issuer is set. '
+ 'Without it, any valid token issued by the trusted issuer '
+ 'for a different application would be accepted, granting '
+ 'full API privileges to an unrelated token holder.'
+ )
+
# Check if server port is already in use by a different application
listen_address = ['0.0.0.0']
port = int(https['port'])
@@ -160,9 +169,18 @@ def verify(https):
# If only key-based methods are enabled,
# fail the commit if no valid key configurations are found
mtls_auth = dict_search('certificates.verify_client', https) is not None
- if (not valid_keys_exist) and (not jwt_auth) and (not mtls_auth):
+ oidc_auth = (
+ dict_search('api.rest.authentication.oidc.issuer', https) is not None
+ )
+ if (
+ (not valid_keys_exist)
+ and (not jwt_auth)
+ and (not mtls_auth)
+ and (not oidc_auth)
+ ):
raise ConfigError(
- 'At least one HTTPS API key is required unless GraphQL token or mTLS authentication is enabled!'
+ 'At least one HTTPS API key is required unless GraphQL token, '
+ 'mTLS, or OIDC authentication is enabled!'
)
if (not valid_keys_exist) and jwt_auth:
@@ -171,6 +189,10 @@ def verify(https):
Warning(
'API keys are not configured: only mTLS client certificate authentication will be available for the REST API!'
)
+ if (not valid_keys_exist) and oidc_auth and not jwt_auth and not mtls_auth:
+ Warning(
+ 'API keys are not configured: only OIDC authentication will be available for the REST API!'
+ )
return None
diff --git a/src/services/api/rest/libs/token_auth.py b/src/services/api/rest/libs/token_auth.py
index e0710cc20..ccc5fbf35 100644
--- a/src/services/api/rest/libs/token_auth.py
+++ b/src/services/api/rest/libs/token_auth.py
@@ -56,10 +56,16 @@ def verify_oidc_token(token: str):
issuer=state.oidc_issuer,
leeway=30,
)
- if state.oidc_audience:
- decode_kwargs["audience"] = state.oidc_audience
- else:
- decode_options["verify_aud"] = False
+ if not state.oidc_audience:
+ # Fail closed: config-time validation in service_https.py's
+ # verify() requires oidc.audience whenever oidc.issuer is
+ # set, but never trust that alone for a security-critical
+ # check. PyJWT also skips aud validation whenever no
+ # "audience" kwarg is passed at all, independent of
+ # verify_aud -- so this must refuse outright, not just stop
+ # forcing verify_aud=False.
+ return None
+ decode_kwargs["audience"] = state.oidc_audience
payload = jwt.decode(token, signing_key.key, **decode_kwargs)
return payload.get("sub") or payload.get("client_id")
except Exception: