Skip to content

Commit f5a0d4a

Browse files
committed
update tests
1 parent f7aa368 commit f5a0d4a

2 files changed

Lines changed: 241 additions & 306 deletions

File tree

internal/controller/user_controller_test.go

Lines changed: 103 additions & 162 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"encoding/json"
55
"net/http/httptest"
66
"path"
7-
"slices"
87
"strings"
98
"testing"
109
"time"
@@ -36,6 +35,23 @@ func TestUserController(t *testing.T) {
3635
Password: "$2a$10$ZwVYQH07JX2zq7Fjkt3gU.BjwvvwPeli4OqOno04RQIv0P7usBrXa", // password
3736
TotpSecret: "JPIEBDKJH6UGWJMX66RR3S55UFP2SGKK",
3837
},
38+
{
39+
Username: "attruser",
40+
Password: "$2a$10$ZwVYQH07JX2zq7Fjkt3gU.BjwvvwPeli4OqOno04RQIv0P7usBrXa", // password
41+
Attributes: config.UserAttributes{
42+
Name: "Alice Smith",
43+
Email: "alice@example.com",
44+
},
45+
},
46+
{
47+
Username: "attrtotpuser",
48+
Password: "$2a$10$ZwVYQH07JX2zq7Fjkt3gU.BjwvvwPeli4OqOno04RQIv0P7usBrXa", // password
49+
TotpSecret: "JPIEBDKJH6UGWJMX66RR3S55UFP2SGKK",
50+
Attributes: config.UserAttributes{
51+
Name: "Bob Jones",
52+
Email: "bob@example.com",
53+
},
54+
},
3955
},
4056
SessionExpiry: 10, // 10 seconds, useful for testing
4157
CookieDomain: "example.com",
@@ -273,6 +289,64 @@ func TestUserController(t *testing.T) {
273289
assert.Contains(t, recorder.Body.String(), "Too many failed TOTP attempts.")
274290
},
275291
},
292+
{
293+
description: "Login uses name and email from user attributes",
294+
middlewares: []gin.HandlerFunc{},
295+
run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
296+
loginReq := controller.LoginRequest{Username: "attruser", Password: "password"}
297+
body, err := json.Marshal(loginReq)
298+
require.NoError(t, err)
299+
300+
req := httptest.NewRequest("POST", "/api/user/login", strings.NewReader(string(body)))
301+
req.Header.Set("Content-Type", "application/json")
302+
router.ServeHTTP(recorder, req)
303+
304+
require.Equal(t, 200, recorder.Code)
305+
cookies := recorder.Result().Cookies()
306+
require.Len(t, cookies, 1)
307+
assert.Equal(t, "tinyauth-session", cookies[0].Name)
308+
},
309+
},
310+
{
311+
description: "Login with TOTP uses name and email from user attributes in pending session",
312+
middlewares: []gin.HandlerFunc{},
313+
run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
314+
loginReq := controller.LoginRequest{Username: "attrtotpuser", Password: "password"}
315+
body, err := json.Marshal(loginReq)
316+
require.NoError(t, err)
317+
318+
req := httptest.NewRequest("POST", "/api/user/login", strings.NewReader(string(body)))
319+
req.Header.Set("Content-Type", "application/json")
320+
router.ServeHTTP(recorder, req)
321+
322+
require.Equal(t, 200, recorder.Code)
323+
var res map[string]any
324+
require.NoError(t, json.Unmarshal(recorder.Body.Bytes(), &res))
325+
assert.Equal(t, true, res["totpPending"])
326+
require.Len(t, recorder.Result().Cookies(), 1)
327+
},
328+
},
329+
{
330+
description: "TOTP completion uses name and email from user attributes",
331+
middlewares: []gin.HandlerFunc{},
332+
run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
333+
code, err := totp.GenerateCode("JPIEBDKJH6UGWJMX66RR3S55UFP2SGKK", time.Now())
334+
require.NoError(t, err)
335+
336+
totpReq := controller.TotpRequest{Code: code}
337+
body, err := json.Marshal(totpReq)
338+
require.NoError(t, err)
339+
340+
req := httptest.NewRequest("POST", "/api/user/totp", strings.NewReader(string(body)))
341+
req.Header.Set("Content-Type", "application/json")
342+
router.ServeHTTP(recorder, req)
343+
344+
require.Equal(t, 200, recorder.Code)
345+
cookies := recorder.Result().Cookies()
346+
require.Len(t, cookies, 1)
347+
assert.Equal(t, "tinyauth-session", cookies[0].Name)
348+
},
349+
},
276350
}
277351

278352
oauthBrokerCfgs := make(map[string]config.OAuthServiceConfig)
@@ -305,9 +379,31 @@ func TestUserController(t *testing.T) {
305379
authService.ClearRateLimitsTestingOnly()
306380
}
307381

308-
setTotpMiddlewareOverrides := []string{
309-
"Should be able to login with totp",
310-
"Totp should rate limit on multiple invalid attempts",
382+
setTotpMiddlewareOverrides := map[string]config.UserContext{
383+
"Should be able to login with totp": {
384+
Username: "totpuser",
385+
Name: "Totpuser",
386+
Email: "totpuser@example.com",
387+
Provider: "local",
388+
TotpPending: true,
389+
TotpEnabled: true,
390+
},
391+
"Totp should rate limit on multiple invalid attempts": {
392+
Username: "totpuser",
393+
Name: "Totpuser",
394+
Email: "totpuser@example.com",
395+
Provider: "local",
396+
TotpPending: true,
397+
TotpEnabled: true,
398+
},
399+
"TOTP completion uses name and email from user attributes": {
400+
Username: "attrtotpuser",
401+
Name: "Bob Jones",
402+
Email: "bob@example.com",
403+
Provider: "local",
404+
TotpPending: true,
405+
TotpEnabled: true,
406+
},
311407
}
312408

313409
for _, test := range tests {
@@ -321,18 +417,10 @@ func TestUserController(t *testing.T) {
321417

322418
// Gin is stupid and doesn't allow setting a middleware after the groups
323419
// so we need to do some stupid overrides here
324-
if slices.Contains(setTotpMiddlewareOverrides, test.description) {
325-
// Assuming the cookie is set, it should be picked up by the
326-
// context middleware
420+
if ctx, ok := setTotpMiddlewareOverrides[test.description]; ok {
421+
ctx := ctx
327422
router.Use(func(c *gin.Context) {
328-
c.Set("context", &config.UserContext{
329-
Username: "totpuser",
330-
Name: "Totpuser",
331-
Email: "totpuser@example.com",
332-
Provider: "local",
333-
TotpPending: true,
334-
TotpEnabled: true,
335-
})
423+
c.Set("context", &ctx)
336424
})
337425
}
338426

@@ -353,150 +441,3 @@ func TestUserController(t *testing.T) {
353441
require.NoError(t, err)
354442
})
355443
}
356-
357-
func TestUserControllerAttributes(t *testing.T) {
358-
tlog.NewTestLogger().Init()
359-
tempDir := t.TempDir()
360-
361-
authServiceCfg := service.AuthServiceConfig{
362-
Users: []config.User{
363-
{
364-
Username: "attruser",
365-
Password: "$2a$10$ZwVYQH07JX2zq7Fjkt3gU.BjwvvwPeli4OqOno04RQIv0P7usBrXa", // password
366-
Attributes: config.UserAttributes{
367-
Name: "Alice Smith",
368-
Email: "alice@example.com",
369-
},
370-
},
371-
{
372-
Username: "attrtotpuser",
373-
Password: "$2a$10$ZwVYQH07JX2zq7Fjkt3gU.BjwvvwPeli4OqOno04RQIv0P7usBrXa", // password
374-
TotpSecret: "JPIEBDKJH6UGWJMX66RR3S55UFP2SGKK",
375-
Attributes: config.UserAttributes{
376-
Name: "Bob Jones",
377-
Email: "bob@example.com",
378-
},
379-
},
380-
},
381-
SessionExpiry: 10,
382-
CookieDomain: "example.com",
383-
LoginTimeout: 10,
384-
LoginMaxRetries: 3,
385-
SessionCookieName: "tinyauth-session",
386-
}
387-
388-
userControllerCfg := controller.UserControllerConfig{
389-
CookieDomain: "example.com",
390-
}
391-
392-
app := bootstrap.NewBootstrapApp(config.Config{})
393-
db, err := app.SetupDatabase(path.Join(tempDir, "tinyauth_attrs.db"))
394-
require.NoError(t, err)
395-
396-
queries := repository.New(db)
397-
398-
docker := service.NewDockerService()
399-
err = docker.Init()
400-
require.NoError(t, err)
401-
402-
ldap := service.NewLdapService(service.LdapServiceConfig{})
403-
err = ldap.Init()
404-
require.NoError(t, err)
405-
406-
broker := service.NewOAuthBrokerService(make(map[string]config.OAuthServiceConfig))
407-
err = broker.Init()
408-
require.NoError(t, err)
409-
410-
authService := service.NewAuthService(authServiceCfg, docker, ldap, queries, broker)
411-
err = authService.Init()
412-
require.NoError(t, err)
413-
414-
makeRouter := func(extraMiddlewares ...gin.HandlerFunc) *gin.Engine {
415-
router := gin.Default()
416-
for _, m := range extraMiddlewares {
417-
router.Use(m)
418-
}
419-
gin.SetMode(gin.TestMode)
420-
group := router.Group("/api")
421-
ctrl := controller.NewUserController(userControllerCfg, group, authService)
422-
ctrl.SetupRoutes()
423-
return router
424-
}
425-
426-
t.Run("Login uses name and email from user attributes", func(t *testing.T) {
427-
authService.ClearRateLimitsTestingOnly()
428-
router := makeRouter()
429-
430-
loginReq := controller.LoginRequest{Username: "attruser", Password: "password"}
431-
body, err := json.Marshal(loginReq)
432-
require.NoError(t, err)
433-
434-
req := httptest.NewRequest("POST", "/api/user/login", strings.NewReader(string(body)))
435-
req.Header.Set("Content-Type", "application/json")
436-
rec := httptest.NewRecorder()
437-
router.ServeHTTP(rec, req)
438-
439-
require.Equal(t, 200, rec.Code)
440-
cookies := rec.Result().Cookies()
441-
require.Len(t, cookies, 1)
442-
assert.Equal(t, "tinyauth-session", cookies[0].Name)
443-
})
444-
445-
t.Run("Login with TOTP uses name and email from user attributes in pending session", func(t *testing.T) {
446-
authService.ClearRateLimitsTestingOnly()
447-
router := makeRouter()
448-
449-
loginReq := controller.LoginRequest{Username: "attrtotpuser", Password: "password"}
450-
body, err := json.Marshal(loginReq)
451-
require.NoError(t, err)
452-
453-
req := httptest.NewRequest("POST", "/api/user/login", strings.NewReader(string(body)))
454-
req.Header.Set("Content-Type", "application/json")
455-
rec := httptest.NewRecorder()
456-
router.ServeHTTP(rec, req)
457-
458-
require.Equal(t, 200, rec.Code)
459-
var res map[string]any
460-
require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &res))
461-
assert.Equal(t, true, res["totpPending"])
462-
require.Len(t, rec.Result().Cookies(), 1)
463-
})
464-
465-
t.Run("TOTP completion uses name and email from user attributes", func(t *testing.T) {
466-
authService.ClearRateLimitsTestingOnly()
467-
468-
// First: login to get TOTP-pending session
469-
router := makeRouter(func(c *gin.Context) {
470-
c.Set("context", &config.UserContext{
471-
Username: "attrtotpuser",
472-
Name: "Bob Jones",
473-
Email: "bob@example.com",
474-
Provider: "local",
475-
TotpPending: true,
476-
TotpEnabled: true,
477-
})
478-
})
479-
480-
code, err := totp.GenerateCode("JPIEBDKJH6UGWJMX66RR3S55UFP2SGKK", time.Now())
481-
require.NoError(t, err)
482-
483-
totpReq := controller.TotpRequest{Code: code}
484-
body, err := json.Marshal(totpReq)
485-
require.NoError(t, err)
486-
487-
req := httptest.NewRequest("POST", "/api/user/totp", strings.NewReader(string(body)))
488-
req.Header.Set("Content-Type", "application/json")
489-
rec := httptest.NewRecorder()
490-
router.ServeHTTP(rec, req)
491-
492-
require.Equal(t, 200, rec.Code)
493-
cookies := rec.Result().Cookies()
494-
require.Len(t, cookies, 1)
495-
assert.Equal(t, "tinyauth-session", cookies[0].Name)
496-
})
497-
498-
t.Cleanup(func() {
499-
err = db.Close()
500-
require.NoError(t, err)
501-
})
502-
}

0 commit comments

Comments
 (0)