github.com/wanddynosios/cli/v8@v8.7.9-0.20240221182337-1a92e3a7017f/command/v7/auth_command_test.go (about)

     1  package v7_test
     2  
     3  import (
     4  	"errors"
     5  
     6  	"code.cloudfoundry.org/cli/api/uaa"
     7  	"code.cloudfoundry.org/cli/api/uaa/constant"
     8  	"code.cloudfoundry.org/cli/api/uaa/uaaversion"
     9  	"code.cloudfoundry.org/cli/command/commandfakes"
    10  	"code.cloudfoundry.org/cli/command/translatableerror"
    11  	. "code.cloudfoundry.org/cli/command/v7"
    12  	"code.cloudfoundry.org/cli/command/v7/v7fakes"
    13  	"code.cloudfoundry.org/cli/util/ui"
    14  	. "github.com/onsi/ginkgo"
    15  	. "github.com/onsi/gomega"
    16  	. "github.com/onsi/gomega/gbytes"
    17  )
    18  
    19  var _ = Describe("auth Command", func() {
    20  	var (
    21  		cmd        AuthCommand
    22  		testUI     *ui.UI
    23  		fakeActor  *v7fakes.FakeActor
    24  		fakeConfig *commandfakes.FakeConfig
    25  		binaryName string
    26  		err        error
    27  	)
    28  
    29  	BeforeEach(func() {
    30  		testUI = ui.NewTestUI(nil, NewBuffer(), NewBuffer())
    31  		fakeActor = new(v7fakes.FakeActor)
    32  		fakeConfig = new(commandfakes.FakeConfig)
    33  
    34  		cmd = AuthCommand{
    35  			BaseCommand: BaseCommand{
    36  				UI:     testUI,
    37  				Config: fakeConfig,
    38  				Actor:  fakeActor,
    39  			},
    40  		}
    41  
    42  		binaryName = "faceman"
    43  		fakeConfig.BinaryNameReturns(binaryName)
    44  		fakeConfig.UAAOAuthClientReturns("cf")
    45  		fakeConfig.APIVersionReturns("3.99.0")
    46  	})
    47  
    48  	JustBeforeEach(func() {
    49  		err = cmd.Execute(nil)
    50  	})
    51  
    52  	When("--origin are set", func() {
    53  		BeforeEach(func() {
    54  			cmd.Origin = "some-origin"
    55  		})
    56  
    57  		When("the UAA is below the minimum API version", func() {
    58  			BeforeEach(func() {
    59  				fakeActor.GetUAAAPIVersionReturns(uaaversion.InvalidUAAClientVersion, nil)
    60  			})
    61  
    62  			It("returns an API version error", func() {
    63  				Expect(err).To(MatchError(translatableerror.MinimumUAAAPIVersionNotMetError{
    64  					Command:        "Option '--origin'",
    65  					MinimumVersion: uaaversion.MinUAAClientVersion,
    66  				}))
    67  			})
    68  		})
    69  
    70  		When("--client-credentials set", func() {
    71  			BeforeEach(func() {
    72  				cmd.ClientCredentials = true
    73  				fakeActor.GetUAAAPIVersionReturns(uaaversion.MinUAAClientVersion, nil)
    74  			})
    75  
    76  			It("returns an ArgumentCombinationError", func() {
    77  				Expect(err).To(MatchError(translatableerror.ArgumentCombinationError{
    78  					Args: []string{"--client-credentials", "--origin"},
    79  				}))
    80  			})
    81  		})
    82  	})
    83  
    84  	When("credentials are missing", func() {
    85  		When("username and password are both missing", func() {
    86  			It("raises an error", func() {
    87  				Expect(err).To(MatchError(translatableerror.MissingCredentialsError{
    88  					MissingUsername: true,
    89  					MissingPassword: true,
    90  				}))
    91  			})
    92  		})
    93  
    94  		When("username is missing", func() {
    95  			BeforeEach(func() {
    96  				cmd.RequiredArgs.Password = "mypassword"
    97  			})
    98  
    99  			It("raises an error", func() {
   100  				Expect(err).To(MatchError(translatableerror.MissingCredentialsError{
   101  					MissingUsername: true,
   102  				}))
   103  			})
   104  		})
   105  
   106  		When("password is missing", func() {
   107  			BeforeEach(func() {
   108  				cmd.RequiredArgs.Username = "myuser"
   109  			})
   110  
   111  			It("raises an error", func() {
   112  				Expect(err).To(MatchError(translatableerror.MissingCredentialsError{
   113  					MissingPassword: true,
   114  				}))
   115  			})
   116  
   117  			When("authenticating against Korifi", func() {
   118  				BeforeEach(func() {
   119  					fakeConfig.IsCFOnK8sReturns(true)
   120  				})
   121  
   122  				It("succeeds", func() {
   123  					Expect(err).NotTo(HaveOccurred())
   124  				})
   125  			})
   126  		})
   127  
   128  		When("the password is given", func() {
   129  			BeforeEach(func() {
   130  				cmd.RequiredArgs.Username = "myuser"
   131  				cmd.RequiredArgs.Password = "mypassword"
   132  			})
   133  
   134  			When("authenticating against korifi", func() {
   135  				BeforeEach(func() {
   136  					fakeConfig.IsCFOnK8sReturns(true)
   137  				})
   138  
   139  				It("succeeds but warns", func() {
   140  					Expect(err).NotTo(HaveOccurred())
   141  					Expect(testUI.Err).To(Say("Warning: password is ignored when authenticating against Kubernetes."))
   142  				})
   143  			})
   144  		})
   145  	})
   146  
   147  	When("there is an auth error", func() {
   148  		BeforeEach(func() {
   149  			cmd.RequiredArgs.Username = "foo"
   150  			cmd.RequiredArgs.Password = "bar"
   151  
   152  			fakeConfig.TargetReturns("some-api-target")
   153  			fakeActor.AuthenticateReturns(uaa.UnauthorizedError{Message: "some message"})
   154  		})
   155  
   156  		It("returns a BadCredentialsError", func() {
   157  			Expect(err).To(MatchError(uaa.UnauthorizedError{Message: "some message"}))
   158  		})
   159  	})
   160  
   161  	When("there is an account locked error", func() {
   162  		BeforeEach(func() {
   163  			cmd.RequiredArgs.Username = "foo"
   164  			cmd.RequiredArgs.Password = "bar"
   165  
   166  			fakeConfig.TargetReturns("some-api-target")
   167  			fakeActor.AuthenticateReturns(uaa.AccountLockedError{Message: "some message"})
   168  		})
   169  
   170  		It("returns a BadCredentialsError", func() {
   171  			Expect(err).To(MatchError(uaa.AccountLockedError{Message: "some message"}))
   172  		})
   173  	})
   174  
   175  	When("there is a non-auth error", func() {
   176  		var expectedError error
   177  
   178  		BeforeEach(func() {
   179  			cmd.RequiredArgs.Username = "foo"
   180  			cmd.RequiredArgs.Password = "bar"
   181  
   182  			fakeConfig.TargetReturns("some-api-target")
   183  			expectedError = errors.New("my humps")
   184  
   185  			fakeActor.AuthenticateReturns(expectedError)
   186  		})
   187  
   188  		It("returns the error", func() {
   189  			Expect(err).To(MatchError(expectedError))
   190  		})
   191  	})
   192  
   193  	When("there are no input errors", func() {
   194  		var (
   195  			testID     string
   196  			testSecret string
   197  		)
   198  
   199  		BeforeEach(func() {
   200  			testID = "hello"
   201  			testSecret = "goodbye"
   202  
   203  			fakeConfig.TargetReturns("some-api-target")
   204  		})
   205  
   206  		When("--client-credentials is set", func() {
   207  			BeforeEach(func() {
   208  				cmd.ClientCredentials = true
   209  				cmd.RequiredArgs.Username = testID
   210  				cmd.RequiredArgs.Password = testSecret
   211  			})
   212  
   213  			It("outputs API target information and clears the targeted org and space", func() {
   214  				Expect(err).ToNot(HaveOccurred())
   215  
   216  				Expect(testUI.Out).To(Say("API endpoint: %s", fakeConfig.Target()))
   217  				Expect(testUI.Out).To(Say(`Authenticating\.\.\.`))
   218  				Expect(testUI.Out).To(Say("OK"))
   219  				Expect(testUI.Out).To(Say("Use '%s target' to view or set your target org and space", binaryName))
   220  
   221  				Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   222  				credentials, origin, grantType := fakeActor.AuthenticateArgsForCall(0)
   223  				ID := credentials["client_id"]
   224  				secret := credentials["client_secret"]
   225  				Expect(ID).To(Equal(testID))
   226  				Expect(secret).To(Equal(testSecret))
   227  				Expect(origin).To(BeEmpty())
   228  				Expect(grantType).To(Equal(constant.GrantTypeClientCredentials))
   229  			})
   230  		})
   231  
   232  		When("--client-credentials is not set", func() {
   233  			When("username and password are only provided as arguments", func() {
   234  				BeforeEach(func() {
   235  					cmd.RequiredArgs.Username = testID
   236  					cmd.RequiredArgs.Password = testSecret
   237  				})
   238  
   239  				When("the API version is older than the minimum supported API version for the v7 CLI", func() {
   240  					BeforeEach(func() {
   241  						fakeConfig.APIVersionReturns("3.83.0")
   242  					})
   243  					It("warns that the user is targeting an unsupported API version and that things may not work correctly", func() {
   244  						Expect(err).ToNot(HaveOccurred())
   245  						Expect(testUI.Out).To(Say("API endpoint: %s", fakeConfig.Target()))
   246  						Expect(testUI.Err).To(Say("Warning: Your targeted API's version \\(3.83.0\\) is less than the minimum supported API version \\(3.99.0\\). Some commands may not function correctly."))
   247  					})
   248  				})
   249  
   250  				When("the API version is empty", func() {
   251  					BeforeEach(func() {
   252  						fakeConfig.APIVersionReturns("")
   253  					})
   254  					It("prints a warning message", func() {
   255  						Expect(err).ToNot(HaveOccurred())
   256  						Expect(testUI.Err).To(Say("Warning: unable to determine whether targeted API's version meets minimum supported."))
   257  					})
   258  				})
   259  
   260  				It("should NOT warn that the user is targeting an unsupported API version", func() {
   261  					Expect(testUI.Err).ToNot(Say("is less than the minimum supported API version"))
   262  				})
   263  
   264  				It("outputs API target information and clears the targeted org and space", func() {
   265  					Expect(err).ToNot(HaveOccurred())
   266  
   267  					Expect(testUI.Out).To(Say("API endpoint: %s", fakeConfig.Target()))
   268  					Expect(testUI.Out).To(Say(`Authenticating\.\.\.`))
   269  					Expect(testUI.Out).To(Say("OK"))
   270  					Expect(testUI.Out).To(Say("Use '%s target' to view or set your target org and space", binaryName))
   271  
   272  					Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   273  					credentials, origin, grantType := fakeActor.AuthenticateArgsForCall(0)
   274  					username := credentials["username"]
   275  					password := credentials["password"]
   276  					Expect(username).To(Equal(testID))
   277  					Expect(password).To(Equal(testSecret))
   278  					Expect(origin).To(BeEmpty())
   279  					Expect(grantType).To(Equal(constant.GrantTypePassword))
   280  				})
   281  			})
   282  
   283  			When("the username and password are provided in env variables", func() {
   284  				var (
   285  					envUsername string
   286  					envPassword string
   287  				)
   288  
   289  				BeforeEach(func() {
   290  					envUsername = "banana"
   291  					envPassword = "potato"
   292  					fakeConfig.CFUsernameReturns(envUsername)
   293  					fakeConfig.CFPasswordReturns(envPassword)
   294  				})
   295  
   296  				When("username and password are not also provided as arguments", func() {
   297  					It("authenticates with the values in the env variables", func() {
   298  						Expect(err).ToNot(HaveOccurred())
   299  
   300  						Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   301  						credentials, origin, _ := fakeActor.AuthenticateArgsForCall(0)
   302  						username := credentials["username"]
   303  						password := credentials["password"]
   304  						Expect(username).To(Equal(envUsername))
   305  						Expect(password).To(Equal(envPassword))
   306  						Expect(origin).To(BeEmpty())
   307  					})
   308  				})
   309  
   310  				When("username and password are also provided as arguments", func() {
   311  					BeforeEach(func() {
   312  						cmd.RequiredArgs.Username = testID
   313  						cmd.RequiredArgs.Password = testSecret
   314  					})
   315  
   316  					It("authenticates with the values from the command line args", func() {
   317  						Expect(err).ToNot(HaveOccurred())
   318  
   319  						Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   320  						credentials, origin, _ := fakeActor.AuthenticateArgsForCall(0)
   321  						username := credentials["username"]
   322  						password := credentials["password"]
   323  						Expect(username).To(Equal(testID))
   324  						Expect(password).To(Equal(testSecret))
   325  						Expect(origin).To(BeEmpty())
   326  					})
   327  				})
   328  			})
   329  
   330  			When("authenticating against Korifi", func() {
   331  				BeforeEach(func() {
   332  					cmd.RequiredArgs.Username = "myuser"
   333  					fakeConfig.IsCFOnK8sReturns(true)
   334  				})
   335  
   336  				It("attempts to authenticate with the correct username", func() {
   337  					Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   338  					credentials, _, _ := fakeActor.AuthenticateArgsForCall(0)
   339  					Expect(credentials).To(HaveKeyWithValue("username", "myuser"))
   340  				})
   341  
   342  				When("there is an error authenticating with the given username", func() {
   343  					BeforeEach(func() {
   344  						fakeActor.AuthenticateReturns(errors.New("stuff go boom"))
   345  					})
   346  
   347  					It("errors", func() {
   348  						Expect(err).To(MatchError("stuff go boom"))
   349  					})
   350  				})
   351  
   352  			})
   353  		})
   354  
   355  		When("a user has manually added their client credentials to the config file", func() {
   356  			BeforeEach(func() {
   357  				fakeConfig.UAAOAuthClientReturns("AClientsId")
   358  			})
   359  
   360  			When("the --client-credentials flag is not set", func() {
   361  				BeforeEach(func() {
   362  					cmd.ClientCredentials = false
   363  					cmd.RequiredArgs.Username = "some-username"
   364  					cmd.RequiredArgs.Password = "some-password"
   365  				})
   366  
   367  				It("fails with an error indicating manual client credentials are no longer supported in the config file", func() {
   368  					Expect(err).To(MatchError(translatableerror.ManualClientCredentialsError{}))
   369  				})
   370  			})
   371  		})
   372  	})
   373  
   374  	When("already logged in via client credentials", func() {
   375  		BeforeEach(func() {
   376  			fakeConfig.UAAGrantTypeReturns("client_credentials")
   377  		})
   378  
   379  		When("authenticating as a user", func() {
   380  			BeforeEach(func() {
   381  				cmd.ClientCredentials = false
   382  				cmd.RequiredArgs.Username = "some-username"
   383  				cmd.RequiredArgs.Password = "some-password"
   384  			})
   385  
   386  			It("returns an already logged in error", func() {
   387  				Expect(err).To(MatchError("Service account currently logged in. Use 'cf logout' to log out service account and try again."))
   388  				Expect(fakeConfig.UAAGrantTypeCallCount()).To(Equal(1))
   389  			})
   390  
   391  			It("the returned error is translatable", func() {
   392  				Expect(err).To(MatchError(translatableerror.PasswordGrantTypeLogoutRequiredError{}))
   393  			})
   394  		})
   395  
   396  		When("authenticating as a client", func() {
   397  			BeforeEach(func() {
   398  				cmd.ClientCredentials = true
   399  				cmd.RequiredArgs.Username = "some-client-id"
   400  				cmd.RequiredArgs.Password = "some-client-secret"
   401  			})
   402  			It("does not error", func() {
   403  				Expect(err).ToNot(HaveOccurred())
   404  				Expect(fakeConfig.UAAGrantTypeCallCount()).To(Equal(0))
   405  			})
   406  		})
   407  	})
   408  })