@@ -11,6 +11,7 @@ licenses/APL2.txt.
1111package auth
1212
1313import (
14+ "fmt"
1415 "net/http"
1516 "net/http/httptest"
1617 "strings"
@@ -23,50 +24,66 @@ import (
2324)
2425
2526func TestCreateSession (t * testing.T ) {
26- const username = "Alice"
27- const invalidSessionTTLError = "400 Invalid session time-to-live"
2827 base .SetUpTestLogging (t , base .LevelDebug , base .KeyAuth )
29- ctx := base .TestCtx (t )
30- testBucket := base .GetTestBucket (t )
31- defer testBucket .Close (ctx )
32- dataStore := testBucket .GetSingleDataStore ()
33- auth := NewTestAuthenticator (t , dataStore , nil , DefaultAuthenticatorOptions (ctx ))
34-
35- user , err := auth .NewUser (username , "password" , base.Set {})
36- require .NoError (t , err )
37- require .NotNil (t , user )
38- require .NoError (t , auth .Save (user ))
39-
40- // Create session with a username and valid TTL of 2 hours.
41- session , err := auth .CreateSession (ctx , user , 2 * time .Hour )
42- require .NoError (t , err )
43-
44- assert .Equal (t , username , session .Username )
45- assert .Equal (t , 2 * time .Hour , session .Ttl )
46- assert .NotEmpty (t , session .ID )
47- assert .NotEmpty (t , session .Expiration )
48-
49- // Once the session is created, the details should be persisted on the bucket
50- // and it must be accessible anytime later within the session expiration time.
51- session , err = auth .GetSession (session .ID )
52- assert .NoError (t , err )
28+ for _ , oneTime := range []bool {true , false } {
29+ t .Run (fmt .Sprintf ("oneTime=%t" , oneTime ), func (t * testing.T ) {
30+ const username = "Alice"
31+ const invalidSessionTTLError = "400 Invalid session time-to-live"
32+ ctx := base .TestCtx (t )
33+ testBucket := base .GetTestBucket (t )
34+ defer testBucket .Close (ctx )
35+ dataStore := testBucket .GetSingleDataStore ()
36+ auth := NewTestAuthenticator (t , dataStore , nil , DefaultAuthenticatorOptions (ctx ))
5337
54- assert . Equal ( t , username , session . Username )
55- assert . Equal (t , 2 * time . Hour , session . Ttl )
56- assert . NotEmpty (t , session . ID )
57- assert . NotEmpty (t , session . Expiration )
38+ user , err := auth . NewUser ( username , "password" , base. Set {} )
39+ require . NoError (t , err )
40+ require . NotNil (t , user )
41+ require . NoError (t , auth . Save ( user ) )
5842
59- // Session must not be created with zero TTL; it's illegal.
60- session , err = auth .CreateSession (ctx , user , time .Duration (0 ))
61- assert .Nil (t , session )
62- assert .Error (t , err )
63- assert .Contains (t , err .Error (), invalidSessionTTLError )
43+ // Create session with a username and valid TTL of 2 hours.
44+ session , err := auth .CreateSession (ctx , user , 2 * time .Hour , oneTime )
45+ require .NoError (t , err )
6446
65- // Session must not be created with negative TTL; it's illegal.
66- session , err = auth .CreateSession (ctx , user , time .Duration (- 1 ))
67- assert .Nil (t , session )
68- assert .Error (t , err )
69- assert .Contains (t , err .Error (), invalidSessionTTLError )
47+ assert .Equal (t , username , session .Username )
48+ assert .Equal (t , 2 * time .Hour , session .Ttl )
49+ assert .NotEmpty (t , session .ID )
50+ assert .NotEmpty (t , session .Expiration )
51+ if oneTime {
52+ require .NotNil (t , session .OneTime )
53+ require .True (t , * session .OneTime )
54+ } else {
55+ assert .Empty (t , session .OneTime )
56+ }
57+
58+ // Once the session is created, the details should be persisted on the bucket
59+ // and it must be accessible anytime later within the session expiration time.
60+ session , _ , err = auth .GetSession (session .ID )
61+ assert .NoError (t , err )
62+
63+ assert .Equal (t , username , session .Username )
64+ assert .Equal (t , 2 * time .Hour , session .Ttl )
65+ assert .NotEmpty (t , session .ID )
66+ assert .NotEmpty (t , session .Expiration )
67+ if oneTime {
68+ require .NotNil (t , session .OneTime )
69+ require .True (t , * session .OneTime )
70+ } else {
71+ assert .Empty (t , session .OneTime )
72+ }
73+
74+ // Session must not be created with zero TTL; it's illegal.
75+ session , err = auth .CreateSession (ctx , user , time .Duration (0 ), oneTime )
76+ assert .Nil (t , session )
77+ assert .Error (t , err )
78+ assert .Contains (t , err .Error (), invalidSessionTTLError )
79+
80+ // Session must not be created with negative TTL; it's illegal.
81+ session , err = auth .CreateSession (ctx , user , time .Duration (- 1 ), oneTime )
82+ assert .Nil (t , session )
83+ assert .Error (t , err )
84+ assert .Contains (t , err .Error (), invalidSessionTTLError )
85+ })
86+ }
7087}
7188
7289func TestDeleteSession (t * testing.T ) {
@@ -91,7 +108,7 @@ func TestDeleteSession(t *testing.T) {
91108 assert .NoError (t , dataStore .Set (auth .DocIDForSession (mockSession .ID ), noSessionExpiry , nil , mockSession ))
92109 assert .NoError (t , auth .DeleteSession (ctx , mockSession .ID , "" ))
93110
94- session , err := auth .GetSession (mockSession .ID )
111+ session , _ , err := auth .GetSession (mockSession .ID )
95112 assert .Nil (t , session )
96113 base .RequireDocNotFoundError (t , err )
97114}
@@ -239,11 +256,12 @@ func TestCreateSessionChangePassword(t *testing.T) {
239256 require .NotNil (t , user )
240257 require .NoError (t , auth .Save (user ))
241258
259+ oneTime := false
242260 // Create session with a username and valid TTL of 2 hours.
243- session , err := auth .CreateSession (ctx , user , 2 * time .Hour )
261+ session , err := auth .CreateSession (ctx , user , 2 * time .Hour , oneTime )
244262 require .NoError (t , err )
245263
246- session , err = auth .GetSession (session .ID )
264+ session , _ , err = auth .GetSession (session .ID )
247265 require .NoError (t , err )
248266
249267 request , err := http .NewRequest (http .MethodGet , "" , nil )
@@ -295,11 +313,11 @@ func TestUserWithoutSessionUUID(t *testing.T) {
295313 require .NoError (t , err )
296314 require .NotNil (t , user )
297315
298- // Create session with a username and valid TTL of 2 hours.
299- session , err := auth .CreateSession (ctx , user , 2 * time .Hour )
316+ oneTime := false
317+ session , err := auth .CreateSession (ctx , user , 2 * time .Hour , oneTime )
300318 require .NoError (t , err )
301319
302- session , err = auth .GetSession (session .ID )
320+ session , _ , err = auth .GetSession (session .ID )
303321 require .NoError (t , err )
304322
305323 request , err := http .NewRequest (http .MethodGet , "" , nil )
@@ -325,11 +343,11 @@ func TestUserDeleteAllSessions(t *testing.T) {
325343 require .NotNil (t , user )
326344 require .NoError (t , auth .Save (user ))
327345
328- // Create session with a username and valid TTL of 2 hours.
329- session , err := auth .CreateSession (ctx , user , 2 * time .Hour )
346+ oneTime := false
347+ session , err := auth .CreateSession (ctx , user , 2 * time .Hour , oneTime )
330348 require .NoError (t , err )
331349
332- session , err = auth .GetSession (session .ID )
350+ session , _ , err = auth .GetSession (session .ID )
333351 require .NoError (t , err )
334352
335353 request , err := http .NewRequest (http .MethodGet , "" , nil )
@@ -348,3 +366,40 @@ func TestUserDeleteAllSessions(t *testing.T) {
348366 _ , err = auth .AuthenticateCookie (request , recorder )
349367 require .EqualError (t , err , "401 Session no longer valid for user" )
350368}
369+
370+ func TestCreateOneTimeSession (t * testing.T ) {
371+ ctx := base .TestCtx (t )
372+ testBucket := base .GetTestBucket (t )
373+ defer testBucket .Close (ctx )
374+ dataStore := testBucket .GetSingleDataStore ()
375+ auth := NewTestAuthenticator (t , dataStore , nil , DefaultAuthenticatorOptions (ctx ))
376+ const username = "Alice"
377+ user , err := auth .NewUser (username , "password" , base.Set {})
378+ require .NoError (t , err )
379+ require .NoError (t , auth .Save (user ))
380+
381+ oneTime := true
382+ session , err := auth .CreateSession (ctx , user , 2 * time .Hour , oneTime )
383+ require .NoError (t , err )
384+
385+ session , user , err = auth .GetSession (session .ID )
386+ require .NoError (t , err )
387+ require .Equal (t , username , session .Username )
388+ require .Equal (t , username , user .Name ())
389+
390+ // make sure this can be retrieved again if not through AuthenticateOneTimeSession
391+ session , user , err = auth .GetSession (session .ID )
392+ require .NoError (t , err )
393+ require .Equal (t , username , session .Username )
394+ require .Equal (t , username , user .Name ())
395+
396+ // now test AuthenticateOneTimeSession deletes it
397+ user , err = auth .AuthenticateOneTimeSession (ctx , session .ID )
398+ require .NoError (t , err )
399+ require .Equal (t , username , user .Name ())
400+
401+ // make sure session is deleted
402+ session , _ , err = auth .GetSession (session .ID )
403+ require .Nil (t , session )
404+ base .RequireDocNotFoundError (t , err )
405+ }
0 commit comments