https://bz.apache.org/bugzilla/show_bug.cgi?id=70276
--- Comment #2 from Syed Hyder Ali <[email protected]> --- PR PACKAGE — mod_autht_jwt: fix JOSE build + add tests PR TITLE mod_autht_jwt: fix build against apr-util with JOSE, and add tests PR DESCRIPTION (paste into GitHub) WHAT mod_autht_jwt currently cannot be built into its working form against an apr-util that provides JOSE (apr-util >= 1.7, or APR 2.0). Two build defects: 1. The HAVE_APU_JOSE feature gate tests APU_MAJOR_VERSION before any APR/APU header is included, so the macro is undefined (= 0) and the entire module body is #ifdef-ed out. The result is a no-op stub whose directives (AuthtJwtVerify, AuthtJwtDriver, …) don't exist, so any JWT config makes httpd fail to start (AH00526: Invalid command 'AuthtJwtDriver'). 2. Once the real body is enabled, jwt_get_token() calls apr_jose_signature_make() with 4 arguments, but apr-util (1.7.x and trunk) declares it with 5 (…, void *ctx, apr_pool_t *pool). Compilation fails: error: too few arguments to function 'apr_jose_signature_make'. FIX - Include apu_version.h before the version gate so APU_MAJOR_VERSION is defined when it is tested. - Pass the missing ctx argument (NULL) to apr_jose_signature_make(). TESTS Adds test/modules/aaa/test_015_autht_jwt.py: a round-trip test that configures AuthtJwtVerify HS256, then checks no-token → 401, valid HS256 token → 200, bad signature → 401, wrong aud → 401. This also serves as a regression test proving the module now builds, loads, and verifies correctly. TESTING DONE Built httpd trunk against APR 2.0 (OpenSSL crypto + JOSE); without this patch the module builds as a 23 KB stub and httpd refuses the config; with it the module builds (~85 KB, references apr_jose_decode / apr_crypto_digest_*) and the new tests pass. PATCH 1 — THE FIX (modules/aaa/mod_autht_jwt.c) --- a/modules/aaa/mod_autht_jwt.c +++ b/modules/aaa/mod_autht_jwt.c @@ -20,6 +20,8 @@ * of JWT bearer tokens, and as an acceptor of JWT Bearer tokens for authentication. */ +#include "apu_version.h" /* for APU_MAJOR_VERSION, before the gate below */ + /* apr_jose support requires >= 1.7 */ #if APU_MAJOR_VERSION > 1 || (APU_MAJOR_VERSION == 1 && APU_MINOR_VERSION > 6) @@ -668,7 +670,7 @@ static const char *jwt_get_token(request_rec *r) APR_JSON_VALUE_STRING), r->pool); } - apr_jose_signature_make(&signature, NULL, protect, r->pool); + apr_jose_signature_make(&signature, NULL, protect, NULL, r->pool); apr_jose_jws_make(&jws, &signature, NULL, &jwt, r->pool); bb = apr_brigade_create(r->pool, r->connection->bucket_alloc); PATCH 2 — CHANGELOG ENTRY (changes-entries/autht_jwt_build.txt, new file) *) mod_autht_jwt: Fix the build against apr-util with JOSE support: include apu_version.h before the HAVE_APU_JOSE version check (otherwise the module was compiled as a no-op stub), and pass the missing ctx argument to apr_jose_signature_make(). [<your name>] PATCH 3 — TEST (test/modules/aaa/test_015_autht_jwt.py, new file) import base64 import hashlib import hmac import json import os import pytest from pyhttpd.conf import HttpdConf SECRET = b"supersecretkey0123456789" def _b64url(data: bytes) -> str: return base64.urlsafe_b64encode(data).rstrip(b"=").decode() def make_jwt(secret: bytes, payload: dict, alg: str = "HS256") -> str: header = _b64url(json.dumps({"alg": alg, "typ": "JWT"}).encode()) body = _b64url(json.dumps(payload).encode()) signing_input = f"{header}.{body}" sig = hmac.new(secret, signing_input.encode(), hashlib.sha256).digest() return f"{signing_input}.{_b64url(sig)}" class TestAuthtJwt: @pytest.fixture(autouse=True, scope="class") def _class_scope(self, env): secret_file = os.path.join(env.server_dir, "jwt.secret") with open(secret_file, "wb") as fd: fd.write(SECRET) conf = HttpdConf(env, extras={ "base": "AuthtJwtDriver openssl", f"test1.{env.http_tld}": f""" <Location "/jwt"> AuthType bearer AuthName "myaud" AuthBearerProvider jwt AuthtJwtVerify HS256 file "{secret_file}" Require valid-user </Location> """, }) conf.add_vhost_test1() conf.install() assert env.apache_restart() == 0 def _get(self, env, token=None): url = f"https://test1.{env.http_tld}:{env.https_port}/jwt/index.html" options = ["-H", f"Authorization: Bearer {token}"] if token else [] return env.curl_get(url, options=options) def test_aaa_015_01_no_token(self, env): assert self._get(env).response["status"] == 401 def test_aaa_015_02_valid_token(self, env): token = make_jwt(SECRET, {"sub": "alice", "aud": "myaud"}) assert self._get(env, token).response["status"] == 200 def test_aaa_015_03_bad_signature(self, env): token = make_jwt(b"wrong-secret", {"sub": "alice", "aud": "myaud"}) assert self._get(env, token).response["status"] == 401 def test_aaa_015_04_wrong_aud(self, env): token = make_jwt(SECRET, {"sub": "alice", "aud": "nope"}) assert self._get(env, token).response["status"] == 401 HARNESS NOTE Method/fixture names (env.server_dir, env.curl_get, add_vhost_test1, env.http_tld, env.https_port) follow the pyhttpd conventions used by the other test/modules/aaa tests — run pytest test/modules/aaa/test_015_autht_jwt.py against your checkout and adjust 015 to the next free number / any helper name that differs in your tree. test1 vhost must have an index.html (the standard harness provides one). GIT COMMANDS # 1. Fork apache/httpd on GitHub, then: git clone https://github.com/<you>/httpd.git && cd httpd git remote add upstream https://github.com/apache/httpd.git git checkout -b mod_autht_jwt-build-fix trunk # 2. apply Patch 1 (or edit by hand), create the two new files, then: git add modules/aaa/mod_autht_jwt.c changes-entries/autht_jwt_build.txt test/modules/aaa/test_015_autht_jwt.py git commit -m "mod_autht_jwt: fix build against apr-util with JOSE, and add tests - include apu_version.h before the HAVE_APU_JOSE gate (the module was otherwise compiled as a no-op stub) - pass the missing ctx argument to apr_jose_signature_make() - add test/modules/aaa/test_015_autht_jwt.py (HS256 verify round-trip)" git push origin mod_autht_jwt-build-fix # 3. Open the PR from your branch against apache/httpd:trunk. -- You are receiving this mail because: You are the assignee for the bug. --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
