* wip(go): wire ctx in extclient apis;

* wip(go): wire ctx in extclient apis;

* wip(go): remove org id check from global scoped get tenant api;

* wip(go): add scope slug to discover response;

* wip(go): wire ctx in get users;

* wip(go): set tenant id in posture check violations;

* wip(go): upsert membership instead of user;

* wip(go): pass correct len;

* wip(go): optimize (single loop);

* wip(go): unify todos;

* wip(go): add todo;

* wip(go): wire context for network get;

* wip(go): wire context;

* wip(go): wire context;

* wip(go): wire ctx when getting tenant superadmin;

* wip(go): add network creator to network admin group;

* wip(go): check for user membership on sync;

* wip(go): add methods with strict membership check;

* wip(go): remove unwanted feature flags;

* wip(go): report per-tenant usage during license validation;

* wip(go): move email setting from tenant to org;

* wip(go): pass org scope to email init;

* wip(go): remove old tenant email settings usages; use org settings to get email settings

* wip(go): use get email settings from org settings;

* wip(go): remove email settings migration;

* wip(go): migrate email settings from server to org settings;

* wip(go): assign global network admin group membership only for super-admin and admins;

* wip(go): assign global network admin group membership only for super-admin and admins;

* wip(go): add membership alias to filter;

* wip(go): skip clearing local license validation response cache;

* wip(go): extend license validation response for multi-tenancy;

* wip(go): add functions to get sole tenant and org;

* wip(go): use tenant-specific feature flags;

* wip(go): add tenant status type;

* 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;
This commit is contained in:
Vishal Dalwadi
2026-08-10 18:59:40 +05:30
committed by GitHub
parent 132aee0bb3
commit f81fe29d4d
27 changed files with 155 additions and 107 deletions
+1
View File
@@ -264,6 +264,7 @@ func joinHostToNetworks(ctx context.Context, key models.EnrollmentKey, host *sch
}
violations, _ := logic.CheckPostureViolationsForHost(
ctx,
host,
keyTags,
schema.NetworkID(network.Name),
+1 -1
View File
@@ -118,7 +118,7 @@ func getDeviceNetworks(w http.ResponseWriter, r *http.Request) {
}
// Ownership mismatch must not block the network list; host-scoped state is omitted without a verified host.
}
networks, err := logic.GetDeviceNetworks(db.WithContext(r.Context()), user, host)
networks, err := logic.GetDeviceNetworks(r.Context(), user, host)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
+1 -1
View File
@@ -593,7 +593,7 @@ func handleHostRegister(w http.ResponseWriter, r *http.Request) {
var joinNetworks []string
for _, netI := range enrollmentKey.Networks {
violations, _ := logic.CheckPostureViolationsForHost(&newHost, keyTags, schema.NetworkID(netI), true)
violations, _ := logic.CheckPostureViolationsForHost(r.Context(), &newHost, keyTags, schema.NetworkID(netI), true)
if len(violations) == 0 {
joinNetworks = append(joinNetworks, netI)
}
+2 -2
View File
@@ -646,7 +646,7 @@ func createExtClient(w http.ResponseWriter, r *http.Request) {
if extclient.DeviceID != "" {
// check for violations connecting from desktop app
staticNode := models.ConvertToStaticNode(extclient)
violations, _ := logic.CheckPostureViolations(logic.GetPostureCheckDeviceInfoByNode(&staticNode), schema.NetworkID(extclient.Network))
violations, _ := logic.CheckPostureViolations(r.Context(), logic.GetPostureCheckDeviceInfoByNode(&staticNode), schema.NetworkID(extclient.Network))
if len(violations) > 0 {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("posture check violations"), logic.Forbidden))
return
@@ -927,7 +927,7 @@ func updateExtClient(w http.ResponseWriter, r *http.Request) {
if newclient.DeviceID != "" && newclient.Enabled {
// check for violations connecting from desktop app
staticNode := models.ConvertToStaticNode(newclient)
violations, _ := logic.CheckPostureViolations(logic.GetPostureCheckDeviceInfoByNode(&staticNode), schema.NetworkID(newclient.Network))
violations, _ := logic.CheckPostureViolations(r.Context(), logic.GetPostureCheckDeviceInfoByNode(&staticNode), schema.NetworkID(newclient.Network))
if len(violations) > 0 {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("posture check violations"), logic.Forbidden))
return
+4 -4
View File
@@ -647,7 +647,7 @@ func hostUpdateFallback(w http.ResponseWriter, r *http.Request) {
)
for _, _node := range _nodes {
node := logic.ConvertSchemaNodeToModelsNode(&_node)
node.PostureChecksViolations, node.PostureCheckViolationSeverityLevel = logic.CheckPostureViolations(logic.GetPostureCheckDeviceInfoByNode(node), schema.NetworkID(node.Network))
node.PostureChecksViolations, node.PostureCheckViolationSeverityLevel = logic.CheckPostureViolations(ctx, logic.GetPostureCheckDeviceInfoByNode(node), schema.NetworkID(node.Network))
_node.PostureCheckSeverity = node.PostureCheckViolationSeverityLevel
_node.PostureCheckLastEvaluationCycleID = uuid.NewString()
_node.PostureCheckLastEvaluatedAt = time.Now().UTC()
@@ -977,7 +977,7 @@ func addHostToNetwork(w http.ResponseWriter, r *http.Request) {
return
}
violations, _ := logic.CheckPostureViolationsForHost(host, nil, schema.NetworkID(networkID), true)
violations, _ := logic.CheckPostureViolationsForHost(r.Context(), host, nil, schema.NetworkID(networkID), true)
if len(violations) > 0 {
logic.ReturnErrorResponseWithJson(w, r, violations, logic.FormatError(errors.New("posture check violations"), logic.BadReq))
return
@@ -1871,7 +1871,7 @@ func approvePendingHost(w http.ResponseWriter, r *http.Request) {
keyTags[models.TagID(tagI)] = struct{}{}
}
violations, _ := logic.CheckPostureViolationsForHost(host, keyTags, schema.NetworkID(network.Name), true)
violations, _ := logic.CheckPostureViolationsForHost(r.Context(), host, keyTags, schema.NetworkID(network.Name), true)
if len(violations) > 0 {
err = fmt.Errorf("failed to approve pending host (%s): posture check violations", id)
logger.Log(0, err.Error())
@@ -1939,7 +1939,7 @@ func addDefaultHostToNetworks(ctx context.Context, host *schema.Host) {
continue
}
violations, _ := logic.CheckPostureViolationsForHost(host, make(map[models.TagID]struct{}), schema.NetworkID(network.Name), true)
violations, _ := logic.CheckPostureViolationsForHost(ctx, host, make(map[models.TagID]struct{}), schema.NetworkID(network.Name), true)
if len(violations) > 0 {
logger.Log(2, "skipping network", network.Name, "for default host", host.Name, ": posture check violations")
continue
+13 -3
View File
@@ -45,10 +45,20 @@ func resolveSoleOrg(ctx context.Context, orgID string) (*schema.Organization, er
if err != nil {
return nil, err
}
if orgID != "sole" && orgID != o.ID && orgID != o.Slug {
return nil, errOrgNotFound
if orgID == "sole" {
return o, nil
}
return o, nil
if orgID == o.ID {
return o, nil
}
if orgID == o.Slug {
return o, nil
}
return nil, errOrgNotFound
}
// @Summary Get organization SSO settings
+44 -26
View File
@@ -324,7 +324,7 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) {
return
}
if logic.IsOauthUser(user) == nil {
if logic.IsOauthUser(request.Context(), user) == nil {
logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("user is registered via SSO"), "badrequest"))
return
}
@@ -1682,48 +1682,61 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
break
}
}
if !ismaster && selfUpdate {
if user.PlatformRoleID != userchange.PlatformRoleID {
slog.Error("user cannot change his own role", "caller", caller.Username, "attempted to update user role", username)
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user not allowed to self assign role"), "forbidden"))
return
}
if scope.Level(r.Context()) == scope.TenantScope {
if !ismaster && selfUpdate {
if user.PlatformRoleID != userchange.PlatformRoleID {
slog.Error("user cannot change his own role", "caller", caller.Username, "attempted to update user role", username)
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user not allowed to self assign role"), "forbidden"))
return
if logic.IsMFAEnforced(r.Context()) && user.IsMFAEnabled && !userchange.IsMFAEnabled {
err = errors.New("mfa is enforced, user cannot unset their own mfa")
slog.Error("failed to update user", "caller", caller.Username, "attempted to update user", username, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
return
}
}
if servercfg.IsPro && caller.PlatformRoleID != schema.SuperAdminRole {
// users cannot update their own groups; superadmin is exempt
if len(user.UserGroups.Data()) != len(userchange.UserGroups.Data()) || !reflect.DeepEqual(user.UserGroups.Data(), userchange.UserGroups.Data()) {
err = errors.New("user cannot update self update their groups")
if logic.IsMFAEnforced(r.Context()) && user.IsMFAEnabled && !userchange.IsMFAEnabled {
err = errors.New("mfa is enforced, user cannot unset their own mfa")
slog.Error("failed to update user", "caller", caller.Username, "attempted to update user", username, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
return
}
if servercfg.IsPro && caller.PlatformRoleID != schema.SuperAdminRole {
// users cannot update their own groups; superadmin is exempt
if len(user.UserGroups.Data()) != len(userchange.UserGroups.Data()) || !reflect.DeepEqual(user.UserGroups.Data(), userchange.UserGroups.Data()) {
err = errors.New("user cannot self update their groups")
slog.Error("failed to update user", "caller", caller.Username, "attempted to update user", username, "error", err)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
return
}
}
}
}
if ismaster {
if user.PlatformRoleID != schema.SuperAdminRole && userchange.PlatformRoleID == schema.SuperAdminRole {
slog.Error("operation not allowed", "caller", logic.MasterUser, "attempted to update user role to superadmin", username)
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("attempted to update user role to superadmin"), "forbidden"))
if ismaster {
if user.PlatformRoleID != schema.SuperAdminRole && userchange.PlatformRoleID == schema.SuperAdminRole {
slog.Error("operation not allowed", "caller", logic.MasterUser, "attempted to update user role to superadmin", username)
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("attempted to update user role to superadmin"), "forbidden"))
return
}
}
if user.AuthType == schema.Inherited && userchange.Password != "" {
err = fmt.Errorf("cannot update password for user with inherited auth")
logic.ReturnErrorResponse(w, r, logic.FormatError(err, logic.BadReq))
return
}
}
if logic.IsOauthUser(user) == nil && userchange.Password != "" {
err := fmt.Errorf("cannot update user's password for an oauth user %s", username)
if logic.IsOauthUser(r.Context(), user) == nil && userchange.Password != "" {
err := fmt.Errorf("cannot update password for an oauth user %s", username)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
return
}
var deleteAccessTokens bool
if scope.Level(r.Context()) == scope.TenantScope &&
(userchange.PlatformRoleID != user.PlatformRoleID || !logic.CompareMaps(user.UserGroups.Data(), userchange.UserGroups.Data())) {
(&schema.UserAccessToken{UserName: user.Username}).DeleteAllUserTokens(r.Context())
deleteAccessTokens = true
}
oldUser := *user
if ismaster {
caller = &schema.User{
@@ -1770,6 +1783,11 @@ func updateUser(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
if deleteAccessTokens {
_ = (&schema.UserAccessToken{UserName: user.Username}).DeleteAllUserTokens(r.Context())
}
logic.LogEvent(r.Context(), &e)
ctx := scope.WithContext(db.WithContext(context.Background()), scope.Level(r.Context()), scope.ID(r.Context()))
go mq.PublishPeerUpdate(ctx, false)
@@ -1916,7 +1934,7 @@ func deleteUser(w http.ResponseWriter, r *http.Request) {
break
}
if user.AuthType == schema.OAuth || user.ExternalIdentityProviderID != "" {
if logic.IsIDPUser(r.Context(), user) {
err = fmt.Errorf("cannot delete idp user %s", username)
logger.Log(0, username, "failed to delete user: ", err.Error())
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
+14 -4
View File
@@ -60,8 +60,8 @@ func ResolveInheritedAuth(ctx context.Context, user *schema.User) error {
}
// IsOauthUser - returns
func IsOauthUser(user *schema.User) error {
var currentValue, err = FetchOAuthSecret()
func IsOauthUser(ctx context.Context, user *schema.User) error {
var currentValue, err = FetchOAuthSecret(ctx)
if err != nil {
return err
}
@@ -346,6 +346,16 @@ func ValidateUser(user *schema.User) error {
return validationErr
}
func IsIDPUser(ctx context.Context, user *schema.User) bool {
if scope.Level(ctx) == scope.TenantScope {
if user.AuthType == schema.OAuth && IsSyncEnabled(ctx) {
return true
}
}
return false
}
// DeleteUser - deletes a given user
func DeleteUser(ctx context.Context, user *schema.User) error {
err := user.DeleteMembership(ctx)
@@ -383,11 +393,11 @@ func SetOAuthSecret(secret string) error {
}
// FetchOAuthSecret fetches secrets for oauth
func FetchOAuthSecret() (string, error) {
func FetchOAuthSecret(ctx context.Context) (string, error) {
oauthSecret := &schema.Internal{
Key: schema.InternalKey_OAuthSecret,
}
err := oauthSecret.Get(db.WithContext(context.TODO()))
err := oauthSecret.Get(ctx)
if err != nil {
return "", err
}
+2 -2
View File
@@ -232,7 +232,7 @@ func applyDeviceNetworkHostState(ctx context.Context, host *schema.Host, network
return
}
violations, _ := CheckPostureViolationsForHost(host, nil, schema.NetworkID(network.Name), true)
violations, _ := CheckPostureViolationsForHost(ctx, host, nil, schema.NetworkID(network.Name), true)
if len(violations) > 0 {
dn.Status = models.DeviceNetworkStatusBlocked
return
@@ -289,7 +289,7 @@ func JoinDeviceNetwork(ctx context.Context, user *schema.User, host *schema.Host
return models.DeviceJoinResult{Status: models.DeviceJoinStatusJoined}, nil
}
violations, _ := CheckPostureViolationsForHost(host, nil, schema.NetworkID(networkID), true)
violations, _ := CheckPostureViolationsForHost(ctx, host, nil, schema.NetworkID(networkID), true)
if len(violations) > 0 {
return empty, errors.New("access blocked: this device doesn't meet security requirements")
}
+3 -4
View File
@@ -40,17 +40,16 @@ var HostLimitExceeded = func(ctx context.Context) bool {
return false
}
// todo(nm-341): add ctx to func
var CheckPostureViolations = func(d models.PostureCheckDeviceInfo, network schema.NetworkID) (v []models.Violation, level schema.Severity) {
var CheckPostureViolations = func(ctx context.Context, d models.PostureCheckDeviceInfo, network schema.NetworkID) (v []models.Violation, level schema.Severity) {
return []models.Violation{}, schema.SeverityUnknown
}
// todo(nm-341): add ctx to func
var CheckPostureViolationsForHost = func(host *schema.Host, tags map[models.TagID]struct{}, network schema.NetworkID, skipAutoUpdate bool) ([]models.Violation, schema.Severity) {
var CheckPostureViolationsForHost = func(ctx context.Context, host *schema.Host, tags map[models.TagID]struct{}, network schema.NetworkID, skipAutoUpdate bool) ([]models.Violation, schema.Severity) {
if host == nil {
return []models.Violation{}, schema.SeverityUnknown
}
return CheckPostureViolations(models.PostureCheckDeviceInfo{
return CheckPostureViolations(ctx, models.PostureCheckDeviceInfo{
ClientLocation: host.CountryCode,
ClientVersion: host.Version,
OS: host.OS,
-1
View File
@@ -9,7 +9,6 @@ import (
)
func GetCurrentServerUsage(ctx context.Context) (limits models.Usage) {
// todo(nm-341): get usage of all tenants or specific tenant?
limits.SetDefaults()
hosts, hErr := GetAllHostsWithStatus(ctx, schema.OnlineSt)
if hErr == nil {
+1 -1
View File
@@ -426,7 +426,7 @@ func syncUsers() {
for _, user := range users {
user := user
user.AuthType = schema.BasicAuth
if logic.IsOauthUser(&user) == nil {
if logic.IsOauthUser(db.WithContext(context.TODO()), &user) == nil {
user.AuthType = schema.OAuth
}
+2 -2
View File
@@ -8,7 +8,7 @@ import (
)
type UserExtensions interface {
ConfigureAuthType(user *schema.User) error
ConfigureAuthType(ctx context.Context, user *schema.User) error
ConfigureGlobalAdminGroup(membership *schema.TenantMembership)
ConfigureGroups(ctx context.Context, membership *schema.TenantMembership, groups datatypes.JSONType[map[schema.UserGroupID]struct{}])
SendEmailValidation(ctx context.Context, user *schema.User) error
@@ -16,7 +16,7 @@ type UserExtensions interface {
type CEUserExtensions struct{}
func (c *CEUserExtensions) ConfigureAuthType(user *schema.User) error {
func (c *CEUserExtensions) ConfigureAuthType(_ context.Context, user *schema.User) error {
user.AuthType = schema.BasicAuth
return nil
}
+4 -4
View File
@@ -153,10 +153,10 @@ func (n *NodeOrchestrator) CreateNode(ctx context.Context, host *schema.Host, ne
}
}
go func() {
go func(ctx context.Context) {
modelsNode := logic.ConvertSchemaNodeToModelsNode(node)
modelsNode.PostureChecksViolations, modelsNode.PostureCheckViolationSeverityLevel = logic.CheckPostureViolations(logic.GetPostureCheckDeviceInfoByNode(modelsNode), schema.NetworkID(node.Network.Name))
modelsNode.PostureChecksViolations, modelsNode.PostureCheckViolationSeverityLevel = logic.CheckPostureViolations(ctx, logic.GetPostureCheckDeviceInfoByNode(modelsNode), schema.NetworkID(node.Network.Name))
node.PostureCheckSeverity = modelsNode.PostureCheckViolationSeverityLevel
node.PostureCheckLastEvaluationCycleID = uuid.NewString()
node.PostureCheckLastEvaluatedAt = time.Now().UTC()
@@ -175,7 +175,7 @@ func (n *NodeOrchestrator) CreateNode(ctx context.Context, host *schema.Host, ne
EvaluatedAt: node.PostureCheckLastEvaluatedAt,
})
}
err = node.UpsertViolations(db.WithContext(context.TODO()), _violations)
err = node.UpsertViolations(ctx, _violations)
if err != nil {
logger.Log(1, fmt.Sprintf("failed to upsert node (%s) posture check violations: %v", modelsNode.ID, err))
}
@@ -204,7 +204,7 @@ func (n *NodeOrchestrator) CreateNode(ctx context.Context, host *schema.Host, ne
time.Sleep(time.Second * 30)
logic.TriggerCollectMetrics(host.ID.String(), node.ID, "join")
}
}()
}(scope.WithContext(db.WithContext(context.Background()), scope.Level(ctx), scope.ID(ctx)))
return node, nil
}
+1 -1
View File
@@ -79,7 +79,7 @@ func (u *UserOrchestrator) CreateUser(ctx context.Context, user *schema.User, op
user.Password = string(passwordHash)
err = u.userExt.ConfigureAuthType(user)
err = u.userExt.ConfigureAuthType(ctx, user)
if err != nil {
return err
}
+2 -2
View File
@@ -98,7 +98,7 @@ func (p *AzureADProvider) HandleCallback(w http.ResponseWriter, r *http.Request)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
if inviteExists {
user, err := proLogic.PrepareOauthUserFromInvite(in)
user, err := proLogic.PrepareOauthUserFromInvite(r.Context(), in)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
@@ -179,7 +179,7 @@ func (p *AzureADProvider) HandleCallback(w http.ResponseWriter, r *http.Request)
return
}
newPass, fetchErr := logic.FetchOAuthSecret()
newPass, fetchErr := logic.FetchOAuthSecret(r.Context())
if fetchErr != nil {
return
}
+2 -2
View File
@@ -119,7 +119,7 @@ func (p *GitHubProvider) HandleCallback(w http.ResponseWriter, r *http.Request)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
if inviteExists {
user, err := proLogic.PrepareOauthUserFromInvite(in)
user, err := proLogic.PrepareOauthUserFromInvite(r.Context(), in)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
@@ -189,7 +189,7 @@ func (p *GitHubProvider) HandleCallback(w http.ResponseWriter, r *http.Request)
return
}
newPass, fetchErr := logic.FetchOAuthSecret()
newPass, fetchErr := logic.FetchOAuthSecret(r.Context())
if fetchErr != nil {
return
}
+2 -2
View File
@@ -102,7 +102,7 @@ func (p *GoogleProvider) HandleCallback(w http.ResponseWriter, r *http.Request)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
if inviteExists {
user, err := proLogic.PrepareOauthUserFromInvite(in)
user, err := proLogic.PrepareOauthUserFromInvite(r.Context(), in)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
@@ -180,7 +180,7 @@ func (p *GoogleProvider) HandleCallback(w http.ResponseWriter, r *http.Request)
return
}
newPass, fetchErr := logic.FetchOAuthSecret()
newPass, fetchErr := logic.FetchOAuthSecret(r.Context())
if fetchErr != nil {
return
}
+1 -1
View File
@@ -95,7 +95,7 @@ func HandleHeadlessSSOCallback(w http.ResponseWriter, r *http.Request) {
handleUserAccountDisabled(w)
return
}
newPass, fetchErr := logic.FetchOAuthSecret()
newPass, fetchErr := logic.FetchOAuthSecret(r.Context())
if fetchErr != nil {
return
}
+2 -2
View File
@@ -113,7 +113,7 @@ func (p *OIDCProvider) HandleCallback(w http.ResponseWriter, r *http.Request) {
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
if inviteExists {
user, err := proLogic.PrepareOauthUserFromInvite(in)
user, err := proLogic.PrepareOauthUserFromInvite(r.Context(), in)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
@@ -189,7 +189,7 @@ func (p *OIDCProvider) HandleCallback(w http.ResponseWriter, r *http.Request) {
return
}
newPass, fetchErr := logic.FetchOAuthSecret()
newPass, fetchErr := logic.FetchOAuthSecret(r.Context())
if fetchErr != nil {
return
}
+18 -11
View File
@@ -10,6 +10,7 @@ import (
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic/pro/netcache"
"github.com/gravitl/netmaker/schema"
"github.com/gravitl/netmaker/scope"
)
var (
@@ -138,19 +139,25 @@ func returnErrTemplate(uname, message, state string, ncache *netcache.CValue) []
// Puts machine key in cache so the callback can retrieve it using the oidc state param
// Listens in /oidc/register/:regKey.
func RegisterHostSSO(w http.ResponseWriter, r *http.Request) {
p, ok := Registry().FromContext(r.Context())
if !ok {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("invalid login attempt"))
return
}
vars := mux.Vars(r)
// machineKeyStr this is not key but state
machineKeyStr := vars["regKey"]
machineKeyStr := mux.Vars(r)["regKey"]
if machineKeyStr == "" {
w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("invalid login attempt"))
_, _ = w.Write([]byte("invalid login attempt: no key"))
return
}
state, err := netcache.Get(machineKeyStr)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte("invalid login attempt: no state"))
return
}
ctx := scope.WithContext(r.Context(), state.Scope, state.ScopeID)
p, ok := Registry().FromContext(ctx)
if !ok {
w.WriteHeader(http.StatusBadRequest)
_, _ = w.Write([]byte("invalid login attempt: no auth provider"))
return
}
+2 -2
View File
@@ -184,7 +184,7 @@ func syncUsers(ctx context.Context, idpUsers []idp.User, filters []string, remov
return err
}
password, err := logic.FetchOAuthSecret()
password, err := logic.FetchOAuthSecret(ctx)
if err != nil {
return err
}
@@ -364,7 +364,7 @@ func syncGroups(ctx context.Context, idpGroups []idp.Group, filters []string) er
}
} else {
dbGroup.Name = group.Name
err = proLogic.UpdateUserGroup(dbGroup)
err = proLogic.UpdateUserGroup(ctx, dbGroup)
if err != nil {
return err
}
+10 -4
View File
@@ -327,6 +327,12 @@ func inviteUsers(w http.ResponseWriter, r *http.Request) {
slog.Error("failed to parse to invite url", "error", err)
return
}
} else {
if scope.Level(r.Context()) == scope.TenantScope {
u, err = url.Parse(fmt.Sprintf("%s&tenant_id=%s", u.String(), url.QueryEscape(scope.ID(r.Context()))))
} else if scope.Level(r.Context()) == scope.OrgScope {
u, err = url.Parse(fmt.Sprintf("%s&org_id=%s", u.String(), url.QueryEscape(scope.ID(r.Context()))))
}
}
invite.InviteURL = u.String()
err = invite.Create(r.Context())
@@ -605,7 +611,7 @@ func createUserGroup(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
}
err = proLogic.ValidateCreateGroupReq(userGroupReq.Group)
err = proLogic.ValidateCreateGroupReq(r.Context(), userGroupReq.Group)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
@@ -683,7 +689,7 @@ func updateUserGroup(w http.ResponseWriter, r *http.Request) {
logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update default user group"), "badrequest"))
return
}
err = proLogic.ValidateUpdateGroupReq(userGroup)
err = proLogic.ValidateUpdateGroupReq(r.Context(), userGroup)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
return
@@ -691,7 +697,7 @@ func updateUserGroup(w http.ResponseWriter, r *http.Request) {
userGroup.ExternalIdentityProviderID = currUserG.ExternalIdentityProviderID
err = proLogic.UpdateUserGroup(userGroup)
err = proLogic.UpdateUserGroup(r.Context(), userGroup)
if err != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
@@ -2124,7 +2130,7 @@ func approvePendingUser(w http.ResponseWriter, r *http.Request) {
return
}
var newPass, fetchErr = logic.FetchOAuthSecret()
var newPass, fetchErr = logic.FetchOAuthSecret(r.Context())
if fetchErr != nil {
logic.ReturnErrorResponse(w, r, logic.FormatError(fetchErr, "internal"))
return
+2 -3
View File
@@ -138,10 +138,9 @@ func InitPro() {
}
}
defaultOrg := &schema.Organization{}
err := defaultOrg.Get(db.WithContext(context.TODO()))
org, err := logic.SoleOrganization(db.WithContext(context.TODO()))
if err == nil {
email.Init(scope.WithContext(db.WithContext(ctx), scope.OrgScope, defaultOrg.ID))
email.Init(scope.WithContext(db.WithContext(ctx), scope.OrgScope, org.ID))
}
go proLogic.EventWatcher()
})
+9 -10
View File
@@ -113,7 +113,7 @@ func RunPostureChecks() error {
if noChecks {
postureCheckVolationSeverityLevel = schema.SeverityUnknown
} else {
postureChecksViolations, postureCheckVolationSeverityLevel = GetPostureCheckViolations(pcLi, deviceInfo)
postureChecksViolations, postureCheckVolationSeverityLevel = GetPostureCheckViolations(ctx, pcLi, deviceInfo)
}
if nodeI.IsUserNode {
extclient, err := logic.GetExtClient(ctx, nodeI.StaticNode.ClientID, nodeI.StaticNode.Network)
@@ -168,16 +168,15 @@ func RunPostureChecks() error {
return nil
}
func CheckPostureViolations(d models.PostureCheckDeviceInfo, network schema.NetworkID) ([]models.Violation, schema.Severity) {
// todo(nm-341): pass tenant scoped context.
if !logic.GetFeatureFlags(context.Background()).EnablePostureChecks {
func CheckPostureViolations(ctx context.Context, d models.PostureCheckDeviceInfo, network schema.NetworkID) ([]models.Violation, schema.Severity) {
if !logic.GetFeatureFlags(ctx).EnablePostureChecks {
return []models.Violation{}, schema.SeverityUnknown
}
pcLi, err := (&schema.PostureCheck{NetworkID: network}).ListByNetwork(db.WithContext(context.TODO()))
pcLi, err := (&schema.PostureCheck{NetworkID: network}).ListByNetwork(ctx)
if err != nil || len(pcLi) == 0 {
return []models.Violation{}, schema.SeverityUnknown
}
violations, level := GetPostureCheckViolations(pcLi, d)
violations, level := GetPostureCheckViolations(ctx, pcLi, d)
return violations, level
}
@@ -185,12 +184,13 @@ func CheckPostureViolations(d models.PostureCheckDeviceInfo, network schema.Netw
// evaluates network posture checks. Use this for registration and join flows
// instead of building PostureCheckDeviceInfo without integration state.
func CheckPostureViolationsForHost(
ctx context.Context,
host *schema.Host,
tags map[models.TagID]struct{},
network schema.NetworkID,
skipAutoUpdate bool,
) ([]models.Violation, schema.Severity) {
return CheckPostureViolations(GetPostureCheckDeviceInfoForHost(host, tags, skipAutoUpdate, true), network)
return CheckPostureViolations(ctx, GetPostureCheckDeviceInfoForHost(host, tags, skipAutoUpdate, true), network)
}
func GetPostureCheckDeviceInfoForHost(
@@ -241,9 +241,8 @@ func attachIntegrationStates(ctx context.Context, hostID string, d *models.Postu
}
}
}
func GetPostureCheckViolations(checks []schema.PostureCheck, d models.PostureCheckDeviceInfo) ([]models.Violation, schema.Severity) {
// todo(nm-341): pass tenant-scoped context.
if !logic.GetFeatureFlags(context.Background()).EnablePostureChecks {
func GetPostureCheckViolations(ctx context.Context, checks []schema.PostureCheck, d models.PostureCheckDeviceInfo) ([]models.Violation, schema.Severity) {
if !logic.GetFeatureFlags(ctx).EnablePostureChecks {
return []models.Violation{}, schema.SeverityUnknown
}
var violations []models.Violation
+10 -10
View File
@@ -366,7 +366,7 @@ func DeleteNetworkRoles(ctx context.Context, netID string) {
for _, userGI := range userGs {
if _, ok := userGI.NetworkRoles.Data()[schema.NetworkID(netID)]; ok {
delete(userGI.NetworkRoles.Data(), schema.NetworkID(netID))
UpdateUserGroup(userGI)
_ = UpdateUserGroup(ctx, userGI)
}
}
@@ -530,7 +530,7 @@ func DeleteRole(ctx context.Context, rid schema.UserRoleID, force bool) error {
if _, ok := networkRoles[rid]; ok {
delete(networkRoles, rid)
ug.NetworkRoles.Data()[netID] = networkRoles
UpdateUserGroup(ug)
_ = UpdateUserGroup(ctx, ug)
}
}
}
@@ -548,13 +548,13 @@ func DeleteRole(ctx context.Context, rid schema.UserRoleID, force bool) error {
}).Delete(ctx)
}
func ValidateCreateGroupReq(g schema.UserGroup) error {
func ValidateCreateGroupReq(ctx context.Context, g schema.UserGroup) error {
// check if network roles are valid
for _, roleMap := range g.NetworkRoles.Data() {
for roleID := range roleMap {
role := &schema.UserRole{ID: roleID}
err := role.Get(db.WithContext(context.TODO()))
err := role.Get(ctx)
if err != nil {
return fmt.Errorf("invalid network role %s", roleID)
}
@@ -565,7 +565,7 @@ func ValidateCreateGroupReq(g schema.UserGroup) error {
}
return nil
}
func ValidateUpdateGroupReq(new schema.UserGroup) error {
func ValidateUpdateGroupReq(ctx context.Context, new schema.UserGroup) error {
var newHasAllNetworkRole, newHasSpecNetworkRole bool
for networkID := range new.NetworkRoles.Data() {
if networkID == schema.AllNetworks {
@@ -577,7 +577,7 @@ func ValidateUpdateGroupReq(new schema.UserGroup) error {
userRolesMap := new.NetworkRoles.Data()[networkID]
for roleID := range userRolesMap {
netRole := &schema.UserRole{ID: roleID}
err := netRole.Get(db.WithContext(context.TODO()))
err := netRole.Get(ctx)
if err != nil {
err = fmt.Errorf("invalid network role")
return err
@@ -679,12 +679,12 @@ func GetDefaultGroupAclName(groupName string) string {
}
// UpdateUserGroup - updates new user group
func UpdateUserGroup(g schema.UserGroup) error {
func UpdateUserGroup(ctx context.Context, g schema.UserGroup) error {
// check if the group exists
if g.ID == "" {
return errors.New("group id cannot be empty")
}
return g.Update(db.WithContext(context.TODO()))
return g.Update(ctx)
}
func DeleteAndCleanUpGroup(group *schema.UserGroup) error {
@@ -855,8 +855,8 @@ func IsNetworkRolesValid(networkRoles map[schema.NetworkID]map[schema.UserRoleID
}
// PrepareOauthUserFromInvite - init oauth user before create
func PrepareOauthUserFromInvite(in *schema.UserInvite) (schema.User, error) {
var newPass, fetchErr = logic.FetchOAuthSecret()
func PrepareOauthUserFromInvite(ctx context.Context, in *schema.UserInvite) (schema.User, error) {
var newPass, fetchErr = logic.FetchOAuthSecret(ctx)
if fetchErr != nil {
return schema.User{}, fetchErr
}
+2 -2
View File
@@ -20,9 +20,9 @@ import (
type ProUserExtensions struct{}
func (p *ProUserExtensions) ConfigureAuthType(user *schema.User) error {
func (p *ProUserExtensions) ConfigureAuthType(ctx context.Context, user *schema.User) error {
user.AuthType = schema.BasicAuth
oauthSecret, err := logic.FetchOAuthSecret()
oauthSecret, err := logic.FetchOAuthSecret(ctx)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil