Files
Vishal Dalwadi 4c08d20c6c NM-341-v6 (#4108)
* wip(go): remove old hook comment;

* wip(go): expect ctx during license validation;

* wip(go): always create default org and tenant for ce;

* wip(go): add tenant-specific check for license validation error;

* wip(go): cache license validation response in memory;

* wip(go): add todo to handle multiple-tenant for integration pull;

* wip(go): pass ctx during license validation;

* wip(go): add todo for making changes later; run hook separately for each tenant;

* wip(go): return specific errors when license validation response not in cache;

* wip(go): use retryable.httpclient for calling license validation api;

* wip(go): process license validation;

* wip(go): license validation function;

* wip(go): migration on license validation;

* wip(go): org settings not expected;

* wip(go): remove expiry from license validation response;

* wip(go): add limits and limits enforcement to license validation response;

* wip(go): remove expiry usages;

* wip(go): add arg to clear cache;

* wip(go): add arg to clear cache;

* wip(go): skip license validation if cached resp;

* wip(go): allow org_id and tenant_id query params;

* wip(go): upsert tenant membership on sync;

* wip(go): pass ctx to delete network roles;

* wip(go): create tenant membership on org owner creation on ce;

* wip(go): add tenant orchestrator;

* wip(go): use tenant orchestrator;

* wip(go): add default settings for tenant;

* wip(go): make org owner superadmin on all tenants;

* wip(go): simplify SyncOrgAndTenants;

* wip(go): retry license validation only 3 times

* wip(go): store invalid err;

* wip(go): add function to check if limits are to be enforced on a tenant;

* wip(go): pass tenant scope if possible when checking for license validation error;

* wip(go): remove merge errors;

* wip(go): add functions for limit checks;

* wip(go): wire host limit check;

* wip(go): wire ingress limit check;

* wip(go): wire egress limit check;

* wip(go): wire client limit check;

* wip(go): wire network limit check;

* wip(go): wire user limit check;

* wip(go): use correct errors;

* wip(go): skip telemetry for msps;

* wip(go): disable telemetry on msp tenants;

* wip(go): err check;

* wip(go): uncomment log event;

* wip(go): get sso state to get scope for non-headless oauth login;

* wip(go): inline delete pending user;

* wip(go): allow both org and tenant scope for pending users table;

* wip(go): add migration for pending user table during set tenant id and rekey org/tenant id;

* wip(go): update queries to use new scope fields in pending users table;

* wip(go): allow both org and tenant scope for user invites table;

* wip(go): update queries to use new scope fields;

* wip(go): add migration for rekey-ing org/tenant id and setting tenant id;

* wip(go): inline delete user invite;

* wip(go): set scope when creating invite;

* wip(go): get user count with membership is ctx is tenant scoped;

* wip(go): add methods to upsert and delete org memberships;

* wip(go): add global valid tenant and org roles map;

* wip(go): add scope query in user invite get by email;

* wip(go): add support for upsert and delete of org and tenant membership both;

* wip(go): infer scope for user invite apis;

* wip(go): wire ctx in get user invite by email;

* wip(go): allow no scope headers to be passed in infer scope apis;

* wip(go): add validation and checks for org-scoped invite api handlers;

* wip(go): wire ctx to is pending user check;

* wip(go): infer scope for pending user apis;

* wip(go): set default role based on ctx scope;

* wip(go): move mfa to tenant membership table; move account status to membership tables;

* wip(go): migrate account status and mfa settings;

* wip(go): update account status on sync;

* wip(go): use update mfa to update mfa setting;

* wip(go): set new membership settings on user creation;

* wip(go): use membership where required;

* wip(go): wire ctx on key unlink refs;

* wip(go): use r.Context directly without reinitializing db;

* wip(go): wire ctx in acls;

* wip(go): add tenant scoped primary key constructor;

* wip(go): use tenant scoped primary key for acls, dns, extclients and tags;

* wip(go): wire ctx for get groups in network;

* wip(go): wire ctx for get groups;

* wip(go): scope non-uuid group ids by tenant id;

* wip(go): migrate non-uuid group ids to scoped ids;

* wip(go): don't expect scope id in invite validation and signup apis;

* wip(go): wire ctx for get matching user; allow org scope when querying by external idp id;

* wip(go): add mfa to org;

* wip(go): scope preauth token;

* wip(go): add fallback for older auth tokens;

* wip(go): wire ctx for preauth token creation;

* wip(go): migrate mfa settings;

* wip(go): resolve mfa settings for inherited auth;

* wip(go): update mfa for org;

* wip(go): infer scope for totp apis;

* wip(go): use ctx when passed;

* wip(go): infer scope for list user apis;

* wip(go): ensure set primary keys don't cause errors during fetch;

* wip(go): make primary key for integrations uuid and store provider in separate key;

* wip(go): migrate integration ids;

* wip(go): use provider instead of id everywhere;

* wip(go): remove gorm column;

* wip(go): wire ctx for igw egress creation;

* wip(go): wire ctx for igw egress update;

* wip(go): wire ctx for host registration;

* wip(go): wire ctx for host registration;

* wip(go): merge errors;

* wip(go): merge errors;

* wip(go): wire ctx; remove default scope usages;

* wip(go): use get with membership;

* wip(go): org scope license validation;

* wip(go): remove debug log;

* wip(go): remove scoping on list roles;

* wip(go): ignore invite creation if already exists;

* wip(go): add is msp func to check if deployment is msp deployment;

* wip(go): ensure username is email for msp users;

* wip(go): add email validated check on user table;

* wip(go): mark email validated when oauth user;

* wip(go): handle gorm error;

* wip(go): add tenant id to siem grpc schema;

* wip(go): read tenant from scoped ctx;

* wip(go): pass scoped ctx to siem grpc client;

* wip(go): remove unused publisher;

* wip(go): publish all tenant exporter updates on pull;

* wip(go): fix wg usage;

* wip(go): tenant scope the ctx when getting server info;

* wip(go): add tenant id to enrollment key token;

* wip(go): make host register tenant scope;

* wip(go): add default settings;

* wip(go): use correct checks for is msp tenant;

* wip(go): add email validation extension;

* wip(go): add pages for validation check;

* wip(go): use extension for validating user;

* wip(go): add invite type;

* wip(go): create only one validation invite per user email;

* wip(go): add validate email handler;

* wip(go): add email builder;

* wip(go): add user invite type migration logic;

* wip(go): only log email send failures;

* wip(go): add tenant id to flows table;

* wip(go): add func to check if connected to clickhouse;

* wip(go): migrate clickhouse;

* wip(go): add tenant id to mdm and edr state;

* wip(go): add delete methods for tables;

* wip(go): add tenant teardown method;

* wip(go): handle tenant deletion;

* wip(go): clean up flow logs on tenant deletion;

* wip(go): add update org membership role id method;

* wip(go): add transfer org ownership api;

* wip(go): move audit logs retention period to org settings;

* wip(go):get retention period from org settings;

* wip(go): remove old audit logs usage;

* wip(go): migrate audit logs retention period;

* wip(go): unmarshal decodes nums as float64;

* wip(go): run flow logs cleanup for all tenants in one go;

* wip(go): add audit logs retention period and smtp settings to tenant settings table for non-msp tenants;

* wip(go): resolve retention period and smtp settings correctly;

* wip(go): handle retention period and smtp settings updates and fetches correctly;

* wip(go): overlay retention period and smtp settings on server settings;;

* wip(go): upsert overlayed settings;

* wip(go): add azure tenant id to org settings;

* wip(go): tenant scope list roles;

* wip(go): add noop creds;

* wip(go): use first instead of find;

* wip(go): use correct roles when transfering ownership;

* wip(go): delete access tokens only if tenant scoped;

* wip(go): make delete user work for both org and tenant scope;

* wip(go): delete extclients only if tenant scoped;

* wip(go): check if caller is allowed to delete user;

* wip(go): infer scope for update user;

* wip(go): prevent org-owner elevation;

* wip(go): permissions check for update;

* wip(go): delete user access tokens only if tenant scope;

* wip(go): delete extclients only if tenant scope;

* wip(go): move upsert membership in upsert user;

* wip(go): set api host when constructing server config;

* wip(go): fix static errors;

* wip(go): fix test cases;

* wip(go): use correct get ns order;

* wip(go): use correct get pending host order;

* wip(go): use correct get access token order;

* wip(go): use correct get event order;

* wip(go): return error response on emqx user creation error;

* wip(go): store correct value in cache;

* wip(go): return better error response;

* wip(go): return better error response;

* wip(go): use cache when listing egress acls;

* wip(go): wire ctx in UserHasNetworkGroupAccess;

* wip(go): remove double scope wrapping;

* wip(go): add security check for list and get org;

* wip(go): ratelimit discover api;

* wip(go): expect sole org id in get and create org owner;

* wip(go): wrap create org owner in tx;

* wip(go): wire ctx correctly;

* wip(go): wire ctx for posture check functions;

* wip(go): remove resolved todo;

* wip(go): wire ctx for posture check function;

* wip(go): remove scope from netdesk login api;

* wip(go): use orgid correctly;

* wip(go): scope user update checks correctly;

* wip(go): wire ctx for fetch oauth secret;

* wip(go): add tenant_id and org_id query string param to user invite url;

* wip(go): get sole org;

* wip(go): set query string correctly;

* wip(go): wire ctx in update user groups;

* wip(go): allow delete oauth non-idp users;

* wip(go): delete access tokens post update but check before update;

* wip(go): ignore h.Nodes on create host;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): create tenant membership for org user directly;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): get user with membership on callback;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): use write locks;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): prevent create, update, delete of roles;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): ensure role belongs to network we are checking permission for;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): handle error on invite creation correctly;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): handle invite not found on org scoped oauth callback;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): init default groups on tenant creation;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): upset org and tenant on change;

* wip(go): use GetPlatformRole method to get platform role;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): created default network roles on tenant creation;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): use GetAnyRole when unsure; remove unused funcs;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): initialize network roles on startup;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): use GetNetworkRole method to get network role;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): migrate ids of all network roles;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): check both scoped and unscoped on delete;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): check both scoped and unscoped on update;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): scope id on network role upsert;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): add methods to fetch platform and network roles;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): scope network role id on create;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): add methods to scope and unscope role ids;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): remove uuid check;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): list scoped network roles;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): remove unuse update method;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): use correct id on get and delete;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): allow all_networks role in permission access;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): scope ctx from state cache;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): remove create, delete and update roles from netmaker cli;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): create network admin and user with ctx;

Signed-off-by: VishalDalwadi <[email protected]>

* wip(go): allow updating names and metadata;

Signed-off-by: VishalDalwadi <[email protected]>

---------

Signed-off-by: VishalDalwadi <[email protected]>
2026-08-17 17:49:04 +05:30

153 lines
4.1 KiB
Go

package auth
import (
"context"
"strings"
"sync"
"github.com/gravitl/netmaker/db"
"github.com/gravitl/netmaker/schema"
"github.com/gravitl/netmaker/scope"
"github.com/gravitl/netmaker/servercfg"
)
var registryInitOnce sync.Once
type ProviderRegistry struct {
mu sync.RWMutex
providers map[scope.Scope]map[string]Provider
}
var registry *ProviderRegistry
func Registry() *ProviderRegistry {
registryInitOnce.Do(func() {
registry = &ProviderRegistry{
providers: make(map[scope.Scope]map[string]Provider),
}
registry.providers[scope.GlobalScope] = make(map[string]Provider)
registry.providers[scope.OrgScope] = make(map[string]Provider)
registry.providers[scope.TenantScope] = make(map[string]Provider)
})
return registry
}
func (p *ProviderRegistry) getOrInit(scopeLevel scope.Scope, scopeID string) (Provider, bool) {
p.mu.RLock()
provider, ok := p.providers[scopeLevel][scopeID]
p.mu.RUnlock()
if ok {
return provider, true
}
p.mu.Lock()
defer p.mu.Unlock()
provider, ok = p.providers[scopeLevel][scopeID]
if ok {
return provider, true
}
provider = p.initProvider(scopeLevel, scopeID)
if provider == nil {
return nil, false
}
p.providers[scopeLevel][scopeID] = provider
return provider, true
}
func (p *ProviderRegistry) Delete(scopeLevel scope.Scope, scopeID string) {
p.mu.Lock()
defer p.mu.Unlock()
delete(p.providers[scopeLevel], scopeID)
}
// FromContext returns the provider for the scope embedded in ctx.
func (p *ProviderRegistry) FromContext(ctx context.Context) (Provider, bool) {
return p.getOrInit(scope.Level(ctx), scope.ID(ctx))
}
func (p *ProviderRegistry) initProvider(scopeLevel scope.Scope, scopeID string) Provider {
redirectUrl := p.getRedirectURL()
switch scopeLevel {
case scope.OrgScope:
settingsRecord := &schema.OrganizationSettings{
ID: scopeID,
}
err := settingsRecord.Get(db.WithContext(context.TODO()))
if err != nil {
return nil
}
settings := settingsRecord.Settings.Data()
switch settings.AuthProvider {
case google_provider_name:
return NewGoogleProvider(redirectUrl, settings.ClientID, settings.ClientSecret)
case azure_ad_provider_name:
return NewAzureADProvider(redirectUrl, settings.ClientID, settings.ClientSecret, settings.AzureTenant)
case github_provider_name:
return NewGitHubProvider(redirectUrl, settings.ClientID, settings.ClientSecret)
case okta_provider_name:
provider, err := NewOktaProvider(redirectUrl, settings.ClientID, settings.ClientSecret, settings.OIDCIssuer)
if err != nil {
return nil
}
return provider
case oidc_provider_name:
provider, err := NewOIDCProvider(redirectUrl, settings.ClientID, settings.ClientSecret, settings.OIDCIssuer)
if err != nil {
return nil
}
return provider
}
return nil
case scope.TenantScope:
settingsRecord := &schema.TenantSettingsRecord{
Key: scopeID,
}
err := settingsRecord.Get(db.WithContext(context.TODO()))
if err != nil {
return nil
}
settings := settingsRecord.Value.Data()
switch settings.AuthProvider {
case google_provider_name:
return NewGoogleProvider(redirectUrl, settings.ClientID, settings.ClientSecret)
case azure_ad_provider_name:
return NewAzureADProvider(redirectUrl, settings.ClientID, settings.ClientSecret, settings.AzureTenant)
case github_provider_name:
return NewGitHubProvider(redirectUrl, settings.ClientID, settings.ClientSecret)
case okta_provider_name:
provider, err := NewOktaProvider(redirectUrl, settings.ClientID, settings.ClientSecret, settings.OIDCIssuer)
if err != nil {
return nil
}
return provider
case oidc_provider_name:
provider, err := NewOIDCProvider(redirectUrl, settings.ClientID, settings.ClientSecret, settings.OIDCIssuer)
if err != nil {
return nil
}
return provider
}
return nil
default:
return nil
}
}
func (p *ProviderRegistry) getRedirectURL() string {
apiHost := servercfg.GetAPIHost()
if strings.Contains(apiHost, "localhost") || strings.Contains(apiHost, "127.0.0.1") {
apiHost = "http://" + apiHost
} else {
apiHost = "https://" + apiHost
}
return apiHost + "/api/oauth/callback"
}