Files
full/all/internal/server/authorization_test.go

101 lines
3.7 KiB
Go

package server
import (
"context"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/golang-jwt/jwt/v5"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/metadata"
"google.golang.org/grpc/status"
)
const testAuthorizationKey = "0123456789abcdef0123456789abcdef"
func TestHTTPAuthorization(t *testing.T) {
auth, err := newAuthorization(testAuthorizationKey, 3600, []string{"/passport.Login/Pwd", "/rest/fts/ping"})
if err != nil {
t.Fatal(err)
}
next := http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { w.WriteHeader(http.StatusNoContent) })
handler := auth.httpMiddleware(next)
tests := []struct {
name string
path string
token string
want int
}{
{name: "grpc gateway anonymous", path: "/passport.Login/Pwd", want: http.StatusNoContent},
{name: "dynamic rpc anonymous", path: "/rpc/passport/Login/Pwd", want: http.StatusNoContent},
{name: "rest anonymous", path: "/rest/fts/ping", want: http.StatusNoContent},
{name: "missing token", path: "/passport.Account/Get", want: http.StatusOK},
{name: "valid raw token", path: "/passport.Account/Get", token: signedToken(t, time.Now(), time.Now().Add(time.Hour)), want: http.StatusNoContent},
{name: "bearer rejected", path: "/passport.Account/Get", token: "Bearer " + signedToken(t, time.Now(), time.Now().Add(time.Hour)), want: http.StatusOK},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
request := httptest.NewRequest(http.MethodPost, test.path, nil)
if test.token != "" {
request.Header.Set("Authorization", test.token)
}
response := httptest.NewRecorder()
handler.ServeHTTP(response, request)
if response.Code != test.want {
t.Fatalf("status=%d body=%s", response.Code, response.Body.String())
}
if test.want == http.StatusOK && !strings.Contains(response.Body.String(), `"code":16`) {
t.Fatalf("unexpected authorization error: %s", response.Body.String())
}
})
}
}
func TestAuthorizationRejectsTokenOlderThanConfiguredLifetime(t *testing.T) {
auth, err := newAuthorization(testAuthorizationKey, 60, nil)
if err != nil {
t.Fatal(err)
}
if err := auth.validate(signedToken(t, time.Now().Add(-2*time.Minute), time.Now().Add(time.Hour))); err == nil {
t.Fatal("expected token older than configured lifetime to be rejected")
}
}
func TestGRPCAuthorization(t *testing.T) {
auth, err := newAuthorization(testAuthorizationKey, 3600, []string{"/passport.Login/Pwd"})
if err != nil {
t.Fatal(err)
}
handler := func(context.Context, any) (any, error) { return "ok", nil }
if _, err := auth.unaryInterceptor(context.Background(), nil, &grpc.UnaryServerInfo{FullMethod: "/passport.Login/Pwd"}, handler); err != nil {
t.Fatalf("anonymous method failed: %v", err)
}
if _, err := auth.unaryInterceptor(context.Background(), nil, &grpc.UnaryServerInfo{FullMethod: "/passport.Account/Get"}, handler); status.Code(err) != codes.Unauthenticated {
t.Fatalf("expected unauthenticated, got %v", err)
}
ctx := metadata.NewIncomingContext(context.Background(), metadata.Pairs("authorization", signedToken(t, time.Now(), time.Now().Add(time.Hour))))
if _, err := auth.unaryInterceptor(ctx, nil, &grpc.UnaryServerInfo{FullMethod: "/passport.Account/Get"}, handler); err != nil {
t.Fatalf("valid token failed: %v", err)
}
}
func signedToken(t *testing.T, issuedAt, expiresAt time.Time) string {
t.Helper()
claims := jwt.RegisteredClaims{
IssuedAt: jwt.NewNumericDate(issuedAt),
NotBefore: jwt.NewNumericDate(issuedAt),
ExpiresAt: jwt.NewNumericDate(expiresAt),
}
value, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString([]byte(testAuthorizationKey))
if err != nil {
t.Fatal(err)
}
return value
}