fix: валидация JWT перебором всех стендов gateway (токен любого стенда принимается)
This commit is contained in:
+1
-3
@@ -64,9 +64,7 @@ type Handler struct {
|
||||
// NewHandler — создаёт admin handler
|
||||
func NewHandler(store *tenant.TenantStore, adminToken string) *Handler {
|
||||
nubesEndpoint := os.Getenv("NUBES_ENDPOINT")
|
||||
if nubesEndpoint == "" {
|
||||
nubesEndpoint = "https://lk-api-gateway.ngcloud.ru/api/v1/svc"
|
||||
}
|
||||
// Если не задан — пустой: PingNubesAPI переберёт все стенды сам.
|
||||
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])
|
||||
}
|
||||
|
||||
// PingNubesAPI — проверяет валидность токена запросом к nubes API.
|
||||
// endpoint — базовый URL (например "https://deck-api-test.ngcloud.ru/api/v1").
|
||||
// Логика: 401/403 → токен отклонён. Ошибка соединения → API недоступен.
|
||||
// nubesAPIEndpoints — стенды Nubes API Gateway, по которым валидируется токен.
|
||||
// Токен принимается, если ХОТЯ БЫ ОДИН стенд его принял.
|
||||
// Юзер может вводить токен от любого стенда — главное, что токен действительный.
|
||||
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 статус → токен принят.
|
||||
func PingNubesAPI(ctx context.Context, endpoint, token string) error {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, endpoint, nil)
|
||||
if err != nil {
|
||||
return fmt.Errorf("build nubes ping request: %w", err)
|
||||
candidates := make([]string, 0, len(nubesAPIEndpoints)+1)
|
||||
if endpoint != "" {
|
||||
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}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("nubes API unreachable at %s: %w", endpoint, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var lastErr error
|
||||
for _, ep := range candidates {
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, ep, nil)
|
||||
if err != nil {
|
||||
lastErr = fmt.Errorf("build nubes ping request: %w", err)
|
||||
continue
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
req.Header.Set("User-Agent", "Mozilla/5.0")
|
||||
|
||||
if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {
|
||||
return fmt.Errorf("nubes API rejected token (HTTP %d)", resp.StatusCode)
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
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