mirror of
https://github.com/apache/httpd.git
synced 2026-10-23 22:49:01 +03:00
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
126 lines
4.3 KiB
Python
126 lines
4.3 KiB
Python
import logging
|
|
import os
|
|
import sys
|
|
|
|
import pytest
|
|
|
|
from .env import AAATestEnv
|
|
from pyhttpd.conf import HttpdConf
|
|
|
|
sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))
|
|
|
|
|
|
def pytest_report_header(config, start_path):
|
|
env = AAATestEnv()
|
|
return f"mod_auth_digest [apache: {env.get_httpd_version()}, mpm: {env.mpm_module}, {env.prefix}]"
|
|
|
|
|
|
def _digest_dir(docs, path, extra_lines):
|
|
lines = [
|
|
f'<Directory "{docs}/digest/{path}">',
|
|
' AuthType Digest',
|
|
f' AuthName "{AAATestEnv.REALM}"',
|
|
]
|
|
lines.extend(f" {l}" for l in extra_lines)
|
|
lines.append(' Require valid-user')
|
|
lines.append('</Directory>')
|
|
return lines
|
|
|
|
|
|
@pytest.fixture(scope="package")
|
|
def env(pytestconfig) -> AAATestEnv:
|
|
level = logging.INFO
|
|
console = logging.StreamHandler()
|
|
console.setLevel(level)
|
|
console.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
|
|
logging.getLogger('').addHandler(console)
|
|
logging.getLogger('').setLevel(level=level)
|
|
env = AAATestEnv(pytestconfig=pytestconfig)
|
|
env.setup_httpd()
|
|
env.apache_access_log_clear()
|
|
env.httpd_error_log.clear_log()
|
|
|
|
docs = env.server_docs_dir
|
|
pwfile = env.digest_pwfile
|
|
conf = HttpdConf(env)
|
|
# Pin the client table to its historical size, ~12 entries, rather than
|
|
# the current default of ~140: the tests which need an entry to be
|
|
# garbage collected (085) drive that by filling the table with bare
|
|
# requests, and a table an order of magnitude larger makes them an order
|
|
# of magnitude slower for nothing.
|
|
conf.add('AuthDigestShmemSize 1000')
|
|
conf.add(_digest_dir(docs, "default", [
|
|
'AuthDigestProvider file',
|
|
f'AuthUserFile "{pwfile}"',
|
|
]))
|
|
conf.add(_digest_dir(docs, "nccheck", [
|
|
'AuthDigestProvider file',
|
|
f'AuthUserFile "{pwfile}"',
|
|
'AuthDigestNcCheck On',
|
|
]))
|
|
conf.add(_digest_dir(docs, "nccheck-shortlife", [
|
|
'AuthDigestProvider file',
|
|
f'AuthUserFile "{pwfile}"',
|
|
'AuthDigestNcCheck On',
|
|
'AuthDigestNonceLifetime 2',
|
|
]))
|
|
conf.add(_digest_dir(docs, "shortlife", [
|
|
'AuthDigestProvider file',
|
|
f'AuthUserFile "{pwfile}"',
|
|
'AuthDigestNonceLifetime 2',
|
|
]))
|
|
conf.add(_digest_dir(docs, "neverexpire", [
|
|
'AuthDigestProvider file',
|
|
f'AuthUserFile "{pwfile}"',
|
|
'AuthDigestNonceLifetime -1',
|
|
]))
|
|
conf.add(_digest_dir(docs, "onetime", [
|
|
'AuthDigestProvider file',
|
|
f'AuthUserFile "{pwfile}"',
|
|
'AuthDigestNonceLifetime 0',
|
|
]))
|
|
conf.add(_digest_dir(docs, "onetime-nccheck", [
|
|
'AuthDigestProvider file',
|
|
f'AuthUserFile "{pwfile}"',
|
|
'AuthDigestNonceLifetime 0',
|
|
'AuthDigestNcCheck On',
|
|
]))
|
|
conf.add(_digest_dir(docs, "domain", [
|
|
'AuthDigestProvider file',
|
|
f'AuthUserFile "{pwfile}"',
|
|
'AuthDigestDomain "/digest/domain/" "https://mirror.example.org/other/"',
|
|
]))
|
|
conf.add(_digest_dir(docs, "noprovider", [
|
|
# AuthDigestProvider intentionally omitted: falls back to "file".
|
|
f'AuthUserFile "{pwfile}"',
|
|
]))
|
|
# A request which fails header validation (e.g. no Host on HTTP/1.1)
|
|
# is answered before the Digest module's post_read_request runs, so it
|
|
# has no per-request Digest record; an ErrorDocument redirecting it into
|
|
# a Digest-protected location must not then dereference that record.
|
|
conf.add('ErrorDocument 400 /digest/default/secret.txt')
|
|
# A reverse-proxied location which authenticates with Digest at the
|
|
# proxy (so the backend is never reached and need not be reachable).
|
|
# The challenge is an origin-style WWW-Authenticate, so AuthDigestDomain
|
|
# applies to it just as for a non-proxied location.
|
|
conf.add([
|
|
'ProxyPass "/pxdomain/" "http://127.0.0.1:1/unused/"',
|
|
'<Location "/pxdomain/">',
|
|
' AuthType Digest',
|
|
f' AuthName "{AAATestEnv.REALM}"',
|
|
' AuthDigestProvider file',
|
|
f' AuthUserFile "{pwfile}"',
|
|
' AuthDigestDomain "/pxdomain/"',
|
|
' Require valid-user',
|
|
'</Location>',
|
|
])
|
|
conf.install()
|
|
assert env.apache_restart() == 0
|
|
return env
|
|
|
|
|
|
@pytest.fixture(autouse=True, scope="package")
|
|
def _stop_package_scope(env):
|
|
yield
|
|
assert env.apache_stop() == 0
|