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