github.com/franc20/ayesa_sap@v7.0.0-beta.28.0.20200124003224-302d4d52fa6c+incompatible/integration/shared/isolated/login_command_test.go (about) 1 package isolated 2 3 import ( 4 "fmt" 5 "net/http" 6 "net/url" 7 "os/exec" 8 "regexp" 9 "time" 10 11 "code.cloudfoundry.org/cli/integration/helpers" 12 "code.cloudfoundry.org/cli/util/configv3" 13 . "github.com/onsi/ginkgo" 14 . "github.com/onsi/gomega" 15 . "github.com/onsi/gomega/gbytes" 16 . "github.com/onsi/gomega/gexec" 17 "github.com/onsi/gomega/ghttp" 18 ) 19 20 var _ = Describe("login command", func() { 21 BeforeEach(func() { 22 helpers.SkipIfClientCredentialsTestMode() 23 }) 24 25 Describe("Help Text", func() { 26 When("--help flag is set", func() { 27 It("displays the command usage", func() { 28 session := helpers.CF("login", "--help") 29 Eventually(session).Should(Exit(0)) 30 31 Expect(session).Should(Say("NAME:\n")) 32 Expect(session).Should(Say("login - Log user in")) 33 34 Expect(session).Should(Say("USAGE:\n")) 35 Expect(session).Should(Say(`cf login \[-a API_URL\] \[-u USERNAME\] \[-p PASSWORD\] \[-o ORG\] \[-s SPACE\] \[--sso | --sso-passcode PASSCODE\] \[--origin ORIGIN\]`)) 36 37 Expect(session).Should(Say("WARNING:\n")) 38 Expect(session).Should(Say("Providing your password as a command line option is highly discouraged\n")) 39 Expect(session).Should(Say("Your password may be visible to others and may be recorded in your shell history\n")) 40 41 Expect(session).Should(Say("EXAMPLES:\n")) 42 Expect(session).Should(Say(regexp.QuoteMeta("cf login (omit username and password to login interactively -- cf will prompt for both)"))) 43 Expect(session).Should(Say(regexp.QuoteMeta("cf login -u name@example.com -p pa55woRD (specify username and password as arguments)"))) 44 Expect(session).Should(Say(regexp.QuoteMeta("cf login -u name@example.com -p \"my password\" (use quotes for passwords with a space)"))) 45 Expect(session).Should(Say(regexp.QuoteMeta("cf login -u name@example.com -p \"\\\"password\\\"\" (escape quotes if used in password)"))) 46 Expect(session).Should(Say(regexp.QuoteMeta("cf login --sso (cf will provide a url to obtain a one-time passcode to login)"))) 47 Expect(session).Should(Say(regexp.QuoteMeta("cf login --origin ldap"))) 48 49 Expect(session).Should(Say("ALIAS:\n")) 50 Expect(session).Should(Say("l")) 51 52 Expect(session).Should(Say("OPTIONS:\n")) 53 Expect(session).Should(Say(`-a\s+API endpoint \(e.g. https://api\.example\.com\)`)) 54 Expect(session).Should(Say(`-o\s+Org`)) 55 Expect(session).Should(Say(`-p\s+Password`)) 56 Expect(session).Should(Say(`-s\s+Space`)) 57 Expect(session).Should(Say(`--skip-ssl-validation\s+Skip verification of the API endpoint\. Not recommended\!`)) 58 Expect(session).Should(Say(`--sso\s+Prompt for a one-time passcode to login`)) 59 Expect(session).Should(Say(`--sso-passcode\s+One-time passcode`)) 60 Expect(session).Should(Say(`-u\s+Username`)) 61 62 Expect(session).Should(Say("SEE ALSO:\n")) 63 Expect(session).Should(Say("api, auth, target")) 64 }) 65 }) 66 }) 67 68 Describe("Invalid Command Usage", func() { 69 When("a random flag is passed in", func() { 70 It("exits 1 and displays an unknown flag error message", func() { 71 session := helpers.CF("login", "--test") 72 Eventually(session).Should(Exit(1)) 73 74 Expect(session.Err).Should(Say("Incorrect Usage: unknown flag `test'")) 75 }) 76 }) 77 }) 78 79 Describe("authorization endpoint", func() { 80 When("an authorization endpoint is advertised by the server", func() { 81 var server *ghttp.Server 82 83 BeforeEach(func() { 84 server = helpers.StartMockServerWithCustomAuthorizationEndpoint("/custom/authorization/endpoint") 85 86 fakeTokenResponse := map[string]string{ 87 "access_token": helpers.BuildTokenString(time.Now().Add(time.Hour)), 88 "token_type": "bearer", 89 "refresh_token": "refresh-token", 90 } 91 server.RouteToHandler(http.MethodGet, "/login", 92 func(http.ResponseWriter, *http.Request) { 93 Fail("The advertized authorization_endpoint should be used in preference to the UAA endpoint") 94 }, 95 ) 96 server.RouteToHandler(http.MethodGet, "/v3/organizations", 97 ghttp.RespondWith(http.StatusOK, `{"total_results": 0, "total_pages": 1, "resources": []}`)) 98 99 server.AppendHandlers( 100 ghttp.CombineHandlers( 101 ghttp.VerifyRequest("POST", "/custom/authorization/endpoint/oauth/token"), 102 ghttp.RespondWithJSONEncoded(http.StatusOK, fakeTokenResponse), 103 ), 104 ) 105 }) 106 107 AfterEach(func() { 108 server.Close() 109 }) 110 111 It("requests a token from the authorization endpoint and exits successfully", func() { 112 username, password := helpers.GetCredentials() 113 session := helpers.CF("-v", "login", "-a", server.URL(), "-u", username, "-p", password, "--skip-ssl-validation") 114 Eventually(session).Should(Exit(0)) 115 }) 116 }) 117 }) 118 119 Describe("Minimum Version Check", func() { 120 When("the v2 API version is less than the minimum supported version", func() { 121 var server *ghttp.Server 122 123 BeforeEach(func() { 124 server = helpers.StartMockServerWithAPIVersions("2.99.9", "3.36.0") 125 126 fakeTokenResponse := map[string]string{ 127 "access_token": helpers.BuildTokenString(time.Now()), 128 "token_type": "bearer", 129 "refresh_token": "refresh-token", 130 } 131 server.RouteToHandler(http.MethodPost, "/oauth/token", 132 ghttp.RespondWithJSONEncoded(http.StatusOK, fakeTokenResponse)) 133 server.RouteToHandler(http.MethodGet, "/v3/organizations", 134 ghttp.RespondWith(http.StatusOK, `{ 135 "total_results": 0, 136 "total_pages": 1, 137 "resources": []}`)) 138 }) 139 140 AfterEach(func() { 141 server.Close() 142 }) 143 144 It("displays the warning to stderr and exits successfully", func() { 145 username, password := helpers.GetCredentials() 146 session := helpers.CF("login", "-a", server.URL(), "-u", username, "-p", password, "--skip-ssl-validation") 147 148 Eventually(session.Err).Should(Say("Your CF API version .+ is no longer supported. Upgrade to a newer version of the API .+")) 149 Eventually(session).Should(Exit(0)) 150 }) 151 152 It("displays the warning before authenticating", func() { 153 username, password := helpers.GetCredentials() 154 cmd := exec.Command("cf", "login", "-a", server.URL(), "-u", username, "-p", password, "--skip-ssl-validation") 155 stdErrAndStdOut, err := cmd.CombinedOutput() 156 Expect(err).ToNot(HaveOccurred()) 157 158 output := BufferWithBytes(stdErrAndStdOut) 159 Expect(output).To(Say("Your CF API version .+ is no longer supported. Upgrade to a newer version of the API .+")) 160 Expect(output).To(Say("Authenticating..."), "Expected Min API version warning before 'Authenticating...' message.") 161 }) 162 }) 163 164 When("the CLI version is lower than the minimum supported version by the CC", func() { 165 var server *ghttp.Server 166 167 BeforeEach(func() { 168 server = helpers.StartMockServerWithMinimumCLIVersion("9000.0.0") 169 170 fakeTokenResponse := map[string]string{ 171 "access_token": "", 172 "token_type": "bearer", 173 } 174 server.RouteToHandler(http.MethodPost, "/oauth/token", 175 ghttp.RespondWithJSONEncoded(http.StatusOK, fakeTokenResponse)) 176 server.RouteToHandler(http.MethodGet, "/v3/organizations", 177 ghttp.RespondWith(http.StatusOK, `{ 178 "total_results": 0, 179 "total_pages": 1, 180 "resources": []}`)) 181 }) 182 183 AfterEach(func() { 184 server.Close() 185 }) 186 187 It("displays the warning to stderr and exits successfully", func() { 188 username, password := helpers.GetCredentials() 189 session := helpers.CF("login", "-a", server.URL(), "-u", username, "-p", password, "--skip-ssl-validation") 190 191 Eventually(session.Err).Should(Say(`Cloud Foundry API version .+ requires CLI version .+\. You are currently on version .+\. To upgrade your CLI, please visit: https://github.com/cloudfoundry/cli#downloads`)) 192 Eventually(session).Should(Exit(0)) 193 }) 194 195 It("displays the warning before authenticating", func() { 196 username, password := helpers.GetCredentials() 197 cmd := exec.Command("cf", "login", "-a", server.URL(), "-u", username, "-p", password, "--skip-ssl-validation") 198 stdErrAndStdOut, err := cmd.CombinedOutput() 199 Expect(err).ToNot(HaveOccurred()) 200 201 output := BufferWithBytes(stdErrAndStdOut) 202 Expect(output).To(Say(`Cloud Foundry API version .+ requires CLI version .+\. You are currently on version .+\. To upgrade your CLI, please visit: https://github.com/cloudfoundry/cli#downloads`)) 203 Expect(output).To(Say("Authenticating..."), "Expected Min CLI version warning before 'Authenticating...' message.") 204 }) 205 }) 206 }) 207 208 Describe("API Endpoint", func() { 209 When("the API endpoint is not set", func() { 210 BeforeEach(func() { 211 helpers.UnsetAPI() 212 }) 213 214 When("the user does not provide the -a flag", func() { 215 It("prompts the user for an endpoint", func() { 216 input := NewBuffer() 217 _, err := input.Write([]byte("\n")) 218 Expect(err).ToNot(HaveOccurred()) 219 session := helpers.CFWithStdin(input, "login") 220 Eventually(session).Should(Say("API endpoint:")) 221 session.Interrupt() 222 Eventually(session).Should(Exit()) 223 }) 224 225 When("the API endpoint provided at the prompt is unreachable", func() { 226 It("returns an error", func() { 227 input := NewBuffer() 228 _, err := input.Write([]byte("does.not.exist\n")) 229 Expect(err).ToNot(HaveOccurred()) 230 session := helpers.CFWithStdin(input, "login") 231 Eventually(session).Should(Say("API endpoint:")) 232 Eventually(session).Should(Say("FAILED")) 233 Eventually(session.Err).Should(Say("Request error: ")) 234 Eventually(session.Err).Should(Say("TIP: If you are behind a firewall and require an HTTP proxy, verify the https_proxy environment variable is correctly set. Else, check your network connection.")) 235 Eventually(session).Should(Exit(1)) 236 }) 237 }) 238 }) 239 240 When("the user provides the -a flag", func() { 241 It("sets the API endpoint and does not prompt the user for the API endpoint", func() { 242 var session *Session 243 if skipSSLValidation { 244 session = helpers.CF("login", "-a", apiURL, "--skip-ssl-validation") 245 } else { 246 session = helpers.CF("login", "-a", apiURL) 247 } 248 Eventually(session).Should(Say("API endpoint: %s", apiURL)) 249 // TODO https://www.pivotaltracker.com/story/show/166938709/comments/204492216 250 //Consistently(session).ShouldNot(Say("API endpoint:")) 251 //session.Interrupt() 252 Eventually(session).Should(Exit()) 253 254 session = helpers.CF("api") 255 Eventually(session).Should(Exit(0)) 256 Expect(session).Should(Say("api endpoint: %s", apiURL)) 257 }) 258 259 When("the provided API endpoint is unreachable", func() { 260 It("displays an error and fails", func() { 261 var session *Session 262 if skipSSLValidation { 263 session = helpers.CF("login", "-a", "does.not.exist", "--skip-ssl-validation") 264 } else { 265 session = helpers.CF("login", "-a", "does.not.exist") 266 } 267 268 Eventually(session).Should(Say("API endpoint: does.not.exist")) 269 Eventually(session).Should(Say("FAILED")) 270 Eventually(session.Err).Should(Say("Request error: ")) 271 Eventually(session.Err).Should(Say("TIP: If you are behind a firewall and require an HTTP proxy, verify the https_proxy environment variable is correctly set. Else, check your network connection.")) 272 Eventually(session).Should(Exit(1)) 273 }) 274 }) 275 276 When("the provided API endpoint has trailing slashes", func() { 277 It("removes the extra slashes", func() { 278 username, password := helpers.GetCredentials() 279 apiURLWithSlash := apiURL + "////" 280 session := helpers.CF("login", "-a", apiURLWithSlash, "-u", username, "-p", password, "--skip-ssl-validation") 281 Eventually(session).Should(Exit(0)) 282 283 session = helpers.CF("api") 284 Eventually(session).Should(Say("api endpoint:\\s+%s\n", apiURL)) 285 Eventually(session).Should(Exit(0)) 286 }) 287 }) 288 }) 289 }) 290 291 When("the API endpoint is already set", func() { 292 It("does not prompt the user for API endpoint", func() { 293 session := helpers.CF("login") 294 Consistently(session).ShouldNot(Say("API endpoint>")) 295 session.Interrupt() 296 Eventually(session).Should(Exit()) 297 }) 298 299 When("the user provides a new API endpoint with the -a flag", func() { 300 When("the provided API endpoint is unreachable", func() { 301 It("displays an error and does not change the API endpoint", func() { 302 var session *Session 303 if skipSSLValidation { 304 session = helpers.CF("login", "-a", "does.not.exist", "--skip-ssl-validation") 305 } else { 306 session = helpers.CF("login", "-a", "does.not.exist") 307 } 308 Eventually(session).Should(Say("API endpoint: does.not.exist")) 309 Eventually(session).Should(Say("FAILED")) 310 Eventually(session.Err).Should(Say("Request error: ")) 311 Eventually(session.Err).Should(Say("TIP: If you are behind a firewall and require an HTTP proxy, verify the https_proxy environment variable is correctly set. Else, check your network connection.")) 312 Eventually(session).Should(Exit(1)) 313 314 apiSession := helpers.CF("api") 315 Eventually(apiSession).Should(Exit(0)) 316 Eventually(apiSession).Should(Say("api endpoint: %s", apiURL)) 317 }) 318 }) 319 }) 320 }) 321 }) 322 323 Describe("https", func() { 324 325 When("no scheme is included in the API endpoint", func() { 326 var ( 327 hostname string 328 serverURL *url.URL 329 err error 330 session *Session 331 ) 332 333 BeforeEach(func() { 334 serverURL, err = url.Parse(helpers.GetAPI()) 335 Expect(err).NotTo(HaveOccurred()) 336 337 hostname = serverURL.Hostname() 338 339 username, password := helpers.GetCredentials() 340 if skipSSLValidation { 341 session = helpers.CF("login", "-u", username, "-p", password, "-a", hostname, "--skip-ssl-validation") 342 } else { 343 session = helpers.CF("login", "-u", username, "-p", password, "-a", hostname) 344 } 345 }) 346 347 It("displays the API endpoint you are about to target as https", func() { 348 Eventually(session).Should(Say("API endpoint: %s", hostname)) 349 Eventually(session).Should(Exit(0)) 350 }) 351 352 It("displays the API endpoint you have targeted as https", func() { 353 Eventually(session).Should(Say(`API endpoint:\s+https://%s\s+\(API version: \d\.\d{1,3}\.\d{1,3}\)`, hostname)) 354 Eventually(session).Should(Exit(0)) 355 }) 356 357 }) 358 359 When("the API endpoint's scheme is http", func() { 360 var httpURL string 361 362 BeforeEach(func() { 363 apiURL, err := url.Parse(helpers.GetAPI()) 364 Expect(err).NotTo(HaveOccurred()) 365 apiURL.Scheme = "http" 366 367 httpURL = apiURL.String() 368 }) 369 370 It("shows a warning to the user", func() { 371 username, password := helpers.GetCredentials() 372 session := helpers.CF("login", "-u", username, "-p", password, "-a", httpURL, "--skip-ssl-validation") 373 374 Eventually(session).Should(Say("API endpoint: %s", httpURL)) 375 Eventually(session.Err).Should(Say("Warning: Insecure http API endpoint detected: secure https API endpoints are recommended")) 376 Eventually(session).Should(Exit(0)) 377 }) 378 }) 379 380 // This test is redundant: 381 // If SKIP_SSL_VALIDATION is disabled 382 // then the test suite would have already logged in 383 // with a valid cert by the time this test gets run 384 When("the OS provides a valid SSL Certificate (Unix: SSL_CERT_FILE or SSL_CERT_DIR Environment variables) (Windows: Import-Certificate call)", func() { 385 BeforeEach(func() { 386 if skipSSLValidation { 387 Skip("SKIP_SSL_VALIDATION is enabled") 388 } 389 }) 390 391 It("trusts the cert and allows the users to log in", func() { 392 username, password := helpers.GetCredentials() 393 session := helpers.CF("login", "-u", username, "-p", password, "-a", helpers.GetAPI()) 394 Eventually(session).Should(Say("API endpoint: %s", apiURL)) 395 Eventually(session).Should(Exit()) 396 397 session = helpers.CF("api") 398 Eventually(session).Should(Exit(0)) 399 Expect(session).Should(Say("api endpoint: %s", apiURL)) 400 }) 401 }) 402 403 When("the SSL Certificate is invalid", func() { 404 var server *ghttp.Server 405 406 BeforeEach(func() { 407 cliVersion := "1.0.0" 408 server = helpers.StartMockServerWithMinimumCLIVersion(cliVersion) 409 }) 410 411 AfterEach(func() { 412 server.Close() 413 }) 414 415 It("displays a helpful error message and exits 1", func() { 416 session := helpers.CF("login", "-a", server.URL()) 417 Eventually(session).Should(Say("API endpoint: %s", server.URL())) 418 Eventually(session).Should(Say("FAILED")) 419 Eventually(session.Err).Should(Say("Invalid SSL Cert for %s", server.URL())) 420 Eventually(session.Err).Should(Say("TIP: Use 'cf login --skip-ssl-validation' to continue with an insecure API endpoint")) 421 Eventually(session).Should(Exit(1)) 422 }) 423 424 When("targeted with --skip-ssl-validation", func() { 425 BeforeEach(func() { 426 Eventually(helpers.CF("api", server.URL(), "--skip-ssl-validation")).Should(Exit(0)) 427 }) 428 429 When("logging in without --skip-ssl-validation", func() { 430 It("displays a helpful error message and exits 1", func() { 431 session := helpers.CF("login", "-a", server.URL()) 432 Eventually(session).Should(Say("API endpoint: %s", server.URL())) 433 Eventually(session).Should(Say("FAILED")) 434 Eventually(session.Err).Should(Say("Invalid SSL Cert for %s", server.URL())) 435 Eventually(session.Err).Should(Say("TIP: Use 'cf login --skip-ssl-validation' to continue with an insecure API endpoint")) 436 Eventually(session).Should(Exit(1)) 437 }) 438 }) 439 }) 440 441 When("the server accepts logins", func() { 442 BeforeEach(func() { 443 fakeTokenResponse := map[string]string{ 444 "access_token": "", 445 "token_type": "bearer", 446 } 447 server.RouteToHandler(http.MethodPost, "/oauth/token", 448 ghttp.RespondWithJSONEncoded(http.StatusOK, fakeTokenResponse)) 449 server.RouteToHandler(http.MethodGet, "/v3/organizations", 450 ghttp.RespondWith(http.StatusOK, `{ 451 "total_results": 0, 452 "total_pages": 1, 453 "resources": []}`)) 454 }) 455 456 It("doesn't complain about an invalid cert when we specify --skip-ssl-validation", func() { 457 session := helpers.CF("login", "-a", server.URL(), "--skip-ssl-validation") 458 //session := helpers.CF("api", server.URL(), "--skip-ssl-validation") 459 Eventually(session).Should(Exit(0)) 460 Expect(session).Should(Say("API endpoint:\\s+" + server.URL())) 461 Expect(session).Should(Say(`Authenticating\.\.\.`)) 462 Expect(session).Should(Say(`OK`)) 463 Expect(session).Should(Say(`API endpoint:\s+` + server.URL() + `\s+\(API version: \d\.\d{1,3}\.\d{1,3}\)`)) 464 465 Expect(string(session.Err.Contents())).Should(Not(ContainSubstring("Invalid SSL Cert for %s", server.URL()))) 466 }) 467 468 }) 469 }) 470 }) 471 472 Describe("SSO", func() { 473 When("--sso-passcode is provided", func() { 474 Context("and --sso is also passed", func() { 475 It("fails with a useful error message", func() { 476 session := helpers.CF("login", "--sso-passcode", "some-passcode", "--sso") 477 Eventually(session.Err).Should(Say("Incorrect Usage: The following arguments cannot be used together: --sso-passcode, --sso")) 478 Eventually(session).Should(Exit(1)) 479 }) 480 }) 481 482 Context("and the provided passcode is incorrect", func() { 483 It("prompts twice, displays an error and fails", func() { 484 input := NewBuffer() 485 _, err := input.Write([]byte("bad-passcode-again\nbad-passcode-strikes-back\n")) 486 Expect(err).ToNot(HaveOccurred()) 487 session := helpers.CFWithStdin(input, "login", "--sso-passcode", "some-passcode") 488 Eventually(session).Should(Say("API endpoint:\\s+" + helpers.GetAPI())) 489 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 490 Eventually(session.Err).Should(Say(`Invalid passcode`)) 491 492 // Leaving out expectation of prompt text, since it comes from UAA (and doesn't show up on Windows) 493 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 494 Eventually(session.Err).Should(Say(`Invalid passcode`)) 495 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 496 Eventually(session.Err).Should(Say(`Invalid passcode`)) 497 Eventually(session).Should(Say(`API endpoint:\s+` + helpers.GetAPI() + `\s+\(API version: \d\.\d{1,3}\.\d{1,3}\)`)) 498 Eventually(session).Should(Say(`Not logged in. Use 'cf login' or 'cf login --sso' to log in.`)) 499 Eventually(session.Err).Should(Say(`Unable to authenticate`)) 500 Eventually(session).Should(Say(`FAILED`)) 501 502 Eventually(session).Should(Exit(1)) 503 }) 504 }) 505 506 When("a passcode isn't provided", func() { 507 It("prompts the user to try again", func() { 508 session := helpers.CF("login", "--sso-passcode") 509 Eventually(session.Err).Should(Say("Incorrect Usage: expected argument for flag `--sso-passcode'")) 510 Eventually(session).Should(Exit(1)) 511 }) 512 }) 513 }) 514 515 When("a user authenticates with valid client credentials", func() { 516 BeforeEach(func() { 517 clientID, clientSecret := helpers.SkipIfClientCredentialsNotSet() 518 session := helpers.CF("auth", clientID, clientSecret, "--client-credentials") 519 Eventually(session).Should(Exit(0)) 520 }) 521 522 When("a different user logs in with valid sso passcode", func() { 523 It("should fail log in and display an error informing the user they need to log out", func() { 524 session := helpers.CF("login", "--sso-passcode", "my-fancy-sso") 525 526 Eventually(session).Should(Say("API endpoint:\\s+" + helpers.GetAPI())) 527 Eventually(session).Should(Say(`API endpoint:\s+` + helpers.GetAPI() + `\s+\(API version: \d\.\d{1,3}\.\d{1,3}\)`)) 528 Eventually(session.Err).Should(Say(`Service account currently logged in\. Use 'cf logout' to log out service account and try again\.`)) 529 Eventually(session).Should(Say("FAILED")) 530 Eventually(session).Should(Exit(1)) 531 532 //And I am still logged in 533 targetSession := helpers.CF("target") 534 Eventually(targetSession).Should(Exit(0)) 535 }) 536 }) 537 }) 538 }) 539 540 Describe("Target Organization", func() { 541 var ( 542 orgName string 543 username string 544 password string 545 ) 546 547 BeforeEach(func() { 548 helpers.LoginCF() 549 orgName = helpers.NewOrgName() 550 session := helpers.CF("create-org", orgName) 551 Eventually(session).Should(Exit(0)) 552 username, password = helpers.CreateUserInOrgRole(orgName, "OrgManager") 553 }) 554 555 When("there is only one org available to the user", func() { 556 It("logs the user in and targets the organization automatically", func() { 557 session := helpers.CF("login", "-u", username, "-p", password, "-a", apiURL, "--skip-ssl-validation") 558 Eventually(session).Should(Exit(0)) 559 560 targetSession := helpers.CF("target") 561 Eventually(targetSession).Should(Exit(0)) 562 Eventually(targetSession).Should(Say(`org:\s+%s`, orgName)) 563 }) 564 565 It("uses v3 endpoints", func() { 566 session := helpers.CF("login", "-v", "-u", username, "-p", password, "-a", apiURL, "--skip-ssl-validation") 567 Eventually(session).Should(Exit(0)) 568 569 Eventually(session).Should(Say(`GET /v3/organizations.*HTTP/`)) 570 Eventually(session).Should(Say(`GET /v3/spaces.*HTTP/`)) 571 }) 572 }) 573 574 When("the -o flag is not passed", func() { 575 When("there are multiple orgs available to the user", func() { 576 BeforeEach(func() { 577 orgName = helpers.NewOrgName() 578 createOrgSession := helpers.CF("create-org", orgName) 579 Eventually(createOrgSession).Should(Exit(0)) 580 setOrgRoleSession := helpers.CF("set-org-role", username, orgName, "OrgManager") 581 Eventually(setOrgRoleSession).Should(Exit(0)) 582 }) 583 584 When("there are more than 50 orgs", func() { 585 var server *ghttp.Server 586 587 BeforeEach(func() { 588 server = helpers.StartAndTargetMockServerWithAPIVersions(helpers.DefaultV2Version, helpers.DefaultV3Version) 589 helpers.AddLoginRoutes(server) 590 helpers.AddFiftyOneOrgs(server) 591 // handle request for spaces under "org20" 592 helpers.AddEmptyPaginatedResponse(server, "/v3/spaces?organization_guids=f6653aac-938e-4469-9a66-56a02796412b") 593 }) 594 595 AfterEach(func() { 596 server.Close() 597 }) 598 599 It("displays a message and prompts the user for the org name", func() { 600 input := NewBuffer() 601 _, wErr := input.Write([]byte(fmt.Sprintf("%s\n", "org20"))) // "org20" is one of the orgs in the test fixture 602 Expect(wErr).ToNot(HaveOccurred()) 603 604 session := helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "--skip-ssl-validation") 605 606 Eventually(session).Should(Say("Select an org:")) 607 Eventually(session).Should(Say("There are too many options to display; please type in the name.")) 608 Eventually(session).Should(Say("\n\n")) 609 Eventually(session).Should(Say(regexp.QuoteMeta(`Org (enter to skip):`))) 610 Eventually(session).Should(Say("Targeted org org20")) 611 612 Eventually(session).Should(Exit(0)) 613 }) 614 }) 615 616 When("user selects an organization by using numbered list", func() { 617 // required 618 It("prompts the user for org and targets the selected org", func() { 619 input := NewBuffer() 620 _, err := input.Write([]byte("1\n")) 621 Expect(err).ToNot(HaveOccurred()) 622 var session *Session 623 // TODO: do we still need this? 624 if skipSSLValidation { 625 session = helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "-a", apiURL, "--skip-ssl-validation") 626 } else { 627 session = helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "-a", apiURL) 628 } 629 630 Eventually(session).Should(Exit(0)) 631 632 re := regexp.MustCompile("1\\. (?P<OrgName>.*)\n") 633 matches := re.FindStringSubmatch(string(session.Out.Contents())) 634 Expect(matches).To(HaveLen((2))) 635 expectedOrgName := matches[1] 636 637 targetSession := helpers.CF("target") 638 Eventually(targetSession).Should(Exit(0)) 639 Eventually(targetSession).Should(Say(`org:\s+%s`, expectedOrgName)) 640 }) 641 642 When("the user selects a number greater than the number of orgs", func() { 643 // allowed to change 644 It("prompts the user until a valid number is entered", func() { 645 input := NewBuffer() 646 _, err := input.Write([]byte("3\n")) 647 Expect(err).ToNot(HaveOccurred()) 648 649 session := helpers.CFWithStdin(input, "login", "-u", username, "-p", password) 650 651 Eventually(session).Should(Say(regexp.QuoteMeta("Select an org:"))) 652 Eventually(session).Should(Say(regexp.QuoteMeta(`Org (enter to skip):`))) 653 Eventually(session).Should(Say(regexp.QuoteMeta(`Org (enter to skip):`))) 654 655 session.Interrupt() 656 Eventually(session).Should(Exit()) 657 }) 658 }) 659 }) 660 661 When("user selects an organization by org name", func() { 662 // required 663 It("prompts the user for an org and then targets the selected org", func() { 664 input := NewBuffer() 665 _, err := input.Write([]byte(fmt.Sprintf("%s\n", orgName))) 666 Expect(err).ToNot(HaveOccurred()) 667 668 var session *Session 669 if skipSSLValidation { 670 session = helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "-a", apiURL, "--skip-ssl-validation") 671 } else { 672 session = helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "-a", apiURL) 673 } 674 Eventually(session).Should(Say(`\d\. %s`, orgName)) 675 Eventually(session).Should(Exit(0)) 676 677 targetSession := helpers.CF("target") 678 Eventually(targetSession).Should(Exit(0)) 679 Eventually(targetSession).Should(Say(`org:\s+%s`, orgName)) 680 }) 681 }) 682 683 When("user does not select an organization", func() { 684 // allowed to change 685 It("succesfully logs in but does not target any org", func() { 686 input := NewBuffer() 687 _, err := input.Write([]byte("\n")) 688 Expect(err).ToNot(HaveOccurred()) 689 690 var session *Session 691 if skipSSLValidation { 692 session = helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "-a", apiURL, "--skip-ssl-validation") 693 } else { 694 session = helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "-a", apiURL) 695 } 696 Eventually(session).Should(Say(`Org \(enter to skip\):`)) 697 Consistently(session).ShouldNot(Say(`Org \(enter to skip\):`)) 698 Eventually(session).Should(Exit(0)) 699 700 targetSession := helpers.CF("target") 701 Eventually(targetSession).Should(Exit(0)) 702 Eventually(targetSession).Should(Say("No org or space targeted, use 'cf target -o ORG -s SPACE'")) 703 }) 704 }) 705 706 When("the user enters an invalid organization at the prompt", func() { 707 It("displays an error message and does not target the org", func() { 708 orgName = "invalid-org" 709 input := NewBuffer() 710 _, err := input.Write([]byte(fmt.Sprintf("%s\n", orgName))) 711 Expect(err).ToNot(HaveOccurred()) 712 713 session := helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "--skip-ssl-validation") 714 Eventually(session).Should(Exit(1)) 715 Eventually(session).Should(Say("FAILED")) 716 Eventually(session.Err).Should(Say("Organization '%s' not found", orgName)) 717 718 targetSession := helpers.CF("target") 719 Eventually(targetSession).Should(Exit(0)) 720 Eventually(targetSession).Should(Say(`user:\s+%s`, username)) 721 Eventually(targetSession).ShouldNot(Say(`org:\s+%s`, orgName)) 722 Eventually(targetSession).Should(Say("No org or space targeted, use 'cf target -o ORG -s SPACE'")) 723 }) 724 }) 725 }) 726 }) 727 728 When("the -o flag is passed", func() { 729 BeforeEach(func() { 730 helpers.LogoutCF() 731 }) 732 733 When("the organization is valid", func() { 734 It("targets the organization that was passed as an argument", func() { 735 session := helpers.CF("login", "-u", username, "-p", password, "-o", orgName) 736 737 Eventually(session).Should(Exit(0)) 738 Eventually(session).Should(Say(`Org:\s+%s`, orgName)) 739 740 targetSession := helpers.CF("target") 741 Eventually(targetSession).Should(Exit(0)) 742 Eventually(targetSession).Should(Say(`org:\s+%s`, orgName)) 743 }) 744 }) 745 746 When("the organization is invalid", func() { 747 It("logs in the user, displays an error message, and does not target any organization", func() { 748 orgName = "invalid-org" 749 session := helpers.CF("login", "-u", username, "-p", password, "-o", orgName) 750 751 Eventually(session).Should(Exit(1)) 752 Eventually(session).Should(Say("FAILED")) 753 Eventually(session.Err).Should(Say("Organization '%s' not found", orgName)) 754 755 targetSession := helpers.CF("target") 756 Eventually(targetSession).Should(Exit(0)) 757 Eventually(targetSession).Should(Say(`user:\s+%s`, username)) 758 Eventually(targetSession).ShouldNot(Say(`org:\s+%s`, orgName)) 759 Eventually(targetSession).Should(Say("No org or space targeted, use 'cf target -o ORG -s SPACE'")) 760 }) 761 }) 762 }) 763 }) 764 765 Describe("Target Space", func() { 766 var ( 767 orgName string 768 username string 769 password string 770 ) 771 772 BeforeEach(func() { 773 helpers.LoginCF() 774 orgName = helpers.NewOrgName() 775 session := helpers.CF("create-org", orgName) 776 Eventually(session).Should(Exit(0)) 777 username, password = helpers.CreateUser() 778 }) 779 780 When("only one space is available to the user", func() { 781 var spaceName string 782 783 BeforeEach(func() { 784 spaceName = helpers.NewSpaceName() 785 session := helpers.CF("create-space", "-o", orgName, spaceName) 786 Eventually(session).Should(Exit(0)) 787 roleSession := helpers.CF("set-space-role", username, orgName, spaceName, "SpaceManager") 788 Eventually(roleSession).Should(Exit(0)) 789 }) 790 791 It("logs the user in and targets the org and the space", func() { 792 session := helpers.CF("login", "-u", username, "-p", password, "-a", apiURL, "--skip-ssl-validation") 793 Eventually(session).Should(Exit(0)) 794 795 targetSession := helpers.CF("target") 796 Eventually(targetSession).Should(Exit(0)) 797 Eventually(targetSession).Should(Say(`org:\s+%s`, orgName)) 798 Eventually(targetSession).Should(Say(`space:\s+%s`, spaceName)) 799 }) 800 801 When("the -s flag is passed", func() { 802 It("targets the org and the space", func() { 803 session := helpers.CF("login", "-u", username, "-p", password, "-a", apiURL, "-s", spaceName, "--skip-ssl-validation") 804 805 Eventually(session).Should(Say(`Targeted org\s+%s`, orgName)) 806 Eventually(session).Should(Say(`\n\nTargeted space\s+%s`, spaceName)) 807 808 Eventually(session).Should(Say(`Org:\s+%s`, orgName)) 809 Eventually(session).Should(Say(`Space:\s+%s`, spaceName)) 810 Eventually(session).Should(Exit(0)) 811 812 sessionOutput := string(session.Out.Contents()) 813 Expect(sessionOutput).To(MatchRegexp(`\S\n\n\n\nAPI`)) 814 815 targetSession := helpers.CF("target") 816 Eventually(targetSession).Should(Exit(0)) 817 Eventually(targetSession).Should(Say(`org:\s+%s`, orgName)) 818 Eventually(targetSession).Should(Say(`space:\s+%s`, spaceName)) 819 }) 820 }) 821 }) 822 823 When("multiple spaces are available to the user", func() { 824 var ( 825 spaceName string 826 spaceName2 string 827 ) 828 829 BeforeEach(func() { 830 spaceName = helpers.NewSpaceName() 831 session := helpers.CF("create-space", "-o", orgName, spaceName) 832 Eventually(session).Should(Exit(0)) 833 roleSession := helpers.CF("set-space-role", username, orgName, spaceName, "SpaceManager") 834 Eventually(roleSession).Should(Exit(0)) 835 836 spaceName2 = helpers.NewSpaceName() 837 session2 := helpers.CF("create-space", "-o", orgName, spaceName2) 838 Eventually(session2).Should(Exit(0)) 839 roleSession2 := helpers.CF("set-space-role", username, orgName, spaceName2, "SpaceManager") 840 Eventually(roleSession2).Should(Exit(0)) 841 }) 842 843 When("the -s flag is passed", func() { 844 BeforeEach(func() { 845 orgName2 := helpers.NewOrgName() 846 session := helpers.CF("create-org", orgName2) 847 Eventually(session).Should(Exit(0)) 848 session = helpers.CF("set-org-role", username, orgName2, "OrgManager") 849 Eventually(session).Should(Exit(0)) 850 }) 851 852 It("targets the org and the space", func() { 853 stdin := NewBuffer() 854 _, writeErr := stdin.Write([]byte(orgName + "\n")) 855 Expect(writeErr).ToNot(HaveOccurred()) 856 session := helpers.CFWithStdin(stdin, "login", "-u", username, "-p", password, "-a", apiURL, "-s", spaceName, "--skip-ssl-validation") 857 858 Eventually(session).Should(Say(`Targeted org\s+%s`, orgName)) 859 Eventually(session).Should(Say(`\n\nTargeted space\s+%s`, spaceName)) 860 861 Eventually(session).Should(Say(`Org:\s+%s`, orgName)) 862 Eventually(session).Should(Say(`Space:\s+%s`, spaceName)) 863 Eventually(session).Should(Exit(0)) 864 865 sessionOutput := string(session.Out.Contents()) 866 Expect(sessionOutput).To(MatchRegexp(`\S\n\n\n\nAPI`)) 867 868 targetSession := helpers.CF("target") 869 Eventually(targetSession).Should(Exit(0)) 870 Eventually(targetSession).Should(Say(`org:\s+%s`, orgName)) 871 Eventually(targetSession).Should(Say(`space:\s+%s`, spaceName)) 872 }) 873 874 When("the space name is invalid", func() { 875 BeforeEach(func() { 876 spaceName = "invalid-space-name" 877 }) 878 879 It("the command fails and displays an error message. It targets the org but not the space.", func() { 880 stdin := NewBuffer() 881 _, writeErr := stdin.Write([]byte(orgName + "\n")) 882 Expect(writeErr).ToNot(HaveOccurred()) 883 session := helpers.CFWithStdin(stdin, "login", "-u", username, "-p", password, "-a", apiURL, "-s", spaceName, "--skip-ssl-validation") 884 Eventually(session).Should(Exit(1)) 885 Eventually(session).Should(Say("FAILED")) 886 Eventually(session.Err).Should(Say("Space '%s' not found", spaceName)) 887 888 targetSession := helpers.CF("target") 889 Eventually(targetSession).Should(Exit(0)) 890 Eventually(targetSession).Should(Say(`org:\s+%s`, orgName)) 891 Eventually(targetSession).ShouldNot(Say(`space:\s+%s`, spaceName)) 892 Eventually(targetSession).Should(Say("No space targeted, use 'cf target -s SPACE'")) 893 }) 894 }) 895 }) 896 897 When("the -s flag is not passed", func() { 898 It("prompts the user to pick their space by list position", func() { 899 input := NewBuffer() 900 _, err := input.Write([]byte("1\n")) 901 Expect(err).ToNot(HaveOccurred()) 902 903 session := helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "-a", apiURL, "--skip-ssl-validation") 904 Eventually(session).Should(Exit(0)) 905 906 re := regexp.MustCompile("1\\. (?P<SpaceName>.*)\n") 907 submatches := re.FindStringSubmatch(string(session.Out.Contents())) 908 Expect(submatches).ToNot(BeEmpty(), "missing numbered space list") 909 expectedSpaceName := submatches[1] 910 911 targetSession := helpers.CF("target") 912 Eventually(targetSession).Should(Exit(0)) 913 Eventually(targetSession).Should(Say(`space:\s+%s`, expectedSpaceName)) 914 }) 915 916 It("reprompts the user if an invalid number is entered", func() { 917 input := NewBuffer() 918 _, err := input.Write([]byte("4\n")) 919 Expect(err).ToNot(HaveOccurred()) 920 921 session := helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "-a", apiURL, "--skip-ssl-validation") 922 Eventually(session).Should(Say(regexp.QuoteMeta("Space (enter to skip):"))) 923 Eventually(session).Should(Say(regexp.QuoteMeta("Space (enter to skip):"))) 924 session.Interrupt() 925 Eventually(session).Should(Exit()) 926 }) 927 928 It("prompts the user to pick their space by name", func() { 929 input := NewBuffer() 930 _, err := input.Write([]byte(spaceName + "\n")) 931 Expect(err).ToNot(HaveOccurred()) 932 933 session := helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "-a", apiURL, "--skip-ssl-validation") 934 Eventually(session).Should(Exit(0)) 935 936 targetSession := helpers.CF("target") 937 Eventually(targetSession).Should(Exit(0)) 938 Eventually(targetSession).Should(Say(`space:\s+%s`, spaceName)) 939 }) 940 941 It("allows the user to skip picking a space", func() { 942 input := NewBuffer() 943 _, err := input.Write([]byte("\n")) 944 Expect(err).ToNot(HaveOccurred()) 945 946 session := helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "-a", apiURL, "--skip-ssl-validation") 947 Eventually(session).Should(Exit(0)) 948 949 targetSession := helpers.CF("target") 950 Eventually(targetSession).Should(Exit(0)) 951 Eventually(targetSession).Should(Say(`No space targeted, use 'cf target -s SPACE'`)) 952 }) 953 954 When("the input space name is invalid", func() { 955 BeforeEach(func() { 956 spaceName = "invalid-space-name" 957 }) 958 959 It("the command fails and displays an error message. It does not target the space.", func() { 960 input := NewBuffer() 961 _, err := input.Write([]byte(spaceName + "\n")) 962 Expect(err).ToNot(HaveOccurred()) 963 964 session := helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "-a", apiURL, "--skip-ssl-validation") 965 Eventually(session).Should(Exit(1)) 966 Eventually(session).Should(Say("FAILED")) 967 Eventually(session.Err).Should(Say("Space '%s' not found", spaceName)) 968 969 targetSession := helpers.CF("target") 970 Eventually(targetSession).Should(Exit(0)) 971 Eventually(targetSession).Should(Say(`org:\s+%s`, orgName)) 972 Eventually(targetSession).ShouldNot(Say(`space:\s+%s`, spaceName)) 973 Eventually(targetSession).Should(Say("No space targeted, use 'cf target -s SPACE'")) 974 }) 975 }) 976 977 When("there are more than 50 spaces", func() { 978 var server *ghttp.Server 979 BeforeEach(func() { 980 server = helpers.StartAndTargetMockServerWithAPIVersions(helpers.DefaultV2Version, helpers.DefaultV3Version) 981 helpers.AddLoginRoutes(server) 982 helpers.AddFiftyOneSpaces(server) 983 }) 984 985 AfterEach(func() { 986 server.Close() 987 }) 988 989 It("displays a message and prompts the user for the space name", func() { 990 input := NewBuffer() 991 _, wErr := input.Write([]byte(fmt.Sprintf("%s\n", "test-space-1"))) 992 Expect(wErr).ToNot(HaveOccurred()) 993 994 session := helpers.CFWithStdin(input, "login", "-u", username, "-p", password, "--skip-ssl-validation") 995 996 Eventually(session).Should(Say("Select a space:")) 997 Eventually(session).Should(Say("There are too many options to display; please type in the name.")) 998 Eventually(session).Should(Say("\n\n")) 999 Eventually(session).Should(Say(regexp.QuoteMeta(`Space (enter to skip):`))) 1000 Eventually(session).Should(Say("Targeted space test-space-1")) 1001 1002 Eventually(session).Should(Exit(0)) 1003 }) 1004 }) 1005 }) 1006 }) 1007 1008 }) 1009 1010 Describe("Full interactive happy path", func() { 1011 var ( 1012 orgName1 string 1013 orgName2 string 1014 spaceName1 string 1015 spaceName2 string 1016 username string 1017 password string 1018 ) 1019 1020 BeforeEach(func() { 1021 helpers.LoginCF() 1022 orgName1 = helpers.NewOrgName() 1023 orgName2 = helpers.NewOrgName() 1024 spaceName1 = helpers.NewSpaceName() 1025 spaceName2 = helpers.NewSpaceName() 1026 1027 Eventually(helpers.CF("create-org", orgName1)).Should(Exit(0)) 1028 Eventually(helpers.CF("create-org", orgName2)).Should(Exit(0)) 1029 Eventually(helpers.CF("create-space", "-o", orgName1, spaceName1)).Should(Exit(0)) 1030 Eventually(helpers.CF("create-space", "-o", orgName1, spaceName2)).Should(Exit(0)) 1031 1032 username, password = helpers.CreateUser() 1033 Eventually(helpers.CF("set-org-role", username, orgName1, "OrgManager")).Should(Exit(0)) 1034 Eventually(helpers.CF("set-org-role", username, orgName2, "OrgManager")).Should(Exit(0)) 1035 Eventually(helpers.CF("set-space-role", username, orgName1, spaceName1, "SpaceManager")).Should(Exit(0)) 1036 Eventually(helpers.CF("set-space-role", username, orgName1, spaceName2, "SpaceManager")).Should(Exit(0)) 1037 }) 1038 1039 When("there are multiple orgs and spaces available to a user", func() { 1040 It("prompts for username, password, org, and space. Then logs in and targets correctly", func() { 1041 buffer := NewBuffer() 1042 _, err := buffer.Write([]byte(fmt.Sprintf("%s\n%s\n%s\n%s\n", username, password, orgName1, spaceName2))) 1043 Expect(err).ToNot(HaveOccurred()) 1044 1045 session := helpers.CFWithStdin(buffer, "login") 1046 Eventually(session).Should(Say("Email:")) 1047 Eventually(session).Should(Say("\n\n")) 1048 Eventually(session).Should(Say("Password:")) 1049 Eventually(session).Should(Say("OK")) 1050 Eventually(session).Should(Say("\n\n")) 1051 Eventually(session).Should(Say("Select an org:")) 1052 Eventually(session).Should(Say("\n\n")) 1053 Eventually(session).Should(Say(regexp.QuoteMeta(`Org (enter to skip):`))) 1054 Eventually(session).Should(Say(fmt.Sprintf("Targeted org %s", orgName1))) 1055 Eventually(session).Should(Say("\n\n")) 1056 Eventually(session).Should(Say("Select a space:")) 1057 Eventually(session).Should(Say("\n\n")) 1058 Eventually(session).Should(Say(regexp.QuoteMeta(`Space (enter to skip):`))) 1059 Eventually(session).Should(Say(fmt.Sprintf("Targeted space %s", spaceName2))) 1060 Eventually(session).Should(Say("\n\n")) 1061 Eventually(session).Should(Say(`Org:\s+%s`, orgName1)) 1062 Eventually(session).Should(Say(`Space:\s+%s`, spaceName2)) 1063 Eventually(session).Should(Exit(0)) 1064 1065 targetSession := helpers.CF("target") 1066 Eventually(targetSession).Should(Exit(0)) 1067 Eventually(targetSession).Should(Say(`org:\s+%s`, orgName1)) 1068 Eventually(targetSession).Should(Say(`space:\s+%s`, spaceName2)) 1069 }) 1070 }) 1071 }) 1072 1073 Describe("User Credentials", func() { 1074 It("prompts the user for email and password", func() { 1075 username, password := helpers.GetCredentials() 1076 buffer := NewBuffer() 1077 _, err := buffer.Write([]byte(fmt.Sprintf("%s\n%s\n", username, password))) 1078 Expect(err).ToNot(HaveOccurred()) 1079 session := helpers.CFWithStdin(buffer, "login") 1080 Eventually(session).Should(Say("Email:")) 1081 Eventually(session).Should(Say("\n\n")) 1082 Eventually(session).Should(Say("Password:")) 1083 Eventually(session).Should(Say("\n\n")) 1084 Eventually(session).Should(Exit(0)) 1085 }) 1086 1087 When("the user's account has been locked due to too many failed attempts", func() { 1088 var username string 1089 1090 BeforeEach(func() { 1091 helpers.LoginCF() 1092 username, _ = helpers.CreateUser() 1093 helpers.LogoutCF() 1094 }) 1095 1096 It("displays a helpful error and does not reprompt", func() { 1097 input := NewBuffer() 1098 _, err := input.Write([]byte("garbage\ngarbage\ngarbage\n")) 1099 Expect(err).ToNot(HaveOccurred()) 1100 session := helpers.CFWithStdin(input, "login", "-u", username) 1101 Eventually(session).Should(Exit(1)) 1102 1103 input = NewBuffer() 1104 _, err = input.Write([]byte("garbage\ngarbage\ngarbage\n")) 1105 Expect(err).ToNot(HaveOccurred()) 1106 session = helpers.CFWithStdin(input, "login", "-u", username) 1107 Eventually(session).Should(Exit(1)) 1108 1109 input = NewBuffer() 1110 _, err = input.Write([]byte("garbage\ngarbage\ngarbage\n")) 1111 Expect(err).NotTo(HaveOccurred()) 1112 session = helpers.CFWithStdin(input, "login", "-u", username) 1113 Eventually(session).Should(Say(`Password`)) 1114 Eventually(session.Err).Should(Say(`Your account has been locked because of too many failed attempts to login\.`)) 1115 Consistently(session).ShouldNot(Say(`Password`)) 1116 Eventually(session.Err).Should(Say(`Unable to authenticate.`)) 1117 Eventually(session).Should(Say("FAILED")) 1118 Eventually(session).Should(Exit(1)) 1119 }) 1120 }) 1121 1122 When("the -u flag is provided", func() { 1123 It("prompts the user for their password", func() { 1124 username, password := helpers.GetCredentials() 1125 buffer := NewBuffer() 1126 _, err := buffer.Write([]byte(fmt.Sprintf("%s\n", password))) 1127 Expect(err).ToNot(HaveOccurred()) 1128 session := helpers.CFWithStdin(buffer, "login", "-u", username) 1129 Eventually(session).Should(Say("Password: ")) 1130 Eventually(session).Should(Exit(0)) 1131 }) 1132 }) 1133 1134 When("the user provides the -p flag", func() { 1135 It("prompts the user for their email and logs in successfully", func() { 1136 username, password := helpers.GetCredentials() 1137 input := NewBuffer() 1138 _, err := input.Write([]byte(username + "\n")) 1139 Expect(err).ToNot(HaveOccurred()) 1140 session := helpers.CFWithStdin(input, "login", "-p", password) 1141 Eventually(session).Should(Say("Email: ")) 1142 Eventually(session).Should(Exit(0)) 1143 }) 1144 1145 When("the password flag is given incorrectly", func() { 1146 It("Prompts the user two more times before exiting with an error", func() { 1147 username, _ := helpers.GetCredentials() 1148 input := NewBuffer() 1149 _, err := input.Write([]byte(username + "\n" + "bad-password\n" + "bad-password\n")) 1150 Expect(err).ToNot(HaveOccurred()) 1151 session := helpers.CFWithStdin(input, "login", "-p", "bad-password") 1152 Eventually(session).Should(Say("Email: ")) 1153 Eventually(session.Err).Should(Say("Credentials were rejected, please try again.")) 1154 Eventually(session).Should(Say("Password: ")) 1155 Eventually(session.Err).Should(Say("Credentials were rejected, please try again.")) 1156 Eventually(session).Should(Say("Not logged in. Use 'cf login' or 'cf login --sso' to log in.")) 1157 Eventually(session).Should(Say("FAILED")) 1158 Eventually(session.Err).Should(Say("Unable to authenticate.")) 1159 Eventually(session).Should(Exit(1)) 1160 }) 1161 }) 1162 }) 1163 1164 When("multiple interactive prompts are used", func() { 1165 var ( 1166 orgName string 1167 orgName2 string 1168 username string 1169 password string 1170 ) 1171 1172 BeforeEach(func() { 1173 helpers.LoginCF() 1174 orgName = helpers.NewOrgName() 1175 session := helpers.CF("create-org", orgName) 1176 Eventually(session).Should(Exit(0)) 1177 username, password = helpers.CreateUserInOrgRole(orgName, "OrgManager") 1178 1179 orgName2 = helpers.NewOrgName() 1180 Eventually(helpers.CF("create-org", orgName2)).Should(Exit(0)) 1181 setOrgRoleSession := helpers.CF("set-org-role", username, orgName2, "OrgManager") 1182 Eventually(setOrgRoleSession).Should(Exit(0)) 1183 }) 1184 1185 It("should accept each value", func() { 1186 input := NewBuffer() 1187 _, err := input.Write([]byte(username + "\n" + password + "\n" + orgName + "\n")) 1188 Expect(err).ToNot(HaveOccurred()) 1189 session := helpers.CFWithStdin(input, "login") 1190 Eventually(session).Should(Exit(0)) 1191 }) 1192 1193 When("MFA is enabled", func() { 1194 var ( 1195 password string 1196 mfaCode string 1197 server *ghttp.Server 1198 ) 1199 1200 BeforeEach(func() { 1201 password = "some-password" 1202 mfaCode = "123456" 1203 server = helpers.StartAndTargetMockServerWithAPIVersions(helpers.DefaultV2Version, helpers.DefaultV3Version) 1204 helpers.AddMfa(server, password, mfaCode) 1205 }) 1206 1207 AfterEach(func() { 1208 server.Close() 1209 }) 1210 1211 When("correct MFA code and credentials are provided", func() { 1212 BeforeEach(func() { 1213 fakeTokenResponse := map[string]string{ 1214 "access_token": "", 1215 "token_type": "bearer", 1216 } 1217 server.RouteToHandler(http.MethodPost, "/oauth/token", 1218 ghttp.RespondWithJSONEncoded(http.StatusOK, fakeTokenResponse)) 1219 server.RouteToHandler(http.MethodGet, "/v3/organizations", 1220 ghttp.RespondWith(http.StatusOK, `{ 1221 "total_results": 0, 1222 "total_pages": 1, 1223 "resources": []}`)) 1224 }) 1225 1226 It("logs in the user", func() { 1227 input := NewBuffer() 1228 _, err := input.Write([]byte(username + "\n" + password + "\n" + mfaCode + "\n")) 1229 Expect(err).ToNot(HaveOccurred()) 1230 session := helpers.CFWithStdin(input, "login") 1231 Eventually(session).Should(Say("Email: ")) 1232 Eventually(session).Should(Say("\n\n")) 1233 Eventually(session).Should(Say("Password:")) 1234 Eventually(session).Should(Say("\n\n")) 1235 Eventually(session).Should(Say("MFA Code \\( Register at %[1]s \\)", server.URL())) 1236 Eventually(session).Should(Exit(0)) 1237 }) 1238 }) 1239 1240 When("incorrect MFA code and credentials are provided", func() { 1241 It("fails", func() { 1242 input := NewBuffer() 1243 wrongMfaCode := mfaCode + "foo" 1244 _, err := input.Write([]byte(username + "\n" + password + "\n" + wrongMfaCode + "\n" + password + "\n" + wrongMfaCode + "\n")) 1245 Expect(err).ToNot(HaveOccurred()) 1246 session := helpers.CFWithStdin(input, "login") 1247 Eventually(session).Should(Say("Password: ")) 1248 Eventually(session).Should(Say("MFA Code \\( Register at %[1]s \\)", server.URL())) 1249 Eventually(session).Should(Say("Password: ")) 1250 Eventually(session).Should(Say("MFA Code \\( Register at %[1]s \\)", server.URL())) 1251 Eventually(session).Should(Say("Not logged in. Use 'cf login' or 'cf login --sso' to log in.")) 1252 Eventually(session).Should(Say("FAILED")) 1253 Eventually(session.Err).Should(Say("Unable to authenticate.")) 1254 1255 Eventually(session).Should(Exit(1)) 1256 }) 1257 }) 1258 }) 1259 }) 1260 1261 When("the user provides the -p and -u flags", func() { 1262 Context("and the credentials are correct", func() { 1263 It("logs in successfully", func() { 1264 username, password := helpers.GetCredentials() 1265 session := helpers.CF("login", "-p", password, "-u", username) 1266 Eventually(session).Should(Say("API endpoint:\\s+" + helpers.GetAPI())) 1267 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 1268 Eventually(session).Should(Say(`OK`)) 1269 Eventually(session).Should(Say(`API endpoint:\s+` + helpers.GetAPI() + `\s+\(API version: \d\.\d{1,3}\.\d{1,3}\)`)) 1270 Eventually(session).Should(Say("User:\\s+" + username)) 1271 Eventually(session).Should(Exit(0)) 1272 }) 1273 }) 1274 1275 Context("and the credentials are incorrect", func() { 1276 It("prompts twice, displays an error and fails", func() { 1277 input := NewBuffer() 1278 _, err := input.Write([]byte("garbage\ngarbage\n")) 1279 Expect(err).ToNot(HaveOccurred()) 1280 session := helpers.CFWithStdin(input, "login", "-p", "nope", "-u", "faker") 1281 Eventually(session).Should(Say("API endpoint:\\s+" + helpers.GetAPI())) 1282 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 1283 Eventually(session.Err).Should(Say(`Credentials were rejected, please try again.`)) 1284 Eventually(session).Should(Say(`Password:`)) 1285 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 1286 Eventually(session.Err).Should(Say(`Credentials were rejected, please try again.`)) 1287 Eventually(session).Should(Say(`Password:`)) 1288 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 1289 Eventually(session.Err).Should(Say(`Credentials were rejected, please try again.`)) 1290 Eventually(session).Should(Say(`API endpoint:\s+` + helpers.GetAPI() + `\s+\(API version: \d\.\d{1,3}\.\d{1,3}\)`)) 1291 Eventually(session).Should(Say(`Not logged in. Use 'cf login' or 'cf login --sso' to log in.`)) 1292 Eventually(session.Err).Should(Say(`Unable to authenticate.`)) 1293 Eventually(session).Should(Say(`FAILED`)) 1294 1295 Eventually(session).Should(Exit(1)) 1296 }) 1297 1298 Context("and the user was previously logged in", func() { 1299 BeforeEach(func() { 1300 helpers.LoginCF() 1301 }) 1302 1303 It("logs them out", func() { 1304 session := helpers.CF("login", "-p", "nope", "-u", "faker") 1305 Eventually(session).Should(Say(`Not logged in. Use 'cf login' or 'cf login --sso' to log in.`)) 1306 Eventually(session).Should(Exit()) 1307 1308 orgsSession := helpers.CF("orgs") 1309 Eventually(orgsSession.Err).Should(Say(`Not logged in. Use 'cf login' or 'cf login --sso' to log in.`)) 1310 Eventually(orgsSession).Should(Exit()) 1311 }) 1312 }) 1313 }) 1314 1315 When("already logged in with client credentials", func() { 1316 BeforeEach(func() { 1317 clientID, clientSecret := helpers.SkipIfClientCredentialsNotSet() 1318 session := helpers.CF("auth", clientID, clientSecret, "--client-credentials") 1319 Eventually(session).Should(Exit(0)) 1320 }) 1321 1322 It("should fail log in and display an error informing the user they need to log out", func() { 1323 username, password := helpers.GetCredentials() 1324 session := helpers.CF("login", "-p", password, "-u", username) 1325 Eventually(session).Should(Say("API endpoint:\\s+" + helpers.GetAPI())) 1326 Eventually(session).Should(Say(`API endpoint:\s+` + helpers.GetAPI() + `\s+\(API version: \d\.\d{1,3}\.\d{1,3}\)`)) 1327 Eventually(session).Should(Say("FAILED")) 1328 Eventually(session.Err).Should(Say("Service account currently logged in. Use 'cf logout' to log out service account and try again.")) 1329 Eventually(session).Should(Exit(1)) 1330 }) 1331 }) 1332 }) 1333 }) 1334 1335 Describe("Authenticating as a user, through a custom client", func() { 1336 var ( 1337 accessTokenExpiration time.Duration 1338 username string 1339 password string 1340 customClientID string 1341 customClientSecret string 1342 ) 1343 1344 BeforeEach(func() { 1345 customClientID, customClientSecret = helpers.SkipIfCustomClientCredentialsNotSet() 1346 1347 helpers.LoginCF() 1348 username, password = helpers.CreateUser() 1349 1350 helpers.SetConfig(func(config *configv3.Config) { 1351 config.ConfigFile.UAAOAuthClient = customClientID 1352 config.ConfigFile.UAAOAuthClientSecret = customClientSecret 1353 config.ConfigFile.UAAGrantType = "" 1354 }) 1355 1356 session := helpers.CF("login", "-u", username, "-p", password) 1357 Eventually(session).Should(Exit(0)) 1358 }) 1359 1360 It("gets a token whose settings match those of the custom client", func() { 1361 accessTokenExpiration = 120 // this was configured in the pipeline 1362 1363 config := helpers.GetConfig() 1364 1365 jwt := helpers.ParseTokenString(config.ConfigFile.AccessToken) 1366 expires, expIsSet := jwt.Claims().Expiration() 1367 Expect(expIsSet).To(BeTrue()) 1368 1369 iat, iatIsSet := jwt.Claims().IssuedAt() 1370 1371 Expect(iatIsSet).To(BeTrue()) 1372 Expect(expires.Sub(iat)).To(Equal(accessTokenExpiration * time.Second)) 1373 }) 1374 1375 It("warns the user that this configuration is deprecated", func() { 1376 deprecationMessage := "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." 1377 1378 session := helpers.CF("login", "-u", username, "-p", password) 1379 Eventually(session.Err).Should(Say(deprecationMessage)) 1380 Eventually(session).Should(Exit(0)) 1381 }) 1382 1383 When("the token has expired", func() { 1384 BeforeEach(func() { 1385 helpers.SetConfig(func(config *configv3.Config) { 1386 config.ConfigFile.AccessToken = helpers.ExpiredAccessToken() 1387 }) 1388 }) 1389 1390 It("re-authenticates using the custom client", func() { 1391 session := helpers.CF("orgs") 1392 Eventually(session).Should(Exit(0)) 1393 }) 1394 }) 1395 }) 1396 1397 Describe("Setting the identity provider to be used", func() { 1398 When("the user provides the --origin flag", func() { 1399 It("logs in successfully", func() { 1400 username, password := helpers.GetCredentials() 1401 session := helpers.CF("login", "-u", username, "-p", password, "--origin", "uaa") 1402 Eventually(session).Should(Say("API endpoint:\\s+" + helpers.GetAPI())) 1403 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 1404 Eventually(session).Should(Say(`OK`)) 1405 Eventually(session).Should(Say(`API endpoint:\s+` + helpers.GetAPI() + `\s+\(API version: \d\.\d{1,3}\.\d{1,3}\)`)) 1406 Eventually(session).Should(Say("User:\\s+" + username)) 1407 Eventually(session).Should(Exit(0)) 1408 }) 1409 }) 1410 1411 When("the user provides the --origin flag and --sso flag", func() { 1412 It("rejects the command", func() { 1413 username, password := helpers.GetCredentials() 1414 session := helpers.CF("login", "-u", username, "-p", password, "--sso", "--origin", "uaa") 1415 1416 Eventually(session.Err).Should(Say(`Incorrect Usage: The following arguments cannot be used together: --sso, --origin`)) 1417 1418 Eventually(session).Should(Exit(1)) 1419 }) 1420 }) 1421 When("the user provides the --origin flag and --sso-passcode flag", func() { 1422 It("rejects the command", func() { 1423 username, password := helpers.GetCredentials() 1424 session := helpers.CF("login", "-u", username, "-p", password, "--sso-passcode", "some-passcode", "--origin", "uaa") 1425 1426 Eventually(session.Err).Should(Say(`Incorrect Usage: The following arguments cannot be used together: --sso-passcode, --origin`)) 1427 1428 Eventually(session).Should(Exit(1)) 1429 }) 1430 }) 1431 }) 1432 })