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:
@@ -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
42
internal/auth/roles.go
Normal 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
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user