mirror of
https://github.com/int128/kubelogin.git
synced 2026-02-14 16:39:51 +00:00
Refactor: replace DTO with oidc.TokenSet type (#394)
* Refactor: remove IDTokenClaims from TokenSet and decode in use-cases * Refactor: use oidc.TokenSet for cache repository
This commit is contained in:
@@ -8,7 +8,6 @@ import (
|
||||
gooidc "github.com/coreos/go-oidc"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/clock"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/logger"
|
||||
"github.com/int128/kubelogin/pkg/jwt"
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
"github.com/int128/kubelogin/pkg/pkce"
|
||||
"github.com/int128/oauth2cli"
|
||||
@@ -184,17 +183,8 @@ func (c *client) verifyToken(ctx context.Context, token *oauth2.Token, nonce str
|
||||
if nonce != "" && nonce != verifiedIDToken.Nonce {
|
||||
return nil, xerrors.Errorf("nonce did not match (wants %s but got %s)", nonce, verifiedIDToken.Nonce)
|
||||
}
|
||||
pretty, err := jwt.DecodePayloadAsPrettyJSON(idToken)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not decode the token: %w", err)
|
||||
}
|
||||
return &oidc.TokenSet{
|
||||
IDToken: idToken,
|
||||
IDTokenClaims: jwt.Claims{
|
||||
Subject: verifiedIDToken.Subject,
|
||||
Expiry: verifiedIDToken.Expiry,
|
||||
Pretty: pretty,
|
||||
},
|
||||
IDToken: idToken,
|
||||
RefreshToken: token.RefreshToken,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ package mock_tokencache
|
||||
import (
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
tokencache "github.com/int128/kubelogin/pkg/adaptors/tokencache"
|
||||
oidc "github.com/int128/kubelogin/pkg/oidc"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
@@ -34,10 +35,10 @@ func (m *MockInterface) EXPECT() *MockInterfaceMockRecorder {
|
||||
}
|
||||
|
||||
// FindByKey mocks base method.
|
||||
func (m *MockInterface) FindByKey(arg0 string, arg1 tokencache.Key) (*tokencache.Value, error) {
|
||||
func (m *MockInterface) FindByKey(arg0 string, arg1 tokencache.Key) (*oidc.TokenSet, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FindByKey", arg0, arg1)
|
||||
ret0, _ := ret[0].(*tokencache.Value)
|
||||
ret0, _ := ret[0].(*oidc.TokenSet)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@@ -49,7 +50,7 @@ func (mr *MockInterfaceMockRecorder) FindByKey(arg0, arg1 interface{}) *gomock.C
|
||||
}
|
||||
|
||||
// Save mocks base method.
|
||||
func (m *MockInterface) Save(arg0 string, arg1 tokencache.Key, arg2 tokencache.Value) error {
|
||||
func (m *MockInterface) Save(arg0 string, arg1 tokencache.Key, arg2 oidc.TokenSet) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Save", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/google/wire"
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
@@ -21,8 +22,8 @@ var Set = wire.NewSet(
|
||||
)
|
||||
|
||||
type Interface interface {
|
||||
FindByKey(dir string, key Key) (*Value, error)
|
||||
Save(dir string, key Key, value Value) error
|
||||
FindByKey(dir string, key Key) (*oidc.TokenSet, error)
|
||||
Save(dir string, key Key, tokenSet oidc.TokenSet) error
|
||||
}
|
||||
|
||||
// Key represents a key of a token cache.
|
||||
@@ -36,8 +37,7 @@ type Key struct {
|
||||
SkipTLSVerify bool
|
||||
}
|
||||
|
||||
// Value represents a value of a token cache.
|
||||
type Value struct {
|
||||
type entity struct {
|
||||
IDToken string `json:"id_token,omitempty"`
|
||||
RefreshToken string `json:"refresh_token,omitempty"`
|
||||
}
|
||||
@@ -46,7 +46,7 @@ type Value struct {
|
||||
// Filename of a token cache is sha256 digest of the issuer, zero-character and client ID.
|
||||
type Repository struct{}
|
||||
|
||||
func (r *Repository) FindByKey(dir string, key Key) (*Value, error) {
|
||||
func (r *Repository) FindByKey(dir string, key Key) (*oidc.TokenSet, error) {
|
||||
filename, err := computeFilename(key)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("could not compute the key: %w", err)
|
||||
@@ -58,14 +58,17 @@ func (r *Repository) FindByKey(dir string, key Key) (*Value, error) {
|
||||
}
|
||||
defer f.Close()
|
||||
d := json.NewDecoder(f)
|
||||
var c Value
|
||||
if err := d.Decode(&c); err != nil {
|
||||
var e entity
|
||||
if err := d.Decode(&e); err != nil {
|
||||
return nil, xerrors.Errorf("invalid json file %s: %w", p, err)
|
||||
}
|
||||
return &c, nil
|
||||
return &oidc.TokenSet{
|
||||
IDToken: e.IDToken,
|
||||
RefreshToken: e.RefreshToken,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *Repository) Save(dir string, key Key, value Value) error {
|
||||
func (r *Repository) Save(dir string, key Key, tokenSet oidc.TokenSet) error {
|
||||
if err := os.MkdirAll(dir, 0700); err != nil {
|
||||
return xerrors.Errorf("could not create directory %s: %w", dir, err)
|
||||
}
|
||||
@@ -79,8 +82,11 @@ func (r *Repository) Save(dir string, key Key, value Value) error {
|
||||
return xerrors.Errorf("could not create file %s: %w", p, err)
|
||||
}
|
||||
defer f.Close()
|
||||
e := json.NewEncoder(f)
|
||||
if err := e.Encode(&value); err != nil {
|
||||
e := entity{
|
||||
IDToken: tokenSet.IDToken,
|
||||
RefreshToken: tokenSet.RefreshToken,
|
||||
}
|
||||
if err := json.NewEncoder(f).Encode(&e); err != nil {
|
||||
return xerrors.Errorf("json encode error: %w", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
)
|
||||
|
||||
func TestRepository_FindByKey(t *testing.T) {
|
||||
@@ -31,12 +32,12 @@ func TestRepository_FindByKey(t *testing.T) {
|
||||
t.Fatalf("could not write to the temp file: %s", err)
|
||||
}
|
||||
|
||||
value, err := r.FindByKey(dir, key)
|
||||
got, err := r.FindByKey(dir, key)
|
||||
if err != nil {
|
||||
t.Errorf("err wants nil but %+v", err)
|
||||
}
|
||||
want := &Value{IDToken: "YOUR_ID_TOKEN", RefreshToken: "YOUR_REFRESH_TOKEN"}
|
||||
if diff := cmp.Diff(want, value); diff != "" {
|
||||
want := &oidc.TokenSet{IDToken: "YOUR_ID_TOKEN", RefreshToken: "YOUR_REFRESH_TOKEN"}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
@@ -55,8 +56,8 @@ func TestRepository_Save(t *testing.T) {
|
||||
CACertFilename: "/path/to/cert",
|
||||
SkipTLSVerify: false,
|
||||
}
|
||||
value := Value{IDToken: "YOUR_ID_TOKEN", RefreshToken: "YOUR_REFRESH_TOKEN"}
|
||||
if err := r.Save(dir, key, value); err != nil {
|
||||
tokenSet := oidc.TokenSet{IDToken: "YOUR_ID_TOKEN", RefreshToken: "YOUR_REFRESH_TOKEN"}
|
||||
if err := r.Save(dir, key, tokenSet); err != nil {
|
||||
t.Errorf("err wants nil but %+v", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -20,12 +20,14 @@ type Provider struct {
|
||||
SkipTLSVerify bool // optional
|
||||
}
|
||||
|
||||
// TokenSet represents an output DTO of
|
||||
// Interface.GetTokenByAuthCode, Interface.GetTokenByROPC and Interface.Refresh.
|
||||
// TokenSet represents a set of ID token and refresh token.
|
||||
type TokenSet struct {
|
||||
IDToken string
|
||||
RefreshToken string
|
||||
IDTokenClaims jwt.Claims
|
||||
IDToken string
|
||||
RefreshToken string
|
||||
}
|
||||
|
||||
func (ts TokenSet) DecodeWithoutVerify() (*jwt.Claims, error) {
|
||||
return jwt.DecodeWithoutVerify(ts.IDToken)
|
||||
}
|
||||
|
||||
func NewState() (string, error) {
|
||||
|
||||
@@ -10,17 +10,11 @@ import (
|
||||
"github.com/int128/kubelogin/pkg/adaptors/browser/mock_browser"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/oidcclient"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/oidcclient/mock_oidcclient"
|
||||
"github.com/int128/kubelogin/pkg/jwt"
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
"github.com/int128/kubelogin/pkg/testing/logger"
|
||||
)
|
||||
|
||||
func TestBrowser_Do(t *testing.T) {
|
||||
dummyTokenClaims := jwt.Claims{
|
||||
Subject: "YOUR_SUBJECT",
|
||||
Expiry: time.Date(2019, 1, 2, 3, 4, 5, 0, time.UTC),
|
||||
Pretty: "PRETTY_JSON",
|
||||
}
|
||||
timeout := 5 * time.Second
|
||||
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
@@ -64,9 +58,8 @@ func TestBrowser_Do(t *testing.T) {
|
||||
readyChan <- "LOCAL_SERVER_URL"
|
||||
}).
|
||||
Return(&oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}, nil)
|
||||
u := Browser{
|
||||
Logger: logger.New(t),
|
||||
@@ -76,9 +69,8 @@ func TestBrowser_Do(t *testing.T) {
|
||||
t.Errorf("Do returned error: %+v", err)
|
||||
}
|
||||
want := &oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("mismatch (-want +got):\n%s", diff)
|
||||
@@ -102,9 +94,8 @@ func TestBrowser_Do(t *testing.T) {
|
||||
readyChan <- "LOCAL_SERVER_URL"
|
||||
}).
|
||||
Return(&oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}, nil)
|
||||
mockBrowser := mock_browser.NewMockInterface(ctrl)
|
||||
mockBrowser.EXPECT().
|
||||
@@ -118,9 +109,8 @@ func TestBrowser_Do(t *testing.T) {
|
||||
t.Errorf("Do returned error: %+v", err)
|
||||
}
|
||||
want := &oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("mismatch (-want +got):\n%s", diff)
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/int128/kubelogin/pkg/adaptors/oidcclient"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/oidcclient/mock_oidcclient"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/reader/mock_reader"
|
||||
"github.com/int128/kubelogin/pkg/jwt"
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
"github.com/int128/kubelogin/pkg/testing/logger"
|
||||
)
|
||||
@@ -18,11 +17,6 @@ import (
|
||||
var nonNil = gomock.Not(gomock.Nil())
|
||||
|
||||
func TestKeyboard_Do(t *testing.T) {
|
||||
dummyTokenClaims := jwt.Claims{
|
||||
Subject: "YOUR_SUBJECT",
|
||||
Expiry: time.Date(2019, 1, 2, 3, 4, 5, 0, time.UTC),
|
||||
Pretty: "PRETTY_JSON",
|
||||
}
|
||||
timeout := 5 * time.Second
|
||||
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
@@ -51,9 +45,8 @@ func TestKeyboard_Do(t *testing.T) {
|
||||
}
|
||||
}).
|
||||
Return(&oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}, nil)
|
||||
mockReader := mock_reader.NewMockInterface(ctrl)
|
||||
mockReader.EXPECT().
|
||||
@@ -68,9 +61,8 @@ func TestKeyboard_Do(t *testing.T) {
|
||||
t.Errorf("Do returned error: %+v", err)
|
||||
}
|
||||
want := &oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("mismatch (-want +got):\n%s", diff)
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/int128/kubelogin/pkg/adaptors/clock"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/logger"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/oidcclient"
|
||||
"github.com/int128/kubelogin/pkg/jwt"
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
"github.com/int128/kubelogin/pkg/usecases/authentication/authcode"
|
||||
"github.com/int128/kubelogin/pkg/usecases/authentication/ropc"
|
||||
@@ -32,9 +31,8 @@ type Interface interface {
|
||||
// Input represents an input DTO of the Authentication use-case.
|
||||
type Input struct {
|
||||
Provider oidc.Provider
|
||||
IDToken string // optional, from the token cache
|
||||
RefreshToken string // optional, from the token cache
|
||||
GrantOptionSet GrantOptionSet
|
||||
CachedTokenSet *oidc.TokenSet // optional
|
||||
}
|
||||
|
||||
type GrantOptionSet struct {
|
||||
@@ -72,12 +70,12 @@ type Authentication struct {
|
||||
}
|
||||
|
||||
func (u *Authentication) Do(ctx context.Context, in Input) (*Output, error) {
|
||||
if in.IDToken != "" {
|
||||
if in.CachedTokenSet != nil {
|
||||
u.Logger.V(1).Infof("checking expiration of the existing token")
|
||||
// Skip verification of the token to reduce time of a discovery request.
|
||||
// Here it trusts the signature and claims and checks only expiration,
|
||||
// because the token has been verified before caching.
|
||||
claims, err := jwt.DecodeWithoutVerify(in.IDToken)
|
||||
claims, err := in.CachedTokenSet.DecodeWithoutVerify()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("invalid token cache (you may need to remove): %w", err)
|
||||
}
|
||||
@@ -85,11 +83,7 @@ func (u *Authentication) Do(ctx context.Context, in Input) (*Output, error) {
|
||||
u.Logger.V(1).Infof("you already have a valid token until %s", claims.Expiry)
|
||||
return &Output{
|
||||
AlreadyHasValidIDToken: true,
|
||||
TokenSet: oidc.TokenSet{
|
||||
IDToken: in.IDToken,
|
||||
RefreshToken: in.RefreshToken,
|
||||
IDTokenClaims: *claims,
|
||||
},
|
||||
TokenSet: *in.CachedTokenSet,
|
||||
}, nil
|
||||
}
|
||||
u.Logger.V(1).Infof("you have an expired token at %s", claims.Expiry)
|
||||
@@ -101,17 +95,11 @@ func (u *Authentication) Do(ctx context.Context, in Input) (*Output, error) {
|
||||
return nil, xerrors.Errorf("oidc error: %w", err)
|
||||
}
|
||||
|
||||
if in.RefreshToken != "" {
|
||||
if in.CachedTokenSet != nil && in.CachedTokenSet.RefreshToken != "" {
|
||||
u.Logger.V(1).Infof("refreshing the token")
|
||||
out, err := client.Refresh(ctx, in.RefreshToken)
|
||||
tokenSet, err := client.Refresh(ctx, in.CachedTokenSet.RefreshToken)
|
||||
if err == nil {
|
||||
return &Output{
|
||||
TokenSet: oidc.TokenSet{
|
||||
IDToken: out.IDToken,
|
||||
IDTokenClaims: out.IDTokenClaims,
|
||||
RefreshToken: out.RefreshToken,
|
||||
},
|
||||
}, nil
|
||||
return &Output{TokenSet: *tokenSet}, nil
|
||||
}
|
||||
u.Logger.V(1).Infof("could not refresh the token: %s", err)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/oidcclient"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/oidcclient/mock_oidcclient"
|
||||
"github.com/int128/kubelogin/pkg/jwt"
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
"github.com/int128/kubelogin/pkg/testing/clock"
|
||||
testingJWT "github.com/int128/kubelogin/pkg/testing/jwt"
|
||||
@@ -27,16 +26,11 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
}
|
||||
cachedIDToken := testingJWT.EncodeF(t, func(claims *testingJWT.Claims) {
|
||||
claims.Issuer = "https://issuer.example.com"
|
||||
claims.Subject = "SUBJECT"
|
||||
issuedIDToken := testingJWT.EncodeF(t, func(claims *testingJWT.Claims) {
|
||||
claims.Issuer = "https://accounts.google.com"
|
||||
claims.Subject = "YOUR_SUBJECT"
|
||||
claims.ExpiresAt = expiryTime.Unix()
|
||||
})
|
||||
dummyClaims := jwt.Claims{
|
||||
Subject: "SUBJECT",
|
||||
Expiry: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
Pretty: "PRETTY_JSON",
|
||||
}
|
||||
|
||||
t.Run("HasValidIDToken", func(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
@@ -45,7 +39,9 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
defer cancel()
|
||||
in := Input{
|
||||
Provider: dummyProvider,
|
||||
IDToken: cachedIDToken,
|
||||
CachedTokenSet: &oidc.TokenSet{
|
||||
IDToken: issuedIDToken,
|
||||
},
|
||||
}
|
||||
u := Authentication{
|
||||
Logger: testingLogger.New(t),
|
||||
@@ -58,16 +54,7 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
want := &Output{
|
||||
AlreadyHasValidIDToken: true,
|
||||
TokenSet: oidc.TokenSet{
|
||||
IDToken: cachedIDToken,
|
||||
IDTokenClaims: jwt.Claims{
|
||||
Subject: "SUBJECT",
|
||||
Expiry: expiryTime,
|
||||
Pretty: `{
|
||||
"exp": 1577934245,
|
||||
"iss": "https://issuer.example.com",
|
||||
"sub": "SUBJECT"
|
||||
}`,
|
||||
},
|
||||
IDToken: issuedIDToken,
|
||||
},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
@@ -81,17 +68,18 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
|
||||
defer cancel()
|
||||
in := Input{
|
||||
Provider: dummyProvider,
|
||||
IDToken: cachedIDToken,
|
||||
RefreshToken: "VALID_REFRESH_TOKEN",
|
||||
Provider: dummyProvider,
|
||||
CachedTokenSet: &oidc.TokenSet{
|
||||
IDToken: issuedIDToken,
|
||||
RefreshToken: "VALID_REFRESH_TOKEN",
|
||||
},
|
||||
}
|
||||
mockOIDCClient := mock_oidcclient.NewMockInterface(ctrl)
|
||||
mockOIDCClient.EXPECT().
|
||||
Refresh(ctx, "VALID_REFRESH_TOKEN").
|
||||
Return(&oidc.TokenSet{
|
||||
IDToken: "NEW_ID_TOKEN",
|
||||
RefreshToken: "NEW_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyClaims,
|
||||
IDToken: "NEW_ID_TOKEN",
|
||||
RefreshToken: "NEW_REFRESH_TOKEN",
|
||||
}, nil)
|
||||
u := Authentication{
|
||||
OIDCClient: &oidcclientFactory{
|
||||
@@ -112,9 +100,8 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
}
|
||||
want := &Output{
|
||||
TokenSet: oidc.TokenSet{
|
||||
IDToken: "NEW_ID_TOKEN",
|
||||
RefreshToken: "NEW_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyClaims,
|
||||
IDToken: "NEW_ID_TOKEN",
|
||||
RefreshToken: "NEW_REFRESH_TOKEN",
|
||||
},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
@@ -128,6 +115,7 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
|
||||
defer cancel()
|
||||
in := Input{
|
||||
Provider: dummyProvider,
|
||||
GrantOptionSet: GrantOptionSet{
|
||||
AuthCodeBrowserOption: &authcode.BrowserOption{
|
||||
BindAddress: []string{"127.0.0.1:8000"},
|
||||
@@ -135,9 +123,10 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
AuthenticationTimeout: 10 * time.Second,
|
||||
},
|
||||
},
|
||||
Provider: dummyProvider,
|
||||
IDToken: cachedIDToken,
|
||||
RefreshToken: "EXPIRED_REFRESH_TOKEN",
|
||||
CachedTokenSet: &oidc.TokenSet{
|
||||
IDToken: issuedIDToken,
|
||||
RefreshToken: "EXPIRED_REFRESH_TOKEN",
|
||||
},
|
||||
}
|
||||
mockOIDCClient := mock_oidcclient.NewMockInterface(ctrl)
|
||||
mockOIDCClient.EXPECT().SupportedPKCEMethods()
|
||||
@@ -150,9 +139,8 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
readyChan <- "LOCAL_SERVER_URL"
|
||||
}).
|
||||
Return(&oidc.TokenSet{
|
||||
IDToken: "NEW_ID_TOKEN",
|
||||
RefreshToken: "NEW_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyClaims,
|
||||
IDToken: "NEW_ID_TOKEN",
|
||||
RefreshToken: "NEW_REFRESH_TOKEN",
|
||||
}, nil)
|
||||
u := Authentication{
|
||||
OIDCClient: &oidcclientFactory{
|
||||
@@ -176,9 +164,8 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
}
|
||||
want := &Output{
|
||||
TokenSet: oidc.TokenSet{
|
||||
IDToken: "NEW_ID_TOKEN",
|
||||
RefreshToken: "NEW_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyClaims,
|
||||
IDToken: "NEW_ID_TOKEN",
|
||||
RefreshToken: "NEW_REFRESH_TOKEN",
|
||||
},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
@@ -204,9 +191,8 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
mockOIDCClient.EXPECT().
|
||||
GetTokenByROPC(gomock.Any(), "USER", "PASS").
|
||||
Return(&oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyClaims,
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}, nil)
|
||||
u := Authentication{
|
||||
OIDCClient: &oidcclientFactory{
|
||||
@@ -229,9 +215,8 @@ func TestAuthentication_Do(t *testing.T) {
|
||||
}
|
||||
want := &Output{
|
||||
TokenSet: oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyClaims,
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
},
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
|
||||
@@ -9,18 +9,12 @@ import (
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/oidcclient/mock_oidcclient"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/reader/mock_reader"
|
||||
"github.com/int128/kubelogin/pkg/jwt"
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
"github.com/int128/kubelogin/pkg/testing/logger"
|
||||
"golang.org/x/xerrors"
|
||||
)
|
||||
|
||||
func TestROPC_Do(t *testing.T) {
|
||||
dummyTokenClaims := jwt.Claims{
|
||||
Subject: "YOUR_SUBJECT",
|
||||
Expiry: time.Date(2019, 1, 2, 3, 4, 5, 0, time.UTC),
|
||||
Pretty: "PRETTY_JSON",
|
||||
}
|
||||
timeout := 5 * time.Second
|
||||
|
||||
t.Run("AskUsernameAndPassword", func(t *testing.T) {
|
||||
@@ -33,9 +27,8 @@ func TestROPC_Do(t *testing.T) {
|
||||
mockOIDCClient.EXPECT().
|
||||
GetTokenByROPC(gomock.Any(), "USER", "PASS").
|
||||
Return(&oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}, nil)
|
||||
mockReader := mock_reader.NewMockInterface(ctrl)
|
||||
mockReader.EXPECT().ReadString(usernamePrompt).Return("USER", nil)
|
||||
@@ -49,9 +42,8 @@ func TestROPC_Do(t *testing.T) {
|
||||
t.Errorf("Do returned error: %+v", err)
|
||||
}
|
||||
want := &oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("mismatch (-want +got):\n%s", diff)
|
||||
@@ -71,9 +63,8 @@ func TestROPC_Do(t *testing.T) {
|
||||
mockOIDCClient.EXPECT().
|
||||
GetTokenByROPC(gomock.Any(), "USER", "PASS").
|
||||
Return(&oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}, nil)
|
||||
u := ROPC{
|
||||
Logger: logger.New(t),
|
||||
@@ -83,9 +74,8 @@ func TestROPC_Do(t *testing.T) {
|
||||
t.Errorf("Do returned error: %+v", err)
|
||||
}
|
||||
want := &oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("mismatch (-want +got):\n%s", diff)
|
||||
@@ -104,9 +94,8 @@ func TestROPC_Do(t *testing.T) {
|
||||
mockOIDCClient.EXPECT().
|
||||
GetTokenByROPC(gomock.Any(), "USER", "PASS").
|
||||
Return(&oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}, nil)
|
||||
mockEnv := mock_reader.NewMockInterface(ctrl)
|
||||
mockEnv.EXPECT().ReadPassword(passwordPrompt).Return("PASS", nil)
|
||||
@@ -119,9 +108,8 @@ func TestROPC_Do(t *testing.T) {
|
||||
t.Errorf("Do returned error: %+v", err)
|
||||
}
|
||||
want := &oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}
|
||||
if diff := cmp.Diff(want, got); diff != "" {
|
||||
t.Errorf("mismatch (-want +got):\n%s", diff)
|
||||
|
||||
@@ -50,18 +50,7 @@ type GetToken struct {
|
||||
|
||||
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")
|
||||
out, err := u.getTokenFromCacheOrProvider(ctx, in)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("could not get a token: %w", err)
|
||||
}
|
||||
u.Logger.V(1).Infof("writing the token to client-go")
|
||||
if err := u.Writer.Write(credentialpluginwriter.Output{Token: out.TokenSet.IDToken, Expiry: out.TokenSet.IDTokenClaims.Expiry}); err != nil {
|
||||
return xerrors.Errorf("could not write the token to client-go: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *GetToken) getTokenFromCacheOrProvider(ctx context.Context, in Input) (*authentication.Output, error) {
|
||||
u.Logger.V(1).Infof("finding a token from cache directory %s", in.TokenCacheDir)
|
||||
tokenCacheKey := tokencache.Key{
|
||||
IssuerURL: in.IssuerURL,
|
||||
@@ -72,20 +61,19 @@ func (u *GetToken) getTokenFromCacheOrProvider(ctx context.Context, in Input) (*
|
||||
CACertData: in.CACertData,
|
||||
SkipTLSVerify: in.SkipTLSVerify,
|
||||
}
|
||||
tokenCacheValue, err := u.TokenCacheRepository.FindByKey(in.TokenCacheDir, tokenCacheKey)
|
||||
cachedTokenSet, err := u.TokenCacheRepository.FindByKey(in.TokenCacheDir, tokenCacheKey)
|
||||
if err != nil {
|
||||
u.Logger.V(1).Infof("could not find a token cache: %s", err)
|
||||
tokenCacheValue = &tokencache.Value{}
|
||||
}
|
||||
certPool := u.NewCertPool()
|
||||
if in.CACertFilename != "" {
|
||||
if err := certPool.AddFile(in.CACertFilename); err != nil {
|
||||
return nil, xerrors.Errorf("could not load the certificate file: %w", err)
|
||||
return xerrors.Errorf("could not load the certificate file: %w", err)
|
||||
}
|
||||
}
|
||||
if in.CACertData != "" {
|
||||
if err := certPool.AddBase64Encoded(in.CACertData); err != nil {
|
||||
return nil, xerrors.Errorf("could not load the certificate data: %w", err)
|
||||
return xerrors.Errorf("could not load the certificate data: %w", err)
|
||||
}
|
||||
}
|
||||
out, err := u.Authentication.Do(ctx, authentication.Input{
|
||||
@@ -97,26 +85,33 @@ func (u *GetToken) getTokenFromCacheOrProvider(ctx context.Context, in Input) (*
|
||||
CertPool: certPool,
|
||||
SkipTLSVerify: in.SkipTLSVerify,
|
||||
},
|
||||
IDToken: tokenCacheValue.IDToken,
|
||||
RefreshToken: tokenCacheValue.RefreshToken,
|
||||
GrantOptionSet: in.GrantOptionSet,
|
||||
CachedTokenSet: cachedTokenSet,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("authentication error: %w", err)
|
||||
return xerrors.Errorf("authentication error: %w", err)
|
||||
}
|
||||
u.Logger.V(1).Infof("you got a token: %s", out.TokenSet.IDTokenClaims.Pretty)
|
||||
idTokenClaims, err := out.TokenSet.DecodeWithoutVerify()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("you got an invalid token: %w", err)
|
||||
}
|
||||
u.Logger.V(1).Infof("you got a token: %s", idTokenClaims.Pretty)
|
||||
if out.AlreadyHasValidIDToken {
|
||||
u.Logger.V(1).Infof("you already have a valid token until %s", out.TokenSet.IDTokenClaims.Expiry)
|
||||
return out, nil
|
||||
u.Logger.V(1).Infof("you already have a valid token until %s", idTokenClaims.Expiry)
|
||||
u.Logger.V(1).Infof("writing the token to client-go")
|
||||
if err := u.Writer.Write(credentialpluginwriter.Output{Token: out.TokenSet.IDToken, Expiry: idTokenClaims.Expiry}); err != nil {
|
||||
return xerrors.Errorf("could not write the token to client-go: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
u.Logger.V(1).Infof("you got a valid token until %s", out.TokenSet.IDTokenClaims.Expiry)
|
||||
newTokenCacheValue := tokencache.Value{
|
||||
IDToken: out.TokenSet.IDToken,
|
||||
RefreshToken: out.TokenSet.RefreshToken,
|
||||
u.Logger.V(1).Infof("you got a valid token until %s", idTokenClaims.Expiry)
|
||||
if err := u.TokenCacheRepository.Save(in.TokenCacheDir, tokenCacheKey, out.TokenSet); err != nil {
|
||||
return xerrors.Errorf("could not write the token cache: %w", err)
|
||||
}
|
||||
if err := u.TokenCacheRepository.Save(in.TokenCacheDir, tokenCacheKey, newTokenCacheValue); err != nil {
|
||||
return nil, xerrors.Errorf("could not write the token cache: %w", err)
|
||||
u.Logger.V(1).Infof("writing the token to client-go")
|
||||
if err := u.Writer.Write(credentialpluginwriter.Output{Token: out.TokenSet.IDToken, Expiry: idTokenClaims.Expiry}); err != nil {
|
||||
return xerrors.Errorf("could not write the token to client-go: %w", err)
|
||||
}
|
||||
return out, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -12,8 +12,8 @@ import (
|
||||
"github.com/int128/kubelogin/pkg/adaptors/credentialpluginwriter/mock_credentialpluginwriter"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/tokencache"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/tokencache/mock_tokencache"
|
||||
"github.com/int128/kubelogin/pkg/jwt"
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
testingJWT "github.com/int128/kubelogin/pkg/testing/jwt"
|
||||
"github.com/int128/kubelogin/pkg/testing/logger"
|
||||
"github.com/int128/kubelogin/pkg/usecases/authentication"
|
||||
"github.com/int128/kubelogin/pkg/usecases/authentication/mock_authentication"
|
||||
@@ -21,11 +21,12 @@ import (
|
||||
)
|
||||
|
||||
func TestGetToken_Do(t *testing.T) {
|
||||
dummyTokenClaims := jwt.Claims{
|
||||
Subject: "YOUR_SUBJECT",
|
||||
Expiry: time.Date(2019, 1, 2, 3, 4, 5, 0, time.UTC),
|
||||
Pretty: "PRETTY_JSON",
|
||||
}
|
||||
issuedIDTokenExpiration := time.Now().Add(1 * time.Hour).Round(time.Second)
|
||||
issuedIDToken := testingJWT.EncodeF(t, func(claims *testingJWT.Claims) {
|
||||
claims.Issuer = "https://accounts.google.com"
|
||||
claims.Subject = "YOUR_SUBJECT"
|
||||
claims.ExpiresAt = issuedIDTokenExpiration.Unix()
|
||||
})
|
||||
|
||||
t.Run("FullOptions", func(t *testing.T) {
|
||||
var grantOptionSet authentication.GrantOptionSet
|
||||
@@ -61,9 +62,8 @@ func TestGetToken_Do(t *testing.T) {
|
||||
}).
|
||||
Return(&authentication.Output{
|
||||
TokenSet: oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: issuedIDToken,
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
},
|
||||
}, nil)
|
||||
tokenCacheRepository := mock_tokencache.NewMockInterface(ctrl)
|
||||
@@ -88,15 +88,15 @@ func TestGetToken_Do(t *testing.T) {
|
||||
CACertData: "BASE64ENCODED",
|
||||
SkipTLSVerify: true,
|
||||
},
|
||||
tokencache.Value{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
oidc.TokenSet{
|
||||
IDToken: issuedIDToken,
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
})
|
||||
credentialPluginWriter := mock_credentialpluginwriter.NewMockInterface(ctrl)
|
||||
credentialPluginWriter.EXPECT().
|
||||
Write(credentialpluginwriter.Output{
|
||||
Token: "YOUR_ID_TOKEN",
|
||||
Expiry: dummyTokenClaims.Expiry,
|
||||
Token: issuedIDToken,
|
||||
Expiry: issuedIDTokenExpiration,
|
||||
})
|
||||
u := GetToken{
|
||||
Authentication: mockAuthentication,
|
||||
@@ -130,13 +130,14 @@ func TestGetToken_Do(t *testing.T) {
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
CertPool: mockCertPool,
|
||||
},
|
||||
IDToken: "VALID_ID_TOKEN",
|
||||
CachedTokenSet: &oidc.TokenSet{
|
||||
IDToken: issuedIDToken,
|
||||
},
|
||||
}).
|
||||
Return(&authentication.Output{
|
||||
AlreadyHasValidIDToken: true,
|
||||
TokenSet: oidc.TokenSet{
|
||||
IDToken: "VALID_ID_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: issuedIDToken,
|
||||
},
|
||||
}, nil)
|
||||
tokenCacheRepository := mock_tokencache.NewMockInterface(ctrl)
|
||||
@@ -146,14 +147,14 @@ func TestGetToken_Do(t *testing.T) {
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
}).
|
||||
Return(&tokencache.Value{
|
||||
IDToken: "VALID_ID_TOKEN",
|
||||
Return(&oidc.TokenSet{
|
||||
IDToken: issuedIDToken,
|
||||
}, nil)
|
||||
credentialPluginWriter := mock_credentialpluginwriter.NewMockInterface(ctrl)
|
||||
credentialPluginWriter.EXPECT().
|
||||
Write(credentialpluginwriter.Output{
|
||||
Token: "VALID_ID_TOKEN",
|
||||
Expiry: dummyTokenClaims.Expiry,
|
||||
Token: issuedIDToken,
|
||||
Expiry: issuedIDTokenExpiration,
|
||||
})
|
||||
u := GetToken{
|
||||
Authentication: mockAuthentication,
|
||||
|
||||
@@ -106,13 +106,17 @@ func (u *Setup) DoStage2(ctx context.Context, in Stage2Input) error {
|
||||
if err != nil {
|
||||
return xerrors.Errorf("authentication error: %w", err)
|
||||
}
|
||||
idTokenClaims, err := out.TokenSet.DecodeWithoutVerify()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("you got an invalid token: %w", err)
|
||||
}
|
||||
|
||||
v := stage2Vars{
|
||||
IDTokenPrettyJSON: out.TokenSet.IDTokenClaims.Pretty,
|
||||
IDTokenPrettyJSON: idTokenClaims.Pretty,
|
||||
IssuerURL: in.IssuerURL,
|
||||
ClientID: in.ClientID,
|
||||
Args: makeCredentialPluginArgs(in),
|
||||
Subject: out.TokenSet.IDTokenClaims.Subject,
|
||||
Subject: idTokenClaims.Subject,
|
||||
}
|
||||
var b strings.Builder
|
||||
if err := stage2Tpl.Execute(&b, &v); err != nil {
|
||||
|
||||
@@ -8,14 +8,20 @@ import (
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/certpool"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/certpool/mock_certpool"
|
||||
"github.com/int128/kubelogin/pkg/jwt"
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
testingJWT "github.com/int128/kubelogin/pkg/testing/jwt"
|
||||
"github.com/int128/kubelogin/pkg/testing/logger"
|
||||
"github.com/int128/kubelogin/pkg/usecases/authentication"
|
||||
"github.com/int128/kubelogin/pkg/usecases/authentication/mock_authentication"
|
||||
)
|
||||
|
||||
func TestSetup_DoStage2(t *testing.T) {
|
||||
issuedIDToken := testingJWT.EncodeF(t, func(claims *testingJWT.Claims) {
|
||||
claims.Issuer = "https://issuer.example.com"
|
||||
claims.Subject = "YOUR_SUBJECT"
|
||||
claims.ExpiresAt = time.Now().Add(1 * time.Hour).Unix()
|
||||
})
|
||||
|
||||
var grantOptionSet authentication.GrantOptionSet
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
@@ -49,13 +55,8 @@ func TestSetup_DoStage2(t *testing.T) {
|
||||
}).
|
||||
Return(&authentication.Output{
|
||||
TokenSet: oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
IDToken: issuedIDToken,
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: jwt.Claims{
|
||||
Subject: "YOUR_SUBJECT",
|
||||
Expiry: time.Date(2019, 1, 2, 3, 4, 5, 0, time.UTC),
|
||||
Pretty: "PRETTY_JSON",
|
||||
},
|
||||
},
|
||||
}, nil)
|
||||
u := Setup{
|
||||
|
||||
@@ -94,6 +94,13 @@ func (u *Standalone) Do(ctx context.Context, in Input) error {
|
||||
return xerrors.Errorf("could not load the certificate data: %w", err)
|
||||
}
|
||||
}
|
||||
var cachedTokenSet *oidc.TokenSet
|
||||
if authProvider.IDToken != "" {
|
||||
cachedTokenSet = &oidc.TokenSet{
|
||||
IDToken: authProvider.IDToken,
|
||||
RefreshToken: authProvider.RefreshToken,
|
||||
}
|
||||
}
|
||||
out, err := u.Authentication.Do(ctx, authentication.Input{
|
||||
Provider: oidc.Provider{
|
||||
IssuerURL: authProvider.IDPIssuerURL,
|
||||
@@ -103,20 +110,23 @@ func (u *Standalone) Do(ctx context.Context, in Input) error {
|
||||
CertPool: certPool,
|
||||
SkipTLSVerify: in.SkipTLSVerify,
|
||||
},
|
||||
IDToken: authProvider.IDToken,
|
||||
RefreshToken: authProvider.RefreshToken,
|
||||
GrantOptionSet: in.GrantOptionSet,
|
||||
CachedTokenSet: cachedTokenSet,
|
||||
})
|
||||
if err != nil {
|
||||
return xerrors.Errorf("authentication error: %w", err)
|
||||
}
|
||||
u.Logger.V(1).Infof("you got a token: %s", out.TokenSet.IDTokenClaims.Pretty)
|
||||
idTokenClaims, err := out.TokenSet.DecodeWithoutVerify()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("you got an invalid token: %w", err)
|
||||
}
|
||||
u.Logger.V(1).Infof("you got a token: %s", idTokenClaims.Pretty)
|
||||
if out.AlreadyHasValidIDToken {
|
||||
u.Logger.Printf("You already have a valid token until %s", out.TokenSet.IDTokenClaims.Expiry)
|
||||
u.Logger.Printf("You already have a valid token until %s", idTokenClaims.Expiry)
|
||||
return nil
|
||||
}
|
||||
|
||||
u.Logger.Printf("You got a valid token until %s", out.TokenSet.IDTokenClaims.Expiry)
|
||||
u.Logger.Printf("You got a valid token until %s", idTokenClaims.Expiry)
|
||||
authProvider.IDToken = out.TokenSet.IDToken
|
||||
authProvider.RefreshToken = out.TokenSet.RefreshToken
|
||||
u.Logger.V(1).Infof("writing the ID token and refresh token to %s", authProvider.LocationOfOrigin)
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
"github.com/int128/kubelogin/pkg/adaptors/certpool/mock_certpool"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/kubeconfig"
|
||||
"github.com/int128/kubelogin/pkg/adaptors/kubeconfig/mock_kubeconfig"
|
||||
"github.com/int128/kubelogin/pkg/jwt"
|
||||
"github.com/int128/kubelogin/pkg/oidc"
|
||||
testingJWT "github.com/int128/kubelogin/pkg/testing/jwt"
|
||||
"github.com/int128/kubelogin/pkg/testing/logger"
|
||||
"github.com/int128/kubelogin/pkg/usecases/authentication"
|
||||
"github.com/int128/kubelogin/pkg/usecases/authentication/mock_authentication"
|
||||
@@ -19,11 +19,12 @@ import (
|
||||
)
|
||||
|
||||
func TestStandalone_Do(t *testing.T) {
|
||||
dummyTokenClaims := jwt.Claims{
|
||||
Subject: "YOUR_SUBJECT",
|
||||
Expiry: time.Date(2019, 1, 2, 3, 4, 5, 0, time.UTC),
|
||||
Pretty: "PRETTY_JSON",
|
||||
}
|
||||
issuedIDTokenExpiration := time.Now().Add(1 * time.Hour).Round(time.Second)
|
||||
issuedIDToken := testingJWT.EncodeF(t, func(claims *testingJWT.Claims) {
|
||||
claims.Issuer = "https://accounts.google.com"
|
||||
claims.Subject = "YOUR_SUBJECT"
|
||||
claims.ExpiresAt = issuedIDTokenExpiration.Unix()
|
||||
})
|
||||
|
||||
t.Run("FullOptions", func(t *testing.T) {
|
||||
var grantOptionSet authentication.GrantOptionSet
|
||||
@@ -70,7 +71,7 @@ func TestStandalone_Do(t *testing.T) {
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
IDPCertificateAuthority: "/path/to/cert2",
|
||||
IDPCertificateAuthorityData: "BASE64ENCODED2",
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
IDToken: issuedIDToken,
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
})
|
||||
mockAuthentication := mock_authentication.NewMockInterface(ctrl)
|
||||
@@ -87,9 +88,8 @@ func TestStandalone_Do(t *testing.T) {
|
||||
}).
|
||||
Return(&authentication.Output{
|
||||
TokenSet: oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: issuedIDToken,
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
},
|
||||
}, nil)
|
||||
u := Standalone{
|
||||
@@ -114,7 +114,7 @@ func TestStandalone_Do(t *testing.T) {
|
||||
IDPIssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
IDToken: "VALID_ID_TOKEN",
|
||||
IDToken: issuedIDToken,
|
||||
}
|
||||
mockCertPool := mock_certpool.NewMockInterface(ctrl)
|
||||
mockKubeconfig := mock_kubeconfig.NewMockInterface(ctrl)
|
||||
@@ -130,13 +130,14 @@ func TestStandalone_Do(t *testing.T) {
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
CertPool: mockCertPool,
|
||||
},
|
||||
IDToken: "VALID_ID_TOKEN",
|
||||
CachedTokenSet: &oidc.TokenSet{
|
||||
IDToken: issuedIDToken,
|
||||
},
|
||||
}).
|
||||
Return(&authentication.Output{
|
||||
AlreadyHasValidIDToken: true,
|
||||
TokenSet: oidc.TokenSet{
|
||||
IDToken: "VALID_ID_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: issuedIDToken,
|
||||
},
|
||||
}, nil)
|
||||
u := Standalone{
|
||||
@@ -233,7 +234,7 @@ func TestStandalone_Do(t *testing.T) {
|
||||
IDPIssuerURL: "https://accounts.google.com",
|
||||
ClientID: "YOUR_CLIENT_ID",
|
||||
ClientSecret: "YOUR_CLIENT_SECRET",
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
IDToken: issuedIDToken,
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
}).
|
||||
Return(xerrors.New("I/O error"))
|
||||
@@ -249,9 +250,8 @@ func TestStandalone_Do(t *testing.T) {
|
||||
}).
|
||||
Return(&authentication.Output{
|
||||
TokenSet: oidc.TokenSet{
|
||||
IDToken: "YOUR_ID_TOKEN",
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
IDTokenClaims: dummyTokenClaims,
|
||||
IDToken: issuedIDToken,
|
||||
RefreshToken: "YOUR_REFRESH_TOKEN",
|
||||
},
|
||||
}, nil)
|
||||
u := Standalone{
|
||||
|
||||
Reference in New Issue
Block a user