// Package authenticate is a pomerium service that handles user authentication // and refersh (AuthN). package authenticate import ( "context" "errors" "fmt" oteltrace "go.opentelemetry.io/otel/trace" "github.com/pomerium/pomerium/config" "github.com/pomerium/pomerium/internal/atomicutil" "github.com/pomerium/pomerium/internal/log" "github.com/pomerium/pomerium/pkg/cryptutil" "github.com/pomerium/pomerium/pkg/telemetry/trace" ) // ValidateOptions checks that configuration are complete and valid. // Returns on first error found. func ValidateOptions(o *config.Options) error { sharedKey, err := o.GetSharedKey() if err != nil { return fmt.Errorf("authenticate: 'SHARED_SECRET' invalid: %w", err) } if _, err := cryptutil.NewAEADCipher(sharedKey); err != nil { return fmt.Errorf("authenticate: 'SHARED_SECRET' invalid: %w", err) } cookieSecret, err := o.GetCookieSecret() if err != nil { return fmt.Errorf("authenticate: 'COOKIE_SECRET' invalid: %w", err) } if _, err := cryptutil.NewAEADCipher(cookieSecret); err != nil { return fmt.Errorf("authenticate: 'COOKIE_SECRET' invalid %w", err) } if o.AuthenticateCallbackPath == "" { return errors.New("authenticate: 'AUTHENTICATE_CALLBACK_PATH' is required") } return nil } // Authenticate contains data required to run the authenticate service. type Authenticate struct { cfg *authenticateConfig options *atomicutil.Value[*config.Options] state *atomicutil.Value[*authenticateState] tracerProvider oteltrace.TracerProvider tracer oteltrace.Tracer } // New validates and creates a new authenticate service from a set of Options. func New(ctx context.Context, cfg *config.Config, options ...Option) (*Authenticate, error) { authenticateConfig := getAuthenticateConfig(options...) tracerProvider := trace.NewTracerProvider(ctx, "Authenticate") tracer := tracerProvider.Tracer(trace.PomeriumCoreTracer) a := &Authenticate{ cfg: authenticateConfig, options: config.NewAtomicOptions(), state: atomicutil.NewValue(newAuthenticateState()), tracerProvider: tracerProvider, tracer: tracer, } a.options.Store(cfg.Options) state, err := newAuthenticateStateFromConfig(ctx, tracerProvider, cfg, authenticateConfig) if err != nil { return nil, err } a.state.Store(state) return a, nil } // OnConfigChange updates internal structures based on config.Options func (a *Authenticate) OnConfigChange(ctx context.Context, cfg *config.Config) { if a == nil { return } a.options.Store(cfg.Options) if state, err := newAuthenticateStateFromConfig(ctx, a.tracerProvider, cfg, a.cfg); err != nil { log.Ctx(ctx).Error().Err(err).Msg("authenticate: failed to update state") } else { a.state.Store(state) } }