pgweb/pkg/api/backend.go

88 lines
2.2 KiB
Go
Raw Normal View History

package api
import (
"bytes"
2022-01-08 23:45:21 +03:00
"context"
"encoding/json"
"fmt"
"net/http"
"strings"
"github.com/gin-gonic/gin"
)
2018-12-02 07:35:11 +03:00
// Backend represents a third party configuration source
type Backend struct {
Endpoint string
Token string
2022-12-02 20:45:23 +03:00
PassHeaders []string
}
2018-12-02 07:35:11 +03:00
// BackendRequest represents a payload sent to the third-party source
type BackendRequest struct {
Resource string `json:"resource"`
Token string `json:"token"`
Headers map[string]string `json:"headers"`
}
2018-12-02 07:35:11 +03:00
// BackendCredential represents the third-party response
type BackendCredential struct {
2018-12-02 07:35:11 +03:00
DatabaseURL string `json:"database_url"`
}
2018-12-02 07:35:11 +03:00
// FetchCredential sends an authentication request to a third-party service
2022-01-08 23:45:21 +03:00
func (be Backend) FetchCredential(ctx context.Context, resource string, c *gin.Context) (*BackendCredential, error) {
2022-12-02 20:45:23 +03:00
logger.WithField("resource", resource).Debug("fetching database credential")
request := BackendRequest{
Resource: resource,
Token: be.Token,
Headers: map[string]string{},
}
2018-12-02 07:35:11 +03:00
// Pass white-listed client headers to the backend request
2022-12-02 20:45:23 +03:00
for _, name := range be.PassHeaders {
request.Headers[strings.ToLower(name)] = c.Request.Header.Get(name)
}
body, err := json.Marshal(request)
if err != nil {
2022-12-02 20:45:23 +03:00
logger.WithField("resource", resource).Error("backend request serialization error:", err)
return nil, err
}
2022-01-08 23:45:21 +03:00
req, err := http.NewRequestWithContext(ctx, http.MethodPost, be.Endpoint, bytes.NewReader(body))
if err != nil {
2022-01-08 23:45:21 +03:00
return nil, err
}
req.Header.Set("content-type", "application/json")
2022-01-08 23:45:21 +03:00
resp, err := http.DefaultClient.Do(req)
if err != nil {
2022-12-02 20:45:23 +03:00
logger.WithField("resource", resource).Error("backend credential fetch failed:", err)
return nil, errBackendConnectError
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
2022-12-02 20:45:23 +03:00
err = fmt.Errorf("backend credential fetch received HTTP status code %v", resp.StatusCode)
logger.
WithField("resource", resource).
WithField("status", resp.StatusCode).
Error(err)
return nil, err
}
cred := &BackendCredential{}
2018-12-02 07:35:11 +03:00
if err := json.NewDecoder(resp.Body).Decode(cred); err != nil {
return nil, err
}
2018-12-02 07:35:11 +03:00
if cred.DatabaseURL == "" {
return nil, errConnStringRequired
}
return cred, nil
}