Skip to content

Commit

Permalink
The login command now accepts -u (and -p) with korifi
Browse files Browse the repository at this point in the history
- Stop using `k8s-auth-info` for kubernetes prompts and credentials and
  use `username` instead. This allows the existing login code to work
  with korifi with fewer changes.

- Remove support for menu-based prompts in login except for username.
  These menus are only used with korifi and only for the username.

- Warn the user when they provide a password and are using korifi

[cloudfoundry/korifi#2195]

Co-authored-by: Dave Walter <walterda@vmware.com>
  • Loading branch information
2 people authored and a-b committed Mar 25, 2023
1 parent 3c3e049 commit 6439266
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 60 deletions.
4 changes: 2 additions & 2 deletions actor/v7action/k8s_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func NewKubernetesAuthActor(config Config, k8sConfigGetter KubernetesConfigGette
}

func (actor kubernetesAuthActor) Authenticate(credentials map[string]string, origin string, grantType constant.GrantType) error {
username := credentials["k8s-auth-info"]
username := credentials["username"]
availableUsernames, err := actor.getAvailableUsernames()
if err != nil {
return err
Expand All @@ -75,7 +75,7 @@ func (actor kubernetesAuthActor) GetLoginPrompts() (map[string]coreconfig.AuthPr
}
sort.Strings(availableUsernames)

return map[string]coreconfig.AuthPrompt{"k8s-auth-info": {
return map[string]coreconfig.AuthPrompt{"username": {
Type: coreconfig.AuthPromptTypeMenu,
Entries: availableUsernames,
DisplayName: "Choose your Kubernetes authentication info",
Expand Down
8 changes: 4 additions & 4 deletions actor/v7action/k8s_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ var _ = Describe("KubernetesAuthActor", func() {
})

JustBeforeEach(func() {
err = k8sAuthActor.Authenticate(map[string]string{"k8s-auth-info": username}, "", constant.GrantTypePassword)
err = k8sAuthActor.Authenticate(map[string]string{"username": username}, "", constant.GrantTypePassword)
})

It("sets the Kubernetes auth-info", func() {
Expand Down Expand Up @@ -90,16 +90,16 @@ var _ = Describe("KubernetesAuthActor", func() {
It("returns an auth prompt menu", func() {
Expect(err).NotTo(HaveOccurred())
Expect(authPrompts).To(HaveLen(1))
Expect(authPrompts).To(HaveKey("k8s-auth-info"))
Expect(authPrompts).To(HaveKey("username"))

authPrompt := authPrompts["k8s-auth-info"]
authPrompt := authPrompts["username"]
Expect(authPrompt.Type).To(Equal(coreconfig.AuthPromptTypeMenu))
Expect(authPrompt.DisplayName).To(Equal("Choose your Kubernetes authentication info"))
Expect(authPrompt.Entries).To(ConsistOf("foo", "bar"))
})

It("sorts the entries", func() {
authPrompt := authPrompts["k8s-auth-info"]
authPrompt := authPrompts["username"]
Expect(authPrompt.Entries).To(Equal([]string{"bar", "foo"}))
})

Expand Down
4 changes: 0 additions & 4 deletions command/v7/auth_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,6 @@ func (cmd AuthCommand) Execute(args []string) error {
grantType = constant.GrantTypeClientCredentials
credentials["client_id"] = username
credentials["client_secret"] = password
} else if cmd.Config.IsCFOnK8s() {
credentials = map[string]string{
"k8s-auth-info": username,
}
} else {
credentials = map[string]string{
"username": username,
Expand Down
2 changes: 1 addition & 1 deletion command/v7/auth_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ var _ = Describe("auth Command", func() {
It("attempts to authenticate with the correct username", func() {
Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
credentials, _, _ := fakeActor.AuthenticateArgsForCall(0)
Expect(credentials).To(Equal(map[string]string{"k8s-auth-info": "myuser"}))
Expect(credentials).To(HaveKeyWithValue("username", "myuser"))
})

When("there is an error authenticating with the given username", func() {
Expand Down
48 changes: 22 additions & 26 deletions command/v7/login_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ func (cmd *LoginCommand) authenticate() error {
return err
}

nonPasswordPrompts, passwordPrompts := cmd.groupPrompts(prompts)
nonSensitivePrompts, sensitivePrompts := cmd.groupPrompts(prompts)

if value, ok := prompts["username"]; ok {
credentials["username"], err = cmd.getFlagValOrPrompt(&cmd.Username, value, true)
Expand All @@ -276,12 +276,8 @@ func (cmd *LoginCommand) authenticate() error {
}
}

for key, prompt := range nonPasswordPrompts {
if prompt.Type == coreconfig.AuthPromptTypeMenu {
credentials[key], err = cmd.UI.DisplayTextMenu(prompt.Entries, prompt.DisplayName)
} else {
credentials[key], err = cmd.UI.DisplayTextPrompt(prompt.DisplayName)
}
for key, prompt := range nonSensitivePrompts {
credentials[key], err = cmd.UI.DisplayTextPrompt(prompt.DisplayName)
if err != nil {
return err
}
Expand All @@ -296,7 +292,7 @@ func (cmd *LoginCommand) authenticate() error {
}
}

for key, prompt := range passwordPrompts {
for key, prompt := range sensitivePrompts {
credentials[key], err = cmd.UI.DisplayPasswordPrompt(prompt.DisplayName)
if err != nil {
return err
Expand All @@ -308,19 +304,17 @@ func (cmd *LoginCommand) authenticate() error {

err = cmd.Actor.Authenticate(credentials, cmd.Origin, constant.GrantTypePassword)

if err != nil {
cmd.UI.DisplayWarning(translatableerror.ConvertToTranslatableError(err).Error())
cmd.UI.DisplayNewline()

if _, ok := err.(uaa.AccountLockedError); ok {
break
}
}

if err == nil {
cmd.UI.DisplayOK()
break
}

cmd.UI.DisplayWarning(translatableerror.ConvertToTranslatableError(err).Error())
cmd.UI.DisplayNewline()

if _, ok := err.(uaa.AccountLockedError); ok {
break
}
}

return err
Expand Down Expand Up @@ -387,12 +381,16 @@ func (cmd *LoginCommand) getFlagValOrPrompt(field *string, prompt coreconfig.Aut
value := *field
*field = ""
return value, nil
} else {
if isText {
return cmd.UI.DisplayTextPrompt(prompt.DisplayName)
}
return cmd.UI.DisplayPasswordPrompt(prompt.DisplayName)
}

if prompt.Type == coreconfig.AuthPromptTypeMenu {
return cmd.UI.DisplayTextMenu(prompt.Entries, prompt.DisplayName)
}

if isText {
return cmd.UI.DisplayTextPrompt(prompt.DisplayName)
}
return cmd.UI.DisplayPasswordPrompt(prompt.DisplayName)
}

func (cmd *LoginCommand) showStatus() {
Expand Down Expand Up @@ -586,17 +584,15 @@ func (cmd *LoginCommand) validateTargetSpecificFlags() error {
}

if cmd.Password != "" {
return translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "-p"}
cmd.UI.DisplayWarning("Warning: password is ignored when authenticating against Kubernetes.")
}

if cmd.SSO {
return translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "--sso"}
}
if cmd.SSOPasscode != "" {
return translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "--sso-passcode"}
}
if cmd.Username != "" {
return translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "-u"}
}
if cmd.Origin != "" {
return translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "--origin"}
}
Expand Down
124 changes: 101 additions & 23 deletions command/v7/login_command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,17 +130,7 @@ var _ = Describe("login Command", func() {
fakeConfig.TargetReturns("https://foo.bar")
})

When("password flag is provider", func() {
BeforeEach(func() {
cmd.Password = "pass"
})

It("returns unsupported flag error", func() {
Expect(executeErr).To(Equal(translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "-p"}))
})
})

When("sso flag is provider", func() {
When("sso flag is provided", func() {
BeforeEach(func() {
cmd.SSO = true
})
Expand All @@ -150,7 +140,7 @@ var _ = Describe("login Command", func() {
})
})

When("sso passcode flag is provider", func() {
When("sso passcode flag is provided", func() {
BeforeEach(func() {
cmd.SSOPasscode = "sso-pass"
})
Expand All @@ -160,17 +150,7 @@ var _ = Describe("login Command", func() {
})
})

When("username flag is provider", func() {
BeforeEach(func() {
cmd.Username = "my-user"
})

It("returns unsupported flag error", func() {
Expect(executeErr).To(Equal(translatableerror.NotSupportedOnKubernetesArgumentError{Arg: "-u"}))
})
})

When("origin flag is provider", func() {
When("origin flag is provided", func() {
BeforeEach(func() {
cmd.Origin = "my-origin"
})
Expand Down Expand Up @@ -684,6 +664,104 @@ var _ = Describe("login Command", func() {
})
})
})

When("authenticating against Korifi", func() {
BeforeEach(func() {
fakeConfig.IsCFOnK8sReturns(true)
k8sLoginPrompts := map[string]coreconfig.AuthPrompt{
"username": {
Type: coreconfig.AuthPromptTypeMenu,
Entries: []string{"myuser", "overly-powerful-admin"},
DisplayName: "Choose your Kubernetes authentication info",
},
}
fakeActor.GetLoginPromptsReturns(k8sLoginPrompts, nil)
})

When("the user selects a valid username", func() {
BeforeEach(func() {
_, err := input.Write([]byte("1\n"))
Expect(err).ToNot(HaveOccurred())
})

It("prompts the user with available k8s usernames", func() {
Expect(executeErr).NotTo(HaveOccurred())

Expect(testUI.Out).To(Say("myuser"))
Expect(testUI.Out).To(Say("overly-powerful-admin"))
Expect(testUI.Out).To(Say("Choose your Kubernetes authentication info"))
})

It("authenticates with the chosen user", func() {
Expect(executeErr).NotTo(HaveOccurred())

Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
credentials, _, _ := fakeActor.AuthenticateArgsForCall(0)
Expect(credentials).To(Equal(map[string]string{
"username": "myuser",
}))
})
})

When("the user selects an invalid username", func() {
BeforeEach(func() {
_, err := input.Write([]byte("3\n"))
Expect(err).ToNot(HaveOccurred())
})

It("errors", func() {
Expect(executeErr).To(MatchError("Unable to authenticate."))
Expect(fakeActor.AuthenticateCallCount()).To(Equal(0))
})
})

When("the username flag is set", func() {
BeforeEach(func() {
cmd.Username = "myuser"
})

It("sets that username in the credentials", func() {
Expect(executeErr).ToNot(HaveOccurred())
Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
credentials, _, _ := fakeActor.AuthenticateArgsForCall(0)
Expect(credentials).To(Equal(map[string]string{
"username": "myuser",
}))

Expect(testUI.Out).NotTo(Say("Choose your Kubernetes authentication info"))
})

When("the password flag is also set", func() {
BeforeEach(func() {
cmd.Password = "should-be-ignored"
})

It("succeeds and sets only the username in the credentials", func() {
Expect(executeErr).ToNot(HaveOccurred())
Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
credentials, _, _ := fakeActor.AuthenticateArgsForCall(0)
Expect(credentials).To(Equal(map[string]string{
"username": "myuser",
}))
})

It("displays a warning that password will be ignored", func() {
Expect(executeErr).ToNot(HaveOccurred())
Expect(testUI.Err).To(Say("Warning: password is ignored when authenticating against Kubernetes."))
})
})

When("authentication fails", func() {
BeforeEach(func() {
fakeActor.AuthenticateReturns(errors.New("boom"))
})

It("errors", func() {
Expect(executeErr).To(MatchError("Unable to authenticate."))
})
})
})
})
})

Describe("SSO Passcode", func() {
Expand Down

0 comments on commit 6439266

Please sign in to comment.