Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions authbridge/authlib/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,23 @@ type Config struct {
Listener ListenerConfig `yaml:"listener" json:"listener"`
Bypass BypassConfig `yaml:"bypass" json:"bypass"`
Routes RoutesConfig `yaml:"routes" json:"routes"`
Pipeline PipelineConfig `yaml:"pipeline" json:"pipeline"`
Stats StatsConfig `yaml:"stats" json:"stats"`
}

// PipelineConfig holds the plugin pipeline composition.
// If omitted (empty), default pipelines are used:
// inbound=[jwt-validation], outbound=[token-exchange].
type PipelineConfig struct {
Inbound PipelineStageConfig `yaml:"inbound" json:"inbound"`
Outbound PipelineStageConfig `yaml:"outbound" json:"outbound"`
}

// PipelineStageConfig lists the plugins for a pipeline stage in execution order.
type PipelineStageConfig struct {
Plugins []string `yaml:"plugins" json:"plugins"`
}

// InboundConfig holds JWT validation settings.
type InboundConfig struct {
JWKSURL string `yaml:"jwks_url" json:"jwks_url"`
Expand Down
27 changes: 27 additions & 0 deletions authbridge/authlib/plugins/defaults.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package plugins

import (
"github.com/kagenti/kagenti-extensions/authbridge/authlib/auth"
"github.com/kagenti/kagenti-extensions/authbridge/authlib/pipeline"
"github.com/kagenti/kagenti-extensions/authbridge/authlib/routing"
)

var (
DefaultInboundPlugins = []string{"jwt-validation"}
DefaultOutboundPlugins = []string{"token-exchange"}
)

func DefaultInboundPipeline(a *auth.Auth) (*pipeline.Pipeline, error) {
return Build(DefaultInboundPlugins, a)
}

func DefaultOutboundPipeline(a *auth.Auth) (*pipeline.Pipeline, error) {
return Build(DefaultOutboundPlugins, a)
}

// WaypointInboundPipeline creates an inbound pipeline for waypoint mode
// where audience is derived per-request from the destination host.
func WaypointInboundPipeline(a *auth.Auth) (*pipeline.Pipeline, error) {
jwtPlugin := NewJWTValidation(a, WithAudienceDeriver(routing.ServiceNameFromHost))
return pipeline.New([]pipeline.Plugin{jwtPlugin})
}
59 changes: 59 additions & 0 deletions authbridge/authlib/plugins/jwtvalidation.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package plugins

import (
"context"

"github.com/kagenti/kagenti-extensions/authbridge/authlib/auth"
"github.com/kagenti/kagenti-extensions/authbridge/authlib/pipeline"
)

// JWTValidation is a pipeline plugin that validates inbound JWTs.
// It delegates to auth.HandleInbound and populates pctx.Claims on success.
type JWTValidation struct {
auth *auth.Auth
audienceDeriver func(string) string
}

// JWTValidationOption configures the JWTValidation plugin.
type JWTValidationOption func(*JWTValidation)

// WithAudienceDeriver sets a function that derives the expected JWT audience
// from the request host. Used in waypoint mode where audience varies per-request.
func WithAudienceDeriver(f func(string) string) JWTValidationOption {
return func(j *JWTValidation) { j.audienceDeriver = f }
}

func NewJWTValidation(a *auth.Auth, opts ...JWTValidationOption) *JWTValidation {
p := &JWTValidation{auth: a}
for _, opt := range opts {
opt(p)
}
return p
}

func (p *JWTValidation) Name() string { return "jwt-validation" }

func (p *JWTValidation) Capabilities() pipeline.PluginCapabilities {
return pipeline.PluginCapabilities{Writes: []string{"security"}}
}

func (p *JWTValidation) OnRequest(ctx context.Context, pctx *pipeline.Context) pipeline.Action {
authHeader := pctx.Headers.Get("Authorization")
path := pctx.Path

var audience string
if p.audienceDeriver != nil {
audience = p.audienceDeriver(pctx.Host)
}

result := p.auth.HandleInbound(ctx, authHeader, path, audience)
if result.Action == auth.ActionDeny {
return pipeline.Action{Type: pipeline.Reject, Status: result.DenyStatus, Reason: result.DenyReason}
}
pctx.Claims = result.Claims
return pipeline.Action{Type: pipeline.Continue}
}

func (p *JWTValidation) OnResponse(_ context.Context, _ *pipeline.Context) pipeline.Action {
return pipeline.Action{Type: pipeline.Continue}
}
Loading
Loading