github.com/mook-as/cf-cli@v7.0.0-beta.28.0.20200120190804-b91c115fae48+incompatible/command/v6/auth_command_test.go (about)

     1  package v6_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/v6"
    12  	"code.cloudfoundry.org/cli/command/v6/v6fakes"
    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  *v6fakes.FakeAuthActor
    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(v6fakes.FakeAuthActor)
    32  		fakeConfig = new(commandfakes.FakeConfig)
    33  
    34  		cmd = AuthCommand{
    35  			UI:     testUI,
    36  			Config: fakeConfig,
    37  			Actor:  fakeActor,
    38  		}
    39  
    40  		binaryName = "faceman"
    41  		fakeConfig.BinaryNameReturns(binaryName)
    42  	})
    43  
    44  	JustBeforeEach(func() {
    45  		err = cmd.Execute(nil)
    46  	})
    47  
    48  	When("--origin are set", func() {
    49  		BeforeEach(func() {
    50  			cmd.Origin = "some-origin"
    51  		})
    52  
    53  		When("the UAA is below the minimum API version", func() {
    54  			BeforeEach(func() {
    55  				fakeActor.UAAAPIVersionReturns(uaaversion.MinUAAClientVersion)
    56  			})
    57  
    58  			It("returns an API version error", func() {
    59  				Expect(err).To(MatchError(translatableerror.MinimumUAAAPIVersionNotMetError{
    60  					Command:        "Option '--origin'",
    61  					MinimumVersion: uaaversion.MinVersionOrigin,
    62  				}))
    63  			})
    64  		})
    65  
    66  		When("--client-credentials set", func() {
    67  			BeforeEach(func() {
    68  				cmd.ClientCredentials = true
    69  				fakeActor.UAAAPIVersionReturns(uaaversion.MinVersionOrigin)
    70  			})
    71  
    72  			It("returns an ArgumentCombinationError", func() {
    73  				Expect(err).To(MatchError(translatableerror.ArgumentCombinationError{
    74  					Args: []string{"--client-credentials", "--origin"},
    75  				}))
    76  			})
    77  		})
    78  
    79  		When("when the UAA is above the minimum API version", func() {
    80  			BeforeEach(func() {
    81  				cmd.RequiredArgs.Username = "doesn't matter"
    82  				cmd.RequiredArgs.Password = "doesn't matter"
    83  				fakeActor.UAAAPIVersionReturns(uaaversion.MinVersionOrigin)
    84  			})
    85  
    86  			It("authenticates with the values from the command line args", func() {
    87  				Expect(err).ToNot(HaveOccurred())
    88  
    89  				Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
    90  				_, _, origin, _ := fakeActor.AuthenticateArgsForCall(0)
    91  				Expect(origin).To(Equal("some-origin"))
    92  			})
    93  		})
    94  	})
    95  
    96  	When("credentials are missing", func() {
    97  		When("username and password are both missing", func() {
    98  			It("raises an error", func() {
    99  				Expect(err).To(MatchError(translatableerror.MissingCredentialsError{
   100  					MissingUsername: true,
   101  					MissingPassword: true,
   102  				}))
   103  			})
   104  		})
   105  
   106  		When("username is missing", func() {
   107  			BeforeEach(func() {
   108  				cmd.RequiredArgs.Password = "mypassword"
   109  			})
   110  
   111  			It("raises an error", func() {
   112  				Expect(err).To(MatchError(translatableerror.MissingCredentialsError{
   113  					MissingUsername: true,
   114  				}))
   115  			})
   116  		})
   117  
   118  		When("password is missing", func() {
   119  			BeforeEach(func() {
   120  				cmd.RequiredArgs.Username = "myuser"
   121  			})
   122  
   123  			It("raises an error", func() {
   124  				Expect(err).To(MatchError(translatableerror.MissingCredentialsError{
   125  					MissingPassword: true,
   126  				}))
   127  			})
   128  		})
   129  	})
   130  
   131  	When("there is an auth error", func() {
   132  		BeforeEach(func() {
   133  			cmd.RequiredArgs.Username = "foo"
   134  			cmd.RequiredArgs.Password = "bar"
   135  
   136  			fakeConfig.TargetReturns("some-api-target")
   137  			fakeActor.AuthenticateReturns(uaa.UnauthorizedError{Message: "some message"})
   138  		})
   139  
   140  		It("returns a BadCredentialsError", func() {
   141  			Expect(err).To(MatchError(uaa.UnauthorizedError{Message: "some message"}))
   142  		})
   143  	})
   144  
   145  	When("there is an account locked error", func() {
   146  		BeforeEach(func() {
   147  			cmd.RequiredArgs.Username = "foo"
   148  			cmd.RequiredArgs.Password = "bar"
   149  
   150  			fakeConfig.TargetReturns("some-api-target")
   151  			fakeActor.AuthenticateReturns(uaa.AccountLockedError{Message: "some message"})
   152  		})
   153  
   154  		It("returns a BadCredentialsError", func() {
   155  			Expect(err).To(MatchError(uaa.AccountLockedError{Message: "some message"}))
   156  		})
   157  	})
   158  
   159  	When("there is a non-auth error", func() {
   160  		var expectedError error
   161  
   162  		BeforeEach(func() {
   163  			cmd.RequiredArgs.Username = "foo"
   164  			cmd.RequiredArgs.Password = "bar"
   165  
   166  			fakeConfig.TargetReturns("some-api-target")
   167  			expectedError = errors.New("my humps")
   168  
   169  			fakeActor.AuthenticateReturns(expectedError)
   170  		})
   171  
   172  		It("returns the error", func() {
   173  			Expect(err).To(MatchError(expectedError))
   174  		})
   175  	})
   176  
   177  	Describe("it checks the CLI version", func() {
   178  		var (
   179  			apiVersion    string
   180  			minCLIVersion string
   181  			binaryVersion string
   182  		)
   183  
   184  		BeforeEach(func() {
   185  			apiVersion = "1.2.3"
   186  			fakeActor.CloudControllerAPIVersionReturns(apiVersion)
   187  			minCLIVersion = "1.0.0"
   188  			fakeConfig.MinCLIVersionReturns(minCLIVersion)
   189  
   190  			cmd.RequiredArgs.Username = "user"
   191  			cmd.RequiredArgs.Password = "password"
   192  		})
   193  
   194  		Context("the CLI version is older than the minimum version required by the API", func() {
   195  			BeforeEach(func() {
   196  				binaryVersion = "0.0.0"
   197  				fakeConfig.BinaryVersionReturns(binaryVersion)
   198  			})
   199  
   200  			It("displays a recommendation to update the CLI version", func() {
   201  				Expect(err).ToNot(HaveOccurred())
   202  				Expect(testUI.Err).To(Say("Cloud Foundry API version %s requires CLI version %s. You are currently on version %s. To upgrade your CLI, please visit: https://github.com/cloudfoundry/cli#downloads", apiVersion, minCLIVersion, binaryVersion))
   203  			})
   204  		})
   205  
   206  		Context("the CLI version satisfies the API's minimum version requirements", func() {
   207  			BeforeEach(func() {
   208  				binaryVersion = "1.0.0"
   209  				fakeConfig.BinaryVersionReturns(binaryVersion)
   210  			})
   211  
   212  			It("does not display a recommendation to update the CLI version", func() {
   213  				Expect(err).ToNot(HaveOccurred())
   214  				Expect(testUI.Err).ToNot(Say("Cloud Foundry API version %s requires CLI version %s. You are currently on version %s. To upgrade your CLI, please visit: https://github.com/cloudfoundry/cli#downloads", apiVersion, minCLIVersion, binaryVersion))
   215  			})
   216  		})
   217  
   218  		When("the CLI version is invalid", func() {
   219  			BeforeEach(func() {
   220  				fakeConfig.BinaryVersionReturns("&#%")
   221  			})
   222  
   223  			It("returns an error", func() {
   224  				Expect(err).To(HaveOccurred())
   225  				Expect(err.Error()).To(Equal("No Major.Minor.Patch elements found"))
   226  			})
   227  		})
   228  	})
   229  
   230  	When("there are no input errors", func() {
   231  		var (
   232  			testID     string
   233  			testSecret string
   234  		)
   235  
   236  		BeforeEach(func() {
   237  			testID = "hello"
   238  			testSecret = "goodbye"
   239  
   240  			fakeConfig.TargetReturns("some-api-target")
   241  		})
   242  
   243  		When("--client-credentials is set", func() {
   244  			BeforeEach(func() {
   245  				cmd.ClientCredentials = true
   246  				cmd.RequiredArgs.Username = testID
   247  				cmd.RequiredArgs.Password = testSecret
   248  			})
   249  
   250  			It("outputs API target information and clears the targeted org and space", func() {
   251  				Expect(err).ToNot(HaveOccurred())
   252  
   253  				Expect(testUI.Out).To(Say("API endpoint: %s", fakeConfig.Target()))
   254  				Expect(testUI.Out).To(Say(`Authenticating\.\.\.`))
   255  				Expect(testUI.Out).To(Say("OK"))
   256  				Expect(testUI.Out).To(Say("Use '%s target' to view or set your target org and space", binaryName))
   257  
   258  				Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   259  				ID, secret, origin, grantType := fakeActor.AuthenticateArgsForCall(0)
   260  				Expect(ID).To(Equal(testID))
   261  				Expect(secret).To(Equal(testSecret))
   262  				Expect(origin).To(BeEmpty())
   263  				Expect(grantType).To(Equal(constant.GrantTypeClientCredentials))
   264  			})
   265  		})
   266  
   267  		When("--client-credentials is not set", func() {
   268  			When("username and password are only provided as arguments", func() {
   269  				BeforeEach(func() {
   270  					cmd.RequiredArgs.Username = testID
   271  					cmd.RequiredArgs.Password = testSecret
   272  				})
   273  
   274  				It("outputs API target information and clears the targeted org and space", func() {
   275  					Expect(err).ToNot(HaveOccurred())
   276  
   277  					Expect(testUI.Out).To(Say("API endpoint: %s", fakeConfig.Target()))
   278  					Expect(testUI.Out).To(Say(`Authenticating\.\.\.`))
   279  					Expect(testUI.Out).To(Say("OK"))
   280  					Expect(testUI.Out).To(Say("Use '%s target' to view or set your target org and space", binaryName))
   281  
   282  					Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   283  					username, password, origin, grantType := fakeActor.AuthenticateArgsForCall(0)
   284  					Expect(username).To(Equal(testID))
   285  					Expect(password).To(Equal(testSecret))
   286  					Expect(origin).To(BeEmpty())
   287  					Expect(grantType).To(Equal(constant.GrantTypePassword))
   288  				})
   289  			})
   290  
   291  			When("the username and password are provided in env variables", func() {
   292  				var (
   293  					envUsername string
   294  					envPassword string
   295  				)
   296  
   297  				BeforeEach(func() {
   298  					envUsername = "banana"
   299  					envPassword = "potato"
   300  					fakeConfig.CFUsernameReturns(envUsername)
   301  					fakeConfig.CFPasswordReturns(envPassword)
   302  				})
   303  
   304  				When("username and password are not also provided as arguments", func() {
   305  					It("authenticates with the values in the env variables", func() {
   306  						Expect(err).ToNot(HaveOccurred())
   307  
   308  						Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   309  						username, password, origin, _ := fakeActor.AuthenticateArgsForCall(0)
   310  						Expect(username).To(Equal(envUsername))
   311  						Expect(password).To(Equal(envPassword))
   312  						Expect(origin).To(BeEmpty())
   313  					})
   314  				})
   315  
   316  				When("username and password are also provided as arguments", func() {
   317  					BeforeEach(func() {
   318  						cmd.RequiredArgs.Username = testID
   319  						cmd.RequiredArgs.Password = testSecret
   320  					})
   321  
   322  					It("authenticates with the values from the command line args", func() {
   323  						Expect(err).ToNot(HaveOccurred())
   324  
   325  						Expect(fakeActor.AuthenticateCallCount()).To(Equal(1))
   326  						username, password, origin, _ := fakeActor.AuthenticateArgsForCall(0)
   327  						Expect(username).To(Equal(testID))
   328  						Expect(password).To(Equal(testSecret))
   329  						Expect(origin).To(BeEmpty())
   330  					})
   331  				})
   332  			})
   333  		})
   334  
   335  		When("client id or client secret are in the config.json", func() {
   336  			BeforeEach(func() {
   337  				fakeConfig.UAAOAuthClientReturns("AClientsId")
   338  			})
   339  			When("using --client-credentials", func() {
   340  				BeforeEach(func() {
   341  					cmd.ClientCredentials = true
   342  					cmd.RequiredArgs.Username = "some-client-id"
   343  					cmd.RequiredArgs.Password = "some-client-secret"
   344  
   345  				})
   346  				It("does not output a deprecation warning", func() {
   347  					Expect(testUI.Err).ToNot(Say("Deprecation warning"))
   348  				})
   349  			})
   350  			When("logging in as a user", func() {
   351  				BeforeEach(func() {
   352  					cmd.ClientCredentials = false
   353  					cmd.RequiredArgs.Username = "some-username"
   354  					cmd.RequiredArgs.Password = "some-password"
   355  				})
   356  				It("outputs a deprecation warning", func() {
   357  					Expect(testUI.Err).To(Say("Deprecation warning: Manually writing your client credentials to the config.json is deprecated and will be removed in the future. For similar functionality, please use the `cf auth --client-credentials` command instead."))
   358  				})
   359  			})
   360  		})
   361  	})
   362  
   363  	When("already logged in via client credentials", func() {
   364  		BeforeEach(func() {
   365  			fakeConfig.UAAGrantTypeReturns("client_credentials")
   366  		})
   367  
   368  		When("authenticating as a user", func() {
   369  			BeforeEach(func() {
   370  				cmd.ClientCredentials = false
   371  				cmd.RequiredArgs.Username = "some-username"
   372  				cmd.RequiredArgs.Password = "some-password"
   373  			})
   374  
   375  			It("returns an already logged in error", func() {
   376  				Expect(err).To(MatchError("Service account currently logged in. Use 'cf logout' to log out service account and try again."))
   377  				Expect(fakeConfig.UAAGrantTypeCallCount()).To(Equal(1))
   378  			})
   379  
   380  			It("the returned error is translatable", func() {
   381  				Expect(err).To(MatchError(translatableerror.PasswordGrantTypeLogoutRequiredError{}))
   382  			})
   383  		})
   384  
   385  		When("authenticating as a client", func() {
   386  			BeforeEach(func() {
   387  				cmd.ClientCredentials = true
   388  				cmd.RequiredArgs.Username = "some-client-id"
   389  				cmd.RequiredArgs.Password = "some-client-secret"
   390  			})
   391  			It("does not error", func() {
   392  				Expect(err).ToNot(HaveOccurred())
   393  				Expect(fakeConfig.UAAGrantTypeCallCount()).To(Equal(0))
   394  			})
   395  		})
   396  	})
   397  })