修复未绑定邮箱用户登录会话失效并保留管理员权限边界
This commit is contained in:
parent
a795d59920
commit
03e7a14aa3
81
backend/internal/httpapi/auth_optional_email_test.go
Normal file
81
backend/internal/httpapi/auth_optional_email_test.go
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
package httpapi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.pcux.cn/xuans/Scert/backend/internal/database"
|
||||||
|
"git.pcux.cn/xuans/Scert/backend/internal/repository"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAuthSessionsSupportOptionalEmail(t *testing.T) {
|
||||||
|
for _, role := range []string{repository.UserRoleUser, repository.UserRoleAdmin} {
|
||||||
|
t.Run(role, func(t *testing.T) {
|
||||||
|
directory := t.TempDir()
|
||||||
|
cfg := readyTestConfig(directory)
|
||||||
|
cfg.Database.DSN = filepath.Join(directory, "optional-email.db")
|
||||||
|
db, err := database.Open(t.Context(), cfg.Database)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer db.Close()
|
||||||
|
if err := database.Migrate(t.Context(), db.DB, "sqlite"); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
users := repository.NewSQLUserRepository(db.DB, "sqlite")
|
||||||
|
user := repository.User{
|
||||||
|
ID: "optional-email", Username: "optional-email",
|
||||||
|
PasswordHash: httpUserPasswordHash(t, "Operator123"),
|
||||||
|
Role: role, Status: repository.UserStatusActive,
|
||||||
|
}
|
||||||
|
if err := users.CreateUser(t.Context(), user); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
server := New(Dependencies{Config: cfg, Repository: &stubDomainRepository{}, Users: users})
|
||||||
|
login := loginAuthTest(t, server, user.Username, "Operator123", false)
|
||||||
|
cookies := login.Result().Cookies()
|
||||||
|
if len(cookies) == 0 {
|
||||||
|
t.Fatal("missing session cookie")
|
||||||
|
}
|
||||||
|
loginAuthTest(t, server, user.Username, "Operator123", false)
|
||||||
|
response := authSessionRequest(server, cookies[0])
|
||||||
|
if response.Code != http.StatusOK {
|
||||||
|
t.Fatalf("optional-email session: status=%d body=%s", response.Code, response.Body.String())
|
||||||
|
}
|
||||||
|
var payload struct {
|
||||||
|
Authenticated bool `json:"authenticated"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
IsAdmin bool `json:"is_admin"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(response.Body.Bytes(), &payload); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if !payload.Authenticated || payload.Email != "" || payload.Role != role || payload.IsAdmin != (role == repository.UserRoleAdmin) {
|
||||||
|
t.Fatalf("unexpected session identity: %+v", payload)
|
||||||
|
}
|
||||||
|
request := httptest.NewRequest(http.MethodGet, "/api/v1/domains", nil)
|
||||||
|
request.AddCookie(cookies[0])
|
||||||
|
access := httptest.NewRecorder()
|
||||||
|
server.Handler().ServeHTTP(access, request)
|
||||||
|
expectedStatus := http.StatusForbidden
|
||||||
|
if role == repository.UserRoleAdmin {
|
||||||
|
expectedStatus = http.StatusOK
|
||||||
|
}
|
||||||
|
if access.Code != expectedStatus {
|
||||||
|
t.Fatalf("role boundary: status=%d want=%d", access.Code, expectedStatus)
|
||||||
|
}
|
||||||
|
user.Status = repository.UserStatusDisabled
|
||||||
|
if err := users.UpdateUser(t.Context(), user); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
disabled := authSessionRequest(server, cookies[0])
|
||||||
|
if disabled.Code != http.StatusUnauthorized {
|
||||||
|
t.Fatalf("disabled session: status=%d", disabled.Code)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,7 +11,8 @@ const authStateCapacity = 4096
|
|||||||
const authUserSessionCapacity = 16
|
const authUserSessionCapacity = 16
|
||||||
|
|
||||||
func (session authSession) complete() bool {
|
func (session authSession) complete() bool {
|
||||||
return strings.TrimSpace(session.UserID) != "" && strings.TrimSpace(session.Username) != "" && strings.TrimSpace(session.Email) != "" &&
|
return strings.TrimSpace(session.UserID) != "" && strings.TrimSpace(session.Username) != "" &&
|
||||||
|
(session.Role != repository.UserRoleSuperAdmin || strings.TrimSpace(session.Email) != "") &&
|
||||||
strings.TrimSpace(session.PasswordHash) != "" &&
|
strings.TrimSpace(session.PasswordHash) != "" &&
|
||||||
(session.Role == repository.UserRoleUser || session.Role == repository.UserRoleAdmin || session.Role == repository.UserRoleSuperAdmin)
|
(session.Role == repository.UserRoleUser || session.Role == repository.UserRoleAdmin || session.Role == repository.UserRoleSuperAdmin)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user