1
0
mirror of https://github.com/amir20/dozzle.git synced 2026-01-04 03:54:58 +01:00

feat: Add user roles (#4133)

This commit is contained in:
Dmitry Mazurov
2025-09-22 00:51:16 +03:00
committed by GitHub
parent 54799b420c
commit 5f24657b41
17 changed files with 207 additions and 79 deletions

View File

@@ -20,6 +20,7 @@ type proxyAuthContext struct {
headerEmail string
headerName string
headerFilter string
headerRoles string
}
func hashEmail(email string) string {
@@ -30,12 +31,13 @@ func hashEmail(email string) string {
return hex.EncodeToString(hash[:])
}
func NewForwardProxyAuth(userHeader, emailHeader, nameHeader, filterHeader string) *proxyAuthContext {
func NewForwardProxyAuth(userHeader, emailHeader, nameHeader, filterHeader, rolesHeader string) *proxyAuthContext {
return &proxyAuthContext{
headerUser: userHeader,
headerEmail: emailHeader,
headerName: nameHeader,
headerFilter: filterHeader,
headerRoles: rolesHeader,
}
}
@@ -46,7 +48,8 @@ func (p *proxyAuthContext) AuthMiddleware(next http.Handler) http.Handler {
if err != nil {
log.Fatal().Str("filter", r.Header.Get(p.headerFilter)).Msg("Failed to parse container filter")
}
user := newUser(r.Header.Get(p.headerUser), r.Header.Get(p.headerEmail), r.Header.Get(p.headerName), containerFilter)
userRoles := ParseRole(r.Header.Get(p.headerRoles))
user := newUser(r.Header.Get(p.headerUser), r.Header.Get(p.headerEmail), r.Header.Get(p.headerName), containerFilter, userRoles)
ctx := context.WithValue(r.Context(), remoteUser, user)
next.ServeHTTP(w, r.WithContext(ctx))
} else {

42
internal/auth/roles.go Normal file
View File

@@ -0,0 +1,42 @@
package auth
import (
"strings"
)
type Role int
const (
NONE Role = 0
Shell Role = 1 << iota
Actions
Download
)
const AllRole = Shell | Actions | Download
func ParseRole(commaValues string) Role {
if commaValues == "" {
return AllRole
}
var roles Role
for r := range strings.SplitSeq(commaValues, ",") {
role := strings.TrimSpace(strings.ToLower(r))
switch role {
case "shell":
roles |= Shell
case "actions":
roles |= Actions
case "download":
roles |= Download
case "none":
return NONE
}
}
return roles
}
func (roles Role) Has(role Role) bool {
return roles&role != 0
}

View File

@@ -38,7 +38,7 @@ func (a *simpleAuthContext) CreateToken(username, password string) (string, erro
return "", ErrInvalidCredentials
}
claims := map[string]interface{}{"username": user.Username, "email": user.Email, "name": user.Name, "filter": user.Filter}
claims := map[string]interface{}{"username": user.Username, "email": user.Email, "name": user.Name, "filter": user.Filter, "roles": user.RolesConfigured}
jwtauth.SetIssuedNow(claims)
if a.ttl > 0 {

View File

@@ -24,7 +24,9 @@ type User struct {
Name string `json:"name" yaml:"name"`
Password string `json:"-" yaml:"password"`
Filter string `json:"-" yaml:"filter"`
RolesConfigured string `json:"-" yaml:"roles"`
ContainerLabels container.ContainerLabels `json:"-" yaml:"-"`
Roles Role `json:"-" yaml:"-"`
}
func (u User) AvatarURL() string {
@@ -35,12 +37,13 @@ func (u User) AvatarURL() string {
return fmt.Sprintf("https://gravatar.com/avatar/%s?d=https%%3A%%2F%%2Fui-avatars.com%%2Fapi%%2F/%s/128", hashEmail(u.Email), url.QueryEscape(name))
}
func newUser(username, email, name string, labels container.ContainerLabels) User {
func newUser(username, email, name string, labels container.ContainerLabels, roles Role) User {
return User{
Username: username,
Email: email,
Name: name,
ContainerLabels: labels,
Roles: roles,
}
}
@@ -198,14 +201,18 @@ func UserFromContext(ctx context.Context) *User {
email := claims["email"].(string)
name := claims["name"].(string)
containerFilter := container.ContainerLabels{}
roles := AllRole
if filter, ok := claims["filter"].(string); ok {
containerFilter, err = container.ParseContainerFilter(filter)
if err != nil {
log.Fatal().Err(err).Str("filter", filter).Msg("Failed to parse container filter")
}
}
if role, ok := claims["roles"].(string); ok {
roles = ParseRole(role)
}
user := newUser(username, email, name, containerFilter)
user := newUser(username, email, name, containerFilter, roles)
return &user
}
return nil