mirror of
https://github.com/int128/kubelogin.git
synced 2026-02-14 16:39:51 +00:00
Add --oidc-redirect-url to override redirect URL (#1263)
This commit is contained in:
@@ -12,8 +12,6 @@ import (
|
||||
"github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
const oobRedirectURI = "urn:ietf:wg:oauth:2.0:oob"
|
||||
|
||||
type authenticationOptions struct {
|
||||
GrantType string
|
||||
ListenAddress []string
|
||||
@@ -23,8 +21,8 @@ type authenticationOptions struct {
|
||||
LocalServerCertFile string
|
||||
LocalServerKeyFile string
|
||||
OpenURLAfterAuthentication string
|
||||
RedirectURLHostname string
|
||||
RedirectURLAuthCodeKeyboard string
|
||||
RedirectURLHostname string // DEPRECATED
|
||||
RedirectURLAuthCodeKeyboard string // DEPRECATED
|
||||
AuthRequestExtraParams map[string]string
|
||||
Username string
|
||||
Password string
|
||||
@@ -47,8 +45,14 @@ func (o *authenticationOptions) addFlags(f *pflag.FlagSet) {
|
||||
f.StringVar(&o.LocalServerCertFile, "local-server-cert", "", "[authcode] Certificate path for the local server")
|
||||
f.StringVar(&o.LocalServerKeyFile, "local-server-key", "", "[authcode] Certificate key path for the local server")
|
||||
f.StringVar(&o.OpenURLAfterAuthentication, "open-url-after-authentication", "", "[authcode] If set, open the URL in the browser after authentication")
|
||||
f.StringVar(&o.RedirectURLHostname, "oidc-redirect-url-hostname", "localhost", "[authcode] Hostname of the redirect URL")
|
||||
f.StringVar(&o.RedirectURLAuthCodeKeyboard, "oidc-redirect-url-authcode-keyboard", oobRedirectURI, "[authcode-keyboard] Redirect URL")
|
||||
f.StringVar(&o.RedirectURLHostname, "oidc-redirect-url-hostname", "", "[authcode] Hostname of the redirect URL")
|
||||
if err := f.MarkDeprecated("oidc-redirect-url-hostname", "use --oidc-redirect-url instead."); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
f.StringVar(&o.RedirectURLAuthCodeKeyboard, "oidc-redirect-url-authcode-keyboard", "", "Equivalent to --oidc-redirect-url")
|
||||
if err := f.MarkDeprecated("oidc-redirect-url-authcode-keyboard", "use --oidc-redirect-url instead."); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
f.StringToStringVar(&o.AuthRequestExtraParams, "oidc-auth-request-extra-params", nil, "[authcode, authcode-keyboard] Extra query parameters to send with an authentication request")
|
||||
f.StringVar(&o.Username, "username", "", "[password] Username for resource owner password credentials grant")
|
||||
f.StringVar(&o.Password, "password", "", "[password] Password for resource owner password credentials grant")
|
||||
@@ -76,7 +80,6 @@ func (o *authenticationOptions) grantOptionSet() (s authentication.GrantOptionSe
|
||||
case o.GrantType == "authcode-keyboard":
|
||||
s.AuthCodeKeyboardOption = &authcode.KeyboardOption{
|
||||
AuthRequestExtraParams: o.AuthRequestExtraParams,
|
||||
RedirectURL: o.RedirectURLAuthCodeKeyboard,
|
||||
}
|
||||
case o.GrantType == "password" || (o.GrantType == "auto" && o.Username != ""):
|
||||
s.ROPCOption = &ropc.Option{
|
||||
|
||||
@@ -21,7 +21,6 @@ func Test_authenticationOptions_grantOptionSet(t *testing.T) {
|
||||
AuthCodeBrowserOption: &authcode.BrowserOption{
|
||||
BindAddress: defaultListenAddress,
|
||||
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
|
||||
RedirectURLHostname: "localhost",
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -61,19 +60,19 @@ func Test_authenticationOptions_grantOptionSet(t *testing.T) {
|
||||
"--grant-type", "authcode-keyboard",
|
||||
},
|
||||
want: authentication.GrantOptionSet{
|
||||
AuthCodeKeyboardOption: &authcode.KeyboardOption{
|
||||
RedirectURL: oobRedirectURI,
|
||||
},
|
||||
AuthCodeKeyboardOption: &authcode.KeyboardOption{},
|
||||
},
|
||||
},
|
||||
"GrantType=authcode-keyboard with full options": {
|
||||
args: []string{
|
||||
"--grant-type", "authcode-keyboard",
|
||||
"--oidc-redirect-url-authcode-keyboard", "http://localhost",
|
||||
"--oidc-auth-request-extra-params", "ttl=86400",
|
||||
"--oidc-auth-request-extra-params", "reauth=true",
|
||||
},
|
||||
want: authentication.GrantOptionSet{
|
||||
AuthCodeKeyboardOption: &authcode.KeyboardOption{
|
||||
RedirectURL: "http://localhost",
|
||||
AuthRequestExtraParams: map[string]string{"ttl": "86400", "reauth": "true"},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -29,7 +29,6 @@ func TestCmd_Run(t *testing.T) {
|
||||
AuthCodeBrowserOption: &authcode.BrowserOption{
|
||||
BindAddress: defaultListenAddress,
|
||||
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
|
||||
RedirectURLHostname: "localhost",
|
||||
},
|
||||
}
|
||||
|
||||
@@ -188,7 +187,6 @@ func TestCmd_Run(t *testing.T) {
|
||||
AuthCodeBrowserOption: &authcode.BrowserOption{
|
||||
BindAddress: defaultListenAddress,
|
||||
AuthenticationTimeout: defaultAuthenticationTimeoutSec * time.Second,
|
||||
RedirectURLHostname: "localhost",
|
||||
LocalServerCertFile: filepath.Join(userHomeDir, ".kube/oidc-server.crt"),
|
||||
LocalServerKeyFile: filepath.Join(userHomeDir, ".kube/oidc-server.key"),
|
||||
},
|
||||
|
||||
@@ -16,6 +16,7 @@ type getTokenOptions struct {
|
||||
IssuerURL string
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
RedirectURL string
|
||||
ExtraScopes []string
|
||||
UseAccessToken bool
|
||||
tokenCacheOptions tokenCacheOptions
|
||||
@@ -29,6 +30,7 @@ func (o *getTokenOptions) addFlags(f *pflag.FlagSet) {
|
||||
f.StringVar(&o.IssuerURL, "oidc-issuer-url", "", "Issuer URL of the provider (mandatory)")
|
||||
f.StringVar(&o.ClientID, "oidc-client-id", "", "Client ID of the provider (mandatory)")
|
||||
f.StringVar(&o.ClientSecret, "oidc-client-secret", "", "Client secret of the provider")
|
||||
f.StringVar(&o.RedirectURL, "oidc-redirect-url", "", "[authcode, authcode-keyboard] Redirect URL")
|
||||
f.StringSliceVar(&o.ExtraScopes, "oidc-extra-scope", nil, "Scopes to request to the provider")
|
||||
f.BoolVar(&o.UseAccessToken, "oidc-use-access-token", false, "Instead of using the id_token, use the access_token to authenticate to Kubernetes")
|
||||
f.BoolVar(&o.ForceRefresh, "force-refresh", false, "If set, refresh the ID token regardless of its expiration time")
|
||||
@@ -80,11 +82,16 @@ func (cmd *GetToken) New() *cobra.Command {
|
||||
if err != nil {
|
||||
return fmt.Errorf("get-token: %w", err)
|
||||
}
|
||||
redirectURL := o.RedirectURL
|
||||
if o.authenticationOptions.RedirectURLAuthCodeKeyboard != "" {
|
||||
redirectURL = o.authenticationOptions.RedirectURLAuthCodeKeyboard
|
||||
}
|
||||
in := credentialplugin.Input{
|
||||
Provider: oidc.Provider{
|
||||
IssuerURL: o.IssuerURL,
|
||||
ClientID: o.ClientID,
|
||||
ClientSecret: o.ClientSecret,
|
||||
RedirectURL: redirectURL,
|
||||
PKCEMethod: pkceMethod,
|
||||
UseAccessToken: o.UseAccessToken,
|
||||
ExtraScopes: o.ExtraScopes,
|
||||
|
||||
@@ -15,6 +15,7 @@ type setupOptions struct {
|
||||
IssuerURL string
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
RedirectURL string
|
||||
ExtraScopes []string
|
||||
UseAccessToken bool
|
||||
tlsOptions tlsOptions
|
||||
@@ -26,6 +27,7 @@ func (o *setupOptions) addFlags(f *pflag.FlagSet) {
|
||||
f.StringVar(&o.IssuerURL, "oidc-issuer-url", "", "Issuer URL of the provider")
|
||||
f.StringVar(&o.ClientID, "oidc-client-id", "", "Client ID of the provider")
|
||||
f.StringVar(&o.ClientSecret, "oidc-client-secret", "", "Client secret of the provider")
|
||||
f.StringVar(&o.RedirectURL, "oidc-redirect-url", "", "[authcode, authcode-keyboard] Redirect URL")
|
||||
f.StringSliceVar(&o.ExtraScopes, "oidc-extra-scope", nil, "Scopes to request to the provider")
|
||||
f.BoolVar(&o.UseAccessToken, "oidc-use-access-token", false, "Instead of using the id_token, use the access_token to authenticate to Kubernetes")
|
||||
o.tlsOptions.addFlags(f)
|
||||
@@ -74,6 +76,7 @@ func (cmd *Setup) New() *cobra.Command {
|
||||
IssuerURL: o.IssuerURL,
|
||||
ClientID: o.ClientID,
|
||||
ClientSecret: o.ClientSecret,
|
||||
RedirectURL: o.RedirectURL,
|
||||
ExtraScopes: o.ExtraScopes,
|
||||
UseAccessToken: o.UseAccessToken,
|
||||
PKCEMethod: pkceMethod,
|
||||
|
||||
@@ -31,15 +31,13 @@ type AuthCodeURLInput struct {
|
||||
State string
|
||||
Nonce string
|
||||
PKCEParams pkce.Params
|
||||
RedirectURI string
|
||||
AuthRequestExtraParams map[string]string
|
||||
}
|
||||
|
||||
type ExchangeAuthCodeInput struct {
|
||||
Code string
|
||||
PKCEParams pkce.Params
|
||||
Nonce string
|
||||
RedirectURI string
|
||||
Code string
|
||||
PKCEParams pkce.Params
|
||||
Nonce string
|
||||
}
|
||||
|
||||
type GetTokenByAuthCodeInput struct {
|
||||
@@ -47,7 +45,7 @@ type GetTokenByAuthCodeInput struct {
|
||||
State string
|
||||
Nonce string
|
||||
PKCEParams pkce.Params
|
||||
RedirectURLHostname string
|
||||
RedirectURLHostname string // DEPRECATED
|
||||
AuthRequestExtraParams map[string]string
|
||||
LocalServerSuccessHTML string
|
||||
LocalServerCertFile string
|
||||
@@ -97,19 +95,15 @@ func (c *client) GetTokenByAuthCode(ctx context.Context, in GetTokenByAuthCodeIn
|
||||
|
||||
// GetAuthCodeURL returns the URL of authentication request for the authorization code flow.
|
||||
func (c *client) GetAuthCodeURL(in AuthCodeURLInput) string {
|
||||
cfg := c.oauth2Config
|
||||
cfg.RedirectURL = in.RedirectURI
|
||||
opts := authorizationRequestOptions(in.Nonce, in.PKCEParams, in.AuthRequestExtraParams)
|
||||
return cfg.AuthCodeURL(in.State, opts...)
|
||||
return c.oauth2Config.AuthCodeURL(in.State, opts...)
|
||||
}
|
||||
|
||||
// ExchangeAuthCode exchanges the authorization code and token.
|
||||
func (c *client) ExchangeAuthCode(ctx context.Context, in ExchangeAuthCodeInput) (*oidc.TokenSet, error) {
|
||||
ctx = c.wrapContext(ctx)
|
||||
cfg := c.oauth2Config
|
||||
cfg.RedirectURL = in.RedirectURI
|
||||
opts := tokenRequestOptions(in.PKCEParams)
|
||||
token, err := cfg.Exchange(ctx, in.Code, opts...)
|
||||
token, err := c.oauth2Config.Exchange(ctx, in.Code, opts...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("exchange error: %w", err)
|
||||
}
|
||||
|
||||
@@ -72,6 +72,7 @@ func (f *Factory) New(ctx context.Context, prov oidc.Provider, tlsClientConfig t
|
||||
Endpoint: provider.Endpoint(),
|
||||
ClientID: prov.ClientID,
|
||||
ClientSecret: prov.ClientSecret,
|
||||
RedirectURL: prov.RedirectURL,
|
||||
Scopes: append(prov.ExtraScopes, gooidc.ScopeOpenID),
|
||||
},
|
||||
clock: f.Clock,
|
||||
|
||||
@@ -15,6 +15,7 @@ type Provider struct {
|
||||
ClientID string
|
||||
ClientSecret string // optional
|
||||
ExtraScopes []string // optional
|
||||
RedirectURL string // optional
|
||||
PKCEMethod PKCEMethod
|
||||
UseAccessToken bool
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ type BrowserOption struct {
|
||||
BindAddress []string
|
||||
AuthenticationTimeout time.Duration
|
||||
OpenURLAfterAuthentication string
|
||||
RedirectURLHostname string
|
||||
RedirectURLHostname string // DEPRECATED
|
||||
AuthRequestExtraParams map[string]string
|
||||
LocalServerCertFile string
|
||||
LocalServerKeyFile string
|
||||
|
||||
@@ -28,7 +28,6 @@ func TestBrowser_Do(t *testing.T) {
|
||||
LocalServerCertFile: "/path/to/local-server-cert",
|
||||
LocalServerKeyFile: "/path/to/local-server-key",
|
||||
OpenURLAfterAuthentication: "https://example.com/success.html",
|
||||
RedirectURLHostname: "localhost",
|
||||
AuthRequestExtraParams: map[string]string{"ttl": "86400", "reauth": "true"},
|
||||
}
|
||||
mockClient := client_mock.NewMockInterface(t)
|
||||
@@ -42,9 +41,6 @@ func TestBrowser_Do(t *testing.T) {
|
||||
if diff := cmp.Diff(BrowserRedirectHTML("https://example.com/success.html"), in.LocalServerSuccessHTML); diff != "" {
|
||||
t.Errorf("LocalServerSuccessHTML mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(o.RedirectURLHostname, in.RedirectURLHostname); diff != "" {
|
||||
t.Errorf("RedirectURLHostname mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(o.AuthRequestExtraParams, in.AuthRequestExtraParams); diff != "" {
|
||||
t.Errorf("AuthRequestExtraParams mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ const keyboardPrompt = "Enter code: "
|
||||
|
||||
type KeyboardOption struct {
|
||||
AuthRequestExtraParams map[string]string
|
||||
RedirectURL string
|
||||
}
|
||||
|
||||
// Keyboard provides the authorization code flow with keyboard interactive.
|
||||
@@ -42,7 +41,6 @@ func (u *Keyboard) Do(ctx context.Context, o *KeyboardOption, oidcClient client.
|
||||
State: state,
|
||||
Nonce: nonce,
|
||||
PKCEParams: pkceParams,
|
||||
RedirectURI: o.RedirectURL,
|
||||
AuthRequestExtraParams: o.AuthRequestExtraParams,
|
||||
})
|
||||
u.Logger.Printf("Please visit the following URL in your browser: %s", authCodeURL)
|
||||
@@ -53,10 +51,9 @@ func (u *Keyboard) Do(ctx context.Context, o *KeyboardOption, oidcClient client.
|
||||
|
||||
u.Logger.V(1).Infof("exchanging the code and token")
|
||||
tokenSet, err := oidcClient.ExchangeAuthCode(ctx, client.ExchangeAuthCodeInput{
|
||||
Code: code,
|
||||
PKCEParams: pkceParams,
|
||||
Nonce: nonce,
|
||||
RedirectURI: o.RedirectURL,
|
||||
Code: code,
|
||||
PKCEParams: pkceParams,
|
||||
Nonce: nonce,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not exchange the authorization code: %w", err)
|
||||
|
||||
@@ -42,6 +42,7 @@ type Input struct {
|
||||
IssuerURL string
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
RedirectURL string
|
||||
ExtraScopes []string
|
||||
UseAccessToken bool
|
||||
PKCEMethod oidc.PKCEMethod
|
||||
@@ -57,6 +58,7 @@ func (u Setup) Do(ctx context.Context, in Input) error {
|
||||
IssuerURL: in.IssuerURL,
|
||||
ClientID: in.ClientID,
|
||||
ClientSecret: in.ClientSecret,
|
||||
RedirectURL: in.RedirectURL,
|
||||
ExtraScopes: in.ExtraScopes,
|
||||
PKCEMethod: in.PKCEMethod,
|
||||
UseAccessToken: in.UseAccessToken,
|
||||
|
||||
Reference in New Issue
Block a user