Files
teleport/integration/helpers/web.go
T
Marco André Dinis 6fd0fa8ef3 Connection Diagnostics: Postgres Database tester (#18558)
* 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.
2022-12-13 18:55:40 +01:00

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)
}