blob: 49b60a469e305a5b50494835d099b5560212c12c [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 Wilsona87ee062014-09-03 11:26:06 -040019 Provider: &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 Wilsoncde68122014-08-28 16:15:43 -040032 fmt.Fprintf(w, `{}`)
33 })
34
Ash Wilson3f59ade2014-10-02 09:22:23 -040035 _, err := Create(&client, options, scope).Extract()
Ash Wilsoncde68122014-08-28 16:15:43 -040036 if err != nil {
37 t.Errorf("Create returned an error: %v", err)
38 }
39}
Ash Wilson417d9222014-08-29 07:58:35 -040040
Ash Wilsona8855ff2014-08-29 08:26:29 -040041func authTokenPostErr(t *testing.T, options gophercloud.AuthOptions, scope *Scope, includeToken bool, expectedErr error) {
Ash Wilson0ab4d612014-08-29 11:10:13 -040042 testhelper.SetupHTTP()
43 defer testhelper.TeardownHTTP()
Ash Wilsona8855ff2014-08-29 08:26:29 -040044
Ash Wilson6425a412014-08-29 12:30:35 -040045 client := gophercloud.ServiceClient{
Ash Wilsona87ee062014-09-03 11:26:06 -040046 Provider: &gophercloud.ProviderClient{},
Ash Wilson0ab4d612014-08-29 11:10:13 -040047 Endpoint: testhelper.Endpoint(),
Ash Wilsona8855ff2014-08-29 08:26:29 -040048 }
49 if includeToken {
Ash Wilsona87ee062014-09-03 11:26:06 -040050 client.Provider.TokenID = "abcdef123456"
Ash Wilsona8855ff2014-08-29 08:26:29 -040051 }
52
Ash Wilson3f59ade2014-10-02 09:22:23 -040053 _, err := Create(&client, options, scope).Extract()
Ash Wilsona8855ff2014-08-29 08:26:29 -040054 if err == nil {
55 t.Errorf("Create did NOT return an error")
56 }
57 if err != expectedErr {
58 t.Errorf("Create returned an unexpected error: wanted %v, got %v", expectedErr, err)
59 }
60}
61
Ash Wilson417d9222014-08-29 07:58:35 -040062func TestCreateUserIDAndPassword(t *testing.T) {
63 authTokenPost(t, gophercloud.AuthOptions{UserID: "me", Password: "squirrel!"}, nil, `
64 {
65 "auth": {
66 "identity": {
67 "methods": ["password"],
68 "password": {
69 "user": { "id": "me", "password": "squirrel!" }
70 }
71 }
72 }
73 }
74 `)
75}
76
77func TestCreateUsernameDomainIDPassword(t *testing.T) {
78 authTokenPost(t, gophercloud.AuthOptions{Username: "fakey", Password: "notpassword", DomainID: "abc123"}, nil, `
79 {
80 "auth": {
81 "identity": {
82 "methods": ["password"],
83 "password": {
84 "user": {
85 "domain": {
86 "id": "abc123"
87 },
88 "name": "fakey",
89 "password": "notpassword"
90 }
91 }
92 }
93 }
94 }
95 `)
96}
Ash Wilsond8da9e42014-08-29 08:01:06 -040097
98func TestCreateUsernameDomainNamePassword(t *testing.T) {
99 authTokenPost(t, gophercloud.AuthOptions{Username: "frank", Password: "swordfish", DomainName: "spork.net"}, nil, `
100 {
101 "auth": {
102 "identity": {
103 "methods": ["password"],
104 "password": {
105 "user": {
106 "domain": {
107 "name": "spork.net"
108 },
109 "name": "frank",
110 "password": "swordfish"
111 }
112 }
113 }
114 }
115 }
116 `)
117}
Ash Wilson053fcb02014-08-29 08:04:35 -0400118
119func TestCreateTokenID(t *testing.T) {
120 authTokenPost(t, gophercloud.AuthOptions{}, nil, `
121 {
122 "auth": {
123 "identity": {
124 "methods": ["token"],
125 "token": {
126 "id": "12345abcdef"
127 }
128 }
129 }
130 }
131 `)
132}
Ash Wilson1fde6162014-08-29 08:13:06 -0400133
134func TestCreateProjectIDScope(t *testing.T) {
135 options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
136 scope := &Scope{ProjectID: "123456"}
137 authTokenPost(t, options, scope, `
138 {
139 "auth": {
140 "identity": {
141 "methods": ["password"],
142 "password": {
143 "user": {
144 "id": "fenris",
145 "password": "g0t0h311"
146 }
147 }
148 },
149 "scope": {
150 "project": {
151 "id": "123456"
152 }
153 }
154 }
155 }
156 `)
157}
158
159func TestCreateDomainIDScope(t *testing.T) {
160 options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
161 scope := &Scope{DomainID: "1000"}
162 authTokenPost(t, options, scope, `
163 {
164 "auth": {
165 "identity": {
166 "methods": ["password"],
167 "password": {
168 "user": {
169 "id": "fenris",
170 "password": "g0t0h311"
171 }
172 }
173 },
174 "scope": {
175 "domain": {
176 "id": "1000"
177 }
178 }
179 }
180 }
181 `)
182}
183
184func TestCreateProjectNameAndDomainIDScope(t *testing.T) {
185 options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
186 scope := &Scope{ProjectName: "world-domination", DomainID: "1000"}
187 authTokenPost(t, options, scope, `
188 {
189 "auth": {
190 "identity": {
191 "methods": ["password"],
192 "password": {
193 "user": {
194 "id": "fenris",
195 "password": "g0t0h311"
196 }
197 }
198 },
199 "scope": {
200 "project": {
201 "domain": {
202 "id": "1000"
203 },
204 "name": "world-domination"
205 }
206 }
207 }
208 }
209 `)
210}
211
212func TestCreateProjectNameAndDomainNameScope(t *testing.T) {
213 options := gophercloud.AuthOptions{UserID: "fenris", Password: "g0t0h311"}
214 scope := &Scope{ProjectName: "world-domination", DomainName: "evil-plans"}
215 authTokenPost(t, options, scope, `
216 {
217 "auth": {
218 "identity": {
219 "methods": ["password"],
220 "password": {
221 "user": {
222 "id": "fenris",
223 "password": "g0t0h311"
224 }
225 }
226 },
227 "scope": {
228 "project": {
229 "domain": {
230 "name": "evil-plans"
231 },
232 "name": "world-domination"
233 }
234 }
235 }
236 }
237 `)
238}
Ash Wilsona8855ff2014-08-29 08:26:29 -0400239
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400240func TestCreateExtractsTokenFromResponse(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400241 testhelper.SetupHTTP()
242 defer testhelper.TeardownHTTP()
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400243
Ash Wilson6425a412014-08-29 12:30:35 -0400244 client := gophercloud.ServiceClient{
Ash Wilsona87ee062014-09-03 11:26:06 -0400245 Provider: &gophercloud.ProviderClient{},
Ash Wilson0ab4d612014-08-29 11:10:13 -0400246 Endpoint: testhelper.Endpoint(),
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400247 }
248
Ash Wilson0ab4d612014-08-29 11:10:13 -0400249 testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400250 w.Header().Add("X-Subject-Token", "aaa111")
251
252 w.WriteHeader(http.StatusCreated)
253 fmt.Fprintf(w, `{}`)
254 })
255
Ash Wilsona87ee062014-09-03 11:26:06 -0400256 options := gophercloud.AuthOptions{UserID: "me", Password: "shhh"}
Ash Wilson3f59ade2014-10-02 09:22:23 -0400257 token, err := Create(&client, options, nil).Extract()
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400258 if err != nil {
259 t.Errorf("Create returned an error: %v", err)
260 }
261
Ash Wilson3f59ade2014-10-02 09:22:23 -0400262 if token.ID != "aaa111" {
263 t.Errorf("Expected token to be aaa111, but was %s", token.ID)
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400264 }
265}
266
Ash Wilsona8855ff2014-08-29 08:26:29 -0400267func TestCreateFailureEmptyAuth(t *testing.T) {
268 authTokenPostErr(t, gophercloud.AuthOptions{}, nil, false, ErrMissingPassword)
269}
270
271func TestCreateFailureAPIKey(t *testing.T) {
272 authTokenPostErr(t, gophercloud.AuthOptions{APIKey: "something"}, nil, false, ErrAPIKeyProvided)
273}
274
275func TestCreateFailureTenantID(t *testing.T) {
276 authTokenPostErr(t, gophercloud.AuthOptions{TenantID: "something"}, nil, false, ErrTenantIDProvided)
277}
278
279func TestCreateFailureTenantName(t *testing.T) {
280 authTokenPostErr(t, gophercloud.AuthOptions{TenantName: "something"}, nil, false, ErrTenantNameProvided)
281}
282
283func TestCreateFailureTokenIDUsername(t *testing.T) {
284 authTokenPostErr(t, gophercloud.AuthOptions{Username: "something"}, nil, true, ErrUsernameWithToken)
285}
286
287func TestCreateFailureTokenIDUserID(t *testing.T) {
288 authTokenPostErr(t, gophercloud.AuthOptions{UserID: "something"}, nil, true, ErrUserIDWithToken)
289}
290
291func TestCreateFailureTokenIDDomainID(t *testing.T) {
292 authTokenPostErr(t, gophercloud.AuthOptions{DomainID: "something"}, nil, true, ErrDomainIDWithToken)
293}
294
295func TestCreateFailureTokenIDDomainName(t *testing.T) {
296 authTokenPostErr(t, gophercloud.AuthOptions{DomainName: "something"}, nil, true, ErrDomainNameWithToken)
297}
Ash Wilsonaed3db42014-08-29 08:59:56 -0400298
299func TestCreateFailureMissingUser(t *testing.T) {
300 options := gophercloud.AuthOptions{Password: "supersecure"}
301 authTokenPostErr(t, options, nil, false, ErrUsernameOrUserID)
302}
303
304func TestCreateFailureBothUser(t *testing.T) {
305 options := gophercloud.AuthOptions{
306 Password: "supersecure",
307 Username: "oops",
308 UserID: "redundancy",
309 }
310 authTokenPostErr(t, options, nil, false, ErrUsernameOrUserID)
311}
312
313func TestCreateFailureMissingDomain(t *testing.T) {
314 options := gophercloud.AuthOptions{
315 Password: "supersecure",
316 Username: "notuniqueenough",
317 }
318 authTokenPostErr(t, options, nil, false, ErrDomainIDOrDomainName)
319}
320
321func TestCreateFailureBothDomain(t *testing.T) {
322 options := gophercloud.AuthOptions{
323 Password: "supersecure",
324 Username: "someone",
325 DomainID: "hurf",
326 DomainName: "durf",
327 }
328 authTokenPostErr(t, options, nil, false, ErrDomainIDOrDomainName)
329}
330
331func TestCreateFailureUserIDDomainID(t *testing.T) {
332 options := gophercloud.AuthOptions{
333 UserID: "100",
334 Password: "stuff",
335 DomainID: "oops",
336 }
337 authTokenPostErr(t, options, nil, false, ErrDomainIDWithUserID)
338}
339
340func TestCreateFailureUserIDDomainName(t *testing.T) {
341 options := gophercloud.AuthOptions{
342 UserID: "100",
343 Password: "sssh",
344 DomainName: "oops",
345 }
346 authTokenPostErr(t, options, nil, false, ErrDomainNameWithUserID)
347}
348
349func TestCreateFailureScopeProjectNameAlone(t *testing.T) {
350 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
351 scope := &Scope{ProjectName: "notenough"}
352 authTokenPostErr(t, options, scope, false, ErrScopeDomainIDOrDomainName)
353}
354
355func TestCreateFailureScopeProjectNameAndID(t *testing.T) {
356 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
357 scope := &Scope{ProjectName: "whoops", ProjectID: "toomuch", DomainID: "1234"}
358 authTokenPostErr(t, options, scope, false, ErrScopeProjectIDOrProjectName)
359}
360
361func TestCreateFailureScopeProjectIDAndDomainID(t *testing.T) {
362 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
363 scope := &Scope{ProjectID: "toomuch", DomainID: "notneeded"}
364 authTokenPostErr(t, options, scope, false, ErrScopeProjectIDAlone)
365}
366
367func TestCreateFailureScopeProjectIDAndDomainNAme(t *testing.T) {
368 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
369 scope := &Scope{ProjectID: "toomuch", DomainName: "notneeded"}
370 authTokenPostErr(t, options, scope, false, ErrScopeProjectIDAlone)
371}
372
373func TestCreateFailureScopeDomainIDAndDomainName(t *testing.T) {
374 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
375 scope := &Scope{DomainID: "toomuch", DomainName: "notneeded"}
376 authTokenPostErr(t, options, scope, false, ErrScopeDomainIDOrDomainName)
377}
378
379func TestCreateFailureScopeDomainNameAlone(t *testing.T) {
380 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
381 scope := &Scope{DomainName: "notenough"}
382 authTokenPostErr(t, options, scope, false, ErrScopeDomainName)
383}
384
385func TestCreateFailureEmptyScope(t *testing.T) {
386 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
387 scope := &Scope{}
388 authTokenPostErr(t, options, scope, false, ErrScopeEmpty)
389}
Ash Wilson46d913f2014-08-29 11:00:11 -0400390
Ash Wilson5266e492014-09-09 15:44:30 -0400391func TestGetRequest(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400392 testhelper.SetupHTTP()
393 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400394
Ash Wilson6425a412014-08-29 12:30:35 -0400395 client := gophercloud.ServiceClient{
Ash Wilsona87ee062014-09-03 11:26:06 -0400396 Provider: &gophercloud.ProviderClient{
Ash Wilson6425a412014-08-29 12:30:35 -0400397 TokenID: "12345abcdef",
398 },
Ash Wilson0ab4d612014-08-29 11:10:13 -0400399 Endpoint: testhelper.Endpoint(),
Ash Wilson46d913f2014-08-29 11:00:11 -0400400 }
401
Ash Wilson0ab4d612014-08-29 11:10:13 -0400402 testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson46d913f2014-08-29 11:00:11 -0400403 testhelper.TestMethod(t, r, "GET")
Jon Perrittd8aef1b2014-09-11 17:50:04 -0500404 testhelper.TestHeader(t, r, "Content-Type", "")
Ash Wilson46d913f2014-08-29 11:00:11 -0400405 testhelper.TestHeader(t, r, "Accept", "application/json")
406 testhelper.TestHeader(t, r, "X-Auth-Token", "12345abcdef")
407 testhelper.TestHeader(t, r, "X-Subject-Token", "abcdef12345")
408
409 w.WriteHeader(http.StatusOK)
410 fmt.Fprintf(w, `
411 { "token": { "expires_at": "2014-08-29T13:10:01.000000Z" } }
412 `)
413 })
414
Ash Wilson3f59ade2014-10-02 09:22:23 -0400415 token, err := Get(&client, "abcdef12345").Extract()
Ash Wilson46d913f2014-08-29 11:00:11 -0400416 if err != nil {
417 t.Errorf("Info returned an error: %v", err)
418 }
419
Ash Wilson46d913f2014-08-29 11:00:11 -0400420 expected, _ := time.Parse(time.UnixDate, "Fri Aug 29 13:10:01 UTC 2014")
Ash Wilson3f59ade2014-10-02 09:22:23 -0400421 if token.ExpiresAt != expected {
422 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 -0400423 }
424}
425
Ash Wilson6425a412014-08-29 12:30:35 -0400426func prepareAuthTokenHandler(t *testing.T, expectedMethod string, status int) gophercloud.ServiceClient {
427 client := gophercloud.ServiceClient{
Ash Wilsona87ee062014-09-03 11:26:06 -0400428 Provider: &gophercloud.ProviderClient{
Ash Wilson6425a412014-08-29 12:30:35 -0400429 TokenID: "12345abcdef",
430 },
Ash Wilson0ab4d612014-08-29 11:10:13 -0400431 Endpoint: testhelper.Endpoint(),
Ash Wilson46d913f2014-08-29 11:00:11 -0400432 }
433
Ash Wilson0ab4d612014-08-29 11:10:13 -0400434 testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson46d913f2014-08-29 11:00:11 -0400435 testhelper.TestMethod(t, r, expectedMethod)
Jon Perrittd8aef1b2014-09-11 17:50:04 -0500436 testhelper.TestHeader(t, r, "Content-Type", "")
Ash Wilson46d913f2014-08-29 11:00:11 -0400437 testhelper.TestHeader(t, r, "Accept", "application/json")
438 testhelper.TestHeader(t, r, "X-Auth-Token", "12345abcdef")
439 testhelper.TestHeader(t, r, "X-Subject-Token", "abcdef12345")
440
441 w.WriteHeader(status)
442 })
443
444 return client
445}
446
447func TestValidateRequestSuccessful(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400448 testhelper.SetupHTTP()
449 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400450 client := prepareAuthTokenHandler(t, "HEAD", http.StatusNoContent)
451
452 ok, err := Validate(&client, "abcdef12345")
453 if err != nil {
454 t.Errorf("Unexpected error from Validate: %v", err)
455 }
456
457 if !ok {
458 t.Errorf("Validate returned false for a valid token")
459 }
460}
461
462func TestValidateRequestFailure(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400463 testhelper.SetupHTTP()
464 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400465 client := prepareAuthTokenHandler(t, "HEAD", http.StatusNotFound)
466
467 ok, err := Validate(&client, "abcdef12345")
468 if err != nil {
469 t.Errorf("Unexpected error from Validate: %v", err)
470 }
471
472 if ok {
473 t.Errorf("Validate returned true for an invalid token")
474 }
475}
476
477func TestValidateRequestError(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400478 testhelper.SetupHTTP()
479 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400480 client := prepareAuthTokenHandler(t, "HEAD", http.StatusUnauthorized)
481
482 _, err := Validate(&client, "abcdef12345")
483 if err == nil {
484 t.Errorf("Missing expected error from Validate")
485 }
486}
487
488func TestRevokeRequestSuccessful(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400489 testhelper.SetupHTTP()
490 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400491 client := prepareAuthTokenHandler(t, "DELETE", http.StatusNoContent)
492
493 err := Revoke(&client, "abcdef12345")
494 if err != nil {
495 t.Errorf("Unexpected error from Revoke: %v", err)
496 }
497}
498
499func TestRevokeRequestError(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400500 testhelper.SetupHTTP()
501 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400502 client := prepareAuthTokenHandler(t, "DELETE", http.StatusNotFound)
503
504 err := Revoke(&client, "abcdef12345")
505 if err == nil {
506 t.Errorf("Missing expected error from Revoke")
507 }
508}