diff --git a/internal/bootstrap/service_bootstrap.go b/internal/bootstrap/service_bootstrap.go index e4383d44..acd5af01 100644 --- a/internal/bootstrap/service_bootstrap.go +++ b/internal/bootstrap/service_bootstrap.go @@ -49,36 +49,48 @@ func (app *BootstrapApp) setupServices() error { } func (app *BootstrapApp) getLabelProvider() (service.LabelProvider, error) { - if app.config.LabelProvider == "none" { - return nil, nil - } - - useKubernetes := app.config.LabelProvider == "kubernetes" || - (app.config.LabelProvider == "auto" && os.Getenv("KUBERNETES_SERVICE_HOST") != "") - - if useKubernetes { - app.log.App.Debug().Msg("Using Kubernetes label provider") - - kubernetesService, err := service.NewKubernetesService(app.log, app.ctx, &app.wg) - - if err != nil { - return nil, fmt.Errorf("failed to initialize kubernetes service: %w", err) + switch app.config.LabelProvider { + case "none", "docker", "kubernetes", "auto": + if app.config.LabelProvider == "none" { + return nil, nil } - app.services.kubernetesService = kubernetesService - return kubernetesService, nil + useKubernetes := app.config.LabelProvider == "kubernetes" || + (app.config.LabelProvider == "auto" && os.Getenv("KUBERNETES_SERVICE_HOST") != "") + + if useKubernetes { + app.log.App.Debug().Msg("Using Kubernetes label provider") + + kubernetesService, err := service.NewKubernetesService(app.log, app.ctx, &app.wg) + + if err != nil { + return nil, fmt.Errorf("failed to initialize kubernetes service: %w", err) + } + + app.services.kubernetesService = kubernetesService + return kubernetesService, nil + } + + app.log.App.Debug().Msg("Using Docker label provider") + + dockerService, err := service.NewDockerService(app.log, app.ctx, &app.wg) + + if err != nil { + return nil, fmt.Errorf("failed to initialize docker service: %w", err) + } + + if dockerService == nil { + if app.config.LabelProvider == "docker" { + app.log.App.Warn().Msg("Docker label provider selected but Docker is not available, will continue without it") + } + return nil, nil + } + + app.services.dockerService = dockerService + return dockerService, nil + default: + return nil, fmt.Errorf("invalid label provider: %s", app.config.LabelProvider) } - - app.log.App.Debug().Msg("Using Docker label provider") - - dockerService, err := service.NewDockerService(app.log, app.ctx, &app.wg) - - if err != nil { - return nil, fmt.Errorf("failed to initialize docker service: %w", err) - } - - app.services.dockerService = dockerService - return dockerService, nil } func (app *BootstrapApp) setupPolicyEngine() error { diff --git a/internal/service/access_control_rules_test.go b/internal/service/access_control_rules_test.go index 19917d52..16dde083 100644 --- a/internal/service/access_control_rules_test.go +++ b/internal/service/access_control_rules_test.go @@ -33,6 +33,16 @@ func TestUserAllowedRule(t *testing.T) { }, expected: EffectAbstain, }, + { + name: "abstains when user context is nil", + ctx: &ACLContext{ + ACLs: &model.App{ + OAuth: model.AppOAuth{Whitelist: "alice"}, + }, + UserContext: nil, + }, + expected: EffectAbstain, + }, { name: "allows OAuth user when email matches whitelist", ctx: &ACLContext{ @@ -204,6 +214,16 @@ func TestOAuthGroupRule(t *testing.T) { }, expected: EffectAbstain, }, + { + name: "abstains when user context is nil", + ctx: &ACLContext{ + ACLs: &model.App{ + OAuth: model.AppOAuth{Whitelist: "alice"}, + }, + UserContext: nil, + }, + expected: EffectAbstain, + }, { name: "abstains when user is not OAuth", ctx: &ACLContext{ @@ -324,6 +344,16 @@ func TestLDAPGroupRule(t *testing.T) { ctx: nil, expected: EffectAbstain, }, + { + name: "abstains when user context is nil", + ctx: &ACLContext{ + ACLs: &model.App{ + OAuth: model.AppOAuth{Whitelist: "alice"}, + }, + UserContext: nil, + }, + expected: EffectAbstain, + }, { name: "abstains when user is not LDAP", ctx: &ACLContext{ diff --git a/internal/service/access_controls_rules.go b/internal/service/access_controls_rules.go index eb060c95..93245c15 100644 --- a/internal/service/access_controls_rules.go +++ b/internal/service/access_controls_rules.go @@ -25,7 +25,7 @@ type UserAllowedRule struct { } func (rule *UserAllowedRule) Evaluate(ctx *ACLContext) Effect { - if ctx.ACLs == nil { + if ctx.ACLs == nil || ctx.UserContext == nil { return EffectAbstain } @@ -80,7 +80,7 @@ type OAuthGroupRule struct { } func (rule *OAuthGroupRule) Evaluate(ctx *ACLContext) Effect { - if ctx.ACLs == nil { + if ctx.ACLs == nil || ctx.UserContext == nil { return EffectAbstain } @@ -114,7 +114,7 @@ type LDAPGroupRule struct { } func (rule *LDAPGroupRule) Evaluate(ctx *ACLContext) Effect { - if ctx == nil { + if ctx == nil || ctx.UserContext == nil { return EffectAbstain } diff --git a/internal/service/access_controls_service.go b/internal/service/access_controls_service.go index bc5bbfb9..7ee5723a 100644 --- a/internal/service/access_controls_service.go +++ b/internal/service/access_controls_service.go @@ -31,19 +31,25 @@ func NewAccessControlsService( func (service *AccessControlsService) lookupStaticACLs(domain string) *model.App { var appAcls *model.App + + // first pass - try to find an exact match for the domain for app, config := range service.config.Apps { if config.Config.Domain == domain { service.log.App.Debug().Str("name", app).Msg("Found matching container by domain") appAcls = &config break // If we find a match by domain, we can stop searching } + } + // second pass - if we didn't find a match by domain, try to find a match by app name (subdomain) + for app, config := range service.config.Apps { if strings.SplitN(domain, ".", 2)[0] == app { service.log.App.Debug().Str("name", app).Msg("Found matching container by app name") appAcls = &config break // If we find a match by app name, we can stop searching } } + return appAcls } @@ -57,7 +63,7 @@ func (service *AccessControlsService) GetAccessControls(domain string) (*model.A } // If we have a label provider configured, try to get ACLs from it - if service.labelProvider != nil { + if service.labelProvider != nil && *service.labelProvider != nil { return (*service.labelProvider).GetLabels(domain) } diff --git a/internal/service/docker_service.go b/internal/service/docker_service.go index 9d077c53..e1d4b877 100644 --- a/internal/service/docker_service.go +++ b/internal/service/docker_service.go @@ -85,12 +85,16 @@ func (docker *DockerService) GetLabels(appDomain string) (*model.App, error) { return nil, err } - for appName, appLabels := range labels.Apps { + // fist pass - try to find an exact match for the domain + for _, appLabels := range labels.Apps { if appLabels.Config.Domain == appDomain { docker.log.App.Debug().Str("id", inspect.ID).Str("name", inspect.Name).Msg("Found matching container by domain") return &appLabels, nil } + } + // second pass - if we didn't find a match by domain, try to find a match by app name (subdomain) + for appName, appLabels := range labels.Apps { if strings.SplitN(appDomain, ".", 2)[0] == appName { docker.log.App.Debug().Str("id", inspect.ID).Str("name", inspect.Name).Msg("Found matching container by app name") return &appLabels, nil