mirror of
https://github.com/h44z/wg-portal.git
synced 2025-07-21 20:47:00 +00:00
add retry handling for auth provider setup (#484)
This commit is contained in:
parent
a6d985d3ce
commit
1794b8653a
@ -87,6 +87,7 @@ func main() {
|
|||||||
|
|
||||||
authenticator, err := auth.NewAuthenticator(&cfg.Auth, cfg.Web.ExternalUrl, eventBus, userManager)
|
authenticator, err := auth.NewAuthenticator(&cfg.Auth, cfg.Web.ExternalUrl, eventBus, userManager)
|
||||||
internal.AssertNoError(err)
|
internal.AssertNoError(err)
|
||||||
|
authenticator.StartBackgroundJobs(ctx)
|
||||||
|
|
||||||
webAuthn, err := auth.NewWebAuthnAuthenticator(cfg, eventBus, userManager)
|
webAuthn, err := auth.NewWebAuthnAuthenticator(cfg, eventBus, userManager)
|
||||||
internal.AssertNoError(err)
|
internal.AssertNoError(err)
|
||||||
|
@ -93,6 +93,8 @@ type Authenticator struct {
|
|||||||
// URL prefix for the callback endpoints, this is a combination of the external URL and the API prefix
|
// URL prefix for the callback endpoints, this is a combination of the external URL and the API prefix
|
||||||
callbackUrlPrefix string
|
callbackUrlPrefix string
|
||||||
|
|
||||||
|
callbackUrl *url.URL
|
||||||
|
|
||||||
users UserManager
|
users UserManager
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,82 +104,136 @@ func NewAuthenticator(cfg *config.Auth, extUrl string, bus EventBus, users UserM
|
|||||||
error,
|
error,
|
||||||
) {
|
) {
|
||||||
a := &Authenticator{
|
a := &Authenticator{
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
bus: bus,
|
bus: bus,
|
||||||
users: users,
|
users: users,
|
||||||
callbackUrlPrefix: fmt.Sprintf("%s/api/v0", extUrl),
|
callbackUrlPrefix: fmt.Sprintf("%s/api/v0", extUrl),
|
||||||
|
oauthAuthenticators: make(map[string]AuthenticatorOauth, len(cfg.OpenIDConnect)+len(cfg.OAuth)),
|
||||||
|
ldapAuthenticators: make(map[string]AuthenticatorLdap, len(cfg.Ldap)),
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
parsedExtUrl, err := url.Parse(a.callbackUrlPrefix)
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
err := a.setupExternalAuthProviders(ctx)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, fmt.Errorf("failed to parse external URL: %w", err)
|
||||||
}
|
}
|
||||||
|
a.callbackUrl = parsedExtUrl
|
||||||
|
|
||||||
return a, nil
|
return a, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Authenticator) setupExternalAuthProviders(ctx context.Context) error {
|
// StartBackgroundJobs starts the background jobs for the authenticator.
|
||||||
extUrl, err := url.Parse(a.callbackUrlPrefix)
|
// It sets up the external authentication providers (OIDC, OAuth, LDAP) and retries in case of errors.
|
||||||
if err != nil {
|
func (a *Authenticator) StartBackgroundJobs(ctx context.Context) {
|
||||||
return fmt.Errorf("failed to parse external url: %w", err)
|
go func() {
|
||||||
}
|
// Initialize local copies of authentication providers to allow retry in case of errors
|
||||||
|
oidcQueue := a.cfg.OpenIDConnect
|
||||||
|
oauthQueue := a.cfg.OAuth
|
||||||
|
ldapQueue := a.cfg.Ldap
|
||||||
|
|
||||||
a.oauthAuthenticators = make(map[string]AuthenticatorOauth, len(a.cfg.OpenIDConnect)+len(a.cfg.OAuth))
|
ticker := time.NewTicker(30 * time.Second) // Ticker for delay between retries
|
||||||
a.ldapAuthenticators = make(map[string]AuthenticatorLdap, len(a.cfg.Ldap))
|
defer ticker.Stop()
|
||||||
|
|
||||||
for i := range a.cfg.OpenIDConnect { // OIDC
|
for {
|
||||||
providerCfg := &a.cfg.OpenIDConnect[i]
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
failedOidc, failedOauth, failedLdap := a.setupExternalAuthProviders(oidcQueue, oauthQueue, ldapQueue)
|
||||||
|
if len(failedOidc) > 0 || len(failedOauth) > 0 || len(failedLdap) > 0 {
|
||||||
|
slog.Warn("failed to setup some external auth providers, retrying in 30 seconds",
|
||||||
|
"failedOidc", len(failedOidc), "failedOauth", len(failedOauth), "failedLdap", len(failedLdap))
|
||||||
|
// Retry failed providers
|
||||||
|
oidcQueue = failedOidc
|
||||||
|
oauthQueue = failedOauth
|
||||||
|
ldapQueue = failedLdap
|
||||||
|
} else {
|
||||||
|
slog.Info("successfully setup all external auth providers")
|
||||||
|
return // Exit goroutine if all providers are set up successfully
|
||||||
|
}
|
||||||
|
case <-ctx.Done():
|
||||||
|
slog.Info("context cancelled, stopping setup of external auth providers")
|
||||||
|
return // Exit goroutine if context is cancelled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Authenticator) setupExternalAuthProviders(
|
||||||
|
oidc []config.OpenIDConnectProvider,
|
||||||
|
oauth []config.OAuthProvider,
|
||||||
|
ldap []config.LdapProvider,
|
||||||
|
) (
|
||||||
|
[]config.OpenIDConnectProvider,
|
||||||
|
[]config.OAuthProvider,
|
||||||
|
[]config.LdapProvider,
|
||||||
|
) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
var failedOidc []config.OpenIDConnectProvider
|
||||||
|
var failedOauth []config.OAuthProvider
|
||||||
|
var failedLdap []config.LdapProvider
|
||||||
|
|
||||||
|
for i := range oidc { // OIDC
|
||||||
|
providerCfg := &oidc[i]
|
||||||
providerId := strings.ToLower(providerCfg.ProviderName)
|
providerId := strings.ToLower(providerCfg.ProviderName)
|
||||||
|
|
||||||
if _, exists := a.oauthAuthenticators[providerId]; exists {
|
if _, exists := a.oauthAuthenticators[providerId]; exists {
|
||||||
return fmt.Errorf("auth provider with name %s is already registerd", providerId)
|
// this is an unrecoverable error, we cannot register the same provider twice
|
||||||
|
slog.Error("OIDC auth provider is already registered", "name", providerId)
|
||||||
|
continue // skip this provider
|
||||||
}
|
}
|
||||||
|
|
||||||
redirectUrl := *extUrl
|
redirectUrl := *a.callbackUrl
|
||||||
redirectUrl.Path = path.Join(redirectUrl.Path, "/auth/login/", providerId, "/callback")
|
redirectUrl.Path = path.Join(redirectUrl.Path, "/auth/login/", providerId, "/callback")
|
||||||
|
|
||||||
provider, err := newOidcAuthenticator(ctx, redirectUrl.String(), providerCfg)
|
provider, err := newOidcAuthenticator(ctx, redirectUrl.String(), providerCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to setup oidc authentication provider %s: %w", providerCfg.ProviderName, err)
|
failedOidc = append(failedOidc, oidc[i])
|
||||||
|
slog.Error("failed to setup oidc authentication provider", "name", providerId, "error", err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
a.oauthAuthenticators[providerId] = provider
|
a.oauthAuthenticators[providerId] = provider
|
||||||
}
|
}
|
||||||
for i := range a.cfg.OAuth { // PLAIN OAUTH
|
for i := range oauth { // PLAIN OAUTH
|
||||||
providerCfg := &a.cfg.OAuth[i]
|
providerCfg := &oauth[i]
|
||||||
providerId := strings.ToLower(providerCfg.ProviderName)
|
providerId := strings.ToLower(providerCfg.ProviderName)
|
||||||
|
|
||||||
if _, exists := a.oauthAuthenticators[providerId]; exists {
|
if _, exists := a.oauthAuthenticators[providerId]; exists {
|
||||||
return fmt.Errorf("auth provider with name %s is already registerd", providerId)
|
// this is an unrecoverable error, we cannot register the same provider twice
|
||||||
|
slog.Error("OAUTH auth provider is already registered", "name", providerId)
|
||||||
|
continue // skip this provider
|
||||||
}
|
}
|
||||||
|
|
||||||
redirectUrl := *extUrl
|
redirectUrl := *a.callbackUrl
|
||||||
redirectUrl.Path = path.Join(redirectUrl.Path, "/auth/login/", providerId, "/callback")
|
redirectUrl.Path = path.Join(redirectUrl.Path, "/auth/login/", providerId, "/callback")
|
||||||
|
|
||||||
provider, err := newPlainOauthAuthenticator(ctx, redirectUrl.String(), providerCfg)
|
provider, err := newPlainOauthAuthenticator(ctx, redirectUrl.String(), providerCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to setup oauth authentication provider %s: %w", providerId, err)
|
failedOauth = append(failedOauth, oauth[i])
|
||||||
|
slog.Error("failed to setup oauth authentication provider", "name", providerId, "error", err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
a.oauthAuthenticators[providerId] = provider
|
a.oauthAuthenticators[providerId] = provider
|
||||||
}
|
}
|
||||||
for i := range a.cfg.Ldap { // LDAP
|
for i := range ldap { // LDAP
|
||||||
providerCfg := &a.cfg.Ldap[i]
|
providerCfg := &ldap[i]
|
||||||
providerId := strings.ToLower(providerCfg.URL)
|
providerId := strings.ToLower(providerCfg.URL)
|
||||||
|
|
||||||
if _, exists := a.ldapAuthenticators[providerId]; exists {
|
if _, exists := a.ldapAuthenticators[providerId]; exists {
|
||||||
return fmt.Errorf("auth provider with name %s is already registerd", providerId)
|
// this is an unrecoverable error, we cannot register the same provider twice
|
||||||
|
slog.Error("LDAP auth provider is already registered", "name", providerId)
|
||||||
|
continue // skip this provider
|
||||||
}
|
}
|
||||||
|
|
||||||
provider, err := newLdapAuthenticator(ctx, providerCfg)
|
provider, err := newLdapAuthenticator(ctx, providerCfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to setup ldap authentication provider %s: %w", providerId, err)
|
failedLdap = append(failedLdap, ldap[i])
|
||||||
|
slog.Error("failed to setup ldap authentication provider", "name", providerId, "error", err)
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
a.ldapAuthenticators[providerId] = provider
|
a.ldapAuthenticators[providerId] = provider
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return failedOidc, failedOauth, failedLdap
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetExternalLoginProviders returns a list of all available external login providers.
|
// GetExternalLoginProviders returns a list of all available external login providers.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user