github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/integration/v7/isolated/auth_command_test.go (about) 1 package isolated 2 3 import ( 4 "encoding/json" 5 "io/ioutil" 6 "path/filepath" 7 8 "code.cloudfoundry.org/cli/api/uaa/uaaversion" 9 "code.cloudfoundry.org/cli/integration/helpers" 10 "code.cloudfoundry.org/cli/util/configv3" 11 . "github.com/onsi/ginkgo" 12 . "github.com/onsi/gomega" 13 . "github.com/onsi/gomega/gbytes" 14 . "github.com/onsi/gomega/gexec" 15 ) 16 17 var _ = Describe("auth command", func() { 18 BeforeEach(func() { 19 helpers.SkipIfClientCredentialsTestMode() 20 }) 21 22 Context("Help", func() { 23 It("displays the help information", func() { 24 session := helpers.CF("auth", "--help") 25 Eventually(session).Should(Say("NAME:")) 26 Eventually(session).Should(Say("auth - Authenticate non-interactively\n\n")) 27 28 Eventually(session).Should(Say("USAGE:")) 29 Eventually(session).Should(Say("cf auth USERNAME PASSWORD\n")) 30 Eventually(session).Should(Say("cf auth CLIENT_ID CLIENT_SECRET --client-credentials\n\n")) 31 32 Eventually(session).Should(Say("ENVIRONMENT VARIABLES:")) 33 Eventually(session).Should(Say(`CF_USERNAME=user\s+Authenticating user. Overridden if USERNAME argument is provided.`)) 34 Eventually(session).Should(Say(`CF_PASSWORD=password\s+Password associated with user. Overridden if PASSWORD argument is provided.`)) 35 36 Eventually(session).Should(Say("WARNING:")) 37 Eventually(session).Should(Say("Providing your password as a command line option is highly discouraged")) 38 Eventually(session).Should(Say("Your password may be visible to others and may be recorded in your shell history\n")) 39 Eventually(session).Should(Say("Consider using the CF_PASSWORD environment variable instead\n\n")) 40 41 Eventually(session).Should(Say("EXAMPLES:")) 42 Eventually(session).Should(Say("cf auth name@example\\.com \"my password\" \\(use quotes for passwords with a space\\)")) 43 Eventually(session).Should(Say("cf auth name@example\\.com \\\"\\\\\"password\\\\\"\\\" \\(escape quotes if used in password\\)\n\n")) 44 45 Eventually(session).Should(Say("OPTIONS:")) 46 Eventually(session).Should(Say("--client-credentials\\s+Use \\(non-user\\) service account \\(also called client credentials\\)\n")) 47 Eventually(session).Should(Say("--origin\\s+Indicates the identity provider to be used for authentication\n\n")) 48 49 Eventually(session).Should(Say("SEE ALSO:")) 50 Eventually(session).Should(Say("api, login, target")) 51 52 Eventually(session).Should(Exit(0)) 53 }) 54 }) 55 56 When("no positional arguments are provided", func() { 57 Context("and no env variables are provided", func() { 58 It("errors-out with the help information", func() { 59 envWithoutLoginInfo := map[string]string{ 60 "CF_USERNAME": "", 61 "CF_PASSWORD": "", 62 } 63 session := helpers.CFWithEnv(envWithoutLoginInfo, "auth") 64 Eventually(session.Err).Should(Say("Username and password not provided.")) 65 Eventually(session).Should(Say("NAME:")) 66 67 Eventually(session).Should(Exit(1)) 68 }) 69 }) 70 71 When("env variables are provided", func() { 72 It("authenticates the user", func() { 73 username, password := helpers.GetCredentials() 74 env := map[string]string{ 75 "CF_USERNAME": username, 76 "CF_PASSWORD": password, 77 } 78 session := helpers.CFWithEnv(env, "auth") 79 80 Eventually(session).Should(Say("API endpoint: %s", helpers.GetAPI())) 81 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 82 Eventually(session).Should(Say("OK")) 83 Eventually(session).Should(Say("Use 'cf target' to view or set your target org and space")) 84 85 Eventually(session).Should(Exit(0)) 86 }) 87 }) 88 }) 89 90 When("only a username is provided", func() { 91 It("errors-out with a password required error and the help information", func() { 92 envWithoutLoginInfo := map[string]string{ 93 "CF_USERNAME": "", 94 "CF_PASSWORD": "", 95 } 96 session := helpers.CFWithEnv(envWithoutLoginInfo, "auth", "some-user") 97 Eventually(session.Err).Should(Say("Password not provided.")) 98 Eventually(session).Should(Say("NAME:")) 99 100 Eventually(session).Should(Exit(1)) 101 }) 102 }) 103 104 When("only a password is provided", func() { 105 It("errors-out with a username required error and the help information", func() { 106 env := map[string]string{ 107 "CF_USERNAME": "", 108 "CF_PASSWORD": "some-pass", 109 } 110 session := helpers.CFWithEnv(env, "auth") 111 Eventually(session.Err).Should(Say("Username not provided.")) 112 Eventually(session).Should(Say("NAME:")) 113 114 Eventually(session).Should(Exit(1)) 115 }) 116 }) 117 118 When("extra input is given", func() { 119 It("displays an 'unknown flag' error message", func() { 120 session := helpers.CF("auth", "some-username", "some-password", "-a", "api.bosh-lite.com") 121 122 Eventually(session.Err).Should(Say("Incorrect Usage: unknown flag `a'")) 123 Eventually(session).Should(Say("NAME:")) 124 125 Eventually(session).Should(Exit(1)) 126 }) 127 }) 128 129 When("the API endpoint is not set", func() { 130 BeforeEach(func() { 131 helpers.UnsetAPI() 132 }) 133 134 It("displays an error message", func() { 135 session := helpers.CF("auth", "some-username", "some-password") 136 137 Eventually(session).Should(Say("FAILED")) 138 Eventually(session.Err).Should(Say(`No API endpoint set\. Use 'cf login' or 'cf api' to target an endpoint\.`)) 139 140 Eventually(session).Should(Exit(1)) 141 }) 142 }) 143 144 When("no flags are set (logging in with password grant type)", func() { 145 When("the user provides an invalid username/password combo", func() { 146 BeforeEach(func() { 147 helpers.LoginCF() 148 helpers.TargetOrgAndSpace(ReadOnlyOrg, ReadOnlySpace) 149 }) 150 151 It("clears the cached tokens and target info, then displays an error message", func() { 152 session := helpers.CF("auth", "some-username", "some-password") 153 154 Eventually(session).Should(Say("API endpoint: %s", helpers.GetAPI())) 155 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 156 Eventually(session).Should(Say("FAILED")) 157 Eventually(session.Err).Should(Say(`Credentials were rejected, please try again\.`)) 158 Eventually(session).Should(Exit(1)) 159 160 // Verify that the user is not logged-in 161 targetSession1 := helpers.CF("target") 162 Eventually(targetSession1.Err).Should(Say(`Not logged in\. Use 'cf login' or 'cf login --sso' to log in\.`)) 163 Eventually(targetSession1).Should(Say("FAILED")) 164 Eventually(targetSession1).Should(Exit(1)) 165 166 // Verify that neither org nor space is targeted 167 helpers.LoginCF() 168 targetSession2 := helpers.CF("target") 169 Eventually(targetSession2).Should(Say("No org or space targeted, use 'cf target -o ORG -s SPACE'")) 170 Eventually(targetSession2).Should(Exit(0)) 171 }) 172 }) 173 174 When("the username and password are valid", func() { 175 It("authenticates the user", func() { 176 username, password := helpers.GetCredentials() 177 session := helpers.CF("auth", username, password) 178 179 Eventually(session).Should(Say("API endpoint: %s", helpers.GetAPI())) 180 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 181 Eventually(session).Should(Say("OK")) 182 Eventually(session).Should(Say("Use 'cf target' to view or set your target org and space")) 183 184 Eventually(session).Should(Exit(0)) 185 }) 186 }) 187 }) 188 189 When("the 'client-credentials' flag is set", func() { 190 When("the user provides an invalid client id/secret combo", func() { 191 BeforeEach(func() { 192 helpers.LoginCF() 193 helpers.TargetOrgAndSpace(ReadOnlyOrg, ReadOnlySpace) 194 }) 195 196 It("clears the cached tokens and target info, then displays an error message", func() { 197 session := helpers.CF("auth", "some-client-id", "some-client-secret", "--client-credentials") 198 199 Eventually(session).Should(Say("API endpoint: %s", helpers.GetAPI())) 200 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 201 Eventually(session).Should(Say("FAILED")) 202 Eventually(session.Err).Should(Say(`Credentials were rejected, please try again\.`)) 203 Eventually(session).Should(Exit(1)) 204 205 // Verify that the user is not logged-in 206 targetSession1 := helpers.CF("target") 207 Eventually(targetSession1.Err).Should(Say(`Not logged in\. Use 'cf login' or 'cf login --sso' to log in\.`)) 208 Eventually(targetSession1).Should(Say("FAILED")) 209 Eventually(targetSession1).Should(Exit(1)) 210 211 // Verify that neither org nor space is targeted 212 helpers.LoginCF() 213 targetSession2 := helpers.CF("target") 214 Eventually(targetSession2).Should(Say("No org or space targeted, use 'cf target -o ORG -s SPACE'")) 215 Eventually(targetSession2).Should(Exit(0)) 216 }) 217 }) 218 219 When("the client id and client secret are valid", func() { 220 It("authenticates the user", func() { 221 clientID, clientSecret := helpers.SkipIfClientCredentialsNotSet() 222 session := helpers.CF("auth", clientID, clientSecret, "--client-credentials") 223 224 Eventually(session).Should(Say("API endpoint: %s", helpers.GetAPI())) 225 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 226 Eventually(session).Should(Say("OK")) 227 Eventually(session).Should(Say("Use 'cf target' to view or set your target org and space")) 228 229 Eventually(session).Should(Exit(0)) 230 }) 231 232 It("writes the client id but does not write the client secret to the config file", func() { 233 clientID, clientSecret := helpers.SkipIfClientCredentialsNotSet() 234 session := helpers.CF("auth", clientID, clientSecret, "--client-credentials") 235 Eventually(session).Should(Exit(0)) 236 237 rawConfig, err := ioutil.ReadFile(filepath.Join(homeDir, ".cf", "config.json")) 238 Expect(err).NotTo(HaveOccurred()) 239 240 Expect(string(rawConfig)).ToNot(ContainSubstring(clientSecret)) 241 242 var configFile configv3.JSONConfig 243 err = json.Unmarshal(rawConfig, &configFile) 244 245 Expect(err).NotTo(HaveOccurred()) 246 Expect(configFile.UAAOAuthClient).To(Equal(clientID)) 247 Expect(configFile.UAAOAuthClientSecret).To(BeEmpty()) 248 Expect(configFile.UAAGrantType).To(Equal("client_credentials")) 249 }) 250 }) 251 }) 252 253 When("a user authenticates with valid client credentials", func() { 254 BeforeEach(func() { 255 clientID, clientSecret := helpers.SkipIfClientCredentialsNotSet() 256 session := helpers.CF("auth", clientID, clientSecret, "--client-credentials") 257 Eventually(session).Should(Exit(0)) 258 }) 259 260 When("a different user authenticates with valid password credentials", func() { 261 It("should fail authentication and display an error informing the user they need to log out", func() { 262 username, password := helpers.GetCredentials() 263 session := helpers.CF("auth", username, password) 264 265 Eventually(session).Should(Say("FAILED")) 266 Eventually(session.Err).Should(Say(`Service account currently logged in\. Use 'cf logout' to log out service account and try again\.`)) 267 Eventually(session).Should(Exit(1)) 268 }) 269 }) 270 271 }) 272 273 When("the origin flag is set", func() { 274 When("the UAA version is too low to use the --origin flag", func() { 275 BeforeEach(func() { 276 helpers.SkipIfUAAVersionAtLeast(uaaversion.MinUAAClientVersion) 277 }) 278 It("prints an error message", func() { 279 session := helpers.CF("auth", "some-username", "some-password", "--client-credentials", "--origin", "garbage") 280 Eventually(session.Err).Should(Say("Option '--origin' requires UAA API version 4.19.0 or higher. Update your Cloud Foundry instance.")) 281 Eventually(session).Should(Say("FAILED")) 282 Eventually(session).Should(Exit(1)) 283 }) 284 }) 285 286 When("the UAA version is recent enough to support the flag", func() { 287 BeforeEach(func() { 288 helpers.SkipIfUAAVersionLessThan(uaaversion.MinUAAClientVersion) 289 }) 290 When("--client-credentials is also set", func() { 291 It("displays the appropriate error message", func() { 292 session := helpers.CF("auth", "some-username", "some-password", "--client-credentials", "--origin", "garbage") 293 294 Eventually(session.Err).Should(Say("Incorrect Usage: The following arguments cannot be used together: --client-credentials, --origin")) 295 Eventually(session).Should(Exit(1)) 296 }) 297 }) 298 299 When("a user authenticates with valid user credentials for that origin", func() { 300 var ( 301 username string 302 password string 303 ) 304 305 BeforeEach(func() { 306 username, password = helpers.SkipIfOIDCCredentialsNotSet() 307 }) 308 309 It("authenticates the user", func() { 310 session := helpers.CF("auth", username, password, "--origin", "cli-oidc-provider") 311 312 Eventually(session).Should(Say("API endpoint: %s", helpers.GetAPI())) 313 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 314 Eventually(session).Should(Say("OK")) 315 Eventually(session).Should(Say("Use 'cf target' to view or set your target org and space")) 316 Eventually(session).Should(Exit(0)) 317 }) 318 }) 319 320 When("the user provides the default origin and valid credentials", func() { 321 It("authenticates the user", func() { 322 username, password := helpers.GetCredentials() 323 session := helpers.CF("auth", username, password, "--origin", "uaa") 324 325 Eventually(session).Should(Say("API endpoint: %s", helpers.GetAPI())) 326 Eventually(session).Should(Say(`Authenticating\.\.\.`)) 327 Eventually(session).Should(Say("OK")) 328 Eventually(session).Should(Say("Use 'cf target' to view or set your target org and space")) 329 Eventually(session).Should(Exit(0)) 330 }) 331 }) 332 333 When("when the user provides an invalid origin", func() { 334 It("returns an error", func() { 335 session := helpers.CF("auth", "some-user", "some-password", "--origin", "EA") 336 Eventually(session.Err).Should(Say("The origin provided is invalid.")) 337 Eventually(session).Should(Say("FAILED")) 338 Eventually(session).Should(Exit(1)) 339 }) 340 }) 341 }) 342 }) 343 344 Describe("Authenticating as a user, through a custom client", func() { 345 var ( 346 session *Session 347 ) 348 349 BeforeEach(func() { 350 customClientID, customClientSecret := helpers.SkipIfCustomClientCredentialsNotSet() 351 352 helpers.LoginCF() 353 354 helpers.SetConfig(func(config *configv3.Config) { 355 config.ConfigFile.UAAOAuthClient = customClientID 356 config.ConfigFile.UAAOAuthClientSecret = customClientSecret 357 config.ConfigFile.UAAGrantType = "" 358 }) 359 }) 360 361 It("fails and shows a helpful message", func() { 362 username, password := helpers.CreateUser() 363 364 session = helpers.CF("auth", username, password) 365 366 Eventually(session).Should(Exit(1)) 367 Eventually(session.Err).Should(Say("Error: Support for manually writing your client credentials to config.json has been removed. For similar functionality please use `cf auth --client-credentials`.")) 368 }) 369 }) 370 })