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