@@ -9,8 +9,10 @@ import (
9
9
"crypto/rsa"
10
10
"crypto/x509"
11
11
"encoding/pem"
12
+ "errors"
12
13
"fmt"
13
14
"github.com/oracle/oci-go-sdk/common"
15
+ "io/ioutil"
14
16
"net/http"
15
17
"os"
16
18
"strings"
@@ -21,10 +23,113 @@ import (
21
23
// federationClient is a client to retrieve the security token for an instance principal necessary to sign a request.
22
24
// It also provides the private key whose corresponding public key is used to retrieve the security token.
23
25
type federationClient interface {
26
+ ClaimHolder
24
27
PrivateKey () (* rsa.PrivateKey , error )
25
28
SecurityToken () (string , error )
26
29
}
27
30
31
+ // ClaimHolder is implemented by any token interface that provides access to the security claims embedded in the token.
32
+ type ClaimHolder interface {
33
+ GetClaim (key string ) (interface {}, error )
34
+ }
35
+
36
+ type genericFederationClient struct {
37
+ SessionKeySupplier sessionKeySupplier
38
+ RefreshSecurityToken func () (securityToken , error )
39
+
40
+ securityToken securityToken
41
+ mux sync.Mutex
42
+ }
43
+
44
+ var _ federationClient = & genericFederationClient {}
45
+
46
+ func (c * genericFederationClient ) PrivateKey () (* rsa.PrivateKey , error ) {
47
+ c .mux .Lock ()
48
+ defer c .mux .Unlock ()
49
+
50
+ if err := c .renewKeyAndSecurityTokenIfNotValid (); err != nil {
51
+ return nil , err
52
+ }
53
+ return c .SessionKeySupplier .PrivateKey (), nil
54
+ }
55
+
56
+ func (c * genericFederationClient ) SecurityToken () (token string , err error ) {
57
+ c .mux .Lock ()
58
+ defer c .mux .Unlock ()
59
+
60
+ if err = c .renewKeyAndSecurityTokenIfNotValid (); err != nil {
61
+ return "" , err
62
+ }
63
+ return c .securityToken .String (), nil
64
+ }
65
+
66
+ func (c * genericFederationClient ) renewKeyAndSecurityTokenIfNotValid () (err error ) {
67
+ if c .securityToken == nil || ! c .securityToken .Valid () {
68
+ if err = c .renewKeyAndSecurityToken (); err != nil {
69
+ return fmt .Errorf ("failed to renew security token: %s" , err .Error ())
70
+ }
71
+ }
72
+ return nil
73
+ }
74
+
75
+ func (c * genericFederationClient ) renewKeyAndSecurityToken () (err error ) {
76
+ common .Logf ("Renewing keys for file based security token at: %v\n " , time .Now ().Format ("15:04:05.000" ))
77
+ if err = c .SessionKeySupplier .Refresh (); err != nil {
78
+ return fmt .Errorf ("failed to refresh session key: %s" , err .Error ())
79
+ }
80
+
81
+ common .Logf ("Renewing security token at: %v\n " , time .Now ().Format ("15:04:05.000" ))
82
+ if c .securityToken , err = c .RefreshSecurityToken (); err != nil {
83
+ return fmt .Errorf ("failed to refresh security token key: %s" , err .Error ())
84
+ }
85
+ common .Logf ("Security token renewed at: %v\n " , time .Now ().Format ("15:04:05.000" ))
86
+ return nil
87
+ }
88
+
89
+ func (c * genericFederationClient ) GetClaim (key string ) (interface {}, error ) {
90
+ c .mux .Lock ()
91
+ defer c .mux .Unlock ()
92
+
93
+ if err := c .renewKeyAndSecurityTokenIfNotValid (); err != nil {
94
+ return nil , err
95
+ }
96
+ return c .securityToken .GetClaim (key )
97
+ }
98
+
99
+ func newFileBasedFederationClient (securityTokenPath string , supplier sessionKeySupplier ) (* genericFederationClient , error ) {
100
+ return & genericFederationClient {
101
+ SessionKeySupplier : supplier ,
102
+ RefreshSecurityToken : func () (token securityToken , err error ) {
103
+ var content []byte
104
+ if content , err = ioutil .ReadFile (securityTokenPath ); err != nil {
105
+ return nil , fmt .Errorf ("failed to read security token from :%s. Due to: %s" , securityTokenPath , err .Error ())
106
+ }
107
+
108
+ var newToken securityToken
109
+ if newToken , err = newInstancePrincipalToken (string (content )); err != nil {
110
+ return nil , fmt .Errorf ("failed to read security token from :%s. Due to: %s" , securityTokenPath , err .Error ())
111
+ }
112
+
113
+ return newToken , nil
114
+ },
115
+ }, nil
116
+ }
117
+
118
+ func newStaticFederationClient (sessionToken string , supplier sessionKeySupplier ) (* genericFederationClient , error ) {
119
+ var newToken securityToken
120
+ var err error
121
+ if newToken , err = newInstancePrincipalToken (string (sessionToken )); err != nil {
122
+ return nil , fmt .Errorf ("failed to read security token. Due to: %s" , err .Error ())
123
+ }
124
+
125
+ return & genericFederationClient {
126
+ SessionKeySupplier : supplier ,
127
+ RefreshSecurityToken : func () (token securityToken , err error ) {
128
+ return newToken , nil
129
+ },
130
+ }, nil
131
+ }
132
+
28
133
// x509FederationClient retrieves a security token from Auth service.
29
134
type x509FederationClient struct {
30
135
tenancyID string
@@ -197,6 +302,16 @@ func (c *x509FederationClient) getSecurityToken() (securityToken, error) {
197
302
return newInstancePrincipalToken (response .Token .Token )
198
303
}
199
304
305
+ func (c * x509FederationClient ) GetClaim (key string ) (interface {}, error ) {
306
+ c .mux .Lock ()
307
+ defer c .mux .Unlock ()
308
+
309
+ if err := c .renewSecurityTokenIfNotValid (); err != nil {
310
+ return nil , err
311
+ }
312
+ return c .securityToken .GetClaim (key )
313
+ }
314
+
200
315
type x509FederationRequest struct {
201
316
X509FederationDetails `contributesTo:"body"`
202
317
}
@@ -249,6 +364,103 @@ type sessionKeySupplier interface {
249
364
PublicKeyPemRaw () []byte
250
365
}
251
366
367
+ //genericKeySupplier implements sessionKeySupplier and provides an arbitrary refresh mechanism
368
+ type genericKeySupplier struct {
369
+ RefreshFn func () (* rsa.PrivateKey , []byte , error )
370
+
371
+ privateKey * rsa.PrivateKey
372
+ publicKeyPemRaw []byte
373
+ }
374
+
375
+ func (s genericKeySupplier ) PrivateKey () * rsa.PrivateKey {
376
+ if s .privateKey == nil {
377
+ return nil
378
+ }
379
+
380
+ c := * s .privateKey
381
+ return & c
382
+ }
383
+
384
+ func (s genericKeySupplier ) PublicKeyPemRaw () []byte {
385
+ if s .publicKeyPemRaw == nil {
386
+ return nil
387
+ }
388
+
389
+ c := make ([]byte , len (s .publicKeyPemRaw ))
390
+ copy (c , s .publicKeyPemRaw )
391
+ return c
392
+ }
393
+
394
+ func (s * genericKeySupplier ) Refresh () (err error ) {
395
+ privateKey , publicPem , err := s .RefreshFn ()
396
+ if err != nil {
397
+ return err
398
+ }
399
+
400
+ s .privateKey = privateKey
401
+ s .publicKeyPemRaw = publicPem
402
+ return nil
403
+ }
404
+
405
+ // create a sessionKeySupplier that reads keys from file every time it refreshes
406
+ func newFileBasedKeySessionSupplier (privateKeyPemPath string , passphrasePath * string ) (* genericKeySupplier , error ) {
407
+ return & genericKeySupplier {
408
+ RefreshFn : func () (* rsa.PrivateKey , []byte , error ) {
409
+ var err error
410
+ var passContent []byte
411
+ if passphrasePath != nil {
412
+ if passContent , err = ioutil .ReadFile (* passphrasePath ); err != nil {
413
+ return nil , nil , fmt .Errorf ("can not read passphrase from file: %s, due to %s" , * passphrasePath , err .Error ())
414
+ }
415
+ }
416
+
417
+ var keyPemContent []byte
418
+ if keyPemContent , err = ioutil .ReadFile (privateKeyPemPath ); err != nil {
419
+ return nil , nil , fmt .Errorf ("can not read private privateKey pem from file: %s, due to %s" , privateKeyPemPath , err .Error ())
420
+ }
421
+
422
+ var privateKey * rsa.PrivateKey
423
+ if privateKey , err = common .PrivateKeyFromBytesWithPassword (keyPemContent , passContent ); err != nil {
424
+ return nil , nil , fmt .Errorf ("can not create private privateKey from contents of: %s, due to: %s" , privateKeyPemPath , err .Error ())
425
+ }
426
+
427
+ var publicKeyAsnBytes []byte
428
+ if publicKeyAsnBytes , err = x509 .MarshalPKIXPublicKey (privateKey .Public ()); err != nil {
429
+ return nil , nil , fmt .Errorf ("failed to marshal the public part of the new keypair: %s" , err .Error ())
430
+ }
431
+ publicKeyPemRaw := pem .EncodeToMemory (& pem.Block {
432
+ Type : "PUBLIC KEY" ,
433
+ Bytes : publicKeyAsnBytes ,
434
+ })
435
+ return privateKey , publicKeyPemRaw , nil
436
+ },
437
+ }, nil
438
+ }
439
+
440
+ func newStaticKeySessionSupplier (privateKeyPemContent , passphrase []byte ) (* genericKeySupplier , error ) {
441
+ var err error
442
+ var privateKey * rsa.PrivateKey
443
+
444
+ if privateKey , err = common .PrivateKeyFromBytesWithPassword (privateKeyPemContent , passphrase ); err != nil {
445
+ return nil , fmt .Errorf ("can not create private privateKey, due to: %s" , err .Error ())
446
+ }
447
+
448
+ var publicKeyAsnBytes []byte
449
+ if publicKeyAsnBytes , err = x509 .MarshalPKIXPublicKey (privateKey .Public ()); err != nil {
450
+ return nil , fmt .Errorf ("failed to marshal the public part of the new keypair: %s" , err .Error ())
451
+ }
452
+ publicKeyPemRaw := pem .EncodeToMemory (& pem.Block {
453
+ Type : "PUBLIC KEY" ,
454
+ Bytes : publicKeyAsnBytes ,
455
+ })
456
+
457
+ return & genericKeySupplier {
458
+ RefreshFn : func () (key * rsa.PrivateKey , bytes []byte , err error ) {
459
+ return privateKey , publicKeyPemRaw , nil
460
+ },
461
+ }, nil
462
+ }
463
+
252
464
// inMemorySessionKeySupplier implements sessionKeySupplier to vend an RSA keypair.
253
465
// Refresh() generates a new RSA keypair with a random source, and keeps it in memory.
254
466
//
@@ -311,6 +523,8 @@ func (s *inMemorySessionKeySupplier) PublicKeyPemRaw() []byte {
311
523
type securityToken interface {
312
524
fmt.Stringer
313
525
Valid () bool
526
+
527
+ ClaimHolder
314
528
}
315
529
316
530
type instancePrincipalToken struct {
@@ -333,3 +547,15 @@ func (t *instancePrincipalToken) String() string {
333
547
func (t * instancePrincipalToken ) Valid () bool {
334
548
return ! t .jwtToken .expired ()
335
549
}
550
+
551
+ var (
552
+ // ErrNoSuchClaim is returned when a token does not hold the claim sought
553
+ ErrNoSuchClaim = errors .New ("no such claim" )
554
+ )
555
+
556
+ func (t * instancePrincipalToken ) GetClaim (key string ) (interface {}, error ) {
557
+ if value , ok := t .jwtToken .payload [key ]; ok {
558
+ return value , nil
559
+ }
560
+ return nil , ErrNoSuchClaim
561
+ }
0 commit comments