Skip to content

Commit fd1c0db

Browse files
authored
added Interactive login hint (#663)
* added --login-hint support * update doc
1 parent aac3f20 commit fd1c0db

File tree

7 files changed

+67
-1
lines changed

7 files changed

+67
-1
lines changed

docs/book/src/cli/convert-kubeconfig.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ Flags:
3131
--kubeconfig string Path to the kubeconfig file to use for CLI requests.
3232
--legacy set to true to get token with 'spn:' prefix in audience claim
3333
-l, --login string Login method. Supported methods: devicecode, interactive, spn, ropc, msi, azurecli, azd, workloadidentity. It may be specified in AAD_LOGIN_METHOD environment variable (default "devicecode")
34+
--login-hint string The login hint to pre-fill the username in the interactive login flow.
3435
--password string password for ropc login flow. It may be specified in AAD_USER_PRINCIPAL_PASSWORD or AZURE_PASSWORD environment variable
3536
--pop-claims key=val,key2=val2 contains a comma-separated list of claims to attach to the pop token in the format key=val,key2=val2. At minimum, specify the ARM ID of the cluster as `u=ARM_ID`
3637
--pop-enabled set to true to use a PoP token for authentication or false to use a regular bearer token

docs/book/src/cli/get-token.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ Flags:
2626
--identity-resource-id string Managed Identity resource id.
2727
--legacy set to true to get token with 'spn:' prefix in audience claim
2828
-l, --login string Login method. Supported methods: devicecode, interactive, spn, ropc, msi, azurecli, azd, workloadidentity. It may be specified in AAD_LOGIN_METHOD environment variable (default "devicecode")
29+
--login-hint string The login hint to pre-fill the username in the interactive login flow.
2930
--password string password for ropc login flow. It may be specified in AAD_USER_PRINCIPAL_PASSWORD or AZURE_PASSWORD environment variable
3031
--pop-claims key=val,key2=val2 contains a comma-separated list of claims to attach to the pop token in the format key=val,key2=val2. At minimum, specify the ARM ID of the cluster as `u=ARM_ID`
3132
--pop-enabled set to true to use a PoP token for authentication or false to use a regular bearer token

docs/book/src/concepts/login-modes/interactive.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ kubelogin convert-kubeconfig -l interactive --redirect-url http://localhost:8080
2727
kubectl get nodes
2828
```
2929

30+
### Specifying login user hint
31+
32+
```sh
33+
export KUBECONFIG=/path/to/kubeconfig
34+
35+
kubelogin convert-kubeconfig -l interactive --login-hint user@example.com
36+
37+
kubectl get nodes
38+
```
39+
3040

3141
### Proof-of-possession (PoP) token with interactive flow
3242

@@ -38,6 +48,12 @@ kubelogin convert-kubeconfig -l interactive --pop-enabled --pop-claims "u=/ARM/I
3848
kubectl get nodes
3949
```
4050

51+
### Clearing the cache
52+
53+
```sh
54+
kubelogin remove-cache-dir
55+
```
56+
4157
## References
4258

4359
- https://learn.microsoft.com/en-us/python/api/azure-identity/azure.identity.interactivebrowsercredential?view=azure-python

pkg/internal/converter/convert.go

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ const (
3838
argPoPTokenClaims = "--pop-claims"
3939
argDisableEnvironmentOverride = "--disable-environment-override"
4040
argRedirectURL = "--redirect-url"
41+
argLoginHint = "--login-hint"
4142

4243
flagAzureConfigDir = "azure-config-dir"
4344
flagClientID = "client-id"
@@ -61,6 +62,7 @@ const (
6162
flagPoPTokenClaims = "pop-claims"
6263
flagDisableEnvironmentOverride = "disable-environment-override"
6364
flagRedirectURL = "redirect-url"
65+
flagLoginHint = "login-hint"
6466

6567
execName = "kubelogin"
6668
getTokenCommand = "get-token"
@@ -81,7 +83,8 @@ func getArgValues(o Options, authInfo *api.AuthInfo) (
8183
argTenantIDVal,
8284
argAuthRecordCacheDirVal,
8385
argPoPTokenClaimsVal,
84-
argRedirectURLVal string,
86+
argRedirectURLVal,
87+
argLoginHintVal string,
8588
argIsLegacyConfigModeVal,
8689
argIsPoPTokenEnabledVal bool,
8790
) {
@@ -173,6 +176,12 @@ func getArgValues(o Options, authInfo *api.AuthInfo) (
173176
argRedirectURLVal = getExecArg(authInfo, argRedirectURL)
174177
}
175178

179+
if o.isSet(flagLoginHint) {
180+
argLoginHintVal = o.TokenOptions.LoginHint
181+
} else {
182+
argLoginHintVal = getExecArg(authInfo, argLoginHint)
183+
}
184+
176185
return
177186
}
178187

@@ -249,6 +258,7 @@ func Convert(o Options, pathOptions *clientcmd.PathOptions) error {
249258
argAuthRecordCacheDirVal,
250259
argPoPTokenClaimsVal,
251260
argRedirectURLVal,
261+
argLoginHintVal,
252262
isLegacyConfigMode,
253263
isPoPTokenEnabled := getArgValues(o, authInfo)
254264
exec := &api.ExecConfig{
@@ -349,6 +359,10 @@ func Convert(o Options, pathOptions *clientcmd.PathOptions) error {
349359
exec.Args = append(exec.Args, argRedirectURL, argRedirectURLVal)
350360
}
351361

362+
if argLoginHintVal != "" {
363+
exec.Args = append(exec.Args, argLoginHint, argLoginHintVal)
364+
}
365+
352366
case token.ServicePrincipalLogin:
353367

354368
if argClientIDVal == "" {

pkg/internal/converter/convert_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ func TestConvert(t *testing.T) {
3333
authRecordCacheDir = "/tmp/token_dir"
3434
azureCLIDir = "/tmp/foo"
3535
redirectURL = "http://localhost:8000"
36+
usernameHint = "username"
3637
)
3738
testData := []struct {
3839
name string
@@ -1238,6 +1239,35 @@ func TestConvert(t *testing.T) {
12381239
},
12391240
command: execName,
12401241
},
1242+
{
1243+
name: "with exec format kubeconfig, convert from devicecode to interactive with login hint override",
1244+
execArgItems: []string{
1245+
getTokenCommand,
1246+
argServerID, serverID,
1247+
argClientID, clientID,
1248+
argTenantID, tenantID,
1249+
argEnvironment, envName,
1250+
argLoginMethod, token.DeviceCodeLogin,
1251+
},
1252+
overrideFlags: map[string]string{
1253+
flagLoginMethod: token.InteractiveLogin,
1254+
flagServerID: serverID,
1255+
flagClientID: clientID,
1256+
flagTenantID: tenantID,
1257+
flagEnvironment: envName,
1258+
flagLoginHint: usernameHint,
1259+
},
1260+
expectedArgs: []string{
1261+
getTokenCommand,
1262+
argServerID, serverID,
1263+
argClientID, clientID,
1264+
argTenantID, tenantID,
1265+
argEnvironment, envName,
1266+
argLoginMethod, token.InteractiveLogin,
1267+
argLoginHint, usernameHint,
1268+
},
1269+
command: execName,
1270+
},
12411271
{
12421272
name: "convert with context specified, auth info not specified by the context should not be changed",
12431273
authProviderConfig: map[string]string{

pkg/internal/token/interactivebrowsercredential.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func newInteractiveBrowserCredential(opts *Options, record azidentity.Authentica
4343
TenantID: opts.TenantID,
4444
DisableInstanceDiscovery: opts.DisableInstanceDiscovery,
4545
RedirectURL: opts.RedirectURL,
46+
LoginHint: opts.LoginHint,
4647
}
4748

4849
if opts.httpClient != nil {

pkg/internal/token/options.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type Options struct {
4242
DisableInstanceDiscovery bool
4343
httpClient *http.Client
4444
RedirectURL string
45+
LoginHint string
4546
}
4647

4748
const (
@@ -121,6 +122,7 @@ func (o *Options) AddFlags(fs *pflag.FlagSet) {
121122
fs.BoolVar(&o.DisableEnvironmentOverride, "disable-environment-override", o.DisableEnvironmentOverride, "Enable or disable the use of env-variables. Default false")
122123
fs.BoolVar(&o.DisableInstanceDiscovery, "disable-instance-discovery", o.DisableInstanceDiscovery, "set to true to disable instance discovery in environments with their own simple Identity Provider (not AAD) that do not have instance metadata discovery endpoint. Default false")
123124
fs.StringVar(&o.RedirectURL, "redirect-url", o.RedirectURL, "The URL Microsoft Entra ID will redirect to with the access token. This is only used for interactive login. This is an optional parameter.")
125+
fs.StringVar(&o.LoginHint, "login-hint", o.LoginHint, "The login hint to pre-fill the username in the interactive login flow.")
124126
}
125127

126128
func (o *Options) Validate() error {
@@ -291,6 +293,7 @@ func (o *Options) ToString() string {
291293
fmt.Sprintf("tokenauthRecordFile: %s", o.authRecordCacheFile),
292294
fmt.Sprintf("AZURE_CONFIG_DIR: %s", azureConfigDir),
293295
fmt.Sprintf("RedirectURL: %s", o.RedirectURL),
296+
fmt.Sprintf("LoginHint: %s", o.LoginHint),
294297
}
295298

296299
return strings.Join(parts, ", ")

0 commit comments

Comments
 (0)