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
79 changes: 59 additions & 20 deletions internal/service/access_controls_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

type LabelProvider interface {
GetLabels(appDomain string) (*model.App, error)
Lookup(locator func(name string, app *model.App) bool) error
}

type AccessControlsService struct {
Expand All @@ -37,35 +37,74 @@ func NewAccessControlsService(i AccessControlServiceInput) *AccessControlsServic
}
}

func (service *AccessControlsService) lookupStaticACLs(domain string) *model.App {
var nameMatch *model.App

func (service *AccessControlsService) getACLs(domain string, lookup func(locator func(name string, app *model.App) bool) error) (*model.App, error) {
v := validators.NewDomainValidator(validators.DomainValidatorOptions{})

// First try to find a matching app by domain, then fallback to matching by app name (subdomain)
for app, config := range service.config.Apps {
if config.Config.Domain != "" {
err := v.Validate(config.Config.Domain, domain)
var domainMatch *model.App
var nameMatch *model.App
var nameMatchedApps []string

locatorFunc := func(name string, app *model.App) bool {
if app.Config.Domain != "" {
err := v.Validate(app.Config.Domain, domain)
if err == nil {
service.log.App.Debug().Str("name", app).Msg("Found matching container by domain")
return &config
}
if !errors.Is(err, validators.ErrHostnameMismatch) {
service.log.App.Debug().Str("name", app).Err(err).Msg("Domain validation failed")
service.log.App.Debug().Str("name", name).Msg("Found matching container by domain")
domainMatch = app
return true
} else if !errors.Is(err, validators.ErrHostnameMismatch) {
service.log.App.Debug().Str("name", name).Err(err).Msg("Domain validation failed")
}
}
if strings.HasPrefix(strings.ToLower(domain), strings.ToLower(app+".")) {
service.log.App.Debug().Str("name", app).Msg("Found matching container by app name")
nameMatch = &config
if strings.HasPrefix(strings.ToLower(domain), strings.ToLower(name+".")) {
service.log.App.Debug().Str("name", name).Msg("Found matching container by app name")
nameMatch = app
nameMatchedApps = append(nameMatchedApps, name)
}
return false
}

return nameMatch
err := lookup(locatorFunc)
if err != nil {
return nil, err
}

if domainMatch != nil {
service.log.App.Debug().Str("domain", domain).Msg("Found matching app by domain")
return domainMatch, nil
}

if nameMatch == nil {
service.log.App.Debug().Str("domain", domain).Msg("No match found for domain, skipping")
return nil, nil
}

if len(nameMatchedApps) > 1 {
service.log.App.Warn().Str("domain", domain).Strs("apps", nameMatchedApps).Msg("Multiple apps matched domain by name, app names must be unique, using last match")
}

service.log.App.Debug().Str("domain", domain).Msg("Found matching app by app name")
return nameMatch, nil
}

func (service *AccessControlsService) lookupStaticACLs(domain string) (*model.App, error) {
return service.getACLs(domain, func(locator func(name string, app *model.App) bool) error {
for app, config := range service.config.Apps {
if ok := locator(app, &config); ok {
return nil
}
}
return nil
})
}

func (service *AccessControlsService) GetAccessControls(domain string) (*model.App, error) {
// First check in the static config
app := service.lookupStaticACLs(domain)
app, err := service.lookupStaticACLs(domain)

// Will never return an error here, but we need to check it
if err != nil {
return nil, err
}

if app != nil {
service.log.App.Debug().Msg("Using static ACLs for app")
Expand All @@ -74,9 +113,9 @@ 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 {
return service.labelProvider.GetLabels(domain)
return service.getACLs(domain, service.labelProvider.Lookup)
}

// no labels
// No labels
return nil, nil
}
Loading