mirror of
https://github.com/akvorado/akvorado.git
synced 2025-12-11 22:14:02 +01:00
Some checks failed
CI / 🤖 Check dependabot status (push) Has been cancelled
CI / 🐧 Test on Linux (${{ github.ref_type == 'tag' }}, misc) (push) Has been cancelled
CI / 🐧 Test on Linux (coverage) (push) Has been cancelled
CI / 🐧 Test on Linux (regular) (push) Has been cancelled
CI / ❄️ Build on Nix (push) Has been cancelled
CI / 🍏 Build and test on macOS (push) Has been cancelled
CI / 🧪 End-to-end testing (push) Has been cancelled
CI / 🔍 Upload code coverage (push) Has been cancelled
CI / 🔬 Test only Go (push) Has been cancelled
CI / 🔬 Test only JS (${{ needs.dependabot.outputs.package-ecosystem }}, 20) (push) Has been cancelled
CI / 🔬 Test only JS (${{ needs.dependabot.outputs.package-ecosystem }}, 22) (push) Has been cancelled
CI / 🔬 Test only JS (${{ needs.dependabot.outputs.package-ecosystem }}, 24) (push) Has been cancelled
CI / ⚖️ Check licenses (push) Has been cancelled
CI / 🐋 Build Docker images (push) Has been cancelled
CI / 🐋 Tag Docker images (push) Has been cancelled
CI / 🚀 Publish release (push) Has been cancelled
112 lines
3.0 KiB
Go
112 lines
3.0 KiB
Go
// SPDX-FileCopyrightText: 2022 Free Mobile
|
|
// SPDX-License-Identifier: AGPL-3.0-only
|
|
|
|
package authentication
|
|
|
|
import (
|
|
"net/http"
|
|
"reflect"
|
|
"strings"
|
|
"text/template"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/gin-gonic/gin/binding"
|
|
)
|
|
|
|
// UserInformation contains information about the current user.
|
|
type UserInformation struct {
|
|
Login string `json:"login" header:"LOGIN" binding:"required"`
|
|
Name string `json:"name,omitempty" header:"NAME"`
|
|
Email string `json:"email,omitempty" header:"EMAIL" binding:"omitempty,email"`
|
|
LogoutURL string `json:"logout-url,omitempty" header:"LOGOUT" binding:"omitempty,uri"`
|
|
AvatarURL string `json:"avatar-url,omitempty" header:"AVATAR" binding:"omitempty,uri"`
|
|
}
|
|
|
|
// UserAuthentication is a middleware to fill information about the
|
|
// current user. It does not really perform authentication but relies
|
|
// on HTTP headers.
|
|
func (c *Component) UserAuthentication() gin.HandlerFunc {
|
|
var logoutURLTmpl, avatarURLTmpl *template.Template
|
|
if c.config.LogoutURL != "" {
|
|
logoutURLTmpl, _ = template.New("logout").Parse(c.config.LogoutURL)
|
|
}
|
|
if c.config.AvatarURL != "" {
|
|
avatarURLTmpl, _ = template.New("avatar").Parse(c.config.AvatarURL)
|
|
}
|
|
|
|
return func(gc *gin.Context) {
|
|
var info UserInformation
|
|
if err := gc.ShouldBindWith(&info, customHeaderBinding{c}); err != nil {
|
|
if c.config.DefaultUser.Login == "" {
|
|
gc.JSON(http.StatusUnauthorized, gin.H{"message": "No user logged in."})
|
|
gc.Abort()
|
|
return
|
|
}
|
|
info = c.config.DefaultUser
|
|
}
|
|
|
|
// Apply configured templates (they can access header values and choose to keep or override)
|
|
if logoutURLTmpl != nil {
|
|
var buf strings.Builder
|
|
if err := logoutURLTmpl.Execute(&buf, info); err == nil {
|
|
info.LogoutURL = buf.String()
|
|
}
|
|
}
|
|
if avatarURLTmpl != nil {
|
|
var buf strings.Builder
|
|
if err := avatarURLTmpl.Execute(&buf, info); err == nil {
|
|
info.AvatarURL = buf.String()
|
|
}
|
|
}
|
|
|
|
gc.Set("user", info)
|
|
gc.Next()
|
|
}
|
|
}
|
|
|
|
type customHeaderBinding struct {
|
|
c *Component
|
|
}
|
|
|
|
func (customHeaderBinding) Name() string {
|
|
return "header"
|
|
}
|
|
|
|
// Bind will bind struct fields to HTTP headers using the configured mapping.
|
|
func (b customHeaderBinding) Bind(req *http.Request, obj any) error {
|
|
value := reflect.ValueOf(obj).Elem()
|
|
tValue := reflect.TypeOf(obj).Elem()
|
|
if value.Kind() != reflect.Struct {
|
|
panic("should be a struct")
|
|
}
|
|
for i := range tValue.NumField() {
|
|
sf := tValue.Field(i)
|
|
if sf.PkgPath != "" && !sf.Anonymous { // unexported
|
|
continue
|
|
}
|
|
tag := sf.Tag.Get("header")
|
|
if tag == "" || tag == "-" {
|
|
continue
|
|
}
|
|
var header string
|
|
switch tag {
|
|
case "LOGIN":
|
|
header = b.c.config.Headers.Login
|
|
case "NAME":
|
|
header = b.c.config.Headers.Name
|
|
case "EMAIL":
|
|
header = b.c.config.Headers.Email
|
|
case "LOGOUT":
|
|
header = b.c.config.Headers.LogoutURL
|
|
case "AVATAR":
|
|
header = b.c.config.Headers.AvatarURL
|
|
}
|
|
if header == "" {
|
|
continue
|
|
}
|
|
value.Field(i).SetString(req.Header.Get(header))
|
|
}
|
|
|
|
return binding.Validator.ValidateStruct(obj)
|
|
}
|