github.com/verrazzano/verrazzano@v1.7.1/authproxy/src/auth/login.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  	"crypto/rand"
     9  	"crypto/x509"
    10  	"encoding/base64"
    11  	"fmt"
    12  	"net/http"
    13  
    14  	"github.com/coreos/go-oidc/v3/oidc"
    15  	"github.com/verrazzano/verrazzano/authproxy/internal/httputil"
    16  	"github.com/verrazzano/verrazzano/pkg/certs"
    17  	"golang.org/x/oauth2"
    18  	"k8s.io/client-go/util/cert"
    19  )
    20  
    21  // initExternalOIDCProvider initializes the external URL based OIDC Provider in the given Authenticator
    22  func (a *OIDCAuthenticator) initExternalOIDCProvider() error {
    23  	ctx, err := a.createContextWithHTTPClient()
    24  	if err != nil {
    25  		return err
    26  	}
    27  	provider, err := oidc.NewProvider(ctx, a.oidcConfig.ExternalURL)
    28  	if err != nil {
    29  		return err
    30  	}
    31  	a.ExternalProvider = provider
    32  	return nil
    33  }
    34  
    35  // createContextWithHTTPClient creates a context with the correct certificates and
    36  // client to redirect to the OIDC provider
    37  func (a *OIDCAuthenticator) createContextWithHTTPClient() (context.Context, error) {
    38  	caBundleData, err := certs.GetLocalClusterCABundleData(a.Log, a.k8sClient, context.TODO())
    39  	if err != nil {
    40  		return nil, err
    41  	}
    42  	var certPool *x509.CertPool
    43  	if caBundleData != nil {
    44  		if certPool, err = cert.NewPoolFromBytes(caBundleData); err != nil {
    45  			return nil, err
    46  		}
    47  	}
    48  
    49  	httpClient := httputil.GetHTTPClientWithCABundle(certPool)
    50  	ctx := context.Background()
    51  	return context.WithValue(ctx, oauth2.HTTPClient, httpClient.HTTPClient), nil
    52  }
    53  
    54  // performLoginRedirect redirects the incoming request to the OIDC provider
    55  func (a *OIDCAuthenticator) performLoginRedirect(req *http.Request, rw http.ResponseWriter) error {
    56  	var state string
    57  	var nonce string
    58  	var err error
    59  	if state, err = randomBase64(32); err != nil {
    60  		return fmt.Errorf("could not redirect for login - failed to generate random base64: %v", err)
    61  	}
    62  	if nonce, err = randomBase64(32); err != nil {
    63  		return fmt.Errorf("could not redirect for login - failed to generate random base64: %v", err)
    64  	}
    65  
    66  	oauthConfig := oauth2.Config{
    67  		ClientID:    a.oidcConfig.ClientID,
    68  		Endpoint:    a.ExternalProvider.Endpoint(),
    69  		RedirectURL: a.oidcConfig.CallbackURL,
    70  		Scopes:      []string{oidc.ScopeOpenID, "profile", "email"},
    71  	}
    72  	http.Redirect(rw, req, oauthConfig.AuthCodeURL(state, oidc.Nonce(nonce)), http.StatusFound)
    73  	return nil
    74  }
    75  
    76  // randomBase64 returns a random base64-encoded string of the given size
    77  func randomBase64(size int) (string, error) {
    78  	b := make([]byte, size)
    79  	if _, err := rand.Read(b); err != nil {
    80  		return "", err
    81  	}
    82  	return base64.RawURLEncoding.EncodeToString(b), nil
    83  }