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
0 commit comments