@@ -10,9 +10,12 @@ import (
10
10
"fmt"
11
11
"github.com/99designs/keyring"
12
12
"os"
13
+ "os/user"
13
14
"path/filepath"
14
15
"runtime"
16
+ "strconv"
15
17
"strings"
18
+ "sync"
16
19
"time"
17
20
)
18
21
@@ -44,7 +47,7 @@ type secureTokenSpec struct {
44
47
tokenType tokenType
45
48
}
46
49
47
- func (t * secureTokenSpec ) buildKey () string {
50
+ func (t * secureTokenSpec ) buildKey () ( string , error ) {
48
51
return buildCredentialsKey (t .host , t .user , t .tokenType )
49
52
}
50
53
@@ -80,9 +83,9 @@ func newSecureStorageManager() secureStorageManager {
80
83
logger .Debugf ("failed to create credentials cache dir. %v" , err )
81
84
return newNoopSecureStorageManager ()
82
85
}
83
- return ssm
86
+ return & threadSafeSecureStorageManager { & sync. Mutex {}, ssm }
84
87
case "darwin" , "windows" :
85
- return newKeyringBasedSecureStorageManager ()
88
+ return & threadSafeSecureStorageManager { & sync. Mutex {}, newKeyringBasedSecureStorageManager ()}
86
89
default :
87
90
logger .Infof ("OS %v does not support credentials cache" , runtime .GOOS )
88
91
return newNoopSecureStorageManager ()
@@ -171,8 +174,12 @@ func (ssm *fileBasedSecureStorageManager) getTokens(data map[string]any) map[str
171
174
}
172
175
173
176
func (ssm * fileBasedSecureStorageManager ) setCredential (tokenSpec * secureTokenSpec , value string ) {
174
- credentialsKey := tokenSpec .buildKey ()
175
- err := ssm .lockFile ()
177
+ credentialsKey , err := tokenSpec .buildKey ()
178
+ if err != nil {
179
+ logger .Warn (err )
180
+ return
181
+ }
182
+ err = ssm .lockFile ()
176
183
if err != nil {
177
184
logger .Warnf ("Set credential failed. Unable to lock cache. %v" , err )
178
185
return
@@ -241,8 +248,12 @@ func (ssm *fileBasedSecureStorageManager) unlockFile() {
241
248
}
242
249
243
250
func (ssm * fileBasedSecureStorageManager ) getCredential (tokenSpec * secureTokenSpec ) string {
244
- credentialsKey := tokenSpec .buildKey ()
245
- err := ssm .lockFile ()
251
+ credentialsKey , err := tokenSpec .buildKey ()
252
+ if err != nil {
253
+ logger .Warn (err )
254
+ return ""
255
+ }
256
+ err = ssm .lockFile ()
246
257
if err != nil {
247
258
logger .Warn ("Failed to lock credential cache file." )
248
259
return ""
@@ -294,12 +305,37 @@ func (ssm *fileBasedSecureStorageManager) ensurePermissions() error {
294
305
return nil
295
306
}
296
307
297
- func (ssm * fileBasedSecureStorageManager ) readTemporaryCacheFile () map [ string ] any {
298
- err := ssm . ensurePermissions ()
308
+ func (ssm * fileBasedSecureStorageManager ) ensureOwner ( filePath string ) error {
309
+ currentUser , err := user . Current ()
299
310
if err != nil {
311
+ return err
312
+ }
313
+ dirOwnerUid , err := provideFileOwner (filePath )
314
+ if err != nil && ! errors .Is (err , os .ErrNotExist ) {
315
+ return err
316
+ }
317
+ if errors .Is (err , os .ErrNotExist ) {
318
+ return nil
319
+ }
320
+ if strconv .Itoa (int (dirOwnerUid )) != currentUser .Uid {
321
+ return errors .New ("incorrect owner of " + ssm .credDirPath )
322
+ }
323
+ return nil
324
+ }
325
+
326
+ func (ssm * fileBasedSecureStorageManager ) readTemporaryCacheFile () map [string ]any {
327
+ if err := ssm .ensurePermissions (); err != nil {
300
328
logger .Warnf ("Failed to ensure permission for temporary cache file. %v.\n " , err )
301
329
return map [string ]any {}
302
330
}
331
+ if err := ssm .ensureOwner (ssm .credDirPath ); err != nil {
332
+ logger .Warn ("Failed to ensure owner for %v. %v" , ssm .credDirPath , err )
333
+ return map [string ]any {}
334
+ }
335
+ if err := ssm .ensureOwner (ssm .credFilePath ()); err != nil {
336
+ logger .Warn ("Failed to ensure owner for %v. %v" , ssm .credFilePath (), err )
337
+ return map [string ]any {}
338
+ }
303
339
304
340
jsonData , err := os .ReadFile (ssm .credFilePath ())
305
341
if err != nil {
@@ -317,8 +353,12 @@ func (ssm *fileBasedSecureStorageManager) readTemporaryCacheFile() map[string]an
317
353
}
318
354
319
355
func (ssm * fileBasedSecureStorageManager ) deleteCredential (tokenSpec * secureTokenSpec ) {
320
- credentialsKey := tokenSpec .buildKey ()
321
- err := ssm .lockFile ()
356
+ credentialsKey , err := tokenSpec .buildKey ()
357
+ if err != nil {
358
+ logger .Warn (err )
359
+ return
360
+ }
361
+ err = ssm .lockFile ()
322
362
if err != nil {
323
363
logger .Warnf ("Set credential failed. Unable to lock cache. %v" , err )
324
364
return
@@ -335,6 +375,14 @@ func (ssm *fileBasedSecureStorageManager) deleteCredential(tokenSpec *secureToke
335
375
}
336
376
337
377
func (ssm * fileBasedSecureStorageManager ) writeTemporaryCacheFile (cache map [string ]any ) error {
378
+ if err := ssm .ensureOwner (ssm .credDirPath ); err != nil {
379
+ return err
380
+ }
381
+ if err := ssm .ensureOwner (ssm .credFilePath ()); err != nil {
382
+ logger .Warn ("Failed to ensure owner for %v. %v" , ssm .credFilePath (), err )
383
+ return err
384
+ }
385
+
338
386
bytes , err := json .Marshal (cache )
339
387
if err != nil {
340
388
return fmt .Errorf ("failed to marshal credential cache map. %w" , err )
@@ -370,7 +418,11 @@ func (ssm *keyringSecureStorageManager) setCredential(tokenSpec *secureTokenSpec
370
418
if value == "" {
371
419
logger .Debug ("no token provided" )
372
420
} else {
373
- credentialsKey := tokenSpec .buildKey ()
421
+ credentialsKey , err := tokenSpec .buildKey ()
422
+ if err != nil {
423
+ logger .Warn (err )
424
+ return
425
+ }
374
426
if runtime .GOOS == "windows" {
375
427
ring , _ := keyring .Open (keyring.Config {
376
428
WinCredPrefix : strings .ToUpper (tokenSpec .host ),
@@ -401,7 +453,11 @@ func (ssm *keyringSecureStorageManager) setCredential(tokenSpec *secureTokenSpec
401
453
402
454
func (ssm * keyringSecureStorageManager ) getCredential (tokenSpec * secureTokenSpec ) string {
403
455
cred := ""
404
- credentialsKey := tokenSpec .buildKey ()
456
+ credentialsKey , err := tokenSpec .buildKey ()
457
+ if err != nil {
458
+ logger .Warn (err )
459
+ return ""
460
+ }
405
461
if runtime .GOOS == "windows" {
406
462
ring , _ := keyring .Open (keyring.Config {
407
463
WinCredPrefix : strings .ToUpper (tokenSpec .host ),
@@ -432,7 +488,11 @@ func (ssm *keyringSecureStorageManager) getCredential(tokenSpec *secureTokenSpec
432
488
}
433
489
434
490
func (ssm * keyringSecureStorageManager ) deleteCredential (tokenSpec * secureTokenSpec ) {
435
- credentialsKey := tokenSpec .buildKey ()
491
+ credentialsKey , err := tokenSpec .buildKey ()
492
+ if err != nil {
493
+ logger .Warn (err )
494
+ return
495
+ }
436
496
if runtime .GOOS == "windows" {
437
497
ring , _ := keyring .Open (keyring.Config {
438
498
WinCredPrefix : strings .ToUpper (tokenSpec .host ),
@@ -454,11 +514,17 @@ func (ssm *keyringSecureStorageManager) deleteCredential(tokenSpec *secureTokenS
454
514
}
455
515
}
456
516
457
- func buildCredentialsKey (host , user string , credType tokenType ) string {
517
+ func buildCredentialsKey (host , user string , credType tokenType ) (string , error ) {
518
+ if host == "" {
519
+ return "" , errors .New ("host is not provided to store in token cache, skipping" )
520
+ }
521
+ if user == "" {
522
+ return "" , errors .New ("user is not provided to store in token cache, skipping" )
523
+ }
458
524
plainCredKey := host + ":" + user + ":" + string (credType )
459
525
checksum := sha256 .New ()
460
526
checksum .Write ([]byte (plainCredKey ))
461
- return hex .EncodeToString (checksum .Sum (nil ))
527
+ return hex .EncodeToString (checksum .Sum (nil )), nil
462
528
}
463
529
464
530
type noopSecureStorageManager struct {
@@ -477,3 +543,26 @@ func (ssm *noopSecureStorageManager) getCredential(_ *secureTokenSpec) string {
477
543
478
544
func (ssm * noopSecureStorageManager ) deleteCredential (_ * secureTokenSpec ) {
479
545
}
546
+
547
+ type threadSafeSecureStorageManager struct {
548
+ mu * sync.Mutex
549
+ delegate secureStorageManager
550
+ }
551
+
552
+ func (ssm * threadSafeSecureStorageManager ) setCredential (tokenSpec * secureTokenSpec , value string ) {
553
+ ssm .mu .Lock ()
554
+ defer ssm .mu .Unlock ()
555
+ ssm .delegate .setCredential (tokenSpec , value )
556
+ }
557
+
558
+ func (ssm * threadSafeSecureStorageManager ) getCredential (tokenSpec * secureTokenSpec ) string {
559
+ ssm .mu .Lock ()
560
+ defer ssm .mu .Unlock ()
561
+ return ssm .delegate .getCredential (tokenSpec )
562
+ }
563
+
564
+ func (ssm * threadSafeSecureStorageManager ) deleteCredential (tokenSpec * secureTokenSpec ) {
565
+ ssm .mu .Lock ()
566
+ defer ssm .mu .Unlock ()
567
+ ssm .delegate .deleteCredential (tokenSpec )
568
+ }
0 commit comments