mirror of
https://github.com/gravitl/netmaker.git
synced 2025-10-05 16:57:51 +08:00
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
This commit is contained in:
28
auth/auth.go
28
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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -13,7 +13,8 @@ const oauthNotConfigured = `<!DOCTYPE html><html>
|
||||
const userNotAllowed = `<!DOCTYPE html><html>
|
||||
<body>
|
||||
<h3>Only Admins are allowed to access Dashboard.</h3>
|
||||
<p>Non-Admins can access the netmaker networks using <a href="https://docs.netmaker.io/pro/rac.html" target="_blank" rel="noopener">RemoteAccessClient.</a></p>
|
||||
<h3>Furthermore, Admin has to approve your identity to have access to netmaker networks</h3>
|
||||
<p>Once your identity is approved, Non-Admins can access the netmaker networks using <a href="https://docs.netmaker.io/pro/rac.html" target="_blank" rel="noopener">RemoteAccessClient.</a></p>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
@@ -23,6 +24,18 @@ const userNotFound = `<!DOCTYPE html><html>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
const somethingwentwrong = `<!DOCTYPE html><html>
|
||||
<body>
|
||||
<h3>Something went wrong. Contact Admin</h3>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
const notallowedtosignup = `<!DOCTYPE html><html>
|
||||
<body>
|
||||
<h3>You are not allowed to SignUp.</h3>
|
||||
</body>
|
||||
</html>`
|
||||
|
||||
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))
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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())
|
||||
// check if user approval is already pending
|
||||
if logic.IsPendingUser(userClaims.getUserName()) {
|
||||
handleOauthUserNotAllowed(w)
|
||||
return
|
||||
}
|
||||
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("")
|
||||
newPass, fetchErr := FetchPassValue("")
|
||||
if fetchErr != nil {
|
||||
return
|
||||
}
|
||||
jwt, jwtErr := logic.VerifyAuthRequest(models.UserAuthParams{
|
||||
UserName: userClaims.getUserName(),
|
||||
UserName: user.UserName,
|
||||
Password: newPass,
|
||||
})
|
||||
if jwtErr != nil {
|
||||
|
27
auth/oidc.go
27
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
|
||||
}
|
||||
|
@@ -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
|
||||
|
@@ -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")
|
||||
}
|
||||
|
@@ -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 {
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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=*
|
||||
# "<azure-ad|github|google|oidc>"
|
||||
AUTH_PROVIDER=
|
||||
# "<client id of your oauth provider>"
|
||||
|
@@ -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}"
|
||||
|
@@ -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
|
||||
}
|
||||
|
Reference in New Issue
Block a user