222 lines
6.3 KiB
Go
222 lines
6.3 KiB
Go
package cognitoauth
|
|
|
|
import (
|
|
"log/slog"
|
|
"os"
|
|
"reflect"
|
|
"testing"
|
|
)
|
|
|
|
// TestMatchRoute verifies the matchRoute function correctly identifies when a request path
|
|
// matches a route pattern. It tests various scenarios including:
|
|
// - Exact path matching
|
|
// - Path parameter matching (e.g., /:id)
|
|
// - Multiple parameter matching
|
|
// - Wildcard matching
|
|
// - Path mismatches
|
|
// - Partial matching behavior
|
|
// - Special characters in paths
|
|
// - Edge cases like empty paths and root paths
|
|
func TestMatchRoute(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
requestPath string
|
|
routePattern string
|
|
expected bool
|
|
}{
|
|
{
|
|
name: "exact match",
|
|
requestPath: "/api/users",
|
|
routePattern: "/api/users",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "parameter match",
|
|
requestPath: "/api/users/123",
|
|
routePattern: "/api/users/:id",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "multiple parameters",
|
|
requestPath: "/api/users/123/orders/456",
|
|
routePattern: "/api/users/:userId/orders/:orderId",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "wildcard match",
|
|
requestPath: "/api/v1/docs/user-guide.pdf",
|
|
routePattern: "/api/v1/docs/*",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "no match",
|
|
requestPath: "/api/orders",
|
|
routePattern: "/api/users",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "partial match should fail",
|
|
requestPath: "/api/users/123",
|
|
routePattern: "/api/users",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "longer request path should fail",
|
|
requestPath: "/api/users/123/details",
|
|
routePattern: "/api/users/:id",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "regex characters in path",
|
|
requestPath: "/api/users/john.doe+test@example.com",
|
|
routePattern: "/api/users/:email",
|
|
expected: true,
|
|
},
|
|
{
|
|
name: "empty request path",
|
|
requestPath: "",
|
|
routePattern: "/api/users",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "empty route pattern",
|
|
requestPath: "/api/users",
|
|
routePattern: "",
|
|
expected: false,
|
|
},
|
|
{
|
|
name: "root path",
|
|
requestPath: "/",
|
|
routePattern: "/",
|
|
expected: true,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := matchRoute(tt.requestPath, tt.routePattern)
|
|
if result != tt.expected {
|
|
t.Errorf("matchRoute(%q, %q) = %v, want %v",
|
|
tt.requestPath, tt.routePattern, result, tt.expected)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestCheckPermissions verifies the checkPermissions function correctly enforces
|
|
// access control based on user groups and route permissions. It tests:
|
|
// - Admin access to various routes
|
|
// - Group-specific access permissions
|
|
// - Denying access when user lacks required group membership
|
|
// - Public route access without authentication
|
|
// - Multiple group membership scenarios
|
|
// - Routes with non-existent required groups
|
|
// - Path parameter matching with permissions
|
|
// - Default behavior for unmatched routes
|
|
func TestCheckPermissions(t *testing.T) {
|
|
// Setup logger
|
|
logHandler := slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{
|
|
Level: slog.LevelDebug,
|
|
})
|
|
logger := slog.New(logHandler)
|
|
|
|
// Setup route permissions
|
|
routePermissions := map[string][]string{
|
|
"/api/users": {"admin", "user-manager"},
|
|
"/api/orders": {"admin", "order-manager"},
|
|
"/api/products": {"admin", "product-manager"},
|
|
"/api/reports/*": {"admin", "analyst"},
|
|
"/api/users/:id": {"admin", "user-manager", "self-service"},
|
|
"/public/*": {}, // Public route - empty permissions means anyone can access
|
|
"/api/restricted": {"non-existent-group"}, // No one can access this
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
path string
|
|
userGroups []string
|
|
expectedAllowed bool
|
|
expectedGroups []string
|
|
}{
|
|
{
|
|
name: "admin can access user route",
|
|
path: "/api/users",
|
|
userGroups: []string{"admin"},
|
|
expectedAllowed: true,
|
|
expectedGroups: []string{"admin", "user-manager"},
|
|
},
|
|
{
|
|
name: "user-manager can access user route",
|
|
path: "/api/users",
|
|
userGroups: []string{"user-manager"},
|
|
expectedAllowed: true,
|
|
expectedGroups: []string{"admin", "user-manager"},
|
|
},
|
|
{
|
|
name: "order-manager cannot access user route",
|
|
path: "/api/users",
|
|
userGroups: []string{"order-manager"},
|
|
expectedAllowed: false,
|
|
expectedGroups: []string{"admin", "user-manager"},
|
|
},
|
|
{
|
|
name: "empty user groups cannot access protected route",
|
|
path: "/api/users",
|
|
userGroups: []string{},
|
|
expectedAllowed: false,
|
|
expectedGroups: []string{"admin", "user-manager"},
|
|
},
|
|
{
|
|
name: "anyone can access public route",
|
|
path: "/public/info",
|
|
userGroups: []string{},
|
|
expectedAllowed: true,
|
|
expectedGroups: []string{},
|
|
},
|
|
{
|
|
name: "user with multiple groups can access based on any matching group",
|
|
path: "/api/reports/sales",
|
|
userGroups: []string{"user-manager", "analyst"},
|
|
expectedAllowed: true,
|
|
expectedGroups: []string{"admin", "analyst"},
|
|
},
|
|
{
|
|
name: "no one can access route with non-existent group requirement",
|
|
path: "/api/restricted",
|
|
userGroups: []string{"admin", "user-manager", "order-manager"},
|
|
expectedAllowed: false,
|
|
expectedGroups: []string{"non-existent-group"},
|
|
},
|
|
{
|
|
name: "self-service can access specific user route",
|
|
path: "/api/users/123",
|
|
userGroups: []string{"self-service"},
|
|
expectedAllowed: true,
|
|
expectedGroups: []string{"admin", "user-manager", "self-service"},
|
|
},
|
|
{
|
|
name: "unmatched route defaults to allowed",
|
|
path: "/unknown/route",
|
|
userGroups: []string{},
|
|
expectedAllowed: true,
|
|
expectedGroups: nil,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
allowed, groups := checkPermissions(tt.path, tt.userGroups, routePermissions, logger)
|
|
|
|
if allowed != tt.expectedAllowed {
|
|
t.Errorf("checkPermissions(%q, %v) allowed = %v, want %v",
|
|
tt.path, tt.userGroups, allowed, tt.expectedAllowed)
|
|
}
|
|
|
|
if !reflect.DeepEqual(groups, tt.expectedGroups) {
|
|
t.Errorf("checkPermissions(%q, %v) groups = %v, want %v",
|
|
tt.path, tt.userGroups, groups, tt.expectedGroups)
|
|
}
|
|
})
|
|
}
|
|
}
|