Skip to content

Commit 9d008ea

Browse files
committed
chore: variety of minor fixes
Address PR issues on comments, error handling, and add final token matching check in `Store.GetAuthorizationByToken`.
1 parent 7eb9430 commit 9d008ea

File tree

12 files changed

+146
-159
lines changed

12 files changed

+146
-159
lines changed

authorization/hasher.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,11 @@ func (h *AuthorizationHasher) AllHashes(token string) ([]string, error) {
113113
for idx, h := range h.allHashers {
114114
digest, err := h.Hash(token)
115115
if err != nil {
116-
return nil, fmt.Errorf("hashing raw token failed: %w", err)
116+
variantName := "N/A"
117+
if influxdb_hasher, ok := h.(*influxdb2_algo.Hasher); ok {
118+
variantName = influxdb_hasher.Variant().Prefix()
119+
}
120+
return nil, fmt.Errorf("hashing raw token failed (variant=%s): %w", variantName, err)
117121
}
118122
hashes[idx] = digest.Encode()
119123
}

authorization/http_server_test.go

Lines changed: 32 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,10 @@ func TestService_handlePostAuthorization(t *testing.T) {
158158
router.Mount(handler.Prefix(), handler)
159159

160160
req, err := newPostAuthorizationRequest(tt.args.authorization)
161-
if err != nil {
162-
t.Fatalf("failed to create new authorization request: %v", err)
163-
}
161+
require.NoError(t, err)
162+
164163
b, err := json.Marshal(req)
165-
if err != nil {
166-
t.Fatalf("failed to unmarshal authorization: %v", err)
167-
}
164+
require.NoError(t, err)
168165

169166
r := httptest.NewRequest("GET", "http://any.url", bytes.NewReader(b))
170167
r = r.WithContext(context.WithValue(
@@ -185,21 +182,16 @@ func TestService_handlePostAuthorization(t *testing.T) {
185182
handler.handlePostAuthorization(w, r)
186183

187184
res := w.Result()
188-
content := res.Header.Get("Content-Type")
185+
contentType := res.Header.Get("Content-Type")
189186
body, _ := io.ReadAll(res.Body)
190187

191-
if res.StatusCode != tt.wants.statusCode {
192-
t.Logf("headers: %v body: %s", res.Header, body)
193-
t.Errorf("%q. handlePostAuthorization() = %v, want %v", tt.name, res.StatusCode, tt.wants.statusCode)
194-
}
195-
if tt.wants.contentType != "" && content != tt.wants.contentType {
196-
t.Errorf("%q. handlePostAuthorization() = %v, want %v", tt.name, content, tt.wants.contentType)
197-
}
198-
if diff, err := jsonDiff(string(body), tt.wants.body); diff != "" {
199-
t.Errorf("%q. handlePostAuthorization() = ***%s***", tt.name, diff)
200-
} else if err != nil {
201-
t.Errorf("%q, handlePostAuthorization() error: %v", tt.name, err)
188+
require.Equalf(t, tt.wants.statusCode, res.StatusCode, "headers: %v body: %s", res.Header, body)
189+
if tt.wants.contentType != "" {
190+
require.Equal(t, tt.wants.contentType, contentType)
202191
}
192+
diff, err := jsonDiff(string(body), tt.wants.body)
193+
require.NoError(t, err)
194+
require.Empty(t, diff)
203195
})
204196
}
205197
}
@@ -353,21 +345,16 @@ func TestService_handleGetAuthorization(t *testing.T) {
353345
handler.handleGetAuthorization(w, r)
354346

355347
res := w.Result()
356-
content := res.Header.Get("Content-Type")
348+
contentType := res.Header.Get("Content-Type")
357349
body, _ := io.ReadAll(res.Body)
358350

359-
if res.StatusCode != tt.wants.statusCode {
360-
t.Logf("headers: %v body: %s", res.Header, body)
361-
t.Errorf("%q. handleGetAuthorization() = %v, want %v", tt.name, res.StatusCode, tt.wants.statusCode)
362-
}
363-
if tt.wants.contentType != "" && content != tt.wants.contentType {
364-
t.Errorf("%q. handleGetAuthorization() = %v, want %v", tt.name, content, tt.wants.contentType)
365-
}
366-
if diff, err := jsonDiff(string(body), tt.wants.body); err != nil {
367-
t.Errorf("%q, handleGetAuthorization. error unmarshalling json %v", tt.name, err)
368-
} else if tt.wants.body != "" && diff != "" {
369-
t.Errorf("%q. handleGetAuthorization() = -got/+want %s**", tt.name, diff)
351+
require.Equalf(t, tt.wants.statusCode, res.StatusCode, "headers: %v body: %s", res.Header, body)
352+
if tt.wants.contentType != "" {
353+
require.Equal(t, tt.wants.contentType, contentType)
370354
}
355+
diff, err := jsonDiff(string(body), tt.wants.body)
356+
require.NoError(t, err)
357+
require.Empty(t, diff)
371358
})
372359
}
373360
}
@@ -719,9 +706,7 @@ func TestService_handleGetAuthorizations(t *testing.T) {
719706
s := itesting.NewTestInmemStore(t)
720707

721708
storage, err := NewStore(context.Background(), s, useHashedTokens)
722-
if err != nil {
723-
t.Fatal(err)
724-
}
709+
require.NoError(t, err)
725710

726711
svc := NewService(storage, tt.fields.TenantService)
727712

@@ -744,21 +729,16 @@ func TestService_handleGetAuthorizations(t *testing.T) {
744729
handler.handleGetAuthorizations(w, r)
745730

746731
res := w.Result()
747-
content := res.Header.Get("Content-Type")
732+
contentType := res.Header.Get("Content-Type")
748733
body, _ := io.ReadAll(res.Body)
749734

750-
if res.StatusCode != tt.wants.statusCode {
751-
t.Errorf("%q. handleGetAuthorizations() = %v, want %v", tt.name, res.StatusCode, tt.wants.statusCode)
752-
}
753-
if tt.wants.contentType != "" && content != tt.wants.contentType {
754-
t.Errorf("%q. handleGetAuthorizations() = %v, want %v", tt.name, content, tt.wants.contentType)
735+
require.Equal(t, tt.wants.statusCode, res.StatusCode)
736+
if tt.wants.contentType != "" {
737+
require.Equal(t, tt.wants.contentType, contentType)
755738
}
756-
if diff, err := jsonDiff(string(body), tt.wants.body); diff != "" {
757-
t.Errorf("%q. handleGetAuthorizations() = ***%s***", tt.name, diff)
758-
} else if err != nil {
759-
t.Errorf("%q, handleGetAuthorizations() error: %v", tt.name, err)
760-
}
761-
739+
diff, err := jsonDiff(string(body), tt.wants.body)
740+
require.NoError(t, err)
741+
require.Empty(t, diff)
762742
})
763743
}
764744
}
@@ -846,22 +826,18 @@ func TestService_handleDeleteAuthorization(t *testing.T) {
846826
handler.handleDeleteAuthorization(w, r)
847827

848828
res := w.Result()
849-
content := res.Header.Get("Content-Type")
829+
contentType := res.Header.Get("Content-Type")
850830
body, _ := io.ReadAll(res.Body)
851831

852-
if res.StatusCode != tt.wants.statusCode {
853-
t.Errorf("%q. handleDeleteAuthorization() = %v, want %v", tt.name, res.StatusCode, tt.wants.statusCode)
854-
}
855-
if tt.wants.contentType != "" && content != tt.wants.contentType {
856-
t.Errorf("%q. handleDeleteAuthorization() = %v, want %v", tt.name, content, tt.wants.contentType)
832+
require.Equal(t, tt.wants.statusCode, res.StatusCode)
833+
if tt.wants.contentType != "" {
834+
require.Equal(t, tt.wants.contentType, contentType)
857835
}
858836

859837
if tt.wants.body != "" {
860-
if diff, err := jsonDiff(string(body), tt.wants.body); err != nil {
861-
t.Errorf("%q, handleDeleteAuthorization(). error unmarshalling json %v", tt.name, err)
862-
} else if diff != "" {
863-
t.Errorf("%q. handleDeleteAuthorization() = ***%s***", tt.name, diff)
864-
}
838+
diff, err := jsonDiff(string(body), tt.wants.body)
839+
require.NoError(t, err)
840+
require.Empty(t, diff)
865841
}
866842
})
867843
}

authorization/storage.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ The implementation has the following behaviors under different scenarios:
5454
the hash algorithm (e.g. `SHA-512``) instead of the hashed token value.
5555
* Downgrading to an older InfluxDB without hashed token support with a BoltDB containing hashed tokens.
5656
* Downgrading requires a manual `influxd downgrade` command. If hashed tokens are found in the
57-
BoltDB, user configuration is required. The user can also list impacted tokens. When downgrade is
57+
BoltDB, user confirmation is required. The user can also list impacted tokens. When downgrade is
5858
complete, all hashed tokens have been deleted from BoltDB along with their indices. The tokens with
5959
deleted hashes are no longer useable.
6060
* Operations are as usual in InfluxDB 2.7.
@@ -78,7 +78,7 @@ When token hashing is enabled and a backup is restored, raw tokens are hashed be
7878
into BoltDB. Raw tokens are not stored.
7979
8080
To verify tokens when hashed tokens are enabled, the presented token's hash is calculated and used
81-
for the token index lookup. The rest of the authorization flow is unchanged.
81+
for token index lookup. The rest of the authorization flow is unchanged.
8282
8383
To verify tokens when hashed tokens are disabled, the an attempt is made to parse the presented token as
8484
PHC. If the parse succeeds, the access is denied. This prevents an attack described below. After this check,
@@ -100,7 +100,7 @@ can not be used.
100100
A potential future security would be optionally storing "peppered" hashes. This would require retrieving
101101
the pepper key from outside of BoltDB, for example from Vault.
102102
103-
When listing tokens, hashed tokens are listed of "REDACTED" instead of the hashed
103+
When listing tokens, hashed tokens are listed as "REDACTED" instead of the hashed
104104
token value. Raw token values are returned as in previous versions.
105105
106106
---*/
@@ -277,7 +277,7 @@ func (s *Store) hashedTokenMigration(ctx context.Context) error {
277277

278278
for batch := range slices.Chunk(authsNeedingUpdate, 100) {
279279
err := s.Update(ctx, func(tx kv.Tx) error {
280-
// Now update them. This really seems too simple, but s.UpdateJAuthorization() is magical.
280+
// Now update them. This really seems too simple, but s.UpdateAuthorization() is magical.
281281
for _, a := range batch {
282282
if _, err := s.UpdateAuthorization(ctx, tx, a.ID, a); err != nil {
283283
return err

authorization/storage_authorization.go

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717

1818
var (
1919
ErrHashedTokenMismatch = goerrors.New("HashedToken does not match Token")
20+
ErrIncorrectToken = goerrors.New("token is incorrect for authorization")
21+
ErrNoTokenAvailable = goerrors.New("no token available for authorization")
2022
)
2123

2224
func authIndexKey(n string) []byte {
@@ -175,6 +177,25 @@ func (s *Store) GetAuthorizationByID(ctx context.Context, tx kv.Tx, id platform.
175177
return a, nil
176178
}
177179

180+
// validateToken checks if token matches tht token stored in auth. If auth.Token is set, that is
181+
// compared first. Otherwise, auth.HashedToken is used to verify token. If neither field in auth is set, then
182+
// the comparison fails.
183+
func (s *Store) validateToken(auth *influxdb.Authorization, token string) (bool, error) {
184+
if auth.Token != "" {
185+
return auth.Token == token, nil
186+
}
187+
188+
if auth.HashedToken != "" {
189+
match, err := s.hasher.Match(auth.HashedToken, token)
190+
if err != nil {
191+
return false, fmt.Errorf("error matching hashed token for validation: %w", err)
192+
}
193+
return match, nil
194+
}
195+
196+
return false, ErrNoTokenAvailable
197+
}
198+
178199
// GetAuthorizationsByToken searches for an authorization by its raw (unhashed) token value. It will also search
179200
// for entires with equivalent hashed tokens if the raw token is not directly found.
180201
func (s *Store) GetAuthorizationByToken(ctx context.Context, tx kv.Tx, token string) (auth *influxdb.Authorization, retErr error) {
@@ -246,7 +267,26 @@ func (s *Store) GetAuthorizationByToken(ctx context.Context, tx kv.Tx, token str
246267
}
247268
}
248269

249-
return s.GetAuthorizationByID(ctx, tx, id)
270+
// Verify that the token stored in auth matches the requested token. This should be superfluous check, but
271+
// we will just in case somehow the authorization record got out of sync with the index.
272+
auth, err = s.GetAuthorizationByID(ctx, tx, id)
273+
if err != nil {
274+
return nil, &errors.Error{
275+
Code: errors.EInternal,
276+
Err: err,
277+
}
278+
}
279+
match, err := s.validateToken(auth, token)
280+
if err != nil {
281+
return nil, &errors.Error{
282+
Code: errors.EInternal,
283+
Err: err,
284+
}
285+
}
286+
if !match {
287+
return nil, errors.EIncorrectPassword
288+
}
289+
return auth, nil
250290
}
251291

252292
// ListAuthorizations returns all the authorizations matching a set of FindOptions. This function is used for
@@ -310,11 +350,11 @@ func (s *Store) forEachAuthorization(ctx context.Context, tx kv.Tx, pred kv.Curs
310350
// returned on success.
311351
func (s *Store) commitAuthorization(ctx context.Context, tx kv.Tx, a *influxdb.Authorization) error {
312352
if err := s.verifyTokensMatch(a); err != nil {
313-
return err
353+
return errors.ErrInternalServiceError(err, errors.WithErrorCode(errors.EInvalid))
314354
}
315355

316356
if err := s.hashToken(a); err != nil {
317-
return err
357+
return errors.ErrInternalServiceError(err, errors.WithErrorCode(errors.EInternal))
318358
}
319359

320360
v, err := s.encodeAuthorization(a)
@@ -330,33 +370,33 @@ func (s *Store) commitAuthorization(ctx context.Context, tx kv.Tx, a *influxdb.A
330370
if !s.useHashedTokens && a.Token != "" {
331371
idx, err := authIndexBucket(tx)
332372
if err != nil {
333-
return err
373+
return errors.ErrInternalServiceError(err, errors.WithErrorCode(errors.EInternal))
334374
}
335375

336376
if err := idx.Put(authIndexKey(a.Token), encodedID); err != nil {
337-
return err
377+
return errors.ErrInternalServiceError(err, errors.WithErrorCode(errors.EInternal))
338378
}
339379
}
340380

341381
if a.HashedToken != "" {
342382
idx, err := hashedAuthIndexBucket(tx)
343383
// Don't ignore a missing index here, we want an error.
344384
if err != nil {
345-
return err
385+
return errors.ErrInternalServiceError(err, errors.WithErrorCode(errors.EInternal))
346386
}
347387

348388
if err := idx.Put(hashedAuthIndexKey(a.HashedToken), encodedID); err != nil {
349-
return err
389+
return errors.ErrInternalServiceError(err, errors.WithErrorCode(errors.EInternal))
350390
}
351391
}
352392

353393
b, err := tx.Bucket(authBucket)
354394
if err != nil {
355-
return err
395+
return errors.ErrInternalServiceError(err, errors.WithErrorCode(errors.EInternal))
356396
}
357397

358398
if err := b.Put(encodedID, v); err != nil {
359-
return err
399+
return errors.ErrInternalServiceError(err, errors.WithErrorCode(errors.EInternal))
360400
}
361401

362402
return nil

authorization/storage_authorization_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,7 @@ func TestAuthorizationStore_HashingConfigChanges(t *testing.T) {
465465

466466
return nil
467467
})
468+
require.NoError(t, err)
468469
})
469470

470471
}

authorizer/task_test.go

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,7 @@ func TestOnboardingValidation(t *testing.T) {
3838
Bucket: "holder",
3939
RetentionPeriodSeconds: 1,
4040
})
41-
if err != nil {
42-
t.Fatal(err)
43-
}
41+
require.NoError(t, err)
4442

4543
ctx := pctx.SetAuthorizer(context.Background(), r.Auth)
4644

@@ -53,9 +51,7 @@ func TestOnboardingValidation(t *testing.T) {
5351
}
5452
from(bucket:"holder") |> range(start:-5m) |> to(bucket:"holder", org:"thing")`,
5553
})
56-
if err != nil {
57-
t.Fatal(err)
58-
}
54+
require.NoError(t, err)
5955
})
6056
}
6157
}
@@ -146,22 +142,18 @@ func runTestValidations(useHashedTokens bool, t *testing.T) {
146142
Bucket: "holder",
147143
RetentionPeriodSeconds: 1,
148144
})
149-
if err != nil {
150-
t.Fatal(err)
151-
}
145+
require.NoError(t, err)
152146

153-
if err := svc.CreateOrganization(context.Background(), otherOrg); err != nil {
154-
t.Fatal(err)
155-
}
147+
err = svc.CreateOrganization(context.Background(), otherOrg)
148+
require.NoError(t, err)
156149

157150
otherBucket := &influxdb.Bucket{
158151
Name: "other_bucket",
159152
OrgID: otherOrg.ID,
160153
}
161154

162-
if err = svc.CreateBucket(context.Background(), otherBucket); err != nil {
163-
t.Fatal(err)
164-
}
155+
err = svc.CreateBucket(context.Background(), otherBucket)
156+
require.NoError(t, err)
165157

166158
var (
167159
orgID = r.Org.ID
@@ -611,9 +603,8 @@ func newStore(t *testing.T) kv.Store {
611603

612604
store := inmem.NewKVStore()
613605

614-
if err := all.Up(context.Background(), zaptest.NewLogger(t), store); err != nil {
615-
t.Fatal(err)
616-
}
606+
err := all.Up(context.Background(), zaptest.NewLogger(t), store)
607+
require.NoError(t, err)
617608

618609
return store
619610
}

0 commit comments

Comments
 (0)