Prefers DIGEST when RTSP servers sends both BASIC and DIGEST auth info.
Issue: google/ExoPlayer#9800 Added test for RTSP authentication. PiperOrigin-RevId: 420048821
This commit is contained in:
parent
e2c4fd80d3
commit
152a1650f6
@ -554,14 +554,23 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
case 401:
|
||||
if (rtspAuthUserInfo != null && !receivedAuthorizationRequest) {
|
||||
// Unauthorized.
|
||||
@Nullable
|
||||
String wwwAuthenticateHeader = response.headers.get(RtspHeaders.WWW_AUTHENTICATE);
|
||||
if (wwwAuthenticateHeader == null) {
|
||||
ImmutableList<String> wwwAuthenticateHeaders =
|
||||
response.headers.values(RtspHeaders.WWW_AUTHENTICATE);
|
||||
if (wwwAuthenticateHeaders.isEmpty()) {
|
||||
throw ParserException.createForMalformedManifest(
|
||||
"Missing WWW-Authenticate header in a 401 response.", /* cause= */ null);
|
||||
}
|
||||
rtspAuthenticationInfo =
|
||||
RtspMessageUtil.parseWwwAuthenticateHeader(wwwAuthenticateHeader);
|
||||
|
||||
for (int i = 0; i < wwwAuthenticateHeaders.size(); i++) {
|
||||
rtspAuthenticationInfo =
|
||||
RtspMessageUtil.parseWwwAuthenticateHeader(wwwAuthenticateHeaders.get(i));
|
||||
if (rtspAuthenticationInfo.authenticationMechanism
|
||||
== RtspAuthenticationInfo.DIGEST) {
|
||||
// Prefers DIGEST when RTSP servers sends both BASIC and DIGEST auth info.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
messageSender.retryLastRequest();
|
||||
receivedAuthorizationRequest = true;
|
||||
return;
|
||||
|
@ -92,7 +92,7 @@ public final class RtspClientTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
||||
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
|
||||
}
|
||||
@ -167,7 +167,7 @@ public final class RtspClientTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
||||
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
|
||||
}
|
||||
@ -209,7 +209,7 @@ public final class RtspClientTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||
if (!requestedUri.getPath().contains("redirect")) {
|
||||
return new RtspResponse(
|
||||
301,
|
||||
@ -263,7 +263,7 @@ public final class RtspClientTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
||||
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
|
||||
}
|
||||
@ -310,7 +310,7 @@ public final class RtspClientTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||
clientHasSentDescribeRequest.set(true);
|
||||
return RtspTestUtils.RTSP_ERROR_METHOD_NOT_ALLOWED;
|
||||
}
|
||||
@ -356,7 +356,7 @@ public final class RtspClientTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||
// This session description misses required the o, t and s tags.
|
||||
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
||||
/* sessionDescription= */ "v=0\r\n", rtpPacketStreamDumps, requestedUri);
|
||||
|
@ -62,7 +62,7 @@ public final class RtspMediaPeriodTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
||||
"v=0\r\n"
|
||||
+ "o=- 1606776316530225 1 IN IP4 127.0.0.1\r\n"
|
||||
@ -106,4 +106,89 @@ public final class RtspMediaPeriodTest {
|
||||
|
||||
assertThat(refreshedSourceDurationMs.get()).isEqualTo(50_460);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prepareMediaPeriod_withWwwAuthentication_refreshesSourceInfoAndCallsOnPrepared()
|
||||
throws Exception {
|
||||
RtpPacketStreamDump rtpPacketStreamDump =
|
||||
RtspTestUtils.readRtpPacketStreamDump("media/rtsp/aac-dump.json");
|
||||
|
||||
rtspServer =
|
||||
new RtspServer(
|
||||
new RtspServer.ResponseProvider() {
|
||||
@Override
|
||||
public RtspResponse getOptionsResponse() {
|
||||
return new RtspResponse(
|
||||
/* status= */ 200,
|
||||
new RtspHeaders.Builder().add(RtspHeaders.PUBLIC, "OPTIONS, DESCRIBE").build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||
String authorizationHeader = headers.get(RtspHeaders.AUTHORIZATION);
|
||||
if (authorizationHeader == null) {
|
||||
return new RtspResponse(
|
||||
/* status= */ 401,
|
||||
new RtspHeaders.Builder()
|
||||
.add(RtspHeaders.CSEQ, headers.get(RtspHeaders.CSEQ))
|
||||
.add(
|
||||
RtspHeaders.WWW_AUTHENTICATE,
|
||||
"Digest realm=\"LIVE555 Streaming Media\","
|
||||
+ " nonce=\"0cdfe9719e7373b7d5bb2913e2115f3f\","
|
||||
+ " opaque=\"5ccc069c403ebaf9f0171e9517f40e41\"")
|
||||
.add(RtspHeaders.WWW_AUTHENTICATE, "BASIC realm=\"WallyWorld\"")
|
||||
.build());
|
||||
}
|
||||
|
||||
if (!authorizationHeader.contains("Digest")) {
|
||||
return new RtspResponse(
|
||||
401,
|
||||
new RtspHeaders.Builder()
|
||||
.add(RtspHeaders.CSEQ, headers.get(RtspHeaders.CSEQ))
|
||||
.build());
|
||||
}
|
||||
|
||||
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
||||
"v=0\r\n"
|
||||
+ "o=- 1606776316530225 1 IN IP4 127.0.0.1\r\n"
|
||||
+ "s=Exoplayer test\r\n"
|
||||
+ "t=0 0\r\n"
|
||||
// The session is 50.46s long.
|
||||
+ "a=range:npt=0-50.46\r\n",
|
||||
ImmutableList.of(rtpPacketStreamDump),
|
||||
requestedUri);
|
||||
}
|
||||
});
|
||||
AtomicBoolean prepareCallbackCalled = new AtomicBoolean();
|
||||
AtomicLong refreshedSourceDurationMs = new AtomicLong();
|
||||
|
||||
mediaPeriod =
|
||||
new RtspMediaPeriod(
|
||||
new DefaultAllocator(/* trimOnReset= */ true, C.DEFAULT_BUFFER_SEGMENT_SIZE),
|
||||
new TransferRtpDataChannelFactory(DEFAULT_TIMEOUT_MS),
|
||||
RtspTestUtils.getTestUriWithUserInfo(
|
||||
"username", "password", rtspServer.startAndGetPortNumber()),
|
||||
/* listener= */ timing -> refreshedSourceDurationMs.set(timing.getDurationMs()),
|
||||
/* userAgent= */ "ExoPlayer:RtspPeriodTest",
|
||||
/* socketFactory= */ SocketFactory.getDefault(),
|
||||
/* debugLoggingEnabled= */ false);
|
||||
|
||||
mediaPeriod.prepare(
|
||||
new MediaPeriod.Callback() {
|
||||
@Override
|
||||
public void onPrepared(MediaPeriod mediaPeriod) {
|
||||
prepareCallbackCalled.set(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onContinueLoadingRequested(MediaPeriod source) {
|
||||
source.continueLoading(/* positionUs= */ 0);
|
||||
}
|
||||
},
|
||||
/* positionUs= */ 0);
|
||||
RobolectricUtil.runMainLooperUntil(prepareCallbackCalled::get);
|
||||
mediaPeriod.release();
|
||||
|
||||
assertThat(refreshedSourceDurationMs.get()).isEqualTo(50_460);
|
||||
}
|
||||
}
|
||||
|
@ -209,7 +209,7 @@ public final class RtspPlaybackTest {
|
||||
}
|
||||
|
||||
@Override
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
||||
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
||||
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public final class RtspServer implements Closeable {
|
||||
RtspResponse getOptionsResponse();
|
||||
|
||||
/** Returns an RTSP DESCRIBE {@link RtspResponse response}. */
|
||||
default RtspResponse getDescribeResponse(Uri requestedUri) {
|
||||
default RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||
return RtspTestUtils.RTSP_ERROR_METHOD_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
@ -143,7 +143,7 @@ public final class RtspServer implements Closeable {
|
||||
break;
|
||||
|
||||
case METHOD_DESCRIBE:
|
||||
sendResponse(responseProvider.getDescribeResponse(request.uri), cSeq);
|
||||
sendResponse(responseProvider.getDescribeResponse(request.uri, request.headers), cSeq);
|
||||
break;
|
||||
|
||||
case METHOD_SETUP:
|
||||
|
@ -30,6 +30,7 @@ import java.util.List;
|
||||
/* package */ final class RtspTestUtils {
|
||||
|
||||
private static final String TEST_BASE_URI = "rtsp://localhost:%d/test";
|
||||
private static final String TEST_BASE_URI_WITH_USER_INFO = "rtsp://%s:%s@localhost:%d/test";
|
||||
private static final String RTP_TIME_FORMAT = "url=rtsp://localhost/test/%s;seq=%d;rtptime=%d";
|
||||
|
||||
/** RTSP error Method Not Allowed (RFC2326 Section 7.1.1). */
|
||||
@ -72,6 +73,14 @@ import java.util.List;
|
||||
return Uri.parse(Util.formatInvariant(TEST_BASE_URI, serverRtspPortNumber));
|
||||
}
|
||||
|
||||
/** Returns the test RTSP {@link Uri} with user info. */
|
||||
public static Uri getTestUriWithUserInfo(
|
||||
String username, String password, int serverRtspPortNumber) {
|
||||
return Uri.parse(
|
||||
Util.formatInvariant(
|
||||
TEST_BASE_URI_WITH_USER_INFO, username, password, serverRtspPortNumber));
|
||||
}
|
||||
|
||||
public static String getRtpInfoForDumps(List<RtpPacketStreamDump> rtpPacketStreamDumps) {
|
||||
ArrayList<String> rtpInfos = new ArrayList<>(rtpPacketStreamDumps.size());
|
||||
for (RtpPacketStreamDump rtpPacketStreamDump : rtpPacketStreamDumps) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user