Change anon user to localhost user only if DisableLocalhost is set

This commit is contained in:
Ingo Oppermann
2023-03-08 15:21:55 +01:00
parent 41eab6f40a
commit d101a76e9e
5 changed files with 63 additions and 44 deletions

View File

@@ -441,8 +441,7 @@ func (a *api) start() error {
return fmt.Errorf("iam: %w", err)
}
// Create default policies for anonymous users in order to mimic
// the behaviour before IAM
// Create default policies for anonymous users in order to mimic the behaviour before IAM
iam.RemovePolicy("$anon", "$none", "", nil)
iam.RemovePolicy("$localhost", "$none", "", nil)
@@ -451,16 +450,14 @@ func (a *api) start() error {
iam.AddPolicy("$anon", "$none", "api:/api", []string{"GET", "HEAD", "OPTIONS"})
iam.AddPolicy("$anon", "$none", "api:/api/v3/widget/process/**", []string{"GET", "HEAD", "OPTIONS"})
iam.AddPolicy("$localhost", "$none", "api:/api", []string{"GET", "HEAD", "OPTIONS"})
iam.AddPolicy("$localhost", "$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("$localhost", "$none", "api:/api/**", []string{"ANY"})
iam.AddPolicy("$localhost", "$none", "process:*", []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"})
}
@@ -1125,7 +1122,7 @@ func (a *api) start() error {
Router: router,
ReadOnly: cfg.API.ReadOnly,
IAM: a.iam,
IAMDisableLocalhost: cfg.API.Auth.DisableLocalhost,
IAMDisableLocalhost: cfg.API.Auth.Enable && cfg.API.Auth.DisableLocalhost,
}
mainserverhandler, err := http.NewServer(serverConfig)

View File

@@ -36,9 +36,8 @@ func NewAbout(restream restream.Restreamer, auths func() []string) *AboutHandler
// @Router /api [get]
func (p *AboutHandler) About(c echo.Context) error {
user, _ := c.Get("user").(string)
disablelocalhost, _ := c.Get("disablelocalhost").(bool)
if user == "$anon" || (user == "$localhost" && !disablelocalhost) {
if user == "$anon" {
return c.JSON(http.StatusOK, api.MinimalAbout{
App: app.Name,
Auths: p.auths(),

View File

@@ -17,8 +17,9 @@
// 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, the identity will
// be $localhost, representing an anonymous user from localhost.
// an anonmyous user. If the request originates from localhost and DisableLocalhost
// is configured, the identity will be $localhost, representing an anonymous user from
// localhost.
//
// The domain is provided as query parameter "group" for all API requests or the
// first path element after a mountpoint for filesystem requests.
@@ -57,6 +58,7 @@ type Config struct {
Mounts []string
IAM iam.IAM
DisableLocalhost bool
WaitAfterFailedLogin bool
Logger log.Logger
}
@@ -65,9 +67,12 @@ var DefaultConfig = Config{
Mounts: []string{},
IAM: nil,
DisableLocalhost: false,
WaitAfterFailedLogin: false,
Logger: nil,
}
var realm = "datarhei-core"
type iammiddleware struct {
iam iam.IAM
mounts []string
@@ -106,9 +111,6 @@ func NewWithConfig(config Config) echo.MiddlewareFunc {
return func(next echo.HandlerFunc) echo.HandlerFunc {
return func(c echo.Context) error {
c.Set("disablelocalhost", config.DisableLocalhost)
if config.Skipper(c) {
c.Set("user", "$anon")
return next(c)
@@ -129,14 +131,18 @@ func NewWithConfig(config Config) echo.MiddlewareFunc {
if resource == "/api/login" {
identity, err = mw.findIdentityFromUserpass(c)
if err != nil {
if config.WaitAfterFailedLogin {
time.Sleep(5 * time.Second)
}
return api.Err(http.StatusForbidden, "Forbidden", "%s", err)
}
if identity == nil {
identity, err = mw.findIdentityFromAuth0(c)
if err != nil {
if config.WaitAfterFailedLogin {
time.Sleep(5 * time.Second)
}
return api.Err(http.StatusForbidden, "Forbidden", "%s", err)
}
}
@@ -150,38 +156,53 @@ func NewWithConfig(config Config) echo.MiddlewareFunc {
if resource == "/api/login/refresh" {
usefor, _ := c.Get("usefor").(string)
if usefor != "refresh" {
if config.WaitAfterFailedLogin {
time.Sleep(5 * time.Second)
}
return api.Err(http.StatusForbidden, "Forbidden", "invalid token")
}
} else {
usefor, _ := c.Get("usefor").(string)
if usefor != "access" {
if config.WaitAfterFailedLogin {
time.Sleep(5 * time.Second)
}
return api.Err(http.StatusForbidden, "Forbidden", "invalid token")
}
}
}
}
if config.DisableLocalhost {
ip := c.RealIP()
if ip == "127.0.0.1" || ip == "::1" {
username = "$localhost"
}
}
domain = c.QueryParam("group")
resource = "api:" + resource
} else {
identity, err = mw.findIdentityFromBasicAuth(c)
if err != nil {
if err == ErrUnauthorized {
c.Response().Header().Set(echo.HeaderWWWAuthenticate, "Basic realm=datarhei-core")
if err == ErrAuthRequired {
c.Response().Header().Set(echo.HeaderWWWAuthenticate, "Basic realm="+realm)
return api.Err(http.StatusUnauthorized, "Unauthorized", "%s", err)
} else if err == ErrBadRequest {
return api.Err(http.StatusBadRequest, "Bad request", "%s", err)
} else {
if config.WaitAfterFailedLogin {
time.Sleep(5 * time.Second)
}
if err == ErrBadRequest {
return api.Err(http.StatusBadRequest, "Bad request", "%s", err)
} else if err == ErrUnauthorized {
c.Response().Header().Set(echo.HeaderWWWAuthenticate, "Basic realm="+realm)
return api.Err(http.StatusUnauthorized, "Unauthorized", "%s", err)
} else {
return api.Err(http.StatusForbidden, "Forbidden", "%s", err)
}
}
}
domain = mw.findDomainFromFilesystem(resource)
resource = "fs:" + resource
@@ -208,6 +229,7 @@ func NewWithConfig(config Config) echo.MiddlewareFunc {
}
}
var ErrAuthRequired = errors.New("unauthorized")
var ErrUnauthorized = errors.New("unauthorized")
var ErrBadRequest = errors.New("bad request")
@@ -224,7 +246,7 @@ func (m *iammiddleware) findIdentityFromBasicAuth(c echo.Context) (iam.IdentityV
}
if !m.iam.Enforce("$anon", domain, "fs:"+path, c.Request().Method) {
return nil, ErrUnauthorized
return nil, ErrAuthRequired
}
return nil, nil

View File

@@ -147,7 +147,7 @@ func TestFindDomainFromFilesystem(t *testing.T) {
mw := &iammiddleware{
iam: iam,
mounts: []string{"/memfs", "/"},
mounts: []string{"/", "/memfs"},
}
domain := mw.findDomainFromFilesystem("/")

View File

@@ -226,6 +226,7 @@ func NewServer(config Config) (Server, error) {
IAM: config.IAM,
Mounts: mounts,
DisableLocalhost: config.IAMDisableLocalhost,
WaitAfterFailedLogin: true,
Logger: s.logger.WithComponent("IAM"),
})