mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-10-28 04:35:40 +00:00
refactor: rework file structure (#325)
* wip: add middlewares * refactor: use context fom middleware in handlers * refactor: use controller approach in handlers * refactor: move oauth providers into services (non-working) * feat: create oauth broker service * refactor: use a boostrap service to bootstrap the app * refactor: split utils into smaller files * refactor: use more clear name for frontend assets * feat: allow customizability of resources dir * fix: fix typo in ui middleware * fix: validate resource file paths in ui middleware * refactor: move resource handling to a controller * feat: add some logging * fix: configure middlewares before groups * fix: use correct api path in login mutation * fix: coderabbit suggestions * fix: further coderabbit suggestions
This commit is contained in:
260
internal/bootstrap/app_bootstrap.go
Normal file
260
internal/bootstrap/app_bootstrap.go
Normal file
@@ -0,0 +1,260 @@
|
||||
package bootstrap
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"tinyauth/internal/config"
|
||||
"tinyauth/internal/controller"
|
||||
"tinyauth/internal/middleware"
|
||||
"tinyauth/internal/service"
|
||||
"tinyauth/internal/utils"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type Controller interface {
|
||||
SetupRoutes()
|
||||
}
|
||||
|
||||
type Middleware interface {
|
||||
Middleware() gin.HandlerFunc
|
||||
Init() error
|
||||
}
|
||||
|
||||
type Service interface {
|
||||
Init() error
|
||||
}
|
||||
|
||||
type BootstrapApp struct {
|
||||
Config config.Config
|
||||
}
|
||||
|
||||
func NewBootstrapApp(config config.Config) *BootstrapApp {
|
||||
return &BootstrapApp{
|
||||
Config: config,
|
||||
}
|
||||
}
|
||||
|
||||
func (app *BootstrapApp) Setup() error {
|
||||
// Parse users
|
||||
users, err := utils.GetUsers(app.Config.Users, app.Config.UsersFile)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get domain
|
||||
domain, err := utils.GetUpperDomain(app.Config.AppURL)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Cookie names
|
||||
cookieId := utils.GenerateIdentifier(strings.Split(domain, ".")[0])
|
||||
sessionCookieName := fmt.Sprintf("%s-%s", config.SessionCookieName, cookieId)
|
||||
csrfCookieName := fmt.Sprintf("%s-%s", config.CSRFCookieName, cookieId)
|
||||
redirectCookieName := fmt.Sprintf("%s-%s", config.RedirectCookieName, cookieId)
|
||||
|
||||
// Secrets
|
||||
encryptionSecret, err := utils.DeriveKey(app.Config.Secret, "encryption")
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hmacSecret, err := utils.DeriveKey(app.Config.Secret, "hmac")
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create configs
|
||||
authConfig := service.AuthServiceConfig{
|
||||
Users: users,
|
||||
OauthWhitelist: app.Config.OAuthWhitelist,
|
||||
SessionExpiry: app.Config.SessionExpiry,
|
||||
SecureCookie: app.Config.SecureCookie,
|
||||
Domain: domain,
|
||||
LoginTimeout: app.Config.LoginTimeout,
|
||||
LoginMaxRetries: app.Config.LoginMaxRetries,
|
||||
SessionCookieName: sessionCookieName,
|
||||
HMACSecret: hmacSecret,
|
||||
EncryptionSecret: encryptionSecret,
|
||||
}
|
||||
|
||||
// Setup services
|
||||
var ldapService *service.LdapService
|
||||
|
||||
if app.Config.LdapAddress != "" {
|
||||
ldapConfig := service.LdapServiceConfig{
|
||||
Address: app.Config.LdapAddress,
|
||||
BindDN: app.Config.LdapBindDN,
|
||||
BindPassword: app.Config.LdapBindPassword,
|
||||
BaseDN: app.Config.LdapBaseDN,
|
||||
Insecure: app.Config.LdapInsecure,
|
||||
SearchFilter: app.Config.LdapSearchFilter,
|
||||
}
|
||||
|
||||
ldapService = service.NewLdapService(ldapConfig)
|
||||
|
||||
err := ldapService.Init()
|
||||
|
||||
if err != nil {
|
||||
log.Warn().Err(err).Msg("Failed to initialize LDAP service, continuing without LDAP")
|
||||
ldapService = nil
|
||||
}
|
||||
}
|
||||
|
||||
dockerService := service.NewDockerService()
|
||||
authService := service.NewAuthService(authConfig, dockerService, ldapService)
|
||||
oauthBrokerService := service.NewOAuthBrokerService(app.getOAuthBrokerConfig())
|
||||
|
||||
// Initialize services
|
||||
services := []Service{
|
||||
dockerService,
|
||||
authService,
|
||||
oauthBrokerService,
|
||||
}
|
||||
|
||||
for _, svc := range services {
|
||||
if svc != nil {
|
||||
log.Debug().Str("service", fmt.Sprintf("%T", svc)).Msg("Initializing service")
|
||||
err := svc.Init()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Configured providers
|
||||
var configuredProviders []string
|
||||
|
||||
if authService.UserAuthConfigured() || ldapService != nil {
|
||||
configuredProviders = append(configuredProviders, "username")
|
||||
}
|
||||
|
||||
configuredProviders = append(configuredProviders, oauthBrokerService.GetConfiguredServices()...)
|
||||
|
||||
if len(configuredProviders) == 0 {
|
||||
return fmt.Errorf("no authentication providers configured")
|
||||
}
|
||||
|
||||
// Create engine
|
||||
engine := gin.New()
|
||||
|
||||
if config.Version != "development" {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
}
|
||||
|
||||
// Create middlewares
|
||||
var middlewares []Middleware
|
||||
|
||||
contextMiddleware := middleware.NewContextMiddleware(middleware.ContextMiddlewareConfig{
|
||||
Domain: domain,
|
||||
}, authService, oauthBrokerService)
|
||||
|
||||
uiMiddleware := middleware.NewUIMiddleware()
|
||||
zerologMiddleware := middleware.NewZerologMiddleware()
|
||||
|
||||
middlewares = append(middlewares, contextMiddleware, uiMiddleware, zerologMiddleware)
|
||||
|
||||
for _, middleware := range middlewares {
|
||||
log.Debug().Str("middleware", fmt.Sprintf("%T", middleware)).Msg("Initializing middleware")
|
||||
err := middleware.Init()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize middleware %T: %w", middleware, err)
|
||||
}
|
||||
engine.Use(middleware.Middleware())
|
||||
}
|
||||
|
||||
// Create routers
|
||||
mainRouter := engine.Group("")
|
||||
apiRouter := engine.Group("/api")
|
||||
|
||||
// Create controllers
|
||||
contextController := controller.NewContextController(controller.ContextControllerConfig{
|
||||
ConfiguredProviders: configuredProviders,
|
||||
DisableContinue: app.Config.DisableContinue,
|
||||
Title: app.Config.Title,
|
||||
GenericName: app.Config.GenericName,
|
||||
Domain: domain,
|
||||
ForgotPasswordMessage: app.Config.FogotPasswordMessage,
|
||||
BackgroundImage: app.Config.BackgroundImage,
|
||||
OAuthAutoRedirect: app.Config.OAuthAutoRedirect,
|
||||
}, apiRouter)
|
||||
|
||||
oauthController := controller.NewOAuthController(controller.OAuthControllerConfig{
|
||||
AppURL: app.Config.AppURL,
|
||||
SecureCookie: app.Config.SecureCookie,
|
||||
CSRFCookieName: csrfCookieName,
|
||||
RedirectCookieName: redirectCookieName,
|
||||
Domain: domain,
|
||||
}, apiRouter, authService, oauthBrokerService)
|
||||
|
||||
proxyController := controller.NewProxyController(controller.ProxyControllerConfig{
|
||||
AppURL: app.Config.AppURL,
|
||||
}, apiRouter, dockerService, authService)
|
||||
|
||||
userController := controller.NewUserController(controller.UserControllerConfig{
|
||||
Domain: domain,
|
||||
}, apiRouter, authService)
|
||||
|
||||
resourcesController := controller.NewResourcesController(controller.ResourcesControllerConfig{
|
||||
ResourcesDir: app.Config.ResourcesDir,
|
||||
}, mainRouter)
|
||||
|
||||
healthController := controller.NewHealthController(apiRouter)
|
||||
|
||||
// Setup routes
|
||||
controller := []Controller{
|
||||
contextController,
|
||||
oauthController,
|
||||
proxyController,
|
||||
userController,
|
||||
healthController,
|
||||
resourcesController,
|
||||
}
|
||||
|
||||
for _, ctrl := range controller {
|
||||
log.Debug().Msgf("Setting up %T controller", ctrl)
|
||||
ctrl.SetupRoutes()
|
||||
}
|
||||
|
||||
// Start server
|
||||
address := fmt.Sprintf("%s:%d", app.Config.Address, app.Config.Port)
|
||||
log.Info().Msgf("Starting server on %s", address)
|
||||
if err := engine.Run(address); err != nil {
|
||||
log.Fatal().Err(err).Msg("Failed to start server")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Temporary
|
||||
func (app *BootstrapApp) getOAuthBrokerConfig() map[string]config.OAuthServiceConfig {
|
||||
return map[string]config.OAuthServiceConfig{
|
||||
"google": {
|
||||
ClientID: app.Config.GoogleClientId,
|
||||
ClientSecret: app.Config.GoogleClientSecret,
|
||||
RedirectURL: fmt.Sprintf("%s/api/oauth/callback/google", app.Config.AppURL),
|
||||
},
|
||||
"github": {
|
||||
ClientID: app.Config.GithubClientId,
|
||||
ClientSecret: app.Config.GithubClientSecret,
|
||||
RedirectURL: fmt.Sprintf("%s/api/oauth/callback/github", app.Config.AppURL),
|
||||
},
|
||||
"generic": {
|
||||
ClientID: app.Config.GenericClientId,
|
||||
ClientSecret: app.Config.GenericClientSecret,
|
||||
RedirectURL: fmt.Sprintf("%s/api/oauth/callback/generic", app.Config.AppURL),
|
||||
Scopes: strings.Split(app.Config.GenericScopes, ","),
|
||||
AuthURL: app.Config.GenericAuthURL,
|
||||
TokenURL: app.Config.GenericTokenURL,
|
||||
UserinfoURL: app.Config.GenericUserURL,
|
||||
InsecureSkipVerify: app.Config.GenericSkipSSL,
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user