From 0d4552db5efb64675ff59f735bcd071fe1b21a0f Mon Sep 17 00:00:00 2001
From: Abhishek K <32607604+abhishek9686@users.noreply.github.com>
Date: Wed, 3 Apr 2024 11:20:19 +0530
Subject: [PATCH] NET-1064: Oauth User SignUp Approval Flow (#2874)
* add pending users api
* insert user to pending users on first time oauth login
* add pending user check on headless login
* fix conflicting apis
* no records error
* add allowed emails domains for oauth singup to config
* check if user is allowed to signup
---
auth/auth.go | 28 ++++++-
auth/azure-ad.go | 27 ++++++-
auth/error.go | 27 ++++++-
auth/github.go | 27 ++++++-
auth/google.go | 27 ++++++-
auth/headless_callback.go | 21 ++++--
auth/oidc.go | 27 ++++++-
config/config.go | 1 +
controllers/user.go | 139 +++++++++++++++++++++++++++++++++++
database/database.go | 4 +-
logic/jwts.go | 1 -
logic/users.go | 44 +++++++++++
scripts/netmaker.default.env | 4 +-
scripts/nm-quick.sh | 2 +-
servercfg/serverconf.go | 11 +++
15 files changed, 361 insertions(+), 29 deletions(-)
diff --git a/auth/auth.go b/auth/auth.go
index 61bbdda1..f139c2c4 100644
--- a/auth/auth.go
+++ b/auth/auth.go
@@ -75,7 +75,7 @@ func InitializeAuthProvider() string {
if functions == nil {
return ""
}
- var _, err = fetchPassValue(logic.RandomString(64))
+ var _, err = FetchPassValue(logic.RandomString(64))
if err != nil {
logger.Log(0, err.Error())
return ""
@@ -156,7 +156,7 @@ func HandleAuthLogin(w http.ResponseWriter, r *http.Request) {
// IsOauthUser - returns
func IsOauthUser(user *models.User) error {
- var currentValue, err = fetchPassValue("")
+ var currentValue, err = FetchPassValue("")
if err != nil {
return err
}
@@ -246,7 +246,7 @@ func addUser(email string) error {
slog.Error("error checking for existence of admin user during OAuth login for", "email", email, "error", err)
return err
} // generate random password to adapt to current model
- var newPass, fetchErr = fetchPassValue("")
+ var newPass, fetchErr = FetchPassValue("")
if fetchErr != nil {
return fetchErr
}
@@ -272,7 +272,7 @@ func addUser(email string) error {
return nil
}
-func fetchPassValue(newValue string) (string, error) {
+func FetchPassValue(newValue string) (string, error) {
type valueHolder struct {
Value string `json:"value" bson:"value"`
@@ -334,3 +334,23 @@ func isStateCached(state string) bool {
_, err := netcache.Get(state)
return err == nil || strings.Contains(err.Error(), "expired")
}
+
+// isEmailAllowed - checks if email is allowed to signup
+func isEmailAllowed(email string) bool {
+ allowedDomains := servercfg.GetAllowedEmailDomains()
+ domains := strings.Split(allowedDomains, ",")
+ if len(domains) == 1 && domains[0] == "*" {
+ return true
+ }
+ emailParts := strings.Split(email, "@")
+ if len(emailParts) < 2 {
+ return false
+ }
+ baseDomainOfEmail := emailParts[1]
+ for _, domain := range domains {
+ if domain == baseDomainOfEmail {
+ return true
+ }
+ }
+ return false
+}
diff --git a/auth/azure-ad.go b/auth/azure-ad.go
index f6f565fb..7d6d0eb1 100644
--- a/auth/azure-ad.go
+++ b/auth/azure-ad.go
@@ -7,6 +7,7 @@ import (
"io"
"net/http"
+ "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
@@ -60,9 +61,29 @@ func handleAzureCallback(w http.ResponseWriter, r *http.Request) {
handleOauthNotConfigured(w)
return
}
+ if !isEmailAllowed(content.UserPrincipalName) {
+ handleOauthUserNotAllowedToSignUp(w)
+ return
+ }
+ // check if user approval is already pending
+ if logic.IsPendingUser(content.UserPrincipalName) {
+ handleOauthUserNotAllowed(w)
+ return
+ }
_, err = logic.GetUser(content.UserPrincipalName)
- if err != nil { // user must not exists, so try to make one
- if err = addUser(content.UserPrincipalName); err != nil {
+ if err != nil {
+ if database.IsEmptyRecord(err) { // user must not exist, so try to make one
+ err = logic.InsertPendingUser(&models.User{
+ UserName: content.UserPrincipalName,
+ })
+ if err != nil {
+ handleSomethingWentWrong(w)
+ return
+ }
+ handleOauthUserNotAllowed(w)
+ return
+ } else {
+ handleSomethingWentWrong(w)
return
}
}
@@ -75,7 +96,7 @@ func handleAzureCallback(w http.ResponseWriter, r *http.Request) {
handleOauthUserNotAllowed(w)
return
}
- var newPass, fetchErr = fetchPassValue("")
+ var newPass, fetchErr = FetchPassValue("")
if fetchErr != nil {
return
}
diff --git a/auth/error.go b/auth/error.go
index b982bc98..c5bd0e74 100644
--- a/auth/error.go
+++ b/auth/error.go
@@ -13,7 +13,8 @@ const oauthNotConfigured = `
const userNotAllowed = `
Only Admins are allowed to access Dashboard.
-Non-Admins can access the netmaker networks using RemoteAccessClient.
+Furthermore, Admin has to approve your identity to have access to netmaker networks
+Once your identity is approved, Non-Admins can access the netmaker networks using RemoteAccessClient.
`
@@ -23,6 +24,18 @@ const userNotFound = `
`
+const somethingwentwrong = `
+
+Something went wrong. Contact Admin
+
+`
+
+const notallowedtosignup = `
+
+You are not allowed to SignUp.
+
+`
+
func handleOauthUserNotFound(response http.ResponseWriter) {
response.Header().Set("Content-Type", "text/html; charset=utf-8")
response.WriteHeader(http.StatusNotFound)
@@ -35,9 +48,21 @@ func handleOauthUserNotAllowed(response http.ResponseWriter) {
response.Write([]byte(userNotAllowed))
}
+func handleOauthUserNotAllowedToSignUp(response http.ResponseWriter) {
+ response.Header().Set("Content-Type", "text/html; charset=utf-8")
+ response.WriteHeader(http.StatusForbidden)
+ response.Write([]byte(notallowedtosignup))
+}
+
// handleOauthNotConfigured - returns an appropriate html page when oauth is not configured on netmaker server but an oauth login was attempted
func handleOauthNotConfigured(response http.ResponseWriter) {
response.Header().Set("Content-Type", "text/html; charset=utf-8")
response.WriteHeader(http.StatusInternalServerError)
response.Write([]byte(oauthNotConfigured))
}
+
+func handleSomethingWentWrong(response http.ResponseWriter) {
+ response.Header().Set("Content-Type", "text/html; charset=utf-8")
+ response.WriteHeader(http.StatusInternalServerError)
+ response.Write([]byte(somethingwentwrong))
+}
diff --git a/auth/github.go b/auth/github.go
index 4bcc6753..50f9e78e 100644
--- a/auth/github.go
+++ b/auth/github.go
@@ -7,6 +7,7 @@ import (
"io"
"net/http"
+ "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
@@ -60,9 +61,29 @@ func handleGithubCallback(w http.ResponseWriter, r *http.Request) {
handleOauthNotConfigured(w)
return
}
+ if !isEmailAllowed(content.Login) {
+ handleOauthUserNotAllowedToSignUp(w)
+ return
+ }
+ // check if user approval is already pending
+ if logic.IsPendingUser(content.Login) {
+ handleOauthUserNotAllowed(w)
+ return
+ }
_, err = logic.GetUser(content.Login)
- if err != nil { // user must not exist, so try to make one
- if err = addUser(content.Login); err != nil {
+ if err != nil {
+ if database.IsEmptyRecord(err) { // user must not exist, so try to make one
+ err = logic.InsertPendingUser(&models.User{
+ UserName: content.Login,
+ })
+ if err != nil {
+ handleSomethingWentWrong(w)
+ return
+ }
+ handleOauthUserNotAllowed(w)
+ return
+ } else {
+ handleSomethingWentWrong(w)
return
}
}
@@ -75,7 +96,7 @@ func handleGithubCallback(w http.ResponseWriter, r *http.Request) {
handleOauthUserNotAllowed(w)
return
}
- var newPass, fetchErr = fetchPassValue("")
+ var newPass, fetchErr = FetchPassValue("")
if fetchErr != nil {
return
}
diff --git a/auth/google.go b/auth/google.go
index e61ab4c7..e77c7d45 100644
--- a/auth/google.go
+++ b/auth/google.go
@@ -8,6 +8,7 @@ import (
"net/http"
"time"
+ "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
@@ -62,9 +63,29 @@ func handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
handleOauthNotConfigured(w)
return
}
+ if !isEmailAllowed(content.Email) {
+ handleOauthUserNotAllowedToSignUp(w)
+ return
+ }
+ // check if user approval is already pending
+ if logic.IsPendingUser(content.Email) {
+ handleOauthUserNotAllowed(w)
+ return
+ }
_, err = logic.GetUser(content.Email)
- if err != nil { // user must not exists, so try to make one
- if err = addUser(content.Email); err != nil {
+ if err != nil {
+ if database.IsEmptyRecord(err) { // user must not exist, so try to make one
+ err = logic.InsertPendingUser(&models.User{
+ UserName: content.Email,
+ })
+ if err != nil {
+ handleSomethingWentWrong(w)
+ return
+ }
+ handleOauthUserNotAllowed(w)
+ return
+ } else {
+ handleSomethingWentWrong(w)
return
}
}
@@ -77,7 +98,7 @@ func handleGoogleCallback(w http.ResponseWriter, r *http.Request) {
handleOauthUserNotAllowed(w)
return
}
- var newPass, fetchErr = fetchPassValue("")
+ var newPass, fetchErr = FetchPassValue("")
if fetchErr != nil {
return
}
diff --git a/auth/headless_callback.go b/auth/headless_callback.go
index 72c0c500..d76704b7 100644
--- a/auth/headless_callback.go
+++ b/auth/headless_callback.go
@@ -50,19 +50,24 @@ func HandleHeadlessSSOCallback(w http.ResponseWriter, r *http.Request) {
return
}
- _, err = logic.GetUser(userClaims.getUserName())
- if err != nil { // user must not exists, so try to make one
- if err = addUser(userClaims.getUserName()); err != nil {
- logger.Log(1, "could not create new user: ", userClaims.getUserName())
- return
- }
+ // check if user approval is already pending
+ if logic.IsPendingUser(userClaims.getUserName()) {
+ handleOauthUserNotAllowed(w)
+ return
}
- newPass, fetchErr := fetchPassValue("")
+ user, err := logic.GetUser(userClaims.getUserName())
+ if err != nil {
+ response := returnErrTemplate("", "user not found", state, reqKeyIf)
+ w.WriteHeader(http.StatusForbidden)
+ w.Write(response)
+ return
+ }
+ newPass, fetchErr := FetchPassValue("")
if fetchErr != nil {
return
}
jwt, jwtErr := logic.VerifyAuthRequest(models.UserAuthParams{
- UserName: userClaims.getUserName(),
+ UserName: user.UserName,
Password: newPass,
})
if jwtErr != nil {
diff --git a/auth/oidc.go b/auth/oidc.go
index d38ddeea..ccbe7119 100644
--- a/auth/oidc.go
+++ b/auth/oidc.go
@@ -7,6 +7,7 @@ import (
"time"
"github.com/coreos/go-oidc/v3/oidc"
+ "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
@@ -73,9 +74,29 @@ func handleOIDCCallback(w http.ResponseWriter, r *http.Request) {
handleOauthNotConfigured(w)
return
}
+ if !isEmailAllowed(content.Email) {
+ handleOauthUserNotAllowedToSignUp(w)
+ return
+ }
+ // check if user approval is already pending
+ if logic.IsPendingUser(content.Email) {
+ handleOauthUserNotAllowed(w)
+ return
+ }
_, err = logic.GetUser(content.Email)
- if err != nil { // user must not exists, so try to make one
- if err = addUser(content.Email); err != nil {
+ if err != nil {
+ if database.IsEmptyRecord(err) { // user must not exist, so try to make one
+ err = logic.InsertPendingUser(&models.User{
+ UserName: content.Email,
+ })
+ if err != nil {
+ handleSomethingWentWrong(w)
+ return
+ }
+ handleOauthUserNotAllowed(w)
+ return
+ } else {
+ handleSomethingWentWrong(w)
return
}
}
@@ -88,7 +109,7 @@ func handleOIDCCallback(w http.ResponseWriter, r *http.Request) {
handleOauthUserNotAllowed(w)
return
}
- var newPass, fetchErr = fetchPassValue("")
+ var newPass, fetchErr = FetchPassValue("")
if fetchErr != nil {
return
}
diff --git a/config/config.go b/config/config.go
index 67acb117..67eb83af 100644
--- a/config/config.go
+++ b/config/config.go
@@ -92,6 +92,7 @@ type ServerConfig struct {
JwtValidityDuration time.Duration `yaml:"jwt_validity_duration"`
RacAutoDisable bool `yaml:"rac_auto_disable"`
CacheEnabled string `yaml:"caching_enabled"`
+ AllowedEmailDomains string `yaml:"allowed_email_domains"`
}
// SQLConfig - Generic SQL Config
diff --git a/controllers/user.go b/controllers/user.go
index 9548afb7..70c911e6 100644
--- a/controllers/user.go
+++ b/controllers/user.go
@@ -9,6 +9,7 @@ import (
"github.com/gorilla/mux"
"github.com/gorilla/websocket"
"github.com/gravitl/netmaker/auth"
+ "github.com/gravitl/netmaker/database"
"github.com/gravitl/netmaker/logger"
"github.com/gravitl/netmaker/logic"
"github.com/gravitl/netmaker/models"
@@ -35,6 +36,11 @@ func userHandlers(r *mux.Router) {
r.HandleFunc("/api/oauth/callback", auth.HandleAuthCallback).Methods(http.MethodGet)
r.HandleFunc("/api/oauth/headless", auth.HandleHeadlessSSO)
r.HandleFunc("/api/oauth/register/{regKey}", auth.RegisterHostSSO).Methods(http.MethodGet)
+ r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(getPendingUsers))).Methods(http.MethodGet)
+ r.HandleFunc("/api/users_pending", logic.SecurityCheck(true, http.HandlerFunc(deleteAllPendingUsers))).Methods(http.MethodDelete)
+ r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(deletePendingUser))).Methods(http.MethodDelete)
+ r.HandleFunc("/api/users_pending/user/{username}", logic.SecurityCheck(true, http.HandlerFunc(approvePendingUser))).Methods(http.MethodPost)
+
}
// swagger:route POST /api/users/adm/authenticate authenticate authenticateUser
@@ -583,3 +589,136 @@ func socketHandler(w http.ResponseWriter, r *http.Request) {
// Start handling the session
go auth.SessionHandler(conn)
}
+
+// swagger:route GET /api/users_pending user getPendingUsers
+//
+// Get all pending users.
+//
+// Schemes: https
+//
+// Security:
+// oauth
+//
+// Responses:
+// 200: userBodyResponse
+func getPendingUsers(w http.ResponseWriter, r *http.Request) {
+ // set header.
+ w.Header().Set("Content-Type", "application/json")
+
+ users, err := logic.ListPendingUsers()
+ if err != nil {
+ logger.Log(0, "failed to fetch users: ", err.Error())
+ logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+ return
+ }
+
+ logic.SortUsers(users[:])
+ logger.Log(2, r.Header.Get("user"), "fetched pending users")
+ json.NewEncoder(w).Encode(users)
+}
+
+// swagger:route POST /api/users_pending/user/{username} user approvePendingUser
+//
+// approve pending user.
+//
+// Schemes: https
+//
+// Security:
+// oauth
+//
+// Responses:
+// 200: userBodyResponse
+func approvePendingUser(w http.ResponseWriter, r *http.Request) {
+ // set header.
+ w.Header().Set("Content-Type", "application/json")
+ var params = mux.Vars(r)
+ username := params["username"]
+ users, err := logic.ListPendingUsers()
+
+ if err != nil {
+ logger.Log(0, "failed to fetch users: ", err.Error())
+ logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+ return
+ }
+ for _, user := range users {
+ if user.UserName == username {
+ var newPass, fetchErr = auth.FetchPassValue("")
+ if fetchErr != nil {
+ logic.ReturnErrorResponse(w, r, logic.FormatError(fetchErr, "internal"))
+ return
+ }
+ if err = logic.CreateUser(&models.User{
+ UserName: user.UserName,
+ Password: newPass,
+ }); err != nil {
+ logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to create user: %s", err), "internal"))
+ return
+ }
+ err = logic.DeletePendingUser(username)
+ if err != nil {
+ logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete pending user: %s", err), "internal"))
+ return
+ }
+ break
+ }
+ }
+ logic.ReturnSuccessResponse(w, r, "approved "+username)
+}
+
+// swagger:route DELETE /api/users_pending/user/{username} user deletePendingUser
+//
+// delete pending user.
+//
+// Schemes: https
+//
+// Security:
+// oauth
+//
+// Responses:
+// 200: userBodyResponse
+func deletePendingUser(w http.ResponseWriter, r *http.Request) {
+ // set header.
+ w.Header().Set("Content-Type", "application/json")
+ var params = mux.Vars(r)
+ username := params["username"]
+ users, err := logic.ListPendingUsers()
+
+ if err != nil {
+ logger.Log(0, "failed to fetch users: ", err.Error())
+ logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
+ return
+ }
+ for _, user := range users {
+ if user.UserName == username {
+ err = logic.DeletePendingUser(username)
+ if err != nil {
+ logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("failed to delete pending user: %s", err), "internal"))
+ return
+ }
+ break
+ }
+ }
+ logic.ReturnSuccessResponse(w, r, "deleted pending "+username)
+}
+
+// swagger:route DELETE /api/users_pending/{username}/pending user deleteAllPendingUsers
+//
+// delete all pending users.
+//
+// Schemes: https
+//
+// Security:
+// oauth
+//
+// Responses:
+// 200: userBodyResponse
+func deleteAllPendingUsers(w http.ResponseWriter, r *http.Request) {
+ // set header.
+ w.Header().Set("Content-Type", "application/json")
+ err := database.DeleteAllRecords(database.PENDING_USERS_TABLE_NAME)
+ if err != nil {
+ logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("failed to delete all pending users "+err.Error()), "internal"))
+ return
+ }
+ logic.ReturnSuccessResponse(w, r, "cleared all pending users")
+}
diff --git a/database/database.go b/database/database.go
index dc6385b3..dd2b2af1 100644
--- a/database/database.go
+++ b/database/database.go
@@ -61,7 +61,8 @@ const (
ENROLLMENT_KEYS_TABLE_NAME = "enrollmentkeys"
// HOST_ACTIONS_TABLE_NAME - table name for enrollmentkeys
HOST_ACTIONS_TABLE_NAME = "hostactions"
-
+ // PENDING_USERS_TABLE_NAME - table name for pending users
+ PENDING_USERS_TABLE_NAME = "pending_users"
// == ERROR CONSTS ==
// NO_RECORD - no singular result found
NO_RECORD = "no result found"
@@ -144,6 +145,7 @@ func createTables() {
CreateTable(HOSTS_TABLE_NAME)
CreateTable(ENROLLMENT_KEYS_TABLE_NAME)
CreateTable(HOST_ACTIONS_TABLE_NAME)
+ CreateTable(PENDING_USERS_TABLE_NAME)
}
func CreateTable(tableName string) error {
diff --git a/logic/jwts.go b/logic/jwts.go
index 6e227b59..a2b95049 100644
--- a/logic/jwts.go
+++ b/logic/jwts.go
@@ -106,7 +106,6 @@ func VerifyUserToken(tokenString string) (username string, issuperadmin, isadmin
if err != nil {
return "", false, false, err
}
-
if user.UserName != "" {
return user.UserName, user.IsSuperAdmin, user.IsAdmin, nil
}
diff --git a/logic/users.go b/logic/users.go
index 994a71db..987556e2 100644
--- a/logic/users.go
+++ b/logic/users.go
@@ -75,3 +75,47 @@ func GetSuperAdmin() (models.ReturnUser, error) {
}
return models.ReturnUser{}, errors.New("superadmin not found")
}
+
+func InsertPendingUser(u *models.User) error {
+ data, err := json.Marshal(u)
+ if err != nil {
+ return err
+ }
+ return database.Insert(u.UserName, string(data), database.PENDING_USERS_TABLE_NAME)
+}
+
+func DeletePendingUser(username string) error {
+ return database.DeleteRecord(database.PENDING_USERS_TABLE_NAME, username)
+}
+
+func IsPendingUser(username string) bool {
+ records, err := database.FetchRecords(database.PENDING_USERS_TABLE_NAME)
+ if err != nil {
+ return false
+
+ }
+ for _, record := range records {
+ u := models.ReturnUser{}
+ err := json.Unmarshal([]byte(record), &u)
+ if err == nil && u.UserName == username {
+ return true
+ }
+ }
+ return false
+}
+
+func ListPendingUsers() ([]models.ReturnUser, error) {
+ pendingUsers := []models.ReturnUser{}
+ records, err := database.FetchRecords(database.PENDING_USERS_TABLE_NAME)
+ if err != nil && !database.IsEmptyRecord(err) {
+ return pendingUsers, err
+ }
+ for _, record := range records {
+ u := models.ReturnUser{}
+ err = json.Unmarshal([]byte(record), &u)
+ if err == nil {
+ pendingUsers = append(pendingUsers, u)
+ }
+ }
+ return pendingUsers, nil
+}
diff --git a/scripts/netmaker.default.env b/scripts/netmaker.default.env
index b95a3fca..cf0c8d67 100644
--- a/scripts/netmaker.default.env
+++ b/scripts/netmaker.default.env
@@ -53,6 +53,8 @@ TELEMETRY=on
# OAuth section
#
###
+# only mentioned domains will be allowded to signup using oauth, by default all domains are allowed
+ALLOWED_EMAIL_DOMAINS=*
# ""
AUTH_PROVIDER=
# ""
@@ -70,4 +72,4 @@ JWT_VALIDITY_DURATION=43200
# Auto disable a user's connecteds clients bassed on JWT token expiration
RAC_AUTO_DISABLE=true
# if turned on data will be cached on to improve performance significantly (IMPORTANT: If HA set to `false` )
-CACHING_ENABLED=true
+CACHING_ENABLED=true
\ No newline at end of file
diff --git a/scripts/nm-quick.sh b/scripts/nm-quick.sh
index ed092426..787ac01a 100755
--- a/scripts/nm-quick.sh
+++ b/scripts/nm-quick.sh
@@ -248,7 +248,7 @@ save_config() { (
local toCopy=("SERVER_HOST" "MASTER_KEY" "MQ_USERNAME" "MQ_PASSWORD"
"INSTALL_TYPE" "NODE_ID" "DNS_MODE" "NETCLIENT_AUTO_UPDATE" "API_PORT"
"CORS_ALLOWED_ORIGIN" "DISPLAY_KEYS" "DATABASE" "SERVER_BROKER_ENDPOINT" "VERBOSITY"
- "DEBUG_MODE" "REST_BACKEND" "DISABLE_REMOTE_IP_CHECK" "TELEMETRY" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET"
+ "DEBUG_MODE" "REST_BACKEND" "DISABLE_REMOTE_IP_CHECK" "TELEMETRY" "ALLOWED_EMAIL_DOMAINS" "AUTH_PROVIDER" "CLIENT_ID" "CLIENT_SECRET"
"FRONTEND_URL" "AZURE_TENANT" "OIDC_ISSUER" "EXPORTER_API_PORT" "JWT_VALIDITY_DURATION" "RAC_AUTO_DISABLE" "CACHING_ENABLED")
for name in "${toCopy[@]}"; do
save_config_item $name "${!name}"
diff --git a/servercfg/serverconf.go b/servercfg/serverconf.go
index 20bb08bd..46e35233 100644
--- a/servercfg/serverconf.go
+++ b/servercfg/serverconf.go
@@ -703,3 +703,14 @@ func GetEmqxAppID() string {
func GetEmqxAppSecret() string {
return os.Getenv("EMQX_APP_SECRET")
}
+
+// GetAllowedEmailDomains - gets the allowed email domains for oauth signup
+func GetAllowedEmailDomains() string {
+ allowedDomains := "*"
+ if os.Getenv("ALLOWED_EMAIL_DOMAINS") != "" {
+ allowedDomains = os.Getenv("ALLOWED_EMAIL_DOMAINS")
+ } else if config.Config.Server.AllowedEmailDomains != "" {
+ allowedDomains = config.Config.Server.AllowedEmailDomains
+ }
+ return allowedDomains
+}