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:
|
case 401:
|
||||||
if (rtspAuthUserInfo != null && !receivedAuthorizationRequest) {
|
if (rtspAuthUserInfo != null && !receivedAuthorizationRequest) {
|
||||||
// Unauthorized.
|
// Unauthorized.
|
||||||
@Nullable
|
ImmutableList<String> wwwAuthenticateHeaders =
|
||||||
String wwwAuthenticateHeader = response.headers.get(RtspHeaders.WWW_AUTHENTICATE);
|
response.headers.values(RtspHeaders.WWW_AUTHENTICATE);
|
||||||
if (wwwAuthenticateHeader == null) {
|
if (wwwAuthenticateHeaders.isEmpty()) {
|
||||||
throw ParserException.createForMalformedManifest(
|
throw ParserException.createForMalformedManifest(
|
||||||
"Missing WWW-Authenticate header in a 401 response.", /* cause= */ null);
|
"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();
|
messageSender.retryLastRequest();
|
||||||
receivedAuthorizationRequest = true;
|
receivedAuthorizationRequest = true;
|
||||||
return;
|
return;
|
||||||
|
@ -92,7 +92,7 @@ public final class RtspClientTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||||
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
||||||
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
|
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
|
||||||
}
|
}
|
||||||
@ -167,7 +167,7 @@ public final class RtspClientTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||||
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
||||||
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
|
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
|
||||||
}
|
}
|
||||||
@ -209,7 +209,7 @@ public final class RtspClientTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||||
if (!requestedUri.getPath().contains("redirect")) {
|
if (!requestedUri.getPath().contains("redirect")) {
|
||||||
return new RtspResponse(
|
return new RtspResponse(
|
||||||
301,
|
301,
|
||||||
@ -263,7 +263,7 @@ public final class RtspClientTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||||
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
||||||
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
|
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
|
||||||
}
|
}
|
||||||
@ -310,7 +310,7 @@ public final class RtspClientTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||||
clientHasSentDescribeRequest.set(true);
|
clientHasSentDescribeRequest.set(true);
|
||||||
return RtspTestUtils.RTSP_ERROR_METHOD_NOT_ALLOWED;
|
return RtspTestUtils.RTSP_ERROR_METHOD_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
@ -356,7 +356,7 @@ public final class RtspClientTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||||
// This session description misses required the o, t and s tags.
|
// This session description misses required the o, t and s tags.
|
||||||
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
||||||
/* sessionDescription= */ "v=0\r\n", rtpPacketStreamDumps, requestedUri);
|
/* sessionDescription= */ "v=0\r\n", rtpPacketStreamDumps, requestedUri);
|
||||||
|
@ -62,7 +62,7 @@ public final class RtspMediaPeriodTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||||
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
||||||
"v=0\r\n"
|
"v=0\r\n"
|
||||||
+ "o=- 1606776316530225 1 IN IP4 127.0.0.1\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);
|
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
|
@Override
|
||||||
public RtspResponse getDescribeResponse(Uri requestedUri) {
|
public RtspResponse getDescribeResponse(Uri requestedUri, RtspHeaders headers) {
|
||||||
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
return RtspTestUtils.newDescribeResponseWithSdpMessage(
|
||||||
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
|
SESSION_DESCRIPTION, rtpPacketStreamDumps, requestedUri);
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ public final class RtspServer implements Closeable {
|
|||||||
RtspResponse getOptionsResponse();
|
RtspResponse getOptionsResponse();
|
||||||
|
|
||||||
/** Returns an RTSP DESCRIBE {@link RtspResponse response}. */
|
/** 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;
|
return RtspTestUtils.RTSP_ERROR_METHOD_NOT_ALLOWED;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ public final class RtspServer implements Closeable {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case METHOD_DESCRIBE:
|
case METHOD_DESCRIBE:
|
||||||
sendResponse(responseProvider.getDescribeResponse(request.uri), cSeq);
|
sendResponse(responseProvider.getDescribeResponse(request.uri, request.headers), cSeq);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case METHOD_SETUP:
|
case METHOD_SETUP:
|
||||||
|
@ -30,6 +30,7 @@ import java.util.List;
|
|||||||
/* package */ final class RtspTestUtils {
|
/* package */ final class RtspTestUtils {
|
||||||
|
|
||||||
private static final String TEST_BASE_URI = "rtsp://localhost:%d/test";
|
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";
|
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). */
|
/** 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));
|
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) {
|
public static String getRtpInfoForDumps(List<RtpPacketStreamDump> rtpPacketStreamDumps) {
|
||||||
ArrayList<String> rtpInfos = new ArrayList<>(rtpPacketStreamDumps.size());
|
ArrayList<String> rtpInfos = new ArrayList<>(rtpPacketStreamDumps.size());
|
||||||
for (RtpPacketStreamDump rtpPacketStreamDump : rtpPacketStreamDumps) {
|
for (RtpPacketStreamDump rtpPacketStreamDump : rtpPacketStreamDumps) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user