mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2025-10-28 12:45:47 +00:00
tests: add user controller tests
This commit is contained in:
@@ -11,19 +11,49 @@ import (
|
|||||||
"gotest.tools/v3/assert"
|
"gotest.tools/v3/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestAppContextHandler(t *testing.T) {
|
var controllerCfg = controller.ContextControllerConfig{
|
||||||
// Setup
|
ConfiguredProviders: []string{"github", "google", "generic"},
|
||||||
controllerCfg := controller.ContextControllerConfig{
|
Title: "Test App",
|
||||||
ConfiguredProviders: []string{"github", "google", "generic"},
|
GenericName: "Generic",
|
||||||
Title: "Test App",
|
AppURL: "http://localhost:8080",
|
||||||
GenericName: "Generic",
|
RootDomain: "localhost",
|
||||||
AppURL: "http://localhost:8080",
|
ForgotPasswordMessage: "Contact admin to reset your password.",
|
||||||
RootDomain: "localhost",
|
BackgroundImage: "/assets/bg.jpg",
|
||||||
ForgotPasswordMessage: "Contact admin to reset your password.",
|
OAuthAutoRedirect: "google",
|
||||||
BackgroundImage: "/assets/bg.jpg",
|
}
|
||||||
OAuthAutoRedirect: "google",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var userContext = config.UserContext{
|
||||||
|
Username: "testuser",
|
||||||
|
Name: "testuser",
|
||||||
|
Email: "test@example.com",
|
||||||
|
IsLoggedIn: true,
|
||||||
|
OAuth: false,
|
||||||
|
Provider: "username",
|
||||||
|
TotpPending: false,
|
||||||
|
OAuthGroups: "",
|
||||||
|
TotpEnabled: false,
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupContextController() (*gin.Engine, *httptest.ResponseRecorder) {
|
||||||
|
// Setup
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
router := gin.Default()
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
router.Use(func(c *gin.Context) {
|
||||||
|
c.Set("context", &userContext)
|
||||||
|
c.Next()
|
||||||
|
})
|
||||||
|
|
||||||
|
group := router.Group("/api")
|
||||||
|
|
||||||
|
ctrl := controller.NewContextController(controllerCfg, group)
|
||||||
|
ctrl.SetupRoutes()
|
||||||
|
|
||||||
|
return router, recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAppContextHandler(t *testing.T) {
|
||||||
expectedRes := controller.AppContextResponse{
|
expectedRes := controller.AppContextResponse{
|
||||||
Status: 200,
|
Status: 200,
|
||||||
Message: "Success",
|
Message: "Success",
|
||||||
@@ -37,15 +67,7 @@ func TestAppContextHandler(t *testing.T) {
|
|||||||
OAuthAutoRedirect: controllerCfg.OAuthAutoRedirect,
|
OAuthAutoRedirect: controllerCfg.OAuthAutoRedirect,
|
||||||
}
|
}
|
||||||
|
|
||||||
gin.SetMode(gin.TestMode)
|
router, recorder := setupContextController()
|
||||||
router := gin.Default()
|
|
||||||
group := router.Group("/api")
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
|
|
||||||
// Test
|
|
||||||
ctrl := controller.NewContextController(controllerCfg, group)
|
|
||||||
ctrl.SetupRoutes()
|
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "/api/context/app", nil)
|
req := httptest.NewRequest("GET", "/api/context/app", nil)
|
||||||
router.ServeHTTP(recorder, req)
|
router.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
@@ -59,22 +81,7 @@ func TestAppContextHandler(t *testing.T) {
|
|||||||
assert.DeepEqual(t, expectedRes, ctrlRes)
|
assert.DeepEqual(t, expectedRes, ctrlRes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUserContextController(t *testing.T) {
|
func TestUserContextHandler(t *testing.T) {
|
||||||
// Setup
|
|
||||||
controllerCfg := controller.ContextControllerConfig{}
|
|
||||||
|
|
||||||
userContext := config.UserContext{
|
|
||||||
Username: "testuser",
|
|
||||||
Name: "testuser",
|
|
||||||
Email: "test@example.com",
|
|
||||||
IsLoggedIn: true,
|
|
||||||
OAuth: false,
|
|
||||||
Provider: "username",
|
|
||||||
TotpPending: false,
|
|
||||||
OAuthGroups: "",
|
|
||||||
TotpEnabled: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
expectedRes := controller.UserContextResponse{
|
expectedRes := controller.UserContextResponse{
|
||||||
Status: 200,
|
Status: 200,
|
||||||
Message: "Success",
|
Message: "Success",
|
||||||
@@ -87,21 +94,7 @@ func TestUserContextController(t *testing.T) {
|
|||||||
TotpPending: userContext.TotpPending,
|
TotpPending: userContext.TotpPending,
|
||||||
}
|
}
|
||||||
|
|
||||||
gin.SetMode(gin.TestMode)
|
router, recorder := setupContextController()
|
||||||
router := gin.Default()
|
|
||||||
recorder := httptest.NewRecorder()
|
|
||||||
|
|
||||||
router.Use(func(c *gin.Context) {
|
|
||||||
c.Set("context", &userContext)
|
|
||||||
c.Next()
|
|
||||||
})
|
|
||||||
|
|
||||||
group := router.Group("/api")
|
|
||||||
|
|
||||||
// Test
|
|
||||||
ctrl := controller.NewContextController(controllerCfg, group)
|
|
||||||
ctrl.SetupRoutes()
|
|
||||||
|
|
||||||
req := httptest.NewRequest("GET", "/api/context/user", nil)
|
req := httptest.NewRequest("GET", "/api/context/user", nil)
|
||||||
router.ServeHTTP(recorder, req)
|
router.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
|||||||
283
internal/controller/user_controller_test.go
Normal file
283
internal/controller/user_controller_test.go
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
package controller_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
"tinyauth/internal/config"
|
||||||
|
"tinyauth/internal/controller"
|
||||||
|
"tinyauth/internal/service"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/pquerna/otp/totp"
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var cookieValue string
|
||||||
|
var totpSecret = "6WFZXPEZRK5MZHHYAFW4DAOUYQMCASBJ"
|
||||||
|
|
||||||
|
func setupUserController(t *testing.T, middlewares *[]gin.HandlerFunc) (*gin.Engine, *httptest.ResponseRecorder) {
|
||||||
|
// Setup
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
router := gin.Default()
|
||||||
|
|
||||||
|
if middlewares != nil {
|
||||||
|
for _, m := range *middlewares {
|
||||||
|
router.Use(m)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
group := router.Group("/api")
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
// Database
|
||||||
|
databaseService := service.NewDatabaseService(service.DatabaseServiceConfig{
|
||||||
|
DatabasePath: "/tmp/tinyauth_test.db",
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.NilError(t, databaseService.Init())
|
||||||
|
|
||||||
|
database := databaseService.GetDatabase()
|
||||||
|
|
||||||
|
// Auth service
|
||||||
|
authService := service.NewAuthService(service.AuthServiceConfig{
|
||||||
|
Users: []config.User{
|
||||||
|
{
|
||||||
|
Username: "testuser",
|
||||||
|
Password: "$2a$10$ne6z693sTgzT3ePoQ05PgOecUHnBjM7sSNj6M.l5CLUP.f6NyCnt.", // test
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Username: "totpuser",
|
||||||
|
Password: "$2a$10$ne6z693sTgzT3ePoQ05PgOecUHnBjM7sSNj6M.l5CLUP.f6NyCnt.", // test
|
||||||
|
TotpSecret: totpSecret,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
OauthWhitelist: "",
|
||||||
|
SessionExpiry: 3600,
|
||||||
|
SecureCookie: false,
|
||||||
|
RootDomain: "localhost",
|
||||||
|
LoginTimeout: 300,
|
||||||
|
LoginMaxRetries: 3,
|
||||||
|
SessionCookieName: "tinyauth-session",
|
||||||
|
}, nil, nil, database)
|
||||||
|
|
||||||
|
// Controller
|
||||||
|
ctrl := controller.NewUserController(controller.UserControllerConfig{
|
||||||
|
RootDomain: "localhost",
|
||||||
|
}, group, authService)
|
||||||
|
ctrl.SetupRoutes()
|
||||||
|
|
||||||
|
return router, recorder
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoginHandler(t *testing.T) {
|
||||||
|
// Setup
|
||||||
|
router, recorder := setupUserController(t, nil)
|
||||||
|
|
||||||
|
loginReq := controller.LoginRequest{
|
||||||
|
Username: "testuser",
|
||||||
|
Password: "test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginReqJson, err := json.Marshal(loginReq)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
// Test
|
||||||
|
req := httptest.NewRequest("POST", "/api/user/login", strings.NewReader(string(loginReqJson)))
|
||||||
|
router.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
assert.Equal(t, 200, recorder.Code)
|
||||||
|
|
||||||
|
cookie := recorder.Result().Cookies()[0]
|
||||||
|
|
||||||
|
assert.Equal(t, "tinyauth-session", cookie.Name)
|
||||||
|
assert.Assert(t, cookie.Value != "")
|
||||||
|
|
||||||
|
cookieValue = cookie.Value
|
||||||
|
|
||||||
|
// Test invalid credentials
|
||||||
|
loginReq = controller.LoginRequest{
|
||||||
|
Username: "testuser",
|
||||||
|
Password: "invalid",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginReqJson, err = json.Marshal(loginReq)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
recorder = httptest.NewRecorder()
|
||||||
|
req = httptest.NewRequest("POST", "/api/user/login", strings.NewReader(string(loginReqJson)))
|
||||||
|
router.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
assert.Equal(t, 401, recorder.Code)
|
||||||
|
|
||||||
|
// Test totp required
|
||||||
|
loginReq = controller.LoginRequest{
|
||||||
|
Username: "totpuser",
|
||||||
|
Password: "test",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginReqJson, err = json.Marshal(loginReq)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
recorder = httptest.NewRecorder()
|
||||||
|
req = httptest.NewRequest("POST", "/api/user/login", strings.NewReader(string(loginReqJson)))
|
||||||
|
router.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
assert.Equal(t, 200, recorder.Code)
|
||||||
|
|
||||||
|
loginResJson, err := json.Marshal(map[string]any{
|
||||||
|
"message": "TOTP required",
|
||||||
|
"status": 200,
|
||||||
|
"totpPending": true,
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
assert.Equal(t, string(loginResJson), recorder.Body.String())
|
||||||
|
|
||||||
|
// Test rate limiting
|
||||||
|
loginReq = controller.LoginRequest{
|
||||||
|
Username: "testuser",
|
||||||
|
Password: "invalid",
|
||||||
|
}
|
||||||
|
|
||||||
|
loginReqJson, err = json.Marshal(loginReq)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
for range 5 {
|
||||||
|
recorder = httptest.NewRecorder()
|
||||||
|
req = httptest.NewRequest("POST", "/api/user/login", strings.NewReader(string(loginReqJson)))
|
||||||
|
router.ServeHTTP(recorder, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 429, recorder.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLogoutHandler(t *testing.T) {
|
||||||
|
// Setup
|
||||||
|
router, recorder := setupUserController(t, nil)
|
||||||
|
|
||||||
|
// Test
|
||||||
|
req := httptest.NewRequest("POST", "/api/user/logout", nil)
|
||||||
|
|
||||||
|
req.AddCookie(&http.Cookie{
|
||||||
|
Name: "tinyauth-session",
|
||||||
|
Value: cookieValue,
|
||||||
|
})
|
||||||
|
|
||||||
|
router.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
assert.Equal(t, 200, recorder.Code)
|
||||||
|
|
||||||
|
cookie := recorder.Result().Cookies()[0]
|
||||||
|
|
||||||
|
assert.Equal(t, "tinyauth-session", cookie.Name)
|
||||||
|
assert.Equal(t, "", cookie.Value)
|
||||||
|
assert.Equal(t, -1, cookie.MaxAge)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTotpHandler(t *testing.T) {
|
||||||
|
// Setup
|
||||||
|
router, recorder := setupUserController(t, &[]gin.HandlerFunc{
|
||||||
|
func(c *gin.Context) {
|
||||||
|
c.Set("context", &config.UserContext{
|
||||||
|
Username: "totpuser",
|
||||||
|
Name: "totpuser",
|
||||||
|
Email: "totpuser@example.com",
|
||||||
|
IsLoggedIn: false,
|
||||||
|
OAuth: false,
|
||||||
|
Provider: "username",
|
||||||
|
TotpPending: true,
|
||||||
|
OAuthGroups: "",
|
||||||
|
TotpEnabled: true,
|
||||||
|
})
|
||||||
|
c.Next()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test
|
||||||
|
code, err := totp.GenerateCode(totpSecret, time.Now())
|
||||||
|
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
totpReq := controller.TotpRequest{
|
||||||
|
Code: code,
|
||||||
|
}
|
||||||
|
|
||||||
|
totpReqJson, err := json.Marshal(totpReq)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
req := httptest.NewRequest("POST", "/api/user/totp", strings.NewReader(string(totpReqJson)))
|
||||||
|
router.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
assert.Equal(t, 200, recorder.Code)
|
||||||
|
|
||||||
|
cookie := recorder.Result().Cookies()[0]
|
||||||
|
|
||||||
|
assert.Equal(t, "tinyauth-session", cookie.Name)
|
||||||
|
assert.Assert(t, cookie.Value != "")
|
||||||
|
|
||||||
|
// Test rate limiting
|
||||||
|
totpReq = controller.TotpRequest{
|
||||||
|
Code: "000000",
|
||||||
|
}
|
||||||
|
|
||||||
|
totpReqJson, err = json.Marshal(totpReq)
|
||||||
|
assert.NilError(t, err)
|
||||||
|
|
||||||
|
for range 5 {
|
||||||
|
recorder = httptest.NewRecorder()
|
||||||
|
req = httptest.NewRequest("POST", "/api/user/totp", strings.NewReader(string(totpReqJson)))
|
||||||
|
router.ServeHTTP(recorder, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(t, 429, recorder.Code)
|
||||||
|
|
||||||
|
// Test invalid code
|
||||||
|
router, recorder = setupUserController(t, &[]gin.HandlerFunc{
|
||||||
|
func(c *gin.Context) {
|
||||||
|
c.Set("context", &config.UserContext{
|
||||||
|
Username: "totpuser",
|
||||||
|
Name: "totpuser",
|
||||||
|
Email: "totpuser@example.com",
|
||||||
|
IsLoggedIn: false,
|
||||||
|
OAuth: false,
|
||||||
|
Provider: "username",
|
||||||
|
TotpPending: true,
|
||||||
|
OAuthGroups: "",
|
||||||
|
TotpEnabled: true,
|
||||||
|
})
|
||||||
|
c.Next()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
req = httptest.NewRequest("POST", "/api/user/totp", strings.NewReader(string(totpReqJson)))
|
||||||
|
router.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
assert.Equal(t, 401, recorder.Code)
|
||||||
|
|
||||||
|
// Test no totp pending
|
||||||
|
router, recorder = setupUserController(t, &[]gin.HandlerFunc{
|
||||||
|
func(c *gin.Context) {
|
||||||
|
c.Set("context", &config.UserContext{
|
||||||
|
Username: "totpuser",
|
||||||
|
Name: "totpuser",
|
||||||
|
Email: "totpuser@example.com",
|
||||||
|
IsLoggedIn: false,
|
||||||
|
OAuth: false,
|
||||||
|
Provider: "username",
|
||||||
|
TotpPending: false,
|
||||||
|
OAuthGroups: "",
|
||||||
|
TotpEnabled: false,
|
||||||
|
})
|
||||||
|
c.Next()
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
req = httptest.NewRequest("POST", "/api/user/totp", strings.NewReader(string(totpReqJson)))
|
||||||
|
router.ServeHTTP(recorder, req)
|
||||||
|
|
||||||
|
assert.Equal(t, 401, recorder.Code)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user