Skip to content

Commit

Permalink
KubernetesAuthActor.Authenticate validates the username
Browse files Browse the repository at this point in the history
This logic was formerly in the auth command, but this will allow for
reuse in the login command.

[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 b5a352a commit 3c3e049
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 64 deletions.
42 changes: 31 additions & 11 deletions actor/v7action/k8s_auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,37 @@ func NewKubernetesAuthActor(config Config, k8sConfigGetter KubernetesConfigGette
}

func (actor kubernetesAuthActor) Authenticate(credentials map[string]string, origin string, grantType constant.GrantType) error {
actor.config.SetKubernetesAuthInfo(credentials["k8s-auth-info"])
return nil
username := credentials["k8s-auth-info"]
availableUsernames, err := actor.getAvailableUsernames()
if err != nil {
return err
}

for _, u := range availableUsernames {
if u == username {
actor.config.SetKubernetesAuthInfo(username)
return nil
}
}

return errors.New("kubernetes user not found in configuration: " + username)
}

func (actor kubernetesAuthActor) GetLoginPrompts() (map[string]coreconfig.AuthPrompt, error) {
availableUsernames, err := actor.getAvailableUsernames()
if err != nil {
return nil, err
}
sort.Strings(availableUsernames)

return map[string]coreconfig.AuthPrompt{"k8s-auth-info": {
Type: coreconfig.AuthPromptTypeMenu,
Entries: availableUsernames,
DisplayName: "Choose your Kubernetes authentication info",
}}, nil
}

func (actor kubernetesAuthActor) getAvailableUsernames() ([]string, error) {
conf, err := actor.k8sConfigGetter.Get()
if err != nil {
return nil, err
Expand All @@ -66,17 +92,11 @@ func (actor kubernetesAuthActor) GetLoginPrompts() (map[string]coreconfig.AuthPr
return nil, errors.New("no kubernetes authentication infos configured")
}

var prompts []string
var usernames []string
for authInfo := range conf.AuthInfos {
prompts = append(prompts, authInfo)
usernames = append(usernames, authInfo)
}
sort.Strings(prompts)

return map[string]coreconfig.AuthPrompt{"k8s-auth-info": {
Type: coreconfig.AuthPromptTypeMenu,
Entries: prompts,
DisplayName: "Choose your Kubernetes authentication info",
}}, nil
return usernames, nil
}

func (actor kubernetesAuthActor) GetCurrentUser() (configv3.User, error) {
Expand Down
37 changes: 36 additions & 1 deletion actor/v7action/k8s_auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,50 @@ var _ = Describe("KubernetesAuthActor", func() {
})

Describe("Authenticate", func() {
var username string
BeforeEach(func() {
username = "bar"
})

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

It("sets the Kubernetes auth-info", func() {
Expect(err).NotTo(HaveOccurred())
Expect(config.SetKubernetesAuthInfoCallCount()).To(Equal(1))
Expect(config.SetKubernetesAuthInfoArgsForCall(0)).To(Equal("bar"))
})

When("the given username is not in the k8s config", func() {
BeforeEach(func() {
username = "no-such-person"
})

It("returns the error", func() {
Expect(err).To(MatchError("kubernetes user not found in configuration: " + username))
})
})

When("getting the k8s config fails", func() {
BeforeEach(func() {
k8sConfigGetter.GetReturns(nil, errors.New("oomph!"))
})

It("returns the error", func() {
Expect(err).To(MatchError("oomph!"))
})
})

When("no auth infos are in the k8s config", func() {
BeforeEach(func() {
k8sConfigGetter.GetReturns(&clientcmdapi.Config{}, nil)
})

It("returns an error", func() {
Expect(err).To(MatchError("no kubernetes authentication infos configured"))
})
})
})

Describe("GetLoginPrompts", func() {
Expand Down
20 changes: 0 additions & 20 deletions command/v7/auth_command.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package v7

import (
"errors"
"fmt"

"code.cloudfoundry.org/cli/api/uaa/constant"
Expand Down Expand Up @@ -79,25 +78,6 @@ func (cmd AuthCommand) Execute(args []string) error {
credentials["client_id"] = username
credentials["client_secret"] = password
} else if cmd.Config.IsCFOnK8s() {
prompts, err := cmd.Actor.GetLoginPrompts()
if err != nil {
return err
}
prompt, ok := prompts["k8s-auth-info"]
if !ok {
return errors.New("kubernetes login context is missing")
}

userFound := false
for _, val := range prompt.Entries {
if val == username {
userFound = true
break
}
}
if !userFound {
return errors.New("kubernetes user not found in configuration: " + username)
}
credentials = map[string]string{
"k8s-auth-info": username,
}
Expand Down
45 changes: 13 additions & 32 deletions command/v7/auth_command_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package v7_test

import (
"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
"errors"

"code.cloudfoundry.org/cli/api/uaa"
Expand All @@ -19,13 +18,12 @@ import (

var _ = Describe("auth Command", func() {
var (
cmd AuthCommand
testUI *ui.UI
fakeActor *v7fakes.FakeActor
fakeConfig *commandfakes.FakeConfig
binaryName string
err error
k8sLoginPrompts map[string]coreconfig.AuthPrompt
cmd AuthCommand
testUI *ui.UI
fakeActor *v7fakes.FakeActor
fakeConfig *commandfakes.FakeConfig
binaryName string
err error
)

BeforeEach(func() {
Expand All @@ -45,11 +43,6 @@ var _ = Describe("auth Command", func() {
fakeConfig.BinaryNameReturns(binaryName)
fakeConfig.UAAOAuthClientReturns("cf")
fakeConfig.APIVersionReturns("3.99.0")
k8sLoginPrompts = map[string]coreconfig.AuthPrompt{
"k8s-auth-info": {
Entries: []string{"myuser"},
},
}
})

JustBeforeEach(func() {
Expand Down Expand Up @@ -124,7 +117,6 @@ var _ = Describe("auth Command", func() {
When("authenticating against Korifi", func() {
BeforeEach(func() {
fakeConfig.IsCFOnK8sReturns(true)
fakeActor.GetLoginPromptsReturns(k8sLoginPrompts, nil)
})

It("succeeds", func() {
Expand Down Expand Up @@ -321,33 +313,22 @@ var _ = Describe("auth Command", func() {
BeforeEach(func() {
cmd.RequiredArgs.Username = "myuser"
fakeConfig.IsCFOnK8sReturns(true)
fakeActor.GetLoginPromptsReturns(k8sLoginPrompts, nil)
})

When("the specified username doesn't match any k8s context", func() {
BeforeEach(func() {
cmd.RequiredArgs.Username = "some-unknown-user"
})

It("errors", func() {
Expect(err).To(MatchError(errors.New("kubernetes user not found in configuration: some-unknown-user")))
})
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"}))
})

When("the prompts don't contain k8s authentication information", func() {
When("there is an error authenticating with the given username", func() {
BeforeEach(func() {
k8sLoginPrompts = map[string]coreconfig.AuthPrompt{
"some-other-auth-info": {
Entries: []string{"myuser"},
},
}
fakeActor.GetLoginPromptsReturns(k8sLoginPrompts, nil)
fakeActor.AuthenticateReturns(errors.New("stuff go boom"))
})

It("errors", func() {
Expect(err).To(MatchError(errors.New("kubernetes login context is missing")))
Expect(err).To(MatchError("stuff go boom"))
})

})

})
Expand Down

0 comments on commit 3c3e049

Please sign in to comment.