* [FFmpeg-devel] [PATCH] Some RTSP server response 401 with multiple Digest and FFmpeg fails
@ 2025-12-12 4:11 Zhigong Liu via ffmpeg-devel
0 siblings, 0 replies; only message in thread
From: Zhigong Liu via ffmpeg-devel @ 2025-12-12 4:11 UTC (permalink / raw)
To: ffmpeg-devel; +Cc: Zhigong Liu
Signed-off-by: Zhigong Liu <lzhigong@gmail.com>
---
libavformat/httpauth.c | 83 ++++++++++++++++++++++++++++++++++--------
1 file changed, 68 insertions(+), 15 deletions(-)
diff --git a/libavformat/httpauth.c b/libavformat/httpauth.c
index 9048362509..5260b4a9a4 100644
--- a/libavformat/httpauth.c
+++ b/libavformat/httpauth.c
@@ -92,25 +92,57 @@ void ff_http_auth_handle_header(HTTPAuthState *state, const char *key,
{
if (!av_strcasecmp(key, "WWW-Authenticate") || !av_strcasecmp(key, "Proxy-Authenticate")) {
const char *p;
+ av_log(NULL, AV_LOG_DEBUG, "Processing auth header: %s: %s\n", key, value);
+
if (av_stristart(value, "Basic ", &p) &&
state->auth_type <= HTTP_AUTH_BASIC) {
+ av_log(NULL, AV_LOG_DEBUG, "Setting Basic authentication\n");
state->auth_type = HTTP_AUTH_BASIC;
state->realm[0] = 0;
state->stale = 0;
ff_parse_key_value(p, (ff_parse_key_val_cb) handle_basic_params,
state);
- } else if (av_stristart(value, "Digest ", &p) &&
- state->auth_type <= HTTP_AUTH_DIGEST) {
- state->auth_type = HTTP_AUTH_DIGEST;
- memset(&state->digest_params, 0, sizeof(DigestParams));
- state->realm[0] = 0;
- state->stale = 0;
- ff_parse_key_value(p, (ff_parse_key_val_cb) handle_digest_params,
- state);
- choose_qop(state->digest_params.qop,
- sizeof(state->digest_params.qop));
- if (!av_strcasecmp(state->digest_params.stale, "true"))
- state->stale = 1;
+ } else if (av_stristart(value, "Digest ", &p)) {
+ /* Handle multiple Digest authentication headers by preferring MD5 over SHA-256
+ * or updating if we haven't set digest auth yet */
+ if (state->auth_type <= HTTP_AUTH_DIGEST) {
+ const char *alg_start = strstr(p, "algorithm=");
+ int is_md5 = 1; /* Default to MD5 if no algorithm specified */
+
+ if (alg_start) {
+ alg_start += 10; /* Skip "algorithm=" */
+ if (av_strncasecmp(alg_start, "\"MD5\"", 5) == 0 || av_strncasecmp(alg_start, "MD5", 3) == 0) {
+ is_md5 = 1;
+ } else if (av_strncasecmp(alg_start, "\"SHA-256\"", 9) == 0 || av_strncasecmp(alg_start, "SHA-256", 7) == 0) {
+ is_md5 = 0;
+ }
+ }
+
+ av_log(NULL, AV_LOG_DEBUG, "Digest auth: algorithm=%s, is_md5=%d, current_auth_type=%d\n",
+ alg_start ? alg_start : "none", is_md5, state->auth_type);
+
+ /* Prefer MD5 over SHA-256, or set if not already set */
+ if (state->auth_type < HTTP_AUTH_DIGEST ||
+ (is_md5 && av_strcasecmp(state->digest_params.algorithm, "MD5") != 0)) {
+ av_log(NULL, AV_LOG_DEBUG, "Setting Digest authentication with algorithm preference\n");
+ state->auth_type = HTTP_AUTH_DIGEST;
+ memset(&state->digest_params, 0, sizeof(DigestParams));
+ state->realm[0] = 0;
+ state->stale = 0;
+ ff_parse_key_value(p, (ff_parse_key_val_cb) handle_digest_params,
+ state);
+ choose_qop(state->digest_params.qop,
+ sizeof(state->digest_params.qop));
+ if (!av_strcasecmp(state->digest_params.stale, "true"))
+ state->stale = 1;
+
+ av_log(NULL, AV_LOG_DEBUG, "Digest params: realm=%s, nonce=%s, algorithm=%s, qop=%s\n",
+ state->realm, state->digest_params.nonce,
+ state->digest_params.algorithm, state->digest_params.qop);
+ } else {
+ av_log(NULL, AV_LOG_DEBUG, "Skipping digest auth header (already have better)\n");
+ }
+ }
}
} else if (!av_strcasecmp(key, "Authentication-Info")) {
ff_parse_key_value(value, (ff_parse_key_val_cb) handle_digest_update,
@@ -220,9 +252,11 @@ static char *make_digest_auth(HTTPAuthState *state, const char *username,
av_strlcatf(authstr, len, ", uri=\"%s\"", uri);
av_strlcatf(authstr, len, ", response=\"%s\"", response);
- // we are violating the RFC and use "" because all others seem to do that too.
+ // Always include algorithm for better compatibility
if (digest->algorithm[0])
av_strlcatf(authstr, len, ", algorithm=\"%s\"", digest->algorithm);
+ else
+ av_strlcatf(authstr, len, ", algorithm=\"MD5\"");
if (digest->opaque[0])
av_strlcatf(authstr, len, ", opaque=\"%s\"", digest->opaque);
@@ -245,8 +279,14 @@ char *ff_http_auth_create_response(HTTPAuthState *state, const char *auth,
/* Clear the stale flag, we assume the auth is ok now. It is reset
* by the server headers if there's a new issue. */
state->stale = 0;
- if (!auth || !strchr(auth, ':'))
+
+ av_log(NULL, AV_LOG_DEBUG, "Creating auth response: auth_type=%d, auth=%s, path=%s, method=%s\n",
+ state->auth_type, auth ? "[provided]" : "[null]", path ? path : "[null]", method ? method : "[null]");
+
+ if (!auth || !strchr(auth, ':')) {
+ av_log(NULL, AV_LOG_DEBUG, "No valid auth credentials provided\n");
return NULL;
+ }
if (state->auth_type == HTTP_AUTH_BASIC) {
int auth_b64_len, len;
@@ -269,17 +309,30 @@ char *ff_http_auth_create_response(HTTPAuthState *state, const char *auth,
av_base64_encode(ptr, auth_b64_len, decoded_auth, strlen(decoded_auth));
av_strlcat(ptr, "\r\n", len - (ptr - authstr));
av_free(decoded_auth);
+ av_log(NULL, AV_LOG_DEBUG, "Created Basic auth response\n");
} else if (state->auth_type == HTTP_AUTH_DIGEST) {
char *username = ff_urldecode(auth, 0), *password;
- if (!username)
+ if (!username) {
+ av_log(NULL, AV_LOG_DEBUG, "Failed to decode username\n");
return NULL;
+ }
if ((password = strchr(username, ':'))) {
*password++ = 0;
+ av_log(NULL, AV_LOG_DEBUG, "Creating digest auth for user: %s\n", username);
authstr = make_digest_auth(state, username, password, path, method);
+ if (authstr) {
+ av_log(NULL, AV_LOG_DEBUG, "Created Digest auth response: %s\n", authstr);
+ } else {
+ av_log(NULL, AV_LOG_DEBUG, "Failed to create Digest auth response\n");
+ }
+ } else {
+ av_log(NULL, AV_LOG_DEBUG, "No password found in auth string\n");
}
av_free(username);
+ } else {
+ av_log(NULL, AV_LOG_DEBUG, "Unknown auth type: %d\n", state->auth_type);
}
return authstr;
}
--
2.49.0.windows.1
_______________________________________________
ffmpeg-devel mailing list -- ffmpeg-devel@ffmpeg.org
To unsubscribe send an email to ffmpeg-devel-leave@ffmpeg.org
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2025-12-12 5:28 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-12 4:11 [FFmpeg-devel] [PATCH] Some RTSP server response 401 with multiple Digest and FFmpeg fails Zhigong Liu via ffmpeg-devel
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git