Auth: Prevent login if additional accounts may not be created #4266

Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
Michael Mayer
2025-03-12 01:08:16 +01:00
parent bfc6cb2351
commit 7f0717e9a0
4 changed files with 35 additions and 3 deletions

View File

@@ -225,6 +225,12 @@ func OIDCRedirect(router *gin.RouterGroup) {
} else if err = avatar.SetUserImageURL(user, avatarUrl, entity.SrcOIDC, conf.ThumbCachePath()); err != nil {
event.AuditWarn([]string{clientIp, "create session", "oidc", userName, "failed to set avatar image", err.Error()})
}
} else if conf.UsersQuotaExceeded() {
userName = oidcUser.Username()
event.AuditWarn([]string{clientIp, "create session", "oidc", "create user", userName, authn.ErrUsersQuotaExceeded.Error()})
event.LoginError(clientIp, "oidc", userName, userAgent, authn.ErrUsersQuotaExceeded.Error())
c.HTML(http.StatusUnauthorized, "auth.gohtml", CreateSessionError(http.StatusUnauthorized, i18n.Error(i18n.ErrQuotaExceeded)))
return
} else if conf.OIDCRegister() {
// Create new user record.
user = &oidcUser

View File

@@ -97,7 +97,7 @@ func (c *Config) Usage() Usage {
// UsageInfo returns true if resource usage information should be displayed in the user interface.
func (c *Config) UsageInfo() bool {
return c.options.UsageInfo || c.options.FilesQuota > 0
return c.options.UsageInfo || c.options.FilesQuota > 0 || c.options.UsersQuota > 0
}
// FilesQuota returns the maximum aggregated size of all indexed files in gigabytes, or 0 if no limit exists.
@@ -118,12 +118,12 @@ func (c *Config) FilesQuotaBytes() uint64 {
return c.options.FilesQuota * fs.GB
}
// FilesQuotaExceeded checks if the filesystem usage has been reached or exceeded.
// FilesQuotaExceeded checks whether the filesystem usage has been reached or exceeded.
func (c *Config) FilesQuotaExceeded() bool {
return c.Usage().FilesUsedPct >= 100
}
// UsersQuota returns the maximum number of registered user accounts, or 0 if no quota exists.
// UsersQuota returns the maximum number of user accounts without guests, or 0 if unlimited.
func (c *Config) UsersQuota() int {
if c.options.UsersQuota <= 0 {
return 0
@@ -131,3 +131,8 @@ func (c *Config) UsersQuota() int {
return c.options.UsersQuota
}
// UsersQuotaExceeded checks whether the maximum number of user accounts has been reached or exceeded.
func (c *Config) UsersQuotaExceeded() bool {
return c.Usage().UsersUsedPct >= 100
}

View File

@@ -5,6 +5,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/pkg/fs/duf"
)
@@ -49,7 +50,9 @@ func TestConfig_Quota(t *testing.T) {
c.options.FilesQuota = uint64(1)
c.options.UsersQuota = 10
assert.Equal(t, uint64(1), c.FilesQuota())
assert.Equal(t, uint64(fs.GB), c.FilesQuotaBytes())
assert.Equal(t, 10, c.UsersQuota())
c.options.FilesQuota = uint64(0)
@@ -72,3 +75,20 @@ func TestConfig_FilesQuotaExceeded(t *testing.T) {
c.options.FilesQuota = uint64(0)
}
func TestConfig_UsersQuotaExceeded(t *testing.T) {
c := TestConfig()
FlushUsageCache()
assert.False(t, c.UsersQuotaExceeded())
c.options.UsersQuota = 1
FlushUsageCache()
assert.True(t, c.UsersQuotaExceeded())
c.options.UsersQuota = 100000
FlushUsageCache()
assert.False(t, c.UsersQuotaExceeded())
c.options.UsersQuota = 0
}

View File

@@ -28,6 +28,7 @@ var (
ErrDisabledInPublicMode = errors.New("disabled in public mode")
ErrAuthenticationDisabled = errors.New("authentication disabled")
ErrRateLimitExceeded = errors.New("rate limit exceeded")
ErrUsersQuotaExceeded = errors.New("users quota exceeded")
)
// OIDC and OAuth2-related error messages: