mirror of
https://github.com/int128/kubelogin.git
synced 2026-03-02 00:40:19 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1895099836 | ||
|
|
0e9a39a571 | ||
|
|
f1f2a37adc | ||
|
|
438068e9de | ||
|
|
aaf9a6a58f | ||
|
|
9567ab157b | ||
|
|
f49d73087a | ||
|
|
1c84d270a9 | ||
|
|
1b245f9947 | ||
|
|
963942afad | ||
|
|
24357b6ea7 | ||
|
|
4e7a44cdbe | ||
|
|
3f7513754c | ||
|
|
61555d8ee2 | ||
|
|
f22f6ee483 | ||
|
|
c2cbc47438 | ||
|
|
765d97542c |
9
.github/renovate.json5
vendored
9
.github/renovate.json5
vendored
@@ -2,9 +2,10 @@
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"github>int128/renovate-base",
|
||||
"github>int128/go-renovate-config",
|
||||
"github>int128/go-renovate-config:github-actions",
|
||||
"github>int128/go-renovate-config:kubernetes",
|
||||
"github>int128/go-renovate-config:kustomization-github-releases",
|
||||
"github>int128/go-renovate-config#v1.6.1",
|
||||
"github>int128/go-renovate-config:go-directive#v1.6.1",
|
||||
"github>int128/go-renovate-config:github-actions#v1.6.1",
|
||||
"github>int128/go-renovate-config:kubernetes#v1.6.1",
|
||||
"github>int128/go-renovate-config:kustomization-github-releases#v1.6.1",
|
||||
],
|
||||
}
|
||||
|
||||
32
.github/workflows/go.yaml
vendored
32
.github/workflows/go.yaml
vendored
@@ -7,6 +7,8 @@ on:
|
||||
paths:
|
||||
- .github/workflows/go.yaml
|
||||
- pkg/**
|
||||
- integration_test/**
|
||||
- mocks/**
|
||||
- tools/**
|
||||
- go.*
|
||||
tags:
|
||||
@@ -17,14 +19,17 @@ on:
|
||||
paths:
|
||||
- .github/workflows/go.yaml
|
||||
- pkg/**
|
||||
- integration_test/**
|
||||
- mocks/**
|
||||
- tools/**
|
||||
- go.*
|
||||
|
||||
jobs:
|
||||
check:
|
||||
uses: int128/go-workflows/.github/workflows/check.yaml@v0.3.0
|
||||
uses: int128/go-workflows/.github/workflows/check.yaml@v0.4.0
|
||||
with:
|
||||
go-version: 1.23.1
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: go.sum
|
||||
golangci-lint-version: v1.61.0
|
||||
|
||||
test:
|
||||
@@ -34,8 +39,27 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.23.1
|
||||
- run: go test -v -race ./...
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: go.sum
|
||||
- run: go test -v -race ./pkg/...
|
||||
|
||||
integration-test:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- macos-latest
|
||||
- windows-latest
|
||||
runs-on: ${{ matrix.os }}
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: go.sum
|
||||
- run: go test -v -race ./integration_test/...
|
||||
|
||||
generate:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
3
.github/workflows/release.yaml
vendored
3
.github/workflows/release.yaml
vendored
@@ -57,7 +57,8 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.23.1
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: go.sum
|
||||
- run: go build -ldflags '-X main.version=${{ github.ref_name }}'
|
||||
- uses: int128/go-release-action@v2
|
||||
with:
|
||||
|
||||
3
.github/workflows/system-test.yaml
vendored
3
.github/workflows/system-test.yaml
vendored
@@ -25,7 +25,8 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.23.1
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: go.sum
|
||||
|
||||
# for certutil
|
||||
# https://packages.ubuntu.com/xenial/libnss3-tools
|
||||
|
||||
16
go.mod
16
go.mod
@@ -1,9 +1,9 @@
|
||||
module github.com/int128/kubelogin
|
||||
|
||||
go 1.22.2
|
||||
go 1.23.2
|
||||
|
||||
require (
|
||||
github.com/chromedp/chromedp v0.10.0
|
||||
github.com/chromedp/chromedp v0.11.1
|
||||
github.com/coreos/go-oidc/v3 v3.11.0
|
||||
github.com/gofrs/flock v0.12.1
|
||||
github.com/golang-jwt/jwt/v5 v5.2.1
|
||||
@@ -17,16 +17,16 @@ require (
|
||||
github.com/stretchr/testify v1.9.0
|
||||
golang.org/x/oauth2 v0.23.0
|
||||
golang.org/x/sync v0.8.0
|
||||
golang.org/x/term v0.24.0
|
||||
golang.org/x/term v0.25.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/apimachinery v0.31.1
|
||||
k8s.io/client-go v0.31.1
|
||||
k8s.io/apimachinery v0.31.2
|
||||
k8s.io/client-go v0.31.2
|
||||
k8s.io/klog/v2 v2.130.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/chromedp/cdproto v0.0.0-20240801214329-3f85d328b335 // indirect
|
||||
github.com/chromedp/sysutil v1.0.0 // indirect
|
||||
github.com/chromedp/cdproto v0.0.0-20241022234722-4d5d5faf59fb // indirect
|
||||
github.com/chromedp/sysutil v1.1.0 // indirect
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/go-jose/go-jose/v4 v4.0.2 // indirect
|
||||
@@ -49,7 +49,7 @@ require (
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
golang.org/x/crypto v0.25.0 // indirect
|
||||
golang.org/x/net v0.27.0 // indirect
|
||||
golang.org/x/sys v0.25.0 // indirect
|
||||
golang.org/x/sys v0.26.0 // indirect
|
||||
golang.org/x/text v0.16.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
|
||||
33
go.sum
33
go.sum
@@ -34,12 +34,12 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/chromedp/cdproto v0.0.0-20240801214329-3f85d328b335 h1:bATMoZLH2QGct1kzDxfmeBUQI/QhQvB0mBrOTct+YlQ=
|
||||
github.com/chromedp/cdproto v0.0.0-20240801214329-3f85d328b335/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
|
||||
github.com/chromedp/chromedp v0.10.0 h1:bRclRYVpMm/UVD76+1HcRW9eV3l58rFfy7AdBvKab1E=
|
||||
github.com/chromedp/chromedp v0.10.0/go.mod h1:ei/1ncZIqXX1YnAYDkxhD4gzBgavMEUu7JCKvztdomE=
|
||||
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
|
||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
||||
github.com/chromedp/cdproto v0.0.0-20241022234722-4d5d5faf59fb h1:noKVm2SsG4v0Yd0lHNtFYc9EUxIVvrr4kJ6hM8wvIYU=
|
||||
github.com/chromedp/cdproto v0.0.0-20241022234722-4d5d5faf59fb/go.mod h1:4XqMl3iIW08jtieURWL6Tt5924w21pxirC6th662XUM=
|
||||
github.com/chromedp/chromedp v0.11.1 h1:Spca8egFqUlv+JDW+yIs+ijlHlJDPufgrfXPwtq6NMs=
|
||||
github.com/chromedp/chromedp v0.11.1/go.mod h1:lr8dFRLKsdTTWb75C/Ttol2vnBKOSnt0BW8R9Xaupi8=
|
||||
github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipwM=
|
||||
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
@@ -360,17 +360,16 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
|
||||
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
|
||||
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
|
||||
golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24=
|
||||
golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
@@ -533,12 +532,12 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
k8s.io/api v0.31.1 h1:Xe1hX/fPW3PXYYv8BlozYqw63ytA92snr96zMW9gWTU=
|
||||
k8s.io/api v0.31.1/go.mod h1:sbN1g6eY6XVLeqNsZGLnI5FwVseTrZX7Fv3O26rhAaI=
|
||||
k8s.io/apimachinery v0.31.1 h1:mhcUBbj7KUjaVhyXILglcVjuS4nYXiwC+KKFBgIVy7U=
|
||||
k8s.io/apimachinery v0.31.1/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
|
||||
k8s.io/client-go v0.31.1 h1:f0ugtWSbWpxHR7sjVpQwuvw9a3ZKLXX0u0itkFXufb0=
|
||||
k8s.io/client-go v0.31.1/go.mod h1:sKI8871MJN2OyeqRlmA4W4KM9KBdBUpDLu/43eGemCg=
|
||||
k8s.io/api v0.31.2 h1:3wLBbL5Uom/8Zy98GRPXpJ254nEFpl+hwndmk9RwmL0=
|
||||
k8s.io/api v0.31.2/go.mod h1:bWmGvrGPssSK1ljmLzd3pwCQ9MgoTsRCuK35u6SygUk=
|
||||
k8s.io/apimachinery v0.31.2 h1:i4vUt2hPK56W6mlT7Ry+AO8eEsyxMD1U44NR22CLTYw=
|
||||
k8s.io/apimachinery v0.31.2/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo=
|
||||
k8s.io/client-go v0.31.2 h1:Y2F4dxU5d3AQj+ybwSMqQnpZH9F30//1ObxOKlTI9yc=
|
||||
k8s.io/client-go v0.31.2/go.mod h1:NPa74jSVR/+eez2dFsEIHNa+3o09vtNaWwWwb1qSxSs=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag=
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package handler_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package oidcserver_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package cmd_mock
|
||||
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package reader_mock
|
||||
|
||||
import (
|
||||
credentialplugin "github.com/int128/kubelogin/pkg/credentialplugin"
|
||||
mock "github.com/stretchr/testify/mock"
|
||||
)
|
||||
|
||||
// MockInterface is an autogenerated mock type for the Interface type
|
||||
type MockInterface struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
type MockInterface_Expecter struct {
|
||||
mock *mock.Mock
|
||||
}
|
||||
|
||||
func (_m *MockInterface) EXPECT() *MockInterface_Expecter {
|
||||
return &MockInterface_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// Read provides a mock function with given fields:
|
||||
func (_m *MockInterface) Read() (credentialplugin.Input, error) {
|
||||
ret := _m.Called()
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for Read")
|
||||
}
|
||||
|
||||
var r0 credentialplugin.Input
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func() (credentialplugin.Input, error)); ok {
|
||||
return rf()
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func() credentialplugin.Input); ok {
|
||||
r0 = rf()
|
||||
} else {
|
||||
r0 = ret.Get(0).(credentialplugin.Input)
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func() error); ok {
|
||||
r1 = rf()
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// MockInterface_Read_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Read'
|
||||
type MockInterface_Read_Call struct {
|
||||
*mock.Call
|
||||
}
|
||||
|
||||
// Read is a helper method to define mock.On call
|
||||
func (_e *MockInterface_Expecter) Read() *MockInterface_Read_Call {
|
||||
return &MockInterface_Read_Call{Call: _e.mock.On("Read")}
|
||||
}
|
||||
|
||||
func (_c *MockInterface_Read_Call) Run(run func()) *MockInterface_Read_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run()
|
||||
})
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockInterface_Read_Call) Return(_a0 credentialplugin.Input, _a1 error) *MockInterface_Read_Call {
|
||||
_c.Call.Return(_a0, _a1)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockInterface_Read_Call) RunAndReturn(run func() (credentialplugin.Input, error)) *MockInterface_Read_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
// NewMockInterface creates a new instance of MockInterface. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations.
|
||||
// The first argument is typically a *testing.T value.
|
||||
func NewMockInterface(t interface {
|
||||
mock.TestingT
|
||||
Cleanup(func())
|
||||
}) *MockInterface {
|
||||
mock := &MockInterface{}
|
||||
mock.Mock.Test(t)
|
||||
|
||||
t.Cleanup(func() { mock.AssertExpectations(t) })
|
||||
|
||||
return mock
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package writer_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package browser_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package clock_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package logger_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package logger_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package logger_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package reader_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package jwt_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package loader_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package writer_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package client_mock
|
||||
|
||||
@@ -27,9 +27,9 @@ func (_m *MockFactoryInterface) EXPECT() *MockFactoryInterface_Expecter {
|
||||
return &MockFactoryInterface_Expecter{mock: &_m.Mock}
|
||||
}
|
||||
|
||||
// New provides a mock function with given fields: ctx, p, tlsClientConfig, useAccessToken
|
||||
func (_m *MockFactoryInterface) New(ctx context.Context, p oidc.Provider, tlsClientConfig tlsclientconfig.Config, useAccessToken bool) (client.Interface, error) {
|
||||
ret := _m.Called(ctx, p, tlsClientConfig, useAccessToken)
|
||||
// New provides a mock function with given fields: ctx, p, tlsClientConfig
|
||||
func (_m *MockFactoryInterface) New(ctx context.Context, p oidc.Provider, tlsClientConfig tlsclientconfig.Config) (client.Interface, error) {
|
||||
ret := _m.Called(ctx, p, tlsClientConfig)
|
||||
|
||||
if len(ret) == 0 {
|
||||
panic("no return value specified for New")
|
||||
@@ -37,19 +37,19 @@ func (_m *MockFactoryInterface) New(ctx context.Context, p oidc.Provider, tlsCli
|
||||
|
||||
var r0 client.Interface
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, oidc.Provider, tlsclientconfig.Config, bool) (client.Interface, error)); ok {
|
||||
return rf(ctx, p, tlsClientConfig, useAccessToken)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, oidc.Provider, tlsclientconfig.Config) (client.Interface, error)); ok {
|
||||
return rf(ctx, p, tlsClientConfig)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, oidc.Provider, tlsclientconfig.Config, bool) client.Interface); ok {
|
||||
r0 = rf(ctx, p, tlsClientConfig, useAccessToken)
|
||||
if rf, ok := ret.Get(0).(func(context.Context, oidc.Provider, tlsclientconfig.Config) client.Interface); ok {
|
||||
r0 = rf(ctx, p, tlsClientConfig)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(client.Interface)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, oidc.Provider, tlsclientconfig.Config, bool) error); ok {
|
||||
r1 = rf(ctx, p, tlsClientConfig, useAccessToken)
|
||||
if rf, ok := ret.Get(1).(func(context.Context, oidc.Provider, tlsclientconfig.Config) error); ok {
|
||||
r1 = rf(ctx, p, tlsClientConfig)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
@@ -66,14 +66,13 @@ type MockFactoryInterface_New_Call struct {
|
||||
// - ctx context.Context
|
||||
// - p oidc.Provider
|
||||
// - tlsClientConfig tlsclientconfig.Config
|
||||
// - useAccessToken bool
|
||||
func (_e *MockFactoryInterface_Expecter) New(ctx interface{}, p interface{}, tlsClientConfig interface{}, useAccessToken interface{}) *MockFactoryInterface_New_Call {
|
||||
return &MockFactoryInterface_New_Call{Call: _e.mock.On("New", ctx, p, tlsClientConfig, useAccessToken)}
|
||||
func (_e *MockFactoryInterface_Expecter) New(ctx interface{}, p interface{}, tlsClientConfig interface{}) *MockFactoryInterface_New_Call {
|
||||
return &MockFactoryInterface_New_Call{Call: _e.mock.On("New", ctx, p, tlsClientConfig)}
|
||||
}
|
||||
|
||||
func (_c *MockFactoryInterface_New_Call) Run(run func(ctx context.Context, p oidc.Provider, tlsClientConfig tlsclientconfig.Config, useAccessToken bool)) *MockFactoryInterface_New_Call {
|
||||
func (_c *MockFactoryInterface_New_Call) Run(run func(ctx context.Context, p oidc.Provider, tlsClientConfig tlsclientconfig.Config)) *MockFactoryInterface_New_Call {
|
||||
_c.Call.Run(func(args mock.Arguments) {
|
||||
run(args[0].(context.Context), args[1].(oidc.Provider), args[2].(tlsclientconfig.Config), args[3].(bool))
|
||||
run(args[0].(context.Context), args[1].(oidc.Provider), args[2].(tlsclientconfig.Config))
|
||||
})
|
||||
return _c
|
||||
}
|
||||
@@ -83,7 +82,7 @@ func (_c *MockFactoryInterface_New_Call) Return(_a0 client.Interface, _a1 error)
|
||||
return _c
|
||||
}
|
||||
|
||||
func (_c *MockFactoryInterface_New_Call) RunAndReturn(run func(context.Context, oidc.Provider, tlsclientconfig.Config, bool) (client.Interface, error)) *MockFactoryInterface_New_Call {
|
||||
func (_c *MockFactoryInterface_New_Call) RunAndReturn(run func(context.Context, oidc.Provider, tlsclientconfig.Config) (client.Interface, error)) *MockFactoryInterface_New_Call {
|
||||
_c.Call.Return(run)
|
||||
return _c
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package client_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package logger_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package loader_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package repository_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package authentication_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package credentialplugin_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package setup_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package standalone_mock
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Code generated by mockery v2.46.0. DO NOT EDIT.
|
||||
// Code generated by mockery v2.46.3. DO NOT EDIT.
|
||||
|
||||
package io_mock
|
||||
|
||||
|
||||
@@ -125,7 +125,6 @@ func TestCmd_Run(t *testing.T) {
|
||||
RedirectURLHostname: "localhost",
|
||||
},
|
||||
},
|
||||
UseAccessToken: false,
|
||||
},
|
||||
},
|
||||
"FullOptions": {
|
||||
@@ -153,7 +152,6 @@ func TestCmd_Run(t *testing.T) {
|
||||
RedirectURLHostname: "localhost",
|
||||
},
|
||||
},
|
||||
UseAccessToken: false,
|
||||
},
|
||||
},
|
||||
"AccessToken": {
|
||||
@@ -166,8 +164,9 @@ func TestCmd_Run(t *testing.T) {
|
||||
in: credentialplugin.Input{
|
||||
TokenCacheDir: filepath.Join(userHomeDir, ".kube/cache/oidc-login"),
|
||||
Provider: oidc.Provider{
|
||||
IssuerURL: "https://issuer.example.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
IssuerURL: "https://issuer.example.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
UseAccessToken: true,
|
||||
},
|
||||
GrantOptionSet: authentication.GrantOptionSet{
|
||||
AuthCodeBrowserOption: &authcode.BrowserOption{
|
||||
@@ -176,7 +175,6 @@ func TestCmd_Run(t *testing.T) {
|
||||
RedirectURLHostname: "localhost",
|
||||
},
|
||||
},
|
||||
UseAccessToken: true,
|
||||
},
|
||||
},
|
||||
"HomedirExpansion": {
|
||||
@@ -207,7 +205,6 @@ func TestCmd_Run(t *testing.T) {
|
||||
TLSClientConfig: tlsclientconfig.Config{
|
||||
CACertFilename: []string{filepath.Join(userHomeDir, ".kube/ca.crt")},
|
||||
},
|
||||
UseAccessToken: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -77,17 +77,17 @@ func (cmd *GetToken) New() *cobra.Command {
|
||||
}
|
||||
in := credentialplugin.Input{
|
||||
Provider: oidc.Provider{
|
||||
IssuerURL: o.IssuerURL,
|
||||
ClientID: o.ClientID,
|
||||
ClientSecret: o.ClientSecret,
|
||||
UsePKCE: o.UsePKCE,
|
||||
ExtraScopes: o.ExtraScopes,
|
||||
IssuerURL: o.IssuerURL,
|
||||
ClientID: o.ClientID,
|
||||
ClientSecret: o.ClientSecret,
|
||||
UsePKCE: o.UsePKCE,
|
||||
UseAccessToken: o.UseAccessToken,
|
||||
ExtraScopes: o.ExtraScopes,
|
||||
},
|
||||
TokenCacheDir: o.TokenCacheDir,
|
||||
GrantOptionSet: grantOptionSet,
|
||||
TLSClientConfig: o.tlsOptions.tlsClientConfig(),
|
||||
ForceRefresh: o.ForceRefresh,
|
||||
UseAccessToken: o.UseAccessToken,
|
||||
}
|
||||
if err := cmd.GetToken.Do(c.Context(), in); err != nil {
|
||||
return fmt.Errorf("get-token: %w", err)
|
||||
|
||||
39
pkg/credentialplugin/reader/reader.go
Normal file
39
pkg/credentialplugin/reader/reader.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// Package reader provides a loader for the credential plugin.
|
||||
package reader
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/google/wire"
|
||||
"github.com/int128/kubelogin/pkg/credentialplugin"
|
||||
"k8s.io/client-go/pkg/apis/clientauthentication"
|
||||
)
|
||||
|
||||
var Set = wire.NewSet(
|
||||
wire.Struct(new(Reader), "*"),
|
||||
wire.Bind(new(Interface), new(*Reader)),
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
Read() (credentialplugin.Input, error)
|
||||
}
|
||||
|
||||
type Reader struct{}
|
||||
|
||||
// Read parses the environment variable KUBERNETES_EXEC_INFO.
|
||||
// If the environment variable is not given by kubectl, Read returns a zero value.
|
||||
func (r Reader) Read() (credentialplugin.Input, error) {
|
||||
execInfo := os.Getenv("KUBERNETES_EXEC_INFO")
|
||||
if execInfo == "" {
|
||||
return credentialplugin.Input{}, nil
|
||||
}
|
||||
var execCredential clientauthentication.ExecCredential
|
||||
if err := json.Unmarshal([]byte(execInfo), &execCredential); err != nil {
|
||||
return credentialplugin.Input{}, fmt.Errorf("invalid KUBERNETES_EXEC_INFO: %w", err)
|
||||
}
|
||||
return credentialplugin.Input{
|
||||
ClientAuthenticationAPIVersion: execCredential.APIVersion,
|
||||
}, nil
|
||||
}
|
||||
44
pkg/credentialplugin/reader/reader_test.go
Normal file
44
pkg/credentialplugin/reader/reader_test.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/int128/kubelogin/pkg/credentialplugin"
|
||||
)
|
||||
|
||||
func TestReader_Read(t *testing.T) {
|
||||
var reader Reader
|
||||
|
||||
t.Run("KUBERNETES_EXEC_INFO is empty", func(t *testing.T) {
|
||||
input, err := reader.Read()
|
||||
if err != nil {
|
||||
t.Errorf("Read returned error: %v", err)
|
||||
}
|
||||
want := credentialplugin.Input{}
|
||||
if diff := cmp.Diff(want, input); diff != "" {
|
||||
t.Errorf("input mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
t.Run("KUBERNETES_EXEC_INFO is invalid JSON", func(t *testing.T) {
|
||||
t.Setenv("KUBERNETES_EXEC_INFO", "invalid")
|
||||
_, err := reader.Read()
|
||||
if err == nil {
|
||||
t.Errorf("Read wants error but no error")
|
||||
}
|
||||
})
|
||||
t.Run("KUBERNETES_EXEC_INFO is v1", func(t *testing.T) {
|
||||
t.Setenv(
|
||||
"KUBERNETES_EXEC_INFO",
|
||||
`{"kind":"ExecCredential","apiVersion":"client.authentication.k8s.io/v1","spec":{"interactive":true}}`,
|
||||
)
|
||||
input, err := reader.Read()
|
||||
if err != nil {
|
||||
t.Errorf("Read returned error: %v", err)
|
||||
}
|
||||
want := credentialplugin.Input{ClientAuthenticationAPIVersion: "client.authentication.k8s.io/v1"}
|
||||
if diff := cmp.Diff(want, input); diff != "" {
|
||||
t.Errorf("input mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -3,8 +3,15 @@ package credentialplugin
|
||||
|
||||
import "time"
|
||||
|
||||
// Input represents an input object of the credential plugin.
|
||||
// This may be a zero value if the input is not available.
|
||||
type Input struct {
|
||||
ClientAuthenticationAPIVersion string
|
||||
}
|
||||
|
||||
// Output represents an output object of the credential plugin.
|
||||
type Output struct {
|
||||
Token string
|
||||
Expiry time.Time
|
||||
Token string
|
||||
Expiry time.Time
|
||||
ClientAuthenticationAPIVersion string
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Package writer provides a writer for a credential plugin.
|
||||
// Package writer provides a writer for the credential plugin.
|
||||
package writer
|
||||
|
||||
import (
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/int128/kubelogin/pkg/credentialplugin"
|
||||
"github.com/int128/kubelogin/pkg/infrastructure/stdio"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
clientauthenticationv1 "k8s.io/client-go/pkg/apis/clientauthentication/v1"
|
||||
clientauthenticationv1beta1 "k8s.io/client-go/pkg/apis/clientauthentication/v1beta1"
|
||||
)
|
||||
|
||||
@@ -27,19 +28,44 @@ type Writer struct {
|
||||
|
||||
// Write writes the ExecCredential to standard output for kubectl.
|
||||
func (w *Writer) Write(out credentialplugin.Output) error {
|
||||
ec := &clientauthenticationv1beta1.ExecCredential{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: "client.authentication.k8s.io/v1beta1",
|
||||
Kind: "ExecCredential",
|
||||
},
|
||||
Status: &clientauthenticationv1beta1.ExecCredentialStatus{
|
||||
Token: out.Token,
|
||||
ExpirationTimestamp: &metav1.Time{Time: out.Expiry},
|
||||
},
|
||||
execCredential, err := generateExecCredential(out)
|
||||
if err != nil {
|
||||
return fmt.Errorf("generate ExecCredential: %w", err)
|
||||
}
|
||||
e := json.NewEncoder(w.Stdout)
|
||||
if err := e.Encode(ec); err != nil {
|
||||
return fmt.Errorf("could not write the ExecCredential: %w", err)
|
||||
if err := json.NewEncoder(w.Stdout).Encode(execCredential); err != nil {
|
||||
return fmt.Errorf("write ExecCredential: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateExecCredential(out credentialplugin.Output) (any, error) {
|
||||
switch out.ClientAuthenticationAPIVersion {
|
||||
// If the API version is not available, fall back to v1beta1.
|
||||
case clientauthenticationv1beta1.SchemeGroupVersion.String(), "":
|
||||
return &clientauthenticationv1beta1.ExecCredential{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: clientauthenticationv1beta1.SchemeGroupVersion.String(),
|
||||
Kind: "ExecCredential",
|
||||
},
|
||||
Status: &clientauthenticationv1beta1.ExecCredentialStatus{
|
||||
Token: out.Token,
|
||||
ExpirationTimestamp: &metav1.Time{Time: out.Expiry},
|
||||
},
|
||||
}, nil
|
||||
|
||||
case clientauthenticationv1.SchemeGroupVersion.String():
|
||||
return &clientauthenticationv1.ExecCredential{
|
||||
TypeMeta: metav1.TypeMeta{
|
||||
APIVersion: clientauthenticationv1.SchemeGroupVersion.String(),
|
||||
Kind: "ExecCredential",
|
||||
},
|
||||
Status: &clientauthenticationv1.ExecCredentialStatus{
|
||||
Token: out.Token,
|
||||
ExpirationTimestamp: &metav1.Time{Time: out.Expiry},
|
||||
},
|
||||
}, nil
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown apiVersion: %s", out.ClientAuthenticationAPIVersion)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,8 @@ package di
|
||||
import (
|
||||
"github.com/google/wire"
|
||||
"github.com/int128/kubelogin/pkg/cmd"
|
||||
"github.com/int128/kubelogin/pkg/credentialplugin/writer"
|
||||
credentialpluginreader "github.com/int128/kubelogin/pkg/credentialplugin/reader"
|
||||
credentialpluginwriter "github.com/int128/kubelogin/pkg/credentialplugin/writer"
|
||||
"github.com/int128/kubelogin/pkg/infrastructure/browser"
|
||||
"github.com/int128/kubelogin/pkg/infrastructure/clock"
|
||||
"github.com/int128/kubelogin/pkg/infrastructure/logger"
|
||||
@@ -55,7 +56,8 @@ func NewCmdForHeadless(clock.Interface, stdio.Stdin, stdio.Stdout, logger.Interf
|
||||
repository.Set,
|
||||
client.Set,
|
||||
loader.Set,
|
||||
writer.Set,
|
||||
credentialpluginreader.Set,
|
||||
credentialpluginwriter.Set,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ package di
|
||||
|
||||
import (
|
||||
"github.com/int128/kubelogin/pkg/cmd"
|
||||
reader2 "github.com/int128/kubelogin/pkg/credentialplugin/reader"
|
||||
writer2 "github.com/int128/kubelogin/pkg/credentialplugin/writer"
|
||||
"github.com/int128/kubelogin/pkg/infrastructure/browser"
|
||||
"github.com/int128/kubelogin/pkg/infrastructure/clock"
|
||||
@@ -96,15 +97,17 @@ func NewCmdForHeadless(clockInterface clock.Interface, stdin stdio.Stdin, stdout
|
||||
Logger: loggerInterface,
|
||||
}
|
||||
repositoryRepository := &repository.Repository{}
|
||||
reader3 := &reader2.Reader{}
|
||||
writer3 := &writer2.Writer{
|
||||
Stdout: stdout,
|
||||
}
|
||||
getToken := &credentialplugin.GetToken{
|
||||
Authentication: authenticationAuthentication,
|
||||
TokenCacheRepository: repositoryRepository,
|
||||
Writer: writer3,
|
||||
Logger: loggerInterface,
|
||||
Clock: clockInterface,
|
||||
Authentication: authenticationAuthentication,
|
||||
TokenCacheRepository: repositoryRepository,
|
||||
CredentialPluginReader: reader3,
|
||||
CredentialPluginWriter: writer3,
|
||||
Logger: loggerInterface,
|
||||
Clock: clockInterface,
|
||||
}
|
||||
cmdGetToken := &cmd.GetToken{
|
||||
GetToken: getToken,
|
||||
|
||||
@@ -24,7 +24,7 @@ var Set = wire.NewSet(
|
||||
)
|
||||
|
||||
type FactoryInterface interface {
|
||||
New(ctx context.Context, p oidc.Provider, tlsClientConfig tlsclientconfig.Config, useAccessToken bool) (Interface, error)
|
||||
New(ctx context.Context, p oidc.Provider, tlsClientConfig tlsclientconfig.Config) (Interface, error)
|
||||
}
|
||||
|
||||
type Factory struct {
|
||||
@@ -34,7 +34,7 @@ type Factory struct {
|
||||
}
|
||||
|
||||
// New returns an instance of infrastructure.Interface with the given configuration.
|
||||
func (f *Factory) New(ctx context.Context, p oidc.Provider, tlsClientConfig tlsclientconfig.Config, useAccessToken bool) (Interface, error) {
|
||||
func (f *Factory) New(ctx context.Context, p oidc.Provider, tlsClientConfig tlsclientconfig.Config) (Interface, error) {
|
||||
rawTLSClientConfig, err := f.Loader.Load(tlsClientConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not load the TLS client config: %w", err)
|
||||
@@ -80,7 +80,7 @@ func (f *Factory) New(ctx context.Context, p oidc.Provider, tlsClientConfig tlsc
|
||||
logger: f.Logger,
|
||||
supportedPKCEMethods: supportedPKCEMethods,
|
||||
deviceAuthorizationEndpoint: deviceAuthorizationEndpoint,
|
||||
useAccessToken: useAccessToken,
|
||||
useAccessToken: p.UseAccessToken,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -11,11 +11,12 @@ import (
|
||||
|
||||
// Provider represents an OIDC provider.
|
||||
type Provider struct {
|
||||
IssuerURL string
|
||||
ClientID string
|
||||
ClientSecret string // optional
|
||||
ExtraScopes []string // optional
|
||||
UsePKCE bool // optional
|
||||
IssuerURL string
|
||||
ClientID string
|
||||
ClientSecret string // optional
|
||||
ExtraScopes []string // optional
|
||||
UsePKCE bool // optional
|
||||
UseAccessToken bool // optional
|
||||
}
|
||||
|
||||
// TokenSet represents a set of ID token and refresh token.
|
||||
|
||||
@@ -83,20 +83,22 @@ func (r *Repository) Save(dir string, key tokencache.Key, tokenSet oidc.TokenSet
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repository) Lock(dir string, key tokencache.Key) (io.Closer, error) {
|
||||
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||
return nil, fmt.Errorf("could not create directory %s: %w", dir, err)
|
||||
func (r *Repository) Lock(tokenCacheDir string, key tokencache.Key) (io.Closer, error) {
|
||||
if err := os.MkdirAll(tokenCacheDir, 0700); err != nil {
|
||||
return nil, fmt.Errorf("could not create directory %s: %w", tokenCacheDir, err)
|
||||
}
|
||||
filename, err := computeFilename(key)
|
||||
keyDigest, err := computeFilename(key)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not compute the key: %w", err)
|
||||
}
|
||||
p := filepath.Join(dir, filename)
|
||||
f := flock.New(p)
|
||||
if err := f.Lock(); err != nil {
|
||||
return nil, fmt.Errorf("could not lock the cache file %s: %w", p, err)
|
||||
// Do not lock the token cache file.
|
||||
// https://github.com/int128/kubelogin/issues/1144
|
||||
lockFilepath := filepath.Join(tokenCacheDir, keyDigest+".lock")
|
||||
lockFile := flock.New(lockFilepath)
|
||||
if err := lockFile.Lock(); err != nil {
|
||||
return nil, fmt.Errorf("could not lock the cache file %s: %w", lockFilepath, err)
|
||||
}
|
||||
return f, nil
|
||||
return lockFile, nil
|
||||
}
|
||||
|
||||
func computeFilename(key tokencache.Key) (string, error) {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
"github.com/int128/kubelogin/pkg/tlsclientconfig"
|
||||
"github.com/int128/kubelogin/pkg/tokencache"
|
||||
)
|
||||
|
||||
@@ -16,12 +17,15 @@ func TestRepository_FindByKey(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
key := tokencache.Key{
|
||||
IssuerURL: "YOUR_ISSUER",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
ExtraScopes: []string{"openid", "email"},
|
||||
CACertFilename: "/path/to/cert",
|
||||
SkipTLSVerify: false,
|
||||
Provider: oidc.Provider{
|
||||
IssuerURL: "YOUR_ISSUER",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
ExtraScopes: []string{"openid", "email"},
|
||||
},
|
||||
TLSClientConfig: tlsclientconfig.Config{
|
||||
CACertFilename: []string{"/path/to/cert"},
|
||||
},
|
||||
}
|
||||
json := `{"id_token":"YOUR_ID_TOKEN","refresh_token":"YOUR_REFRESH_TOKEN"}`
|
||||
filename, err := computeFilename(key)
|
||||
@@ -50,12 +54,15 @@ func TestRepository_Save(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
key := tokencache.Key{
|
||||
IssuerURL: "YOUR_ISSUER",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
ExtraScopes: []string{"openid", "email"},
|
||||
CACertFilename: "/path/to/cert",
|
||||
SkipTLSVerify: false,
|
||||
Provider: oidc.Provider{
|
||||
IssuerURL: "YOUR_ISSUER",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
ExtraScopes: []string{"openid", "email"},
|
||||
},
|
||||
TLSClientConfig: tlsclientconfig.Config{
|
||||
CACertFilename: []string{"/path/to/cert"},
|
||||
},
|
||||
}
|
||||
tokenSet := oidc.TokenSet{IDToken: "YOUR_ID_TOKEN", RefreshToken: "YOUR_REFRESH_TOKEN"}
|
||||
if err := r.Save(dir, key, tokenSet); err != nil {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package tokencache
|
||||
|
||||
import (
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
"github.com/int128/kubelogin/pkg/tlsclientconfig"
|
||||
)
|
||||
|
||||
// Key represents a key of a token cache.
|
||||
type Key struct {
|
||||
IssuerURL string
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
Username string
|
||||
ExtraScopes []string
|
||||
CACertFilename string
|
||||
CACertData string
|
||||
SkipTLSVerify bool
|
||||
Provider oidc.Provider
|
||||
TLSClientConfig tlsclientconfig.Config
|
||||
Username string
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ type Authentication struct {
|
||||
|
||||
func (u *Authentication) Do(ctx context.Context, in Input) (*Output, error) {
|
||||
u.Logger.V(1).Infof("initializing an OpenID Connect client")
|
||||
oidcClient, err := u.ClientFactory.New(ctx, in.Provider, in.TLSClientConfig, in.UseAccessToken)
|
||||
oidcClient, err := u.ClientFactory.New(ctx, in.Provider, in.TLSClientConfig)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("oidc error: %w", err)
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
}, nil)
|
||||
mockClientFactory := client_mock.NewMockFactoryInterface(t)
|
||||
mockClientFactory.EXPECT().
|
||||
New(ctx, dummyProvider, dummyTLSClientConfig, false).
|
||||
New(ctx, dummyProvider, dummyTLSClientConfig).
|
||||
Return(mockClient, nil)
|
||||
u := Authentication{
|
||||
ClientFactory: mockClientFactory,
|
||||
@@ -113,7 +113,7 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
}, nil)
|
||||
mockClientFactory := client_mock.NewMockFactoryInterface(t)
|
||||
mockClientFactory.EXPECT().
|
||||
New(ctx, dummyProvider, dummyTLSClientConfig, false).
|
||||
New(ctx, dummyProvider, dummyTLSClientConfig).
|
||||
Return(mockClient, nil)
|
||||
u := Authentication{
|
||||
ClientFactory: mockClientFactory,
|
||||
@@ -159,7 +159,7 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
}, nil)
|
||||
mockClientFactory := client_mock.NewMockFactoryInterface(t)
|
||||
mockClientFactory.EXPECT().
|
||||
New(ctx, dummyProvider, dummyTLSClientConfig, false).
|
||||
New(ctx, dummyProvider, dummyTLSClientConfig).
|
||||
Return(mockClient, nil)
|
||||
u := Authentication{
|
||||
ClientFactory: mockClientFactory,
|
||||
|
||||
@@ -6,11 +6,11 @@ package credentialplugin
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/google/wire"
|
||||
"github.com/int128/kubelogin/pkg/credentialplugin"
|
||||
"github.com/int128/kubelogin/pkg/credentialplugin/writer"
|
||||
credentialpluginreader "github.com/int128/kubelogin/pkg/credentialplugin/reader"
|
||||
credentialpluginwriter "github.com/int128/kubelogin/pkg/credentialplugin/writer"
|
||||
"github.com/int128/kubelogin/pkg/infrastructure/clock"
|
||||
"github.com/int128/kubelogin/pkg/infrastructure/logger"
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
@@ -36,29 +36,30 @@ type Input struct {
|
||||
GrantOptionSet authentication.GrantOptionSet
|
||||
TLSClientConfig tlsclientconfig.Config
|
||||
ForceRefresh bool
|
||||
UseAccessToken bool
|
||||
}
|
||||
|
||||
type GetToken struct {
|
||||
Authentication authentication.Interface
|
||||
TokenCacheRepository repository.Interface
|
||||
Writer writer.Interface
|
||||
Logger logger.Interface
|
||||
Clock clock.Interface
|
||||
Authentication authentication.Interface
|
||||
TokenCacheRepository repository.Interface
|
||||
CredentialPluginReader credentialpluginreader.Interface
|
||||
CredentialPluginWriter credentialpluginwriter.Interface
|
||||
Logger logger.Interface
|
||||
Clock clock.Interface
|
||||
}
|
||||
|
||||
func (u *GetToken) Do(ctx context.Context, in Input) error {
|
||||
u.Logger.V(1).Infof("WARNING: log may contain your secrets such as token or password")
|
||||
|
||||
credentialPluginInput, err := u.CredentialPluginReader.Read()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not read the input of credential plugin: %w", err)
|
||||
}
|
||||
u.Logger.V(1).Infof("credential plugin is called with apiVersion: %s", credentialPluginInput.ClientAuthenticationAPIVersion)
|
||||
|
||||
u.Logger.V(1).Infof("finding a token from cache directory %s", in.TokenCacheDir)
|
||||
tokenCacheKey := tokencache.Key{
|
||||
IssuerURL: in.Provider.IssuerURL,
|
||||
ClientID: in.Provider.ClientID,
|
||||
ClientSecret: in.Provider.ClientSecret,
|
||||
ExtraScopes: in.Provider.ExtraScopes,
|
||||
CACertFilename: strings.Join(in.TLSClientConfig.CACertFilename, ","),
|
||||
CACertData: strings.Join(in.TLSClientConfig.CACertData, ","),
|
||||
SkipTLSVerify: in.TLSClientConfig.SkipTLSVerify,
|
||||
Provider: in.Provider,
|
||||
TLSClientConfig: in.TLSClientConfig,
|
||||
}
|
||||
if in.GrantOptionSet.ROPCOption != nil {
|
||||
tokenCacheKey.Username = in.GrantOptionSet.ROPCOption.Username
|
||||
@@ -95,10 +96,11 @@ func (u *GetToken) Do(ctx context.Context, in Input) error {
|
||||
if !claims.IsExpired(u.Clock) {
|
||||
u.Logger.V(1).Infof("you already have a valid token until %s", claims.Expiry)
|
||||
out := credentialplugin.Output{
|
||||
Token: cachedTokenSet.IDToken,
|
||||
Expiry: claims.Expiry,
|
||||
Token: cachedTokenSet.IDToken,
|
||||
Expiry: claims.Expiry,
|
||||
ClientAuthenticationAPIVersion: credentialPluginInput.ClientAuthenticationAPIVersion,
|
||||
}
|
||||
if err := u.Writer.Write(out); err != nil {
|
||||
if err := u.CredentialPluginWriter.Write(out); err != nil {
|
||||
return fmt.Errorf("could not write the token to client-go: %w", err)
|
||||
}
|
||||
return nil
|
||||
@@ -113,7 +115,6 @@ func (u *GetToken) Do(ctx context.Context, in Input) error {
|
||||
CachedTokenSet: cachedTokenSet,
|
||||
TLSClientConfig: in.TLSClientConfig,
|
||||
ForceRefresh: in.ForceRefresh,
|
||||
UseAccessToken: in.UseAccessToken,
|
||||
}
|
||||
authenticationOutput, err := u.Authentication.Do(ctx, authenticationInput)
|
||||
if err != nil {
|
||||
@@ -130,10 +131,11 @@ func (u *GetToken) Do(ctx context.Context, in Input) error {
|
||||
}
|
||||
u.Logger.V(1).Infof("writing the token to client-go")
|
||||
out := credentialplugin.Output{
|
||||
Token: authenticationOutput.TokenSet.IDToken,
|
||||
Expiry: idTokenClaims.Expiry,
|
||||
Token: authenticationOutput.TokenSet.IDToken,
|
||||
Expiry: idTokenClaims.Expiry,
|
||||
ClientAuthenticationAPIVersion: credentialPluginInput.ClientAuthenticationAPIVersion,
|
||||
}
|
||||
if err := u.Writer.Write(out); err != nil {
|
||||
if err := u.CredentialPluginWriter.Write(out); err != nil {
|
||||
return fmt.Errorf("could not write the token to client-go: %w", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/credentialplugin/reader_mock"
|
||||
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/credentialplugin/writer_mock"
|
||||
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/tokencache/repository_mock"
|
||||
"github.com/int128/kubelogin/mocks/github.com/int128/kubelogin/pkg/usecases/authentication_mock"
|
||||
@@ -40,8 +41,12 @@ func TestGetToken_Do(t *testing.T) {
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}
|
||||
issuedOutput := credentialplugin.Output{
|
||||
Token: issuedIDToken,
|
||||
Expiry: expiryTime,
|
||||
Token: issuedIDToken,
|
||||
Expiry: expiryTime,
|
||||
ClientAuthenticationAPIVersion: "client.authentication.k8s.io/v1",
|
||||
}
|
||||
credentialpluginInput := credentialplugin.Input{
|
||||
ClientAuthenticationAPIVersion: "client.authentication.k8s.io/v1",
|
||||
}
|
||||
grantOptionSet := authentication.GrantOptionSet{
|
||||
AuthCodeBrowserOption: &authcode.BrowserOption{
|
||||
@@ -51,9 +56,11 @@ func TestGetToken_Do(t *testing.T) {
|
||||
|
||||
t.Run("NoTokenCache", func(t *testing.T) {
|
||||
tokenCacheKey := tokencache.Key{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
Provider: oidc.Provider{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
},
|
||||
}
|
||||
ctx := context.TODO()
|
||||
in := Input{
|
||||
@@ -82,16 +89,21 @@ func TestGetToken_Do(t *testing.T) {
|
||||
mockRepository.EXPECT().
|
||||
Save("/path/to/token-cache", tokenCacheKey, issuedTokenSet).
|
||||
Return(nil)
|
||||
mockReader := reader_mock.NewMockInterface(t)
|
||||
mockReader.EXPECT().
|
||||
Read().
|
||||
Return(credentialpluginInput, nil)
|
||||
mockWriter := writer_mock.NewMockInterface(t)
|
||||
mockWriter.EXPECT().
|
||||
Write(issuedOutput).
|
||||
Return(nil)
|
||||
u := GetToken{
|
||||
Authentication: mockAuthentication,
|
||||
TokenCacheRepository: mockRepository,
|
||||
Writer: mockWriter,
|
||||
Logger: logger.New(t),
|
||||
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
|
||||
Authentication: mockAuthentication,
|
||||
TokenCacheRepository: mockRepository,
|
||||
CredentialPluginReader: mockReader,
|
||||
CredentialPluginWriter: mockWriter,
|
||||
Logger: logger.New(t),
|
||||
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
|
||||
}
|
||||
if err := u.Do(ctx, in); err != nil {
|
||||
t.Errorf("Do returned error: %+v", err)
|
||||
@@ -103,10 +115,12 @@ func TestGetToken_Do(t *testing.T) {
|
||||
ROPCOption: &ropc.Option{Username: "YOUR_USERNAME"},
|
||||
}
|
||||
tokenCacheKey := tokencache.Key{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
Username: "YOUR_USERNAME",
|
||||
Provider: oidc.Provider{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
},
|
||||
Username: "YOUR_USERNAME",
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
@@ -136,16 +150,21 @@ func TestGetToken_Do(t *testing.T) {
|
||||
mockRepository.EXPECT().
|
||||
Save("/path/to/token-cache", tokenCacheKey, issuedTokenSet).
|
||||
Return(nil)
|
||||
mockReader := reader_mock.NewMockInterface(t)
|
||||
mockReader.EXPECT().
|
||||
Read().
|
||||
Return(credentialplugin.Input{ClientAuthenticationAPIVersion: "client.authentication.k8s.io/v1"}, nil)
|
||||
mockWriter := writer_mock.NewMockInterface(t)
|
||||
mockWriter.EXPECT().
|
||||
Write(issuedOutput).
|
||||
Return(nil)
|
||||
u := GetToken{
|
||||
Authentication: mockAuthentication,
|
||||
TokenCacheRepository: mockRepository,
|
||||
Writer: mockWriter,
|
||||
Logger: logger.New(t),
|
||||
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
|
||||
Authentication: mockAuthentication,
|
||||
TokenCacheRepository: mockRepository,
|
||||
CredentialPluginReader: mockReader,
|
||||
CredentialPluginWriter: mockWriter,
|
||||
Logger: logger.New(t),
|
||||
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
|
||||
}
|
||||
if err := u.Do(ctx, in); err != nil {
|
||||
t.Errorf("Do returned error: %+v", err)
|
||||
@@ -154,9 +173,11 @@ func TestGetToken_Do(t *testing.T) {
|
||||
|
||||
t.Run("HasValidIDToken", func(t *testing.T) {
|
||||
tokenCacheKey := tokencache.Key{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
Provider: oidc.Provider{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
},
|
||||
}
|
||||
|
||||
ctx := context.TODO()
|
||||
@@ -175,21 +196,28 @@ func TestGetToken_Do(t *testing.T) {
|
||||
Return(mockCloser, nil)
|
||||
mockRepository.EXPECT().
|
||||
FindByKey("/path/to/token-cache", tokencache.Key{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
Provider: oidc.Provider{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
},
|
||||
}).
|
||||
Return(&issuedTokenSet, nil)
|
||||
mockReader := reader_mock.NewMockInterface(t)
|
||||
mockReader.EXPECT().
|
||||
Read().
|
||||
Return(credentialpluginInput, nil)
|
||||
mockWriter := writer_mock.NewMockInterface(t)
|
||||
mockWriter.EXPECT().
|
||||
Write(issuedOutput).
|
||||
Return(nil)
|
||||
u := GetToken{
|
||||
Authentication: authentication_mock.NewMockInterface(t),
|
||||
TokenCacheRepository: mockRepository,
|
||||
Writer: mockWriter,
|
||||
Logger: logger.New(t),
|
||||
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
|
||||
Authentication: authentication_mock.NewMockInterface(t),
|
||||
TokenCacheRepository: mockRepository,
|
||||
CredentialPluginReader: mockReader,
|
||||
CredentialPluginWriter: mockWriter,
|
||||
Logger: logger.New(t),
|
||||
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
|
||||
}
|
||||
if err := u.Do(ctx, in); err != nil {
|
||||
t.Errorf("Do returned error: %+v", err)
|
||||
@@ -198,9 +226,11 @@ func TestGetToken_Do(t *testing.T) {
|
||||
|
||||
t.Run("AuthenticationError", func(t *testing.T) {
|
||||
tokenCacheKey := tokencache.Key{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
Provider: oidc.Provider{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
},
|
||||
}
|
||||
ctx := context.TODO()
|
||||
in := Input{
|
||||
@@ -225,17 +255,24 @@ func TestGetToken_Do(t *testing.T) {
|
||||
Return(mockCloser, nil)
|
||||
mockRepository.EXPECT().
|
||||
FindByKey("/path/to/token-cache", tokencache.Key{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
Provider: oidc.Provider{
|
||||
IssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
},
|
||||
}).
|
||||
Return(nil, errors.New("file not found"))
|
||||
mockReader := reader_mock.NewMockInterface(t)
|
||||
mockReader.EXPECT().
|
||||
Read().
|
||||
Return(credentialpluginInput, nil)
|
||||
u := GetToken{
|
||||
Authentication: mockAuthentication,
|
||||
TokenCacheRepository: mockRepository,
|
||||
Writer: writer_mock.NewMockInterface(t),
|
||||
Logger: logger.New(t),
|
||||
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
|
||||
Authentication: mockAuthentication,
|
||||
TokenCacheRepository: mockRepository,
|
||||
CredentialPluginReader: mockReader,
|
||||
CredentialPluginWriter: writer_mock.NewMockInterface(t),
|
||||
Logger: logger.New(t),
|
||||
Clock: clock.Fake(expiryTime.Add(-time.Hour)),
|
||||
}
|
||||
if err := u.Do(ctx, in); err == nil {
|
||||
t.Errorf("err wants non-nil but nil")
|
||||
|
||||
@@ -19,7 +19,8 @@ test: build
|
||||
--browser-command=$(BIN_DIR)/chromelogin
|
||||
# set up the kubeconfig
|
||||
kubectl config set-credentials oidc \
|
||||
--exec-api-version=client.authentication.k8s.io/v1beta1 \
|
||||
--exec-api-version=client.authentication.k8s.io/v1 \
|
||||
--exec-interactive-mode=Never \
|
||||
--exec-command=kubectl \
|
||||
--exec-arg=oidc-login \
|
||||
--exec-arg=get-token \
|
||||
|
||||
@@ -28,20 +28,29 @@ func main() {
|
||||
|
||||
func runBrowser(ctx context.Context, url string) error {
|
||||
execOpts := chromedp.DefaultExecAllocatorOptions[:]
|
||||
execOpts = append(execOpts, chromedp.NoSandbox)
|
||||
ctx, cancel := chromedp.NewExecAllocator(ctx, execOpts...)
|
||||
defer cancel()
|
||||
ctx, cancel = chromedp.NewContext(ctx, chromedp.WithLogf(log.Printf))
|
||||
defer cancel()
|
||||
ctx, cancel = context.WithTimeout(ctx, 30*time.Second)
|
||||
defer cancel()
|
||||
if err := logInToDex(ctx, url); err != nil {
|
||||
execOpts = append(execOpts,
|
||||
chromedp.NoSandbox,
|
||||
chromedp.WSURLReadTimeout(30*time.Second),
|
||||
)
|
||||
ctx, cancelExec := chromedp.NewExecAllocator(ctx, execOpts...)
|
||||
defer cancelExec()
|
||||
ctx, cancelCtx := chromedp.NewContext(ctx, chromedp.WithLogf(log.Printf))
|
||||
defer cancelCtx()
|
||||
log.Printf("Opening a new browser and navigating to %s", url)
|
||||
if err := openBrowser(ctx, url); err != nil {
|
||||
return fmt.Errorf("could not open a new browser: %w", err)
|
||||
}
|
||||
|
||||
ctx, cancelTimeout := context.WithTimeout(ctx, 30*time.Second)
|
||||
defer cancelTimeout()
|
||||
log.Printf("Logging in to Dex")
|
||||
if err := logInToDex(ctx); err != nil {
|
||||
return fmt.Errorf("could not run the browser: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func logInToDex(ctx context.Context, url string) error {
|
||||
func openBrowser(ctx context.Context, url string) error {
|
||||
for {
|
||||
var location string
|
||||
err := chromedp.Run(ctx,
|
||||
@@ -51,14 +60,16 @@ func logInToDex(ctx context.Context, url string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Printf("location: %s", location)
|
||||
log.Printf("Location: %s", location)
|
||||
if strings.HasPrefix(location, `http://`) || strings.HasPrefix(location, `https://`) {
|
||||
break
|
||||
return nil
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
err := chromedp.Run(ctx,
|
||||
func logInToDex(ctx context.Context) error {
|
||||
return chromedp.Run(ctx,
|
||||
// https://dex-server:10443/dex/auth/local
|
||||
chromedp.WaitVisible(`#login`),
|
||||
logPageMetadata(),
|
||||
@@ -73,10 +84,6 @@ func logInToDex(ctx context.Context, url string) error {
|
||||
chromedp.WaitReady(`body`),
|
||||
logPageMetadata(),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func logPageMetadata() chromedp.Action {
|
||||
@@ -86,7 +93,7 @@ func logPageMetadata() chromedp.Action {
|
||||
chromedp.Location(&location),
|
||||
chromedp.Title(&title),
|
||||
chromedp.ActionFunc(func(ctx context.Context) error {
|
||||
log.Printf("location: %s [%s]", location, title)
|
||||
log.Printf("Location: %s, Title: %s", location, title)
|
||||
return nil
|
||||
}),
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
module github.com/int128/kubelogin/tools
|
||||
|
||||
go 1.22.5
|
||||
go 1.23.2
|
||||
|
||||
require (
|
||||
github.com/google/wire v0.6.0
|
||||
github.com/vektra/mockery/v2 v2.46.0
|
||||
github.com/vektra/mockery/v2 v2.46.3
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
@@ -209,8 +209,8 @@ github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
|
||||
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/vektra/mockery/v2 v2.46.0 h1:DKIFj6hAPGwmOYiWfWzdsQtBgU8ozPXo3Bwbmf+Ku80=
|
||||
github.com/vektra/mockery/v2 v2.46.0/go.mod h1:XNTE9RIu3deGAGQRVjP1VZxGpQNm0YedZx4oDs3prr8=
|
||||
github.com/vektra/mockery/v2 v2.46.3 h1:Aia4iShZeNTy6CZJcvweK4X97XOzXcqb+k9jm8IqBS0=
|
||||
github.com/vektra/mockery/v2 v2.46.3/go.mod h1:dDivqi0ShM8A29mLgZn13yZ14MdXlTM4V360u8JDWCQ=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
|
||||
Reference in New Issue
Block a user