Files
geo/server/internal/shared/auth/middleware_test.go
T
root e045e00fbf
Frontend CI / Frontend (push) Successful in 3m8s
Backend CI / Backend (push) Successful in 14m48s
feat(auth,prompt-rule): add password change with session revocation and scope prompt rules by brand
Add self-service password change that re-hashes the credential and bumps a
per-user session version so all existing access/refresh tokens are rejected.
Session version is tracked in Redis with an in-memory fallback and enforced in
middleware and refresh.

Scope prompt rules and rule groups to a brand: new brand_id column (migrated to
a "未归属" fallback brand for existing rows), brand-filtered queries/indexes, and
brand-aware admin-web tabs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 18:09:53 +08:00

146 lines
3.9 KiB
Go

package auth
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
"time"
"github.com/alicebob/miniredis/v2"
"github.com/gin-gonic/gin"
goredis "github.com/redis/go-redis/v9"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func init() {
gin.SetMode(gin.TestMode)
}
func setupTestMiddleware(t *testing.T) (*Manager, *SessionStore, *miniredis.Miniredis) {
t.Helper()
mr := miniredis.RunT(t)
rdb := goredis.NewClient(&goredis.Options{Addr: mr.Addr()})
mgr := NewManager("test-middleware-secret", 15*time.Minute, 7*24*time.Hour)
sessions := NewSessionStore(rdb)
return mgr, sessions, mr
}
func TestAuthMiddleware_ValidToken(t *testing.T) {
mgr, sessions, _ := setupTestMiddleware(t)
pair, err := mgr.Issue(1, 10, 100, "editor")
require.NoError(t, err)
r := gin.New()
r.Use(Middleware(mgr, sessions))
var gotActor Actor
r.GET("/test", func(c *gin.Context) {
a, ok := ActorFromCtx(c.Request.Context())
assert.True(t, ok)
gotActor = a
c.Status(http.StatusOK)
})
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("Authorization", "Bearer "+pair.AccessToken)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusOK, w.Code)
assert.Equal(t, int64(1), gotActor.UserID)
assert.Equal(t, int64(10), gotActor.TenantID)
assert.Equal(t, int64(100), gotActor.PrimaryWorkspaceID)
assert.Equal(t, "editor", gotActor.Role)
}
func TestAuthMiddleware_MissingHeader(t *testing.T) {
mgr, sessions, _ := setupTestMiddleware(t)
r := gin.New()
r.Use(Middleware(mgr, sessions))
r.GET("/test", func(c *gin.Context) { c.Status(http.StatusOK) })
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/test", nil)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusUnauthorized, w.Code)
}
func TestAuthMiddleware_InvalidToken(t *testing.T) {
mgr, sessions, _ := setupTestMiddleware(t)
r := gin.New()
r.Use(Middleware(mgr, sessions))
r.GET("/test", func(c *gin.Context) { c.Status(http.StatusOK) })
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("Authorization", "Bearer bad-token-value")
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusUnauthorized, w.Code)
}
func TestAuthMiddleware_RefreshTokenRejected(t *testing.T) {
mgr, sessions, _ := setupTestMiddleware(t)
pair, err := mgr.Issue(1, 10, 100, "editor")
require.NoError(t, err)
r := gin.New()
r.Use(Middleware(mgr, sessions))
r.GET("/test", func(c *gin.Context) { c.Status(http.StatusOK) })
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("Authorization", "Bearer "+pair.RefreshToken)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusUnauthorized, w.Code)
}
func TestAuthMiddleware_BlacklistedToken(t *testing.T) {
mgr, sessions, mr := setupTestMiddleware(t)
pair, err := mgr.Issue(1, 10, 100, "editor")
require.NoError(t, err)
// Blacklist the access token's JTI
require.NoError(t, mr.Set(fmt.Sprintf("blacklist:%s", pair.AccessJTI), "1"))
r := gin.New()
r.Use(Middleware(mgr, sessions))
r.GET("/test", func(c *gin.Context) { c.Status(http.StatusOK) })
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("Authorization", "Bearer "+pair.AccessToken)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusUnauthorized, w.Code)
}
func TestAuthMiddleware_StaleSessionVersionRejected(t *testing.T) {
mgr, sessions, _ := setupTestMiddleware(t)
pair, err := mgr.IssueWithSessionVersion(1, 10, 100, "editor", 0)
require.NoError(t, err)
_, err = sessions.BumpSessionVersion(t.Context(), 1)
require.NoError(t, err)
r := gin.New()
r.Use(Middleware(mgr, sessions))
r.GET("/test", func(c *gin.Context) { c.Status(http.StatusOK) })
w := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/test", nil)
req.Header.Set("Authorization", "Bearer "+pair.AccessToken)
r.ServeHTTP(w, req)
assert.Equal(t, http.StatusUnauthorized, w.Code)
}