Skip to content

Commit 265976c

Browse files
committed
add simple keycloak login test
Signed-off-by: Jan Larwig <[email protected]>
1 parent 0e461bc commit 265976c

File tree

14 files changed

+2333
-7
lines changed

14 files changed

+2333
-7
lines changed

go.mod

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
module github.com/oauth2-proxy/e2e
22

3-
go 1.23.7
3+
go 1.24
4+
5+
require (
6+
github.com/onsi/ginkgo/v2 v2.23.4
7+
github.com/onsi/gomega v1.37.0
8+
github.com/playwright-community/playwright-go v0.5101.0
9+
)
410

511
require (
612
github.com/deckarep/golang-set/v2 v2.8.0 // indirect
@@ -10,9 +16,6 @@ require (
1016
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
1117
github.com/google/go-cmp v0.7.0 // indirect
1218
github.com/google/pprof v0.0.0-20250418163039-24c5476c6587 // indirect
13-
github.com/onsi/ginkgo/v2 v2.23.4 // indirect
14-
github.com/onsi/gomega v1.37.0 // indirect
15-
github.com/playwright-community/playwright-go v0.5101.0 // indirect
1619
go.uber.org/automaxprocs v1.6.0 // indirect
1720
golang.org/x/net v0.39.0 // indirect
1821
golang.org/x/sys v0.32.0 // indirect

go.sum

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2+
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
3+
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
24
github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ=
35
github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4=
46
github.com/go-jose/go-jose/v3 v3.0.4 h1:Wp5HA7bLQcKnf6YYao/4kpRpVMp/yf6+pJKV8WFSaNY=
@@ -14,15 +16,28 @@ github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
1416
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
1517
github.com/google/pprof v0.0.0-20250418163039-24c5476c6587 h1:b/8HpQhvKLSNzH5oTXN2WkNcMl6YB5K3FRbb+i+Ml34=
1618
github.com/google/pprof v0.0.0-20250418163039-24c5476c6587/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
19+
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
20+
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
21+
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
22+
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
23+
github.com/mitchellh/go-ps v1.0.0 h1:i6ampVEEF4wQFF+bkYfwYgY+F/uYJDktmvLPf7qIgjc=
24+
github.com/mitchellh/go-ps v1.0.0/go.mod h1:J4lOc8z8yJs6vUwklHw2XEIiT4z4C40KtWVN3nvg8Pg=
1725
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
1826
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
1927
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
2028
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
2129
github.com/playwright-community/playwright-go v0.5101.0 h1:gVCMZThDO76LJ/aCI27lpB8hEAWhZszeS0YB+oTxJp0=
2230
github.com/playwright-community/playwright-go v0.5101.0/go.mod h1:kBNWs/w2aJ2ZUp1wEOOFLXgOqvppFngM5OS+qyhl+ZM=
31+
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
2332
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
33+
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
34+
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
35+
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
36+
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
2437
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
2538
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
39+
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
40+
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
2641
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
2742
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
2843
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
@@ -71,7 +86,11 @@ golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
7186
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
7287
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
7388
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
89+
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
90+
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
7491
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
92+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
93+
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
7594
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
7695
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
7796
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package pages
2+
3+
import (
4+
. "github.com/onsi/gomega"
5+
pw "github.com/playwright-community/playwright-go"
6+
)
7+
8+
func KeycloakLogin(page pw.Page, username, password string) {
9+
usernameInput := page.Locator("input#username")
10+
passwordInput := page.Locator("input#password")
11+
12+
err := usernameInput.Fill(username)
13+
Expect(err).NotTo(HaveOccurred(), "Couldn't enter username")
14+
15+
err = passwordInput.Fill(password)
16+
Expect(err).NotTo(HaveOccurred(), "Couldn't enter password")
17+
18+
btn := page.Locator("button#kc-login", pw.PageLocatorOptions{HasText: "Sign In"})
19+
err = btn.Click()
20+
Expect(err).NotTo(HaveOccurred(), "Couldn't login")
21+
}

internal/pages/provider_button_page.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ func (p *ProviderButtonPage) SignIn() {
1919
_, err := p.page.Goto(p.baseUrl)
2020
Expect(err).ToNot(HaveOccurred(), "Provider button page not loading")
2121

22-
btn := p.page.Locator("button", pw.PageLocatorOptions{HasText: "Sign in with Dex"})
22+
btn := p.page.Locator("button", pw.PageLocatorOptions{HasText: "Sign in with " + p.providerName})
2323

2424
err = btn.Click()
2525
Expect(err).NotTo(HaveOccurred(), "Provider button wasn't found")

internal/utils/playwright.go

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
package utils
22

33
import (
4+
"os"
5+
"strconv"
6+
47
"github.com/playwright-community/playwright-go"
58
)
69

@@ -16,7 +19,7 @@ func NewBrowserManager() (*BrowserManager, error) {
1619
}
1720

1821
browser, err := pw.Chromium.Launch(playwright.BrowserTypeLaunchOptions{
19-
Headless: playwright.Bool(false),
22+
Headless: playwright.Bool(getHeadless()),
2023
})
2124
if err != nil {
2225
return nil, err
@@ -35,6 +38,7 @@ func (bm *BrowserManager) NewTestContext() (playwright.BrowserContext, playwrigh
3538
}
3639

3740
page, err := context.NewPage()
41+
page.SetDefaultTimeout(10000)
3842
return context, page, err
3943
}
4044

@@ -44,3 +48,17 @@ func (bm *BrowserManager) Close() error {
4448
}
4549
return bm.pw.Stop()
4650
}
51+
52+
func getHeadless() bool {
53+
val := os.Getenv("BROWSER_HEADLESS")
54+
if val == "" {
55+
return true
56+
}
57+
58+
// Parse as boolean (accepts "false", "true", "0", "1", "t", "yes", "y", etc.)
59+
b, err := strconv.ParseBool(val)
60+
if err != nil {
61+
return true
62+
}
63+
return b
64+
}

tests/keycloak/compose.yaml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
services:
2+
oauth2-proxy:
3+
pull_policy: never
4+
image: quay.io/oauth2-proxy/oauth2-proxy:latest
5+
command: --config /oauth2-proxy.cfg
6+
hostname: oauth2-proxy
7+
volumes:
8+
- "./oauth2-proxy.cfg:/oauth2-proxy.cfg"
9+
restart: unless-stopped
10+
ports:
11+
- 4180:4180/tcp
12+
networks:
13+
keycloak: {}
14+
upstream: {}
15+
depends_on:
16+
- keycloak
17+
- upstream
18+
19+
keycloak:
20+
image: quay.io/keycloak/keycloak:26.2
21+
command:
22+
- "start-dev"
23+
- "--http-port=9080"
24+
- "--health-enabled=true"
25+
- "--import-realm"
26+
volumes:
27+
- ./realm:/opt/keycloak/data/import
28+
environment:
29+
KC_HTTP_PORT: 9080
30+
KEYCLOAK_ADMIN: [email protected]
31+
KEYCLOAK_ADMIN_PASSWORD: password
32+
ports:
33+
- 9080:9080/tcp
34+
networks:
35+
keycloak:
36+
aliases:
37+
- keycloak.localtest.me
38+
39+
wait-for-keycloak:
40+
image: alpine
41+
command:
42+
- "tail"
43+
- "-f"
44+
- "/dev/null"
45+
healthcheck:
46+
test:
47+
["CMD", "wget", "-q", "--spider", "http://keycloak:9000/health/ready"]
48+
interval: 5s
49+
timeout: 10s
50+
retries: 20
51+
depends_on:
52+
- keycloak
53+
networks:
54+
keycloak:
55+
56+
upstream:
57+
image: kennethreitz/httpbin:latest
58+
networks:
59+
upstream:
60+
61+
networks:
62+
keycloak: {}
63+
upstream: {}

tests/keycloak/e2e_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package keycloak
2+
3+
import (
4+
"testing"
5+
6+
"github.com/oauth2-proxy/e2e/internal/pages"
7+
"github.com/oauth2-proxy/e2e/internal/utils"
8+
. "github.com/onsi/ginkgo/v2"
9+
. "github.com/onsi/gomega"
10+
pw "github.com/playwright-community/playwright-go"
11+
)
12+
13+
var (
14+
bm *utils.BrowserManager
15+
)
16+
17+
func TestKeycloakSuite(t *testing.T) {
18+
RegisterFailHandler(Fail)
19+
RunSpecs(t, "Keycloak Test Suite")
20+
}
21+
22+
var _ = BeforeSuite(func() {
23+
var err error
24+
bm, err = utils.NewBrowserManager()
25+
Expect(err).NotTo(HaveOccurred())
26+
})
27+
28+
var _ = AfterSuite(func() {
29+
Expect(bm.Close()).To(Succeed())
30+
})
31+
32+
var _ = Describe("Login Flow", func() {
33+
var (
34+
context pw.BrowserContext
35+
page pw.Page
36+
)
37+
38+
BeforeEach(func() {
39+
var err error
40+
context, page, err = bm.NewTestContext()
41+
Expect(err).NotTo(HaveOccurred())
42+
})
43+
44+
AfterEach(func() {
45+
Expect(context.Close()).To(Succeed())
46+
})
47+
48+
It("should authenticate", func() {
49+
baseUrl := "http://oauth2-proxy.localtest.me:4180"
50+
51+
pages.NewProviderButtonPage(page, baseUrl, "Keycloak").SignIn()
52+
pages.KeycloakLogin(page, "[email protected]", "password")
53+
54+
httpbin := pages.NewHttpbinPage(page, baseUrl)
55+
headers := httpbin.GetHeaders()
56+
57+
Expect(headers["X-Forwarded-Email"]).To(Equal("[email protected]"))
58+
})
59+
})

tests/keycloak/oauth2-proxy.cfg

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
http_address="0.0.0.0:4180"
2+
cookie_secret="OQINaROshtE9TcZkNAm-5Zs2Pv3xaWytBmc5W7sPX7w="
3+
email_domains="example.com"
4+
cookie_secure="false"
5+
upstreams="http://upstream"
6+
cookie_domains=[".localtest.me"] # Required so cookie can be read on all subdomains.
7+
whitelist_domains=[".localtest.me"] # Required to allow redirection back to original requested target.
8+
9+
# keycloak provider
10+
client_secret="72341b6d-7065-4518-a0e4-50ee15025608"
11+
client_id="oauth2-proxy"
12+
redirect_url="http://oauth2-proxy.localtest.me:4180/oauth2/callback"
13+
14+
# in this case oauth2-proxy is going to visit
15+
# http://keycloak.localtest.me:9080/realms/oauth2-proxy/.well-known/openid-configuration for configuration
16+
oidc_issuer_url="http://keycloak.localtest.me:9080/realms/oauth2-proxy"
17+
provider="oidc"
18+
provider_display_name="Keycloak"

0 commit comments

Comments
 (0)