73 lines
2.6 KiB
Go
73 lines
2.6 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"net/http/httptest"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/longpeng/configcenter/internal/domain"
|
|
memory_store "github.com/longpeng/configcenter/internal/store/memory"
|
|
)
|
|
|
|
func TestLoginTokenExpiryAndApplicationRoles(t *testing.T) {
|
|
ctx := context.Background()
|
|
repository := memory_store.New(false)
|
|
manager, err := New(repository, true, "0123456789abcdef0123456789abcdef", time.Hour)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
clock := time.Date(2026, 8, 30, 2, 0, 0, 0, time.UTC)
|
|
manager.now = func() time.Time { return clock }
|
|
if err := manager.Bootstrap(ctx, "root", "a-strong-password", "Root"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
token, principal, err := manager.Login(ctx, "root", "a-strong-password")
|
|
if err != nil || !principal.IsAdmin {
|
|
t.Fatalf("bootstrap login failed: principal=%#v err=%v", principal, err)
|
|
}
|
|
request := httptest.NewRequestWithContext(ctx, "GET", "/v1/applications", nil)
|
|
request.Header.Set("Authorization", "Bearer "+token)
|
|
parsed, err := manager.AuthenticateRequest(request)
|
|
if err != nil || parsed.Username != "root" {
|
|
t.Fatalf("token validation failed: principal=%#v err=%v", parsed, err)
|
|
}
|
|
|
|
app, err := repository.CreateApplication(ctx, domain.Application{Code: "orders", Name: "Orders"})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
viewer, err := manager.CreateUser(ctx, domain.User{Username: "Reader", DisplayName: "Reader"}, "another-strong-password")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if viewer.Username != "reader" {
|
|
t.Fatalf("username was not normalized: %q", viewer.Username)
|
|
}
|
|
if err := repository.SetUserAppRole(ctx, domain.UserAppRole{UserID: viewer.ID, AppID: app.ID, Role: RoleViewer}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
viewerToken, viewerPrincipal, err := manager.Login(ctx, "READER", "another-strong-password")
|
|
if err != nil || viewerToken == "" {
|
|
t.Fatal(err)
|
|
}
|
|
viewerContext := WithPrincipal(ctx, viewerPrincipal)
|
|
if err := manager.RequireAppRole(viewerContext, app.ID, RoleViewer); err != nil {
|
|
t.Fatalf("viewer should read application: %v", err)
|
|
}
|
|
if err := manager.RequireAppRole(viewerContext, app.ID, RoleAppOwner); !errors.Is(err, ErrForbidden) {
|
|
t.Fatalf("viewer must not edit application: %v", err)
|
|
}
|
|
|
|
clock = clock.Add(2 * time.Hour)
|
|
if _, err := manager.AuthenticateRequest(request); !errors.Is(err, ErrUnauthorized) {
|
|
t.Fatalf("expired token must be rejected: %v", err)
|
|
}
|
|
tampered := httptest.NewRequestWithContext(ctx, "GET", "/", nil)
|
|
tampered.Header.Set("Authorization", "Bearer "+token+"x")
|
|
if _, err := manager.AuthenticateRequest(tampered); !errors.Is(err, ErrUnauthorized) {
|
|
t.Fatalf("tampered token must be rejected: %v", err)
|
|
}
|
|
}
|