Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 53 additions & 1 deletion topaz/cmd/access/wellknown.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package access

import (
"context"
"crypto/tls"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"

"github.com/aserto-dev/topaz/topaz/cc"
Expand All @@ -30,7 +32,11 @@ func (cmd *WellKnownCmd) Run(ctx context.Context) error {
return fmt.Errorf("creating request: %w", err)
}

resp, err := http.DefaultClient.Do(req)
if req.URL, err = wellKnownURL(req.URL, info.Directory.Plaintext); err != nil {
return fmt.Errorf("building request URL: %w", err)
}

resp, err := wellKnownClient(info.Directory.Insecure).Do(req)
if err != nil {
return fmt.Errorf("request failed: %w", err)
}
Expand Down Expand Up @@ -60,3 +66,49 @@ func (cmd *WellKnownCmd) Run(ctx context.Context) error {

return enc.Encode(wellknown)
}

func wellKnownURL(reqURL *url.URL, plaintext bool) (*url.URL, error) {
u, err := url.Parse(reqURL.String())
if err != nil {
return nil, err
}

if plaintext {
u.Scheme = "http"
}

return u, nil
}

func wellKnownClient(insecure bool) *http.Client {
if !insecure {
return http.DefaultClient
}

client := *http.DefaultClient

baseTransport := client.Transport
if baseTransport == nil {
baseTransport = http.DefaultTransport
}

transport, ok := baseTransport.(*http.Transport)
if !ok {
return &client
}

clone := transport.Clone()

tlsConfig := &tls.Config{}
if clone.TLSClientConfig != nil {
tlsConfig = clone.TLSClientConfig.Clone()
}

// #nosec G402 -- TOPAZ_INSECURE explicitly requests skipping TLS verification.
tlsConfig.InsecureSkipVerify = true
clone.TLSClientConfig = tlsConfig

client.Transport = clone

return &client
}
88 changes: 88 additions & 0 deletions topaz/cmd/access/wellknown_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//nolint:testpackage
package access

import (
"context"
"io"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
)

func TestWellKnownURLUsesHTTPWhenPlaintext(t *testing.T) {
t.Parallel()

reqURL, err := url.Parse("https://example.com/.well-known/authzen-configuration")
if err != nil {
t.Fatalf("failed to parse URL: %v", err)
}

got, err := wellKnownURL(reqURL, true)
if err != nil {
t.Fatalf("failed to build URL: %v", err)
}

if got.String() != "http://example.com/.well-known/authzen-configuration" {
t.Fatalf("expected plaintext URL, got %q", got.String())
}
}

func TestWellKnownClientSupportsInsecureTLS(t *testing.T) {
t.Parallel()

srv := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, _ = io.WriteString(w, `{"issuer":"topaz"}`)
}))
defer srv.Close()

req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, srv.URL, nil)
if err != nil {
t.Fatalf("failed to build request: %v", err)
}

resp, err := wellKnownClient(true).Do(req)
if err != nil {
t.Fatalf("expected insecure client to connect: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
t.Fatalf("expected status %d, got %d", http.StatusOK, resp.StatusCode)
}
}

func TestWellKnownURLMatchesPlaintextServer(t *testing.T) {
t.Parallel()

srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, _ = io.WriteString(w, `{"issuer":"topaz"}`)
}))
defer srv.Close()

reqURL, err := url.Parse(strings.Replace(srv.URL, "http://", "https://", 1))
if err != nil {
t.Fatalf("failed to parse URL: %v", err)
}

plaintextURL, err := wellKnownURL(reqURL, true)
if err != nil {
t.Fatalf("failed to build URL: %v", err)
}

req, err := http.NewRequestWithContext(context.Background(), http.MethodGet, plaintextURL.String(), nil)
if err != nil {
t.Fatalf("failed to build request: %v", err)
}

resp, err := wellKnownClient(false).Do(req)
if err != nil {
t.Fatalf("expected plaintext client to connect: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
t.Fatalf("expected status %d, got %d", http.StatusOK, resp.StatusCode)
}
}
Loading