github.com/pf-qiu/concourse/v6@v6.7.3-0.20201207032516-1f455d73275f/fly/integration/login_test.go (about) 1 package integration_test 2 3 import ( 4 "bufio" 5 "bytes" 6 "crypto/tls" 7 "encoding/base64" 8 "fmt" 9 "io/ioutil" 10 "net/http" 11 "os" 12 "os/exec" 13 "regexp" 14 15 . "github.com/onsi/ginkgo" 16 . "github.com/onsi/gomega" 17 "github.com/onsi/gomega/gbytes" 18 "github.com/onsi/gomega/gexec" 19 "github.com/onsi/gomega/ghttp" 20 21 "github.com/pf-qiu/concourse/v6/atc" 22 ) 23 24 var _ = Describe("login Command", func() { 25 var ( 26 loginATCServer *ghttp.Server 27 ) 28 29 Describe("login with no target name", func() { 30 var ( 31 flyCmd *exec.Cmd 32 ) 33 34 BeforeEach(func() { 35 loginATCServer = ghttp.NewServer() 36 loginATCServer.AppendHandlers( 37 infoHandler(), 38 ) 39 flyCmd = exec.Command(flyPath, "login", "-c", loginATCServer.URL()) 40 }) 41 42 AfterEach(func() { 43 loginATCServer.Close() 44 }) 45 46 It("instructs the user to specify --target", func() { 47 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 48 Expect(err).NotTo(HaveOccurred()) 49 50 <-sess.Exited 51 Expect(sess.ExitCode()).To(Equal(1)) 52 53 Expect(sess.Err).To(gbytes.Say(`name for the target must be specified \(--target/-t\)`)) 54 }) 55 }) 56 57 Context("with no team name", func() { 58 BeforeEach(func() { 59 loginATCServer = ghttp.NewServer() 60 }) 61 62 AfterEach(func() { 63 loginATCServer.Close() 64 }) 65 66 It("falls back to atc.DefaultTeamName team", func() { 67 loginATCServer.AppendHandlers( 68 infoHandler(), 69 tokenHandler(), 70 userInfoHandler(), 71 ) 72 73 flyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL(), "-u", "user", "-p", "pass") 74 75 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 76 Expect(err).NotTo(HaveOccurred()) 77 78 Eventually(sess).Should(gbytes.Say("logging in to team 'main'")) 79 80 <-sess.Exited 81 Expect(sess.ExitCode()).To(Equal(0)) 82 }) 83 84 Context("when already logged in as different team", func() { 85 BeforeEach(func() { 86 loginATCServer.AppendHandlers( 87 infoHandler(), 88 tokenHandler(), 89 userInfoHandler(), 90 ) 91 92 setupFlyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL(), "-n", "some-team", "-u", "user", "-p", "pass") 93 err := setupFlyCmd.Run() 94 Expect(err).NotTo(HaveOccurred()) 95 }) 96 97 It("uses the saved team name", func() { 98 loginATCServer.AppendHandlers( 99 infoHandler(), 100 tokenHandler(), 101 userInfoHandler(), 102 ) 103 104 flyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-u", "user", "-p", "pass") 105 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 106 Expect(err).NotTo(HaveOccurred()) 107 Eventually(sess).Should(gbytes.Say("logging in to team 'some-team'")) 108 109 <-sess.Exited 110 Expect(sess.ExitCode()).To(Equal(0)) 111 }) 112 }) 113 }) 114 115 Context("with no specified flag but extra arguments ", func() { 116 117 BeforeEach(func() { 118 loginATCServer = ghttp.NewServer() 119 }) 120 121 AfterEach(func() { 122 loginATCServer.Close() 123 }) 124 125 It("return error indicating login failed with unknown arguments", func() { 126 127 flyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL(), "unknown-argument", "blah") 128 129 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 130 Expect(err).NotTo(HaveOccurred()) 131 132 <-sess.Exited 133 Expect(sess.ExitCode()).NotTo(Equal(0)) 134 Expect(sess.Err).To(gbytes.Say(`unexpected argument \[unknown-argument, blah\]`)) 135 }) 136 }) 137 138 Context("with a team name", func() { 139 140 BeforeEach(func() { 141 loginATCServer = ghttp.NewServer() 142 }) 143 144 AfterEach(func() { 145 loginATCServer.Close() 146 }) 147 148 It("uses specified team", func() { 149 loginATCServer.AppendHandlers( 150 infoHandler(), 151 tokenHandler(), 152 userInfoHandler(), 153 ) 154 155 flyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL(), "-n", "some-team", "-u", "user", "-p", "pass") 156 157 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 158 Expect(err).NotTo(HaveOccurred()) 159 160 Eventually(sess).Should(gbytes.Say("logging in to team 'some-team'")) 161 162 <-sess.Exited 163 Expect(sess.ExitCode()).To(Equal(0)) 164 }) 165 166 Context("when tracing is not enabled", func() { 167 It("does not print out API calls", func() { 168 loginATCServer.AppendHandlers( 169 infoHandler(), 170 tokenHandler(), 171 userInfoHandler(), 172 ) 173 174 flyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL(), "-n", "some-team", "-u", "user", "-p", "pass") 175 176 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 177 Expect(err).NotTo(HaveOccurred()) 178 179 Consistently(sess.Err).ShouldNot(gbytes.Say("HTTP/1.1 200 OK")) 180 Consistently(sess.Out).ShouldNot(gbytes.Say("HTTP/1.1 200 OK")) 181 182 <-sess.Exited 183 Expect(sess.ExitCode()).To(Equal(0)) 184 }) 185 }) 186 187 Context("when tracing is enabled", func() { 188 It("prints out API calls", func() { 189 loginATCServer.AppendHandlers( 190 infoHandler(), 191 tokenHandler(), 192 userInfoHandler(), 193 ) 194 195 flyCmd := exec.Command(flyPath, "--verbose", "-t", "some-target", "login", "-c", loginATCServer.URL(), "-n", "some-team", "-u", "user", "-p", "pass") 196 197 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 198 Expect(err).NotTo(HaveOccurred()) 199 200 Eventually(sess.Err).Should(gbytes.Say("HTTP/1.1 200 OK")) 201 202 <-sess.Exited 203 Expect(sess.ExitCode()).To(Equal(0)) 204 }) 205 }) 206 207 Context("when already logged in as different team", func() { 208 BeforeEach(func() { 209 loginATCServer.AppendHandlers( 210 infoHandler(), 211 tokenHandler(), 212 userInfoHandler(), 213 ) 214 215 setupFlyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL(), "-n", "some-team", "-u", "user", "-p", "pass") 216 err := setupFlyCmd.Run() 217 Expect(err).NotTo(HaveOccurred()) 218 }) 219 220 It("passes provided team name", func() { 221 loginATCServer.AppendHandlers( 222 infoHandler(), 223 tokenHandler(), 224 userInfoHandler(), 225 ) 226 227 flyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-n", "some-other-team", "-u", "user", "-p", "pass") 228 229 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 230 Expect(err).NotTo(HaveOccurred()) 231 232 <-sess.Exited 233 Expect(sess.ExitCode()).To(Equal(0)) 234 }) 235 }) 236 }) 237 238 Describe("with ca cert", func() { 239 BeforeEach(func() { 240 loginATCServer = ghttp.NewUnstartedServer() 241 cert, err := tls.X509KeyPair([]byte(serverCert), []byte(serverKey)) 242 Expect(err).NotTo(HaveOccurred()) 243 244 loginATCServer.HTTPTestServer.TLS = &tls.Config{ 245 Certificates: []tls.Certificate{cert}, 246 } 247 loginATCServer.HTTPTestServer.StartTLS() 248 }) 249 250 AfterEach(func() { 251 loginATCServer.Close() 252 }) 253 254 Context("when already logged in with ca cert", func() { 255 var caCertFilePath string 256 257 BeforeEach(func() { 258 loginATCServer.AppendHandlers( 259 infoHandler(), 260 tokenHandler(), 261 userInfoHandler(), 262 ) 263 264 caCertFile, err := ioutil.TempFile("", "fly-login-test") 265 Expect(err).NotTo(HaveOccurred()) 266 caCertFilePath = caCertFile.Name() 267 268 err = ioutil.WriteFile(caCertFilePath, []byte(serverCert), os.ModePerm) 269 Expect(err).NotTo(HaveOccurred()) 270 271 setupFlyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL(), "-n", "some-team", "--ca-cert", caCertFilePath, "-u", "user", "-p", "pass") 272 273 sess, err := gexec.Start(setupFlyCmd, GinkgoWriter, GinkgoWriter) 274 Expect(err).NotTo(HaveOccurred()) 275 <-sess.Exited 276 Expect(sess.ExitCode()).To(Equal(0)) 277 }) 278 279 AfterEach(func() { 280 os.RemoveAll(caCertFilePath) 281 }) 282 283 Context("when ca cert is not provided", func() { 284 It("is using saved ca cert", func() { 285 loginATCServer.AppendHandlers( 286 infoHandler(), 287 tokenHandler(), 288 userInfoHandler(), 289 ) 290 291 flyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-n", "some-team", "-u", "user", "-p", "pass") 292 293 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 294 Expect(err).NotTo(HaveOccurred()) 295 296 <-sess.Exited 297 Expect(sess.ExitCode()).To(Equal(0)) 298 }) 299 }) 300 }) 301 }) 302 303 Describe("login", func() { 304 var ( 305 flyCmd *exec.Cmd 306 ) 307 308 BeforeEach(func() { 309 loginATCServer = ghttp.NewServer() 310 }) 311 312 AfterEach(func() { 313 loginATCServer.Close() 314 }) 315 316 Context("with authorization_code grant", func() { 317 BeforeEach(func() { 318 loginATCServer.AppendHandlers( 319 infoHandler(), 320 userInfoHandler(), 321 ) 322 }) 323 324 It("allows providing the token via stdin", func() { 325 flyCmd = exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL()) 326 327 stdin, err := flyCmd.StdinPipe() 328 Expect(err).NotTo(HaveOccurred()) 329 330 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 331 Expect(err).NotTo(HaveOccurred()) 332 333 Eventually(sess.Out).Should(gbytes.Say("navigate to the following URL in your browser:")) 334 Eventually(sess.Out).Should(gbytes.Say("http://127.0.0.1:(\\d+)/login\\?fly_port=(\\d+)")) 335 Eventually(sess.Out).Should(gbytes.Say("or enter token manually")) 336 337 _, err = fmt.Fprintf(stdin, "Bearer some-token\n") 338 Expect(err).NotTo(HaveOccurred()) 339 340 err = stdin.Close() 341 Expect(err).NotTo(HaveOccurred()) 342 343 <-sess.Exited 344 Expect(sess.ExitCode()).To(Equal(0)) 345 }) 346 347 Context("when the token from stdin is malformed", func() { 348 It("logs an error and accepts further input", func() { 349 flyCmd = exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL()) 350 351 stdin, err := flyCmd.StdinPipe() 352 Expect(err).NotTo(HaveOccurred()) 353 354 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 355 Expect(err).NotTo(HaveOccurred()) 356 357 Eventually(sess.Out).Should(gbytes.Say("or enter token manually")) 358 359 _, err = fmt.Fprintf(stdin, "not a token\n") 360 Expect(err).NotTo(HaveOccurred()) 361 362 Eventually(sess.Out).Should(gbytes.Say("token must be of the format 'TYPE VALUE', e.g. 'Bearer ...'")) 363 364 _, err = fmt.Fprintf(stdin, "Bearer ok-this-time-its-the-real-deal\n") 365 Expect(err).NotTo(HaveOccurred()) 366 367 err = stdin.Close() 368 Expect(err).NotTo(HaveOccurred()) 369 370 <-sess.Exited 371 Expect(sess.ExitCode()).To(Equal(0)) 372 }) 373 }) 374 375 Context("when the token from stdin is terminated with an EOF", func() { 376 It("accepts the input", func() { 377 flyCmd = exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL()) 378 379 stdin, err := flyCmd.StdinPipe() 380 Expect(err).NotTo(HaveOccurred()) 381 382 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 383 Expect(err).NotTo(HaveOccurred()) 384 385 Eventually(sess.Out).Should(gbytes.Say("or enter token manually")) 386 387 _, err = fmt.Fprintf(stdin, "bearer no-new-line-here") 388 Expect(err).NotTo(HaveOccurred()) 389 390 err = stdin.Close() 391 Expect(err).NotTo(HaveOccurred()) 392 393 <-sess.Exited 394 Expect(sess.ExitCode()).To(Equal(0)) 395 }) 396 397 It("ignores empty input", func() { 398 flyCmd = exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL()) 399 400 stdin, err := flyCmd.StdinPipe() 401 Expect(err).NotTo(HaveOccurred()) 402 403 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 404 Expect(err).NotTo(HaveOccurred()) 405 406 err = stdin.Close() 407 Expect(err).NotTo(HaveOccurred()) 408 409 Consistently(sess.Out).ShouldNot(gbytes.Say("error")) 410 411 sess.Kill() 412 }) 413 }) 414 415 Context("token callback listener", func() { 416 var resp *http.Response 417 var req *http.Request 418 var sess *gexec.Session 419 420 BeforeEach(func() { 421 flyCmd = exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL()) 422 _, err := flyCmd.StdinPipe() 423 Expect(err).NotTo(HaveOccurred()) 424 sess, err = gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 425 Expect(err).NotTo(HaveOccurred()) 426 Eventually(sess.Out).Should(gbytes.Say("or enter token manually")) 427 scanner := bufio.NewScanner(bytes.NewBuffer(sess.Out.Contents())) 428 var match []string 429 for scanner.Scan() { 430 re := regexp.MustCompile("fly_port=(\\d+)") 431 match = re.FindStringSubmatch(scanner.Text()) 432 if len(match) > 0 { 433 break 434 } 435 } 436 flyPort := match[1] 437 listenerURL := fmt.Sprintf("http://127.0.0.1:%s?token=Bearer%%20some-token", flyPort) 438 req, err = http.NewRequest("GET", listenerURL, nil) 439 Expect(err).NotTo(HaveOccurred()) 440 }) 441 442 JustBeforeEach(func() { 443 loginATCServer.AppendHandlers(ghttp.CombineHandlers( 444 ghttp.VerifyRequest("GET", "/fly_success"), 445 ghttp.RespondWith(200, ""), 446 )) 447 client := &http.Client{ 448 CheckRedirect: func(req *http.Request, via []*http.Request) error { 449 return http.ErrUseLastResponse 450 }, 451 } 452 var err error 453 resp, err = client.Do(req) 454 Expect(err).NotTo(HaveOccurred()) 455 <-sess.Exited 456 Expect(sess.ExitCode()).To(Equal(0)) 457 }) 458 459 It("sets a CORS header for the ATC being logged in to", func() { 460 corsHeader := resp.Header.Get("Access-Control-Allow-Origin") 461 Expect(corsHeader).To(Equal(loginATCServer.URL())) 462 }) 463 464 It("responds successfully", func() { 465 Expect(resp.StatusCode).To(Equal(http.StatusOK)) 466 }) 467 468 Context("when the request comes from a human operating a browser", func() { 469 BeforeEach(func() { 470 req.Header.Add("Upgrade-Insecure-Requests", "1") 471 }) 472 473 It("redirects back to noop fly success page", func() { 474 Expect(resp.StatusCode).To(Equal(http.StatusFound)) 475 locationHeader := resp.Header.Get("Location") 476 Expect(locationHeader).To(Equal(fmt.Sprintf("%s/fly_success?noop=true", loginATCServer.URL()))) 477 }) 478 }) 479 }) 480 }) 481 482 Context("with password grant", func() { 483 BeforeEach(func() { 484 credentials := base64.StdEncoding.EncodeToString([]byte("fly:Zmx5")) 485 loginATCServer.AppendHandlers( 486 infoHandler(), 487 ghttp.CombineHandlers( 488 ghttp.VerifyRequest("POST", "/sky/issuer/token"), 489 ghttp.VerifyHeaderKV("Content-Type", "application/x-www-form-urlencoded"), 490 ghttp.VerifyHeaderKV("Authorization", fmt.Sprintf("Basic %s", credentials)), 491 ghttp.VerifyFormKV("grant_type", "password"), 492 ghttp.VerifyFormKV("username", "some_username"), 493 ghttp.VerifyFormKV("password", "some_password"), 494 ghttp.VerifyFormKV("scope", "openid profile email federated:id groups"), 495 ghttp.RespondWithJSONEncoded(200, map[string]string{ 496 "token_type": "Bearer", 497 "access_token": "access-token", 498 }), 499 ), 500 userInfoHandler(), 501 ) 502 }) 503 504 It("takes username and password as cli arguments", func() { 505 flyCmd = exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL(), "-u", "some_username", "-p", "some_password") 506 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 507 Expect(err).NotTo(HaveOccurred()) 508 509 Consistently(sess.Out.Contents).ShouldNot(ContainSubstring("some_password")) 510 511 Eventually(sess.Out).Should(gbytes.Say("target saved")) 512 513 <-sess.Exited 514 Expect(sess.ExitCode()).To(Equal(0)) 515 }) 516 517 Context("after logging in succeeds", func() { 518 BeforeEach(func() { 519 flyCmd = exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL(), "-u", "some_username", "-p", "some_password") 520 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 521 Expect(err).NotTo(HaveOccurred()) 522 523 Consistently(sess.Out.Contents).ShouldNot(ContainSubstring("some_password")) 524 525 Eventually(sess.Out).Should(gbytes.Say("target saved")) 526 527 <-sess.Exited 528 Expect(sess.ExitCode()).To(Equal(0)) 529 }) 530 531 It("flyrc is backwards-compatible with pre-v5.4.0", func() { 532 flyRcContents, err := ioutil.ReadFile(homeDir + "/.flyrc") 533 Expect(err).NotTo(HaveOccurred()) 534 Expect(string(flyRcContents)).To(HavePrefix("targets:")) 535 }) 536 537 Describe("running other commands", func() { 538 BeforeEach(func() { 539 loginATCServer.AppendHandlers( 540 infoHandler(), 541 ghttp.CombineHandlers( 542 ghttp.VerifyRequest("GET", "/api/v1/teams/main/pipelines"), 543 ghttp.VerifyHeaderKV("Authorization", "Bearer access-token"), 544 ghttp.RespondWithJSONEncoded(200, []atc.Pipeline{ 545 {Name: "pipeline-1"}, 546 }), 547 ), 548 ) 549 }) 550 551 It("uses the saved token", func() { 552 otherCmd := exec.Command(flyPath, "-t", "some-target", "pipelines") 553 554 sess, err := gexec.Start(otherCmd, GinkgoWriter, GinkgoWriter) 555 Expect(err).NotTo(HaveOccurred()) 556 557 <-sess.Exited 558 559 Expect(sess).To(gbytes.Say("pipeline-1")) 560 561 Expect(sess.ExitCode()).To(Equal(0)) 562 }) 563 }) 564 565 Describe("logging in again with the same target", func() { 566 BeforeEach(func() { 567 credentials := base64.StdEncoding.EncodeToString([]byte("fly:Zmx5")) 568 569 loginATCServer.AppendHandlers( 570 infoHandler(), 571 ghttp.CombineHandlers( 572 ghttp.VerifyRequest("POST", "/sky/issuer/token"), 573 ghttp.VerifyHeaderKV("Content-Type", "application/x-www-form-urlencoded"), 574 ghttp.VerifyHeaderKV("Authorization", fmt.Sprintf("Basic %s", credentials)), 575 ghttp.VerifyFormKV("grant_type", "password"), 576 ghttp.VerifyFormKV("username", "some_other_user"), 577 ghttp.VerifyFormKV("password", "some_other_pass"), 578 ghttp.VerifyFormKV("scope", "openid profile email federated:id groups"), 579 ghttp.RespondWithJSONEncoded(200, map[string]string{ 580 "token_type": "Bearer", 581 "access_token": "some-new-token", 582 }), 583 ), 584 userInfoHandler(), 585 infoHandler(), 586 ghttp.CombineHandlers( 587 ghttp.VerifyRequest("GET", "/api/v1/teams/main/pipelines"), 588 ghttp.VerifyHeaderKV("Authorization", "Bearer some-new-token"), 589 ghttp.RespondWithJSONEncoded(200, []atc.Pipeline{ 590 {Name: "pipeline-2"}, 591 }), 592 ), 593 ) 594 }) 595 596 It("updates the token", func() { 597 loginAgainCmd := exec.Command(flyPath, "-t", "some-target", "login", "-u", "some_other_user", "-p", "some_other_pass") 598 599 sess, err := gexec.Start(loginAgainCmd, GinkgoWriter, GinkgoWriter) 600 Expect(err).NotTo(HaveOccurred()) 601 602 Consistently(sess.Out.Contents).ShouldNot(ContainSubstring("some_other_pass")) 603 604 Eventually(sess.Out).Should(gbytes.Say("target saved")) 605 606 <-sess.Exited 607 Expect(sess.ExitCode()).To(Equal(0)) 608 609 otherCmd := exec.Command(flyPath, "-t", "some-target", "pipelines") 610 611 sess, err = gexec.Start(otherCmd, GinkgoWriter, GinkgoWriter) 612 Expect(err).NotTo(HaveOccurred()) 613 614 <-sess.Exited 615 616 Expect(sess).To(gbytes.Say("pipeline-2")) 617 618 Expect(sess.ExitCode()).To(Equal(0)) 619 }) 620 }) 621 }) 622 }) 623 624 Context("cannot successfully login", func() { 625 Context("team does not exist", func() { 626 It("returns a warning", func() { 627 loginATCServer.AppendHandlers( 628 infoHandler(), 629 tokenHandler(), 630 ghttp.CombineHandlers( 631 ghttp.VerifyRequest("GET", "/api/v1/user"), 632 ghttp.RespondWithJSONEncoded(200, map[string]interface{}{ 633 "user_name": "user", 634 "teams": map[string][]string{ 635 "other_team": {"owner"}, 636 }, 637 }), 638 ), 639 ) 640 641 flyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL(), "-n", "any-team", "-u", "user", "-p", "pass") 642 643 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 644 Expect(err).NotTo(HaveOccurred()) 645 646 Eventually(sess.Err).Should(gbytes.Say("you are not a member of 'any-team' or the team does not exist")) 647 648 <-sess.Exited 649 Expect(sess.ExitCode()).To(Equal(1)) 650 }) 651 }) 652 Context("/api/v1/user returns garbage", func() { 653 It("returns a warning", func() { 654 loginATCServer.AppendHandlers( 655 infoHandler(), 656 tokenHandler(), 657 ghttp.CombineHandlers( 658 ghttp.VerifyRequest("GET", "/api/v1/user"), 659 ghttp.RespondWithJSONEncoded(200, map[string]interface{}{ 660 "a-key": "a-value", 661 }), 662 ), 663 ) 664 665 flyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL(), "-n", "any-team", "-u", "user", "-p", "pass") 666 667 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 668 Expect(err).NotTo(HaveOccurred()) 669 670 Eventually(sess.Err).Should(gbytes.Say("unable to verify role on team")) 671 672 <-sess.Exited 673 Expect(sess.ExitCode()).To(Equal(1)) 674 }) 675 }) 676 }) 677 678 Context("when logging in as an admin user", func() { 679 It("can login to any team that exists", func() { 680 loginATCServer.AppendHandlers( 681 infoHandler(), 682 tokenHandler(), 683 ghttp.CombineHandlers( 684 ghttp.VerifyRequest("GET", "/api/v1/user"), 685 ghttp.RespondWithJSONEncoded(200, map[string]interface{}{ 686 "user_name": "admin_user", 687 "is_admin": true, 688 }), 689 ), 690 ghttp.CombineHandlers( 691 ghttp.VerifyRequest("GET", "/api/v1/teams"), 692 ghttp.RespondWithJSONEncoded(200, []atc.Team{ 693 { 694 ID: 1, 695 Name: "any-team", 696 Auth: atc.TeamAuth{ 697 "owner": map[string][]string{ 698 "groups": []string{}, 699 "users": []string{}, 700 }, 701 }, 702 }, 703 }), 704 ), 705 ) 706 707 flyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL(), "-n", "any-team", "-u", "admin_user", "-p", "pass") 708 709 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 710 Expect(err).NotTo(HaveOccurred()) 711 712 Eventually(sess.Out).Should(gbytes.Say("target saved")) 713 714 <-sess.Exited 715 Expect(sess.ExitCode()).To(Equal(0)) 716 }) 717 It("fails to login if the team does not exist", func() { 718 loginATCServer.AppendHandlers( 719 infoHandler(), 720 tokenHandler(), 721 ghttp.CombineHandlers( 722 ghttp.VerifyRequest("GET", "/api/v1/user"), 723 ghttp.RespondWithJSONEncoded(200, map[string]interface{}{ 724 "user_name": "admin_user", 725 "is_admin": true, 726 }), 727 ), 728 ghttp.CombineHandlers( 729 ghttp.VerifyRequest("GET", "/api/v1/teams"), 730 ghttp.RespondWithJSONEncoded(200, []atc.Team{ 731 { 732 ID: 1, 733 Name: "main", 734 Auth: atc.TeamAuth{ 735 "owner": map[string][]string{ 736 "groups": []string{}, 737 "users": []string{}, 738 }, 739 }, 740 }, 741 }), 742 ), 743 ) 744 745 flyCmd := exec.Command(flyPath, "-t", "some-target", "login", "-c", loginATCServer.URL(), "-n", "doesNotExist", "-u", "admin_user", "-p", "pass") 746 747 sess, err := gexec.Start(flyCmd, GinkgoWriter, GinkgoWriter) 748 Expect(err).NotTo(HaveOccurred()) 749 750 Eventually(sess.Err).Should(gbytes.Say("error: team 'doesNotExist' does not exist")) 751 752 <-sess.Exited 753 Expect(sess.ExitCode()).To(Equal(1)) 754 }) 755 }) 756 }) 757 })