@@ -11,19 +11,20 @@ import (
1111 "github.com/influxdata/influxdb/v2/kit/platform"
1212 "github.com/influxdata/influxdb/v2/kv"
1313 "github.com/influxdata/influxdb/v2/kv/migration/all"
14+ influxdb2_algo "github.com/influxdata/influxdb/v2/pkg/crypt/algorithm/influxdb2"
1415 "github.com/stretchr/testify/require"
1516 "go.uber.org/zap/zaptest"
1617)
1718
19+ const (
20+ authIndexName = "authorizationindexv1"
21+ hashedAuthIndexName = "authorizationhashedindexv1"
22+ )
23+
1824func TestAuth (t * testing.T ) {
1925 checkIndexCounts := func (t * testing.T , tx kv.Tx , expAuthIndexCount , expHashedAuthIndexCount int ) {
2026 t .Helper ()
2127
22- const (
23- authIndexName = "authorizationindexv1"
24- hashedAuthIndexName = "authorizationhashedindexv1"
25- )
26-
2728 indexCount := make (map [string ]int )
2829 for _ , indexName := range []string {authIndexName , hashedAuthIndexName } {
2930 index , err := tx .Bucket ([]byte (indexName ))
@@ -279,3 +280,192 @@ func TestAuth(t *testing.T) {
279280 }
280281 }
281282}
283+
284+ func TestAuthorizationStore_HashingConfigChanges (t * testing.T ) {
285+ sha256 , err := influxdb2_algo .New (influxdb2_algo .WithVariant (influxdb2_algo .VariantSHA256 ))
286+ require .NoError (t , err )
287+ sha512 , err := influxdb2_algo .New (influxdb2_algo .WithVariant (influxdb2_algo .VariantSHA512 ))
288+ require .NoError (t , err )
289+
290+ type authData struct {
291+ ID platform.ID
292+ Token string
293+ HashedToken string
294+ }
295+ type testConfig struct {
296+ enabled bool
297+ algo string
298+ }
299+ type testCase struct {
300+ desc string
301+ config testConfig
302+ action func (t * testing.T , ctx context.Context , store * authorization.Store , tx kv.Tx )
303+ exp []authData
304+ hashedTokens []string // tokens which only exists as hashes
305+ }
306+ cases := []testCase {
307+ {
308+ desc : "initial unhashed" ,
309+ config : testConfig {enabled : false },
310+ action : func (t * testing.T , ctx context.Context , store * authorization.Store , tx kv.Tx ) {
311+ a := & influxdb.Authorization {
312+ ID : platform .ID (1 ),
313+ OrgID : platform .ID (1 ),
314+ UserID : platform .ID (1 ),
315+ Token : "Token#1" ,
316+ }
317+ require .NoError (t , store .CreateAuthorization (ctx , tx , a ))
318+ },
319+ exp : []authData {
320+ {ID : platform .ID (1 ), Token : "Token#1" },
321+ },
322+ },
323+ {
324+ desc : "upgrade hashed #1" , // update hash and indices
325+ config : testConfig {enabled : true , algo : influxdb2_algo .VariantIdentifierSHA256 },
326+ exp : []authData {
327+ {ID : platform .ID (1 ), HashedToken : sha256 .MustHash ("Token#1" ).Encode ()},
328+ },
329+ hashedTokens : []string {"Token#1" },
330+ },
331+ {
332+ desc : "downgrade hashed #1" , // can't unhash
333+ config : testConfig {enabled : false , algo : influxdb2_algo .VariantIdentifierSHA256 },
334+ action : func (t * testing.T , ctx context.Context , store * authorization.Store , tx kv.Tx ) {
335+ a := & influxdb.Authorization {
336+ ID : platform .ID (2 ),
337+ OrgID : platform .ID (2 ),
338+ UserID : platform .ID (2 ),
339+ Token : "Token#2" ,
340+ }
341+ require .NoError (t , store .CreateAuthorization (ctx , tx , a ))
342+ },
343+ exp : []authData {
344+ {ID : platform .ID (1 ), HashedToken : sha256 .MustHash ("Token#1" ).Encode ()},
345+ {ID : platform .ID (2 ), Token : "Token#2" },
346+ },
347+ hashedTokens : []string {"Token#1" },
348+ },
349+ {
350+ desc : "upgrade hashed sha512" , // can't rehash existing, use new algo for new auths
351+ config : testConfig {enabled : true , algo : influxdb2_algo .VariantIdentifierSHA512 },
352+ action : func (t * testing.T , ctx context.Context , store * authorization.Store , tx kv.Tx ) {
353+ a := & influxdb.Authorization {
354+ ID : platform .ID (3 ),
355+ OrgID : platform .ID (3 ),
356+ UserID : platform .ID (3 ),
357+ Token : "Token#3" ,
358+ }
359+ require .NoError (t , store .CreateAuthorization (ctx , tx , a ))
360+ },
361+ exp : []authData {
362+ {ID : platform .ID (1 ), HashedToken : sha256 .MustHash ("Token#1" ).Encode ()},
363+ {ID : platform .ID (2 ), HashedToken : sha512 .MustHash ("Token#2" ).Encode ()},
364+ {ID : platform .ID (3 ), HashedToken : sha512 .MustHash ("Token#3" ).Encode ()},
365+ },
366+ hashedTokens : []string {"Token#1" , "Token#2" , "Token#3" },
367+ },
368+ }
369+
370+ ctx := context .Background ()
371+
372+ // The underlying kv store persists across tests cases. This allows for testing how opening with
373+ // new authentication configurations impacts the data.
374+ kvStore := inmem .NewKVStore ()
375+ err = all .Up (ctx , zaptest .NewLogger (t ), kvStore )
376+ require .NoError (t , err )
377+
378+ for _ , tc := range cases {
379+ t .Run (tc .desc , func (t * testing.T ) {
380+ // Create new authorization.Store for test cases using existing kvStore.
381+ variantName := tc .config .algo
382+ if variantName == "" {
383+ if ! tc .config .enabled {
384+ variantName = authorization .DefaultHashVariantName
385+ } else {
386+ require .Fail (t , "Must specific algo if hashing is enabled for test case" )
387+ }
388+ }
389+ store , err := authorization .NewStore (ctx , kvStore , tc .config .enabled , authorization .WithAuthorizationHashVariantName (variantName ))
390+ require .NoError (t , err )
391+ require .NotNil (t , store )
392+
393+ // Execute action, if given. Simply opening the store with a different configuration may be the "action".
394+ if tc .action != nil {
395+ err = kvStore .Update (ctx , func (tx kv.Tx ) error {
396+ tc .action (t , ctx , store , tx )
397+ return nil
398+ })
399+ require .NoError (t , err )
400+ }
401+
402+ // Check results.
403+ err = kvStore .View (ctx , func (tx kv.Tx ) error {
404+ // Collect all authorization data from store.
405+ storedAuths , err := store .ListAuthorizations (ctx , tx , influxdb.AuthorizationFilter {})
406+ require .NoError (t , err )
407+
408+ // Collect auth data from data currently in store
409+ actualAuthData := make ([]authData , 0 , len (storedAuths ))
410+ for _ , sa := range storedAuths {
411+ ad := authData {ID : sa .ID , Token : sa .Token , HashedToken : sa .HashedToken }
412+ actualAuthData = append (actualAuthData , ad )
413+ }
414+
415+ // Check that authData matches exp.
416+ require .ElementsMatch (t , tc .exp , actualAuthData )
417+
418+ // Collect data from kvStore's token index.
419+ collectIndex := func (indexName string ) map [string ]platform.ID {
420+ indexMap := make (map [string ]platform.ID )
421+ index , err := tx .Bucket ([]byte (indexName ))
422+ require .NoError (t , err )
423+ cursor , err := index .Cursor ()
424+ require .NoError (t , err )
425+ for k , v := cursor .First (); k != nil ; k , v = cursor .Next () {
426+ var id platform.ID
427+ require .NoError (t , id .Decode (v ))
428+ indexMap [string (k )] = id
429+ }
430+ return indexMap
431+ }
432+ actualTokenIndex := collectIndex (authIndexName )
433+ actualHashedIndex := collectIndex (hashedAuthIndexName )
434+
435+ // Collect expected token and hashed indices.
436+ expTokenIndex := make (map [string ]platform.ID )
437+ expHashedIndex := make (map [string ]platform.ID )
438+ for _ , d := range tc .exp {
439+ if d .Token != "" {
440+ expTokenIndex [d .Token ] = d .ID
441+ }
442+ if d .HashedToken != "" {
443+ expHashedIndex [d .HashedToken ] = d .ID
444+ }
445+ }
446+
447+ // Compare indices.
448+ require .Equal (t , expTokenIndex , actualTokenIndex )
449+ require .Equal (t , expHashedIndex , actualHashedIndex )
450+
451+ // Make sure we can lookup all tokens.
452+ var allTokens []string
453+ for _ , d := range tc .exp {
454+ if d .Token != "" {
455+ allTokens = append (allTokens , d .Token )
456+ }
457+ }
458+ allTokens = append (allTokens , tc .hashedTokens ... )
459+
460+ for _ , token := range allTokens {
461+ auth , err := store .GetAuthorizationByToken (ctx , tx , token )
462+ require .NoError (t , err , "error looking up token %q" , token )
463+ require .NotNil (t , auth )
464+ }
465+
466+ return nil
467+ })
468+ })
469+
470+ }
471+ }
0 commit comments