github.com/jasonkeene/cli@v6.14.1-0.20160816203908-ca5715166dfb+incompatible/cf/commands/login_test.go (about)

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