From e70e031a1f0698e9c0ab2a41bbe2872c00428b93 Mon Sep 17 00:00:00 2001 From: Jens Langhammer Date: Mon, 24 Jan 2022 20:12:25 +0100 Subject: [PATCH] internal: start adding tests to outpost Signed-off-by: Jens Langhammer --- .github/workflows/ci-outpost.yml | 25 ++++++ go.mod | 1 + go.sum | 2 + internal/outpost/ak/test.go | 66 ++++++++++++++ .../proxyv2/application/mode_forward_test.go | 85 +++++++++++++++++++ 5 files changed, 179 insertions(+) create mode 100644 internal/outpost/ak/test.go create mode 100644 internal/outpost/proxyv2/application/mode_forward_test.go diff --git a/.github/workflows/ci-outpost.yml b/.github/workflows/ci-outpost.yml index 8bb0a7b49..f3cfa24d4 100644 --- a/.github/workflows/ci-outpost.yml +++ b/.github/workflows/ci-outpost.yml @@ -30,9 +30,34 @@ jobs: -w /app \ golangci/golangci-lint:v1.43 \ golangci-lint run -v --timeout 200s + test-unittest: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + with: + go-version: "^1.17" + - name: Get dependencies + run: | + go get github.com/axw/gocov/gocov + go get github.com/AlekSi/gocov-xml + go get github.com/jstemmer/go-junit-report + - name: Go unittests + run: | + go test -timeout 0 -v -race -coverprofile=coverage.out -covermode=atomic -cover ./... | go-junit-report > junit.xml + - uses: testspace-com/setup-testspace@v1 + with: + domain: ${{github.repository_owner}} + - name: run testspace + if: ${{ always() }} + run: | + gocov convert coverage.out | gocov-xml > coverage.xml + testspace [outpost]junit.xml --link=codecov + testspace [outpost]coverage.xml --link=codecov ci-outpost-mark: needs: - lint-golint + - test-unittest runs-on: ubuntu-latest steps: - run: echo mark diff --git a/go.mod b/go.mod index 8164f92f0..1d1cb45b9 100644 --- a/go.mod +++ b/go.mod @@ -26,6 +26,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/pquerna/cachecontrol v0.0.0-20201205024021-ac21108117ac // indirect github.com/prometheus/client_golang v1.12.0 + github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b // indirect github.com/sirupsen/logrus v1.8.1 goauthentik.io/api v0.2021125.1 golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c diff --git a/go.sum b/go.sum index 758b0c2f0..0ec8ca18a 100644 --- a/go.sum +++ b/go.sum @@ -489,6 +489,8 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b h1:aUNXCGgukb4gtY99imuIeoh8Vr0GSwAlYxPAhqZrpFc= +github.com/quasoft/memstore v0.0.0-20191010062613-2bce066d2b0b/go.mod h1:wTPjTepVu7uJBYgZ0SdWHQlIas582j6cn2jgk4DDdlg= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= diff --git a/internal/outpost/ak/test.go b/internal/outpost/ak/test.go new file mode 100644 index 000000000..9e4885d72 --- /dev/null +++ b/internal/outpost/ak/test.go @@ -0,0 +1,66 @@ +package ak + +import ( + "encoding/base64" + "fmt" + "math/rand" + "net/http" + "time" + + "github.com/google/uuid" + "github.com/gorilla/securecookie" + log "github.com/sirupsen/logrus" + "goauthentik.io/api" +) + +func TestSecret() string { + return base64.RawURLEncoding.EncodeToString(securecookie.GenerateRandomKey(32)) +} + +func MockConfig() api.Config { + return *api.NewConfig( + *api.NewErrorReportingConfig(false, "test", false, 0.0), + []api.CapabilitiesEnum{}, + 100, + 100, + 100, + 100, + ) +} + +func MockAK(outpost api.Outpost, globalConfig api.Config) *APIController { + config := api.NewConfiguration() + config.HTTPClient = &http.Client{ + Transport: GetTLSTransport(), + } + token := TestSecret() + config.AddDefaultHeader("Authorization", fmt.Sprintf("Bearer %s", token)) + + // create the API client, with the transport + apiClient := api.NewAPIClient(config) + + log := log.WithField("logger", "authentik.outpost.ak-api-controller") + + log.WithField("name", outpost.Name).Debug("Fetched outpost configuration") + + log.Debug("Fetched global configuration") + + // doGlobalSetup is called by the OnRefresh handler, which ticks on start + // doGlobalSetup(outpost, akConfig) + + ac := &APIController{ + Client: apiClient, + GlobalConfig: globalConfig, + + token: token, + logger: log, + + reloadOffset: time.Duration(rand.Intn(10)) * time.Second, + instanceUUID: uuid.New(), + Outpost: outpost, + wsBackoffMultiplier: 1, + refreshHandlers: make([]func(), 0), + } + ac.logger.WithField("offset", ac.reloadOffset.String()).Debug("HA Reload offset") + return ac +} diff --git a/internal/outpost/proxyv2/application/mode_forward_test.go b/internal/outpost/proxyv2/application/mode_forward_test.go new file mode 100644 index 000000000..d2b1a0cd6 --- /dev/null +++ b/internal/outpost/proxyv2/application/mode_forward_test.go @@ -0,0 +1,85 @@ +package application + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/quasoft/memstore" + "github.com/stretchr/testify/assert" + "goauthentik.io/api" + "goauthentik.io/internal/outpost/ak" + "goauthentik.io/internal/outpost/proxyv2/constants" +) + +func newTestApplication() *Application { + a, _ := NewApplication( + api.ProxyOutpostConfig{ + Name: *api.PtrString(ak.TestSecret()), + ClientId: api.PtrString(ak.TestSecret()), + ClientSecret: api.PtrString(ak.TestSecret()), + CookieSecret: api.PtrString(ak.TestSecret()), + CookieDomain: api.PtrString(""), + Mode: api.PROXYMODE_FORWARD_SINGLE.Ptr(), + SkipPathRegex: api.PtrString(""), + }, + http.DefaultClient, + nil, + ak.MockAK( + api.Outpost{ + Config: map[string]interface{}{ + "authentik_host": ak.TestSecret(), + }, + }, + ak.MockConfig(), + ), + ) + a.sessions = memstore.NewMemStore( + []byte(ak.TestSecret()), + ) + return a +} + +func TestForwardHandleTraefik_Blank(t *testing.T) { + a := newTestApplication() + req, _ := http.NewRequest("GET", "/akprox/auth/traefik", nil) + + rr := httptest.NewRecorder() + a.forwardHandleTraefik(rr, req) + + assert.Equal(t, rr.Code, http.StatusTemporaryRedirect) + loc, _ := rr.Result().Location() + assert.Equal(t, loc.String(), "/akprox/start") + + s, _ := a.sessions.Get(req, constants.SeesionName) + // Since we're not setting the traefik specific headers, expect it to redirect to the auth URL + assert.Equal(t, s.Values[constants.SessionRedirect], "/akprox/auth/traefik") +} + +func TestForwardHandleTraefik_Headers(t *testing.T) { + a := newTestApplication() + req, _ := http.NewRequest("GET", "/akprox/auth/traefik", nil) + req.Header.Set("X-Forwarded-Proto", "http") + req.Header.Set("X-Forwarded-Host", "test.goauthentik.io") + req.Header.Set("X-Forwarded-Uri", "/") + + rr := httptest.NewRecorder() + a.forwardHandleTraefik(rr, req) + + assert.Equal(t, rr.Code, http.StatusTemporaryRedirect) + loc, _ := rr.Result().Location() + assert.Equal(t, loc.String(), "http://test.goauthentik.io/akprox/start") + + s, _ := a.sessions.Get(req, constants.SeesionName) + assert.Equal(t, s.Values[constants.SessionRedirect], "http://test.goauthentik.io/") +} + +func TestForwardHandleNginx_Blank(t *testing.T) { + a := newTestApplication() + req, _ := http.NewRequest("GET", "/akprox/auth/nginx", nil) + + rr := httptest.NewRecorder() + a.forwardHandleNginx(rr, req) + + assert.Equal(t, rr.Code, http.StatusUnauthorized) +}