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