github.com/sleungcy/cli@v7.1.0+incompatible/integration/v6/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 = "2.59.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: "2.59.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 targetted 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 "name":"", 178 "build":"", 179 "support":"http://support.cloudfoundry.com", 180 "version":0, 181 "description":"", 182 "authorization_endpoint":"https://login.APISERVER", 183 "min_cli_version":null, 184 "min_recommended_cli_version":null, 185 "api_version":"2.59.0", 186 "app_ssh_endpoint":"ssh.APISERVER", 187 "app_ssh_host_key_fingerprint":"a6:d1:08:0b:b0:cb:9b:5f:c4:ba:44:2a:97:26:19:8a", 188 "app_ssh_oauth_client":"ssh-proxy", 189 "logging_endpoint":"wss://loggregator.APISERVER", 190 "doppler_logging_endpoint":"wss://doppler.APISERVER" 191 }` 192 response = strings.Replace(response, "APISERVER", serverAPIURL, -1) 193 server.AppendHandlers( 194 ghttp.CombineHandlers( 195 ghttp.VerifyRequest("GET", "/v2/info"), 196 ghttp.RespondWith(http.StatusOK, response), 197 ), 198 ghttp.CombineHandlers( 199 ghttp.VerifyRequest(http.MethodGet, "/"), 200 ghttp.RespondWith(http.StatusOK, `{ "links": {"log_cache": {"href": "api.coolbeans.log-cache"}}}`), 201 ), 202 ) 203 }) 204 205 AfterEach(func() { 206 server.Close() 207 }) 208 209 It("falls back to http and gives a warning", func() { 210 session := helpers.CF("api", server.URL(), "--skip-ssl-validation") 211 Eventually(session).Should(Say("Setting api endpoint to %s...", server.URL())) 212 Eventually(session).Should(Say("Warning: Insecure http API endpoint detected: secure https API endpoints are recommended")) 213 Eventually(session).Should(Say("OK")) 214 Eventually(session).Should(Say("Not logged in. Use 'cf login' or 'cf login --sso' to log in.")) 215 Eventually(session).Should(Exit(0)) 216 }) 217 }) 218 219 It("sets SSL Disabled in the config file to true", func() { 220 command := exec.Command("cf", "api", apiURL, "--skip-ssl-validation") 221 session, err := Start(command, GinkgoWriter, GinkgoWriter) 222 Expect(err).NotTo(HaveOccurred()) 223 Eventually(session).Should(Exit(0)) 224 225 rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json")) 226 Expect(err).NotTo(HaveOccurred()) 227 228 var configFile configv3.JSONConfig 229 err = json.Unmarshal(rawConfig, &configFile) 230 Expect(err).NotTo(HaveOccurred()) 231 232 Expect(configFile.SkipSSLValidation).To(BeTrue()) 233 }) 234 }) 235 236 When("skip-ssl-validation is not required", func() { 237 BeforeEach(func() { 238 if skipSSLValidation { 239 Skip("SKIP_SSL_VALIDATION is enabled") 240 } 241 }) 242 243 It("logs in without any warnings", func() { 244 session := helpers.CF("api", apiURL) 245 Eventually(session).Should(Say("Setting api endpoint to %s...", apiURL)) 246 Consistently(session).ShouldNot(Say("Warning: Insecure http API endpoint detected: secure https API endpoints are recommended")) 247 Eventually(session).Should(Say("OK")) 248 Eventually(session).Should(Say("Not logged in. Use 'cf login' or 'cf login --sso' to log in.")) 249 Eventually(session).Should(Exit(0)) 250 }) 251 252 It("sets SSL Disabled in the config file to false", func() { 253 session := helpers.CF("api", apiURL) 254 Eventually(session).Should(Exit(0)) 255 256 rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json")) 257 Expect(err).NotTo(HaveOccurred()) 258 259 var configFile configv3.JSONConfig 260 err = json.Unmarshal(rawConfig, &configFile) 261 Expect(err).NotTo(HaveOccurred()) 262 263 Expect(configFile.SkipSSLValidation).To(BeFalse()) 264 }) 265 }) 266 267 When("the v3 api supports routing", func() { 268 It("sets the routing endpoing in the config file", func() { 269 var session *Session 270 if skipSSLValidation { 271 session = helpers.CF("api", apiURL, "--skip-ssl-validation") 272 } else { 273 session = helpers.CF("api", apiURL) 274 } 275 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.RoutingEndpoint).NotTo(BeEmpty()) 286 }) 287 }) 288 289 It("sets the config file", func() { 290 var session *Session 291 if skipSSLValidation { 292 session = helpers.CF("api", apiURL, "--skip-ssl-validation") 293 } else { 294 session = helpers.CF("api", apiURL) 295 } 296 Eventually(session).Should(Exit(0)) 297 298 rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json")) 299 Expect(err).NotTo(HaveOccurred()) 300 301 var configFile configv3.JSONConfig 302 err = json.Unmarshal(rawConfig, &configFile) 303 Expect(err).NotTo(HaveOccurred()) 304 305 Expect(configFile.ConfigVersion).To(Equal(configv3.CurrentConfigVersion)) 306 Expect(configFile.Target).To(Equal(apiURL)) 307 Expect(configFile.APIVersion).To(MatchRegexp(`\d+\.\d+\.\d+`)) 308 Expect(configFile.AuthorizationEndpoint).ToNot(BeEmpty()) 309 Expect(configFile.DopplerEndpoint).To(MatchRegexp("^wss://")) 310 Expect(configFile.LogCacheEndpoint).To(MatchRegexp(".*log-cache.*")) 311 Expect(configFile.UAAEndpoint).To(BeEmpty()) 312 Expect(configFile.AccessToken).To(BeEmpty()) 313 Expect(configFile.RefreshToken).To(BeEmpty()) 314 Expect(configFile.TargetedOrganization.GUID).To(BeEmpty()) 315 Expect(configFile.TargetedOrganization.Name).To(BeEmpty()) 316 Expect(configFile.TargetedSpace.GUID).To(BeEmpty()) 317 Expect(configFile.TargetedSpace.Name).To(BeEmpty()) 318 Expect(configFile.TargetedSpace.AllowSSH).To(BeFalse()) 319 }) 320 321 It("handles API endpoints with trailing slash", func() { 322 var session *Session 323 324 if skipSSLValidation { 325 session = helpers.CF("api", apiURL+"/", "--skip-ssl-validation") 326 } else { 327 session = helpers.CF("api", apiURL+"/") 328 } 329 330 Eventually(session).Should(Exit(0)) 331 332 helpers.LoginCF() 333 334 session = helpers.CF("orgs") 335 Eventually(session).Should(Exit(0)) 336 }) 337 })