inside the client hash table:
* modules/aaa/mod_auth_digest.c (struct hash_table): Hold the counter here
as a 64-bit otn_counter, issued under client_lock like next_id rather
than with 32-bit atomics (apr_atomic_inc64 is not available on the
minimum APR).
(initialize_tables): Seed it; drop its separate shared-memory allocation.
(gen_nonce): Issue the ordinal under client_lock.
(set_shmem_size): Account for two allocations rather than three.
* test/modules/aaa/test_006_config_errors.py
(test_digest_069_shmemsize_no_room_for_entry_rejected): Adjust for the
smaller minimum.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GitHub: close#787
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1939038 13f79535-47bb-0310-9956-ffa450edef68
* modules/aaa/mod_auth_digest.c (set_shmem_size): Parse with apr_strtoff,
reject overflow and trailing junk, and require room for the table, the
counter, and at least one entry including rmm overhead.
* test/modules/aaa/test_006_config_errors.py
(test_digest_068_shmemsize_trailing_junk_rejected,
test_digest_069_shmemsize_no_room_for_entry_rejected): New.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GitHub: PR #787
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1939036 13f79535-47bb-0310-9956-ffa450edef68
The domain was suppressed for any proxy request, but a reverse-proxied
request authenticates to this server with an origin-style
WWW-Authenticate, so AuthDigestDomain applies to it as it does to a
non-proxied request; only a forward-proxy (PROXYREQ_PROXY) request, whose
challenge is Proxy-Authenticate, should omit it.
* modules/aaa/mod_auth_digest.c (note_digest_auth_failure): Suppress
domain= only for PROXYREQ_PROXY, matching the rest of the file.
* test/modules/aaa/env.py: Load mod_proxy and mod_proxy_http.
* test/modules/aaa/conftest.py: Add a reverse-proxied location which
authenticates with Digest and sets AuthDigestDomain.
* test/modules/aaa/test_013_proxy_domain.py: New test suite.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GitHub: PR #787
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1939035 13f79535-47bb-0310-9956-ffa450edef68
* modules/aaa/mod_auth_digest.c (copy_uri_components): Return the
ap_unescape_url status rather than discarding it.
(authenticate_digest_user): Fail the request when the request-target or
the Authorization uri does not unescape.
* test/modules/aaa/test_001_challenge_response.py
(test_digest_015_uri_bad_escaping_rejected): New.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GitHub: PR #787
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1939034 13f79535-47bb-0310-9956-ffa450edef68
* modules/aaa/mod_auth_digest.c (digest_header_rec): Add nc, the parsed
nonce-count.
(parse_digest_header): Require nc to be 8 hex digits (RFC 7616 3.4) and
store its value, so it is well-formed everywhere it is used or echoed.
(check_and_record_nonce): Use the parsed value; drop the local strtol
and the now-unreachable AH01773.
* test/modules/aaa/test_003_nccheck.py
(test_digest_036_malformed_nc_rejected,
test_digest_037_malformed_nc_does_not_poison_client): New.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GitHub: PR #787
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1939033 13f79535-47bb-0310-9956-ffa450edef68
The per-request record is created in a post_read_request hook, which does
not run for a request rejected earlier (e.g. no Host on HTTP/1.1). An
ErrorDocument directing such a request into a Digest-protected location
then reached the auth hooks, which walked ->prev to the original request
and used its record without checking it had been created.
* modules/aaa/mod_auth_digest.c (make_digest_rec): New, split from
init_digest_request, storing the record on a given request.
(get_digest_rec): New; walk to the shared record and create it if the
originating request never ran init_digest_request.
(authenticate_digest_user, hook_note_digest_auth_failure): Use it in
place of the open-coded walk, which did not check for a missing record.
* test/modules/aaa/conftest.py: Add an ErrorDocument 400 into a
Digest-protected location.
* test/modules/aaa/test_012_errordoc.py: New test suite.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GitHub: PR #787
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1939032 13f79535-47bb-0310-9956-ffa450edef68
* modules/aaa/mod_auth_digest.c (client_id_t): Widen to apr_uint64_t.
(CLIENT_ID_MAX): New.
(initialize_tables): Cap the seed at CLIENT_ID_MAX.
(client_generate): Issue ids in 1..CLIENT_ID_MAX.
(client_exists, client_update_nonce, client_generate): Log ids with
APR_UINT64_T_FMT.
(parse_digest_header): Parse the opaque with apr_strtoi64(), returning
INVALID if it is not in 1..CLIENT_ID_MAX.
(authenticate_digest_user): Remove the now-unreachable invalid opaque
check (AH01787); mention an invalid opaque in AH01782.
(ltox): Rename to...
(client_id_to_opaque): ...this; format with APR_UINT64_T_HEX_FMT.
(note_digest_auth_failure): Update callers.
* test/modules/aaa/test_001_challenge_response.py
(test_digest_013_invalid_opaque): Accept AH01782 as well as AH01787.
* test/modules/aaa/test_003_nccheck.py
(test_digest_035_out_of_range_opaque_is_not_truncated): Try opaques
2^32 and 2^64 above the live id.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
GitHub: PR #787
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1939031 13f79535-47bb-0310-9956-ffa450edef68
* test/modules/aaa/test_012_truncated_nonce.py
(TestDigestTruncatedNonce.test_digest_012_01): New test. Request a
Digest challenge, truncate the nonce by stripping the base64 time
prefix up to the '=', and send an Authorization header built with the
truncated nonce. Expect a 401 response and ignore the logged AH01782
error.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Submitted by: Paul Lodge <plodge redhat.com>
GitHub: closes#798
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1938930 13f79535-47bb-0310-9956-ffa450edef68
* modules/aaa/mod_auth_digest.c (add_auth_info): Add the
(Proxy-)Authentication-Info header to err_headers_out, so a one-time
nonce client gets its nextnonce after an error response rather than a
stale re-challenge.
(note_digest_auth_failure): Drop any (Proxy-)Authentication-Info when
issuing a challenge, so a post-authentication 401 carries only the
fresh nonce.
* test/modules/aaa/test_011_authinfo_errors.py: New tests.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
GitHub: closes PR #739
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1937888 13f79535-47bb-0310-9956-ffa450edef68
Done with the help of Claude Code Opus 4.6
this closes#731
M test/modules/http1/env.py
M test/modules/http2/env.py
M test/modules/http2/test_006_assets.py
M test/modules/http2/test_103_upgrade.py
M test/modules/http2/test_104_padding.py
M test/modules/http2/test_107_frame_lengths.py
M test/modules/http2/test_202_trailer.py
M test/modules/http2/test_400_push.py
M test/modules/http2/test_401_early_hints.py
M test/modules/http2/test_710_load_post_static.py
M test/modules/http2/test_711_load_post_cgi.py
M test/pyhttpd/certs.py
M test/pyhttpd/conf/httpd.conf.template
M test/pyhttpd/env.py
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1937863 13f79535-47bb-0310-9956-ffa450edef68
* modules/aaa/mod_auth_digest.c (gen_nonce_hash): Use apr_siphash24_auth()
where APU 1.6 or later provides it, keeping the SHA-1 hash otherwise.
Take a pool for the message buffer, and length-prefix the realm.
* test/modules/aaa/test_002_nonce.py (test_digest_021): Take the length of
the hash from the nonce rather than assuming SHA-1's.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GitHub: closes#730
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1937716 13f79535-47bb-0310-9956-ffa450edef68
have never authenticated before the least recently used.
* test/modules/aaa/test_010_eviction.py: New test suite.
* test/modules/aaa/test_008_onetime_nccheck.py (085): Fill the table with
clients which have authenticated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GitHub: PR #730
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1937713 13f79535-47bb-0310-9956-ffa450edef68
8192 bytes, holding around 140 clients.
* docs/manual/mod/mod_auth_digest.xml: Document the new default.
* test/modules/aaa/conftest.py, test/modules/aaa/test_008_onetime_nccheck.py:
Pin AuthDigestShmemSize to the old size.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GitHub: PR #730
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1937712 13f79535-47bb-0310-9956-ffa450edef68
* modules/aaa/mod_auth_digest.c (initialize_tables): Seed the client ids
randomly for each shared memory segment.
* test/modules/aaa/test_009_restart.py: New test suite.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GitHub: PR #730
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1937711 13f79535-47bb-0310-9956-ffa450edef68
in check_and_record_nonce, accepting a nonce iff it is newer than
the last used, and re-challenging as stale when reused.
* test/modules/aaa/test_008_onetime_nccheck.py: Add tests for one-time
nonces, alone and with AuthDigestNcCheck.
* test/modules/aaa/conftest.py: Add an AuthDigestNonceLifetime 0 plus
AuthDigestNcCheck location.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
GitHub: PR #705
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1937105 13f79535-47bb-0310-9956-ffa450edef68
nonce-count per-nonce, require it to increase (RFC 7616 3.4.3), and
record it only for a fully verified request.
* test/modules/aaa/test_007_replay.py: Add replay tests.
* test/modules/aaa/test_003_nccheck.py, test/modules/aaa/conftest.py:
Update for the new semantics.
Assisted-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
GitHub: PR #705
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1937104 13f79535-47bb-0310-9956-ffa450edef68