github.com/verrazzano/verrazzano@v1.7.0/authproxy/src/auth/token.go (about)

     1  // Copyright (c) 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package auth
     5  
     6  import (
     7  	"context"
     8  	"encoding/base64"
     9  	"encoding/json"
    10  	"fmt"
    11  	"net/http"
    12  	"strings"
    13  	"time"
    14  
    15  	"github.com/coreos/go-oidc/v3/oidc"
    16  )
    17  
    18  // AuthenticateToken verifies a given bearer token against the OIDC key and verifies the issuer is correct
    19  func (a *OIDCAuthenticator) AuthenticateToken(ctx context.Context, token string) (bool, error) {
    20  	verifier, err := a.loadVerifier()
    21  	if err != nil {
    22  		return false, err
    23  	}
    24  
    25  	idToken, err := verifier.Verify(ctx, token)
    26  	if err != nil {
    27  		a.Log.Errorf("Failed to verify JWT token: %v", err)
    28  		return false, err
    29  	}
    30  
    31  	// Do issuer check for external URL
    32  	// This is skipped in the go-oidc package because it could be the service or the ingress
    33  	if idToken.Issuer != a.oidcConfig.ExternalURL && idToken.Issuer != a.oidcConfig.ServiceURL {
    34  		err := fmt.Errorf("failed to verify issuer, got %s, expected %s or %s", idToken.Issuer, a.oidcConfig.ServiceURL, a.oidcConfig.ExternalURL)
    35  		a.Log.Errorf("Failed to validate JWT issuer: %v", err)
    36  		return false, err
    37  	}
    38  
    39  	return true, nil
    40  }
    41  
    42  // getTokenFromAuthHeader returns the bearer token from the authorization header
    43  func getTokenFromAuthHeader(authHeader string) (string, error) {
    44  	splitHeader := strings.SplitN(authHeader, " ", 3)
    45  
    46  	if len(splitHeader) < 2 || !strings.EqualFold(splitHeader[0], authTypeBearer) {
    47  		return "", fmt.Errorf("failed to verify authorization bearer header")
    48  	}
    49  
    50  	return splitHeader[1], nil
    51  }
    52  
    53  // initServiceOIDCVerifier creates an OIDC provider using the Service URL
    54  // and populates the authenticator with a verifier
    55  func (a *OIDCAuthenticator) initServiceOIDCVerifier() error {
    56  	if a.oidcConfig == nil {
    57  		err := fmt.Errorf("the OIDC config is not initialized")
    58  		a.Log.Errorf("Failed to set up token verifier: %v", err)
    59  		return err
    60  	}
    61  
    62  	provider, err := oidc.NewProvider(context.TODO(), a.oidcConfig.ServiceURL)
    63  	if err != nil {
    64  		a.Log.Errorf("Failed to load OIDC provider: %v", err)
    65  		return err
    66  	}
    67  
    68  	config := &oidc.Config{
    69  		ClientID:             a.oidcConfig.ClientID,
    70  		SkipIssuerCheck:      true,
    71  		SupportedSigningAlgs: []string{oidc.RS256},
    72  		Now:                  time.Now,
    73  	}
    74  
    75  	verifier := provider.Verifier(config)
    76  	a.verifier.Store(verifier)
    77  	return nil
    78  }
    79  
    80  // loadVerifier returns the stored value and casts it to a verifier object
    81  func (a *OIDCAuthenticator) loadVerifier() (verifier, error) {
    82  	vAny := a.verifier.Load()
    83  	if vAny == nil {
    84  		err := fmt.Errorf("nil verifier object")
    85  		a.Log.Errorf("Failed to load verifier: %v", err)
    86  	}
    87  
    88  	if vTyped, ok := vAny.(verifier); ok {
    89  		return vTyped, nil
    90  	}
    91  
    92  	err := fmt.Errorf("object does not implement the verifier interface")
    93  	a.Log.Errorf("Failed to load verifier: %v", err)
    94  	return nil, err
    95  }
    96  
    97  // GetImpersonationHeadersFromRequest returns the user and group fields from the bearer token to be used as
    98  // impersonation headers for the API server request
    99  func GetImpersonationHeadersFromRequest(req *http.Request) (ImpersonationHeaders, error) {
   100  	var headers ImpersonationHeaders
   101  
   102  	token, err := getTokenFromAuthHeader(req.Header.Get(authHeaderKey))
   103  	if err != nil {
   104  		return headers, err
   105  	}
   106  
   107  	jwtParts := strings.SplitN(token, ".", 3)
   108  	if len(jwtParts) != 3 {
   109  		return headers, fmt.Errorf("malformed jwt token, found %d sections", len(jwtParts))
   110  	}
   111  
   112  	payload, err := base64.RawURLEncoding.DecodeString(jwtParts[1])
   113  	if err != nil {
   114  		return headers, err
   115  	}
   116  
   117  	err = json.Unmarshal(payload, &headers)
   118  	if err != nil {
   119  		return headers, err
   120  	}
   121  
   122  	return headers, nil
   123  }