1
0
Fork 0
forked from External/mediamtx

prevent mixing together legacy and current auth mechanism (#3258) (#3460)

This commit is contained in:
Alessandro Ros 2024-06-12 17:38:55 +02:00 committed by GitHub
parent 39ae1269ad
commit 9554fc4ba0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 124 additions and 67 deletions

View file

@ -247,16 +247,14 @@ func TestConfigPathDefaultsPatch(t *testing.T) {
httpRequest(t, hc, http.MethodPatch, "http://localhost:9997/v3/config/pathdefaults/patch", httpRequest(t, hc, http.MethodPatch, "http://localhost:9997/v3/config/pathdefaults/patch",
map[string]interface{}{ map[string]interface{}{
"readUser": "myuser", "recordFormat": "fmp4",
"readPass": "mypass",
}, nil) }, nil)
time.Sleep(500 * time.Millisecond) time.Sleep(500 * time.Millisecond)
var out map[string]interface{} var out map[string]interface{}
httpRequest(t, hc, http.MethodGet, "http://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, "fmp4", out["recordFormat"])
require.Equal(t, "mypass", out["readPass"])
} }
func TestConfigPathsList(t *testing.T) { func TestConfigPathsList(t *testing.T) {

View file

@ -94,24 +94,25 @@ func mustParseCIDR(v string) net.IPNet {
return *ne return *ne
} }
func credentialIsNotEmpty(c *Credential) bool { func anyPathHasDeprecatedCredentials(pathDefaults Path, paths map[string]*OptionalPath) bool {
return c != nil && *c != "" if pathDefaults.PublishUser != nil ||
} pathDefaults.PublishPass != nil ||
pathDefaults.PublishIPs != nil ||
pathDefaults.ReadUser != nil ||
pathDefaults.ReadPass != nil ||
pathDefaults.ReadIPs != nil {
return true
}
func ipNetworkIsNotEmpty(i *IPNetworks) bool {
return i != nil && len(*i) != 0
}
func anyPathHasDeprecatedCredentials(paths map[string]*OptionalPath) bool {
for _, pa := range paths { for _, pa := range paths {
if pa != nil { if pa != nil {
rva := reflect.ValueOf(pa.Values).Elem() rva := reflect.ValueOf(pa.Values).Elem()
if credentialIsNotEmpty(rva.FieldByName("PublishUser").Interface().(*Credential)) || if rva.FieldByName("PublishUser").Interface().(*Credential) != nil ||
credentialIsNotEmpty(rva.FieldByName("PublishPass").Interface().(*Credential)) || rva.FieldByName("PublishPass").Interface().(*Credential) != nil ||
ipNetworkIsNotEmpty(rva.FieldByName("PublishIPs").Interface().(*IPNetworks)) || rva.FieldByName("PublishIPs").Interface().(*IPNetworks) != nil ||
credentialIsNotEmpty(rva.FieldByName("ReadUser").Interface().(*Credential)) || rva.FieldByName("ReadUser").Interface().(*Credential) != nil ||
credentialIsNotEmpty(rva.FieldByName("ReadPass").Interface().(*Credential)) || rva.FieldByName("ReadPass").Interface().(*Credential) != nil ||
ipNetworkIsNotEmpty(rva.FieldByName("ReadIPs").Interface().(*IPNetworks)) { rva.FieldByName("ReadIPs").Interface().(*IPNetworks) != nil {
return true return true
} }
} }
@ -119,6 +120,40 @@ func anyPathHasDeprecatedCredentials(paths map[string]*OptionalPath) bool {
return false 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. // Conf is a configuration.
// WARNING: Avoid using slices directly due to https://github.com/golang/go/issues/21092 // WARNING: Avoid using slices directly due to https://github.com/golang/go/issues/21092
type Conf struct { type Conf struct {
@ -276,39 +311,7 @@ func (conf *Conf) setDefaults() {
conf.UDPMaxPayloadSize = 1472 conf.UDPMaxPayloadSize = 1472
// Authentication // Authentication
conf.AuthInternalUsers = []AuthInternalUser{ conf.AuthInternalUsers = defaultAuthInternalUsers
{
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.AuthHTTPExclude = []AuthInternalUserPermission{ conf.AuthHTTPExclude = []AuthInternalUserPermission{
{ {
Action: AuthActionAPI, Action: AuthActionAPI,
@ -501,7 +504,6 @@ func (conf *Conf) Validate() error {
} }
// Authentication // Authentication
if conf.ExternalAuthenticationURL != nil { if conf.ExternalAuthenticationURL != nil {
conf.AuthMethod = AuthMethodHTTP conf.AuthMethod = AuthMethodHTTP
conf.AuthHTTPAddress = *conf.ExternalAuthenticationURL conf.AuthHTTPAddress = *conf.ExternalAuthenticationURL
@ -517,17 +519,15 @@ func (conf *Conf) Validate() error {
return fmt.Errorf("'authJWTJWKS' must be a HTTP URL") return fmt.Errorf("'authJWTJWKS' must be a HTTP URL")
} }
deprecatedCredentialsMode := false deprecatedCredentialsMode := false
if credentialIsNotEmpty(conf.PathDefaults.PublishUser) || if anyPathHasDeprecatedCredentials(conf.PathDefaults, conf.OptionalPaths) {
credentialIsNotEmpty(conf.PathDefaults.PublishPass) || if conf.AuthInternalUsers != nil && !reflect.DeepEqual(conf.AuthInternalUsers, defaultAuthInternalUsers) {
ipNetworkIsNotEmpty(conf.PathDefaults.PublishIPs) || return fmt.Errorf("authInternalUsers and legacy credentials " +
credentialIsNotEmpty(conf.PathDefaults.ReadUser) || "(publishUser, publishPass, publishIPs, readUser, readPass, readIPs) cannot be used together")
credentialIsNotEmpty(conf.PathDefaults.ReadPass) || }
ipNetworkIsNotEmpty(conf.PathDefaults.ReadIPs) ||
anyPathHasDeprecatedCredentials(conf.OptionalPaths) {
conf.AuthInternalUsers = []AuthInternalUser{ conf.AuthInternalUsers = []AuthInternalUser{
{ {
User: "any", User: "any",
Pass: "",
Permissions: []AuthInternalUserPermission{ Permissions: []AuthInternalUserPermission{
{ {
Action: AuthActionPlayback, Action: AuthActionPlayback,
@ -536,7 +536,6 @@ func (conf *Conf) Validate() error {
}, },
{ {
User: "any", User: "any",
Pass: "",
IPs: IPNetworks{mustParseCIDR("127.0.0.1/32"), mustParseCIDR("::1/128")}, IPs: IPNetworks{mustParseCIDR("127.0.0.1/32"), mustParseCIDR("::1/128")},
Permissions: []AuthInternalUserPermission{ Permissions: []AuthInternalUserPermission{
{ {

View file

@ -192,6 +192,66 @@ func TestConfEncryption(t *testing.T) {
require.Equal(t, true, ok) 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) { func TestConfErrors(t *testing.T) {
for _, ca := range []struct { for _, ca := range []struct {
name string name string

View file

@ -399,17 +399,17 @@ func (pconf *Path) validate(
if deprecatedCredentialsMode { if deprecatedCredentialsMode {
func() { func() {
var user Credential = "any" var user Credential = "any"
if credentialIsNotEmpty(pconf.PublishUser) { if pconf.PublishUser != nil && *pconf.PublishUser != "" {
user = *pconf.PublishUser user = *pconf.PublishUser
} }
var pass Credential var pass Credential
if credentialIsNotEmpty(pconf.PublishPass) { if pconf.PublishPass != nil && *pconf.PublishPass != "" {
pass = *pconf.PublishPass pass = *pconf.PublishPass
} }
ips := IPNetworks{mustParseCIDR("0.0.0.0/0")} ips := IPNetworks{mustParseCIDR("0.0.0.0/0")}
if ipNetworkIsNotEmpty(pconf.PublishIPs) { if pconf.PublishIPs != nil && len(*pconf.PublishIPs) != 0 {
ips = *pconf.PublishIPs ips = *pconf.PublishIPs
} }
@ -431,17 +431,17 @@ func (pconf *Path) validate(
func() { func() {
var user Credential = "any" var user Credential = "any"
if credentialIsNotEmpty(pconf.ReadUser) { if pconf.ReadUser != nil && *pconf.ReadUser != "" {
user = *pconf.ReadUser user = *pconf.ReadUser
} }
var pass Credential var pass Credential
if credentialIsNotEmpty(pconf.ReadPass) { if pconf.ReadPass != nil && *pconf.ReadPass != "" {
pass = *pconf.ReadPass pass = *pconf.ReadPass
} }
ips := IPNetworks{mustParseCIDR("0.0.0.0/0")} ips := IPNetworks{mustParseCIDR("0.0.0.0/0")}
if ipNetworkIsNotEmpty(pconf.ReadIPs) { if pconf.ReadIPs != nil && len(*pconf.ReadIPs) != 0 {
ips = *pconf.ReadIPs ips = *pconf.ReadIPs
} }