mirror of
https://github.com/pomerium/pomerium.git
synced 2025-07-03 01:48:02 +02:00
Merge branch 'main' into cdoxsey/upgrade-lint
This commit is contained in:
commit
359376e786
33 changed files with 2016 additions and 57 deletions
2
.github/Dockerfile-cloudrun
vendored
2
.github/Dockerfile-cloudrun
vendored
|
@ -2,7 +2,7 @@
|
|||
FROM busybox:latest@sha256:1ceb872bcc68a8fcd34c97952658b58086affdcb604c90c1dee2735bde5edc2f as build
|
||||
RUN touch /config.yaml
|
||||
|
||||
FROM gcr.io/distroless/base:latest@sha256:46c5b9bd3e3efff512e28350766b54355fce6337a0b44ba3f822ab918eca4520
|
||||
FROM gcr.io/distroless/base:latest@sha256:b31a6e02605827e77b7ebb82a0ac9669ec51091edd62c2c076175e05556f4ab9
|
||||
ENV AUTOCERT_DIR /data/autocert
|
||||
WORKDIR /pomerium
|
||||
COPY pomerium* /bin/
|
||||
|
|
4
.github/workflows/benchmark.yaml
vendored
4
.github/workflows/benchmark.yaml
vendored
|
@ -20,7 +20,7 @@ jobs:
|
|||
platform: [ubuntu-latest]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
|
||||
|
||||
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
with:
|
||||
|
@ -43,7 +43,7 @@ jobs:
|
|||
- name: start cluster
|
||||
run: |
|
||||
export POMERIUM_TAG=dev
|
||||
cd ./integration/clusters/single
|
||||
cd ./integration/clusters/single-stateful
|
||||
docker-compose up -d
|
||||
|
||||
- name: integration tests
|
||||
|
|
4
.github/workflows/docker-main.yaml
vendored
4
.github/workflows/docker-main.yaml
vendored
|
@ -15,7 +15,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3
|
||||
|
@ -75,7 +75,7 @@ jobs:
|
|||
needs: publish
|
||||
steps:
|
||||
- name: Checkout Gitops Repo
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
|
||||
with:
|
||||
repository: pomerium/gitops-argocd
|
||||
token: ${{ secrets.APPARITOR_GITHUB_TOKEN }}
|
||||
|
|
|
@ -13,7 +13,7 @@ jobs:
|
|||
labels: linux
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
|
||||
|
||||
- name: Docker meta
|
||||
id: meta
|
||||
|
|
2
.github/workflows/lint.yaml
vendored
2
.github/workflows/lint.yaml
vendored
|
@ -11,7 +11,7 @@ jobs:
|
|||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
|
||||
|
||||
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
with:
|
||||
|
|
4
.github/workflows/release.yaml
vendored
4
.github/workflows/release.yaml
vendored
|
@ -20,7 +20,7 @@ jobs:
|
|||
tag: ${{ steps.tagName.outputs.tag }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
|
||||
|
||||
- name: Unshallow
|
||||
run: git fetch --prune --unshallow
|
||||
|
@ -121,7 +121,7 @@ jobs:
|
|||
needs: goreleaser
|
||||
steps:
|
||||
- name: Checkout Gitops Repo
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
|
||||
with:
|
||||
repository: pomerium/gitops-argocd
|
||||
token: ${{ secrets.APPARITOR_GITHUB_TOKEN }}
|
||||
|
|
13
.github/workflows/test.yaml
vendored
13
.github/workflows/test.yaml
vendored
|
@ -16,9 +16,10 @@ jobs:
|
|||
node-version: [16.x]
|
||||
platform: [ubuntu-latest]
|
||||
deployment: [multi, single]
|
||||
authenticate-flow: [stateful, stateless]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
|
||||
|
||||
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
with:
|
||||
|
@ -41,12 +42,12 @@ jobs:
|
|||
- name: start cluster
|
||||
run: |
|
||||
export POMERIUM_TAG=dev
|
||||
cd ./integration/clusters/${{matrix.deployment}}
|
||||
cd ./integration/clusters/${{matrix.deployment}}-${{matrix.authenticate-flow}}
|
||||
docker-compose up -d
|
||||
|
||||
- name: integration tests
|
||||
run: |
|
||||
(cd ./integration/clusters/${{matrix.deployment}} && docker-compose logs -f &)
|
||||
(cd ./integration/clusters/${{matrix.deployment}}-${{matrix.authenticate-flow}} && docker-compose logs -f &)
|
||||
go test -v ./integration/...
|
||||
|
||||
build:
|
||||
|
@ -57,7 +58,7 @@ jobs:
|
|||
platform: [ubuntu-latest, macos-latest]
|
||||
runs-on: ${{ matrix.platform }}
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
|
||||
|
||||
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491
|
||||
with:
|
||||
|
@ -101,7 +102,7 @@ jobs:
|
|||
build-docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226
|
||||
|
@ -119,7 +120,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608
|
||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ func (a *Authenticate) mountDashboard(r *mux.Router) {
|
|||
AllowedHeaders: []string{"*"},
|
||||
})
|
||||
sr.Use(c.Handler)
|
||||
sr.Use(a.RetrieveSession)
|
||||
|
||||
// routes that don't need a session:
|
||||
sr.Path("/sign_out").Handler(httputil.HandlerFunc(a.SignOut))
|
||||
|
@ -91,7 +92,6 @@ func (a *Authenticate) mountDashboard(r *mux.Router) {
|
|||
|
||||
// routes that need a session:
|
||||
sr = sr.NewRoute().Subrouter()
|
||||
sr.Use(a.RetrieveSession)
|
||||
sr.Use(a.VerifySession)
|
||||
sr.Path("/").Handler(a.requireValidSignatureOnRedirect(a.userInfo))
|
||||
sr.Path("/sign_in").Handler(httputil.HandlerFunc(a.SignIn))
|
||||
|
@ -475,7 +475,9 @@ func (a *Authenticate) revokeSession(ctx context.Context, w http.ResponseWriter,
|
|||
return ""
|
||||
}
|
||||
|
||||
return state.flow.RevokeSession(ctx, r, authenticator, nil)
|
||||
sessionState, _ := a.getSessionFromCtx(ctx)
|
||||
|
||||
return state.flow.RevokeSession(ctx, r, authenticator, sessionState)
|
||||
}
|
||||
|
||||
// Callback handles the result of a successful call to the authenticate service
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
|
@ -248,6 +249,40 @@ func TestAuthenticate_SignOut(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestAuthenticate_SignOutDoesNotRequireSession(t *testing.T) {
|
||||
// A direct sign_out request would not be signed.
|
||||
f := new(stubFlow)
|
||||
f.verifySignatureErr = errors.New("no signature")
|
||||
|
||||
sessionStore := &mstore.Store{LoadError: errors.New("no session")}
|
||||
a := &Authenticate{
|
||||
cfg: getAuthenticateConfig(WithGetIdentityProvider(func(options *config.Options, idpID string) (identity.Authenticator, error) {
|
||||
return identity.MockProvider{}, nil
|
||||
})),
|
||||
state: atomicutil.NewValue(&authenticateState{
|
||||
cookieSecret: cryptutil.NewKey(),
|
||||
sessionLoader: sessionStore,
|
||||
sessionStore: sessionStore,
|
||||
sharedEncoder: mock.Encoder{},
|
||||
flow: f,
|
||||
}),
|
||||
options: config.NewAtomicOptions(),
|
||||
}
|
||||
r := httptest.NewRequest(http.MethodGet, "/.pomerium/sign_out", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
a.Handler().ServeHTTP(w, r)
|
||||
result := w.Result()
|
||||
|
||||
// The handler should serve a sign out confirmation page, not a login redirect.
|
||||
expectedStatus := "200 OK"
|
||||
if result.Status != expectedStatus {
|
||||
t.Fatalf("wrong status code: got %q want %q", result.Status, expectedStatus)
|
||||
}
|
||||
body, _ := io.ReadAll(result.Body)
|
||||
assert.Contains(t, string(body), `"page":"SignOutConfirm"`)
|
||||
}
|
||||
|
||||
func TestAuthenticate_OAuthCallback(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
@ -144,13 +144,17 @@ func newAuthenticateStateFromConfig(
|
|||
}
|
||||
}
|
||||
|
||||
state.flow, err = authenticateflow.NewStateless(
|
||||
cfg,
|
||||
cookieStore,
|
||||
authenticateConfig.getIdentityProvider,
|
||||
authenticateConfig.profileTrimFn,
|
||||
authenticateConfig.authEventFn,
|
||||
)
|
||||
if cfg.Options.UseStatelessAuthenticateFlow() {
|
||||
state.flow, err = authenticateflow.NewStateless(
|
||||
cfg,
|
||||
cookieStore,
|
||||
authenticateConfig.getIdentityProvider,
|
||||
authenticateConfig.profileTrimFn,
|
||||
authenticateConfig.authEventFn,
|
||||
)
|
||||
} else {
|
||||
state.flow, err = authenticateflow.NewStateful(cfg, cookieStore)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -83,7 +83,11 @@ func newAuthorizeStateFromConfig(
|
|||
return nil, fmt.Errorf("authorize: invalid session store: %w", err)
|
||||
}
|
||||
|
||||
state.authenticateFlow, err = authenticateflow.NewStateless(cfg, nil, nil, nil, nil)
|
||||
if cfg.Options.UseStatelessAuthenticateFlow() {
|
||||
state.authenticateFlow, err = authenticateflow.NewStateless(cfg, nil, nil, nil, nil)
|
||||
} else {
|
||||
state.authenticateFlow, err = authenticateflow.NewStateful(cfg, nil)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
@ -827,6 +827,25 @@ func (o *Options) GetInternalAuthenticateURL() (*url.URL, error) {
|
|||
return urlutil.ParseAndValidateURL(o.AuthenticateInternalURLString)
|
||||
}
|
||||
|
||||
// UseStatelessAuthenticateFlow returns true if the stateless authentication
|
||||
// flow should be used (i.e. for hosted authenticate).
|
||||
func (o *Options) UseStatelessAuthenticateFlow() bool {
|
||||
if flow := os.Getenv("DEBUG_FORCE_AUTHENTICATE_FLOW"); flow != "" {
|
||||
if flow == "stateless" {
|
||||
return true
|
||||
} else if flow == "stateful" {
|
||||
return false
|
||||
}
|
||||
log.Warn(context.Background()).
|
||||
Msgf("ignoring unknown DEBUG_FORCE_AUTHENTICATE_FLOW setting %q", flow)
|
||||
}
|
||||
u, err := o.GetInternalAuthenticateURL()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return urlutil.IsHostedAuthenticateDomain(u.Hostname())
|
||||
}
|
||||
|
||||
// GetAuthorizeURLs returns the AuthorizeURLs in the options or 127.0.0.1:5443.
|
||||
func (o *Options) GetAuthorizeURLs() ([]*url.URL, error) {
|
||||
if IsAll(o.Services) && o.AuthorizeURLString == "" && len(o.AuthorizeURLStrings) == 0 {
|
||||
|
|
|
@ -856,6 +856,31 @@ func TestOptions_DefaultURL(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestOptions_UseStatelessAuthenticateFlow(t *testing.T) {
|
||||
t.Run("enabled by default", func(t *testing.T) {
|
||||
options := &Options{}
|
||||
assert.True(t, options.UseStatelessAuthenticateFlow())
|
||||
})
|
||||
t.Run("enabled explicitly", func(t *testing.T) {
|
||||
options := &Options{AuthenticateURLString: "https://authenticate.pomerium.app"}
|
||||
assert.True(t, options.UseStatelessAuthenticateFlow())
|
||||
})
|
||||
t.Run("disabled", func(t *testing.T) {
|
||||
options := &Options{AuthenticateURLString: "https://authenticate.example.com"}
|
||||
assert.False(t, options.UseStatelessAuthenticateFlow())
|
||||
})
|
||||
t.Run("force enabled", func(t *testing.T) {
|
||||
options := &Options{AuthenticateURLString: "https://authenticate.example.com"}
|
||||
t.Setenv("DEBUG_FORCE_AUTHENTICATE_FLOW", "stateless")
|
||||
assert.True(t, options.UseStatelessAuthenticateFlow())
|
||||
})
|
||||
t.Run("force disabled", func(t *testing.T) {
|
||||
options := &Options{}
|
||||
t.Setenv("DEBUG_FORCE_AUTHENTICATE_FLOW", "stateful")
|
||||
assert.False(t, options.UseStatelessAuthenticateFlow())
|
||||
})
|
||||
}
|
||||
|
||||
func TestOptions_GetOauthOptions(t *testing.T) {
|
||||
opts := &Options{AuthenticateURLString: "https://authenticate.example.com"}
|
||||
oauthOptions, err := opts.GetOauthOptions()
|
||||
|
|
4
go.mod
4
go.mod
|
@ -53,7 +53,7 @@ require (
|
|||
github.com/pomerium/zero-sdk v0.0.0-20231127153820-dcd408d87b54
|
||||
github.com/prometheus/client_golang v1.17.0
|
||||
github.com/prometheus/client_model v0.5.0
|
||||
github.com/prometheus/common v0.44.0
|
||||
github.com/prometheus/common v0.45.0
|
||||
github.com/prometheus/procfs v0.12.0
|
||||
github.com/rs/cors v1.10.1
|
||||
github.com/rs/zerolog v1.31.0
|
||||
|
@ -173,7 +173,7 @@ require (
|
|||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
|
||||
github.com/miekg/dns v1.1.55 // indirect
|
||||
github.com/minio/md5-simd v1.1.2 // indirect
|
||||
github.com/minio/sha256-simd v1.0.1 // indirect
|
||||
|
|
8
go.sum
8
go.sum
|
@ -540,8 +540,8 @@ github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D
|
|||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 h1:jWpvCLoY8Z/e3VKvlsiIGKtc+UG6U5vzxaoagmhXfyg=
|
||||
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0/go.mod h1:QUyp042oQthUoa9bqDv0ER0wrtXnBruoNd7aNjkbP+k=
|
||||
github.com/mholt/acmez v1.2.0 h1:1hhLxSgY5FvH5HCnGUuwbKY2VQVo8IU7rxXKSnZ7F30=
|
||||
github.com/mholt/acmez v1.2.0/go.mod h1:VT9YwH1xgNX1kmYY89gY8xPJC84BFAisjo8Egigt4kE=
|
||||
github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo=
|
||||
|
@ -671,8 +671,8 @@ github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9
|
|||
github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls=
|
||||
github.com/prometheus/common v0.35.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||
github.com/prometheus/common v0.37.0/go.mod h1:phzohg0JFMnBEFGxTDbfu3QyL5GI8gTQJFhYO5B3mfA=
|
||||
github.com/prometheus/common v0.44.0 h1:+5BrQJwiBB9xsMygAB3TNvpQKOwlkc25LbISbrdOOfY=
|
||||
github.com/prometheus/common v0.44.0/go.mod h1:ofAIvZbQ1e/nugmZGz4/qCb9Ap1VoSTIO7x0VV9VvuY=
|
||||
github.com/prometheus/common v0.45.0 h1:2BGz0eBc2hdMDLnO/8n0jeB3oPrt2D08CekT0lneoxM=
|
||||
github.com/prometheus/common v0.45.0/go.mod h1:YJmSTw9BoKxJplESWWxlbyttQR4uaEcGyv9MZjVOJsY=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
|
|
77
integration/authentication_test.go
Normal file
77
integration/authentication_test.go
Normal file
|
@ -0,0 +1,77 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-jose/go-jose/v3/jwt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/pomerium/pomerium/integration/flows"
|
||||
)
|
||||
|
||||
func TestRouteSessions(t *testing.T) {
|
||||
ctx, clearTimeout := context.WithTimeout(context.Background(), time.Second*30)
|
||||
defer clearTimeout()
|
||||
|
||||
client := getClient(t)
|
||||
|
||||
// Sign in to access one route.
|
||||
url1 := mustParseURL("https://httpdetails.localhost.pomerium.io/by-domain")
|
||||
res, err := flows.Authenticate(ctx, client, url1, flows.WithEmail("user1@dogs.test"))
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, "expected OK for httpdetails")
|
||||
|
||||
// Now request a different route. This should not require signing in again,
|
||||
// but will redirect through the authenticate service if using the
|
||||
// stateless authentication flow.
|
||||
client.CheckRedirect = nil
|
||||
url2 := mustParseURL("https://restricted-httpdetails.localhost.pomerium.io/by-domain")
|
||||
req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url2.String(), nil)
|
||||
res, err = client.Do(req)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, http.StatusOK, res.StatusCode, "expected OK for restricted-httpdetails")
|
||||
|
||||
// Now examine the session cookies saved for each route.
|
||||
claims1 := getSessionCookieJWTClaims(t, client, url1)
|
||||
claims2 := getSessionCookieJWTClaims(t, client, url2)
|
||||
|
||||
if AuthenticateFlow == "stateless" {
|
||||
// Under the stateless authenticate flow, each route should have its
|
||||
// own session.
|
||||
assert.NotEqual(t, claims1.ID, claims2.ID)
|
||||
} else {
|
||||
// Under the stateful authenticate flow, the two routes should share
|
||||
// the same session.
|
||||
assert.Equal(t, claims1.ID, claims2.ID)
|
||||
}
|
||||
}
|
||||
|
||||
func getSessionCookieJWTClaims(t *testing.T, client *http.Client, u *url.URL) *jwt.Claims {
|
||||
t.Helper()
|
||||
cookie := getSessionCookie(t, client, u)
|
||||
|
||||
token, err := jwt.ParseSigned(cookie.Value)
|
||||
require.NoError(t, err)
|
||||
|
||||
var claims jwt.Claims
|
||||
err = token.UnsafeClaimsWithoutVerification(&claims)
|
||||
require.NoError(t, err)
|
||||
|
||||
return &claims
|
||||
}
|
||||
|
||||
func getSessionCookie(t *testing.T, client *http.Client, u *url.URL) *http.Cookie {
|
||||
t.Helper()
|
||||
for _, c := range client.Jar.Cookies(u) {
|
||||
if c.Name == "_pomerium" {
|
||||
return c
|
||||
}
|
||||
}
|
||||
t.Fatalf("no session cookie found for URL %q", u.String())
|
||||
return nil
|
||||
}
|
981
integration/clusters/multi-stateless/compose.yml
Normal file
981
integration/clusters/multi-stateless/compose.yml
Normal file
File diff suppressed because one or more lines are too long
793
integration/clusters/single-stateless/compose.yml
Normal file
793
integration/clusters/single-stateless/compose.yml
Normal file
File diff suppressed because one or more lines are too long
|
@ -23,7 +23,7 @@ import (
|
|||
"golang.org/x/net/publicsuffix"
|
||||
)
|
||||
|
||||
var IDP, ClusterType string
|
||||
var IDP, ClusterType, AuthenticateFlow string
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
|
||||
|
@ -44,7 +44,7 @@ func TestMain(m *testing.M) {
|
|||
return
|
||||
}
|
||||
|
||||
setIDPAndClusterType(ctx)
|
||||
setClusterInfo(ctx)
|
||||
|
||||
status := m.Run()
|
||||
os.Exit(status)
|
||||
|
@ -169,9 +169,10 @@ func waitForHealthy(ctx context.Context) error {
|
|||
}
|
||||
}
|
||||
|
||||
func setIDPAndClusterType(ctx context.Context) {
|
||||
func setClusterInfo(ctx context.Context) {
|
||||
IDP = "oidc"
|
||||
ClusterType = "single"
|
||||
AuthenticateFlow = "stateful"
|
||||
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
|
||||
if err != nil {
|
||||
|
@ -185,14 +186,19 @@ func setIDPAndClusterType(ctx context.Context) {
|
|||
}
|
||||
for _, container := range containers {
|
||||
for _, name := range container.Names {
|
||||
parts := regexp.MustCompile(`^/(\w+?)[-_]pomerium.*$`).FindStringSubmatch(name)
|
||||
if len(parts) == 2 {
|
||||
parts := regexp.MustCompile(`^/(\w+?)-(\w+?)[-_]pomerium.*$`).FindStringSubmatch(name)
|
||||
if len(parts) == 3 {
|
||||
ClusterType = parts[1]
|
||||
AuthenticateFlow = parts[2]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log.Info().Str("idp", IDP).Str("cluster-type", ClusterType).Send()
|
||||
log.Info().
|
||||
Str("idp", IDP).
|
||||
Str("cluster-type", ClusterType).
|
||||
Str("authenticate-flow", AuthenticateFlow).
|
||||
Send()
|
||||
}
|
||||
|
||||
func mustParseURL(str string) *url.URL {
|
||||
|
|
|
@ -74,7 +74,7 @@ local KubernetesService(name) =
|
|||
};
|
||||
|
||||
|
||||
local Environment(mode, idp, dns_suffix) =
|
||||
local Environment(mode, idp, authentication_flow, dns_suffix) =
|
||||
{
|
||||
AUTHENTICATE_SERVICE_URL: 'https://authenticate.localhost.pomerium.io',
|
||||
CERTIFICATE: std.base64(importstr '../files/trusted.pem'),
|
||||
|
@ -98,13 +98,19 @@ local Environment(mode, idp, dns_suffix) =
|
|||
SHARED_SECRET: 'UYgnt8bxxK5G2sFaNzyqi5Z+OgF8m2akNc0xdQx718w=',
|
||||
SIGNING_KEY: std.base64(importstr '../files/signing-key.pem'),
|
||||
SIGNING_KEY_ALGORITHM: 'ES256',
|
||||
} + if mode == 'multi' then {
|
||||
AUTHENTICATE_INTERNAL_SERVICE_URL: 'https://pomerium-authenticate',
|
||||
AUTHORIZE_SERVICE_URL: 'https://pomerium-authorize:5443',
|
||||
DATABROKER_SERVICE_URL: 'https://pomerium-databroker:5443',
|
||||
GRPC_ADDRESS: ':5443',
|
||||
GRPC_INSECURE: 'false',
|
||||
} else {};
|
||||
} + (
|
||||
if mode == 'multi' then {
|
||||
AUTHENTICATE_INTERNAL_SERVICE_URL: 'https://pomerium-authenticate',
|
||||
AUTHORIZE_SERVICE_URL: 'https://pomerium-authorize:5443',
|
||||
DATABROKER_SERVICE_URL: 'https://pomerium-databroker:5443',
|
||||
GRPC_ADDRESS: ':5443',
|
||||
GRPC_INSECURE: 'false',
|
||||
} else {}
|
||||
) + (
|
||||
if authentication_flow == 'stateless' then {
|
||||
DEBUG_FORCE_AUTHENTICATE_FLOW: 'stateless',
|
||||
} else {}
|
||||
);
|
||||
|
||||
local ComposeService(name, definition, additionalAliases=[]) =
|
||||
utils.ComposeService(name, definition {
|
||||
|
@ -128,10 +134,10 @@ local ComposeService(name, definition, additionalAliases=[]) =
|
|||
},
|
||||
}, additionalAliases);
|
||||
|
||||
function(mode, idp, dns_suffix='') {
|
||||
function(mode, idp, authentication_flow, dns_suffix='') {
|
||||
local name = 'pomerium',
|
||||
local image = 'pomerium/pomerium:${POMERIUM_TAG:-main}',
|
||||
local environment = Environment(mode, idp, dns_suffix),
|
||||
local environment = Environment(mode, idp, authentication_flow, dns_suffix),
|
||||
|
||||
compose: {
|
||||
services: if mode == 'multi' then
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
(import '../../deployments/multi.libsonnet')('oidc', 'stateful')
|
|
@ -0,0 +1 @@
|
|||
(import '../../deployments/multi.libsonnet')('oidc', 'stateless')
|
|
@ -1 +0,0 @@
|
|||
(import '../../deployments/multi.libsonnet')('oidc')
|
|
@ -0,0 +1 @@
|
|||
(import '../../deployments/single.libsonnet')('oidc', 'stateful')
|
|
@ -0,0 +1 @@
|
|||
(import '../../deployments/single.libsonnet')('oidc', 'stateless')
|
|
@ -1 +0,0 @@
|
|||
(import '../../deployments/single.libsonnet')('oidc')
|
|
@ -6,7 +6,7 @@ function(idp) utils.Merge([
|
|||
(import '../backends/fortio.libsonnet')().kubernetes +
|
||||
(import '../backends/httpdetails.libsonnet')().kubernetes +
|
||||
(import '../backends/mock-idp.libsonnet')(idp).kubernetes +
|
||||
(import '../backends/pomerium.libsonnet')('single', idp, '.default.svc.cluster.local').kubernetes +
|
||||
(import '../backends/pomerium.libsonnet')('single', idp, 'stateful', '.default.svc.cluster.local').kubernetes +
|
||||
(import '../backends/postgres.libsonnet')().kubernetes +
|
||||
(import '../backends/verify.libsonnet')('single').kubernetes +
|
||||
(import '../backends/websocket-echo.libsonnet')().kubernetes
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
local utils = import '../utils.libsonnet';
|
||||
|
||||
function(idp) utils.Merge([
|
||||
function(idp, authentication_flow) utils.Merge([
|
||||
(import '../backends/fortio.libsonnet')().compose,
|
||||
(import '../backends/httpdetails.libsonnet')().compose,
|
||||
(import '../backends/mock-idp.libsonnet')(idp).compose,
|
||||
(import '../backends/pomerium.libsonnet')('multi', idp).compose,
|
||||
(import '../backends/pomerium.libsonnet')('multi', idp, authentication_flow).compose,
|
||||
(import '../backends/postgres.libsonnet')().compose,
|
||||
(import '../backends/verify.libsonnet')('multi').compose,
|
||||
(import '../backends/websocket-echo.libsonnet')().compose,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
local utils = import '../utils.libsonnet';
|
||||
|
||||
function(idp) utils.Merge([
|
||||
function(idp, authentication_flow) utils.Merge([
|
||||
(import '../backends/fortio.libsonnet')().compose,
|
||||
(import '../backends/httpdetails.libsonnet')().compose,
|
||||
(import '../backends/mock-idp.libsonnet')(idp).compose,
|
||||
(import '../backends/pomerium.libsonnet')('single', idp).compose,
|
||||
(import '../backends/pomerium.libsonnet')('single', idp, authentication_flow).compose,
|
||||
(import '../backends/postgres.libsonnet')().compose,
|
||||
(import '../backends/verify.libsonnet')('single').compose,
|
||||
(import '../backends/websocket-echo.libsonnet')().compose,
|
||||
|
|
|
@ -33,7 +33,7 @@ type inMemoryKey struct {
|
|||
}
|
||||
|
||||
// New constructs a new registry tracking service that operates in RAM
|
||||
// as such, it is not usable for multi-node deployment where REDIS or other alternative should be used
|
||||
// as such, it is not usable for multi-node deployment.
|
||||
func New(ctx context.Context, ttl time.Duration) registry.Interface {
|
||||
srv := &inMemoryServer{
|
||||
ttl: ttl,
|
||||
|
|
|
@ -114,8 +114,12 @@ func newProxyStateFromConfig(cfg *config.Config) (*proxyState, error) {
|
|||
|
||||
state.programmaticRedirectDomainWhitelist = cfg.Options.ProgrammaticRedirectDomainWhitelist
|
||||
|
||||
state.authenticateFlow, err = authenticateflow.NewStateless(
|
||||
cfg, state.sessionStore, nil, nil, nil)
|
||||
if cfg.Options.UseStatelessAuthenticateFlow() {
|
||||
state.authenticateFlow, err = authenticateflow.NewStateless(
|
||||
cfg, state.sessionStore, nil, nil, nil)
|
||||
} else {
|
||||
state.authenticateFlow, err = authenticateflow.NewStateful(cfg, state.sessionStore)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue