From 2bd8ac7e191527346bb4900f3c4f805cc86714c7 Mon Sep 17 00:00:00 2001 From: Rafael Scheidt Date: Thu, 18 Apr 2024 18:55:48 -0300 Subject: [PATCH] fix support for JWT authentication in API, metrics, playback, pprof (#3253) Co-authored-by: Rafael Scheidt Co-authored-by: aler9 <46489434+aler9@users.noreply.github.com> --- internal/api/api.go | 7 +- internal/api/api_test.go | 120 ++++++++++-------- internal/core/api_test.go | 4 +- internal/core/metrics_test.go | 2 +- internal/core/path_test.go | 2 +- internal/metrics/metrics.go | 7 +- internal/playback/on_get_test.go | 41 +++--- internal/playback/on_list_test.go | 21 ++- internal/playback/server.go | 7 +- internal/pprof/pprof.go | 7 +- .../protocols/webrtc/peer_connection_test.go | 2 +- internal/record/agent_test.go | 8 +- internal/record/cleaner_test.go | 2 +- internal/servers/hls/server_test.go | 14 +- internal/servers/rtmp/server_test.go | 10 +- internal/servers/rtsp/server_test.go | 10 +- internal/servers/srt/server_test.go | 10 +- internal/servers/webrtc/server_test.go | 18 +-- internal/staticsources/webrtc/source_test.go | 2 +- internal/test/auth_manager.go | 20 +++ internal/test/logger.go | 11 ++ internal/test/nil_logger.go | 10 -- 22 files changed, 201 insertions(+), 134 deletions(-) create mode 100644 internal/test/auth_manager.go create mode 100644 internal/test/logger.go delete mode 100644 internal/test/nil_logger.go diff --git a/internal/api/api.go b/internal/api/api.go index 00597059d47..607a69cee3d 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -151,6 +151,10 @@ type WebRTCServer interface { APISessionsKick(uuid.UUID) error } +type apiAuthManager interface { + Authenticate(req *auth.Request) error +} + type apiParent interface { logger.Writer APIConfigSet(conf *conf.Conf) @@ -161,7 +165,7 @@ type API struct { Address string ReadTimeout conf.StringDuration Conf *conf.Conf - AuthManager *auth.Manager + AuthManager apiAuthManager PathManager PathManager RTSPServer RTSPServer RTSPSServer RTSPServer @@ -296,6 +300,7 @@ func (a *API) mwAuth(ctx *gin.Context) { err := a.AuthManager.Authenticate(&auth.Request{ User: user, Pass: pass, + Query: ctx.Request.URL.RawQuery, IP: net.ParseIP(ctx.ClientIP()), Action: conf.AuthActionAPI, }) diff --git a/internal/api/api_test.go b/internal/api/api_test.go index 3ca9fe1eedd..6fb8801162c 100644 --- a/internal/api/api_test.go +++ b/internal/api/api_test.go @@ -106,20 +106,38 @@ func TestPaginate(t *testing.T) { require.Equal(t, []int{4, 5}, items) } -var authManager = &auth.Manager{ - Method: conf.AuthMethodInternal, - InternalUsers: []conf.AuthInternalUser{ - { - User: "myuser", - Pass: "mypass", - Permissions: []conf.AuthInternalUserPermission{ - { - Action: conf.AuthActionAPI, - }, +func TestConfigAuth(t *testing.T) { + cnf := tempConf(t, "api: yes\n") + + api := API{ + Address: "localhost:9997", + ReadTimeout: conf.StringDuration(10 * time.Second), + Conf: cnf, + AuthManager: &test.AuthManager{ + Func: func(req *auth.Request) error { + require.Equal(t, &auth.Request{ + User: "myuser", + Pass: "mypass", + IP: req.IP, + Action: "api", + Query: "key=val", + }, req) + return nil }, }, - }, - RTSPAuthMethods: nil, + Parent: &testParent{}, + } + err := api.Initialize() + require.NoError(t, err) + defer api.Close() + + tr := &http.Transport{} + defer tr.CloseIdleConnections() + hc := &http.Client{Transport: tr} + + var out map[string]interface{} + httpRequest(t, hc, http.MethodGet, "http://myuser:mypass@localhost:9997/v3/config/global/get?key=val", nil, &out) + require.Equal(t, true, out["api"]) } func TestConfigGlobalGet(t *testing.T) { @@ -129,7 +147,7 @@ func TestConfigGlobalGet(t *testing.T) { Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err := api.Initialize() @@ -141,7 +159,7 @@ func TestConfigGlobalGet(t *testing.T) { hc := &http.Client{Transport: tr} var out map[string]interface{} - httpRequest(t, hc, http.MethodGet, "http://myuser:mypass@localhost:9997/v3/config/global/get", nil, &out) + httpRequest(t, hc, http.MethodGet, "http://localhost:9997/v3/config/global/get", nil, &out) require.Equal(t, true, out["api"]) } @@ -152,7 +170,7 @@ func TestConfigGlobalPatch(t *testing.T) { Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err := api.Initialize() @@ -163,7 +181,7 @@ func TestConfigGlobalPatch(t *testing.T) { defer tr.CloseIdleConnections() hc := &http.Client{Transport: tr} - httpRequest(t, hc, http.MethodPatch, "http://myuser:mypass@localhost:9997/v3/config/global/patch", + httpRequest(t, hc, http.MethodPatch, "http://localhost:9997/v3/config/global/patch", map[string]interface{}{ "rtmp": false, "readTimeout": "7s", @@ -174,7 +192,7 @@ func TestConfigGlobalPatch(t *testing.T) { time.Sleep(500 * time.Millisecond) var out map[string]interface{} - httpRequest(t, hc, http.MethodGet, "http://myuser:mypass@localhost:9997/v3/config/global/get", nil, &out) + httpRequest(t, hc, http.MethodGet, "http://localhost:9997/v3/config/global/get", nil, &out) require.Equal(t, false, out["rtmp"]) require.Equal(t, "7s", out["readTimeout"]) require.Equal(t, []interface{}{"tcp"}, out["protocols"]) @@ -188,7 +206,7 @@ func TestConfigGlobalPatchUnknownField(t *testing.T) { //nolint:dupl Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err := api.Initialize() @@ -206,7 +224,7 @@ func TestConfigGlobalPatchUnknownField(t *testing.T) { //nolint:dupl defer tr.CloseIdleConnections() hc := &http.Client{Transport: tr} - req, err := http.NewRequest(http.MethodPatch, "http://myuser:mypass@localhost:9997/v3/config/global/patch", + req, err := http.NewRequest(http.MethodPatch, "http://localhost:9997/v3/config/global/patch", bytes.NewReader(byts)) require.NoError(t, err) @@ -225,7 +243,7 @@ func TestConfigPathDefaultsGet(t *testing.T) { Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err := api.Initialize() @@ -237,7 +255,7 @@ func TestConfigPathDefaultsGet(t *testing.T) { hc := &http.Client{Transport: tr} var out map[string]interface{} - httpRequest(t, hc, http.MethodGet, "http://myuser:mypass@localhost:9997/v3/config/pathdefaults/get", nil, &out) + httpRequest(t, hc, http.MethodGet, "http://localhost:9997/v3/config/pathdefaults/get", nil, &out) require.Equal(t, "publisher", out["source"]) } @@ -248,7 +266,7 @@ func TestConfigPathDefaultsPatch(t *testing.T) { Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err := api.Initialize() @@ -259,7 +277,7 @@ func TestConfigPathDefaultsPatch(t *testing.T) { defer tr.CloseIdleConnections() hc := &http.Client{Transport: tr} - httpRequest(t, hc, http.MethodPatch, "http://myuser:mypass@localhost:9997/v3/config/pathdefaults/patch", + httpRequest(t, hc, http.MethodPatch, "http://localhost:9997/v3/config/pathdefaults/patch", map[string]interface{}{ "readUser": "myuser", "readPass": "mypass", @@ -268,7 +286,7 @@ func TestConfigPathDefaultsPatch(t *testing.T) { time.Sleep(500 * time.Millisecond) var out map[string]interface{} - httpRequest(t, hc, http.MethodGet, "http://myuser:mypass@localhost:9997/v3/config/pathdefaults/get", nil, &out) + httpRequest(t, hc, http.MethodGet, "http://localhost:9997/v3/config/pathdefaults/get", nil, &out) require.Equal(t, "myuser", out["readUser"]) require.Equal(t, "mypass", out["readPass"]) } @@ -287,7 +305,7 @@ func TestConfigPathsList(t *testing.T) { Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err := api.Initialize() @@ -307,7 +325,7 @@ func TestConfigPathsList(t *testing.T) { hc := &http.Client{Transport: tr} var out listRes - httpRequest(t, hc, http.MethodGet, "http://myuser:mypass@localhost:9997/v3/config/paths/list", nil, &out) + httpRequest(t, hc, http.MethodGet, "http://localhost:9997/v3/config/paths/list", nil, &out) require.Equal(t, 2, out.ItemCount) require.Equal(t, 1, out.PageCount) require.Equal(t, "path1", out.Items[0]["name"]) @@ -329,7 +347,7 @@ func TestConfigPathsGet(t *testing.T) { Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err := api.Initialize() @@ -341,7 +359,7 @@ func TestConfigPathsGet(t *testing.T) { hc := &http.Client{Transport: tr} var out map[string]interface{} - httpRequest(t, hc, http.MethodGet, "http://myuser:mypass@localhost:9997/v3/config/paths/get/my/path", nil, &out) + httpRequest(t, hc, http.MethodGet, "http://localhost:9997/v3/config/paths/get/my/path", nil, &out) require.Equal(t, "my/path", out["name"]) require.Equal(t, "myuser", out["readUser"]) } @@ -353,7 +371,7 @@ func TestConfigPathsAdd(t *testing.T) { Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err := api.Initialize() @@ -364,7 +382,7 @@ func TestConfigPathsAdd(t *testing.T) { defer tr.CloseIdleConnections() hc := &http.Client{Transport: tr} - httpRequest(t, hc, http.MethodPost, "http://myuser:mypass@localhost:9997/v3/config/paths/add/my/path", + httpRequest(t, hc, http.MethodPost, "http://localhost:9997/v3/config/paths/add/my/path", map[string]interface{}{ "source": "rtsp://127.0.0.1:9999/mypath", "sourceOnDemand": true, @@ -373,7 +391,7 @@ func TestConfigPathsAdd(t *testing.T) { }, nil) var out map[string]interface{} - httpRequest(t, hc, http.MethodGet, "http://myuser:mypass@localhost:9997/v3/config/paths/get/my/path", nil, &out) + httpRequest(t, hc, http.MethodGet, "http://localhost:9997/v3/config/paths/get/my/path", nil, &out) require.Equal(t, "rtsp://127.0.0.1:9999/mypath", out["source"]) require.Equal(t, true, out["sourceOnDemand"]) require.Equal(t, true, out["disablePublisherOverride"]) @@ -387,7 +405,7 @@ func TestConfigPathsAddUnknownField(t *testing.T) { //nolint:dupl Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err := api.Initialize() @@ -406,7 +424,7 @@ func TestConfigPathsAddUnknownField(t *testing.T) { //nolint:dupl hc := &http.Client{Transport: tr} req, err := http.NewRequest(http.MethodPost, - "http://myuser:mypass@localhost:9997/v3/config/paths/add/my/path", bytes.NewReader(byts)) + "http://localhost:9997/v3/config/paths/add/my/path", bytes.NewReader(byts)) require.NoError(t, err) res, err := hc.Do(req) @@ -424,7 +442,7 @@ func TestConfigPathsPatch(t *testing.T) { //nolint:dupl Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err := api.Initialize() @@ -435,7 +453,7 @@ func TestConfigPathsPatch(t *testing.T) { //nolint:dupl defer tr.CloseIdleConnections() hc := &http.Client{Transport: tr} - httpRequest(t, hc, http.MethodPost, "http://myuser:mypass@localhost:9997/v3/config/paths/add/my/path", + httpRequest(t, hc, http.MethodPost, "http://localhost:9997/v3/config/paths/add/my/path", map[string]interface{}{ "source": "rtsp://127.0.0.1:9999/mypath", "sourceOnDemand": true, @@ -443,14 +461,14 @@ func TestConfigPathsPatch(t *testing.T) { //nolint:dupl "rpiCameraVFlip": true, }, nil) - httpRequest(t, hc, http.MethodPatch, "http://myuser:mypass@localhost:9997/v3/config/paths/patch/my/path", + httpRequest(t, hc, http.MethodPatch, "http://localhost:9997/v3/config/paths/patch/my/path", map[string]interface{}{ "source": "rtsp://127.0.0.1:9998/mypath", "sourceOnDemand": true, }, nil) var out map[string]interface{} - httpRequest(t, hc, http.MethodGet, "http://myuser:mypass@localhost:9997/v3/config/paths/get/my/path", nil, &out) + httpRequest(t, hc, http.MethodGet, "http://localhost:9997/v3/config/paths/get/my/path", nil, &out) require.Equal(t, "rtsp://127.0.0.1:9998/mypath", out["source"]) require.Equal(t, true, out["sourceOnDemand"]) require.Equal(t, true, out["disablePublisherOverride"]) @@ -464,7 +482,7 @@ func TestConfigPathsReplace(t *testing.T) { //nolint:dupl Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err := api.Initialize() @@ -475,7 +493,7 @@ func TestConfigPathsReplace(t *testing.T) { //nolint:dupl defer tr.CloseIdleConnections() hc := &http.Client{Transport: tr} - httpRequest(t, hc, http.MethodPost, "http://myuser:mypass@localhost:9997/v3/config/paths/add/my/path", + httpRequest(t, hc, http.MethodPost, "http://localhost:9997/v3/config/paths/add/my/path", map[string]interface{}{ "source": "rtsp://127.0.0.1:9999/mypath", "sourceOnDemand": true, @@ -483,14 +501,14 @@ func TestConfigPathsReplace(t *testing.T) { //nolint:dupl "rpiCameraVFlip": true, }, nil) - httpRequest(t, hc, http.MethodPost, "http://myuser:mypass@localhost:9997/v3/config/paths/replace/my/path", + httpRequest(t, hc, http.MethodPost, "http://localhost:9997/v3/config/paths/replace/my/path", map[string]interface{}{ "source": "rtsp://127.0.0.1:9998/mypath", "sourceOnDemand": true, }, nil) var out map[string]interface{} - httpRequest(t, hc, http.MethodGet, "http://myuser:mypass@localhost:9997/v3/config/paths/get/my/path", nil, &out) + httpRequest(t, hc, http.MethodGet, "http://localhost:9997/v3/config/paths/get/my/path", nil, &out) require.Equal(t, "rtsp://127.0.0.1:9998/mypath", out["source"]) require.Equal(t, true, out["sourceOnDemand"]) require.Equal(t, nil, out["disablePublisherOverride"]) @@ -504,7 +522,7 @@ func TestConfigPathsDelete(t *testing.T) { Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err := api.Initialize() @@ -515,15 +533,15 @@ func TestConfigPathsDelete(t *testing.T) { defer tr.CloseIdleConnections() hc := &http.Client{Transport: tr} - httpRequest(t, hc, http.MethodPost, "http://myuser:mypass@localhost:9997/v3/config/paths/add/my/path", + httpRequest(t, hc, http.MethodPost, "http://localhost:9997/v3/config/paths/add/my/path", map[string]interface{}{ "source": "rtsp://127.0.0.1:9999/mypath", "sourceOnDemand": true, }, nil) - httpRequest(t, hc, http.MethodDelete, "http://myuser:mypass@localhost:9997/v3/config/paths/delete/my/path", nil, nil) + httpRequest(t, hc, http.MethodDelete, "http://localhost:9997/v3/config/paths/delete/my/path", nil, nil) - req, err := http.NewRequest(http.MethodGet, "http://myuser:mypass@localhost:9997/v3/config/paths/get/my/path", nil) + req, err := http.NewRequest(http.MethodGet, "http://localhost:9997/v3/config/paths/get/my/path", nil) require.NoError(t, err) res, err := hc.Do(req) @@ -548,7 +566,7 @@ func TestRecordingsList(t *testing.T) { Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err = api.Initialize() @@ -575,7 +593,7 @@ func TestRecordingsList(t *testing.T) { hc := &http.Client{Transport: tr} var out interface{} - httpRequest(t, hc, http.MethodGet, "http://myuser:mypass@localhost:9997/v3/recordings/list", nil, &out) + httpRequest(t, hc, http.MethodGet, "http://localhost:9997/v3/recordings/list", nil, &out) require.Equal(t, map[string]interface{}{ "itemCount": float64(2), "pageCount": float64(1), @@ -617,7 +635,7 @@ func TestRecordingsGet(t *testing.T) { Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err = api.Initialize() @@ -638,7 +656,7 @@ func TestRecordingsGet(t *testing.T) { hc := &http.Client{Transport: tr} var out interface{} - httpRequest(t, hc, http.MethodGet, "http://myuser:mypass@localhost:9997/v3/recordings/get/mypath1", nil, &out) + httpRequest(t, hc, http.MethodGet, "http://localhost:9997/v3/recordings/get/mypath1", nil, &out) require.Equal(t, map[string]interface{}{ "name": "mypath1", "segments": []interface{}{ @@ -666,7 +684,7 @@ func TestRecordingsDeleteSegment(t *testing.T) { Address: "localhost:9997", ReadTimeout: conf.StringDuration(10 * time.Second), Conf: cnf, - AuthManager: authManager, + AuthManager: test.NilAuthManager, Parent: &testParent{}, } err = api.Initialize() @@ -683,7 +701,7 @@ func TestRecordingsDeleteSegment(t *testing.T) { defer tr.CloseIdleConnections() hc := &http.Client{Transport: tr} - u, err := url.Parse("http://myuser:mypass@localhost:9997/v3/recordings/deletesegment") + u, err := url.Parse("http://localhost:9997/v3/recordings/deletesegment") require.NoError(t, err) v := url.Values{} diff --git a/internal/core/api_test.go b/internal/core/api_test.go index f8eb185a5a3..829f956d8c6 100644 --- a/internal/core/api_test.go +++ b/internal/core/api_test.go @@ -523,7 +523,7 @@ func TestAPIProtocolListGet(t *testing.T) { c := &webrtc.WHIPClient{ HTTPClient: hc, URL: u, - Log: test.NilLogger{}, + Log: test.NilLogger, } _, err = c.Read(context.Background()) @@ -996,7 +996,7 @@ func TestAPIProtocolKick(t *testing.T) { c := &webrtc.WHIPClient{ HTTPClient: hc, URL: u, - Log: test.NilLogger{}, + Log: test.NilLogger, } _, err = c.Publish(context.Background(), medi.Formats[0], nil) diff --git a/internal/core/metrics_test.go b/internal/core/metrics_test.go index 2e80491b056..5cb09c9473d 100644 --- a/internal/core/metrics_test.go +++ b/internal/core/metrics_test.go @@ -174,7 +174,7 @@ webrtc_sessions_bytes_sent 0 s := &webrtc.WHIPClient{ HTTPClient: hc, URL: su, - Log: test.NilLogger{}, + Log: test.NilLogger, } tracks, err := s.Publish(context.Background(), test.MediaH264.Formats[0], nil) diff --git a/internal/core/path_test.go b/internal/core/path_test.go index 9c8613513a1..0b21759c35b 100644 --- a/internal/core/path_test.go +++ b/internal/core/path_test.go @@ -407,7 +407,7 @@ func TestPathRunOnRead(t *testing.T) { c := &webrtc.WHIPClient{ HTTPClient: hc, URL: u, - Log: test.NilLogger{}, + Log: test.NilLogger, } writerDone := make(chan struct{}) diff --git a/internal/metrics/metrics.go b/internal/metrics/metrics.go index b6fe11e6c00..507d5a303d7 100644 --- a/internal/metrics/metrics.go +++ b/internal/metrics/metrics.go @@ -32,6 +32,10 @@ func metricFloat(key string, tags string, value float64) string { return key + tags + " " + strconv.FormatFloat(value, 'f', -1, 64) + "\n" } +type metricsAuthManager interface { + Authenticate(req *auth.Request) error +} + type metricsParent interface { logger.Writer } @@ -40,7 +44,7 @@ type metricsParent interface { type Metrics struct { Address string ReadTimeout conf.StringDuration - AuthManager *auth.Manager + AuthManager metricsAuthManager Parent metricsParent httpServer *httpp.WrappedServer @@ -100,6 +104,7 @@ func (m *Metrics) mwAuth(ctx *gin.Context) { err := m.AuthManager.Authenticate(&auth.Request{ User: user, Pass: pass, + Query: ctx.Request.URL.RawQuery, IP: net.ParseIP(ctx.ClientIP()), Action: conf.AuthActionMetrics, }) diff --git a/internal/playback/on_get_test.go b/internal/playback/on_get_test.go index 63996774978..86acb41c959 100644 --- a/internal/playback/on_get_test.go +++ b/internal/playback/on_get_test.go @@ -216,23 +216,6 @@ func writeSegment3(t *testing.T, fpath string) { require.NoError(t, err) } -var authManager = &auth.Manager{ - Method: conf.AuthMethodInternal, - InternalUsers: []conf.AuthInternalUser{ - { - User: "myuser", - Pass: "mypass", - Permissions: []conf.AuthInternalUserPermission{ - { - Action: conf.AuthActionPlayback, - Path: "mypath", - }, - }, - }, - }, - RTSPAuthMethods: nil, -} - func TestOnGet(t *testing.T) { for _, format := range []string{"fmp4", "mp4"} { t.Run(format, func(t *testing.T) { @@ -255,8 +238,20 @@ func TestOnGet(t *testing.T) { RecordPath: filepath.Join(dir, "%path/%Y-%m-%d_%H-%M-%S-%f"), }, }, - AuthManager: authManager, - Parent: &test.NilLogger{}, + AuthManager: &test.AuthManager{ + Func: func(req *auth.Request) error { + require.Equal(t, &auth.Request{ + User: "myuser", + Pass: "mypass", + IP: req.IP, + Action: "playback", + Path: "mypath", + Query: req.Query, + }, req) + return nil + }, + }, + Parent: test.NilLogger, } err = s.Initialize() require.NoError(t, err) @@ -528,8 +523,8 @@ func TestOnGetDifferentInit(t *testing.T) { RecordPath: filepath.Join(dir, "%path/%Y-%m-%d_%H-%M-%S-%f"), }, }, - AuthManager: authManager, - Parent: &test.NilLogger{}, + AuthManager: test.NilAuthManager, + Parent: test.NilLogger, } err = s.Initialize() require.NoError(t, err) @@ -603,8 +598,8 @@ func TestOnGetNTPCompensation(t *testing.T) { RecordPath: filepath.Join(dir, "%path/%Y-%m-%d_%H-%M-%S-%f"), }, }, - AuthManager: authManager, - Parent: &test.NilLogger{}, + AuthManager: test.NilAuthManager, + Parent: test.NilLogger, } err = s.Initialize() require.NoError(t, err) diff --git a/internal/playback/on_list_test.go b/internal/playback/on_list_test.go index f01307b8de0..e1795a19406 100644 --- a/internal/playback/on_list_test.go +++ b/internal/playback/on_list_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/bluenviron/mediamtx/internal/auth" "github.com/bluenviron/mediamtx/internal/conf" "github.com/bluenviron/mediamtx/internal/test" "github.com/stretchr/testify/require" @@ -34,8 +35,20 @@ func TestOnList(t *testing.T) { RecordPath: filepath.Join(dir, "%path/%Y-%m-%d_%H-%M-%S-%f"), }, }, - AuthManager: authManager, - Parent: &test.NilLogger{}, + AuthManager: &test.AuthManager{ + Func: func(req *auth.Request) error { + require.Equal(t, &auth.Request{ + User: "myuser", + Pass: "mypass", + IP: req.IP, + Action: "playback", + Query: "path=mypath", + Path: "mypath", + }, req) + return nil + }, + }, + Parent: test.NilLogger, } err = s.Initialize() require.NoError(t, err) @@ -92,8 +105,8 @@ func TestOnListDifferentInit(t *testing.T) { RecordPath: filepath.Join(dir, "%path/%Y-%m-%d_%H-%M-%S-%f"), }, }, - AuthManager: authManager, - Parent: &test.NilLogger{}, + AuthManager: test.NilAuthManager, + Parent: test.NilLogger, } err = s.Initialize() require.NoError(t, err) diff --git a/internal/playback/server.go b/internal/playback/server.go index 88033332849..8f18e7260a7 100644 --- a/internal/playback/server.go +++ b/internal/playback/server.go @@ -18,12 +18,16 @@ import ( var errNoSegmentsFound = errors.New("no recording segments found for the given timestamp") +type serverAuthManager interface { + Authenticate(req *auth.Request) error +} + // Server is the playback server. type Server struct { Address string ReadTimeout conf.StringDuration PathConfs map[string]*conf.Path - AuthManager *auth.Manager + AuthManager serverAuthManager Parent logger.Writer httpServer *httpp.WrappedServer @@ -101,6 +105,7 @@ func (p *Server) doAuth(ctx *gin.Context, pathName string) bool { err := p.AuthManager.Authenticate(&auth.Request{ User: user, Pass: pass, + Query: ctx.Request.URL.RawQuery, IP: net.ParseIP(ctx.ClientIP()), Action: conf.AuthActionPlayback, Path: pathName, diff --git a/internal/pprof/pprof.go b/internal/pprof/pprof.go index 55ada0a97ba..bd3b1e1b3cb 100644 --- a/internal/pprof/pprof.go +++ b/internal/pprof/pprof.go @@ -17,6 +17,10 @@ import ( "github.com/bluenviron/mediamtx/internal/restrictnetwork" ) +type pprofAuthManager interface { + Authenticate(req *auth.Request) error +} + type pprofParent interface { logger.Writer } @@ -25,7 +29,7 @@ type pprofParent interface { type PPROF struct { Address string ReadTimeout conf.StringDuration - AuthManager *auth.Manager + AuthManager pprofAuthManager Parent pprofParent httpServer *httpp.WrappedServer @@ -73,6 +77,7 @@ func (pp *PPROF) ServeHTTP(w http.ResponseWriter, r *http.Request) { err := pp.AuthManager.Authenticate(&auth.Request{ User: user, Pass: pass, + Query: r.URL.RawQuery, IP: net.ParseIP(ip), Action: conf.AuthActionMetrics, }) diff --git a/internal/protocols/webrtc/peer_connection_test.go b/internal/protocols/webrtc/peer_connection_test.go index f00e1fcb996..1aa747f7671 100644 --- a/internal/protocols/webrtc/peer_connection_test.go +++ b/internal/protocols/webrtc/peer_connection_test.go @@ -18,7 +18,7 @@ func TestPeerConnectionCloseAfterError(t *testing.T) { pc := &PeerConnection{ API: api, Publish: false, - Log: test.NilLogger{}, + Log: test.NilLogger, } err = pc.Start() require.NoError(t, err) diff --git a/internal/record/agent_test.go b/internal/record/agent_test.go index 28857eebc5c..29d2710e9c4 100644 --- a/internal/record/agent_test.go +++ b/internal/record/agent_test.go @@ -123,7 +123,7 @@ func TestAgent(t *testing.T) { 1460, desc, true, - &test.NilLogger{}, + test.NilLogger, ) require.NoError(t, err) defer stream.Close() @@ -158,7 +158,7 @@ func TestAgent(t *testing.T) { OnSegmentComplete: func(_ string) { segDone <- struct{}{} }, - Parent: &test.NilLogger{}, + Parent: test.NilLogger, restartPause: 1 * time.Millisecond, } w.Initialize() @@ -305,7 +305,7 @@ func TestAgentFMP4NegativeDTS(t *testing.T) { 1460, desc, true, - &test.NilLogger{}, + test.NilLogger, ) require.NoError(t, err) defer stream.Close() @@ -324,7 +324,7 @@ func TestAgentFMP4NegativeDTS(t *testing.T) { SegmentDuration: 1 * time.Second, PathName: "mypath", Stream: stream, - Parent: &test.NilLogger{}, + Parent: test.NilLogger, } w.Initialize() diff --git a/internal/record/cleaner_test.go b/internal/record/cleaner_test.go index a8b18bde4e8..dbdea55edb9 100644 --- a/internal/record/cleaner_test.go +++ b/internal/record/cleaner_test.go @@ -37,7 +37,7 @@ func TestCleaner(t *testing.T) { Format: conf.RecordFormatFMP4, DeleteAfter: 10 * time.Second, }}, - Parent: test.NilLogger{}, + Parent: test.NilLogger, } c.Initialize() defer c.Close() diff --git a/internal/servers/hls/server_test.go b/internal/servers/hls/server_test.go index e0c4548b16b..0db2bb65d0f 100644 --- a/internal/servers/hls/server_test.go +++ b/internal/servers/hls/server_test.go @@ -90,7 +90,7 @@ func TestServerNotFound(t *testing.T) { ReadTimeout: conf.StringDuration(10 * time.Second), WriteQueueSize: 512, PathManager: &dummyPathManager{}, - Parent: &test.NilLogger{}, + Parent: test.NilLogger, } err := s.Initialize() require.NoError(t, err) @@ -131,7 +131,7 @@ func TestServerRead(t *testing.T) { 1460, desc, true, - test.NilLogger{}, + test.NilLogger, ) require.NoError(t, err) @@ -154,7 +154,7 @@ func TestServerRead(t *testing.T) { ReadTimeout: conf.StringDuration(10 * time.Second), WriteQueueSize: 512, PathManager: pathManager, - Parent: &test.NilLogger{}, + Parent: test.NilLogger, } err = s.Initialize() require.NoError(t, err) @@ -216,7 +216,7 @@ func TestServerRead(t *testing.T) { 1460, desc, true, - test.NilLogger{}, + test.NilLogger, ) require.NoError(t, err) @@ -239,7 +239,7 @@ func TestServerRead(t *testing.T) { ReadTimeout: conf.StringDuration(10 * time.Second), WriteQueueSize: 512, PathManager: pathManager, - Parent: &test.NilLogger{}, + Parent: test.NilLogger, } err = s.Initialize() require.NoError(t, err) @@ -307,7 +307,7 @@ func TestDirectory(t *testing.T) { 1460, desc, true, - test.NilLogger{}, + test.NilLogger, ) require.NoError(t, err) @@ -330,7 +330,7 @@ func TestDirectory(t *testing.T) { ReadTimeout: conf.StringDuration(10 * time.Second), WriteQueueSize: 512, PathManager: pathManager, - Parent: &test.NilLogger{}, + Parent: test.NilLogger, } err = s.Initialize() require.NoError(t, err) diff --git a/internal/servers/rtmp/server_test.go b/internal/servers/rtmp/server_test.go index 6bf292ebcbb..007691e19cc 100644 --- a/internal/servers/rtmp/server_test.go +++ b/internal/servers/rtmp/server_test.go @@ -44,7 +44,7 @@ func (p *dummyPath) StartPublisher(req defs.PathStartPublisherReq) (*stream.Stre 1460, req.Desc, true, - test.NilLogger{}, + test.NilLogger, ) if err != nil { return nil, err @@ -120,7 +120,7 @@ func TestServerPublish(t *testing.T) { RunOnDisconnect: "", ExternalCmdPool: nil, PathManager: pathManager, - Parent: &test.NilLogger{}, + Parent: test.NilLogger, } err := s.Initialize() require.NoError(t, err) @@ -146,7 +146,7 @@ func TestServerPublish(t *testing.T) { <-path.streamCreated - aw := asyncwriter.New(512, &test.NilLogger{}) + aw := asyncwriter.New(512, test.NilLogger) recv := make(chan struct{}) @@ -200,7 +200,7 @@ func TestServerRead(t *testing.T) { 1460, desc, true, - test.NilLogger{}, + test.NilLogger, ) require.NoError(t, err) @@ -222,7 +222,7 @@ func TestServerRead(t *testing.T) { RunOnDisconnect: "", ExternalCmdPool: nil, PathManager: pathManager, - Parent: &test.NilLogger{}, + Parent: test.NilLogger, } err = s.Initialize() require.NoError(t, err) diff --git a/internal/servers/rtsp/server_test.go b/internal/servers/rtsp/server_test.go index c732d214d73..e256fada170 100644 --- a/internal/servers/rtsp/server_test.go +++ b/internal/servers/rtsp/server_test.go @@ -43,7 +43,7 @@ func (p *dummyPath) StartPublisher(req defs.PathStartPublisherReq) (*stream.Stre 1460, req.Desc, true, - test.NilLogger{}, + test.NilLogger, ) if err != nil { return nil, err @@ -114,7 +114,7 @@ func TestServerPublish(t *testing.T) { RunOnDisconnect: "", ExternalCmdPool: nil, PathManager: pathManager, - Parent: &test.NilLogger{}, + Parent: test.NilLogger, } err := s.Initialize() require.NoError(t, err) @@ -132,7 +132,7 @@ func TestServerPublish(t *testing.T) { <-path.streamCreated - aw := asyncwriter.New(512, &test.NilLogger{}) + aw := asyncwriter.New(512, test.NilLogger) recv := make(chan struct{}) @@ -174,7 +174,7 @@ func TestServerRead(t *testing.T) { 1460, desc, true, - test.NilLogger{}, + test.NilLogger, ) require.NoError(t, err) @@ -205,7 +205,7 @@ func TestServerRead(t *testing.T) { RunOnDisconnect: "", ExternalCmdPool: nil, PathManager: pathManager, - Parent: &test.NilLogger{}, + Parent: test.NilLogger, } err = s.Initialize() require.NoError(t, err) diff --git a/internal/servers/srt/server_test.go b/internal/servers/srt/server_test.go index b3b238a67bd..74645d644d4 100644 --- a/internal/servers/srt/server_test.go +++ b/internal/servers/srt/server_test.go @@ -42,7 +42,7 @@ func (p *dummyPath) StartPublisher(req defs.PathStartPublisherReq) (*stream.Stre 1460, req.Desc, true, - test.NilLogger{}, + test.NilLogger, ) if err != nil { return nil, err @@ -100,7 +100,7 @@ func TestServerPublish(t *testing.T) { RunOnDisconnect: "string", ExternalCmdPool: externalCmdPool, PathManager: pathManager, - Parent: &test.NilLogger{}, + Parent: test.NilLogger, } err := s.Initialize() require.NoError(t, err) @@ -139,7 +139,7 @@ func TestServerPublish(t *testing.T) { <-path.streamCreated - aw := asyncwriter.New(512, &test.NilLogger{}) + aw := asyncwriter.New(512, test.NilLogger) recv := make(chan struct{}) @@ -179,7 +179,7 @@ func TestServerRead(t *testing.T) { 1460, desc, true, - test.NilLogger{}, + test.NilLogger, ) require.NoError(t, err) @@ -199,7 +199,7 @@ func TestServerRead(t *testing.T) { RunOnDisconnect: "string", ExternalCmdPool: externalCmdPool, PathManager: pathManager, - Parent: &test.NilLogger{}, + Parent: test.NilLogger, } err = s.Initialize() require.NoError(t, err) diff --git a/internal/servers/webrtc/server_test.go b/internal/servers/webrtc/server_test.go index 103a7316dd2..e21b04f0388 100644 --- a/internal/servers/webrtc/server_test.go +++ b/internal/servers/webrtc/server_test.go @@ -55,7 +55,7 @@ func (p *dummyPath) StartPublisher(req defs.PathStartPublisherReq) (*stream.Stre 1460, req.Desc, true, - test.NilLogger{}, + test.NilLogger, ) if err != nil { return nil, err @@ -119,7 +119,7 @@ func initializeTestServer(t *testing.T) *Server { ICEServers: []conf.WebRTCICEServer{}, ExternalCmdPool: nil, PathManager: pathManager, - Parent: test.NilLogger{}, + Parent: test.NilLogger, } err := s.Initialize() require.NoError(t, err) @@ -197,7 +197,7 @@ func TestServerOptionsICEServer(t *testing.T) { }}, ExternalCmdPool: nil, PathManager: pathManager, - Parent: test.NilLogger{}, + Parent: test.NilLogger, } err := s.Initialize() require.NoError(t, err) @@ -251,7 +251,7 @@ func TestServerPublish(t *testing.T) { ICEServers: []conf.WebRTCICEServer{}, ExternalCmdPool: nil, PathManager: pathManager, - Parent: test.NilLogger{}, + Parent: test.NilLogger, } err := s.Initialize() require.NoError(t, err) @@ -267,7 +267,7 @@ func TestServerPublish(t *testing.T) { wc := &webrtc.WHIPClient{ HTTPClient: hc, URL: su, - Log: test.NilLogger{}, + Log: test.NilLogger, } tracks, err := wc.Publish(context.Background(), test.FormatH264, nil) @@ -289,7 +289,7 @@ func TestServerPublish(t *testing.T) { <-path.streamCreated - aw := asyncwriter.New(512, &test.NilLogger{}) + aw := asyncwriter.New(512, test.NilLogger) recv := make(chan struct{}) @@ -336,7 +336,7 @@ func TestServerRead(t *testing.T) { 1460, desc, true, - test.NilLogger{}, + test.NilLogger, ) require.NoError(t, err) @@ -361,7 +361,7 @@ func TestServerRead(t *testing.T) { ICEServers: []conf.WebRTCICEServer{}, ExternalCmdPool: nil, PathManager: pathManager, - Parent: test.NilLogger{}, + Parent: test.NilLogger, } err = s.Initialize() require.NoError(t, err) @@ -377,7 +377,7 @@ func TestServerRead(t *testing.T) { wc := &webrtc.WHIPClient{ HTTPClient: hc, URL: u, - Log: test.NilLogger{}, + Log: test.NilLogger, } writerDone := make(chan struct{}) diff --git a/internal/staticsources/webrtc/source_test.go b/internal/staticsources/webrtc/source_test.go index c0c68a2c278..e8bf85ac35f 100644 --- a/internal/staticsources/webrtc/source_test.go +++ b/internal/staticsources/webrtc/source_test.go @@ -36,7 +36,7 @@ func TestSource(t *testing.T) { pc := &webrtc.PeerConnection{ API: api, Publish: true, - Log: test.NilLogger{}, + Log: test.NilLogger, } err = pc.Start() require.NoError(t, err) diff --git a/internal/test/auth_manager.go b/internal/test/auth_manager.go new file mode 100644 index 00000000000..be23ede8459 --- /dev/null +++ b/internal/test/auth_manager.go @@ -0,0 +1,20 @@ +package test + +import "github.com/bluenviron/mediamtx/internal/auth" + +// AuthManager is a test auth manager. +type AuthManager struct { + Func func(req *auth.Request) error +} + +// Authenticate replicates auth.Manager.Replicate +func (m *AuthManager) Authenticate(req *auth.Request) error { + return m.Func(req) +} + +// NilAuthManager is an auth manager that accepts everything. +var NilAuthManager = &AuthManager{ + Func: func(_ *auth.Request) error { + return nil + }, +} diff --git a/internal/test/logger.go b/internal/test/logger.go new file mode 100644 index 00000000000..4331bd19772 --- /dev/null +++ b/internal/test/logger.go @@ -0,0 +1,11 @@ +package test + +import "github.com/bluenviron/mediamtx/internal/logger" + +type nilLogger struct{} + +func (nilLogger) Log(_ logger.Level, _ string, _ ...interface{}) { +} + +// NilLogger is a logger to /dev/null +var NilLogger logger.Writer = &nilLogger{} diff --git a/internal/test/nil_logger.go b/internal/test/nil_logger.go deleted file mode 100644 index f8cca30a128..00000000000 --- a/internal/test/nil_logger.go +++ /dev/null @@ -1,10 +0,0 @@ -package test - -import "github.com/bluenviron/mediamtx/internal/logger" - -// NilLogger is a logger to /dev/null -type NilLogger struct{} - -// Log implements logger.Writer. -func (NilLogger) Log(_ logger.Level, _ string, _ ...interface{}) { -}