mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-10-28 20:55:42 +00:00
refactor: use context fom middleware in handlers
This commit is contained in:
2
air.toml
2
air.toml
@@ -4,7 +4,7 @@ tmp_dir = "tmp"
|
|||||||
[build]
|
[build]
|
||||||
pre_cmd = ["mkdir -p internal/assets/dist", "echo 'backend running' > internal/assets/dist/index.html", "go install github.com/go-delve/delve/cmd/dlv@v1.25.0"]
|
pre_cmd = ["mkdir -p internal/assets/dist", "echo 'backend running' > internal/assets/dist/index.html", "go install github.com/go-delve/delve/cmd/dlv@v1.25.0"]
|
||||||
cmd = "CGO_ENABLED=0 go build -gcflags=\"all=-N -l\" -o tmp/tinyauth ."
|
cmd = "CGO_ENABLED=0 go build -gcflags=\"all=-N -l\" -o tmp/tinyauth ."
|
||||||
bin = "/go/bin/dlv --listen :4000 --headless=true --api-version=2 --accept-multiclient --log=true exec tmp/tinyauth --continue"
|
bin = "/go/bin/dlv --listen :4000 --headless=true --api-version=2 --accept-multiclient --log=true exec tmp/tinyauth --continue --check-go-version=false"
|
||||||
include_ext = ["go"]
|
include_ext = ["go"]
|
||||||
exclude_dir = ["internal/assets/dist"]
|
exclude_dir = ["internal/assets/dist"]
|
||||||
exclude_regex = [".*_test\\.go"]
|
exclude_regex = [".*_test\\.go"]
|
||||||
|
|||||||
25
cmd/root.go
25
cmd/root.go
@@ -10,8 +10,8 @@ import (
|
|||||||
"tinyauth/internal/constants"
|
"tinyauth/internal/constants"
|
||||||
"tinyauth/internal/docker"
|
"tinyauth/internal/docker"
|
||||||
"tinyauth/internal/handlers"
|
"tinyauth/internal/handlers"
|
||||||
"tinyauth/internal/hooks"
|
|
||||||
"tinyauth/internal/ldap"
|
"tinyauth/internal/ldap"
|
||||||
|
"tinyauth/internal/middleware"
|
||||||
"tinyauth/internal/providers"
|
"tinyauth/internal/providers"
|
||||||
"tinyauth/internal/server"
|
"tinyauth/internal/server"
|
||||||
"tinyauth/internal/types"
|
"tinyauth/internal/types"
|
||||||
@@ -84,7 +84,7 @@ var rootCmd = &cobra.Command{
|
|||||||
AppURL: config.AppURL,
|
AppURL: config.AppURL,
|
||||||
}
|
}
|
||||||
|
|
||||||
handlersConfig := types.HandlersConfig{
|
handlersConfig := handlers.HandlersConfig{
|
||||||
AppURL: config.AppURL,
|
AppURL: config.AppURL,
|
||||||
DisableContinue: config.DisableContinue,
|
DisableContinue: config.DisableContinue,
|
||||||
Title: config.Title,
|
Title: config.Title,
|
||||||
@@ -116,10 +116,6 @@ var rootCmd = &cobra.Command{
|
|||||||
EncryptionSecret: encryptionSecret,
|
EncryptionSecret: encryptionSecret,
|
||||||
}
|
}
|
||||||
|
|
||||||
hooksConfig := types.HooksConfig{
|
|
||||||
Domain: domain,
|
|
||||||
}
|
|
||||||
|
|
||||||
var ldapService *ldap.LDAP
|
var ldapService *ldap.LDAP
|
||||||
|
|
||||||
if config.LdapAddress != "" {
|
if config.LdapAddress != "" {
|
||||||
@@ -151,9 +147,20 @@ var rootCmd = &cobra.Command{
|
|||||||
HandleError(err, "Failed to initialize docker")
|
HandleError(err, "Failed to initialize docker")
|
||||||
auth := auth.NewAuth(authConfig, docker, ldapService)
|
auth := auth.NewAuth(authConfig, docker, ldapService)
|
||||||
providers := providers.NewProviders(oauthConfig)
|
providers := providers.NewProviders(oauthConfig)
|
||||||
hooks := hooks.NewHooks(hooksConfig, auth, providers)
|
handlers := handlers.NewHandlers(handlersConfig, auth, providers, docker)
|
||||||
handlers := handlers.NewHandlers(handlersConfig, auth, hooks, providers, docker)
|
|
||||||
srv, err := server.NewServer(serverConfig, handlers)
|
// Setup the middlewares
|
||||||
|
var middlewares []server.Middleware
|
||||||
|
|
||||||
|
contextMiddleware := middleware.NewContextMiddleware(middleware.ContextMiddlewareConfig{
|
||||||
|
Domain: domain,
|
||||||
|
}, auth, providers)
|
||||||
|
uiMiddleware := middleware.NewUIMiddleware()
|
||||||
|
zerologMiddleware := middleware.NewZerologMiddleware()
|
||||||
|
|
||||||
|
middlewares = append(middlewares, contextMiddleware, uiMiddleware, zerologMiddleware)
|
||||||
|
|
||||||
|
srv, err := server.NewServer(serverConfig, handlers, middlewares)
|
||||||
HandleError(err, "Failed to create server")
|
HandleError(err, "Failed to create server")
|
||||||
|
|
||||||
// Start up
|
// Start up
|
||||||
|
|||||||
@@ -37,8 +37,28 @@ func (h *Handlers) AppContextHandler(c *gin.Context) {
|
|||||||
func (h *Handlers) UserContextHandler(c *gin.Context) {
|
func (h *Handlers) UserContextHandler(c *gin.Context) {
|
||||||
log.Debug().Msg("Getting user context")
|
log.Debug().Msg("Getting user context")
|
||||||
|
|
||||||
// Create user context using hooks
|
// Get user context from middleware
|
||||||
userContext := h.Hooks.UseUserContext(c)
|
userContextValue, exists := c.Get("context")
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
c.JSON(200, types.UserContextResponse{
|
||||||
|
Status: 200,
|
||||||
|
Message: "Unauthorized",
|
||||||
|
IsLoggedIn: false,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userContext, ok := userContextValue.(*types.UserContext)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
c.JSON(200, types.UserContextResponse{
|
||||||
|
Status: 200,
|
||||||
|
Message: "Unauthorized",
|
||||||
|
IsLoggedIn: false,
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
userContextResponse := types.UserContextResponse{
|
userContextResponse := types.UserContextResponse{
|
||||||
Status: 200,
|
Status: 200,
|
||||||
|
|||||||
@@ -3,26 +3,36 @@ package handlers
|
|||||||
import (
|
import (
|
||||||
"tinyauth/internal/auth"
|
"tinyauth/internal/auth"
|
||||||
"tinyauth/internal/docker"
|
"tinyauth/internal/docker"
|
||||||
"tinyauth/internal/hooks"
|
|
||||||
"tinyauth/internal/providers"
|
"tinyauth/internal/providers"
|
||||||
"tinyauth/internal/types"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type HandlersConfig struct {
|
||||||
|
AppURL string
|
||||||
|
Domain string
|
||||||
|
CookieSecure bool
|
||||||
|
DisableContinue bool
|
||||||
|
GenericName string
|
||||||
|
Title string
|
||||||
|
ForgotPasswordMessage string
|
||||||
|
BackgroundImage string
|
||||||
|
OAuthAutoRedirect string
|
||||||
|
CsrfCookieName string
|
||||||
|
RedirectCookieName string
|
||||||
|
}
|
||||||
|
|
||||||
type Handlers struct {
|
type Handlers struct {
|
||||||
Config types.HandlersConfig
|
Config HandlersConfig
|
||||||
Auth *auth.Auth
|
Auth *auth.Auth
|
||||||
Hooks *hooks.Hooks
|
|
||||||
Providers *providers.Providers
|
Providers *providers.Providers
|
||||||
Docker *docker.Docker
|
Docker *docker.Docker
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandlers(config types.HandlersConfig, auth *auth.Auth, hooks *hooks.Hooks, providers *providers.Providers, docker *docker.Docker) *Handlers {
|
func NewHandlers(config HandlersConfig, auth *auth.Auth, providers *providers.Providers, docker *docker.Docker) *Handlers {
|
||||||
return &Handlers{
|
return &Handlers{
|
||||||
Config: config,
|
Config: config,
|
||||||
Auth: auth,
|
Auth: auth,
|
||||||
Hooks: hooks,
|
|
||||||
Providers: providers,
|
Providers: providers,
|
||||||
Docker: docker,
|
Docker: docker,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -146,7 +146,24 @@ func (h *Handlers) ProxyHandler(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userContext := h.Hooks.UseUserContext(c)
|
var userContext *types.UserContext
|
||||||
|
|
||||||
|
userContextValue, exists := c.Get("context")
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
userContext = &types.UserContext{
|
||||||
|
IsLoggedIn: false,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var ok bool
|
||||||
|
userContext, ok = userContextValue.(*types.UserContext)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
userContext = &types.UserContext{
|
||||||
|
IsLoggedIn: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we are using basic auth, we need to check if the user has totp and if it does then disable basic auth
|
// If we are using basic auth, we need to check if the user has totp and if it does then disable basic auth
|
||||||
if userContext.Provider == "basic" && userContext.TotpEnabled {
|
if userContext.Provider == "basic" && userContext.TotpEnabled {
|
||||||
@@ -158,7 +175,7 @@ func (h *Handlers) ProxyHandler(c *gin.Context) {
|
|||||||
log.Debug().Msg("Authenticated")
|
log.Debug().Msg("Authenticated")
|
||||||
|
|
||||||
// Check if user is allowed to access subdomain, if request is nginx.example.com the subdomain (resource) is nginx
|
// Check if user is allowed to access subdomain, if request is nginx.example.com the subdomain (resource) is nginx
|
||||||
appAllowed := h.Auth.ResourceAllowed(c, userContext, labels)
|
appAllowed := h.Auth.ResourceAllowed(c, *userContext, labels)
|
||||||
|
|
||||||
log.Debug().Bool("appAllowed", appAllowed).Msg("Checking if app is allowed")
|
log.Debug().Bool("appAllowed", appAllowed).Msg("Checking if app is allowed")
|
||||||
|
|
||||||
@@ -195,7 +212,7 @@ func (h *Handlers) ProxyHandler(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if userContext.OAuth {
|
if userContext.OAuth {
|
||||||
groupOk := h.Auth.OAuthGroup(c, userContext, labels)
|
groupOk := h.Auth.OAuthGroup(c, *userContext, labels)
|
||||||
|
|
||||||
log.Debug().Bool("groupOk", groupOk).Msg("Checking if user is in required groups")
|
log.Debug().Bool("groupOk", groupOk).Msg("Checking if user is in required groups")
|
||||||
|
|
||||||
|
|||||||
@@ -141,7 +141,25 @@ func (h *Handlers) TOTPHandler(c *gin.Context) {
|
|||||||
log.Debug().Msg("Checking totp")
|
log.Debug().Msg("Checking totp")
|
||||||
|
|
||||||
// Get user context
|
// Get user context
|
||||||
userContext := h.Hooks.UseUserContext(c)
|
userContextValue, exists := c.Get("context")
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
c.JSON(401, gin.H{
|
||||||
|
"status": 401,
|
||||||
|
"message": "Unauthorized",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
userContext, ok := userContextValue.(*types.UserContext)
|
||||||
|
|
||||||
|
if !ok {
|
||||||
|
c.JSON(401, gin.H{
|
||||||
|
"status": 401,
|
||||||
|
"message": "Unauthorized",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Check if we have a user
|
// Check if we have a user
|
||||||
if userContext.Username == "" {
|
if userContext.Username == "" {
|
||||||
@@ -157,7 +175,7 @@ func (h *Handlers) TOTPHandler(c *gin.Context) {
|
|||||||
user := h.Auth.GetLocalUser(userContext.Username)
|
user := h.Auth.GetLocalUser(userContext.Username)
|
||||||
|
|
||||||
// Check if totp is correct
|
// Check if totp is correct
|
||||||
ok := totp.Validate(totpReq.Code, user.TotpSecret)
|
ok = totp.Validate(totpReq.Code, user.TotpSecret)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Debug().Msg("Totp incorrect")
|
log.Debug().Msg("Totp incorrect")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package middlewares
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -29,6 +29,14 @@ func NewContextMiddleware(config ContextMiddlewareConfig, auth *auth.Auth, provi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *ContextMiddleware) Init() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ContextMiddleware) Name() string {
|
||||||
|
return "ContextMiddleware"
|
||||||
|
}
|
||||||
|
|
||||||
func (m *ContextMiddleware) Middleware() gin.HandlerFunc {
|
func (m *ContextMiddleware) Middleware() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
cookie, err := m.Auth.GetSessionCookie(c)
|
cookie, err := m.Auth.GetSessionCookie(c)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package middlewares
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io/fs"
|
"io/fs"
|
||||||
@@ -16,24 +16,29 @@ type UIMiddleware struct {
|
|||||||
ResourcesFileServer http.Handler
|
ResourcesFileServer http.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewUIMiddleware() (*UIMiddleware, error) {
|
func NewUIMiddleware() *UIMiddleware {
|
||||||
|
return &UIMiddleware{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UIMiddleware) Init() error {
|
||||||
ui, err := fs.Sub(assets.Assets, "dist")
|
ui, err := fs.Sub(assets.Assets, "dist")
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
uiFileServer := http.FileServer(http.FS(ui))
|
m.UIFS = ui
|
||||||
resourcesFileServer := http.FileServer(http.Dir("/data/resources"))
|
m.UIFileServer = http.FileServer(http.FS(ui))
|
||||||
|
m.ResourcesFileServer = http.FileServer(http.Dir("/data/resources"))
|
||||||
|
|
||||||
return &UIMiddleware{
|
return nil
|
||||||
UIFS: ui,
|
|
||||||
UIFileServer: uiFileServer,
|
|
||||||
ResourcesFileServer: resourcesFileServer,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m UIMiddleware) Middlware() gin.HandlerFunc {
|
func (m *UIMiddleware) Name() string {
|
||||||
|
return "UIMiddleware"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *UIMiddleware) Middleware() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
switch strings.Split(c.Request.URL.Path, "/")[1] {
|
switch strings.Split(c.Request.URL.Path, "/")[1] {
|
||||||
case "api":
|
case "api":
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package middlewares
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
@@ -22,7 +22,15 @@ func NewZerologMiddleware() *ZerologMiddleware {
|
|||||||
return &ZerologMiddleware{}
|
return &ZerologMiddleware{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m ZerologMiddleware) logPath(path string) bool {
|
func (m *ZerologMiddleware) Init() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ZerologMiddleware) Name() string {
|
||||||
|
return "ZerologMiddleware"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *ZerologMiddleware) logPath(path string) bool {
|
||||||
for _, prefix := range loggerSkipPathsPrefix {
|
for _, prefix := range loggerSkipPathsPrefix {
|
||||||
if strings.HasPrefix(path, prefix) {
|
if strings.HasPrefix(path, prefix) {
|
||||||
return false
|
return false
|
||||||
@@ -31,7 +39,7 @@ func (m ZerologMiddleware) logPath(path string) bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m ZerologMiddleware) Middlware() gin.HandlerFunc {
|
func (m *ZerologMiddleware) Middleware() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
tStart := time.Now()
|
tStart := time.Now()
|
||||||
|
|
||||||
|
|||||||
@@ -15,15 +15,22 @@ type Server struct {
|
|||||||
Router *gin.Engine
|
Router *gin.Engine
|
||||||
}
|
}
|
||||||
|
|
||||||
type Middlware interface {
|
type Middleware interface {
|
||||||
Middlware() gin.HandlerFunc
|
Middleware() gin.HandlerFunc
|
||||||
|
Init() error
|
||||||
|
Name() string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewServer(config types.ServerConfig, handlers *handlers.Handlers, middlewares []Middlware) (*Server, error) {
|
func NewServer(config types.ServerConfig, handlers *handlers.Handlers, middlewares []Middleware) (*Server, error) {
|
||||||
router := gin.New()
|
router := gin.New()
|
||||||
|
|
||||||
for _, middleware := range middlewares {
|
for _, middleware := range middlewares {
|
||||||
router.Use(middleware.Middlware())
|
log.Debug().Str("middleware", middleware.Name()).Msg("Initializing middleware")
|
||||||
|
err := middleware.Init()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to initialize middleware %s: %w", middleware.Name(), err)
|
||||||
|
}
|
||||||
|
router.Use(middleware.Middleware())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Proxy routes
|
// Proxy routes
|
||||||
|
|||||||
@@ -44,21 +44,6 @@ type Config struct {
|
|||||||
LdapSearchFilter string `mapstructure:"ldap-search-filter"`
|
LdapSearchFilter string `mapstructure:"ldap-search-filter"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Server configuration
|
|
||||||
type HandlersConfig struct {
|
|
||||||
AppURL string
|
|
||||||
Domain string
|
|
||||||
CookieSecure bool
|
|
||||||
DisableContinue bool
|
|
||||||
GenericName string
|
|
||||||
Title string
|
|
||||||
ForgotPasswordMessage string
|
|
||||||
BackgroundImage string
|
|
||||||
OAuthAutoRedirect string
|
|
||||||
CsrfCookieName string
|
|
||||||
RedirectCookieName string
|
|
||||||
}
|
|
||||||
|
|
||||||
// OAuthConfig is the configuration for the providers
|
// OAuthConfig is the configuration for the providers
|
||||||
type OAuthConfig struct {
|
type OAuthConfig struct {
|
||||||
GithubClientId string
|
GithubClientId string
|
||||||
|
|||||||
Reference in New Issue
Block a user