Ctrl K
ComunidadGuías…

proxy/state.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package proxy

import (
	"context"
	"net/http"
	"net/url"

	"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
	oteltrace "go.opentelemetry.io/otel/trace"
	googlegrpc "google.golang.org/grpc"

	"github.com/pomerium/pomerium/config"
	"github.com/pomerium/pomerium/internal/authenticateflow"
	"github.com/pomerium/pomerium/pkg/endpoints"
	"github.com/pomerium/pomerium/pkg/grpc"
	"github.com/pomerium/pomerium/pkg/grpc/databroker"
	"github.com/pomerium/pomerium/pkg/storage"
)

type authenticateFlow interface {
	AuthenticateSignInURL(ctx context.Context, queryParams url.Values, redirectURL *url.URL, idpID string, additionalHosts []string) (string, error)
	Callback(w http.ResponseWriter, r *http.Request) error
}

type proxyState struct {
	authenticateURL          *url.URL
	authenticateDashboardURL *url.URL

	sharedKey                           []byte
	sessionStore                        *config.SessionStore
	dataBrokerClient                    databroker.DataBrokerServiceClient
	programmaticRedirectDomainWhitelist []string
	authenticateFlow                    authenticateFlow
	incomingIDPTokenSessionCreator      config.IncomingIDPTokenSessionCreator
	idpResolver                         *config.IdentityProviderResolver
}

func newProxyStateFromConfig(ctx context.Context, previousState *proxyState, tracerProvider oteltrace.TracerProvider, cfg *config.Config, outboundGrpcConn *grpc.CachedOutboundGRPClientConn) (*proxyState, error) {
	err := ValidateOptions(cfg.Options)
	if err != nil {
		return nil, err
	}

	state := new(proxyState)

	state.authenticateURL, err = cfg.Options.GetAuthenticateURL()
	if err != nil {
		return nil, err
	}
	state.authenticateDashboardURL = state.authenticateURL.ResolveReference(&url.URL{Path: endpoints.PathPomeriumDashboard + "/"})

	state.sharedKey, err = cfg.Options.GetSharedKey()
	if err != nil {
		return nil, err
	}

	state.sessionStore, err = config.NewSessionStore(cfg.Options)
	if err != nil {
		return nil, err
	}

	cacheInvalidator := databroker.NewCacheInvalidator(storage.GlobalCache)
	dataBrokerConn, err := outboundGrpcConn.Get(
		ctx,
		&grpc.OutboundOptions{
			OutboundPort: cfg.OutboundPort,
			SignedJWTKey: state.sharedKey,
		},
		googlegrpc.WithStatsHandler(otelgrpc.NewClientHandler(otelgrpc.WithTracerProvider(tracerProvider))),
		googlegrpc.WithChainUnaryInterceptor(cacheInvalidator.UnaryClientInterceptor),
		googlegrpc.WithChainStreamInterceptor(cacheInvalidator.StreamClientInterceptor),
	)
	if err != nil {
		return nil, err
	}
	state.dataBrokerClient = databroker.NewDataBrokerServiceClient(dataBrokerConn)

	state.programmaticRedirectDomainWhitelist = cfg.Options.ProgrammaticRedirectDomainWhitelist

	if cfg.Options.UseStatelessAuthenticateFlow() {
		state.authenticateFlow, err = authenticateflow.NewStateless(ctx, tracerProvider,
			cfg, state.sessionStore, nil, nil, nil, outboundGrpcConn)
	} else {
		state.authenticateFlow, err = authenticateflow.NewStateful(ctx, tracerProvider, cfg, state.sessionStore, outboundGrpcConn)
	}
	if err != nil {
		return nil, err
	}

	// Built here, off the request path, reusing the previous generation's resolver
	// when nothing it is built from changed. It cannot fail; a provider that could
	// not be built rejects only the tokens of its own issuer (see
	// newAuthorizeStateFromConfig for the reasoning).
	var previousIDPResolver *config.IdentityProviderResolver
	if previousState != nil {
		previousIDPResolver = previousState.idpResolver
	}
	state.idpResolver = config.NewIdentityProviderResolverFromConfig(ctx, cfg, previousIDPResolver)

	state.incomingIDPTokenSessionCreator = config.NewIncomingIDPTokenSessionCreator(
		tracerProvider,
		func(ctx context.Context, recordType, recordID string) (*databroker.Record, error) {
			return storage.GetDataBrokerRecord(ctx, recordType, recordID, 0)
		},
		func(ctx context.Context, records []*databroker.Record) error {
			_, err := state.dataBrokerClient.Put(ctx, &databroker.PutRequest{
				Records: records,
			})
			if err != nil {
				return err
			}
			storage.InvalidateCacheForDataBrokerRecords(ctx, records...)
			return err
		},
		config.WithIdentityProviderResolver(state.idpResolver),
	)

	return state, nil
}