url: use same credentials on redirect

Previously it could lose the username and only use the password.

Added test 998 and 999 to verify.

Reported-by: Tobias Bora
Fixes #15262
Closes #15282
This commit is contained in:
Daniel Stenberg 2024-10-12 23:54:39 +02:00
parent eb77297ccc
commit 9bee39bfed
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
6 changed files with 257 additions and 73 deletions

View File

@ -679,6 +679,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
if(data->set.str[STRING_USERNAME] ||
data->set.str[STRING_PASSWORD])
data->state.creds_from = CREDS_OPTION;
if(!result) if(!result)
result = Curl_setstropt(&data->state.aptr.user, result = Curl_setstropt(&data->state.aptr.user,
data->set.str[STRING_USERNAME]); data->set.str[STRING_USERNAME]);

View File

@ -1860,10 +1860,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return result; return result;
/* /*
* username and password set with their own options override the * username and password set with their own options override the credentials
* credentials possibly set in the URL. * possibly set in the URL, but netrc does not.
*/ */
if(!data->set.str[STRING_PASSWORD]) { if(!data->state.aptr.passwd || (data->state.creds_from != CREDS_OPTION)) {
uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0); uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
if(!uc) { if(!uc) {
char *decoded; char *decoded;
@ -1876,12 +1876,13 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
result = Curl_setstropt(&data->state.aptr.passwd, decoded); result = Curl_setstropt(&data->state.aptr.passwd, decoded);
if(result) if(result)
return result; return result;
data->state.creds_from = CREDS_URL;
} }
else if(uc != CURLUE_NO_PASSWORD) else if(uc != CURLUE_NO_PASSWORD)
return Curl_uc_to_curlcode(uc); return Curl_uc_to_curlcode(uc);
} }
if(!data->set.str[STRING_USERNAME]) { if(!data->state.aptr.user || (data->state.creds_from != CREDS_OPTION)) {
/* we do not use the URL API's URL decoder option here since it rejects /* we do not use the URL API's URL decoder option here since it rejects
control codes and we want to allow them for some schemes in the user control codes and we want to allow them for some schemes in the user
and password fields */ and password fields */
@ -1895,13 +1896,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
return result; return result;
conn->user = decoded; conn->user = decoded;
result = Curl_setstropt(&data->state.aptr.user, decoded); result = Curl_setstropt(&data->state.aptr.user, decoded);
data->state.creds_from = CREDS_URL;
} }
else if(uc != CURLUE_NO_USER) else if(uc != CURLUE_NO_USER)
return Curl_uc_to_curlcode(uc); return Curl_uc_to_curlcode(uc);
else if(data->state.aptr.passwd) {
/* no user was set but a password, set a blank user */
result = Curl_setstropt(&data->state.aptr.user, "");
}
if(result) if(result)
return result; return result;
} }
@ -2685,7 +2683,8 @@ static CURLcode override_login(struct Curl_easy *data,
int ret; int ret;
bool url_provided = FALSE; bool url_provided = FALSE;
if(data->state.aptr.user) { if(data->state.aptr.user &&
(data->state.creds_from != CREDS_NETRC)) {
/* there was a username in the URL. Use the URL decoded version */ /* there was a username in the URL. Use the URL decoded version */
userp = &data->state.aptr.user; userp = &data->state.aptr.user;
url_provided = TRUE; url_provided = TRUE;
@ -2733,6 +2732,7 @@ static CURLcode override_login(struct Curl_easy *data,
result = Curl_setstropt(&data->state.aptr.user, *userp); result = Curl_setstropt(&data->state.aptr.user, *userp);
if(result) if(result)
return result; return result;
data->state.creds_from = CREDS_NETRC;
} }
} }
if(data->state.aptr.user) { if(data->state.aptr.user) {
@ -2750,6 +2750,7 @@ static CURLcode override_login(struct Curl_easy *data,
CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp); CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
if(result) if(result)
return result; return result;
data->state.creds_from = CREDS_NETRC;
} }
if(data->state.aptr.passwd) { if(data->state.aptr.passwd) {
uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,

View File

@ -1206,6 +1206,11 @@ struct urlpieces {
char *query; char *query;
}; };
#define CREDS_NONE 0
#define CREDS_URL 1 /* from URL */
#define CREDS_OPTION 2 /* set with a CURLOPT_ */
#define CREDS_NETRC 3 /* found in netrc */
struct UrlState { struct UrlState {
/* buffers to store authentication data in, as parsed from input options */ /* buffers to store authentication data in, as parsed from input options */
struct curltime keeps_speed; /* for the progress meter really */ struct curltime keeps_speed; /* for the progress meter really */
@ -1344,7 +1349,6 @@ struct UrlState {
char *proxypasswd; char *proxypasswd;
#endif #endif
} aptr; } aptr;
unsigned char httpwant; /* when non-zero, a specific HTTP version requested unsigned char httpwant; /* when non-zero, a specific HTTP version requested
to be used in the library's request(s) */ to be used in the library's request(s) */
unsigned char httpversion; /* the lowest HTTP version*10 reported by any unsigned char httpversion; /* the lowest HTTP version*10 reported by any
@ -1354,6 +1358,9 @@ struct UrlState {
unsigned char select_bits; /* != 0 -> bitmask of socket events for this unsigned char select_bits; /* != 0 -> bitmask of socket events for this
transfer overriding anything the socket may transfer overriding anything the socket may
report */ report */
unsigned int creds_from:2; /* where is the server credentials originating
from, see the CREDS_* defines above */
/* when curl_easy_perform() is called, the multi handle is "owned" by /* when curl_easy_perform() is called, the multi handle is "owned" by
the easy handle so curl_easy_cleanup() on such an easy handle will the easy handle so curl_easy_cleanup() on such an easy handle will
also close the multi handle! */ also close the multi handle! */

View File

@ -133,69 +133,69 @@ test961 test962 test963 test964 test965 test966 test967 test968 test969 \
test970 test971 test972 test973 test974 test975 test976 test977 test978 \ test970 test971 test972 test973 test974 test975 test976 test977 test978 \
test979 test980 test981 test982 test983 test984 test985 test986 test987 \ test979 test980 test981 test982 test983 test984 test985 test986 test987 \
test988 test989 test990 test991 test992 test993 test994 test995 test996 \ test988 test989 test990 test991 test992 test993 test994 test995 test996 \
test997 \ test997 test998 test999 test1000 test1001 test1002 test1003 test1004 \
test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \ test1005 test1006 test1007 test1008 test1009 test1010 test1011 test1012 \
test1008 test1009 test1010 test1011 test1012 test1013 test1014 test1015 \ test1013 test1014 test1015 test1016 test1017 test1018 test1019 test1020 \
test1016 test1017 test1018 test1019 test1020 test1021 test1022 test1023 \ test1021 test1022 test1023 test1024 test1025 test1026 test1027 test1028 \
test1024 test1025 test1026 test1027 test1028 test1029 test1030 test1031 \ test1029 test1030 test1031 test1032 test1033 test1034 test1035 test1036 \
test1032 test1033 test1034 test1035 test1036 test1037 test1038 test1039 \ test1037 test1038 test1039 test1040 test1041 test1042 test1043 test1044 \
test1040 test1041 test1042 test1043 test1044 test1045 test1046 test1047 \ test1045 test1046 test1047 test1048 test1049 test1050 test1051 test1052 \
test1048 test1049 test1050 test1051 test1052 test1053 test1054 test1055 \ test1053 test1054 test1055 test1056 test1057 test1058 test1059 test1060 \
test1056 test1057 test1058 test1059 test1060 test1061 test1062 test1063 \ test1061 test1062 test1063 test1064 test1065 test1066 test1067 test1068 \
test1064 test1065 test1066 test1067 test1068 test1069 test1070 test1071 \ test1069 test1070 test1071 test1072 test1073 test1074 test1075 test1076 \
test1072 test1073 test1074 test1075 test1076 test1077 test1078 test1079 \ test1077 test1078 test1079 test1080 test1081 test1082 test1083 test1084 \
test1080 test1081 test1082 test1083 test1084 test1085 test1086 test1087 \ test1085 test1086 test1087 test1088 test1089 test1090 test1091 test1092 \
test1088 test1089 test1090 test1091 test1092 test1093 test1094 test1095 \ test1093 test1094 test1095 test1096 test1097 test1098 test1099 test1100 \
test1096 test1097 test1098 test1099 test1100 test1101 test1102 test1103 \ test1101 test1102 test1103 test1104 test1105 test1106 test1107 test1108 \
test1104 test1105 test1106 test1107 test1108 test1109 test1110 test1111 \ test1109 test1110 test1111 test1112 test1113 test1114 test1115 test1116 \
test1112 test1113 test1114 test1115 test1116 test1117 test1118 test1119 \ test1117 test1118 test1119 test1120 test1121 test1122 test1123 test1124 \
test1120 test1121 test1122 test1123 test1124 test1125 test1126 test1127 \ test1125 test1126 test1127 test1128 test1129 test1130 test1131 test1132 \
test1128 test1129 test1130 test1131 test1132 test1133 test1134 test1135 \ test1133 test1134 test1135 test1136 test1137 test1138 test1139 test1140 \
test1136 test1137 test1138 test1139 test1140 test1141 test1142 test1143 \ test1141 test1142 test1143 test1144 test1145 test1146 test1147 test1148 \
test1144 test1145 test1146 test1147 test1148 test1149 test1150 test1151 \ test1149 test1150 test1151 test1152 test1153 test1154 test1155 test1156 \
test1152 test1153 test1154 test1155 test1156 test1157 test1158 test1159 \ test1157 test1158 test1159 test1160 test1161 test1162 test1163 test1164 \
test1160 test1161 test1162 test1163 test1164 test1165 test1166 test1167 \ test1165 test1166 test1167 test1168 test1169 test1170 test1171 test1172 \
test1168 test1169 test1170 test1171 test1172 test1173 test1174 test1175 \ test1173 test1174 test1175 test1176 test1177 test1178 test1179 test1180 \
test1176 test1177 test1178 test1179 test1180 test1181 test1182 test1183 \ test1181 test1182 test1183 test1184 test1185 test1186 test1187 test1188 \
test1184 test1185 test1186 test1187 test1188 test1189 test1190 test1190 \ test1189 test1190 test1190 test1191 test1192 test1193 test1194 test1195 \
test1191 test1192 test1193 test1194 test1195 test1196 test1197 test1198 \ test1196 test1197 test1198 test1199 test1200 test1201 test1202 test1203 \
test1199 test1200 test1201 test1202 test1203 test1204 test1205 test1206 \ test1204 test1205 test1206 test1207 test1208 test1209 test1210 test1211 \
test1207 test1208 test1209 test1210 test1211 test1212 test1213 test1214 \ test1212 test1213 test1214 test1215 test1216 test1217 test1218 test1219 \
test1215 test1216 test1217 test1218 test1219 test1220 test1221 test1222 \ test1220 test1221 test1222 test1223 test1224 test1225 test1226 test1227 \
test1223 test1224 test1225 test1226 test1227 test1228 test1229 test1230 \ test1228 test1229 test1230 test1231 test1232 test1233 test1234 test1235 \
test1231 test1232 test1233 test1234 test1235 test1236 test1237 test1238 \ test1236 test1237 test1238 test1239 test1240 test1241 test1242 test1243 \
test1239 test1240 test1241 test1242 test1243 test1244 test1245 test1246 \ test1244 test1245 test1246 test1247 test1248 test1249 test1250 test1251 \
test1247 test1248 test1249 test1250 test1251 test1252 test1253 test1254 \ test1252 test1253 test1254 test1255 test1256 test1257 test1258 test1259 \
test1255 test1256 test1257 test1258 test1259 test1260 test1261 test1262 \ test1260 test1261 test1262 test1263 test1264 test1265 test1266 test1267 \
test1263 test1264 test1265 test1266 test1267 test1268 test1269 test1270 \ test1268 test1269 test1270 test1271 test1272 test1273 test1274 test1275 \
test1271 test1272 test1273 test1274 test1275 test1276 test1277 test1278 \ test1276 test1277 test1278 test1279 test1280 test1281 test1282 test1283 \
test1279 test1280 test1281 test1282 test1283 test1284 test1285 test1286 \ test1284 test1285 test1286 test1287 test1288 test1289 test1290 test1291 \
test1287 test1288 test1289 test1290 test1291 test1292 test1293 test1294 \ test1292 test1293 test1294 test1295 test1296 test1297 test1298 test1299 \
test1295 test1296 test1297 test1298 test1299 test1300 test1301 test1302 \ test1300 test1301 test1302 test1303 test1304 test1305 test1306 test1307 \
test1303 test1304 test1305 test1306 test1307 test1308 test1309 test1310 \ test1308 test1309 test1310 test1311 test1312 test1313 test1314 test1315 \
test1311 test1312 test1313 test1314 test1315 test1316 test1317 test1318 \ test1316 test1317 test1318 test1319 test1320 test1321 test1322 test1323 \
test1319 test1320 test1321 test1322 test1323 test1324 test1325 test1326 \ test1324 test1325 test1326 test1327 test1328 test1329 test1330 test1331 \
test1327 test1328 test1329 test1330 test1331 test1332 test1333 test1334 \ test1332 test1333 test1334 test1335 test1336 test1337 test1338 test1339 \
test1335 test1336 test1337 test1338 test1339 test1340 test1341 test1342 \ test1340 test1341 test1342 test1343 test1344 test1345 test1346 test1347 \
test1343 test1344 test1345 test1346 test1347 test1348 test1349 test1350 \ test1348 test1349 test1350 test1351 test1352 test1353 test1354 test1355 \
test1351 test1352 test1353 test1354 test1355 test1356 test1357 test1358 \ test1356 test1357 test1358 test1359 test1360 test1361 test1362 test1363 \
test1359 test1360 test1361 test1362 test1363 test1364 test1365 test1366 \ test1364 test1365 test1366 test1367 test1368 test1369 test1370 test1371 \
test1367 test1368 test1369 test1370 test1371 test1372 test1373 test1374 \ test1372 test1373 test1374 test1375 test1376 test1377 test1378 test1379 \
test1375 test1376 test1377 test1378 test1379 test1380 test1381 test1382 \ test1380 test1381 test1382 test1383 test1384 test1385 test1386 test1387 \
test1383 test1384 test1385 test1386 test1387 test1388 test1389 test1390 \ test1388 test1389 test1390 test1391 test1392 test1393 test1394 test1395 \
test1391 test1392 test1393 test1394 test1395 test1396 test1397 test1398 \ test1396 test1397 test1398 test1399 test1400 test1401 test1402 test1403 \
test1399 test1400 test1401 test1402 test1403 test1404 test1405 test1406 \ test1404 test1405 test1406 test1407 test1408 test1409 test1410 test1411 \
test1407 test1408 test1409 test1410 test1411 test1412 test1413 test1414 \ test1412 test1413 test1414 test1415 test1416 test1417 test1418 test1419 \
test1415 test1416 test1417 test1418 test1419 test1420 test1421 test1422 \ test1420 test1421 test1422 test1423 test1424 test1425 test1426 test1427 \
test1423 test1424 test1425 test1426 test1427 test1428 test1429 test1430 \ test1428 test1429 test1430 test1431 test1432 test1433 test1434 test1435 \
test1431 test1432 test1433 test1434 test1435 test1436 test1437 test1438 \ test1436 test1437 test1438 test1439 test1440 test1441 test1442 test1443 \
test1439 test1440 test1441 test1442 test1443 test1444 test1445 test1446 \ test1444 test1445 test1446 test1447 test1448 test1449 test1450 test1451 \
test1447 test1448 test1449 test1450 test1451 test1452 test1453 test1454 \ test1452 test1453 test1454 test1455 test1456 test1457 test1458 test1459 \
test1455 test1456 test1457 test1458 test1459 test1460 test1461 test1462 \ test1460 test1461 test1462 test1463 test1464 test1465 test1466 test1467 \
test1463 test1464 test1465 test1466 test1467 test1468 test1469 test1470 \ test1468 test1469 test1470 test1471 test1472 test1473 test1474 test1475 \
test1471 test1472 test1473 test1474 test1475 test1476 test1477 test1478 \ test1476 test1477 test1478 test1479 test1480 test1481 test1482 test1483 \
test1479 test1480 test1481 test1482 test1483 test1484 test1485 test1486 \ test1484 test1485 test1486 test1487 test1488 test1489 test1490 test1491 \
test1487 test1488 test1489 test1490 test1491 test1492 \ test1492 \
\ \
test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \ test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \ test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \

92
tests/data/test998 Normal file
View File

@ -0,0 +1,92 @@
<testcase>
<info>
<keywords>
HTTP
--location-trusted
</keywords>
</info>
#
# Server-side
<reply>
<data>
HTTP/1.1 301 redirect
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 0
Connection: close
Content-Type: text/html
Location: http://somewhere.else.example/a/path/%TESTNUMBER0002
</data>
<data2>
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Content-Length: 6
Content-Type: text/html
Funny-head: yesyes
-foo-
</data2>
<datacheck>
HTTP/1.1 301 redirect
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 0
Connection: close
Content-Type: text/html
Location: http://somewhere.else.example/a/path/%TESTNUMBER0002
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Content-Length: 6
Content-Type: text/html
Funny-head: yesyes
-foo-
</datacheck>
</reply>
#
# Client-side
<client>
<features>
proxy
</features>
<server>
http
</server>
<name>
HTTP with auth in URL redirected to another host
</name>
<command>
-x %HOSTIP:%HTTPPORT http://alberto:einstein@somwhere.example/%TESTNUMBER --location-trusted
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<strip>
QUIT
</strip>
<protocol>
GET http://somwhere.example/998 HTTP/1.1
Host: somwhere.example
Authorization: Basic YWxiZXJ0bzplaW5zdGVpbg==
User-Agent: curl/%VERSION
Accept: */*
Proxy-Connection: Keep-Alive
GET http://somewhere.else.example/a/path/9980002 HTTP/1.1
Host: somewhere.else.example
Authorization: Basic YWxiZXJ0bzplaW5zdGVpbg==
User-Agent: curl/%VERSION
Accept: */*
Proxy-Connection: Keep-Alive
</protocol>
</verify>
</testcase>

81
tests/data/test999 Normal file
View File

@ -0,0 +1,81 @@
<testcase>
<info>
<keywords>
HTTP
--location-trusted
</keywords>
</info>
#
# Server-side
<reply>
<data nocheck="yes">
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Content-Length: 6
Content-Type: text/html
Funny-head: yesyes
-foo-
</data>
<datacheck>
HTTP/1.1 301 redirect
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 0
Connection: close
Content-Type: text/html
Location: http://somewhere.else.example/a/path/%TESTNUMBER0002
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Content-Length: 6
Content-Type: text/html
Funny-head: yesyes
-foo-
</datacheck>
</reply>
#
# Client-side
<client>
<features>
proxy
</features>
<server>
http
</server>
<name>
HTTP with auth in first URL but not second
</name>
<command>
-x %HOSTIP:%HTTPPORT http://alberto:einstein@somwhere.example/%TESTNUMBER http://somewhere.else.example/%TESTNUMBER
</command>
</client>
#
# Verify data after the test has been "shot"
<verify>
<strip>
QUIT
</strip>
<protocol>
GET http://somwhere.example/%TESTNUMBER HTTP/1.1
Host: somwhere.example
Authorization: Basic YWxiZXJ0bzplaW5zdGVpbg==
User-Agent: curl/%VERSION
Accept: */*
Proxy-Connection: Keep-Alive
GET http://somewhere.else.example/%TESTNUMBER HTTP/1.1
Host: somewhere.else.example
User-Agent: curl/%VERSION
Accept: */*
Proxy-Connection: Keep-Alive
</protocol>
</verify>
</testcase>