netmaker/logic/settings.go
Vishal Dalwadi 3551e8e24e
NET-1996: Add Support for TOTP Authentication. (#3517)
* feat(git): ignore run configurations;

* feat(go): add support for TOTP authentication;

* fix(go): api docs;

* fix(go): static checks failing;

* fix(go): ignore mfa enforcement for user auth;

* feat(go): allow resetting mfa;

* feat(go): allow resetting mfa;

* feat(go): use library function;

* fix(go): signature;

* feat(go): allow only master user to unset user's mfa;

* feat(go): set caller when master to prevent panic;

* feat(go): make messages more user friendly;

* fix(go): run go mod tidy;

* fix(go): optimize imports;

* fix(go): return unauthorized on token expiry;

* fix(go): move mfa endpoints under username;

* fix(go): set is mfa enabled when converting;

* feat(go): allow authenticated users to use preauth apis;

* feat(go): set correct header value;

* feat(go): allow super-admins and admins to unset mfa;

* feat(go): allow user to unset mfa if not enforced;
2025-06-26 08:29:13 +05:30

353 lines
10 KiB
Go

package logic
import (
"encoding/json"
"os"
"regexp"
"strconv"
"strings"
"sync"
"time"
"github.com/gravitl/netmaker/config"
"github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/models"
"github.com/gravitl/netmaker/servercfg"
)
var serverSettingsDBKey = "server_cfg"
var SettingsMutex = &sync.RWMutex{}
func GetServerSettings() (s models.ServerSettings) {
data, err := database.FetchRecord(database.SERVER_SETTINGS, serverSettingsDBKey)
if err != nil {
return
}
json.Unmarshal([]byte(data), &s)
return
}
func UpsertServerSettings(s models.ServerSettings) error {
// get curr settings
currSettings := GetServerSettings()
if s.ClientSecret == Mask() {
s.ClientSecret = currSettings.ClientSecret
}
data, err := json.Marshal(s)
if err != nil {
return err
}
err = database.Insert(serverSettingsDBKey, string(data), database.SERVER_SETTINGS)
if err != nil {
return err
}
return nil
}
func ValidateNewSettings(req models.ServerSettings) bool {
// TODO: add checks for different fields
return true
}
func GetServerSettingsFromEnv() (s models.ServerSettings) {
s = models.ServerSettings{
NetclientAutoUpdate: servercfg.AutoUpdateEnabled(),
Verbosity: servercfg.GetVerbosity(),
AuthProvider: os.Getenv("AUTH_PROVIDER"),
OIDCIssuer: os.Getenv("OIDC_ISSUER"),
ClientID: os.Getenv("CLIENT_ID"),
ClientSecret: os.Getenv("CLIENT_SECRET"),
AzureTenant: servercfg.GetAzureTenant(),
Telemetry: servercfg.Telemetry(),
BasicAuth: servercfg.IsBasicAuthEnabled(),
JwtValidityDuration: servercfg.GetJwtValidityDurationFromEnv() / 60,
RacRestrictToSingleNetwork: servercfg.GetRacRestrictToSingleNetwork(),
EndpointDetection: servercfg.IsEndpointDetectionEnabled(),
AllowedEmailDomains: servercfg.GetAllowedEmailDomains(),
EmailSenderAddr: servercfg.GetSenderEmail(),
EmailSenderUser: servercfg.GetSenderUser(),
EmailSenderPassword: servercfg.GetEmaiSenderPassword(),
SmtpHost: servercfg.GetSmtpHost(),
SmtpPort: servercfg.GetSmtpPort(),
MetricInterval: servercfg.GetMetricInterval(),
MetricsPort: servercfg.GetMetricsPort(),
ManageDNS: servercfg.GetManageDNS(),
DefaultDomain: servercfg.GetDefaultDomain(),
Stun: servercfg.IsStunEnabled(),
StunServers: servercfg.GetStunServers(),
TextSize: "16",
Theme: models.Dark,
ReducedMotion: false,
}
return
}
// GetServerConfig - gets the server config into memory from file or env
func GetServerConfig() config.ServerConfig {
var cfg config.ServerConfig
settings := GetServerSettings()
cfg.APIConnString = servercfg.GetAPIConnString()
cfg.CoreDNSAddr = servercfg.GetCoreDNSAddr()
cfg.APIHost = servercfg.GetAPIHost()
cfg.APIPort = servercfg.GetAPIPort()
cfg.MasterKey = "(hidden)"
cfg.DNSKey = "(hidden)"
cfg.AllowedOrigin = servercfg.GetAllowedOrigin()
cfg.RestBackend = "off"
cfg.NodeID = servercfg.GetNodeID()
cfg.BrokerType = servercfg.GetBrokerType()
cfg.EmqxRestEndpoint = servercfg.GetEmqxRestEndpoint()
if settings.NetclientAutoUpdate {
cfg.NetclientAutoUpdate = "enabled"
} else {
cfg.NetclientAutoUpdate = "disabled"
}
if servercfg.IsRestBackend() {
cfg.RestBackend = "on"
}
cfg.DNSMode = "off"
if servercfg.IsDNSMode() {
cfg.DNSMode = "on"
}
cfg.DisplayKeys = "off"
if servercfg.IsDisplayKeys() {
cfg.DisplayKeys = "on"
}
cfg.DisableRemoteIPCheck = "off"
if servercfg.DisableRemoteIPCheck() {
cfg.DisableRemoteIPCheck = "on"
}
cfg.Database = servercfg.GetDB()
cfg.Platform = servercfg.GetPlatform()
cfg.Version = servercfg.GetVersion()
cfg.PublicIp = servercfg.GetServerHostIP()
// == auth config ==
var authInfo = GetAuthProviderInfo(settings)
cfg.AuthProvider = authInfo[0]
cfg.ClientID = authInfo[1]
cfg.ClientSecret = authInfo[2]
cfg.FrontendURL = servercfg.GetFrontendURL()
cfg.AzureTenant = settings.AzureTenant
cfg.Telemetry = settings.Telemetry
cfg.Server = servercfg.GetServer()
cfg.Verbosity = settings.Verbosity
cfg.IsPro = "no"
if servercfg.IsPro {
cfg.IsPro = "yes"
}
cfg.JwtValidityDuration = time.Duration(settings.JwtValidityDuration) * time.Minute
cfg.RacRestrictToSingleNetwork = settings.RacRestrictToSingleNetwork
cfg.MetricInterval = settings.MetricInterval
cfg.ManageDNS = settings.ManageDNS
cfg.Stun = settings.Stun
cfg.StunServers = settings.StunServers
cfg.DefaultDomain = settings.DefaultDomain
return cfg
}
// GetServerInfo - gets the server config into memory from file or env
func GetServerInfo() models.ServerConfig {
var cfg models.ServerConfig
serverSettings := GetServerSettings()
cfg.Server = servercfg.GetServer()
if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
cfg.MQUserName = "HOST_ID"
cfg.MQPassword = "HOST_PASS"
} else {
cfg.MQUserName = servercfg.GetMqUserName()
cfg.MQPassword = servercfg.GetMqPassword()
}
cfg.API = servercfg.GetAPIConnString()
cfg.CoreDNSAddr = servercfg.GetCoreDNSAddr()
cfg.APIPort = servercfg.GetAPIPort()
cfg.DNSMode = "off"
cfg.Broker = servercfg.GetPublicBrokerEndpoint()
cfg.BrokerType = servercfg.GetBrokerType()
if servercfg.IsDNSMode() {
cfg.DNSMode = "on"
}
cfg.Version = servercfg.GetVersion()
cfg.IsPro = servercfg.IsPro
cfg.MetricInterval = serverSettings.MetricInterval
cfg.MetricsPort = serverSettings.MetricsPort
cfg.ManageDNS = serverSettings.ManageDNS
cfg.Stun = serverSettings.Stun
cfg.StunServers = serverSettings.StunServers
cfg.DefaultDomain = serverSettings.DefaultDomain
cfg.EndpointDetection = serverSettings.EndpointDetection
return cfg
}
// GetDefaultDomain - get the default domain
func GetDefaultDomain() string {
return GetServerSettings().DefaultDomain
}
func ValidateDomain(domain string) bool {
domainPattern := `[a-zA-Z0-9][a-zA-Z0-9_-]{0,62}(\.[a-zA-Z0-9][a-zA-Z0-9_-]{0,62})*(\.[a-zA-Z][a-zA-Z0-9]{0,10}){1}`
exp := regexp.MustCompile("^" + domainPattern + "$")
return exp.MatchString(domain)
}
// Telemetry - checks if telemetry data should be sent
func Telemetry() string {
return GetServerSettings().Telemetry
}
// GetJwtValidityDuration - returns the JWT validity duration in minutes
func GetJwtValidityDuration() time.Duration {
return GetServerConfig().JwtValidityDuration
}
// GetRacRestrictToSingleNetwork - returns whether the feature to allow simultaneous network connections via RAC is enabled
func GetRacRestrictToSingleNetwork() bool {
return GetServerSettings().RacRestrictToSingleNetwork
}
func GetSmtpHost() string {
return GetServerSettings().SmtpHost
}
func GetSmtpPort() int {
return GetServerSettings().SmtpPort
}
func GetSenderEmail() string {
return GetServerSettings().EmailSenderAddr
}
func GetSenderUser() string {
return GetServerSettings().EmailSenderUser
}
func GetEmaiSenderPassword() string {
return GetServerSettings().EmailSenderPassword
}
// AutoUpdateEnabled returns a boolean indicating whether netclient auto update is enabled or disabled
// default is enabled
func AutoUpdateEnabled() bool {
return GetServerSettings().NetclientAutoUpdate
}
// GetAuthProviderInfo = gets the oauth provider info
func GetAuthProviderInfo(settings models.ServerSettings) (pi []string) {
var authProvider = ""
defer func() {
if authProvider == "oidc" {
if settings.OIDCIssuer != "" {
pi = append(pi, settings.OIDCIssuer)
} else {
pi = []string{"", "", ""}
}
}
}()
if settings.AuthProvider != "" && settings.ClientID != "" && settings.ClientSecret != "" {
authProvider = strings.ToLower(settings.AuthProvider)
if authProvider == "google" || authProvider == "azure-ad" || authProvider == "github" || authProvider == "oidc" {
return []string{authProvider, settings.ClientID, settings.ClientSecret}
} else {
authProvider = ""
}
}
return []string{"", "", ""}
}
// GetAzureTenant - retrieve the azure tenant ID from env variable or config file
func GetAzureTenant() string {
return GetServerSettings().AzureTenant
}
// IsSyncEnabled returns whether auth provider sync is enabled.
func IsSyncEnabled() bool {
return GetServerSettings().SyncEnabled
}
// GetIDPSyncInterval returns the interval at which the netmaker should sync
// data from IDP.
func GetIDPSyncInterval() time.Duration {
syncInterval, err := time.ParseDuration(GetServerSettings().IDPSyncInterval)
if err != nil {
return 24 * time.Hour
}
if syncInterval == 0 {
return 24 * time.Hour
}
return syncInterval
}
// GetMetricsPort - get metrics port
func GetMetricsPort() int {
return GetServerSettings().MetricsPort
}
// GetMetricInterval - get the publish metric interval
func GetMetricIntervalInMinutes() time.Duration {
//default 15 minutes
mi := "15"
if os.Getenv("PUBLISH_METRIC_INTERVAL") != "" {
mi = os.Getenv("PUBLISH_METRIC_INTERVAL")
}
interval, err := strconv.Atoi(mi)
if err != nil {
interval = 15
}
return time.Duration(interval) * time.Minute
}
// GetMetricInterval - get the publish metric interval
func GetMetricInterval() string {
return GetServerSettings().MetricInterval
}
// GetManageDNS - if manage DNS enabled or not
func GetManageDNS() bool {
return GetServerSettings().ManageDNS
}
// IsBasicAuthEnabled - checks if basic auth has been configured to be turned off
func IsBasicAuthEnabled() bool {
return GetServerSettings().BasicAuth
}
// IsMFAEnforced returns whether MFA has been enforced.
func IsMFAEnforced() bool {
return GetServerSettings().MFAEnforced
}
// IsEndpointDetectionEnabled - returns true if endpoint detection enabled
func IsEndpointDetectionEnabled() bool {
return GetServerSettings().EndpointDetection
}
// IsStunEnabled - returns true if STUN set to on
func IsStunEnabled() bool {
return GetServerSettings().Stun
}
func GetStunServers() string {
return GetServerSettings().StunServers
}
// GetAllowedEmailDomains - gets the allowed email domains for oauth signup
func GetAllowedEmailDomains() string {
return GetServerSettings().AllowedEmailDomains
}
func GetVerbosity() int32 {
return GetServerSettings().Verbosity
}
func Mask() string {
return ("..................")
}