mirror of
https://github.com/gravitational/teleport.git
synced 2026-11-01 21:52:02 +08:00
* Connection Diagnostics: Postgres Database tester When adding a new resource using the Web UI we want to allow users to test connecting to it. We have two connection testers already: - for SSH Nodes - for Kube clusters This PR adds a third tester: Postgres Database. Most of the required changes for any Database are already present but we're focusing on Postgres for now. Other databases will be added as future PRs. Testing a Database is similar to the other tests: - generate certs for the logged in user - connect to the resource using those certs When generating the certificate, we inject an ID so that the Database Service can add Connection Diagnostic traces.
146 lines
3.9 KiB
Go
146 lines
3.9 KiB
Go
// Copyright 2022 Gravitational, Inc
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package helpers
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto/tls"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/http"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gravitational/trace"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/gravitational/teleport/lib/httplib/csrf"
|
|
"github.com/gravitational/teleport/lib/utils"
|
|
"github.com/gravitational/teleport/lib/web"
|
|
"github.com/gravitational/teleport/lib/web/ui"
|
|
)
|
|
|
|
// WebClientPack is an authenticated HTTP Client for Teleport.
|
|
type WebClientPack struct {
|
|
clt *http.Client
|
|
host string
|
|
webCookie string
|
|
bearerToken string
|
|
clusterName string
|
|
}
|
|
|
|
// LoginWebClient receives the host url, the username and a password.
|
|
// It will login into that host and return a WebClientPack.
|
|
func LoginWebClient(t *testing.T, host, username, password string) *WebClientPack {
|
|
csReq, err := json.Marshal(web.CreateSessionReq{
|
|
User: username,
|
|
Pass: password,
|
|
})
|
|
require.NoError(t, err)
|
|
|
|
// Create POST request to create session.
|
|
u := url.URL{
|
|
Scheme: "https",
|
|
Host: host,
|
|
Path: "/v1/webapi/sessions/web",
|
|
}
|
|
req, err := http.NewRequest(http.MethodPost, u.String(), bytes.NewBuffer(csReq))
|
|
require.NoError(t, err)
|
|
|
|
// Attach CSRF token in cookie and header.
|
|
csrfToken, err := utils.CryptoRandomHex(32)
|
|
require.NoError(t, err)
|
|
req.AddCookie(&http.Cookie{
|
|
Name: csrf.CookieName,
|
|
Value: csrfToken,
|
|
})
|
|
req.Header.Set("Content-Type", "application/json; charset=utf-8")
|
|
req.Header.Set(csrf.HeaderName, csrfToken)
|
|
|
|
// Issue request.
|
|
client := &http.Client{
|
|
Transport: &http.Transport{
|
|
TLSClientConfig: &tls.Config{
|
|
InsecureSkipVerify: true,
|
|
},
|
|
},
|
|
}
|
|
resp, err := client.Do(req)
|
|
require.NoError(t, err)
|
|
defer resp.Body.Close()
|
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
|
|
|
// Read in response.
|
|
var csResp *web.CreateSessionResponse
|
|
err = json.NewDecoder(resp.Body).Decode(&csResp)
|
|
require.NoError(t, err)
|
|
|
|
// Extract session cookie and bearer token.
|
|
require.Len(t, resp.Cookies(), 1)
|
|
cookie := resp.Cookies()[0]
|
|
require.Equal(t, cookie.Name, web.CookieName)
|
|
|
|
webClient := &WebClientPack{
|
|
clt: client,
|
|
host: host,
|
|
webCookie: cookie.Value,
|
|
bearerToken: csResp.Token,
|
|
}
|
|
|
|
resp, err = webClient.DoRequest(http.MethodGet, "sites", nil)
|
|
require.NoError(t, err)
|
|
defer resp.Body.Close()
|
|
|
|
var clusters []ui.Cluster
|
|
require.NoError(t, json.NewDecoder(resp.Body).Decode(&clusters))
|
|
require.NotEmpty(t, clusters)
|
|
|
|
webClient.clusterName = clusters[0].Name
|
|
return webClient
|
|
}
|
|
|
|
// DoRequest receives a method, endpoint and payload and sends an HTTP Request to the Teleport API.
|
|
// The endpoint must not contain the host neither the base path ('/v1/webapi/').
|
|
// Returns the http.Response.
|
|
func (w *WebClientPack) DoRequest(method, endpoint string, payload any) (*http.Response, error) {
|
|
endpoint = strings.ReplaceAll(endpoint, "$site", w.clusterName)
|
|
u := url.URL{
|
|
Scheme: "https",
|
|
Host: w.host,
|
|
Path: fmt.Sprintf("/v1/webapi/%s", endpoint),
|
|
}
|
|
|
|
bs, err := json.Marshal(payload)
|
|
if err != nil {
|
|
return nil, trace.Wrap(err)
|
|
}
|
|
|
|
req, err := http.NewRequest(method, u.String(), bytes.NewBuffer(bs))
|
|
if err != nil {
|
|
return nil, trace.Wrap(err)
|
|
}
|
|
|
|
req.AddCookie(&http.Cookie{
|
|
Name: web.CookieName,
|
|
Value: w.webCookie,
|
|
})
|
|
req.Header.Add("Authorization", fmt.Sprintf("Bearer %v", w.bearerToken))
|
|
req.Header.Add("Content-Type", "application/json")
|
|
|
|
resp, err := w.clt.Do(req)
|
|
return resp, trace.Wrap(err)
|
|
}
|