blob: cfb4ff162b3460347acafa01016c57c482847e8f [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{
19 ProviderClient: gophercloud.ProviderClient{
20 IdentityEndpoint: testhelper.Endpoint(),
21 Options: options,
22 TokenID: "12345abcdef",
23 },
Ash Wilson0ab4d612014-08-29 11:10:13 -040024 Endpoint: testhelper.Endpoint(),
Ash Wilsoncde68122014-08-28 16:15:43 -040025 }
26
Ash Wilson0ab4d612014-08-29 11:10:13 -040027 testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
Ash Wilsoncde68122014-08-28 16:15:43 -040028 testhelper.TestMethod(t, r, "POST")
29 testhelper.TestHeader(t, r, "Content-Type", "application/json")
30 testhelper.TestHeader(t, r, "Accept", "application/json")
Ash Wilson417d9222014-08-29 07:58:35 -040031 testhelper.TestJSONRequest(t, r, requestJSON)
Ash Wilsoncde68122014-08-28 16:15:43 -040032
Ash Wilson4a52e2a2014-08-29 09:28:00 -040033 w.WriteHeader(http.StatusCreated)
Ash Wilsoncde68122014-08-28 16:15:43 -040034 fmt.Fprintf(w, `{}`)
35 })
36
Ash Wilson417d9222014-08-29 07:58:35 -040037 _, err := Create(&client, scope)
Ash Wilsoncde68122014-08-28 16:15:43 -040038 if err != nil {
39 t.Errorf("Create returned an error: %v", err)
40 }
41}
Ash Wilson417d9222014-08-29 07:58:35 -040042
Ash Wilsona8855ff2014-08-29 08:26:29 -040043func authTokenPostErr(t *testing.T, options gophercloud.AuthOptions, scope *Scope, includeToken bool, expectedErr error) {
Ash Wilson0ab4d612014-08-29 11:10:13 -040044 testhelper.SetupHTTP()
45 defer testhelper.TeardownHTTP()
Ash Wilsona8855ff2014-08-29 08:26:29 -040046
Ash Wilson6425a412014-08-29 12:30:35 -040047 client := gophercloud.ServiceClient{
48 ProviderClient: gophercloud.ProviderClient{
49 Options: options,
50 },
Ash Wilson0ab4d612014-08-29 11:10:13 -040051 Endpoint: testhelper.Endpoint(),
Ash Wilsona8855ff2014-08-29 08:26:29 -040052 }
53 if includeToken {
54 client.TokenID = "abcdef123456"
55 }
56
57 _, err := Create(&client, scope)
58 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{
249 ProviderClient: gophercloud.ProviderClient{
250 Options: gophercloud.AuthOptions{UserID: "me", Password: "shhh"},
251 },
Ash Wilson0ab4d612014-08-29 11:10:13 -0400252 Endpoint: testhelper.Endpoint(),
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400253 }
254
Ash Wilson0ab4d612014-08-29 11:10:13 -0400255 testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson4a52e2a2014-08-29 09:28:00 -0400256 w.Header().Add("X-Subject-Token", "aaa111")
257
258 w.WriteHeader(http.StatusCreated)
259 fmt.Fprintf(w, `{}`)
260 })
261
262 result, err := Create(&client, nil)
263 if err != nil {
264 t.Errorf("Create returned an error: %v", err)
265 }
266
267 token, _ := result.TokenID()
268 if token != "aaa111" {
269 t.Errorf("Expected token to be aaa111, but was %s", token)
270 }
271}
272
Ash Wilsona8855ff2014-08-29 08:26:29 -0400273func TestCreateFailureEmptyAuth(t *testing.T) {
274 authTokenPostErr(t, gophercloud.AuthOptions{}, nil, false, ErrMissingPassword)
275}
276
277func TestCreateFailureAPIKey(t *testing.T) {
278 authTokenPostErr(t, gophercloud.AuthOptions{APIKey: "something"}, nil, false, ErrAPIKeyProvided)
279}
280
281func TestCreateFailureTenantID(t *testing.T) {
282 authTokenPostErr(t, gophercloud.AuthOptions{TenantID: "something"}, nil, false, ErrTenantIDProvided)
283}
284
285func TestCreateFailureTenantName(t *testing.T) {
286 authTokenPostErr(t, gophercloud.AuthOptions{TenantName: "something"}, nil, false, ErrTenantNameProvided)
287}
288
289func TestCreateFailureTokenIDUsername(t *testing.T) {
290 authTokenPostErr(t, gophercloud.AuthOptions{Username: "something"}, nil, true, ErrUsernameWithToken)
291}
292
293func TestCreateFailureTokenIDUserID(t *testing.T) {
294 authTokenPostErr(t, gophercloud.AuthOptions{UserID: "something"}, nil, true, ErrUserIDWithToken)
295}
296
297func TestCreateFailureTokenIDDomainID(t *testing.T) {
298 authTokenPostErr(t, gophercloud.AuthOptions{DomainID: "something"}, nil, true, ErrDomainIDWithToken)
299}
300
301func TestCreateFailureTokenIDDomainName(t *testing.T) {
302 authTokenPostErr(t, gophercloud.AuthOptions{DomainName: "something"}, nil, true, ErrDomainNameWithToken)
303}
Ash Wilsonaed3db42014-08-29 08:59:56 -0400304
305func TestCreateFailureMissingUser(t *testing.T) {
306 options := gophercloud.AuthOptions{Password: "supersecure"}
307 authTokenPostErr(t, options, nil, false, ErrUsernameOrUserID)
308}
309
310func TestCreateFailureBothUser(t *testing.T) {
311 options := gophercloud.AuthOptions{
312 Password: "supersecure",
313 Username: "oops",
314 UserID: "redundancy",
315 }
316 authTokenPostErr(t, options, nil, false, ErrUsernameOrUserID)
317}
318
319func TestCreateFailureMissingDomain(t *testing.T) {
320 options := gophercloud.AuthOptions{
321 Password: "supersecure",
322 Username: "notuniqueenough",
323 }
324 authTokenPostErr(t, options, nil, false, ErrDomainIDOrDomainName)
325}
326
327func TestCreateFailureBothDomain(t *testing.T) {
328 options := gophercloud.AuthOptions{
329 Password: "supersecure",
330 Username: "someone",
331 DomainID: "hurf",
332 DomainName: "durf",
333 }
334 authTokenPostErr(t, options, nil, false, ErrDomainIDOrDomainName)
335}
336
337func TestCreateFailureUserIDDomainID(t *testing.T) {
338 options := gophercloud.AuthOptions{
339 UserID: "100",
340 Password: "stuff",
341 DomainID: "oops",
342 }
343 authTokenPostErr(t, options, nil, false, ErrDomainIDWithUserID)
344}
345
346func TestCreateFailureUserIDDomainName(t *testing.T) {
347 options := gophercloud.AuthOptions{
348 UserID: "100",
349 Password: "sssh",
350 DomainName: "oops",
351 }
352 authTokenPostErr(t, options, nil, false, ErrDomainNameWithUserID)
353}
354
355func TestCreateFailureScopeProjectNameAlone(t *testing.T) {
356 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
357 scope := &Scope{ProjectName: "notenough"}
358 authTokenPostErr(t, options, scope, false, ErrScopeDomainIDOrDomainName)
359}
360
361func TestCreateFailureScopeProjectNameAndID(t *testing.T) {
362 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
363 scope := &Scope{ProjectName: "whoops", ProjectID: "toomuch", DomainID: "1234"}
364 authTokenPostErr(t, options, scope, false, ErrScopeProjectIDOrProjectName)
365}
366
367func TestCreateFailureScopeProjectIDAndDomainID(t *testing.T) {
368 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
369 scope := &Scope{ProjectID: "toomuch", DomainID: "notneeded"}
370 authTokenPostErr(t, options, scope, false, ErrScopeProjectIDAlone)
371}
372
373func TestCreateFailureScopeProjectIDAndDomainNAme(t *testing.T) {
374 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
375 scope := &Scope{ProjectID: "toomuch", DomainName: "notneeded"}
376 authTokenPostErr(t, options, scope, false, ErrScopeProjectIDAlone)
377}
378
379func TestCreateFailureScopeDomainIDAndDomainName(t *testing.T) {
380 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
381 scope := &Scope{DomainID: "toomuch", DomainName: "notneeded"}
382 authTokenPostErr(t, options, scope, false, ErrScopeDomainIDOrDomainName)
383}
384
385func TestCreateFailureScopeDomainNameAlone(t *testing.T) {
386 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
387 scope := &Scope{DomainName: "notenough"}
388 authTokenPostErr(t, options, scope, false, ErrScopeDomainName)
389}
390
391func TestCreateFailureEmptyScope(t *testing.T) {
392 options := gophercloud.AuthOptions{UserID: "myself", Password: "swordfish"}
393 scope := &Scope{}
394 authTokenPostErr(t, options, scope, false, ErrScopeEmpty)
395}
Ash Wilson46d913f2014-08-29 11:00:11 -0400396
397func TestInfoRequest(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400398 testhelper.SetupHTTP()
399 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400400
Ash Wilson6425a412014-08-29 12:30:35 -0400401 client := gophercloud.ServiceClient{
402 ProviderClient: gophercloud.ProviderClient{
403 TokenID: "12345abcdef",
404 },
Ash Wilson0ab4d612014-08-29 11:10:13 -0400405 Endpoint: testhelper.Endpoint(),
Ash Wilson46d913f2014-08-29 11:00:11 -0400406 }
407
Ash Wilson0ab4d612014-08-29 11:10:13 -0400408 testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson46d913f2014-08-29 11:00:11 -0400409 testhelper.TestMethod(t, r, "GET")
410 testhelper.TestHeader(t, r, "Content-Type", "application/json")
411 testhelper.TestHeader(t, r, "Accept", "application/json")
412 testhelper.TestHeader(t, r, "X-Auth-Token", "12345abcdef")
413 testhelper.TestHeader(t, r, "X-Subject-Token", "abcdef12345")
414
415 w.WriteHeader(http.StatusOK)
416 fmt.Fprintf(w, `
417 { "token": { "expires_at": "2014-08-29T13:10:01.000000Z" } }
418 `)
419 })
420
421 result, err := Info(&client, "abcdef12345")
422 if err != nil {
423 t.Errorf("Info returned an error: %v", err)
424 }
425
426 expires, err := result.ExpiresAt()
427 if err != nil {
428 t.Errorf("Error extracting token expiration time: %v", err)
429 }
430
431 expected, _ := time.Parse(time.UnixDate, "Fri Aug 29 13:10:01 UTC 2014")
432 if expires != expected {
433 t.Errorf("Expected expiration time %s, but was %s", expected.Format(time.UnixDate), expires.Format(time.UnixDate))
434 }
435}
436
Ash Wilson6425a412014-08-29 12:30:35 -0400437func prepareAuthTokenHandler(t *testing.T, expectedMethod string, status int) gophercloud.ServiceClient {
438 client := gophercloud.ServiceClient{
439 ProviderClient: gophercloud.ProviderClient{
440 TokenID: "12345abcdef",
441 },
Ash Wilson0ab4d612014-08-29 11:10:13 -0400442 Endpoint: testhelper.Endpoint(),
Ash Wilson46d913f2014-08-29 11:00:11 -0400443 }
444
Ash Wilson0ab4d612014-08-29 11:10:13 -0400445 testhelper.Mux.HandleFunc("/auth/tokens", func(w http.ResponseWriter, r *http.Request) {
Ash Wilson46d913f2014-08-29 11:00:11 -0400446 testhelper.TestMethod(t, r, expectedMethod)
447 testhelper.TestHeader(t, r, "Content-Type", "application/json")
448 testhelper.TestHeader(t, r, "Accept", "application/json")
449 testhelper.TestHeader(t, r, "X-Auth-Token", "12345abcdef")
450 testhelper.TestHeader(t, r, "X-Subject-Token", "abcdef12345")
451
452 w.WriteHeader(status)
453 })
454
455 return client
456}
457
458func TestValidateRequestSuccessful(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400459 testhelper.SetupHTTP()
460 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400461 client := prepareAuthTokenHandler(t, "HEAD", http.StatusNoContent)
462
463 ok, err := Validate(&client, "abcdef12345")
464 if err != nil {
465 t.Errorf("Unexpected error from Validate: %v", err)
466 }
467
468 if !ok {
469 t.Errorf("Validate returned false for a valid token")
470 }
471}
472
473func TestValidateRequestFailure(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400474 testhelper.SetupHTTP()
475 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400476 client := prepareAuthTokenHandler(t, "HEAD", http.StatusNotFound)
477
478 ok, err := Validate(&client, "abcdef12345")
479 if err != nil {
480 t.Errorf("Unexpected error from Validate: %v", err)
481 }
482
483 if ok {
484 t.Errorf("Validate returned true for an invalid token")
485 }
486}
487
488func TestValidateRequestError(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, "HEAD", http.StatusUnauthorized)
492
493 _, err := Validate(&client, "abcdef12345")
494 if err == nil {
495 t.Errorf("Missing expected error from Validate")
496 }
497}
498
499func TestRevokeRequestSuccessful(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.StatusNoContent)
503
504 err := Revoke(&client, "abcdef12345")
505 if err != nil {
506 t.Errorf("Unexpected error from Revoke: %v", err)
507 }
508}
509
510func TestRevokeRequestError(t *testing.T) {
Ash Wilson0ab4d612014-08-29 11:10:13 -0400511 testhelper.SetupHTTP()
512 defer testhelper.TeardownHTTP()
Ash Wilson46d913f2014-08-29 11:00:11 -0400513 client := prepareAuthTokenHandler(t, "DELETE", http.StatusNotFound)
514
515 err := Revoke(&client, "abcdef12345")
516 if err == nil {
517 t.Errorf("Missing expected error from Revoke")
518 }
519}