mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-10-28 04:35:40 +00:00
refactor: remove dependency on gin sessions
This commit is contained in:
@@ -11,8 +11,6 @@ import (
|
||||
"tinyauth/internal/handlers"
|
||||
"tinyauth/internal/types"
|
||||
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-contrib/sessions/cookie"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
@@ -51,21 +49,6 @@ func (api *API) Init() {
|
||||
log.Debug().Msg("Setting up file server")
|
||||
fileServer := http.FileServer(http.FS(dist))
|
||||
|
||||
// Setup cookie store
|
||||
log.Debug().Msg("Setting up cookie store")
|
||||
store := cookie.NewStore([]byte(api.Config.Secret))
|
||||
|
||||
// Use session middleware
|
||||
store.Options(sessions.Options{
|
||||
Domain: api.Config.Domain,
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
Secure: api.Config.CookieSecure,
|
||||
MaxAge: api.Config.SessionExpiry,
|
||||
})
|
||||
|
||||
router.Use(sessions.Sessions("tinyauth", store))
|
||||
|
||||
// UI middleware
|
||||
router.Use(func(c *gin.Context) {
|
||||
// If not an API request, serve the UI
|
||||
|
||||
@@ -21,11 +21,8 @@ import (
|
||||
|
||||
// Simple API config for tests
|
||||
var apiConfig = types.APIConfig{
|
||||
Port: 8080,
|
||||
Address: "0.0.0.0",
|
||||
Secret: "super-secret-api-thing-for-tests", // It is 32 chars long
|
||||
CookieSecure: false,
|
||||
SessionExpiry: 3600,
|
||||
Port: 8080,
|
||||
Address: "0.0.0.0",
|
||||
}
|
||||
|
||||
// Simple handlers config for tests
|
||||
@@ -42,6 +39,8 @@ var handlersConfig = types.HandlersConfig{
|
||||
var authConfig = types.AuthConfig{
|
||||
Users: types.Users{},
|
||||
OauthWhitelist: []string{},
|
||||
Secret: "super-secret-api-thing-for-tests", // It is 32 chars long
|
||||
CookieSecure: false,
|
||||
SessionExpiry: 3600,
|
||||
LoginTimeout: 0,
|
||||
LoginMaxRetries: 0,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
@@ -9,8 +11,8 @@ import (
|
||||
"tinyauth/internal/docker"
|
||||
"tinyauth/internal/types"
|
||||
|
||||
"github.com/gin-contrib/sessions"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/rs/zerolog/log"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
@@ -30,6 +32,30 @@ type Auth struct {
|
||||
LoginMutex sync.RWMutex
|
||||
}
|
||||
|
||||
func (auth *Auth) GetSession(c *gin.Context) (*sessions.Session, error) {
|
||||
// Create cookie store
|
||||
store := sessions.NewCookieStore([]byte(auth.Config.Secret))
|
||||
|
||||
// Configure cookie store
|
||||
store.Options = &sessions.Options{
|
||||
Path: "/",
|
||||
MaxAge: auth.Config.SessionExpiry,
|
||||
Secure: auth.Config.CookieSecure,
|
||||
HttpOnly: true,
|
||||
SameSite: http.SameSiteDefaultMode,
|
||||
Domain: fmt.Sprintf(".%s", auth.Config.Domain),
|
||||
}
|
||||
|
||||
// Get session
|
||||
session, err := store.Get(c.Request, "tinyauth")
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get session")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return session, nil
|
||||
}
|
||||
|
||||
func (auth *Auth) GetUser(username string) *types.User {
|
||||
// Loop through users and return the user if the username matches
|
||||
for _, user := range auth.Config.Users {
|
||||
@@ -126,11 +152,15 @@ func (auth *Auth) EmailWhitelisted(emailSrc string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (auth *Auth) CreateSessionCookie(c *gin.Context, data *types.SessionCookie) {
|
||||
func (auth *Auth) CreateSessionCookie(c *gin.Context, data *types.SessionCookie) error {
|
||||
log.Debug().Msg("Creating session cookie")
|
||||
|
||||
// Get session
|
||||
sessions := sessions.Default(c)
|
||||
session, err := auth.GetSession(c)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get session")
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debug().Msg("Setting session cookie")
|
||||
|
||||
@@ -144,39 +174,63 @@ func (auth *Auth) CreateSessionCookie(c *gin.Context, data *types.SessionCookie)
|
||||
}
|
||||
|
||||
// Set data
|
||||
sessions.Set("username", data.Username)
|
||||
sessions.Set("provider", data.Provider)
|
||||
sessions.Set("expiry", time.Now().Add(time.Duration(sessionExpiry)*time.Second).Unix())
|
||||
sessions.Set("totpPending", data.TotpPending)
|
||||
session.Values["username"] = data.Username
|
||||
session.Values["provider"] = data.Provider
|
||||
session.Values["expiry"] = time.Now().Add(time.Duration(sessionExpiry) * time.Second).Unix()
|
||||
session.Values["totpPending"] = data.TotpPending
|
||||
|
||||
// Save session
|
||||
sessions.Save()
|
||||
err = session.Save(c.Request, c.Writer)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to save session")
|
||||
return err
|
||||
}
|
||||
|
||||
// Return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (auth *Auth) DeleteSessionCookie(c *gin.Context) {
|
||||
func (auth *Auth) DeleteSessionCookie(c *gin.Context) error {
|
||||
log.Debug().Msg("Deleting session cookie")
|
||||
|
||||
// Get session
|
||||
sessions := sessions.Default(c)
|
||||
session, err := auth.GetSession(c)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get session")
|
||||
return err
|
||||
}
|
||||
|
||||
// Clear session
|
||||
sessions.Clear()
|
||||
// Delete all values in the session
|
||||
for key := range session.Values {
|
||||
delete(session.Values, key)
|
||||
}
|
||||
|
||||
// Save session
|
||||
sessions.Save()
|
||||
err = session.Save(c.Request, c.Writer)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to save session")
|
||||
return err
|
||||
}
|
||||
|
||||
// Return nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (auth *Auth) GetSessionCookie(c *gin.Context) types.SessionCookie {
|
||||
func (auth *Auth) GetSessionCookie(c *gin.Context) (types.SessionCookie, error) {
|
||||
log.Debug().Msg("Getting session cookie")
|
||||
|
||||
// Get session
|
||||
sessions := sessions.Default(c)
|
||||
session, err := auth.GetSession(c)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get session")
|
||||
return types.SessionCookie{}, err
|
||||
}
|
||||
|
||||
// Get data
|
||||
cookieUsername := sessions.Get("username")
|
||||
cookieProvider := sessions.Get("provider")
|
||||
cookieExpiry := sessions.Get("expiry")
|
||||
cookieTotpPending := sessions.Get("totpPending")
|
||||
cookieUsername := session.Values["username"]
|
||||
cookieProvider := session.Values["provider"]
|
||||
cookieExpiry := session.Values["expiry"]
|
||||
cookieTotpPending := session.Values["totpPending"]
|
||||
|
||||
// Convert interfaces to correct types
|
||||
username, usernameOk := cookieUsername.(string)
|
||||
@@ -187,7 +241,7 @@ func (auth *Auth) GetSessionCookie(c *gin.Context) types.SessionCookie {
|
||||
// Check if the cookie is invalid
|
||||
if !usernameOk || !providerOk || !expiryOk || !totpPendingOk {
|
||||
log.Warn().Msg("Session cookie invalid")
|
||||
return types.SessionCookie{}
|
||||
return types.SessionCookie{}, nil
|
||||
}
|
||||
|
||||
// Check if the cookie has expired
|
||||
@@ -198,7 +252,7 @@ func (auth *Auth) GetSessionCookie(c *gin.Context) types.SessionCookie {
|
||||
auth.DeleteSessionCookie(c)
|
||||
|
||||
// Return empty cookie
|
||||
return types.SessionCookie{}
|
||||
return types.SessionCookie{}, nil
|
||||
}
|
||||
|
||||
log.Debug().Str("username", username).Str("provider", provider).Int64("expiry", expiry).Bool("totpPending", totpPending).Msg("Parsed cookie")
|
||||
@@ -208,7 +262,7 @@ func (auth *Auth) GetSessionCookie(c *gin.Context) types.SessionCookie {
|
||||
Username: username,
|
||||
Provider: provider,
|
||||
TotpPending: totpPending,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (auth *Auth) UserAuthConfigured() bool {
|
||||
|
||||
@@ -23,7 +23,7 @@ type Hooks struct {
|
||||
|
||||
func (hooks *Hooks) UseUserContext(c *gin.Context) types.UserContext {
|
||||
// Get session cookie and basic auth
|
||||
cookie := hooks.Auth.GetSessionCookie(c)
|
||||
cookie, err := hooks.Auth.GetSessionCookie(c)
|
||||
basic := hooks.Auth.GetBasicAuth(c)
|
||||
|
||||
// Check if basic auth is set
|
||||
@@ -46,6 +46,19 @@ func (hooks *Hooks) UseUserContext(c *gin.Context) types.UserContext {
|
||||
|
||||
}
|
||||
|
||||
// Check cookie error after basic auth
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("Failed to get session cookie")
|
||||
// Return empty context
|
||||
return types.UserContext{
|
||||
Username: "",
|
||||
IsLoggedIn: false,
|
||||
OAuth: false,
|
||||
Provider: "",
|
||||
TotpPending: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Check if session cookie has totp pending
|
||||
if cookie.TotpPending {
|
||||
log.Debug().Msg("Totp pending")
|
||||
|
||||
@@ -66,12 +66,8 @@ type OAuthConfig struct {
|
||||
|
||||
// APIConfig is the configuration for the API
|
||||
type APIConfig struct {
|
||||
Port int
|
||||
Address string
|
||||
Secret string
|
||||
CookieSecure bool
|
||||
SessionExpiry int
|
||||
Domain string
|
||||
Port int
|
||||
Address string
|
||||
}
|
||||
|
||||
// AuthConfig is the configuration for the auth service
|
||||
@@ -79,6 +75,9 @@ type AuthConfig struct {
|
||||
Users Users
|
||||
OauthWhitelist []string
|
||||
SessionExpiry int
|
||||
Secret string
|
||||
CookieSecure bool
|
||||
Domain string
|
||||
LoginTimeout int
|
||||
LoginMaxRetries int
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user