fix: валидация JWT перебором всех стендов gateway (токен любого стенда принимается)
This commit is contained in:
+1
-2
@@ -16,8 +16,7 @@ EXPOSE 4100
|
|||||||
# Нечувствительные значения зашиты в образ. Секреты (SHARED_SQS_ADMIN_TOKEN, REDIS_PASSWORD) — env'ом контейнера в deck.
|
# Нечувствительные значения зашиты в образ. Секреты (SHARED_SQS_ADMIN_TOKEN, REDIS_PASSWORD) — env'ом контейнера в deck.
|
||||||
ENV REDIS_ADDR=redisk8s.4ff5678b-b683-4aef-91da-22d89dec8a25.svc.cluster.local:6379 \
|
ENV REDIS_ADDR=redisk8s.4ff5678b-b683-4aef-91da-22d89dec8a25.svc.cluster.local:6379 \
|
||||||
REDIS_USER=default \
|
REDIS_USER=default \
|
||||||
SHARED_SQS_SEED_DEMO=false \
|
SHARED_SQS_SEED_DEMO=false
|
||||||
NUBES_ENDPOINT=https://lk-api-gateway.ngcloud.ru/api/v1/svc
|
|
||||||
HEALTHCHECK --interval=10s --timeout=5s --retries=3 \
|
HEALTHCHECK --interval=10s --timeout=5s --retries=3 \
|
||||||
CMD wget -q -O - http://localhost:4100/health || exit 1
|
CMD wget -q -O - http://localhost:4100/health || exit 1
|
||||||
ENTRYPOINT ["shared-sqs", "--config", "/conf/goaws.yaml"]
|
ENTRYPOINT ["shared-sqs", "--config", "/conf/goaws.yaml"]
|
||||||
|
|||||||
+1
-3
@@ -64,9 +64,7 @@ type Handler struct {
|
|||||||
// NewHandler — создаёт admin handler
|
// NewHandler — создаёт admin handler
|
||||||
func NewHandler(store *tenant.TenantStore, adminToken string) *Handler {
|
func NewHandler(store *tenant.TenantStore, adminToken string) *Handler {
|
||||||
nubesEndpoint := os.Getenv("NUBES_ENDPOINT")
|
nubesEndpoint := os.Getenv("NUBES_ENDPOINT")
|
||||||
if nubesEndpoint == "" {
|
// Если не задан — пустой: PingNubesAPI переберёт все стенды сам.
|
||||||
nubesEndpoint = "https://lk-api-gateway.ngcloud.ru/api/v1/svc"
|
|
||||||
}
|
|
||||||
return &Handler{store: store, adminToken: adminToken, nubesEndpoint: nubesEndpoint}
|
return &Handler{store: store, adminToken: adminToken, nubesEndpoint: nubesEndpoint}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+46
-17
@@ -74,27 +74,56 @@ func TenantIDFromSub(sub string) string {
|
|||||||
return fmt.Sprintf("sless-%x", hash[:8])
|
return fmt.Sprintf("sless-%x", hash[:8])
|
||||||
}
|
}
|
||||||
|
|
||||||
// PingNubesAPI — проверяет валидность токена запросом к nubes API.
|
// nubesAPIEndpoints — стенды Nubes API Gateway, по которым валидируется токен.
|
||||||
// endpoint — базовый URL (например "https://deck-api-test.ngcloud.ru/api/v1").
|
// Токен принимается, если ХОТЯ БЫ ОДИН стенд его принял.
|
||||||
// Логика: 401/403 → токен отклонён. Ошибка соединения → API недоступен.
|
// Юзер может вводить токен от любого стенда — главное, что токен действительный.
|
||||||
|
var nubesAPIEndpoints = []string{
|
||||||
|
"https://lk-api-gateway.ngcloud.ru/api/v1/svc",
|
||||||
|
"https://lk-api-gateway-test.ngcloud.ru/api/v1/svc",
|
||||||
|
"https://lk-api-gateway-dev.ngcloud.ru/api/v1/svc",
|
||||||
|
}
|
||||||
|
|
||||||
|
// PingNubesAPI — проверяет валидность токена перебором стендов Nubes API.
|
||||||
|
// endpoint (если задан через NUBES_ENDPOINT) пробуется первым.
|
||||||
|
// Логика: 401/403 → токен отклонён ЭТИМ стендом, пробуем следующий.
|
||||||
// Любой другой HTTP статус → токен принят.
|
// Любой другой HTTP статус → токен принят.
|
||||||
func PingNubesAPI(ctx context.Context, endpoint, token string) error {
|
func PingNubesAPI(ctx context.Context, endpoint, token string) error {
|
||||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
|
candidates := make([]string, 0, len(nubesAPIEndpoints)+1)
|
||||||
if err != nil {
|
if endpoint != "" {
|
||||||
return fmt.Errorf("build nubes ping request: %w", err)
|
candidates = append(candidates, endpoint)
|
||||||
|
}
|
||||||
|
for _, ep := range nubesAPIEndpoints {
|
||||||
|
if ep != endpoint {
|
||||||
|
candidates = append(candidates, ep)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
req.Header.Set("Authorization", "Bearer "+token)
|
|
||||||
req.Header.Set("User-Agent", "Mozilla/5.0")
|
|
||||||
|
|
||||||
client := &http.Client{Timeout: 10 * time.Second}
|
var lastErr error
|
||||||
resp, err := client.Do(req)
|
for _, ep := range candidates {
|
||||||
if err != nil {
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, ep, nil)
|
||||||
return fmt.Errorf("nubes API unreachable at %s: %w", endpoint, err)
|
if err != nil {
|
||||||
}
|
lastErr = fmt.Errorf("build nubes ping request: %w", err)
|
||||||
defer resp.Body.Close()
|
continue
|
||||||
|
}
|
||||||
|
req.Header.Set("Authorization", "Bearer "+token)
|
||||||
|
req.Header.Set("User-Agent", "Mozilla/5.0")
|
||||||
|
|
||||||
if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {
|
client := &http.Client{Timeout: 10 * time.Second}
|
||||||
return fmt.Errorf("nubes API rejected token (HTTP %d)", resp.StatusCode)
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
lastErr = fmt.Errorf("nubes API unreachable at %s: %w", ep, err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {
|
||||||
|
lastErr = fmt.Errorf("nubes API rejected token (HTTP %d)", resp.StatusCode)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
return nil
|
if lastErr == nil {
|
||||||
|
lastErr = fmt.Errorf("nubes API rejected token")
|
||||||
|
}
|
||||||
|
return lastErr
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user