From 1d5f3c92aeae4cfe9316e4a660cb83159686c128 Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Sat, 30 Oct 2021 14:47:58 +0200 Subject: [PATCH] add VLC authentication workaround --- client_read_test.go | 4 ++-- client_test.go | 2 +- pkg/auth/package_test.go | 8 ++++---- pkg/auth/validator.go | 36 ++++++++++++++++++++++++++++++++---- pkg/auth/validator_test.go | 2 +- serverconn.go | 9 --------- serversession.go | 9 +++++++++ 7 files changed, 49 insertions(+), 21 deletions(-) diff --git a/client_read_test.go b/client_read_test.go index 58ff8d90..f9ebffce 100644 --- a/client_read_test.go +++ b/client_read_test.go @@ -975,7 +975,7 @@ func TestClientReadAutomaticProtocol(t *testing.T) { require.NoError(t, err) require.Equal(t, base.Describe, req.Method) - err = v.ValidateRequest(req, nil) + err = v.ValidateRequest(req) require.NoError(t, err) track, err := NewTrackH264(96, &TrackConfigH264{[]byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}}) @@ -1063,7 +1063,7 @@ func TestClientReadAutomaticProtocol(t *testing.T) { require.Equal(t, base.Setup, req.Method) require.Equal(t, mustParseURL("rtsp://localhost:8554/teststream/trackID=0"), req.URL) - err = v.ValidateRequest(req, nil) + err = v.ValidateRequest(req) require.NoError(t, err) inTH = headers.Transport{} diff --git a/client_test.go b/client_test.go index 9631d551..17c0a213 100644 --- a/client_test.go +++ b/client_test.go @@ -146,7 +146,7 @@ func TestClientAuth(t *testing.T) { require.NoError(t, err) require.Equal(t, base.Describe, req.Method) - err = v.ValidateRequest(req, nil) + err = v.ValidateRequest(req) require.NoError(t, err) track, err := NewTrackH264(96, &TrackConfigH264{[]byte{0x01, 0x02, 0x03, 0x04}, []byte{0x01, 0x02, 0x03, 0x04}}) diff --git a/pkg/auth/package_test.go b/pkg/auth/package_test.go index 795fafec..305ffb0a 100644 --- a/pkg/auth/package_test.go +++ b/pkg/auth/package_test.go @@ -77,7 +77,7 @@ func TestAuth(t *testing.T) { req.URL = mustParseURL("rtsp://myhost/mypath") - err = va.ValidateRequest(req, nil) + err = va.ValidateRequest(req) if conf != "nofail" { require.Error(t, err) @@ -110,14 +110,14 @@ func TestAuthVLC(t *testing.T) { require.NoError(t, err) req := &base.Request{ - Method: base.Announce, + Method: base.Setup, URL: mustParseURL(ca.clientURL), } se.AddAuthorization(req) req.URL = mustParseURL(ca.serverURL) - err = va.ValidateRequest(req, mustParseURL(ca.clientURL)) + err = va.ValidateRequest(req) require.NoError(t, err) } } @@ -154,7 +154,7 @@ func TestAuthHashed(t *testing.T) { } va.AddAuthorization(req) - err = se.ValidateRequest(req, nil) + err = se.ValidateRequest(req) if conf != "nofail" { require.Error(t, err) diff --git a/pkg/auth/validator.go b/pkg/auth/validator.go index 0e0588dc..ee240b2d 100644 --- a/pkg/auth/validator.go +++ b/pkg/auth/validator.go @@ -10,6 +10,34 @@ import ( "github.com/aler9/gortsplib/pkg/headers" ) +func stringsReverseIndex(s, substr string) int { + for i := len(s) - 1 - len(substr); i >= 0; i-- { + if s[i:i+len(substr)] == substr { + return i + } + } + return -1 +} + +func generateAltURL(req *base.Request) (*base.URL, bool) { + if req.Method != base.Setup { + return nil, false + } + + pathAndQuery, ok := req.URL.RTSPPathAndQuery() + if !ok { + return nil, false + } + + i := stringsReverseIndex(pathAndQuery, "/trackID=") + if i < 0 { + return nil, false + } + + ur, _ := base.ParseURL(req.URL.Scheme + "://" + req.URL.Host + "/" + pathAndQuery[:i+1]) + return ur, true +} + // Validator allows to validate credentials generated by a Sender. type Validator struct { user string @@ -84,8 +112,7 @@ func (va *Validator) Header() base.HeaderValue { } // ValidateRequest validates a request sent by a client. -func (va *Validator) ValidateRequest(req *base.Request, - altURL *base.URL) error { +func (va *Validator) ValidateRequest(req *base.Request) error { var auth headers.Authorization err := auth.Read(req.Header["Authorization"]) if err != nil { @@ -150,8 +177,9 @@ func (va *Validator) ValidateRequest(req *base.Request, ur := req.URL if *auth.DigestValues.URI != ur.String() { - // do another try with the alternative URL - if altURL != nil { + // in SETUP requests, VLC strips the control attribute. + // try again with an alternative URL without the control attribute. + if altURL, ok := generateAltURL(req); ok { ur = altURL if *auth.DigestValues.URI != ur.String() { diff --git a/pkg/auth/validator_test.go b/pkg/auth/validator_test.go index 596d863a..605ea3c1 100644 --- a/pkg/auth/validator_test.go +++ b/pkg/auth/validator_test.go @@ -64,7 +64,7 @@ func TestValidatorErrors(t *testing.T) { Header: base.Header{ "Authorization": ca.hv, }, - }, nil) + }) require.Equal(t, ca.err, err.Error()) }) } diff --git a/serverconn.go b/serverconn.go index cc32230f..6bb4e2b7 100644 --- a/serverconn.go +++ b/serverconn.go @@ -19,15 +19,6 @@ const ( serverConnWriteBufferSize = 4096 ) -func stringsReverseIndex(s, substr string) int { - for i := len(s) - 1 - len(substr); i >= 0; i-- { - if s[i:i+len(substr)] == substr { - return i - } - } - return -1 -} - func getSessionID(header base.Header) string { if h, ok := header["Session"]; ok && len(h) == 1 { return h[0] diff --git a/serversession.go b/serversession.go index c523f5aa..ba488118 100644 --- a/serversession.go +++ b/serversession.go @@ -20,6 +20,15 @@ const ( serverSessionCheckStreamPeriod = 1 * time.Second ) +func stringsReverseIndex(s, substr string) int { + for i := len(s) - 1 - len(substr); i >= 0; i-- { + if s[i:i+len(substr)] == substr { + return i + } + } + return -1 +} + func setupGetTrackIDPathQuery( url *base.URL, thMode *headers.TransportMode,