@@ -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 )
@@ -311,3 +329,40 @@ func TestUserWithoutSessionUUID(t *testing.T) {
311329 require .NoError (t , err )
312330
313331}
332+
333+ func TestCreateOneTimeSession (t * testing.T ) {
334+ ctx := base .TestCtx (t )
335+ testBucket := base .GetTestBucket (t )
336+ defer testBucket .Close (ctx )
337+ dataStore := testBucket .GetSingleDataStore ()
338+ auth := NewTestAuthenticator (t , dataStore , nil , DefaultAuthenticatorOptions (ctx ))
339+ const username = "Alice"
340+ user , err := auth .NewUser (username , "password" , base.Set {})
341+ require .NoError (t , err )
342+ require .NoError (t , auth .Save (user ))
343+
344+ oneTime := true
345+ session , err := auth .CreateSession (ctx , user , 2 * time .Hour , oneTime )
346+ require .NoError (t , err )
347+
348+ session , user , err = auth .GetSession (session .ID )
349+ require .NoError (t , err )
350+ require .Equal (t , username , session .Username )
351+ require .Equal (t , username , user .Name ())
352+
353+ // make sure this can be retrieved again if not through AuthenticateOneTimeSession
354+ session , user , err = auth .GetSession (session .ID )
355+ require .NoError (t , err )
356+ require .Equal (t , username , session .Username )
357+ require .Equal (t , username , user .Name ())
358+
359+ // now test AuthenticateOneTimeSession deletes it
360+ user , err = auth .AuthenticateOneTimeSession (ctx , session .ID )
361+ require .NoError (t , err )
362+ require .Equal (t , username , user .Name ())
363+
364+ // make sure session is deleted
365+ session , _ , err = auth .GetSession (session .ID )
366+ require .Nil (t , session )
367+ base .RequireDocNotFoundError (t , err )
368+ }
0 commit comments