diff --git a/console/cmd/server/main.go b/console/cmd/server/main.go index e995ce1..63d4b22 100644 --- a/console/cmd/server/main.go +++ b/console/cmd/server/main.go @@ -39,11 +39,15 @@ func main() { testMode := os.Getenv("FISSION_TEST_MODE") == "true" - var authenticator auth.Authenticator + var jwtAuth auth.Authenticator if testMode { - authenticator = &auth.TestAuthenticator{} + jwtAuth = &auth.TestAuthenticator{} } else { - authenticator = auth.NewDeckAuthenticator(auth.DefaultDeckAPIs, nil) + jwtAuth = auth.NewDeckAuthenticator(auth.DefaultDeckAPIs, nil) + } + authenticator := &auth.MultiAuthenticator{ + JWT: jwtAuth, + Demo: &auth.DemoAuthenticator{}, } srv := api.NewServer(api.Config{ diff --git a/console/deploy/console.yaml b/console/deploy/console.yaml index 8ec10f2..428a3b2 100644 --- a/console/deploy/console.yaml +++ b/console/deploy/console.yaml @@ -52,7 +52,7 @@ spec: serviceAccountName: fission-console containers: - name: console - image: naeel/fission-console:v1.3.25 + image: naeel/fission-console:v1.3.26 imagePullPolicy: Always ports: - containerPort: 8090 diff --git a/console/internal/auth/auth.go b/console/internal/auth/auth.go index 889814a..1b5a606 100644 --- a/console/internal/auth/auth.go +++ b/console/internal/auth/auth.go @@ -6,6 +6,7 @@ package auth import ( "context" + "crypto/sha1" "crypto/sha256" "encoding/base64" "encoding/hex" @@ -172,3 +173,74 @@ func identityFromJWT(token string) (UserIdentity, error) { email, _ := claims["email"].(string) return UserIdentity{Sub: sub, Email: email}, nil } + +// isJWT возвращает true если строка похожа на JWT (три непустые части через точку). +func isJWT(s string) bool { + parts := strings.SplitN(s, ".", 4) + return len(parts) == 3 && parts[0] != "" && parts[1] != "" && parts[2] != "" +} + +// uuidV5 генерирует детерминированный UUID v5 (RFC 4122) из строки. +// Namespace: произвольный фиксированный UUID для demo-логинов. +func uuidV5(name string) string { + // Фиксированный namespace UUID для demo-логинов + ns := []byte{0xf4, 0x7a, 0xc1, 0x0b, 0x58, 0xcc, 0x43, 0x72, 0xa5, 0x67, 0x0e, 0x02, 0xb2, 0xc3, 0xd4, 0x79} + h := sha1.New() + _, _ = h.Write(ns) + _, _ = h.Write([]byte(name)) + sum := h.Sum(nil) + sum[6] = (sum[6] & 0x0f) | 0x50 // version 5 + sum[8] = (sum[8] & 0x3f) | 0x80 // RFC 4122 variant + return fmt.Sprintf("%08x-%04x-%04x-%04x-%012x", + sum[0:4], sum[4:6], sum[6:8], sum[8:10], sum[10:16]) +} + +// demoEmail формирует маскированный email для демо-логина. +// Пример: "mylogin" → "demo-my***in" +func demoEmail(login string) string { + r := []rune(login) + n := len(r) + if n <= 4 { + return "demo-" + string(r) + } + return "demo-" + string(r[:2]) + strings.Repeat("*", n-4) + string(r[n-2:]) +} + +// --- DemoAuthenticator --- + +// DemoAuthenticator — аутентификация по произвольному логину (≥6 символов). +// Не обращается ни к каким внешним сервисам. +// Sub = UUID v5 от логина (детерминированный), Email = маскированный логин. +type DemoAuthenticator struct{} + +// Authenticate принимает логин ≥6 символов и возвращает UserIdentity. +func (d *DemoAuthenticator) Authenticate(_ context.Context, login, _ string) (UserIdentity, error) { + login = strings.TrimSpace(login) + if len([]rune(login)) < 6 { + return UserIdentity{}, fmt.Errorf("login must be at least 6 characters") + } + return UserIdentity{Sub: uuidV5(login), Email: demoEmail(login)}, nil +} + +// --- MultiAuthenticator --- + +// MultiAuthenticator роутит аутентификацию: +// - JWT (три части через точку) → JWT authenticator (DeckAuthenticator или TestAuthenticator) +// - Иначе → DemoAuthenticator +// Оба пути равноправны и возвращают одинаковый UserIdentity. +type MultiAuthenticator struct { + JWT Authenticator + Demo *DemoAuthenticator +} + +// Authenticate определяет тип входных данных и делегирует нужному authenticator. +func (m *MultiAuthenticator) Authenticate(ctx context.Context, token, env string) (UserIdentity, error) { + token = strings.TrimSpace(token) + if token == "" { + return UserIdentity{}, fmt.Errorf("token or login required") + } + if isJWT(token) { + return m.JWT.Authenticate(ctx, token, env) + } + return m.Demo.Authenticate(ctx, token, env) +} diff --git a/console/ui/index.html b/console/ui/index.html index 6c89929..935da79 100644 --- a/console/ui/index.html +++ b/console/ui/index.html @@ -46,12 +46,12 @@