github.com/sleungcy-sap/cli@v7.1.0+incompatible/integration/v7/isolated/api_command_test.go (about)

     1  package isolated
     2  
     3  import (
     4  	"encoding/json"
     5  	"io/ioutil"
     6  	"net/http"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"strings"
    11  
    12  	"code.cloudfoundry.org/cli/integration/helpers"
    13  	"code.cloudfoundry.org/cli/util/configv3"
    14  	. "github.com/onsi/ginkgo"
    15  	. "github.com/onsi/gomega"
    16  	. "github.com/onsi/gomega/gbytes"
    17  	. "github.com/onsi/gomega/gexec"
    18  	"github.com/onsi/gomega/ghttp"
    19  )
    20  
    21  var _ = Describe("api command", func() {
    22  	Context("no arguments", func() {
    23  		When("the API is set", func() {
    24  			When("the user is not logged in", func() {
    25  				It("outputs the current API", func() {
    26  					session := helpers.CF("api")
    27  
    28  					Eventually(session).Should(Say(`API endpoint:\s+%s`, apiURL))
    29  					Eventually(session).Should(Say(`API version:\s+\d+\.\d+\.\d+`))
    30  					Eventually(session).Should(Exit(0))
    31  				})
    32  			})
    33  
    34  			When("the user is logged in", func() {
    35  				var target, apiVersion, org, space string
    36  
    37  				BeforeEach(func() {
    38  					target = "https://api.fake.com"
    39  					apiVersion = "3.81.0"
    40  					org = "the-org"
    41  					space = "the-space"
    42  
    43  					userConfig := configv3.Config{
    44  						ConfigFile: configv3.JSONConfig{
    45  							Target:      target,
    46  							APIVersion:  apiVersion,
    47  							AccessToken: "bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImxlZ2FjeS10b2tlbi1rZXkiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiI3YzZkMDA2MjA2OTI0NmViYWI0ZjBmZjY3NGQ3Zjk4OSIsInN1YiI6Ijk1MTliZTNlLTQ0ZDktNDBkMC1hYjlhLWY0YWNlMTFkZjE1OSIsInNjb3BlIjpbIm9wZW5pZCIsInJvdXRpbmcucm91dGVyX2dyb3Vwcy53cml0ZSIsInNjaW0ucmVhZCIsImNsb3VkX2NvbnRyb2xsZXIuYWRtaW4iLCJ1YWEudXNlciIsInJvdXRpbmcucm91dGVyX2dyb3Vwcy5yZWFkIiwiY2xvdWRfY29udHJvbGxlci5yZWFkIiwicGFzc3dvcmQud3JpdGUiLCJjbG91ZF9jb250cm9sbGVyLndyaXRlIiwiZG9wcGxlci5maXJlaG9zZSIsInNjaW0ud3JpdGUiXSwiY2xpZW50X2lkIjoiY2YiLCJjaWQiOiJjZiIsImF6cCI6ImNmIiwiZ3JhbnRfdHlwZSI6InBhc3N3b3JkIiwidXNlcl9pZCI6Ijk1MTliZTNlLTQ0ZDktNDBkMC1hYjlhLWY0YWNlMTFkZjE1OSIsIm9yaWdpbiI6InVhYSIsInVzZXJfbmFtZSI6ImFkbWluIiwiZW1haWwiOiJhZG1pbiIsImF1dGhfdGltZSI6MTQ3MzI4NDU3NywicmV2X3NpZyI6IjZiMjdkYTZjIiwiaWF0IjoxNDczMjg0NTc3LCJleHAiOjE0NzMyODUxNzcsImlzcyI6Imh0dHBzOi8vdWFhLmJvc2gtbGl0ZS5jb20vb2F1dGgvdG9rZW4iLCJ6aWQiOiJ1YWEiLCJhdWQiOlsiY2YiLCJvcGVuaWQiLCJyb3V0aW5nLnJvdXRlcl9ncm91cHMiLCJzY2ltIiwiY2xvdWRfY29udHJvbGxlciIsInVhYSIsInBhc3N3b3JkIiwiZG9wcGxlciJdfQ.OcH_w9yIKJkEcTZMThIs-qJAHk3G0JwNjG-aomVH9hKye4ciFO6IMQMLKmCBrrAQVc7ST1SZZwq7gv12Dq__6Jp-hai0a2_ADJK-Vc9YXyNZKgYTWIeVNGM1JGdHgFSrBR2Lz7IIrH9HqeN8plrKV5HzU8uI9LL4lyOCjbXJ9cM",
    48  							TargetedOrganization: configv3.Organization{
    49  								Name: org,
    50  							},
    51  							TargetedSpace: configv3.Space{
    52  								Name: space,
    53  							},
    54  							ConfigVersion: configv3.CurrentConfigVersion,
    55  						},
    56  					}
    57  					err := userConfig.WriteConfig()
    58  					Expect(err).ToNot(HaveOccurred())
    59  				})
    60  
    61  				It("outputs the user's target information", func() {
    62  					session := helpers.CF("api")
    63  					Eventually(session).Should(Say(`API endpoint:\s+%s`, target))
    64  					Eventually(session).Should(Say(`API version:\s+%s`, apiVersion))
    65  					Eventually(session).Should(Exit(0))
    66  				})
    67  			})
    68  		})
    69  
    70  		When("the API is not set", func() {
    71  			BeforeEach(func() {
    72  				os.RemoveAll(filepath.Join(homeDir, ".cf"))
    73  			})
    74  
    75  			It("outputs that nothing is set", func() {
    76  				session := helpers.CF("api")
    77  				Eventually(session).Should(Say("No API endpoint set. Use 'cf api' to set an endpoint"))
    78  				Eventually(session).Should(Exit(0))
    79  			})
    80  		})
    81  
    82  		Context("--unset is passed", func() {
    83  			BeforeEach(func() {
    84  
    85  				userConfig := configv3.Config{
    86  					ConfigFile: configv3.JSONConfig{
    87  						ConfigVersion: configv3.CurrentConfigVersion,
    88  						Target:        "https://api.fake.com",
    89  						APIVersion:    "3.81.0",
    90  						AccessToken:   "bearer tokenstuff",
    91  						TargetedOrganization: configv3.Organization{
    92  							Name: "the-org",
    93  						},
    94  						TargetedSpace: configv3.Space{
    95  							Name: "the-space",
    96  						},
    97  					},
    98  				}
    99  				err := userConfig.WriteConfig()
   100  				Expect(err).ToNot(HaveOccurred())
   101  			})
   102  
   103  			It("clears the targeted context", func() {
   104  				session := helpers.CF("api", "--unset")
   105  
   106  				Eventually(session).Should(Say("Unsetting API endpoint..."))
   107  				Eventually(session).Should(Say("OK"))
   108  				Eventually(session).Should(Exit(0))
   109  
   110  				rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json"))
   111  				Expect(err).NotTo(HaveOccurred())
   112  
   113  				var configFile configv3.JSONConfig
   114  				err = json.Unmarshal(rawConfig, &configFile)
   115  				Expect(err).NotTo(HaveOccurred())
   116  
   117  				Expect(configFile.ConfigVersion).To(Equal(configv3.CurrentConfigVersion))
   118  				Expect(configFile.Target).To(BeEmpty())
   119  				Expect(configFile.APIVersion).To(BeEmpty())
   120  				Expect(configFile.AuthorizationEndpoint).To(BeEmpty())
   121  				Expect(configFile.DopplerEndpoint).To(BeEmpty())
   122  				Expect(configFile.LogCacheEndpoint).To(BeEmpty())
   123  				Expect(configFile.UAAEndpoint).To(BeEmpty())
   124  				Expect(configFile.AccessToken).To(BeEmpty())
   125  				Expect(configFile.RefreshToken).To(BeEmpty())
   126  				Expect(configFile.TargetedOrganization.GUID).To(BeEmpty())
   127  				Expect(configFile.TargetedOrganization.Name).To(BeEmpty())
   128  				Expect(configFile.TargetedSpace.GUID).To(BeEmpty())
   129  				Expect(configFile.TargetedSpace.Name).To(BeEmpty())
   130  				Expect(configFile.TargetedSpace.AllowSSH).To(BeFalse())
   131  				Expect(configFile.SkipSSLValidation).To(BeFalse())
   132  			})
   133  		})
   134  	})
   135  
   136  	When("Skip SSL Validation is required", func() {
   137  		Context("API has SSL", func() {
   138  			var server *ghttp.Server
   139  
   140  			BeforeEach(func() {
   141  				cliVersion := "1.0.0"
   142  				server = helpers.StartMockServerWithMinimumCLIVersion(cliVersion)
   143  				apiURL = server.URL()
   144  			})
   145  
   146  			AfterEach(func() {
   147  				server.Close()
   148  			})
   149  
   150  			It("warns about skip SSL", func() {
   151  				session := helpers.CF("api", apiURL)
   152  				Eventually(session).Should(Say("Setting API endpoint to %s...", apiURL))
   153  				Eventually(session.Err).Should(Say("x509: certificate has expired or is not yet valid|SSL Certificate Error x509: certificate is valid for|Invalid SSL Cert for %s", apiURL))
   154  				Eventually(session.Err).Should(Say("TIP: Use 'cf api --skip-ssl-validation' to continue with an insecure API endpoint"))
   155  				Eventually(session).Should(Say("FAILED"))
   156  				Eventually(session).Should(Exit(1))
   157  			})
   158  
   159  			It("sets the API endpoint", func() {
   160  				session := helpers.CF("api", apiURL, "--skip-ssl-validation")
   161  				Eventually(session).Should(Say("Setting API endpoint to %s...", apiURL))
   162  				Eventually(session).Should(Say("OK"))
   163  				Eventually(session).Should(Say(`API endpoint:\s+%s`, apiURL))
   164  				Eventually(session).Should(Say(`API version:\s+\d+\.\d+\.\d+`))
   165  				Eventually(session).Should(Exit(0))
   166  			})
   167  		})
   168  
   169  		Context("API does not have SSL", func() {
   170  			var server *ghttp.Server
   171  
   172  			BeforeEach(func() {
   173  				server = ghttp.NewServer()
   174  				serverAPIURL := server.URL()[7:]
   175  
   176  				response := `{
   177     "links":{
   178        "self":{
   179           "href":"http://APISERVER"
   180        },
   181        "bits_service":null,
   182        "cloud_controller_v2":{
   183           "href":"http://APISERVER/v2",
   184           "meta":{
   185              "version":"2.146.0"
   186           }
   187        },
   188        "cloud_controller_v3":{
   189           "href":"http://APISERVER/v3",
   190           "meta":{
   191              "version":"3.81.0"
   192           }
   193        }
   194     }
   195  }`
   196  				response = strings.Replace(response, "APISERVER", serverAPIURL, -1)
   197  				server.AppendHandlers(
   198  					ghttp.CombineHandlers(
   199  						ghttp.VerifyRequest("GET", "/"),
   200  						ghttp.RespondWith(http.StatusOK, response),
   201  					),
   202  				)
   203  
   204  				response2 := `{
   205     "links":{
   206        "self":{
   207           "href":"http://APISERVER/v3"
   208        }
   209     }
   210  }`
   211  				response2 = strings.Replace(response2, "APISERVER", serverAPIURL, -1)
   212  				server.AppendHandlers(
   213  					ghttp.CombineHandlers(
   214  						ghttp.VerifyRequest("GET", "/v3"),
   215  						ghttp.RespondWith(http.StatusOK, response2),
   216  					),
   217  				)
   218  
   219  				server.AppendHandlers(
   220  					ghttp.CombineHandlers(
   221  						ghttp.VerifyRequest("GET", "/"),
   222  						ghttp.RespondWith(http.StatusOK, response),
   223  					),
   224  				)
   225  			})
   226  
   227  			AfterEach(func() {
   228  				server.Close()
   229  			})
   230  
   231  			It("falls back to http and gives a warning", func() {
   232  				session := helpers.CF("api", server.URL(), "--skip-ssl-validation")
   233  				Eventually(session).Should(Say("Setting API endpoint to %s...", server.URL()))
   234  				Eventually(session).Should(Say("Warning: Insecure http API endpoint detected: secure https API endpoints are recommended"))
   235  				Eventually(session).Should(Say("OK"))
   236  				Eventually(session).Should(Say("Not logged in. Use 'cf login' or 'cf login --sso' to log in."))
   237  				Eventually(session).Should(Exit(0))
   238  			})
   239  		})
   240  
   241  		It("sets SSL Disabled in the config file to true", func() {
   242  			command := exec.Command("cf", "api", apiURL, "--skip-ssl-validation")
   243  			session, err := Start(command, GinkgoWriter, GinkgoWriter)
   244  			Expect(err).NotTo(HaveOccurred())
   245  			Eventually(session).Should(Exit(0))
   246  
   247  			rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json"))
   248  			Expect(err).NotTo(HaveOccurred())
   249  
   250  			var configFile configv3.JSONConfig
   251  			err = json.Unmarshal(rawConfig, &configFile)
   252  			Expect(err).NotTo(HaveOccurred())
   253  
   254  			Expect(configFile.SkipSSLValidation).To(BeTrue())
   255  		})
   256  	})
   257  
   258  	When("skip-ssl-validation is not required", func() {
   259  		BeforeEach(func() {
   260  			if skipSSLValidation {
   261  				Skip("SKIP_SSL_VALIDATION is enabled")
   262  			}
   263  		})
   264  
   265  		It("logs in without any warnings", func() {
   266  			session := helpers.CF("api", apiURL)
   267  			Eventually(session).Should(Say("Setting API endpoint to %s...", apiURL))
   268  			Consistently(session).ShouldNot(Say("Warning: Insecure http API endpoint detected: secure https API endpoints are recommended"))
   269  			Eventually(session).Should(Say("OK"))
   270  			Eventually(session).Should(Say("Not logged in. Use 'cf login' or 'cf login --sso' to log in."))
   271  			Eventually(session).Should(Exit(0))
   272  		})
   273  
   274  		It("sets SSL Disabled in the config file to false", func() {
   275  			session := helpers.CF("api", apiURL)
   276  			Eventually(session).Should(Exit(0))
   277  
   278  			rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json"))
   279  			Expect(err).NotTo(HaveOccurred())
   280  
   281  			var configFile configv3.JSONConfig
   282  			err = json.Unmarshal(rawConfig, &configFile)
   283  			Expect(err).NotTo(HaveOccurred())
   284  
   285  			Expect(configFile.SkipSSLValidation).To(BeFalse())
   286  		})
   287  	})
   288  
   289  	When("the v3 API supports routing", func() {
   290  		It("sets the routing endpoint in the config file", func() {
   291  			var session *Session
   292  			if skipSSLValidation {
   293  				session = helpers.CF("api", apiURL, "--skip-ssl-validation")
   294  			} else {
   295  				session = helpers.CF("api", apiURL)
   296  			}
   297  
   298  			Eventually(session).Should(Exit(0))
   299  
   300  			rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json"))
   301  			Expect(err).NotTo(HaveOccurred())
   302  
   303  			var configFile configv3.JSONConfig
   304  			err = json.Unmarshal(rawConfig, &configFile)
   305  			Expect(err).NotTo(HaveOccurred())
   306  
   307  			Expect(configFile.RoutingEndpoint).NotTo(BeEmpty())
   308  		})
   309  	})
   310  
   311  	It("sets the config file", func() {
   312  		var session *Session
   313  		if skipSSLValidation {
   314  			session = helpers.CF("api", apiURL, "--skip-ssl-validation")
   315  		} else {
   316  			session = helpers.CF("api", apiURL)
   317  		}
   318  		Eventually(session).Should(Exit(0))
   319  
   320  		rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json"))
   321  		Expect(err).NotTo(HaveOccurred())
   322  
   323  		var configFile configv3.JSONConfig
   324  		err = json.Unmarshal(rawConfig, &configFile)
   325  		Expect(err).NotTo(HaveOccurred())
   326  
   327  		Expect(configFile.ConfigVersion).To(Equal(configv3.CurrentConfigVersion))
   328  		Expect(configFile.Target).To(Equal(apiURL))
   329  		Expect(configFile.APIVersion).To(MatchRegexp(`\d+\.\d+\.\d+`))
   330  		Expect(configFile.AuthorizationEndpoint).ToNot(BeEmpty())
   331  		Expect(configFile.DopplerEndpoint).To(MatchRegexp("^wss://"))
   332  		Expect(configFile.LogCacheEndpoint).To(MatchRegexp(".*log-cache.*"))
   333  		Expect(configFile.UAAEndpoint).To(BeEmpty())
   334  		Expect(configFile.AccessToken).To(BeEmpty())
   335  		Expect(configFile.RefreshToken).To(BeEmpty())
   336  		Expect(configFile.TargetedOrganization.GUID).To(BeEmpty())
   337  		Expect(configFile.TargetedOrganization.Name).To(BeEmpty())
   338  		Expect(configFile.TargetedSpace.GUID).To(BeEmpty())
   339  		Expect(configFile.TargetedSpace.Name).To(BeEmpty())
   340  		Expect(configFile.TargetedSpace.AllowSSH).To(BeFalse())
   341  	})
   342  
   343  	It("handles API endpoints with trailing slash", func() {
   344  		var session *Session
   345  
   346  		if skipSSLValidation {
   347  			session = helpers.CF("api", apiURL+"/", "--skip-ssl-validation")
   348  		} else {
   349  			session = helpers.CF("api", apiURL+"/")
   350  		}
   351  
   352  		Eventually(session).Should(Exit(0))
   353  
   354  		helpers.LoginCF()
   355  
   356  		session = helpers.CF("orgs")
   357  		Eventually(session).Should(Exit(0))
   358  	})
   359  })