github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/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 userConfig := configv3.Config{ 85 ConfigFile: configv3.JSONConfig{ 86 ConfigVersion: configv3.CurrentConfigVersion, 87 Target: "https://api.fake.com", 88 APIVersion: "3.81.0", 89 AccessToken: "bearer tokenstuff", 90 TargetedOrganization: configv3.Organization{ 91 Name: "the-org", 92 }, 93 TargetedSpace: configv3.Space{ 94 Name: "the-space", 95 }, 96 }, 97 } 98 err := userConfig.WriteConfig() 99 Expect(err).ToNot(HaveOccurred()) 100 }) 101 102 It("clears the targeted context", func() { 103 session := helpers.CF("api", "--unset") 104 105 Eventually(session).Should(Say("Unsetting API endpoint...")) 106 Eventually(session).Should(Say("OK")) 107 Eventually(session).Should(Exit(0)) 108 109 rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json")) 110 Expect(err).NotTo(HaveOccurred()) 111 112 var configFile configv3.JSONConfig 113 err = json.Unmarshal(rawConfig, &configFile) 114 Expect(err).NotTo(HaveOccurred()) 115 116 Expect(configFile.ConfigVersion).To(Equal(configv3.CurrentConfigVersion)) 117 Expect(configFile.Target).To(BeEmpty()) 118 Expect(configFile.APIVersion).To(BeEmpty()) 119 Expect(configFile.AuthorizationEndpoint).To(BeEmpty()) 120 Expect(configFile.DopplerEndpoint).To(BeEmpty()) 121 Expect(configFile.LogCacheEndpoint).To(BeEmpty()) 122 Expect(configFile.UAAEndpoint).To(BeEmpty()) 123 Expect(configFile.AccessToken).To(BeEmpty()) 124 Expect(configFile.RefreshToken).To(BeEmpty()) 125 Expect(configFile.TargetedOrganization.GUID).To(BeEmpty()) 126 Expect(configFile.TargetedOrganization.Name).To(BeEmpty()) 127 Expect(configFile.TargetedSpace.GUID).To(BeEmpty()) 128 Expect(configFile.TargetedSpace.Name).To(BeEmpty()) 129 Expect(configFile.TargetedSpace.AllowSSH).To(BeFalse()) 130 Expect(configFile.SkipSSLValidation).To(BeFalse()) 131 }) 132 }) 133 }) 134 135 When("Skip SSL Validation is required", func() { 136 Context("API has SSL", func() { 137 var server *ghttp.Server 138 139 BeforeEach(func() { 140 cliVersion := "1.0.0" 141 server = helpers.StartMockServerWithMinimumCLIVersion(cliVersion) 142 apiURL = server.URL() 143 }) 144 145 AfterEach(func() { 146 server.Close() 147 }) 148 149 It("warns about skip SSL", func() { 150 session := helpers.CF("api", apiURL) 151 Eventually(session).Should(Say("Setting API endpoint to %s...", apiURL)) 152 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)) 153 Eventually(session.Err).Should(Say("TIP: Use 'cf api --skip-ssl-validation' to continue with an insecure API endpoint")) 154 Eventually(session).Should(Say("FAILED")) 155 Eventually(session).Should(Exit(1)) 156 }) 157 158 It("sets the API endpoint", func() { 159 session := helpers.CF("api", apiURL, "--skip-ssl-validation") 160 Eventually(session).Should(Say("Setting API endpoint to %s...", apiURL)) 161 Eventually(session).Should(Say("OK")) 162 Eventually(session).Should(Say(`API endpoint:\s+%s`, apiURL)) 163 Eventually(session).Should(Say(`API version:\s+\d+\.\d+\.\d+`)) 164 Eventually(session).Should(Exit(0)) 165 }) 166 }) 167 168 Context("API does not have SSL", func() { 169 var server *ghttp.Server 170 171 BeforeEach(func() { 172 server = ghttp.NewServer() 173 serverAPIURL := server.URL()[7:] 174 175 response := `{ 176 "links":{ 177 "self":{ 178 "href":"http://APISERVER" 179 }, 180 "bits_service":null, 181 "cloud_controller_v2":{ 182 "href":"http://APISERVER/v2", 183 "meta":{ 184 "version":"2.146.0" 185 } 186 }, 187 "cloud_controller_v3":{ 188 "href":"http://APISERVER/v3", 189 "meta":{ 190 "version":"3.81.0" 191 } 192 } 193 } 194 }` 195 response = strings.Replace(response, "APISERVER", serverAPIURL, -1) 196 server.AppendHandlers( 197 ghttp.CombineHandlers( 198 ghttp.VerifyRequest("GET", "/"), 199 ghttp.RespondWith(http.StatusOK, response), 200 ), 201 ) 202 203 response2 := `{ 204 "links":{ 205 "self":{ 206 "href":"http://APISERVER/v3" 207 } 208 } 209 }` 210 response2 = strings.Replace(response2, "APISERVER", serverAPIURL, -1) 211 server.AppendHandlers( 212 ghttp.CombineHandlers( 213 ghttp.VerifyRequest("GET", "/v3"), 214 ghttp.RespondWith(http.StatusOK, response2), 215 ), 216 ) 217 218 server.AppendHandlers( 219 ghttp.CombineHandlers( 220 ghttp.VerifyRequest("GET", "/"), 221 ghttp.RespondWith(http.StatusOK, response), 222 ), 223 ) 224 }) 225 226 AfterEach(func() { 227 server.Close() 228 }) 229 230 It("falls back to http and gives a warning", func() { 231 session := helpers.CF("api", server.URL(), "--skip-ssl-validation") 232 Eventually(session).Should(Say("Setting API endpoint to %s...", server.URL())) 233 Eventually(session).Should(Say("Warning: Insecure http API endpoint detected: secure https API endpoints are recommended")) 234 Eventually(session).Should(Say("OK")) 235 Eventually(session).Should(Say("Not logged in. Use 'cf login' or 'cf login --sso' to log in.")) 236 Eventually(session).Should(Exit(0)) 237 }) 238 }) 239 240 It("sets SSL Disabled in the config file to true", func() { 241 command := exec.Command("cf", "api", apiURL, "--skip-ssl-validation") 242 session, err := Start(command, GinkgoWriter, GinkgoWriter) 243 Expect(err).NotTo(HaveOccurred()) 244 Eventually(session).Should(Exit(0)) 245 246 rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json")) 247 Expect(err).NotTo(HaveOccurred()) 248 249 var configFile configv3.JSONConfig 250 err = json.Unmarshal(rawConfig, &configFile) 251 Expect(err).NotTo(HaveOccurred()) 252 253 Expect(configFile.SkipSSLValidation).To(BeTrue()) 254 }) 255 }) 256 257 When("skip-ssl-validation is not required", func() { 258 BeforeEach(func() { 259 if skipSSLValidation { 260 Skip("SKIP_SSL_VALIDATION is enabled") 261 } 262 }) 263 264 It("logs in without any warnings", func() { 265 session := helpers.CF("api", apiURL) 266 Eventually(session).Should(Say("Setting API endpoint to %s...", apiURL)) 267 Consistently(session).ShouldNot(Say("Warning: Insecure http API endpoint detected: secure https API endpoints are recommended")) 268 Eventually(session).Should(Say("OK")) 269 Eventually(session).Should(Say("Not logged in. Use 'cf login' or 'cf login --sso' to log in.")) 270 Eventually(session).Should(Exit(0)) 271 }) 272 273 It("sets SSL Disabled in the config file to false", func() { 274 session := helpers.CF("api", apiURL) 275 Eventually(session).Should(Exit(0)) 276 277 rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json")) 278 Expect(err).NotTo(HaveOccurred()) 279 280 var configFile configv3.JSONConfig 281 err = json.Unmarshal(rawConfig, &configFile) 282 Expect(err).NotTo(HaveOccurred()) 283 284 Expect(configFile.SkipSSLValidation).To(BeFalse()) 285 }) 286 }) 287 288 When("the v3 API supports routing", func() { 289 It("sets the routing endpoint in 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 297 Eventually(session).Should(Exit(0)) 298 299 rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json")) 300 Expect(err).NotTo(HaveOccurred()) 301 302 var configFile configv3.JSONConfig 303 err = json.Unmarshal(rawConfig, &configFile) 304 Expect(err).NotTo(HaveOccurred()) 305 306 Expect(configFile.RoutingEndpoint).NotTo(BeEmpty()) 307 }) 308 }) 309 310 It("sets the config file", func() { 311 var session *Session 312 if skipSSLValidation { 313 session = helpers.CF("api", apiURL, "--skip-ssl-validation") 314 } else { 315 session = helpers.CF("api", apiURL) 316 } 317 Eventually(session).Should(Exit(0)) 318 319 rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json")) 320 Expect(err).NotTo(HaveOccurred()) 321 322 var configFile configv3.JSONConfig 323 err = json.Unmarshal(rawConfig, &configFile) 324 Expect(err).NotTo(HaveOccurred()) 325 326 Expect(configFile.ConfigVersion).To(Equal(configv3.CurrentConfigVersion)) 327 Expect(configFile.Target).To(Equal(apiURL)) 328 Expect(configFile.APIVersion).To(MatchRegexp(`\d+\.\d+\.\d+`)) 329 Expect(configFile.AuthorizationEndpoint).ToNot(BeEmpty()) 330 Expect(configFile.DopplerEndpoint).To(MatchRegexp("^wss://")) 331 Expect(configFile.LogCacheEndpoint).To(MatchRegexp(".*log-cache.*")) 332 Expect(configFile.UAAEndpoint).To(MatchRegexp(".*uaa.*")) 333 Expect(configFile.AccessToken).To(BeEmpty()) 334 Expect(configFile.RefreshToken).To(BeEmpty()) 335 Expect(configFile.TargetedOrganization.GUID).To(BeEmpty()) 336 Expect(configFile.TargetedOrganization.Name).To(BeEmpty()) 337 Expect(configFile.TargetedSpace.GUID).To(BeEmpty()) 338 Expect(configFile.TargetedSpace.Name).To(BeEmpty()) 339 Expect(configFile.TargetedSpace.AllowSSH).To(BeFalse()) 340 Expect(configFile.CFOnK8s).To(Equal(configv3.CFOnK8s{})) 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 })