chore(auth): #331 unify existing tests #341

Merged
tim merged 1 commits from 331-unify-existing-tests into prod 2024-12-22 20:32:33 +00:00
+146 -137
View File
@@ -112,184 +112,193 @@ func TestIntegrationSecurityHeader(t *testing.T) {
func TestIntegrationAuth(t *testing.T) { func TestIntegrationAuth(t *testing.T) {
t.Parallel() t.Parallel()
t.Run("should return secure cookie on signin with generated csrf-token and session-id", func(t *testing.T) { t.Run("SignIn", func(t *testing.T) {
t.Parallel() t.Run("should return secure cookie with NEW session-id", func(t *testing.T) {
t.Parallel()
db, basePath, ctx := setupIntegrationTest(t) db, basePath, ctx := setupIntegrationTest(t)
pass := service.GetHashPassword("password", []byte("salt")) pass := service.GetHashPassword("password", []byte("salt"))
_, err := db.Exec(` _, err := db.Exec(`
INSERT INTO user (user_id, email, email_verified, is_admin, password, salt, created_at) INSERT INTO user (user_id, email, email_verified, is_admin, password, salt, created_at)
VALUES (?, "mail@mail.de", FALSE, FALSE, ?, ?, datetime())`, uuid.New(), pass, []byte("salt")) VALUES (?, "mail@mail.de", FALSE, FALSE, ?, ?, datetime())`, uuid.New(), pass, []byte("salt"))
assert.Nil(t, err) assert.Nil(t, err)
req, err := http.NewRequestWithContext(ctx, "GET", basePath+"/auth/signin", nil) req, err := http.NewRequestWithContext(ctx, "GET", basePath+"/auth/signin", nil)
assert.Nil(t, err) assert.Nil(t, err)
resp, err := httpClient.Do(req) resp, err := httpClient.Do(req)
assert.Nil(t, err) assert.Nil(t, err)
html, err := html.Parse(resp.Body) html, err := html.Parse(resp.Body)
assert.Nil(t, err) assert.Nil(t, err)
csrfToken := findCsrfToken(html) anonymousCsrfToken := findCsrfToken(html)
assert.NotEqual(t, "", csrfToken) assert.NotEqual(t, "", anonymousCsrfToken)
anonymousSession := findCookie(resp, "id") anonymousSession := findCookie(resp, "id")
assert.NotNil(t, anonymousSession) assert.NotNil(t, anonymousSession)
formData := url.Values{ formData := url.Values{
"email": {"mail@mail.de"}, "email": {"mail@mail.de"},
"password": {"password"}, "password": {"password"},
"csrf-token": {csrfToken}, "csrf-token": {anonymousCsrfToken},
} }
req, err = http.NewRequestWithContext(ctx, "POST", basePath+"/api/auth/signin", strings.NewReader(formData.Encode())) req, err = http.NewRequestWithContext(ctx, "POST", basePath+"/api/auth/signin", strings.NewReader(formData.Encode()))
assert.Nil(t, err) assert.Nil(t, err)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Cookie", "id="+anonymousSession.Value) req.Header.Set("Cookie", "id="+anonymousSession.Value)
resp, err = httpClient.Do(req) resp, err = httpClient.Do(req)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, http.StatusSeeOther, resp.StatusCode) assert.Equal(t, http.StatusSeeOther, resp.StatusCode)
cookie := findCookie(resp, "id") cookie := findCookie(resp, "id")
assert.NotNil(t, cookie) assert.NotNil(t, cookie)
assert.Equal(t, http.SameSiteStrictMode, cookie.SameSite, "Cookie is not secure") assert.Equal(t, http.SameSiteStrictMode, cookie.SameSite, "Cookie is not secure")
assert.True(t, cookie.HttpOnly, "Cookie is not secure") assert.True(t, cookie.HttpOnly, "Cookie is not secure")
assert.True(t, cookie.Secure, "Cookie is not secure") assert.True(t, cookie.Secure, "Cookie is not secure")
assert.NotEqual(t, anonymousSession.Value, cookie.Value, "Session ID did not change")
})
}) })
t.Run("should change password and invalidate other sessions from user", func(t *testing.T) { t.Run("ChangePassword", func(t *testing.T) {
t.Parallel() t.Run("should change password and invalidate all other user sessions", func(t *testing.T) {
t.Parallel()
db, basePath, ctx := setupIntegrationTest(t) db, basePath, ctx := setupIntegrationTest(t)
userId := uuid.New() userId := uuid.New()
userIdOther := uuid.New() userIdOther := uuid.New()
pass := service.GetHashPassword("password", []byte("salt")) pass := service.GetHashPassword("password", []byte("salt"))
_, err := db.Exec(` _, err := db.Exec(`
INSERT INTO user (user_id, email, email_verified, is_admin, password, salt, created_at) INSERT INTO user (user_id, email, email_verified, is_admin, password, salt, created_at)
VALUES (?, "mail@mail.de", FALSE, FALSE, ?, ?, datetime())`, userId, pass, []byte("salt")) VALUES (?, "mail@mail.de", FALSE, FALSE, ?, ?, datetime())`, userId, pass, []byte("salt"))
sessionId := "session-id" sessionId := "session-id"
assert.Nil(t, err) assert.Nil(t, err)
_, err = db.Exec(` _, err = db.Exec(`
INSERT INTO session (session_id, user_id, created_at, expires_at) INSERT INTO session (session_id, user_id, created_at, expires_at)
VALUES (?, ?, datetime(), datetime("now", "+1 day"))`, sessionId, userId) VALUES (?, ?, datetime(), datetime("now", "+1 day"))`, sessionId, userId)
assert.Nil(t, err) assert.Nil(t, err)
_, err = db.Exec(` _, err = db.Exec(`
INSERT INTO session (session_id, user_id, created_at, expires_at) INSERT INTO session (session_id, user_id, created_at, expires_at)
VALUES ("second", ?, datetime(), datetime("now", "+1 day"))`, userId) VALUES ("second", ?, datetime(), datetime("now", "+1 day"))`, userId)
assert.Nil(t, err) assert.Nil(t, err)
_, err = db.Exec(` _, err = db.Exec(`
INSERT INTO session (session_id, user_id, created_at, expires_at) INSERT INTO session (session_id, user_id, created_at, expires_at)
VALUES ("other", ?, datetime(), datetime("now", "+1 day"))`, userIdOther) VALUES ("other", ?, datetime(), datetime("now", "+1 day"))`, userIdOther)
assert.Nil(t, err)
req, err := http.NewRequestWithContext(ctx, "GET", basePath+"/auth/change-password", nil)
assert.Nil(t, err)
req.Header.Set("Cookie", "id="+sessionId)
resp, err := httpClient.Do(req)
assert.Nil(t, err)
html, err := html.Parse(resp.Body)
assert.Nil(t, err)
csrfToken := findCsrfToken(html)
assert.NotEqual(t, "", csrfToken)
formData := url.Values{
"current-password": {"password"},
"new-password": {"MyNewSecurePassword1!"},
"csrf-token": {csrfToken},
}
req, err = http.NewRequestWithContext(ctx, "POST", basePath+"/api/auth/change-password", strings.NewReader(formData.Encode()))
assert.Nil(t, err)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Cookie", "id="+sessionId)
req.Header.Set("HX-Request", "true")
resp, err = httpClient.Do(req)
assert.Nil(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
var sessionIds []string
sessions, err := db.Query(`SELECT session_id FROM session WHERE NOT user_id = ? ORDER BY session_id`, uuid.Nil)
assert.Nil(t, err)
for sessions.Next() {
var sessionId string
err = sessions.Scan(&sessionId)
assert.Nil(t, err) assert.Nil(t, err)
sessionIds = append(sessionIds, sessionId)
}
assert.Equal(t, 2, len(sessionIds)) req, err := http.NewRequestWithContext(ctx, "GET", basePath+"/auth/change-password", nil)
assert.Equal(t, "other", sessionIds[0]) assert.Nil(t, err)
assert.Equal(t, "session-id", sessionIds[1]) req.Header.Set("Cookie", "id="+sessionId)
resp, err := httpClient.Do(req)
assert.Nil(t, err)
html, err := html.Parse(resp.Body)
assert.Nil(t, err)
csrfToken := findCsrfToken(html)
assert.NotEqual(t, "", csrfToken)
formData := url.Values{
"current-password": {"password"},
"new-password": {"MyNewSecurePassword1!"},
"csrf-token": {csrfToken},
}
req, err = http.NewRequestWithContext(ctx, "POST", basePath+"/api/auth/change-password", strings.NewReader(formData.Encode()))
assert.Nil(t, err)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Cookie", "id="+sessionId)
req.Header.Set("HX-Request", "true")
resp, err = httpClient.Do(req)
assert.Nil(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
var sessionIds []string
sessions, err := db.Query(`SELECT session_id FROM session WHERE NOT user_id = ? ORDER BY session_id`, uuid.Nil)
assert.Nil(t, err)
for sessions.Next() {
var sessionId string
err = sessions.Scan(&sessionId)
assert.Nil(t, err)
sessionIds = append(sessionIds, sessionId)
}
assert.Equal(t, 2, len(sessionIds))
assert.Equal(t, "other", sessionIds[0])
assert.Equal(t, "session-id", sessionIds[1])
})
}) })
t.Run("should forget password and invalidate all user sessions", func(t *testing.T) {
t.Parallel()
d, basePath, ctx := setupIntegrationTest(t) t.Run("ForgotPassword", func(t *testing.T) {
userId := uuid.New() t.Run("should change password and invalidate ALL sessions", func(t *testing.T) {
t.Parallel()
pass := service.GetHashPassword("password", []byte("salt")) d, basePath, ctx := setupIntegrationTest(t)
_, err := d.Exec(` userId := uuid.New()
pass := service.GetHashPassword("password", []byte("salt"))
_, err := d.Exec(`
INSERT INTO user (user_id, email, email_verified, is_admin, password, salt, created_at) INSERT INTO user (user_id, email, email_verified, is_admin, password, salt, created_at)
VALUES (?, "mail@mail.de", FALSE, FALSE, ?, ?, datetime())`, userId, pass, []byte("salt")) VALUES (?, "mail@mail.de", FALSE, FALSE, ?, ?, datetime())`, userId, pass, []byte("salt"))
assert.Nil(t, err) assert.Nil(t, err)
_, err = d.Exec(` _, err = d.Exec(`
INSERT INTO session (session_id, user_id, created_at, expires_at) INSERT INTO session (session_id, user_id, created_at, expires_at)
VALUES ("session-id", ?, datetime(), datetime("now", "+1 day"))`, userId) VALUES ("session-id", ?, datetime(), datetime("now", "+1 day"))`, userId)
assert.Nil(t, err) assert.Nil(t, err)
req, err := http.NewRequestWithContext(ctx, "GET", basePath+"/auth/forgot-password", nil) req, err := http.NewRequestWithContext(ctx, "GET", basePath+"/auth/forgot-password", nil)
assert.Nil(t, err) assert.Nil(t, err)
resp, err := httpClient.Do(req) resp, err := httpClient.Do(req)
assert.Nil(t, err) assert.Nil(t, err)
sessionId := findCookie(resp, "id").Value sessionId := findCookie(resp, "id").Value
html, err := html.Parse(resp.Body) html, err := html.Parse(resp.Body)
assert.Nil(t, err) assert.Nil(t, err)
csrfToken := findCsrfToken(html) csrfToken := findCsrfToken(html)
assert.NotEqual(t, "", csrfToken) assert.NotEqual(t, "", csrfToken)
formData := url.Values{ formData := url.Values{
"email": {"mail@mail.de"}, "email": {"mail@mail.de"},
"csrf-token": {csrfToken}, "csrf-token": {csrfToken},
} }
req, err = http.NewRequestWithContext(ctx, "POST", basePath+"/api/auth/forgot-password", strings.NewReader(formData.Encode())) req, err = http.NewRequestWithContext(ctx, "POST", basePath+"/api/auth/forgot-password", strings.NewReader(formData.Encode()))
assert.Nil(t, err) assert.Nil(t, err)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Cookie", "id="+sessionId) req.Header.Set("Cookie", "id="+sessionId)
req.Header.Set("HX-Request", "true") req.Header.Set("HX-Request", "true")
resp, err = httpClient.Do(req) resp, err = httpClient.Do(req)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
var token string var token string
err = d.QueryRow("SELECT token FROM token WHERE type = ?", types.TokenTypePasswordReset).Scan(&token) err = d.QueryRow("SELECT token FROM token WHERE type = ?", types.TokenTypePasswordReset).Scan(&token)
assert.Nil(t, err) assert.Nil(t, err)
formData = url.Values{ formData = url.Values{
"new-password": {"MyNewSecurePassword1!"}, "new-password": {"MyNewSecurePassword1!"},
"csrf-token": {csrfToken}, "csrf-token": {csrfToken},
} }
req, err = http.NewRequestWithContext(ctx, "POST", basePath+"/api/auth/forgot-password-actual", strings.NewReader(formData.Encode())) req, err = http.NewRequestWithContext(ctx, "POST", basePath+"/api/auth/forgot-password-actual", strings.NewReader(formData.Encode()))
assert.Nil(t, err) assert.Nil(t, err)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
req.Header.Set("Cookie", "id="+sessionId) req.Header.Set("Cookie", "id="+sessionId)
req.Header.Set("HX-Request", "true") req.Header.Set("HX-Request", "true")
req.Header.Set("HX-Current-URL", basePath+"/auth/change-password?token="+url.QueryEscape(token)) req.Header.Set("HX-Current-URL", basePath+"/auth/change-password?token="+url.QueryEscape(token))
resp, err = httpClient.Do(req) resp, err = httpClient.Do(req)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
sessions, err := d.Query("SELECT session_id FROM session WHERE user_id = ?", userId) sessions, err := d.Query("SELECT session_id FROM session WHERE user_id = ?", userId)
assert.Nil(t, err) assert.Nil(t, err)
assert.False(t, sessions.Next()) assert.False(t, sessions.Next())
})
}) })
} }