blob: a61bb2c118a622e45865f371f902b3ac3469afab [file] [log] [blame]
Ash Wilsoncde68122014-08-28 16:15:43 -04001package tokens
2
3import (
4 "fmt"
5 "net/http"
6 "testing"
Ash Wilson46d913f2014-08-29 11:00:11 -04007 "time"
Ash Wilsoncde68122014-08-28 16:15:43 -04008
9 "github.com/rackspace/gophercloud"
10 "github.com/rackspace/gophercloud/testhelper"
11)
12
Ash Wilson417d9222014-08-29 07:58:35 -040013// authTokenPost verifies that providing certain AuthOptions and Scope results in an expected JSON structure.
14func authTokenPost(t *testing.T, options gophercloud.AuthOptions, scope *Scope, requestJSON string) {
Ash Wilson0ab4d612014-08-29 11:10:13 -040015 testhelper.SetupHTTP()
16 defer testhelper.TeardownHTTP()
Ash Wilsoncde68122014-08-28 16:15:43 -040017
Ash Wilson6425a412014-08-29 12:30:35 -040018 client := gophercloud.ServiceClient{
Ash Wilsond7f73e92014-10-22 09:11:49 -040019 ProviderClient: &gophercloud.ProviderClient{
Ash Wilson49f0f562014-09-03 08:58:20 -040020 TokenID: "12345abcdef",
Ash Wilson6425a412014-08-29 12:30:35 -040021 },
Ash Wilson0ab4d612014-08-29 11:10:13 -040022 Endpoint: testhelper.Endpoint(),
Ash Wilsoncde68122014-08-28 16:15:43 -040023 }
24
Ash Wilson0ab4d612014-08-29 11:10:13 -040025 testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
Ash Wilsoncde68122014-08-28 16:15:43 -040026 testhelper.TestMethod(t, r, "POST")
27 testhelper.TestHeader(t, r, "Content-Type", "application/json")
28 testhelper.TestHeader(t, r, "Accept", "application/json")
Ash Wilson417d9222014-08-29 07:58:35 -040029 testhelper.TestJSONRequest(t, r, requestJSON)
Ash Wilsoncde68122014-08-28 16:15:43 -040030
Ash Wilson4a52e2a2014-08-29 09:28:00 -040031 w.WriteHeader(http.StatusCreated)
Ash Wilson63b2a292014-10-02 09:29:06 -040032 fmt.Fprintf(w, `{
33 "token": {
34 "expires_at": "2014-10-02T13:45:00.000000Z"
35 }
36 }`)
Ash Wilsoncde68122014-08-28 16:15:43 -040037 })
38
Ash Wilson3f59ade2014-10-02 09:22:23 -040039 _, err := Create(&client, options, scope).Extract()
Ash Wilsoncde68122014-08-28 16:15:43 -040040 if err != nil {
41 t.Errorf("Create returned an error: %v", err)
42 }
43}
Ash Wilson417d9222014-08-29 07:58:35 -040044
Ash Wilsona8855ff2014-08-29 08:26:29 -040045func authTokenPostErr(t *testing.T, options gophercloud.AuthOptions, scope *Scope, includeToken bool, expectedErr error) {
Ash Wilson0ab4d612014-08-29 11:10:13 -040046 testhelper.SetupHTTP()
47 defer testhelper.TeardownHTTP()
Ash Wilsona8855ff2014-08-29 08:26:29 -040048
Ash Wilson6425a412014-08-29 12:30:35 -040049 client := gophercloud.ServiceClient{
Ash Wilsond7f73e92014-10-22 09:11:49 -040050 ProviderClient: &gophercloud.ProviderClient{},
51 Endpoint: testhelper.Endpoint(),
Ash Wilsona8855ff2014-08-29 08:26:29 -040052 }
53 if includeToken {
Ash Wilsond7f73e92014-10-22 09:11:49 -040054 client.TokenID = "abcdef123456"
Ash Wilsona8855ff2014-08-29 08:26:29 -040055 }
56
Ash Wilson3f59ade2014-10-02 09:22:23 -040057 _, err := Create(&client, options, scope).Extract()
Ash Wilsona8855ff2014-08-29 08:26:29 -040058 if err == nil {
59 t.Errorf("Create did NOT return an error")
60 }
61 if err != expectedErr {
62 t.Errorf("Create returned an unexpected error: wanted %v, got %v", expectedErr, err)
63 }
64}
65
Ash Wilson417d9222014-08-29 07:58:35 -040066func TestCreateUserIDAndPassword(t *testing.T) {
67 authTokenPost(t, gophercloud.AuthOptions{UserID: "me", Password: "squirrel!"}, nil, `
68 {
69 "auth": {
70 "identity": {
71 "methods": ["password"],
72 "password": {
73 "user": { "id": "me", "password": "squirrel!" }
74 }
75 }
76 }
77 }
78 `)
79}
80
81func TestCreateUsernameDomainIDPassword(t *testing.T) {
82 authTokenPost(t, gophercloud.AuthOptions{Username: "fakey", Password: "notpassword", DomainID: "abc123"}, nil, `
83 {
84 "auth": {
85 "identity": {
86 "methods": ["password"],
87 "password": {
88 "user": {
89 "domain": {
90 "id": "abc123"
91 },
92 "name": "fakey",
93 "password": "notpassword"
94 }
95 }
96 }
97 }
98 }
99 `)
100}
Ash Wilsond8da9e42014-08-29 08:01:06 -0400101
102func TestCreateUsernameDomainNamePassword(t *testing.T) {
103 authTokenPost(t, gophercloud.AuthOptions{Username: "frank", Password: "swordfish", DomainName: "spork.net"}, nil, `
104 {
105 "auth": {
106 "identity": {
107 "methods": ["password"],
108 "password": {
109 "user": {
110 "domain": {
111 "name": "spork.net"
112 },
113 "name": "frank",
114 "password": "swordfish"
115 }
116 }
117 }
118 }
119 }
120 `)
121}
Ash Wilson053fcb02014-08-29 08:04:35 -0400122
123func TestCreateTokenID(t *testing.T) {
124 authTokenPost(t, gophercloud.AuthOptions{}, nil, `
125 {
126 "auth": {
127 "identity": {
128 "methods": ["token"],
129 "token": {
130 "id": "12345abcdef"
131 }
132 }
133 }
134 }
135 `)
136}
Ash Wilson1fde6162014-08-29 08:13:06 -0400137
138func TestCreateProjectIDScope(t *testing.T) {
139 options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
140 scope := &Scope{ProjectID: "123456"}
141 authTokenPost(t, options, scope, `
142 {
143 "auth": {
144 "identity": {
145 "methods": ["password"],
146 "password": {
147 "user": {
148 "id": "fenris",
149 "password": "g0t0h311"
150 }
151 }
152 },
153 "scope": {
154 "project": {
155 "id": "123456"
156 }
157 }
158 }
159 }
160 `)
161}
162
163func TestCreateDomainIDScope(t *testing.T) {
164 options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
165 scope := &Scope{DomainID: "1000"}
166 authTokenPost(t, options, scope, `
167 {
168 "auth": {
169 "identity": {
170 "methods": ["password"],
171 "password": {
172 "user": {
173 "id": "fenris",
174 "password": "g0t0h311"
175 }
176 }
177 },
178 "scope": {
179 "domain": {
180 "id": "1000"
181 }
182 }
183 }
184 }
185 `)
186}
187
188func TestCreateProjectNameAndDomainIDScope(t *testing.T) {
189 options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
190 scope := &Scope{ProjectName: "world-domination", DomainID: "1000"}
191 authTokenPost(t, options, scope, `
192 {
193 "auth": {
194 "identity": {
195 "methods": ["password"],
196 "password": {
197 "user": {
198 "id": "fenris",
199 "password": "g0t0h311"
200 }
201 }
202 },
203 "scope": {
204 "project": {
205 "domain": {
206 "id": "1000"
207 },
208 "name": "world-domination"
209 }
210 }
211 }
212 }
213 `)
214}
215
216func TestCreateProjectNameAndDomainNameScope(t *testing.T) {
217 options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
218 scope := &Scope{ProjectName: "world-domination", DomainName: "evil-plans"}
219 authTokenPost(t, options, scope, `
220 {
221 "auth": {
222 "identity": {
223 "methods": ["password"],
224 "password": {
225 "user": {
226 "id": "fenris",
227 "password": "g0t0h311"
228 }
229 }
230 },
231 "scope": {
232 "project": {
233 "domain": {
234 "name": "evil-plans"
235 },
236 "name": "world-domination"
237 }
238 }
239 }
240 }
241 `)
242}
Ash Wilsona8855ff2014-08-29 08:26:29 -0400243
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400244func TestCreateExtractsTokenFromResponse(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400245 testhelper.SetupHTTP()
246 defer testhelper.TeardownHTTP()
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400247
Ash Wilson6425a412014-08-29 12:30:35 -0400248 client := gophercloud.ServiceClient{
Ash Wilsond7f73e92014-10-22 09:11:49 -0400249 ProviderClient: &gophercloud.ProviderClient{},
250 Endpoint: testhelper.Endpoint(),
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400251 }
252
Ash Wilson0ab4d612014-08-29 11:10:13 -0400253 testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400254 w.Header().Add("X-Subject-Token", "aaa111")
255
256 w.WriteHeader(http.StatusCreated)
Ash Wilson63b2a292014-10-02 09:29:06 -0400257 fmt.Fprintf(w, `{
258 "token": {
259 "expires_at": "2014-10-02T13:45:00.000000Z"
260 }
261 }`)
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400262 })
263
Ash Wilsona87ee062014-09-03 11:26:06 -0400264 options := gophercloud.AuthOptions{UserID: "me", Password: "shhh"}
Ash Wilson3f59ade2014-10-02 09:22:23 -0400265 token, err := Create(&client, options, nil).Extract()
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400266 if err != nil {
Ash Wilson63b2a292014-10-02 09:29:06 -0400267 t.Fatalf("Create returned an error: %v", err)
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400268 }
269
Ash Wilson3f59ade2014-10-02 09:22:23 -0400270 if token.ID != "aaa111" {
271 t.Errorf("Expected token to be aaa111, but was %s", token.ID)
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400272 }
273}
274
Ash Wilsona8855ff2014-08-29 08:26:29 -0400275func TestCreateFailureEmptyAuth(t *testing.T) {
276 authTokenPostErr(t, gophercloud.AuthOptions{}, nil, false, ErrMissingPassword)
277}
278
279func TestCreateFailureAPIKey(t *testing.T) {
280 authTokenPostErr(t, gophercloud.AuthOptions{APIKey: "something"}, nil, false, ErrAPIKeyProvided)
281}
282
283func TestCreateFailureTenantID(t *testing.T) {
284 authTokenPostErr(t, gophercloud.AuthOptions{TenantID: "something"}, nil, false, ErrTenantIDProvided)
285}
286
287func TestCreateFailureTenantName(t *testing.T) {
288 authTokenPostErr(t, gophercloud.AuthOptions{TenantName: "something"}, nil, false, ErrTenantNameProvided)
289}
290
291func TestCreateFailureTokenIDUsername(t *testing.T) {
292 authTokenPostErr(t, gophercloud.AuthOptions{Username: "something"}, nil, true, ErrUsernameWithToken)
293}
294
295func TestCreateFailureTokenIDUserID(t *testing.T) {
296 authTokenPostErr(t, gophercloud.AuthOptions{UserID: "something"}, nil, true, ErrUserIDWithToken)
297}
298
299func TestCreateFailureTokenIDDomainID(t *testing.T) {
300 authTokenPostErr(t, gophercloud.AuthOptions{DomainID: "something"}, nil, true, ErrDomainIDWithToken)
301}
302
303func TestCreateFailureTokenIDDomainName(t *testing.T) {
304 authTokenPostErr(t, gophercloud.AuthOptions{DomainName: "something"}, nil, true, ErrDomainNameWithToken)
305}
Ash Wilsonaed3db42014-08-29 08:59:56 -0400306
307func TestCreateFailureMissingUser(t *testing.T) {
308 options := gophercloud.AuthOptions{Password: "supersecure"}
309 authTokenPostErr(t, options, nil, false, ErrUsernameOrUserID)
310}
311
312func TestCreateFailureBothUser(t *testing.T) {
313 options := gophercloud.AuthOptions{
314 Password: "supersecure",
315 Username: "oops",
316 UserID: "redundancy",
317 }
318 authTokenPostErr(t, options, nil, false, ErrUsernameOrUserID)
319}
320
321func TestCreateFailureMissingDomain(t *testing.T) {
322 options := gophercloud.AuthOptions{
323 Password: "supersecure",
324 Username: "notuniqueenough",
325 }
326 authTokenPostErr(t, options, nil, false, ErrDomainIDOrDomainName)
327}
328
329func TestCreateFailureBothDomain(t *testing.T) {
330 options := gophercloud.AuthOptions{
331 Password: "supersecure",
332 Username: "someone",
333 DomainID: "hurf",
334 DomainName: "durf",
335 }
336 authTokenPostErr(t, options, nil, false, ErrDomainIDOrDomainName)
337}
338
339func TestCreateFailureUserIDDomainID(t *testing.T) {
340 options := gophercloud.AuthOptions{
341 UserID: "100",
342 Password: "stuff",
343 DomainID: "oops",
344 }
345 authTokenPostErr(t, options, nil, false, ErrDomainIDWithUserID)
346}
347
348func TestCreateFailureUserIDDomainName(t *testing.T) {
349 options := gophercloud.AuthOptions{
350 UserID: "100",
351 Password: "sssh",
352 DomainName: "oops",
353 }
354 authTokenPostErr(t, options, nil, false, ErrDomainNameWithUserID)
355}
356
357func TestCreateFailureScopeProjectNameAlone(t *testing.T) {
358 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
359 scope := &Scope{ProjectName: "notenough"}
360 authTokenPostErr(t, options, scope, false, ErrScopeDomainIDOrDomainName)
361}
362
363func TestCreateFailureScopeProjectNameAndID(t *testing.T) {
364 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
365 scope := &Scope{ProjectName: "whoops", ProjectID: "toomuch", DomainID: "1234"}
366 authTokenPostErr(t, options, scope, false, ErrScopeProjectIDOrProjectName)
367}
368
369func TestCreateFailureScopeProjectIDAndDomainID(t *testing.T) {
370 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
371 scope := &Scope{ProjectID: "toomuch", DomainID: "notneeded"}
372 authTokenPostErr(t, options, scope, false, ErrScopeProjectIDAlone)
373}
374
375func TestCreateFailureScopeProjectIDAndDomainNAme(t *testing.T) {
376 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
377 scope := &Scope{ProjectID: "toomuch", DomainName: "notneeded"}
378 authTokenPostErr(t, options, scope, false, ErrScopeProjectIDAlone)
379}
380
381func TestCreateFailureScopeDomainIDAndDomainName(t *testing.T) {
382 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
383 scope := &Scope{DomainID: "toomuch", DomainName: "notneeded"}
384 authTokenPostErr(t, options, scope, false, ErrScopeDomainIDOrDomainName)
385}
386
387func TestCreateFailureScopeDomainNameAlone(t *testing.T) {
388 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
389 scope := &Scope{DomainName: "notenough"}
390 authTokenPostErr(t, options, scope, false, ErrScopeDomainName)
391}
392
393func TestCreateFailureEmptyScope(t *testing.T) {
394 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
395 scope := &Scope{}
396 authTokenPostErr(t, options, scope, false, ErrScopeEmpty)
397}
Ash Wilson46d913f2014-08-29 11:00:11 -0400398
Ash Wilson5266e492014-09-09 15:44:30 -0400399func TestGetRequest(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400400 testhelper.SetupHTTP()
401 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400402
Ash Wilson6425a412014-08-29 12:30:35 -0400403 client := gophercloud.ServiceClient{
Ash Wilsond7f73e92014-10-22 09:11:49 -0400404 ProviderClient: &gophercloud.ProviderClient{
Ash Wilson6425a412014-08-29 12:30:35 -0400405 TokenID: "12345abcdef",
406 },
Ash Wilson0ab4d612014-08-29 11:10:13 -0400407 Endpoint: testhelper.Endpoint(),
Ash Wilson46d913f2014-08-29 11:00:11 -0400408 }
409
Ash Wilson0ab4d612014-08-29 11:10:13 -0400410 testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson46d913f2014-08-29 11:00:11 -0400411 testhelper.TestMethod(t, r, "GET")
Jon Perrittd8aef1b2014-09-11 17:50:04 -0500412 testhelper.TestHeader(t, r, "Content-Type", "")
Ash Wilson46d913f2014-08-29 11:00:11 -0400413 testhelper.TestHeader(t, r, "Accept", "application/json")
414 testhelper.TestHeader(t, r, "X-Auth-Token", "12345abcdef")
415 testhelper.TestHeader(t, r, "X-Subject-Token", "abcdef12345")
416
417 w.WriteHeader(http.StatusOK)
418 fmt.Fprintf(w, `
419 { "token": { "expires_at": "2014-08-29T13:10:01.000000Z" } }
420 `)
421 })
422
Ash Wilson3f59ade2014-10-02 09:22:23 -0400423 token, err := Get(&client, "abcdef12345").Extract()
Ash Wilson46d913f2014-08-29 11:00:11 -0400424 if err != nil {
425 t.Errorf("Info returned an error: %v", err)
426 }
427
Ash Wilson46d913f2014-08-29 11:00:11 -0400428 expected, _ := time.Parse(time.UnixDate, "Fri Aug 29 13:10:01 UTC 2014")
Ash Wilson3f59ade2014-10-02 09:22:23 -0400429 if token.ExpiresAt != expected {
430 t.Errorf("Expected expiration time %s, but was %s", expected.Format(time.UnixDate), token.ExpiresAt.Format(time.UnixDate))
Ash Wilson46d913f2014-08-29 11:00:11 -0400431 }
432}
433
Ash Wilson6425a412014-08-29 12:30:35 -0400434func prepareAuthTokenHandler(t *testing.T, expectedMethod string, status int) gophercloud.ServiceClient {
435 client := gophercloud.ServiceClient{
Ash Wilsond7f73e92014-10-22 09:11:49 -0400436 ProviderClient: &gophercloud.ProviderClient{
Ash Wilson6425a412014-08-29 12:30:35 -0400437 TokenID: "12345abcdef",
438 },
Ash Wilson0ab4d612014-08-29 11:10:13 -0400439 Endpoint: testhelper.Endpoint(),
Ash Wilson46d913f2014-08-29 11:00:11 -0400440 }
441
Ash Wilson0ab4d612014-08-29 11:10:13 -0400442 testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson46d913f2014-08-29 11:00:11 -0400443 testhelper.TestMethod(t, r, expectedMethod)
Jon Perrittd8aef1b2014-09-11 17:50:04 -0500444 testhelper.TestHeader(t, r, "Content-Type", "")
Ash Wilson46d913f2014-08-29 11:00:11 -0400445 testhelper.TestHeader(t, r, "Accept", "application/json")
446 testhelper.TestHeader(t, r, "X-Auth-Token", "12345abcdef")
447 testhelper.TestHeader(t, r, "X-Subject-Token", "abcdef12345")
448
449 w.WriteHeader(status)
450 })
451
452 return client
453}
454
455func TestValidateRequestSuccessful(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400456 testhelper.SetupHTTP()
457 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400458 client := prepareAuthTokenHandler(t, "HEAD", http.StatusNoContent)
459
460 ok, err := Validate(&client, "abcdef12345")
461 if err != nil {
462 t.Errorf("Unexpected error from Validate: %v", err)
463 }
464
465 if !ok {
466 t.Errorf("Validate returned false for a valid token")
467 }
468}
469
470func TestValidateRequestFailure(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400471 testhelper.SetupHTTP()
472 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400473 client := prepareAuthTokenHandler(t, "HEAD", http.StatusNotFound)
474
475 ok, err := Validate(&client, "abcdef12345")
476 if err != nil {
477 t.Errorf("Unexpected error from Validate: %v", err)
478 }
479
480 if ok {
481 t.Errorf("Validate returned true for an invalid token")
482 }
483}
484
485func TestValidateRequestError(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400486 testhelper.SetupHTTP()
487 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400488 client := prepareAuthTokenHandler(t, "HEAD", http.StatusUnauthorized)
489
490 _, err := Validate(&client, "abcdef12345")
491 if err == nil {
492 t.Errorf("Missing expected error from Validate")
493 }
494}
495
496func TestRevokeRequestSuccessful(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400497 testhelper.SetupHTTP()
498 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400499 client := prepareAuthTokenHandler(t, "DELETE", http.StatusNoContent)
500
501 err := Revoke(&client, "abcdef12345")
502 if err != nil {
503 t.Errorf("Unexpected error from Revoke: %v", err)
504 }
505}
506
507func TestRevokeRequestError(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400508 testhelper.SetupHTTP()
509 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400510 client := prepareAuthTokenHandler(t, "DELETE", http.StatusNotFound)
511
512 err := Revoke(&client, "abcdef12345")
513 if err == nil {
514 t.Errorf("Missing expected error from Revoke")
515 }
516}