From ea67c6b752513310665f60316730fde9937910bd Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Thu, 7 Dec 2023 23:09:42 +0400 Subject: [PATCH 1/7] block normal user login from accessing dashboard --- controllers/user.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/controllers/user.go b/controllers/user.go index 64dd187a2..3e5eef3b5 100644 --- a/controllers/user.go +++ b/controllers/user.go @@ -62,6 +62,21 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) { return } + if val := request.Header.Get("from-ui"); val == "true" { + // request came from UI, if normal user block Login + user, err := logic.GetUser(authRequest.UserName) + if err != nil { + logger.Log(0, authRequest.UserName, "user validation failed: ", + err.Error()) + logic.ReturnErrorResponse(response, request, logic.FormatError(err, "unauthorized")) + return + } + if !(user.IsAdmin || user.IsSuperAdmin) { + logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("only admins can access dashboard"), "unauthorized")) + return + } + } + decoder := json.NewDecoder(request.Body) decoderErr := decoder.Decode(&authRequest) defer request.Body.Close() @@ -119,7 +134,7 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) { if client.OwnerID == username && !client.Enabled { slog.Info(fmt.Sprintf("enabling ext client %s for user %s due to RAC autodisabling feature", client.ClientID, client.OwnerID)) if newClient, err := logic.ToggleExtClientConnectivity(&client, true); err != nil { - slog.Error("error disabling ext client in RAC autodisable hook", "error", err) + slog.Error("error enabling ext client in RAC autodisable hook", "error", err) continue // dont return but try for other clients } else { // publish peer update to ingress gateway From 03b7141fde022f14529d5b7f05993637c49b43c9 Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Fri, 8 Dec 2023 16:58:07 +0400 Subject: [PATCH 2/7] header change --- controllers/user.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/user.go b/controllers/user.go index 3e5eef3b5..e9aa35f01 100644 --- a/controllers/user.go +++ b/controllers/user.go @@ -62,7 +62,7 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) { return } - if val := request.Header.Get("from-ui"); val == "true" { + if val := request.Header.Get("From-UI"); val == "true" { // request came from UI, if normal user block Login user, err := logic.GetUser(authRequest.UserName) if err != nil { From 5019ee7cce3e6c14c75f32b0b7e4851fb5608572 Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Fri, 8 Dec 2023 17:30:52 +0400 Subject: [PATCH 3/7] allow from ui header --- controllers/controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controllers/controller.go b/controllers/controller.go index 8e54d38b1..ea9747bc0 100644 --- a/controllers/controller.go +++ b/controllers/controller.go @@ -41,7 +41,7 @@ func HandleRESTRequests(wg *sync.WaitGroup, ctx context.Context) { // Currently allowed dev origin is all. Should change in prod // should consider analyzing the allowed methods further - headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "X-Requested-With", "Content-Type", "authorization"}) + headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "X-Requested-With", "Content-Type", "authorization", "From-UI"}) originsOk := handlers.AllowedOrigins(strings.Split(servercfg.GetAllowedOrigin(), ",")) methodsOk := handlers.AllowedMethods([]string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete}) From 8e3853afb2fcbf7f0cbf0326fbab8ac665425cd4 Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Fri, 8 Dec 2023 17:52:25 +0400 Subject: [PATCH 4/7] allow from ui header --- controllers/controller.go | 2 +- controllers/user.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/controller.go b/controllers/controller.go index ea9747bc0..d80093beb 100644 --- a/controllers/controller.go +++ b/controllers/controller.go @@ -41,7 +41,7 @@ func HandleRESTRequests(wg *sync.WaitGroup, ctx context.Context) { // Currently allowed dev origin is all. Should change in prod // should consider analyzing the allowed methods further - headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "X-Requested-With", "Content-Type", "authorization", "From-UI"}) + headersOk := handlers.AllowedHeaders([]string{"Access-Control-Allow-Origin", "X-Requested-With", "Content-Type", "authorization", "From-Ui"}) originsOk := handlers.AllowedOrigins(strings.Split(servercfg.GetAllowedOrigin(), ",")) methodsOk := handlers.AllowedMethods([]string{http.MethodGet, http.MethodPut, http.MethodPost, http.MethodDelete}) diff --git a/controllers/user.go b/controllers/user.go index e9aa35f01..149116472 100644 --- a/controllers/user.go +++ b/controllers/user.go @@ -62,7 +62,7 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) { return } - if val := request.Header.Get("From-UI"); val == "true" { + if val := request.Header.Get("From-Ui"); val == "true" { // request came from UI, if normal user block Login user, err := logic.GetUser(authRequest.UserName) if err != nil { From 5c878eac22fb79bfd4c01eb8fc3aa7871c27ac30 Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Fri, 8 Dec 2023 19:45:37 +0400 Subject: [PATCH 5/7] check for user role after decoding --- controllers/user.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/controllers/user.go b/controllers/user.go index 149116472..76e712182 100644 --- a/controllers/user.go +++ b/controllers/user.go @@ -62,6 +62,15 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) { return } + decoder := json.NewDecoder(request.Body) + decoderErr := decoder.Decode(&authRequest) + defer request.Body.Close() + if decoderErr != nil { + logger.Log(0, "error decoding request body: ", + decoderErr.Error()) + logic.ReturnErrorResponse(response, request, errorResponse) + return + } if val := request.Header.Get("From-Ui"); val == "true" { // request came from UI, if normal user block Login user, err := logic.GetUser(authRequest.UserName) @@ -76,16 +85,6 @@ func authenticateUser(response http.ResponseWriter, request *http.Request) { return } } - - decoder := json.NewDecoder(request.Body) - decoderErr := decoder.Decode(&authRequest) - defer request.Body.Close() - if decoderErr != nil { - logger.Log(0, "error decoding request body: ", - decoderErr.Error()) - logic.ReturnErrorResponse(response, request, errorResponse) - return - } username := authRequest.UserName jwt, err := logic.VerifyAuthRequest(authRequest) if err != nil { From f57abc7bb870bc6d14a4f64bb70a0585ab615fed Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Fri, 8 Dec 2023 20:43:19 +0400 Subject: [PATCH 6/7] block oauth login for normal user --- auth/error.go | 25 +++++++++++++++++++++++++ auth/google.go | 9 +++++++++ 2 files changed, 34 insertions(+) diff --git a/auth/error.go b/auth/error.go index 002eed058..b982bc980 100644 --- a/auth/error.go +++ b/auth/error.go @@ -10,6 +10,31 @@ const oauthNotConfigured = ` ` +const userNotAllowed = ` + +

Only Admins are allowed to access Dashboard.

+

Non-Admins can access the netmaker networks using RemoteAccessClient.

+ + +` +const userNotFound = ` + +

User Not Found.

+ +` + +func handleOauthUserNotFound(response http.ResponseWriter) { + response.Header().Set("Content-Type", "text/html; charset=utf-8") + response.WriteHeader(http.StatusNotFound) + response.Write([]byte(userNotFound)) +} + +func handleOauthUserNotAllowed(response http.ResponseWriter) { + response.Header().Set("Content-Type", "text/html; charset=utf-8") + response.WriteHeader(http.StatusForbidden) + response.Write([]byte(userNotAllowed)) +} + // 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") diff --git a/auth/google.go b/auth/google.go index de144a3cc..e61ab4c7c 100644 --- a/auth/google.go +++ b/auth/google.go @@ -68,6 +68,15 @@ func handleGoogleCallback(w http.ResponseWriter, r *http.Request) { return } } + user, err := logic.GetUser(content.Email) + if err != nil { + handleOauthUserNotFound(w) + return + } + if !(user.IsSuperAdmin || user.IsAdmin) { + handleOauthUserNotAllowed(w) + return + } var newPass, fetchErr = fetchPassValue("") if fetchErr != nil { return From 745f6237deec7250ea2417e0858518ed1c7adfbc Mon Sep 17 00:00:00 2001 From: Abhishek Kondur Date: Fri, 8 Dec 2023 21:24:59 +0400 Subject: [PATCH 7/7] handle other oauth provider callback funcs for user login --- auth/azure-ad.go | 9 +++++++++ auth/github.go | 9 +++++++++ auth/oidc.go | 9 +++++++++ 3 files changed, 27 insertions(+) diff --git a/auth/azure-ad.go b/auth/azure-ad.go index 76b861167..f5bdf4c5b 100644 --- a/auth/azure-ad.go +++ b/auth/azure-ad.go @@ -66,6 +66,15 @@ func handleAzureCallback(w http.ResponseWriter, r *http.Request) { return } } + user, err := logic.GetUser(content.Email) + if err != nil { + handleOauthUserNotFound(w) + return + } + if !(user.IsSuperAdmin || user.IsAdmin) { + handleOauthUserNotAllowed(w) + return + } var newPass, fetchErr = fetchPassValue("") if fetchErr != nil { return diff --git a/auth/github.go b/auth/github.go index bdbbabc80..37c66085a 100644 --- a/auth/github.go +++ b/auth/github.go @@ -66,6 +66,15 @@ func handleGithubCallback(w http.ResponseWriter, r *http.Request) { return } } + user, err := logic.GetUser(content.Email) + if err != nil { + handleOauthUserNotFound(w) + return + } + if !(user.IsSuperAdmin || user.IsAdmin) { + handleOauthUserNotAllowed(w) + return + } var newPass, fetchErr = fetchPassValue("") if fetchErr != nil { return diff --git a/auth/oidc.go b/auth/oidc.go index 86530bc91..d38ddeea0 100644 --- a/auth/oidc.go +++ b/auth/oidc.go @@ -79,6 +79,15 @@ func handleOIDCCallback(w http.ResponseWriter, r *http.Request) { return } } + user, err := logic.GetUser(content.Email) + if err != nil { + handleOauthUserNotFound(w) + return + } + if !(user.IsSuperAdmin || user.IsAdmin) { + handleOauthUserNotAllowed(w) + return + } var newPass, fetchErr = fetchPassValue("") if fetchErr != nil { return