federation_client.go raw
1 // Copyright (c) 2016, 2018, 2025, Oracle and/or its affiliates. All rights reserved.
2 // This software is dual-licensed to you under the Universal Permissive License (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose either license.
3
4 // Package auth provides supporting functions and structs for authentication
5 package auth
6
7 import (
8 "context"
9 "crypto/rand"
10 "crypto/rsa"
11 "crypto/x509"
12 "encoding/pem"
13 "errors"
14 "fmt"
15 "io/ioutil"
16 "math"
17 "net/http"
18 "os"
19 "strings"
20 "sync"
21 "time"
22
23 "github.com/nrdcg/oci-go-sdk/common/v1065"
24 )
25
26 // federationClient is a client to retrieve the security token for an instance principal necessary to sign a request.
27 // It also provides the private key whose corresponding public key is used to retrieve the security token.
28 type federationClient interface {
29 ClaimHolder
30 PrivateKey() (*rsa.PrivateKey, error)
31 SecurityToken() (string, error)
32 }
33
34 // ClaimHolder is implemented by any token interface that provides access to the security claims embedded in the token.
35 type ClaimHolder interface {
36 GetClaim(key string) (interface{}, error)
37 }
38
39 type genericFederationClient struct {
40 SessionKeySupplier sessionKeySupplier
41 RefreshSecurityToken func() (securityToken, error)
42
43 securityToken securityToken
44 mux sync.Mutex
45 }
46
47 var _ federationClient = &genericFederationClient{}
48
49 func (c *genericFederationClient) PrivateKey() (*rsa.PrivateKey, error) {
50 c.mux.Lock()
51 defer c.mux.Unlock()
52
53 if err := c.renewKeyAndSecurityTokenIfNotValid(); err != nil {
54 return nil, err
55 }
56 return c.SessionKeySupplier.PrivateKey(), nil
57 }
58
59 func (c *genericFederationClient) SecurityToken() (token string, err error) {
60 c.mux.Lock()
61 defer c.mux.Unlock()
62
63 if err = c.renewKeyAndSecurityTokenIfNotValid(); err != nil {
64 return "", err
65 }
66 return c.securityToken.String(), nil
67 }
68
69 func (c *genericFederationClient) renewKeyAndSecurityTokenIfNotValid() (err error) {
70 if c.securityToken == nil || !c.securityToken.Valid() {
71 if err = c.renewKeyAndSecurityToken(); err != nil {
72 return fmt.Errorf("failed to renew security token: %s", err.Error())
73 }
74 }
75 return nil
76 }
77
78 func (c *genericFederationClient) renewKeyAndSecurityToken() (err error) {
79 common.Logf("Renewing keys for file based security token at: %v\n", time.Now().Format("15:04:05.000"))
80 if err = c.SessionKeySupplier.Refresh(); err != nil {
81 return fmt.Errorf("failed to refresh session key: %s", err.Error())
82 }
83
84 common.Logf("Renewing security token at: %v\n", time.Now().Format("15:04:05.000"))
85 if c.securityToken, err = c.RefreshSecurityToken(); err != nil {
86 return fmt.Errorf("failed to refresh security token key: %s", err.Error())
87 }
88 common.Logf("Security token renewed at: %v\n", time.Now().Format("15:04:05.000"))
89 return nil
90 }
91
92 func (c *genericFederationClient) GetClaim(key string) (interface{}, error) {
93 c.mux.Lock()
94 defer c.mux.Unlock()
95
96 if err := c.renewKeyAndSecurityTokenIfNotValid(); err != nil {
97 return nil, err
98 }
99 return c.securityToken.GetClaim(key)
100 }
101
102 func newFileBasedFederationClient(securityTokenPath string, supplier sessionKeySupplier) (*genericFederationClient, error) {
103 return &genericFederationClient{
104 SessionKeySupplier: supplier,
105 RefreshSecurityToken: func() (token securityToken, err error) {
106 var content []byte
107 if content, err = ioutil.ReadFile(securityTokenPath); err != nil {
108 return nil, fmt.Errorf("failed to read security token from :%s. Due to: %s", securityTokenPath, err.Error())
109 }
110
111 var newToken securityToken
112 if newToken, err = newPrincipalToken(string(content)); err != nil {
113 return nil, fmt.Errorf("failed to read security token from :%s. Due to: %s", securityTokenPath, err.Error())
114 }
115
116 return newToken, nil
117 },
118 }, nil
119 }
120
121 func newStaticFederationClient(sessionToken string, supplier sessionKeySupplier) (*genericFederationClient, error) {
122 var newToken securityToken
123 var err error
124 if newToken, err = newPrincipalToken(string(sessionToken)); err != nil {
125 return nil, fmt.Errorf("failed to read security token. Due to: %s", err.Error())
126 }
127
128 return &genericFederationClient{
129 SessionKeySupplier: supplier,
130 RefreshSecurityToken: func() (token securityToken, err error) {
131 return newToken, nil
132 },
133 }, nil
134 }
135
136 // oAuth2FederationClient retrieves a security token from the scoped OAuth endpoint in Auth Service
137 type oAuth2FederationClient struct {
138 sessionKeySupplier sessionKeySupplier
139 authClientKeyProvider common.KeyProvider
140 authClient *common.BaseClient
141 securityToken securityToken
142 lastRefresh time.Time
143 scope string
144 targetCompartment string
145 mux sync.Mutex
146 }
147
148 var OAuthTokenStaleWindow = 20 * time.Minute
149
150 // newOAuth2FederationClient creates a new oAuth2FederationClient from the provided configProvider and Auth request parameters
151 func newOAuth2FederationClient(configProvider common.ConfigurationProvider, scope string, targetCompartment string, sessionKeySupplier sessionKeySupplier) (federationClient, error) {
152 client := &oAuth2FederationClient{}
153 client.sessionKeySupplier = sessionKeySupplier
154 region, err := configProvider.Region()
155 if err != nil {
156 return nil, fmt.Errorf("failed to build OAuth Federation Client: %s", err.Error())
157 }
158 authClient := newAuthClient(common.StringToRegion(region), configProvider, "v1/oauth2/scoped")
159 client.authClient = authClient
160 client.authClientKeyProvider = configProvider
161 client.scope = scope
162 client.targetCompartment = targetCompartment
163 return client, nil
164 }
165
166 // KeyID calls the KeyID method of the auth provider given to the federation client
167 func (c *oAuth2FederationClient) KeyID() (string, error) {
168 return c.authClientKeyProvider.KeyID()
169 }
170
171 // PrivateRSAKey calls the PrivateRSAKey method of the auth provider given to the federation client
172 func (c *oAuth2FederationClient) PrivateRSAKey() (*rsa.PrivateKey, error) {
173 return c.authClientKeyProvider.PrivateRSAKey()
174 }
175
176 func (c *oAuth2FederationClient) GetClaim(key string) (interface{}, error) {
177 c.mux.Lock()
178 defer c.mux.Unlock()
179
180 if err := c.renewKeyAndSecurityTokenIfNotValid(); err != nil {
181 return nil, err
182 }
183 return c.securityToken.GetClaim(key)
184 }
185
186 // isTokenStale returns true if the JWT token is older than OAuthTokenStaleWindow
187 func (c *oAuth2FederationClient) isTokenStale() bool {
188 return c.lastRefresh.IsZero() || time.Now().After(c.lastRefresh.Add(OAuthTokenStaleWindow))
189 }
190
191 func (c *oAuth2FederationClient) renewKeyAndSecurityTokenIfNotValid() (err error) {
192 return c.renewSecurityTokenIfNotValid()
193 }
194
195 func (c *oAuth2FederationClient) renewSecurityTokenIfNotValid() (err error) {
196
197 // Get a new token if this one is stale (or nil), even if it is still valid
198 if c.securityToken == nil || c.isTokenStale() {
199 if err = c.renewSecurityToken(); err != nil {
200 if c.securityToken != nil && c.securityToken.Valid() {
201 // Token is stale but still valid. We failed to get a new token
202 // but we can still use the old one
203 common.Debugln("failed to refresh OAuth token. Using valid cached token")
204 return nil
205 }
206
207 return fmt.Errorf("failed to refresh token: %s", err.Error())
208 }
209 }
210
211 // Token exists and is not stale,
212 // or token was stale and a new one was retrieved
213 return nil
214 }
215
216 func (c *oAuth2FederationClient) renewSecurityToken() (err error) {
217 if err = c.sessionKeySupplier.Refresh(); err != nil {
218 return fmt.Errorf("failed to refresh session key: %s", err.Error())
219 }
220
221 common.Logf("Renewing security token at: %v\n", time.Now().Format("15:04:05.000"))
222 if newToken, err := c.getSecurityToken(); err != nil {
223 return fmt.Errorf("failed to get security token: %s", err.Error())
224 } else {
225 // only update token if a new one was retrieved.
226 c.lastRefresh = time.Now()
227 c.securityToken = newToken
228 }
229
230 common.Logf("Security token renewed at: %v\n", time.Now().Format("15:04:05.000"))
231
232 return nil
233
234 }
235
236 func (c *oAuth2FederationClient) getSecurityToken() (securityToken, error) {
237 var err error
238 var httpRequest http.Request
239 var httpResponse *http.Response
240 defer common.CloseBodyIfValid(httpResponse)
241 for retry := 0; retry < 3; retry++ {
242 request := c.makeOAuthFederationRequest()
243
244 if httpRequest, err = common.MakeDefaultHTTPRequestWithTaggedStruct(http.MethodPost, "", request); err != nil {
245 return nil, fmt.Errorf("failed to make http request: %s", err.Error())
246 }
247
248 if httpResponse, err = c.authClient.Call(context.Background(), &httpRequest); err == nil {
249 break
250 }
251 // Don't retry on 4xx errors
252 if httpResponse != nil && httpResponse.StatusCode >= 400 && httpResponse.StatusCode <= 499 {
253 return nil, fmt.Errorf("error %s returned by auth service: %s", httpResponse.Status, err.Error())
254 }
255 nextDuration := time.Duration(1000.0*(math.Pow(2.0, float64(retry)))) * time.Millisecond
256 time.Sleep(nextDuration)
257 }
258 if err != nil {
259 return nil, fmt.Errorf("failed to call: %s", err.Error())
260 }
261
262 response := oAuthFederationResponse{}
263 if err = common.UnmarshalResponse(httpResponse, &response); err != nil {
264 return nil, fmt.Errorf("failed to unmarshal the response: %s", err.Error())
265 }
266
267 return newPrincipalToken(response.Token.Token)
268
269 }
270
271 type oAuthFederationRequest struct {
272 OAuthFederationDetails `contributesTo:"body"`
273 }
274
275 // OAuthFederationDetails Scoped Oauth federation details
276 // The scope type should correspond to the type of config provider used to create
277 // the OAuth Federation Client
278 type OAuthFederationDetails struct {
279 Scope string `mandatory:"true" json:"scope,omitempty"`
280 PublicKey string `mandatory:"true" json:"public_key,omitempty"`
281 TargetCompartment string `mandatory:"true" json:"target_compartment,omitempty"`
282 }
283
284 type oAuthFederationResponse struct {
285 Token `presentIn:"body"`
286 }
287
288 func (c *oAuth2FederationClient) makeOAuthFederationRequest() *oAuthFederationRequest {
289 publicKey := sanitizeCertificateString(string(c.sessionKeySupplier.PublicKeyPemRaw()))
290 details := OAuthFederationDetails{
291 Scope: c.scope,
292 PublicKey: publicKey,
293 TargetCompartment: c.targetCompartment,
294 }
295 return &oAuthFederationRequest{details}
296 }
297
298 func (c *oAuth2FederationClient) PrivateKey() (*rsa.PrivateKey, error) {
299 c.mux.Lock()
300 defer c.mux.Unlock()
301
302 if err := c.renewSecurityTokenIfNotValid(); err != nil {
303 return nil, err
304 }
305 return c.sessionKeySupplier.PrivateKey(), nil
306 }
307
308 func (c *oAuth2FederationClient) SecurityToken() (token string, err error) {
309 c.mux.Lock()
310 defer c.mux.Unlock()
311
312 if err = c.renewSecurityTokenIfNotValid(); err != nil {
313 return "", err
314 }
315 return c.securityToken.String(), nil
316 }
317
318 // x509FederationClient retrieves a security token from Auth service.
319 type x509FederationClient struct {
320 tenancyID string
321 sessionKeySupplier sessionKeySupplier
322 leafCertificateRetriever x509CertificateRetriever
323 intermediateCertificateRetrievers []x509CertificateRetriever
324 securityToken securityToken
325 authClient *common.BaseClient
326 mux sync.Mutex
327 }
328
329 func newX509FederationClient(region common.Region, tenancyID string, leafCertificateRetriever x509CertificateRetriever, intermediateCertificateRetrievers []x509CertificateRetriever, modifier dispatcherModifier) (federationClient, error) {
330 client := &x509FederationClient{
331 tenancyID: tenancyID,
332 leafCertificateRetriever: leafCertificateRetriever,
333 intermediateCertificateRetrievers: intermediateCertificateRetrievers,
334 }
335 client.sessionKeySupplier = newSessionKeySupplier()
336 authClient := newAuthClient(region, client, "v1/x509")
337
338 var err error
339
340 if authClient.HTTPClient, err = modifier.Modify(authClient.HTTPClient); err != nil {
341 err = fmt.Errorf("failed to modify client: %s", err.Error())
342 return nil, err
343 }
344
345 client.authClient = authClient
346 return client, nil
347 }
348
349 func newX509FederationClientWithCerts(region common.Region, tenancyID string, leafCertificate, leafPassphrase, leafPrivateKey []byte, intermediateCertificates [][]byte, modifier dispatcherModifier) (federationClient, error) {
350 intermediateRetrievers := make([]x509CertificateRetriever, len(intermediateCertificates))
351 for i, c := range intermediateCertificates {
352 intermediateRetrievers[i] = &staticCertificateRetriever{Passphrase: []byte(""), CertificatePem: c, PrivateKeyPem: nil}
353 }
354
355 client := &x509FederationClient{
356 tenancyID: tenancyID,
357 leafCertificateRetriever: &staticCertificateRetriever{Passphrase: leafPassphrase, CertificatePem: leafCertificate, PrivateKeyPem: leafPrivateKey},
358 intermediateCertificateRetrievers: intermediateRetrievers,
359 }
360 client.sessionKeySupplier = newSessionKeySupplier()
361 authClient := newAuthClient(region, client, "v1/x509")
362
363 var err error
364
365 if authClient.HTTPClient, err = modifier.Modify(authClient.HTTPClient); err != nil {
366 err = fmt.Errorf("failed to modify client: %s", err.Error())
367 return nil, err
368 }
369
370 client.authClient = authClient
371 return client, nil
372 }
373
374 var (
375 genericHeaders = []string{"date", "(request-target)"} // "host" is not needed for the federation endpoint. Don't ask me why.
376 bodyHeaders = []string{"content-length", "content-type", "x-content-sha256"}
377 )
378
379 func newAuthClient(region common.Region, provider common.KeyProvider, authBasePath string) *common.BaseClient {
380 signer := common.RequestSigner(provider, genericHeaders, bodyHeaders)
381 client := common.DefaultBaseClientWithSigner(signer)
382
383 if regionURL, ok := os.LookupEnv("OCI_SDK_AUTH_CLIENT_REGION_URL"); ok {
384 client.Host = regionURL
385 } else {
386 client.Host = region.Endpoint("auth")
387 }
388 client.BasePath = authBasePath
389
390 if common.GlobalAuthClientCircuitBreakerSetting != nil {
391 client.Configuration.CircuitBreaker = common.NewCircuitBreaker(common.GlobalAuthClientCircuitBreakerSetting)
392 } else if !common.IsEnvVarFalse("OCI_SDK_AUTH_CLIENT_CIRCUIT_BREAKER_ENABLED") {
393 common.Logf("Configuring DefaultAuthClientCircuitBreakerSetting for federation client")
394 client.Configuration.CircuitBreaker = common.NewCircuitBreaker(common.DefaultAuthClientCircuitBreakerSetting())
395 }
396 return &client
397 }
398
399 // For authClient to sign requests to X509 Federation Endpoint
400 func (c *x509FederationClient) KeyID() (string, error) {
401 tenancy := c.tenancyID
402 fingerprint := fingerprint(c.leafCertificateRetriever.Certificate())
403 return fmt.Sprintf("%s/fed-x509-sha256/%s", tenancy, fingerprint), nil
404 }
405
406 // For authClient to sign requests to X509 Federation Endpoint
407 func (c *x509FederationClient) PrivateRSAKey() (*rsa.PrivateKey, error) {
408 key := c.leafCertificateRetriever.PrivateKey()
409 if key == nil {
410 return nil, fmt.Errorf("can not read private key from leaf certificate. Likely an error in the metadata service")
411 }
412
413 return key, nil
414 }
415
416 func (c *x509FederationClient) PrivateKey() (*rsa.PrivateKey, error) {
417 c.mux.Lock()
418 defer c.mux.Unlock()
419
420 if err := c.renewSecurityTokenIfNotValid(); err != nil {
421 return nil, err
422 }
423 return c.sessionKeySupplier.PrivateKey(), nil
424 }
425
426 func (c *x509FederationClient) SecurityToken() (token string, err error) {
427 c.mux.Lock()
428 defer c.mux.Unlock()
429
430 if err = c.renewSecurityTokenIfNotValid(); err != nil {
431 return "", err
432 }
433 return c.securityToken.String(), nil
434 }
435
436 func (c *x509FederationClient) renewSecurityTokenIfNotValid() (err error) {
437 if c.securityToken == nil || !c.securityToken.Valid() {
438 if err = c.renewSecurityToken(); err != nil {
439 return fmt.Errorf("failed to renew security token: %s", err.Error())
440 }
441 }
442 return nil
443 }
444
445 func (c *x509FederationClient) renewSecurityToken() (err error) {
446 if err = c.sessionKeySupplier.Refresh(); err != nil {
447 return fmt.Errorf("failed to refresh session key: %s", err.Error())
448 }
449
450 if err = c.leafCertificateRetriever.Refresh(); err != nil {
451 return fmt.Errorf("failed to refresh leaf certificate: %s", err.Error())
452 }
453
454 updatedTenancyID := extractTenancyIDFromCertificate(c.leafCertificateRetriever.Certificate())
455 if c.tenancyID != updatedTenancyID {
456 err = fmt.Errorf("unexpected update of tenancy OCID in the leaf certificate. Previous tenancy: %s, Updated: %s", c.tenancyID, updatedTenancyID)
457 return
458 }
459
460 for _, retriever := range c.intermediateCertificateRetrievers {
461 if err = retriever.Refresh(); err != nil {
462 return fmt.Errorf("failed to refresh intermediate certificate: %s", err.Error())
463 }
464 }
465
466 common.Logf("Renewing security token at: %v\n", time.Now().Format("15:04:05.000"))
467 if c.securityToken, err = c.getSecurityToken(); err != nil {
468 return fmt.Errorf("failed to get security token: %s", err.Error())
469 }
470 common.Logf("Security token renewed at: %v\n", time.Now().Format("15:04:05.000"))
471
472 return nil
473 }
474
475 func (c *x509FederationClient) getSecurityToken() (securityToken, error) {
476 var err error
477 var httpRequest http.Request
478 var httpResponse *http.Response
479 defer common.CloseBodyIfValid(httpResponse)
480
481 for retry := 0; retry < 3; retry++ {
482 request := c.makeX509FederationRequest()
483
484 if httpRequest, err = common.MakeDefaultHTTPRequestWithTaggedStruct(http.MethodPost, "", request); err != nil {
485 return nil, fmt.Errorf("failed to make http request: %s", err.Error())
486 }
487
488 if httpResponse, err = c.authClient.Call(context.Background(), &httpRequest); err == nil {
489 break
490 }
491 // Don't retry on 4xx errors
492 if httpResponse != nil && httpResponse.StatusCode >= 400 && httpResponse.StatusCode <= 499 {
493 return nil, fmt.Errorf("error %s returned by auth service: %s", httpResponse.Status, err.Error())
494 }
495 nextDuration := time.Duration(1000.0*(math.Pow(2.0, float64(retry)))) * time.Millisecond
496 time.Sleep(nextDuration)
497 }
498 if err != nil {
499 return nil, fmt.Errorf("failed to call: %s", err.Error())
500 }
501
502 response := x509FederationResponse{}
503 if err = common.UnmarshalResponse(httpResponse, &response); err != nil {
504 return nil, fmt.Errorf("failed to unmarshal the response: %s", err.Error())
505 }
506
507 return newPrincipalToken(response.Token.Token)
508 }
509
510 func (c *x509FederationClient) GetClaim(key string) (interface{}, error) {
511 c.mux.Lock()
512 defer c.mux.Unlock()
513
514 if err := c.renewSecurityTokenIfNotValid(); err != nil {
515 return nil, err
516 }
517 return c.securityToken.GetClaim(key)
518 }
519
520 type x509FederationRequest struct {
521 X509FederationDetails `contributesTo:"body"`
522 }
523
524 // X509FederationDetails x509 federation details
525 type X509FederationDetails struct {
526 Certificate string `mandatory:"true" json:"certificate,omitempty"`
527 PublicKey string `mandatory:"true" json:"publicKey,omitempty"`
528 IntermediateCertificates []string `mandatory:"false" json:"intermediateCertificates,omitempty"`
529 FingerprintAlgorithm string `mandatory:"false" json:"fingerprintAlgorithm,omitempty"`
530 }
531
532 type x509FederationResponse struct {
533 Token `presentIn:"body"`
534 }
535
536 // Token token
537 type Token struct {
538 Token string `mandatory:"true" json:"token,omitempty"`
539 }
540
541 func (c *x509FederationClient) makeX509FederationRequest() *x509FederationRequest {
542 certificate := c.sanitizeCertificateString(string(c.leafCertificateRetriever.CertificatePemRaw()))
543 publicKey := c.sanitizeCertificateString(string(c.sessionKeySupplier.PublicKeyPemRaw()))
544 var intermediateCertificates []string
545 for _, retriever := range c.intermediateCertificateRetrievers {
546 intermediateCertificates = append(intermediateCertificates, c.sanitizeCertificateString(string(retriever.CertificatePemRaw())))
547 }
548
549 details := X509FederationDetails{
550 Certificate: certificate,
551 PublicKey: publicKey,
552 IntermediateCertificates: intermediateCertificates,
553 FingerprintAlgorithm: "SHA256",
554 }
555 return &x509FederationRequest{details}
556 }
557
558 func (c *x509FederationClient) sanitizeCertificateString(certString string) string {
559 certString = strings.Replace(certString, "-----BEGIN CERTIFICATE-----", "", -1)
560 certString = strings.Replace(certString, "-----END CERTIFICATE-----", "", -1)
561 certString = strings.Replace(certString, "-----BEGIN PUBLIC KEY-----", "", -1)
562 certString = strings.Replace(certString, "-----END PUBLIC KEY-----", "", -1)
563 certString = strings.Replace(certString, "\n", "", -1)
564 return certString
565 }
566
567 // sessionKeySupplier provides an RSA keypair which can be re-generated by calling Refresh().
568 type sessionKeySupplier interface {
569 Refresh() error
570 PrivateKey() *rsa.PrivateKey
571 PublicKeyPemRaw() []byte
572 }
573
574 // genericKeySupplier implements sessionKeySupplier and provides an arbitrary refresh mechanism
575 type genericKeySupplier struct {
576 RefreshFn func() (*rsa.PrivateKey, []byte, error)
577
578 privateKey *rsa.PrivateKey
579 publicKeyPemRaw []byte
580 }
581
582 func (s genericKeySupplier) PrivateKey() *rsa.PrivateKey {
583 if s.privateKey == nil {
584 return nil
585 }
586
587 c := *s.privateKey
588 return &c
589 }
590
591 func (s genericKeySupplier) PublicKeyPemRaw() []byte {
592 if s.publicKeyPemRaw == nil {
593 return nil
594 }
595
596 c := make([]byte, len(s.publicKeyPemRaw))
597 copy(c, s.publicKeyPemRaw)
598 return c
599 }
600
601 func (s *genericKeySupplier) Refresh() (err error) {
602 privateKey, publicPem, err := s.RefreshFn()
603 if err != nil {
604 return err
605 }
606
607 s.privateKey = privateKey
608 s.publicKeyPemRaw = publicPem
609 return nil
610 }
611
612 // create a sessionKeySupplier that reads keys from file every time it refreshes
613 func newFileBasedKeySessionSupplier(privateKeyPemPath string, passphrasePath *string) (*genericKeySupplier, error) {
614 return &genericKeySupplier{
615 RefreshFn: func() (*rsa.PrivateKey, []byte, error) {
616 var err error
617 var passContent []byte
618 if passphrasePath != nil {
619 if passContent, err = ioutil.ReadFile(*passphrasePath); err != nil {
620 return nil, nil, fmt.Errorf("can not read passphrase from file: %s, due to %s", *passphrasePath, err.Error())
621 }
622 }
623
624 var keyPemContent []byte
625 if keyPemContent, err = ioutil.ReadFile(privateKeyPemPath); err != nil {
626 return nil, nil, fmt.Errorf("can not read private privateKey pem from file: %s, due to %s", privateKeyPemPath, err.Error())
627 }
628
629 var privateKey *rsa.PrivateKey
630 if privateKey, err = common.PrivateKeyFromBytesWithPassword(keyPemContent, passContent); err != nil {
631 return nil, nil, fmt.Errorf("can not create private privateKey from contents of: %s, due to: %s", privateKeyPemPath, err.Error())
632 }
633
634 var publicKeyAsnBytes []byte
635 if publicKeyAsnBytes, err = x509.MarshalPKIXPublicKey(privateKey.Public()); err != nil {
636 return nil, nil, fmt.Errorf("failed to marshal the public part of the new keypair: %s", err.Error())
637 }
638 publicKeyPemRaw := pem.EncodeToMemory(&pem.Block{
639 Type: "PUBLIC KEY",
640 Bytes: publicKeyAsnBytes,
641 })
642 return privateKey, publicKeyPemRaw, nil
643 },
644 }, nil
645 }
646
647 func newStaticKeySessionSupplier(privateKeyPemContent, passphrase []byte) (*genericKeySupplier, error) {
648 var err error
649 var privateKey *rsa.PrivateKey
650
651 if privateKey, err = common.PrivateKeyFromBytesWithPassword(privateKeyPemContent, passphrase); err != nil {
652 return nil, fmt.Errorf("can not create private privateKey, due to: %s", err.Error())
653 }
654
655 var publicKeyAsnBytes []byte
656 if publicKeyAsnBytes, err = x509.MarshalPKIXPublicKey(privateKey.Public()); err != nil {
657 return nil, fmt.Errorf("failed to marshal the public part of the new keypair: %s", err.Error())
658 }
659 publicKeyPemRaw := pem.EncodeToMemory(&pem.Block{
660 Type: "PUBLIC KEY",
661 Bytes: publicKeyAsnBytes,
662 })
663
664 return &genericKeySupplier{
665 RefreshFn: func() (key *rsa.PrivateKey, bytes []byte, err error) {
666 return privateKey, publicKeyPemRaw, nil
667 },
668 }, nil
669 }
670
671 // inMemorySessionKeySupplier implements sessionKeySupplier to vend an RSA keypair.
672 // Refresh() generates a new RSA keypair with a random source, and keeps it in memory.
673 //
674 // inMemorySessionKeySupplier is not thread-safe.
675 type inMemorySessionKeySupplier struct {
676 keySize int
677 privateKey *rsa.PrivateKey
678 publicKeyPemRaw []byte
679 }
680
681 // newSessionKeySupplier creates and returns a sessionKeySupplier instance which generates key pairs of size 2048.
682 func newSessionKeySupplier() sessionKeySupplier {
683 return &inMemorySessionKeySupplier{keySize: 2048}
684 }
685
686 // Refresh() is failure atomic, i.e., PrivateKey() and PublicKeyPemRaw() would return their previous values
687 // if Refresh() fails.
688 func (s *inMemorySessionKeySupplier) Refresh() (err error) {
689 common.Debugln("Refreshing session key")
690
691 var privateKey *rsa.PrivateKey
692 privateKey, err = rsa.GenerateKey(rand.Reader, s.keySize)
693 if err != nil {
694 return fmt.Errorf("failed to generate a new keypair: %s", err)
695 }
696
697 var publicKeyAsnBytes []byte
698 if publicKeyAsnBytes, err = x509.MarshalPKIXPublicKey(privateKey.Public()); err != nil {
699 return fmt.Errorf("failed to marshal the public part of the new keypair: %s", err.Error())
700 }
701 publicKeyPemRaw := pem.EncodeToMemory(&pem.Block{
702 Type: "PUBLIC KEY",
703 Bytes: publicKeyAsnBytes,
704 })
705
706 s.privateKey = privateKey
707 s.publicKeyPemRaw = publicKeyPemRaw
708 return nil
709 }
710
711 func (s *inMemorySessionKeySupplier) PrivateKey() *rsa.PrivateKey {
712 if s.privateKey == nil {
713 return nil
714 }
715
716 c := *s.privateKey
717 return &c
718 }
719
720 func (s *inMemorySessionKeySupplier) PublicKeyPemRaw() []byte {
721 if s.publicKeyPemRaw == nil {
722 return nil
723 }
724
725 c := make([]byte, len(s.publicKeyPemRaw))
726 copy(c, s.publicKeyPemRaw)
727 return c
728 }
729
730 type securityToken interface {
731 fmt.Stringer
732 Valid() bool
733
734 ClaimHolder
735 }
736
737 type principalToken struct {
738 tokenString string
739 jwtToken *jwtToken
740 }
741
742 func newPrincipalToken(tokenString string) (newToken securityToken, err error) {
743 var jwtToken *jwtToken
744 if jwtToken, err = parseJwt(tokenString); err != nil {
745 return nil, fmt.Errorf("failed to parse the token string \"%s\": %s", tokenString, err.Error())
746 }
747 return &principalToken{tokenString, jwtToken}, nil
748 }
749
750 func (t *principalToken) String() string {
751 return t.tokenString
752 }
753
754 func (t *principalToken) Valid() bool {
755 return !t.jwtToken.expired()
756 }
757
758 var (
759 // ErrNoSuchClaim is returned when a token does not hold the claim sought
760 ErrNoSuchClaim = errors.New("no such claim")
761 )
762
763 func (t *principalToken) GetClaim(key string) (interface{}, error) {
764 if value, ok := t.jwtToken.payload[key]; ok {
765 return value, nil
766 }
767 return nil, ErrNoSuchClaim
768 }
769