From 6e93c1d5a1056ab1ce4023558ad7a54ae8ae281e Mon Sep 17 00:00:00 2001 From: Ingo Oppermann Date: Thu, 9 Mar 2023 21:10:04 +0100 Subject: [PATCH] Get rid of $localhost pseudo user --- app/api/api.go | 51 +++++++++++++++++++------------------- http/middleware/iam/iam.go | 24 +++++++----------- http/server.go | 44 ++++++++++++++++---------------- iam/iam.go | 16 ++++++------ restream/restream.go | 7 +----- rtmp/rtmp.go | 2 +- srt/srt.go | 2 +- 7 files changed, 68 insertions(+), 78 deletions(-) diff --git a/app/api/api.go b/app/api/api.go index aba706f0..8d5d3c98 100644 --- a/app/api/api.go +++ b/app/api/api.go @@ -444,27 +444,11 @@ func (a *api) start() error { // Create default policies for anonymous users in order to mimic the behaviour before IAM iam.RemovePolicy("$anon", "$none", "", nil) - iam.RemovePolicy("$localhost", "$none", "", nil) iam.AddPolicy("$anon", "$none", "fs:/**", []string{"GET", "HEAD", "OPTIONS"}) iam.AddPolicy("$anon", "$none", "api:/api", []string{"GET", "HEAD", "OPTIONS"}) iam.AddPolicy("$anon", "$none", "api:/api/v3/widget/process/**", []string{"GET", "HEAD", "OPTIONS"}) - if !cfg.API.Auth.Enable { - iam.AddPolicy("$anon", "$none", "api:/api/**", []string{"ANY"}) - iam.AddPolicy("$anon", "$none", "process:*", []string{"ANY"}) - iam.AddPolicy("$anon", "$none", "iam:*", []string{"ANY"}) - } else { - if cfg.API.Auth.DisableLocalhost { - iam.AddPolicy("$localhost", "$none", "api:/api", []string{"GET", "HEAD", "OPTIONS"}) - iam.AddPolicy("$localhost", "$none", "api:/api/v3/widget/process/**", []string{"GET", "HEAD", "OPTIONS"}) - - iam.AddPolicy("$localhost", "$none", "api:/api/**", []string{"ANY"}) - iam.AddPolicy("$localhost", "$none", "process:*", []string{"ANY"}) - iam.AddPolicy("$localhost", "$none", "iam:*", []string{"ANY"}) - } - } - if !cfg.Storage.Memory.Auth.Enable { iam.AddPolicy("$anon", "$none", "fs:/memfs/**", []string{"ANY"}) } @@ -671,7 +655,7 @@ func (a *api) start() error { var identity iam.IdentityVerifier = nil if len(config.Owner) == 0 { - identity, _ = a.iam.GetDefaultVerifier() + identity = a.iam.GetDefaultVerifier() } else { identity, _ = a.iam.GetVerifier(config.Owner) } @@ -697,7 +681,7 @@ func (a *api) start() error { var identity iam.IdentityVerifier = nil if len(config.Owner) == 0 { - identity, _ = a.iam.GetDefaultVerifier() + identity = a.iam.GetDefaultVerifier() } else { identity, _ = a.iam.GetVerifier(config.Owner) } @@ -1117,14 +1101,29 @@ func (a *api) start() error { Cors: http.CorsConfig{ Origins: cfg.Storage.CORS.Origins, }, - RTMP: a.rtmpserver, - SRT: a.srtserver, - Config: a.config.store, - Sessions: a.sessions, - Router: router, - ReadOnly: cfg.API.ReadOnly, - IAM: a.iam, - IAMDisableLocalhost: cfg.API.Auth.Enable && cfg.API.Auth.DisableLocalhost, + RTMP: a.rtmpserver, + SRT: a.srtserver, + Config: a.config.store, + Sessions: a.sessions, + Router: router, + ReadOnly: cfg.API.ReadOnly, + IAM: a.iam, + IAMSkipper: func(ip string) bool { + if !cfg.API.Auth.Enable { + return true + } else { + isLocalhost := false + if ip == "127.0.0.1" || ip == "::1" { + isLocalhost = true + } + + if isLocalhost && cfg.API.Auth.DisableLocalhost { + return true + } + } + + return false + }, } mainserverhandler, err := http.NewServer(serverConfig) diff --git a/http/middleware/iam/iam.go b/http/middleware/iam/iam.go index 4cfe7df8..ebb8e9f1 100644 --- a/http/middleware/iam/iam.go +++ b/http/middleware/iam/iam.go @@ -17,9 +17,8 @@ // only allow JWT as authentication method. // // If the identity can't be detected, the identity of "$anon" is given, representing -// an anonmyous user. If the request originates from localhost and DisableLocalhost -// is configured, the identity will be $localhost, representing an anonymous user from -// localhost. +// an anonmyous user. If the Skipper function returns true for the request and the +// API is accessed, the username will be the one of the IAM superuser. // // The domain is provided as query parameter "group" for all API requests or the // first path element after a mountpoint for filesystem requests. @@ -57,7 +56,6 @@ type Config struct { Skipper middleware.Skipper Mounts []string IAM iam.IAM - DisableLocalhost bool WaitAfterFailedLogin bool Logger log.Logger } @@ -66,7 +64,6 @@ var DefaultConfig = Config{ Skipper: middleware.DefaultSkipper, Mounts: []string{}, IAM: nil, - DisableLocalhost: false, WaitAfterFailedLogin: false, Logger: nil, } @@ -111,15 +108,15 @@ func NewWithConfig(config Config) echo.MiddlewareFunc { return func(next echo.HandlerFunc) echo.HandlerFunc { return func(c echo.Context) error { - if config.Skipper(c) { - c.Set("user", "$anon") - return next(c) - } - if config.IAM == nil { return api.Err(http.StatusForbidden, "Forbidden", "IAM is not provided") } + isAPISuperuser := false + if config.Skipper(c) { + isAPISuperuser = true + } + var identity iam.IdentityVerifier = nil var err error @@ -173,11 +170,8 @@ func NewWithConfig(config Config) echo.MiddlewareFunc { } } - if config.DisableLocalhost { - ip := c.RealIP() - if ip == "127.0.0.1" || ip == "::1" { - username = "$localhost" - } + if isAPISuperuser { + username = config.IAM.GetDefaultVerifier().Name() } domain = c.QueryParam("group") diff --git a/http/server.go b/http/server.go index 1bc9c7d2..fe552729 100644 --- a/http/server.go +++ b/http/server.go @@ -75,25 +75,25 @@ import ( var ListenAndServe = http.ListenAndServe type Config struct { - Logger log.Logger - LogBuffer log.BufferWriter - Restream restream.Restreamer - Metrics monitor.HistoryReader - Prometheus prometheus.Reader - MimeTypesFile string - Filesystems []fs.FS - IPLimiter net.IPLimiter - Profiling bool - Cors CorsConfig - RTMP rtmp.Server - SRT srt.Server - Config cfgstore.Store - Cache cache.Cacher - Sessions session.RegistryReader - Router router.Router - ReadOnly bool - IAM iam.IAM - IAMDisableLocalhost bool + Logger log.Logger + LogBuffer log.BufferWriter + Restream restream.Restreamer + Metrics monitor.HistoryReader + Prometheus prometheus.Reader + MimeTypesFile string + Filesystems []fs.FS + IPLimiter net.IPLimiter + Profiling bool + Cors CorsConfig + RTMP rtmp.Server + SRT srt.Server + Config cfgstore.Store + Cache cache.Cacher + Sessions session.RegistryReader + Router router.Router + ReadOnly bool + IAM iam.IAM + IAMSkipper func(ip string) bool } type CorsConfig struct { @@ -132,8 +132,6 @@ type server struct { middleware struct { iplimit echo.MiddlewareFunc log echo.MiddlewareFunc - accessJWT echo.MiddlewareFunc - refreshJWT echo.MiddlewareFunc cors echo.MiddlewareFunc cache echo.MiddlewareFunc session echo.MiddlewareFunc @@ -223,9 +221,11 @@ func NewServer(config Config) (Server, error) { } s.middleware.iam = mwiam.NewWithConfig(mwiam.Config{ + Skipper: func(c echo.Context) bool { + return config.IAMSkipper(c.RealIP()) + }, IAM: config.IAM, Mounts: mounts, - DisableLocalhost: config.IAMDisableLocalhost, WaitAfterFailedLogin: true, Logger: s.logger.WithComponent("IAM"), }) diff --git a/iam/iam.go b/iam/iam.go index 28b2ec28..b742bf76 100644 --- a/iam/iam.go +++ b/iam/iam.go @@ -28,7 +28,7 @@ type IAM interface { GetVerifier(name string) (IdentityVerifier, error) GetVerfierFromAuth0(name string) (IdentityVerifier, error) - GetDefaultVerifier() (IdentityVerifier, error) + GetDefaultVerifier() IdentityVerifier CreateJWT(name string) (string, string, error) @@ -107,10 +107,6 @@ func (i *iam) Enforce(name, domain, resource, action string) bool { } } - //if name == "$localhost" { - // superuser = true - //} - l := i.logger.Debug().WithFields(log.Fields{ "subject": name, "domain": domain, @@ -128,6 +124,10 @@ func (i *iam) Enforce(name, domain, resource, action string) bool { if !ok { l.Log("no match") } else { + if name == "$superuser" { + rule = "" + } + l.WithField("rule", rule).Log("match") } @@ -166,8 +166,10 @@ func (i *iam) GetVerfierFromAuth0(name string) (IdentityVerifier, error) { return i.im.GetVerifierFromAuth0(name) } -func (i *iam) GetDefaultVerifier() (IdentityVerifier, error) { - return i.im.GetDefaultVerifier() +func (i *iam) GetDefaultVerifier() IdentityVerifier { + v, _ := i.im.GetDefaultVerifier() + + return v } func (i *iam) CreateJWT(name string) (string, string, error) { diff --git a/restream/restream.go b/restream/restream.go index fc0c1507..68016bf8 100644 --- a/restream/restream.go +++ b/restream/restream.go @@ -424,12 +424,7 @@ func (r *restream) enforce(name, group, processid, action string) bool { if len(name) == 0 { // This is for backwards compatibility. Existing processes don't have an owner. // All processes that will be added later will have an owner ($anon, ...). - identity, err := r.iam.GetDefaultVerifier() - if err != nil { - name = "$anon" - } else { - name = identity.Name() - } + name = r.iam.GetDefaultVerifier().Name() } if len(group) == 0 { diff --git a/rtmp/rtmp.go b/rtmp/rtmp.go index d7f50756..e9080da1 100644 --- a/rtmp/rtmp.go +++ b/rtmp/rtmp.go @@ -428,7 +428,7 @@ func (s *server) findIdentityFromStreamKey(key string) (string, error) { elements := strings.Split(key, ":") if len(elements) == 1 { - identity, err = s.iam.GetDefaultVerifier() + identity = s.iam.GetDefaultVerifier() token = elements[0] } else { identity, err = s.iam.GetVerifier(elements[0]) diff --git a/srt/srt.go b/srt/srt.go index d8166b34..fa0bad11 100644 --- a/srt/srt.go +++ b/srt/srt.go @@ -387,7 +387,7 @@ func (s *server) findIdentityFromToken(key string) (string, error) { elements := strings.Split(key, ":") if len(elements) == 1 { - identity, err = s.iam.GetDefaultVerifier() + identity = s.iam.GetDefaultVerifier() token = elements[0] } else { identity, err = s.iam.GetVerifier(elements[0])