From 625b527e1b4d3aee73e8e1b46bb3ab9a60be5bdc Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Wed, 12 Jun 2024 15:48:28 +0200 Subject: [PATCH] prevent mixing together legacy and current auth mechanism (#3258) --- internal/api/api_test.go | 6 +- internal/conf/conf.go | 113 ++++++++++++++++++------------------- internal/conf/conf_test.go | 60 ++++++++++++++++++++ internal/conf/path.go | 12 ++-- 4 files changed, 124 insertions(+), 67 deletions(-) diff --git a/internal/api/api_test.go b/internal/api/api_test.go index a88446aa242..9cddc2576fc 100644 --- a/internal/api/api_test.go +++ b/internal/api/api_test.go @@ -247,16 +247,14 @@ func TestConfigPathDefaultsPatch(t *testing.T) { httpRequest(t, hc, http.MethodPatch, "http://localhost:9997/v3/config/pathdefaults/patch", map[string]interface{}{ - "readUser": "myuser", - "readPass": "mypass", + "recordFormat": "fmp4", }, nil) time.Sleep(500 * time.Millisecond) var out map[string]interface{} 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"]) + require.Equal(t, "fmp4", out["recordFormat"]) } func TestConfigPathsList(t *testing.T) { diff --git a/internal/conf/conf.go b/internal/conf/conf.go index e70da0dcb93..8516d2711d6 100644 --- a/internal/conf/conf.go +++ b/internal/conf/conf.go @@ -94,24 +94,25 @@ func mustParseCIDR(v string) net.IPNet { return *ne } -func credentialIsNotEmpty(c *Credential) bool { - return c != nil && *c != "" -} - -func ipNetworkIsNotEmpty(i *IPNetworks) bool { - return i != nil && len(*i) != 0 -} +func anyPathHasDeprecatedCredentials(pathDefaults Path, paths map[string]*OptionalPath) bool { + if pathDefaults.PublishUser != nil || + pathDefaults.PublishPass != nil || + pathDefaults.PublishIPs != nil || + pathDefaults.ReadUser != nil || + pathDefaults.ReadPass != nil || + pathDefaults.ReadIPs != nil { + return true + } -func anyPathHasDeprecatedCredentials(paths map[string]*OptionalPath) bool { for _, pa := range paths { if pa != nil { rva := reflect.ValueOf(pa.Values).Elem() - if credentialIsNotEmpty(rva.FieldByName("PublishUser").Interface().(*Credential)) || - credentialIsNotEmpty(rva.FieldByName("PublishPass").Interface().(*Credential)) || - ipNetworkIsNotEmpty(rva.FieldByName("PublishIPs").Interface().(*IPNetworks)) || - credentialIsNotEmpty(rva.FieldByName("ReadUser").Interface().(*Credential)) || - credentialIsNotEmpty(rva.FieldByName("ReadPass").Interface().(*Credential)) || - ipNetworkIsNotEmpty(rva.FieldByName("ReadIPs").Interface().(*IPNetworks)) { + if rva.FieldByName("PublishUser").Interface().(*Credential) != nil || + rva.FieldByName("PublishPass").Interface().(*Credential) != nil || + rva.FieldByName("PublishIPs").Interface().(*IPNetworks) != nil || + rva.FieldByName("ReadUser").Interface().(*Credential) != nil || + rva.FieldByName("ReadPass").Interface().(*Credential) != nil || + rva.FieldByName("ReadIPs").Interface().(*IPNetworks) != nil { return true } } @@ -119,6 +120,40 @@ func anyPathHasDeprecatedCredentials(paths map[string]*OptionalPath) bool { return false } +var defaultAuthInternalUsers = AuthInternalUsers{ + { + User: "any", + Pass: "", + Permissions: []AuthInternalUserPermission{ + { + Action: AuthActionPublish, + }, + { + Action: AuthActionRead, + }, + { + Action: AuthActionPlayback, + }, + }, + }, + { + User: "any", + Pass: "", + IPs: IPNetworks{mustParseCIDR("127.0.0.1/32"), mustParseCIDR("::1/128")}, + Permissions: []AuthInternalUserPermission{ + { + Action: AuthActionAPI, + }, + { + Action: AuthActionMetrics, + }, + { + Action: AuthActionPprof, + }, + }, + }, +} + // Conf is a configuration. // WARNING: Avoid using slices directly due to https://github.com/golang/go/issues/21092 type Conf struct { @@ -276,39 +311,7 @@ func (conf *Conf) setDefaults() { conf.UDPMaxPayloadSize = 1472 // Authentication - conf.AuthInternalUsers = []AuthInternalUser{ - { - User: "any", - Pass: "", - Permissions: []AuthInternalUserPermission{ - { - Action: AuthActionPublish, - }, - { - Action: AuthActionRead, - }, - { - Action: AuthActionPlayback, - }, - }, - }, - { - User: "any", - Pass: "", - IPs: IPNetworks{mustParseCIDR("127.0.0.1/32"), mustParseCIDR("::1/128")}, - Permissions: []AuthInternalUserPermission{ - { - Action: AuthActionAPI, - }, - { - Action: AuthActionMetrics, - }, - { - Action: AuthActionPprof, - }, - }, - }, - } + conf.AuthInternalUsers = defaultAuthInternalUsers conf.AuthHTTPExclude = []AuthInternalUserPermission{ { Action: AuthActionAPI, @@ -501,7 +504,6 @@ func (conf *Conf) Validate() error { } // Authentication - if conf.ExternalAuthenticationURL != nil { conf.AuthMethod = AuthMethodHTTP conf.AuthHTTPAddress = *conf.ExternalAuthenticationURL @@ -517,17 +519,15 @@ func (conf *Conf) Validate() error { return fmt.Errorf("'authJWTJWKS' must be a HTTP URL") } deprecatedCredentialsMode := false - if credentialIsNotEmpty(conf.PathDefaults.PublishUser) || - credentialIsNotEmpty(conf.PathDefaults.PublishPass) || - ipNetworkIsNotEmpty(conf.PathDefaults.PublishIPs) || - credentialIsNotEmpty(conf.PathDefaults.ReadUser) || - credentialIsNotEmpty(conf.PathDefaults.ReadPass) || - ipNetworkIsNotEmpty(conf.PathDefaults.ReadIPs) || - anyPathHasDeprecatedCredentials(conf.OptionalPaths) { + if anyPathHasDeprecatedCredentials(conf.PathDefaults, conf.OptionalPaths) { + if conf.AuthInternalUsers != nil && !reflect.DeepEqual(conf.AuthInternalUsers, defaultAuthInternalUsers) { + return fmt.Errorf("authInternalUsers and legacy credentials " + + "(publishUser, publishPass, publishIPs, readUser, readPass, readIPs) cannot be used together") + } + conf.AuthInternalUsers = []AuthInternalUser{ { User: "any", - Pass: "", Permissions: []AuthInternalUserPermission{ { Action: AuthActionPlayback, @@ -536,7 +536,6 @@ func (conf *Conf) Validate() error { }, { User: "any", - Pass: "", IPs: IPNetworks{mustParseCIDR("127.0.0.1/32"), mustParseCIDR("::1/128")}, Permissions: []AuthInternalUserPermission{ { diff --git a/internal/conf/conf_test.go b/internal/conf/conf_test.go index 540abdaf88a..0c26086cfa6 100644 --- a/internal/conf/conf_test.go +++ b/internal/conf/conf_test.go @@ -192,6 +192,66 @@ func TestConfEncryption(t *testing.T) { require.Equal(t, true, ok) } +func TestConfDeprecatedAuth(t *testing.T) { + tmpf, err := createTempFile([]byte( + "paths:\n" + + " cam:\n" + + " readUser: myuser\n" + + " readPass: mypass\n")) + require.NoError(t, err) + defer os.Remove(tmpf) + + conf, _, err := Load(tmpf, nil) + require.NoError(t, err) + + require.Equal(t, AuthInternalUsers{ + { + User: "any", + Permissions: []AuthInternalUserPermission{ + { + Action: AuthActionPlayback, + }, + }, + }, + { + User: "any", + IPs: IPNetworks{mustParseCIDR("127.0.0.1/32"), mustParseCIDR("::1/128")}, + Permissions: []AuthInternalUserPermission{ + { + Action: AuthActionAPI, + }, + { + Action: AuthActionMetrics, + }, + { + Action: AuthActionPprof, + }, + }, + }, + { + User: "any", + IPs: IPNetworks{mustParseCIDR("0.0.0.0/0")}, + Permissions: []AuthInternalUserPermission{ + { + Action: AuthActionPublish, + Path: "cam", + }, + }, + }, + { + User: "myuser", + Pass: "mypass", + IPs: IPNetworks{mustParseCIDR("0.0.0.0/0")}, + Permissions: []AuthInternalUserPermission{ + { + Action: AuthActionRead, + Path: "cam", + }, + }, + }, + }, conf.AuthInternalUsers) +} + func TestConfErrors(t *testing.T) { for _, ca := range []struct { name string diff --git a/internal/conf/path.go b/internal/conf/path.go index 042eae2242e..925f050f439 100644 --- a/internal/conf/path.go +++ b/internal/conf/path.go @@ -399,17 +399,17 @@ func (pconf *Path) validate( if deprecatedCredentialsMode { func() { var user Credential = "any" - if credentialIsNotEmpty(pconf.PublishUser) { + if pconf.PublishUser != nil && *pconf.PublishUser != "" { user = *pconf.PublishUser } var pass Credential - if credentialIsNotEmpty(pconf.PublishPass) { + if pconf.PublishPass != nil && *pconf.PublishPass != "" { pass = *pconf.PublishPass } ips := IPNetworks{mustParseCIDR("0.0.0.0/0")} - if ipNetworkIsNotEmpty(pconf.PublishIPs) { + if pconf.PublishIPs != nil && len(*pconf.PublishIPs) != 0 { ips = *pconf.PublishIPs } @@ -431,17 +431,17 @@ func (pconf *Path) validate( func() { var user Credential = "any" - if credentialIsNotEmpty(pconf.ReadUser) { + if pconf.ReadUser != nil && *pconf.ReadUser != "" { user = *pconf.ReadUser } var pass Credential - if credentialIsNotEmpty(pconf.ReadPass) { + if pconf.ReadPass != nil && *pconf.ReadPass != "" { pass = *pconf.ReadPass } ips := IPNetworks{mustParseCIDR("0.0.0.0/0")} - if ipNetworkIsNotEmpty(pconf.ReadIPs) { + if pconf.ReadIPs != nil && len(*pconf.ReadIPs) != 0 { ips = *pconf.ReadIPs }