github.com/dcarley/cf-cli@v6.24.1-0.20170220111324-4225ff346898+incompatible/cf/commands/login_test.go (about)

     1  package commands_test
     2  
     3  import (
     4  	"strconv"
     5  
     6  	"code.cloudfoundry.org/cli/cf/api/authentication/authenticationfakes"
     7  	"code.cloudfoundry.org/cli/cf/api/organizations/organizationsfakes"
     8  	"code.cloudfoundry.org/cli/cf/api/spaces/spacesfakes"
     9  	"code.cloudfoundry.org/cli/cf/commandregistry"
    10  	"code.cloudfoundry.org/cli/cf/configuration/coreconfig"
    11  	"code.cloudfoundry.org/cli/cf/configuration/coreconfig/coreconfigfakes"
    12  	"code.cloudfoundry.org/cli/cf/errors"
    13  	"code.cloudfoundry.org/cli/cf/models"
    14  	testcmd "code.cloudfoundry.org/cli/util/testhelpers/commands"
    15  	testconfig "code.cloudfoundry.org/cli/util/testhelpers/configuration"
    16  	testterm "code.cloudfoundry.org/cli/util/testhelpers/terminal"
    17  	. "github.com/onsi/ginkgo"
    18  	. "github.com/onsi/gomega"
    19  
    20  	. "code.cloudfoundry.org/cli/util/testhelpers/matchers"
    21  )
    22  
    23  var _ = Describe("Login Command", func() {
    24  	var (
    25  		Flags        []string
    26  		Config       coreconfig.Repository
    27  		ui           *testterm.FakeUI
    28  		authRepo     *authenticationfakes.FakeRepository
    29  		endpointRepo *coreconfigfakes.FakeEndpointRepository
    30  		orgRepo      *organizationsfakes.FakeOrganizationRepository
    31  		spaceRepo    *spacesfakes.FakeSpaceRepository
    32  
    33  		org  models.Organization
    34  		deps commandregistry.Dependency
    35  
    36  		minCLIVersion            string
    37  		minRecommendedCLIVersion string
    38  	)
    39  
    40  	updateCommandDependency := func(pluginCall bool) {
    41  		deps.UI = ui
    42  		deps.Config = Config
    43  		deps.RepoLocator = deps.RepoLocator.SetEndpointRepository(endpointRepo)
    44  		deps.RepoLocator = deps.RepoLocator.SetAuthenticationRepository(authRepo)
    45  		deps.RepoLocator = deps.RepoLocator.SetOrganizationRepository(orgRepo)
    46  		deps.RepoLocator = deps.RepoLocator.SetSpaceRepository(spaceRepo)
    47  		commandregistry.Commands.SetCommand(commandregistry.Commands.FindCommand("login").SetDependency(deps, pluginCall))
    48  	}
    49  
    50  	listSpacesStub := func(spaces []models.Space) func(func(models.Space) bool) error {
    51  		return func(cb func(models.Space) bool) error {
    52  			var keepGoing bool
    53  			for _, s := range spaces {
    54  				keepGoing = cb(s)
    55  				if !keepGoing {
    56  					return nil
    57  				}
    58  			}
    59  			return nil
    60  		}
    61  	}
    62  
    63  	BeforeEach(func() {
    64  		Flags = []string{}
    65  		Config = testconfig.NewRepository()
    66  		ui = &testterm.FakeUI{}
    67  		authRepo = new(authenticationfakes.FakeRepository)
    68  		authRepo.AuthenticateStub = func(credentials map[string]string) error {
    69  			Config.SetAccessToken("my_access_token")
    70  			Config.SetRefreshToken("my_refresh_token")
    71  			return nil
    72  		}
    73  		endpointRepo = new(coreconfigfakes.FakeEndpointRepository)
    74  		minCLIVersion = "1.0.0"
    75  		minRecommendedCLIVersion = "1.0.0"
    76  
    77  		org = models.Organization{}
    78  		org.Name = "my-new-org"
    79  		org.GUID = "my-new-org-guid"
    80  
    81  		orgRepo = &organizationsfakes.FakeOrganizationRepository{}
    82  		orgRepo.ListOrgsReturns([]models.Organization{org}, nil)
    83  
    84  		space := models.Space{}
    85  		space.GUID = "my-space-guid"
    86  		space.Name = "my-space"
    87  
    88  		spaceRepo = new(spacesfakes.FakeSpaceRepository)
    89  		spaceRepo.ListSpacesStub = listSpacesStub([]models.Space{space})
    90  
    91  		authRepo.GetLoginPromptsAndSaveUAAServerURLReturns(map[string]coreconfig.AuthPrompt{
    92  			"username": {
    93  				DisplayName: "Username",
    94  				Type:        coreconfig.AuthPromptTypeText,
    95  			},
    96  			"password": {
    97  				DisplayName: "Password",
    98  				Type:        coreconfig.AuthPromptTypePassword,
    99  			},
   100  		}, nil)
   101  	})
   102  
   103  	Context("interactive usage", func() {
   104  		JustBeforeEach(func() {
   105  			endpointRepo.GetCCInfoStub = func(endpoint string) (*coreconfig.CCInfo, string, error) {
   106  				return &coreconfig.CCInfo{
   107  					APIVersion:               "some-version",
   108  					AuthorizationEndpoint:    "auth/endpoint",
   109  					DopplerEndpoint:          "doppler/endpoint",
   110  					MinCLIVersion:            minCLIVersion,
   111  					MinRecommendedCLIVersion: minRecommendedCLIVersion,
   112  					SSHOAuthClient:           "some-client",
   113  					RoutingAPIEndpoint:       "routing/endpoint",
   114  				}, endpoint, nil
   115  			}
   116  		})
   117  
   118  		Describe("when there are a small number of organizations and spaces", func() {
   119  			var org2 models.Organization
   120  			var space2 models.Space
   121  
   122  			BeforeEach(func() {
   123  				org1 := models.Organization{}
   124  				org1.GUID = "some-org-guid"
   125  				org1.Name = "some-org"
   126  
   127  				org2 = models.Organization{}
   128  				org2.GUID = "my-new-org-guid"
   129  				org2.Name = "my-new-org"
   130  
   131  				space1 := models.Space{}
   132  				space1.GUID = "my-space-guid"
   133  				space1.Name = "my-space"
   134  
   135  				space2 = models.Space{}
   136  				space2.GUID = "some-space-guid"
   137  				space2.Name = "some-space"
   138  
   139  				orgRepo.ListOrgsReturns([]models.Organization{org1, org2}, nil)
   140  				spaceRepo.ListSpacesStub = listSpacesStub([]models.Space{space1, space2})
   141  				spaceRepo.FindByNameStub = func(name string) (models.Space, error) {
   142  					m := map[string]models.Space{
   143  						space1.Name: space1,
   144  						space2.Name: space2,
   145  					}
   146  					return m[name], nil
   147  				}
   148  			})
   149  
   150  			It("lets the user select an org and space by number", func() {
   151  				orgRepo.FindByNameReturns(org2, nil)
   152  				OUT_OF_RANGE_CHOICE := "3"
   153  				ui.Inputs = []string{"api.example.com", "user@example.com", "password", OUT_OF_RANGE_CHOICE, "2", OUT_OF_RANGE_CHOICE, "1"}
   154  
   155  				testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   156  
   157  				Expect(ui.Outputs()).To(ContainSubstrings(
   158  					[]string{"Select an org"},
   159  					[]string{"1. some-org"},
   160  					[]string{"2. my-new-org"},
   161  					[]string{"Select a space"},
   162  					[]string{"1. my-space"},
   163  					[]string{"2. some-space"},
   164  				))
   165  
   166  				Expect(Config.OrganizationFields().GUID).To(Equal("my-new-org-guid"))
   167  				Expect(Config.SpaceFields().GUID).To(Equal("my-space-guid"))
   168  				Expect(Config.AccessToken()).To(Equal("my_access_token"))
   169  				Expect(Config.RefreshToken()).To(Equal("my_refresh_token"))
   170  
   171  				Expect(Config.APIEndpoint()).To(Equal("api.example.com"))
   172  				Expect(Config.APIVersion()).To(Equal("some-version"))
   173  				Expect(Config.AuthenticationEndpoint()).To(Equal("auth/endpoint"))
   174  				Expect(Config.SSHOAuthClient()).To(Equal("some-client"))
   175  				Expect(Config.MinCLIVersion()).To(Equal("1.0.0"))
   176  				Expect(Config.MinRecommendedCLIVersion()).To(Equal("1.0.0"))
   177  				Expect(Config.DopplerEndpoint()).To(Equal("doppler/endpoint"))
   178  				Expect(Config.RoutingAPIEndpoint()).To(Equal("routing/endpoint"))
   179  
   180  				Expect(endpointRepo.GetCCInfoCallCount()).To(Equal(1))
   181  				Expect(endpointRepo.GetCCInfoArgsForCall(0)).To(Equal("api.example.com"))
   182  
   183  				Expect(orgRepo.FindByNameArgsForCall(0)).To(Equal("my-new-org"))
   184  				Expect(spaceRepo.FindByNameArgsForCall(0)).To(Equal("my-space"))
   185  
   186  				Expect(ui.ShowConfigurationCalled).To(BeTrue())
   187  			})
   188  
   189  			It("lets the user select an org and space by name", func() {
   190  				ui.Inputs = []string{"api.example.com", "user@example.com", "password", "my-new-org", "my-space"}
   191  				orgRepo.FindByNameReturns(org2, nil)
   192  
   193  				testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   194  
   195  				Expect(ui.Outputs()).To(ContainSubstrings(
   196  					[]string{"Select an org"},
   197  					[]string{"1. some-org"},
   198  					[]string{"2. my-new-org"},
   199  					[]string{"Select a space"},
   200  					[]string{"1. my-space"},
   201  					[]string{"2. some-space"},
   202  				))
   203  
   204  				Expect(Config.OrganizationFields().GUID).To(Equal("my-new-org-guid"))
   205  				Expect(Config.SpaceFields().GUID).To(Equal("my-space-guid"))
   206  				Expect(Config.AccessToken()).To(Equal("my_access_token"))
   207  				Expect(Config.RefreshToken()).To(Equal("my_refresh_token"))
   208  
   209  				Expect(endpointRepo.GetCCInfoCallCount()).To(Equal(1))
   210  				Expect(endpointRepo.GetCCInfoArgsForCall(0)).To(Equal("api.example.com"))
   211  
   212  				Expect(orgRepo.FindByNameArgsForCall(0)).To(Equal("my-new-org"))
   213  				Expect(spaceRepo.FindByNameArgsForCall(0)).To(Equal("my-space"))
   214  
   215  				Expect(ui.ShowConfigurationCalled).To(BeTrue())
   216  			})
   217  
   218  			It("lets the user specify an org and space using flags", func() {
   219  				Flags = []string{"-a", "api.example.com", "-u", "user@example.com", "-p", "password", "-o", "my-new-org", "-s", "my-space"}
   220  
   221  				orgRepo.FindByNameReturns(org2, nil)
   222  				testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   223  
   224  				Expect(Config.OrganizationFields().GUID).To(Equal("my-new-org-guid"))
   225  				Expect(Config.SpaceFields().GUID).To(Equal("my-space-guid"))
   226  				Expect(Config.AccessToken()).To(Equal("my_access_token"))
   227  				Expect(Config.RefreshToken()).To(Equal("my_refresh_token"))
   228  
   229  				Expect(endpointRepo.GetCCInfoCallCount()).To(Equal(1))
   230  				Expect(endpointRepo.GetCCInfoArgsForCall(0)).To(Equal("api.example.com"))
   231  				Expect(authRepo.AuthenticateCallCount()).To(Equal(1))
   232  				Expect(authRepo.AuthenticateArgsForCall(0)).To(Equal(map[string]string{
   233  					"username": "user@example.com",
   234  					"password": "password",
   235  				}))
   236  
   237  				Expect(ui.ShowConfigurationCalled).To(BeTrue())
   238  			})
   239  
   240  			It("doesn't ask the user for the API url if they have it in their config", func() {
   241  				orgRepo.FindByNameReturns(org, nil)
   242  				Config.SetAPIEndpoint("http://api.example.com")
   243  
   244  				Flags = []string{"-o", "my-new-org", "-s", "my-space"}
   245  				ui.Inputs = []string{"user@example.com", "password"}
   246  
   247  				testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   248  
   249  				Expect(Config.APIEndpoint()).To(Equal("http://api.example.com"))
   250  				Expect(Config.OrganizationFields().GUID).To(Equal("my-new-org-guid"))
   251  				Expect(Config.SpaceFields().GUID).To(Equal("my-space-guid"))
   252  				Expect(Config.AccessToken()).To(Equal("my_access_token"))
   253  				Expect(Config.RefreshToken()).To(Equal("my_refresh_token"))
   254  
   255  				Expect(endpointRepo.GetCCInfoCallCount()).To(Equal(1))
   256  				Expect(endpointRepo.GetCCInfoArgsForCall(0)).To(Equal("http://api.example.com"))
   257  				Expect(ui.ShowConfigurationCalled).To(BeTrue())
   258  			})
   259  		})
   260  
   261  		It("displays an update notification", func() {
   262  			ui.Inputs = []string{"http://api.example.com", "user@example.com", "password"}
   263  			testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   264  			Expect(ui.NotifyUpdateIfNeededCallCount).To(Equal(1))
   265  		})
   266  
   267  		It("tries to get the organizations", func() {
   268  			Flags = []string{}
   269  			ui.Inputs = []string{"api.example.com", "user@example.com", "password", "my-org-1", "my-space"}
   270  			testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   271  			Expect(orgRepo.ListOrgsCallCount()).To(Equal(1))
   272  			Expect(orgRepo.ListOrgsArgsForCall(0)).To(Equal(50))
   273  		})
   274  
   275  		Describe("when there are too many orgs to show", func() {
   276  			BeforeEach(func() {
   277  				organizations := []models.Organization{}
   278  				for i := 0; i < 60; i++ {
   279  					id := strconv.Itoa(i)
   280  					org := models.Organization{}
   281  					org.GUID = "my-org-guid-" + id
   282  					org.Name = "my-org-" + id
   283  					organizations = append(organizations, org)
   284  				}
   285  				orgRepo.ListOrgsReturns(organizations, nil)
   286  				orgRepo.FindByNameReturns(organizations[1], nil)
   287  
   288  				space1 := models.Space{}
   289  				space1.GUID = "my-space-guid"
   290  				space1.Name = "my-space"
   291  
   292  				space2 := models.Space{}
   293  				space2.GUID = "some-space-guid"
   294  				space2.Name = "some-space"
   295  
   296  				spaceRepo.ListSpacesStub = listSpacesStub([]models.Space{space1, space2})
   297  			})
   298  
   299  			It("doesn't display a list of orgs (the user must type the name)", func() {
   300  				ui.Inputs = []string{"api.example.com", "user@example.com", "password", "my-org-1", "my-space"}
   301  
   302  				testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   303  
   304  				Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"my-org-2"}))
   305  				Expect(orgRepo.FindByNameArgsForCall(0)).To(Equal("my-org-1"))
   306  				Expect(Config.OrganizationFields().GUID).To(Equal("my-org-guid-1"))
   307  			})
   308  		})
   309  
   310  		Describe("when there is only a single org and space", func() {
   311  			It("does not ask the user to select an org/space", func() {
   312  				ui.Inputs = []string{"http://api.example.com", "user@example.com", "password"}
   313  
   314  				testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   315  
   316  				Expect(Config.OrganizationFields().GUID).To(Equal("my-new-org-guid"))
   317  				Expect(Config.SpaceFields().GUID).To(Equal("my-space-guid"))
   318  				Expect(Config.AccessToken()).To(Equal("my_access_token"))
   319  				Expect(Config.RefreshToken()).To(Equal("my_refresh_token"))
   320  
   321  				Expect(endpointRepo.GetCCInfoCallCount()).To(Equal(1))
   322  				Expect(endpointRepo.GetCCInfoArgsForCall(0)).To(Equal("http://api.example.com"))
   323  				Expect(authRepo.AuthenticateCallCount()).To(Equal(1))
   324  				Expect(authRepo.AuthenticateArgsForCall(0)).To(Equal(map[string]string{
   325  					"username": "user@example.com",
   326  					"password": "password",
   327  				}))
   328  				Expect(ui.ShowConfigurationCalled).To(BeTrue())
   329  			})
   330  		})
   331  
   332  		Describe("where there are no available orgs", func() {
   333  			BeforeEach(func() {
   334  				orgRepo.ListOrgsReturns([]models.Organization{}, nil)
   335  				spaceRepo.ListSpacesStub = listSpacesStub([]models.Space{})
   336  			})
   337  
   338  			It("does not as the user to select an org", func() {
   339  				ui.Inputs = []string{"http://api.example.com", "user@example.com", "password"}
   340  				testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   341  
   342  				Expect(Config.OrganizationFields().GUID).To(Equal(""))
   343  				Expect(Config.SpaceFields().GUID).To(Equal(""))
   344  				Expect(Config.AccessToken()).To(Equal("my_access_token"))
   345  				Expect(Config.RefreshToken()).To(Equal("my_refresh_token"))
   346  
   347  				Expect(endpointRepo.GetCCInfoCallCount()).To(Equal(1))
   348  				Expect(endpointRepo.GetCCInfoArgsForCall(0)).To(Equal("http://api.example.com"))
   349  				Expect(authRepo.AuthenticateCallCount()).To(Equal(1))
   350  				Expect(authRepo.AuthenticateArgsForCall(0)).To(Equal(map[string]string{
   351  					"username": "user@example.com",
   352  					"password": "password",
   353  				}))
   354  				Expect(ui.ShowConfigurationCalled).To(BeTrue())
   355  			})
   356  		})
   357  
   358  		Describe("when there is only a single org and no spaces", func() {
   359  			BeforeEach(func() {
   360  				orgRepo.ListOrgsReturns([]models.Organization{org}, nil)
   361  				spaceRepo.ListSpacesStub = listSpacesStub([]models.Space{})
   362  			})
   363  
   364  			It("does not ask the user to select a space", func() {
   365  				ui.Inputs = []string{"http://api.example.com", "user@example.com", "password"}
   366  				testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   367  
   368  				Expect(Config.OrganizationFields().GUID).To(Equal("my-new-org-guid"))
   369  				Expect(Config.SpaceFields().GUID).To(Equal(""))
   370  				Expect(Config.AccessToken()).To(Equal("my_access_token"))
   371  				Expect(Config.RefreshToken()).To(Equal("my_refresh_token"))
   372  
   373  				Expect(endpointRepo.GetCCInfoCallCount()).To(Equal(1))
   374  				Expect(endpointRepo.GetCCInfoArgsForCall(0)).To(Equal("http://api.example.com"))
   375  				Expect(authRepo.AuthenticateCallCount()).To(Equal(1))
   376  				Expect(authRepo.AuthenticateArgsForCall(0)).To(Equal(map[string]string{
   377  					"username": "user@example.com",
   378  					"password": "password",
   379  				}))
   380  				Expect(ui.ShowConfigurationCalled).To(BeTrue())
   381  			})
   382  		})
   383  
   384  		Describe("login prompts", func() {
   385  			BeforeEach(func() {
   386  				authRepo.GetLoginPromptsAndSaveUAAServerURLReturns(map[string]coreconfig.AuthPrompt{
   387  					"account_number": {
   388  						DisplayName: "Account Number",
   389  						Type:        coreconfig.AuthPromptTypeText,
   390  					},
   391  					"username": {
   392  						DisplayName: "Username",
   393  						Type:        coreconfig.AuthPromptTypeText,
   394  					},
   395  					"passcode": {
   396  						DisplayName: "It's a passcode, what you want it to be???",
   397  						Type:        coreconfig.AuthPromptTypePassword,
   398  					},
   399  					"password": {
   400  						DisplayName: "Your Password",
   401  						Type:        coreconfig.AuthPromptTypePassword,
   402  					},
   403  				}, nil)
   404  			})
   405  
   406  			Context("when the user does not provide the --sso flag", func() {
   407  				It("prompts the user for 'password' prompt and any text type prompt", func() {
   408  					ui.Inputs = []string{"api.example.com", "the-username", "the-account-number", "the-password"}
   409  
   410  					testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   411  
   412  					Expect(ui.Prompts).To(ContainSubstrings(
   413  						[]string{"API endpoint"},
   414  						[]string{"Account Number"},
   415  						[]string{"Username"},
   416  					))
   417  					Expect(ui.PasswordPrompts).To(ContainSubstrings([]string{"Your Password"}))
   418  					Expect(ui.PasswordPrompts).ToNot(ContainSubstrings(
   419  						[]string{"passcode"},
   420  					))
   421  
   422  					Expect(authRepo.AuthenticateCallCount()).To(Equal(1))
   423  					Expect(authRepo.AuthenticateArgsForCall(0)).To(Equal(map[string]string{
   424  						"account_number": "the-account-number",
   425  						"username":       "the-username",
   426  						"password":       "the-password",
   427  					}))
   428  				})
   429  			})
   430  
   431  			Context("when the user does provide the --sso flag", func() {
   432  				It("only prompts the user for the passcode type prompts", func() {
   433  					Flags = []string{"--sso", "-a", "api.example.com"}
   434  					ui.Inputs = []string{"the-one-time-code"}
   435  
   436  					testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   437  
   438  					Expect(ui.Prompts).To(BeEmpty())
   439  					Expect(ui.PasswordPrompts).To(ContainSubstrings([]string{"passcode"}))
   440  					Expect(authRepo.AuthenticateCallCount()).To(Equal(1))
   441  					Expect(authRepo.AuthenticateArgsForCall(0)).To(Equal(map[string]string{
   442  						"passcode": "the-one-time-code",
   443  					}))
   444  				})
   445  			})
   446  
   447  			It("takes the password from the -p flag", func() {
   448  				Flags = []string{"-p", "the-password"}
   449  				ui.Inputs = []string{"api.example.com", "the-username", "the-account-number", "the-pin"}
   450  
   451  				testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   452  
   453  				Expect(ui.PasswordPrompts).ToNot(ContainSubstrings([]string{"Your Password"}))
   454  				Expect(authRepo.AuthenticateCallCount()).To(Equal(1))
   455  				Expect(authRepo.AuthenticateArgsForCall(0)).To(Equal(map[string]string{
   456  					"account_number": "the-account-number",
   457  					"username":       "the-username",
   458  					"password":       "the-password",
   459  				}))
   460  			})
   461  
   462  			It("tries 3 times for the password-type prompts", func() {
   463  				authRepo.AuthenticateReturns(errors.New("Error authenticating."))
   464  				ui.Inputs = []string{"api.example.com", "the-username", "the-account-number",
   465  					"the-password-1", "the-password-2", "the-password-3"}
   466  
   467  				testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   468  
   469  				Expect(authRepo.AuthenticateCallCount()).To(Equal(3))
   470  				Expect(authRepo.AuthenticateArgsForCall(0)).To(Equal(map[string]string{
   471  					"username":       "the-username",
   472  					"account_number": "the-account-number",
   473  					"password":       "the-password-1",
   474  				}))
   475  				Expect(authRepo.AuthenticateArgsForCall(1)).To(Equal(map[string]string{
   476  					"username":       "the-username",
   477  					"account_number": "the-account-number",
   478  					"password":       "the-password-2",
   479  				}))
   480  				Expect(authRepo.AuthenticateArgsForCall(2)).To(Equal(map[string]string{
   481  					"username":       "the-username",
   482  					"account_number": "the-account-number",
   483  					"password":       "the-password-3",
   484  				}))
   485  
   486  				Expect(ui.Outputs()).To(ContainSubstrings([]string{"FAILED"}))
   487  			})
   488  
   489  			It("prompts user for password again if password given on the cmd line fails", func() {
   490  				authRepo.AuthenticateReturns(errors.New("Error authenticating."))
   491  
   492  				Flags = []string{"-p", "the-password-1"}
   493  
   494  				ui.Inputs = []string{"api.example.com", "the-username", "the-account-number",
   495  					"the-password-2", "the-password-3"}
   496  
   497  				testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   498  
   499  				Expect(authRepo.AuthenticateCallCount()).To(Equal(3))
   500  				Expect(authRepo.AuthenticateArgsForCall(0)).To(Equal(map[string]string{
   501  					"username":       "the-username",
   502  					"account_number": "the-account-number",
   503  					"password":       "the-password-1",
   504  				}))
   505  				Expect(authRepo.AuthenticateArgsForCall(1)).To(Equal(map[string]string{
   506  					"username":       "the-username",
   507  					"account_number": "the-account-number",
   508  					"password":       "the-password-2",
   509  				}))
   510  				Expect(authRepo.AuthenticateArgsForCall(2)).To(Equal(map[string]string{
   511  					"username":       "the-username",
   512  					"account_number": "the-account-number",
   513  					"password":       "the-password-3",
   514  				}))
   515  
   516  				Expect(ui.Outputs()).To(ContainSubstrings([]string{"FAILED"}))
   517  			})
   518  		})
   519  	})
   520  
   521  	Describe("updates to the config", func() {
   522  		BeforeEach(func() {
   523  			Config.SetAPIEndpoint("api.the-old-endpoint.com")
   524  			Config.SetAccessToken("the-old-access-token")
   525  			Config.SetRefreshToken("the-old-refresh-token")
   526  			endpointRepo.GetCCInfoStub = func(endpoint string) (*coreconfig.CCInfo, string, error) {
   527  				return &coreconfig.CCInfo{
   528  					APIVersion:               "some-version",
   529  					AuthorizationEndpoint:    "auth/endpoint",
   530  					DopplerEndpoint:          "doppler/endpoint",
   531  					MinCLIVersion:            minCLIVersion,
   532  					MinRecommendedCLIVersion: minRecommendedCLIVersion,
   533  					SSHOAuthClient:           "some-client",
   534  					RoutingAPIEndpoint:       "routing/endpoint",
   535  				}, endpoint, nil
   536  			}
   537  
   538  		})
   539  
   540  		JustBeforeEach(func() {
   541  			testcmd.RunCLICommand("login", Flags, nil, updateCommandDependency, false, ui)
   542  		})
   543  
   544  		var ItShowsTheTarget = func() {
   545  			It("shows the target", func() {
   546  				Expect(ui.ShowConfigurationCalled).To(BeTrue())
   547  			})
   548  		}
   549  
   550  		var ItDoesntShowTheTarget = func() {
   551  			It("does not show the target info", func() {
   552  				Expect(ui.ShowConfigurationCalled).To(BeFalse())
   553  			})
   554  		}
   555  
   556  		var ItFails = func() {
   557  			It("fails", func() {
   558  				Expect(ui.Outputs()).To(ContainSubstrings([]string{"FAILED"}))
   559  			})
   560  		}
   561  
   562  		var ItSucceeds = func() {
   563  			It("runs successfully", func() {
   564  				Expect(ui.Outputs()).ToNot(ContainSubstrings([]string{"FAILED"}))
   565  				Expect(ui.Outputs()).To(ContainSubstrings([]string{"OK"}))
   566  			})
   567  		}
   568  
   569  		Describe("when the user is setting an API", func() {
   570  			BeforeEach(func() {
   571  				Flags = []string{"-a", "https://api.the-server.com", "-u", "the-user-name", "-p", "the-password"}
   572  			})
   573  
   574  			Describe("when the --skip-ssl-validation flag is provided", func() {
   575  				BeforeEach(func() {
   576  					Flags = append(Flags, "--skip-ssl-validation")
   577  				})
   578  
   579  				Describe("setting api endpoint is successful", func() {
   580  					BeforeEach(func() {
   581  						Config.SetSSLDisabled(false)
   582  					})
   583  
   584  					ItSucceeds()
   585  					ItShowsTheTarget()
   586  
   587  					It("stores the API endpoint and the skip-ssl flag", func() {
   588  						Expect(endpointRepo.GetCCInfoCallCount()).To(Equal(1))
   589  						Expect(endpointRepo.GetCCInfoArgsForCall(0)).To(Equal("https://api.the-server.com"))
   590  						Expect(Config.IsSSLDisabled()).To(BeTrue())
   591  					})
   592  				})
   593  
   594  				Describe("setting api endpoint failed", func() {
   595  					BeforeEach(func() {
   596  						Config.SetSSLDisabled(true)
   597  						endpointRepo.GetCCInfoReturns(nil, "", errors.New("API endpoint not found"))
   598  					})
   599  
   600  					ItFails()
   601  					ItDoesntShowTheTarget()
   602  
   603  					It("clears the entire config", func() {
   604  						Expect(Config.APIEndpoint()).To(BeEmpty())
   605  						Expect(Config.IsSSLDisabled()).To(BeFalse())
   606  						Expect(Config.AccessToken()).To(BeEmpty())
   607  						Expect(Config.RefreshToken()).To(BeEmpty())
   608  						Expect(Config.OrganizationFields().GUID).To(BeEmpty())
   609  						Expect(Config.SpaceFields().GUID).To(BeEmpty())
   610  					})
   611  				})
   612  			})
   613  
   614  			Describe("when the --skip-ssl-validation flag is not provided", func() {
   615  				Describe("setting api endpoint is successful", func() {
   616  					BeforeEach(func() {
   617  						Config.SetSSLDisabled(true)
   618  					})
   619  
   620  					ItSucceeds()
   621  					ItShowsTheTarget()
   622  
   623  					It("updates the API endpoint and enables SSL validation", func() {
   624  						Expect(endpointRepo.GetCCInfoCallCount()).To(Equal(1))
   625  						Expect(endpointRepo.GetCCInfoArgsForCall(0)).To(Equal("https://api.the-server.com"))
   626  						Expect(Config.IsSSLDisabled()).To(BeFalse())
   627  					})
   628  				})
   629  
   630  				Describe("setting api endpoint failed", func() {
   631  					BeforeEach(func() {
   632  						Config.SetSSLDisabled(true)
   633  						endpointRepo.GetCCInfoReturns(nil, "", errors.New("API endpoint not found"))
   634  					})
   635  
   636  					ItFails()
   637  					ItDoesntShowTheTarget()
   638  
   639  					It("clears the entire config", func() {
   640  						Expect(Config.APIEndpoint()).To(BeEmpty())
   641  						Expect(Config.IsSSLDisabled()).To(BeFalse())
   642  						Expect(Config.AccessToken()).To(BeEmpty())
   643  						Expect(Config.RefreshToken()).To(BeEmpty())
   644  						Expect(Config.OrganizationFields().GUID).To(BeEmpty())
   645  						Expect(Config.SpaceFields().GUID).To(BeEmpty())
   646  					})
   647  				})
   648  			})
   649  
   650  			Describe("when there is an invalid SSL cert", func() {
   651  				BeforeEach(func() {
   652  					endpointRepo.GetCCInfoReturns(nil, "", errors.NewInvalidSSLCert("https://bobs-burgers.com", "SELF SIGNED SADNESS"))
   653  					ui.Inputs = []string{"bobs-burgers.com"}
   654  				})
   655  
   656  				It("fails and suggests the user skip SSL validation", func() {
   657  					Expect(ui.Outputs()).To(ContainSubstrings(
   658  						[]string{"FAILED"},
   659  						[]string{"SSL Cert", "https://bobs-burgers.com"},
   660  						[]string{"TIP", "login", "--skip-ssl-validation"},
   661  					))
   662  				})
   663  
   664  				ItDoesntShowTheTarget()
   665  			})
   666  		})
   667  
   668  		Describe("when user is logging in and not setting the api endpoint", func() {
   669  			BeforeEach(func() {
   670  				Flags = []string{"-u", "the-user-name", "-p", "the-password"}
   671  			})
   672  
   673  			Describe("when the --skip-ssl-validation flag is provided", func() {
   674  				BeforeEach(func() {
   675  					Flags = append(Flags, "--skip-ssl-validation")
   676  					Config.SetSSLDisabled(false)
   677  				})
   678  
   679  				It("disables SSL validation", func() {
   680  					Expect(Config.IsSSLDisabled()).To(BeTrue())
   681  				})
   682  			})
   683  
   684  			Describe("when the --skip-ssl-validation flag is not provided", func() {
   685  				BeforeEach(func() {
   686  					Config.SetSSLDisabled(true)
   687  				})
   688  
   689  				It("should not change config's SSLDisabled flag", func() {
   690  					Expect(Config.IsSSLDisabled()).To(BeTrue())
   691  				})
   692  			})
   693  
   694  			Describe("and the login fails authenticaton", func() {
   695  				BeforeEach(func() {
   696  					authRepo.AuthenticateReturns(errors.New("Error authenticating."))
   697  
   698  					Config.SetSSLDisabled(true)
   699  
   700  					Flags = []string{"-u", "user@example.com"}
   701  					ui.Inputs = []string{"password", "password2", "password3", "password4"}
   702  				})
   703  
   704  				ItFails()
   705  				ItShowsTheTarget()
   706  
   707  				It("does not change the api endpoint or SSL setting in the config", func() {
   708  					Expect(Config.APIEndpoint()).To(Equal("api.the-old-endpoint.com"))
   709  					Expect(Config.IsSSLDisabled()).To(BeTrue())
   710  				})
   711  
   712  				It("clears Access Token, Refresh Token, Org, and Space in the config", func() {
   713  					Expect(Config.AccessToken()).To(BeEmpty())
   714  					Expect(Config.RefreshToken()).To(BeEmpty())
   715  					Expect(Config.OrganizationFields().GUID).To(BeEmpty())
   716  					Expect(Config.SpaceFields().GUID).To(BeEmpty())
   717  				})
   718  			})
   719  		})
   720  
   721  		Describe("and the login fails to target an org", func() {
   722  			BeforeEach(func() {
   723  				Flags = []string{"-u", "user@example.com", "-p", "password", "-o", "nonexistentorg", "-s", "my-space"}
   724  				orgRepo.FindByNameReturns(models.Organization{}, errors.New("No org"))
   725  				Config.SetSSLDisabled(true)
   726  			})
   727  
   728  			ItFails()
   729  			ItShowsTheTarget()
   730  
   731  			It("does not update the api endpoint or ssl setting in the config", func() {
   732  				Expect(Config.APIEndpoint()).To(Equal("api.the-old-endpoint.com"))
   733  				Expect(Config.IsSSLDisabled()).To(BeTrue())
   734  			})
   735  
   736  			It("clears Org, and Space in the config", func() {
   737  				Expect(Config.OrganizationFields().GUID).To(BeEmpty())
   738  				Expect(Config.SpaceFields().GUID).To(BeEmpty())
   739  			})
   740  		})
   741  
   742  		Describe("and the login fails to target a space", func() {
   743  			BeforeEach(func() {
   744  				Flags = []string{"-u", "user@example.com", "-p", "password", "-o", "my-new-org", "-s", "nonexistent"}
   745  				orgRepo.FindByNameReturns(org, nil)
   746  				spaceRepo.FindByNameReturns(models.Space{}, errors.New("find-by-name-err"))
   747  
   748  				Config.SetSSLDisabled(true)
   749  			})
   750  
   751  			ItFails()
   752  			ItShowsTheTarget()
   753  
   754  			It("does not update the api endpoint or ssl setting in the config", func() {
   755  				Expect(Config.APIEndpoint()).To(Equal("api.the-old-endpoint.com"))
   756  				Expect(Config.IsSSLDisabled()).To(BeTrue())
   757  			})
   758  
   759  			It("updates the org in the config", func() {
   760  				Expect(Config.OrganizationFields().GUID).To(Equal("my-new-org-guid"))
   761  			})
   762  
   763  			It("clears the space in the config", func() {
   764  				Expect(Config.SpaceFields().GUID).To(BeEmpty())
   765  			})
   766  		})
   767  
   768  		Describe("and the login succeeds", func() {
   769  			BeforeEach(func() {
   770  				orgRepo.FindByNameReturns(models.Organization{
   771  					OrganizationFields: models.OrganizationFields{
   772  						Name: "new-org",
   773  						GUID: "new-org-guid",
   774  					},
   775  				}, nil)
   776  
   777  				space1 := models.Space{}
   778  				space1.GUID = "new-space-guid"
   779  				space1.Name = "new-space-name"
   780  				spaceRepo.ListSpacesStub = listSpacesStub([]models.Space{space1})
   781  				spaceRepo.FindByNameReturns(space1, nil)
   782  
   783  				authRepo.AuthenticateStub = func(credentials map[string]string) error {
   784  					Config.SetAccessToken("new_access_token")
   785  					Config.SetRefreshToken("new_refresh_token")
   786  					return nil
   787  				}
   788  
   789  				Flags = []string{"-u", "user@example.com", "-p", "password", "-o", "new-org", "-s", "new-space"}
   790  
   791  				Config.SetAPIEndpoint("api.the-old-endpoint.com")
   792  				Config.SetSSLDisabled(true)
   793  			})
   794  
   795  			ItSucceeds()
   796  			ItShowsTheTarget()
   797  
   798  			It("does not update the api endpoint or SSL setting", func() {
   799  				Expect(Config.APIEndpoint()).To(Equal("api.the-old-endpoint.com"))
   800  				Expect(Config.IsSSLDisabled()).To(BeTrue())
   801  			})
   802  
   803  			It("updates the config", func() {
   804  				Expect(Config.AccessToken()).To(Equal("new_access_token"))
   805  				Expect(Config.RefreshToken()).To(Equal("new_refresh_token"))
   806  				Expect(Config.OrganizationFields().GUID).To(Equal("new-org-guid"))
   807  				Expect(Config.SpaceFields().GUID).To(Equal("new-space-guid"))
   808  
   809  				Expect(Config.APIVersion()).To(Equal("some-version"))
   810  				Expect(Config.AuthenticationEndpoint()).To(Equal("auth/endpoint"))
   811  				Expect(Config.SSHOAuthClient()).To(Equal("some-client"))
   812  				Expect(Config.MinCLIVersion()).To(Equal("1.0.0"))
   813  				Expect(Config.MinRecommendedCLIVersion()).To(Equal("1.0.0"))
   814  				Expect(Config.DopplerEndpoint()).To(Equal("doppler/endpoint"))
   815  				Expect(Config.RoutingAPIEndpoint()).To(Equal("routing/endpoint"))
   816  
   817  			})
   818  		})
   819  	})
   820  })