From 175e371da908d517bd64483e1ec51476c47742f6 Mon Sep 17 00:00:00 2001 From: Anish Mukherjee Date: Fri, 20 Jan 2023 18:42:18 +0530 Subject: [PATCH 1/5] use host id in jwt claims --- controllers/node.go | 18 ++---------------- logic/jwts.go | 2 +- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/controllers/node.go b/controllers/node.go index 4af5526b..d87744a4 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -53,7 +53,6 @@ func nodeHandlers(r *mux.Router) { func authenticate(response http.ResponseWriter, request *http.Request) { var authRequest models.AuthParams - var result models.Node var errorResponse = models.ErrorResponse{ Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.", } @@ -82,20 +81,7 @@ func authenticate(response http.ResponseWriter, request *http.Request) { logic.ReturnErrorResponse(response, request, errorResponse) return } - var err error - result, err = logic.GetNodeByID(authRequest.ID) - if err != nil { - result, err = logic.GetDeletedNodeByID(authRequest.ID) - if err != nil { - errorResponse.Code = http.StatusBadRequest - errorResponse.Message = err.Error() - logger.Log(0, request.Header.Get("user"), - fmt.Sprintf("failed to get node info [%s]: %v", authRequest.ID, err)) - logic.ReturnErrorResponse(response, request, errorResponse) - return - } - } - host, err := logic.GetHost(result.HostID.String()) + host, err := logic.GetHost(authRequest.ID) if err != nil { errorResponse.Code = http.StatusBadRequest errorResponse.Message = err.Error() @@ -114,7 +100,7 @@ func authenticate(response http.ResponseWriter, request *http.Request) { return } - tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, result.Network) + tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, mux.Vars(request)["network"]) if tokenString == "" { errorResponse.Code = http.StatusBadRequest errorResponse.Message = "Could not create Token" diff --git a/logic/jwts.go b/logic/jwts.go index 8afe8c3b..0e1716da 100644 --- a/logic/jwts.go +++ b/logic/jwts.go @@ -130,7 +130,7 @@ func VerifyUserToken(tokenString string) (username string, networks []string, is } // VerifyToken - [nodes] Only -func VerifyToken(tokenString string) (nodeID string, mac string, network string, err error) { +func VerifyToken(tokenString string) (hostID string, mac string, network string, err error) { claims := &models.Claims{} // this may be a stupid way of serving up a master key From c57cf670ceac587f4de481180a9e9c39eda78c2a Mon Sep 17 00:00:00 2001 From: Anish Mukherjee Date: Mon, 23 Jan 2023 16:56:32 +0530 Subject: [PATCH 2/5] add separate auth endpoint for hosts --- controllers/hosts.go | 95 ++++++++++++++++++++++++++++++++++++++++++++ controllers/node.go | 18 ++++++++- 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/controllers/hosts.go b/controllers/hosts.go index a2b708fc..ee8ce047 100644 --- a/controllers/hosts.go +++ b/controllers/hosts.go @@ -12,6 +12,7 @@ import ( "github.com/gravitl/netmaker/logic" "github.com/gravitl/netmaker/models" "github.com/gravitl/netmaker/mq" + "golang.org/x/crypto/bcrypt" ) type hostNetworksUpdatePayload struct { @@ -26,6 +27,7 @@ func hostHandlers(r *mux.Router) { r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(deleteHostFromNetwork))).Methods(http.MethodDelete) r.HandleFunc("/api/hosts/{hostid}/relay", logic.SecurityCheck(false, http.HandlerFunc(createHostRelay))).Methods(http.MethodPost) r.HandleFunc("/api/hosts/{hostid}/relay", logic.SecurityCheck(false, http.HandlerFunc(deleteHostRelay))).Methods(http.MethodDelete) + r.HandleFunc("/api/hosts/adm/{network}/authenticate", authenticateHost).Methods(http.MethodPost) } // swagger:route GET /api/hosts hosts getHosts @@ -279,3 +281,96 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) { logger.Log(2, r.Header.Get("user"), fmt.Sprintf("removed host %s from network %s", currHost.Name, network)) w.WriteHeader(http.StatusOK) } + +// swagger:route POST /api/hosts/adm/{network}/authenticate hosts authenticateHost +// +// Authenticate to make further API calls related to a network. +// +// Schemes: https +// +// Security: +// oauth +// +// Responses: +// 200: successResponse +func authenticateHost(response http.ResponseWriter, request *http.Request) { + var authRequest models.AuthParams + var errorResponse = models.ErrorResponse{ + Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.", + } + + decoder := json.NewDecoder(request.Body) + decoderErr := decoder.Decode(&authRequest) + defer request.Body.Close() + + if decoderErr != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Message = decoderErr.Error() + logger.Log(0, request.Header.Get("user"), "error decoding request body: ", + decoderErr.Error()) + logic.ReturnErrorResponse(response, request, errorResponse) + return + } + errorResponse.Code = http.StatusBadRequest + if authRequest.ID == "" { + errorResponse.Message = "W1R3: ID can't be empty" + logger.Log(0, request.Header.Get("user"), errorResponse.Message) + logic.ReturnErrorResponse(response, request, errorResponse) + return + } else if authRequest.Password == "" { + errorResponse.Message = "W1R3: Password can't be empty" + logger.Log(0, request.Header.Get("user"), errorResponse.Message) + logic.ReturnErrorResponse(response, request, errorResponse) + return + } + host, err := logic.GetHost(authRequest.ID) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Message = err.Error() + logger.Log(0, request.Header.Get("user"), + "error retrieving host: ", err.Error()) + logic.ReturnErrorResponse(response, request, errorResponse) + return + } + err = bcrypt.CompareHashAndPassword([]byte(host.HostPass), []byte(authRequest.Password)) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Message = err.Error() + logger.Log(0, request.Header.Get("user"), + "error validating user password: ", err.Error()) + logic.ReturnErrorResponse(response, request, errorResponse) + return + } + + tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, mux.Vars(request)["network"]) + if tokenString == "" { + errorResponse.Code = http.StatusBadRequest + errorResponse.Message = "Could not create Token" + logger.Log(0, request.Header.Get("user"), + fmt.Sprintf("%s: %v", errorResponse.Message, err)) + logic.ReturnErrorResponse(response, request, errorResponse) + return + } + + var successResponse = models.SuccessResponse{ + Code: http.StatusOK, + Message: "W1R3: Host " + authRequest.ID + " Authorized", + Response: models.SuccessfulLoginResponse{ + AuthToken: tokenString, + ID: authRequest.ID, + }, + } + successJSONResponse, jsonError := json.Marshal(successResponse) + + if jsonError != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Message = err.Error() + logger.Log(0, request.Header.Get("user"), + "error marshalling resp: ", err.Error()) + logic.ReturnErrorResponse(response, request, errorResponse) + return + } + response.WriteHeader(http.StatusOK) + response.Header().Set("Content-Type", "application/json") + response.Write(successJSONResponse) +} diff --git a/controllers/node.go b/controllers/node.go index d87744a4..4af5526b 100644 --- a/controllers/node.go +++ b/controllers/node.go @@ -53,6 +53,7 @@ func nodeHandlers(r *mux.Router) { func authenticate(response http.ResponseWriter, request *http.Request) { var authRequest models.AuthParams + var result models.Node var errorResponse = models.ErrorResponse{ Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.", } @@ -81,7 +82,20 @@ func authenticate(response http.ResponseWriter, request *http.Request) { logic.ReturnErrorResponse(response, request, errorResponse) return } - host, err := logic.GetHost(authRequest.ID) + var err error + result, err = logic.GetNodeByID(authRequest.ID) + if err != nil { + result, err = logic.GetDeletedNodeByID(authRequest.ID) + if err != nil { + errorResponse.Code = http.StatusBadRequest + errorResponse.Message = err.Error() + logger.Log(0, request.Header.Get("user"), + fmt.Sprintf("failed to get node info [%s]: %v", authRequest.ID, err)) + logic.ReturnErrorResponse(response, request, errorResponse) + return + } + } + host, err := logic.GetHost(result.HostID.String()) if err != nil { errorResponse.Code = http.StatusBadRequest errorResponse.Message = err.Error() @@ -100,7 +114,7 @@ func authenticate(response http.ResponseWriter, request *http.Request) { return } - tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, mux.Vars(request)["network"]) + tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, result.Network) if tokenString == "" { errorResponse.Code = http.StatusBadRequest errorResponse.Message = "Could not create Token" From 41fe78ccaf0cdc5c1d917c81d1d2f55351c89891 Mon Sep 17 00:00:00 2001 From: Anish Mukherjee Date: Mon, 23 Jan 2023 19:19:33 +0530 Subject: [PATCH 3/5] use status authorized on password check --- controllers/hosts.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/controllers/hosts.go b/controllers/hosts.go index ee8ce047..518aebb9 100644 --- a/controllers/hosts.go +++ b/controllers/hosts.go @@ -334,8 +334,8 @@ func authenticateHost(response http.ResponseWriter, request *http.Request) { } err = bcrypt.CompareHashAndPassword([]byte(host.HostPass), []byte(authRequest.Password)) if err != nil { - errorResponse.Code = http.StatusBadRequest - errorResponse.Message = err.Error() + errorResponse.Code = http.StatusUnauthorized + errorResponse.Message = "unauthorized" logger.Log(0, request.Header.Get("user"), "error validating user password: ", err.Error()) logic.ReturnErrorResponse(response, request, errorResponse) @@ -344,8 +344,8 @@ func authenticateHost(response http.ResponseWriter, request *http.Request) { tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, mux.Vars(request)["network"]) if tokenString == "" { - errorResponse.Code = http.StatusBadRequest - errorResponse.Message = "Could not create Token" + errorResponse.Code = http.StatusUnauthorized + errorResponse.Message = "unauthorized" logger.Log(0, request.Header.Get("user"), fmt.Sprintf("%s: %v", errorResponse.Message, err)) logic.ReturnErrorResponse(response, request, errorResponse) From e95772b1c09ffb69ee365727373e243e9a909b17 Mon Sep 17 00:00:00 2001 From: Anish Mukherjee Date: Tue, 24 Jan 2023 11:17:55 +0530 Subject: [PATCH 4/5] remove network param --- controllers/hosts.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/hosts.go b/controllers/hosts.go index 518aebb9..6063a868 100644 --- a/controllers/hosts.go +++ b/controllers/hosts.go @@ -27,7 +27,7 @@ func hostHandlers(r *mux.Router) { r.HandleFunc("/api/hosts/{hostid}/networks/{network}", logic.SecurityCheck(true, http.HandlerFunc(deleteHostFromNetwork))).Methods(http.MethodDelete) r.HandleFunc("/api/hosts/{hostid}/relay", logic.SecurityCheck(false, http.HandlerFunc(createHostRelay))).Methods(http.MethodPost) r.HandleFunc("/api/hosts/{hostid}/relay", logic.SecurityCheck(false, http.HandlerFunc(deleteHostRelay))).Methods(http.MethodDelete) - r.HandleFunc("/api/hosts/adm/{network}/authenticate", authenticateHost).Methods(http.MethodPost) + r.HandleFunc("/api/hosts/adm/authenticate", authenticateHost).Methods(http.MethodPost) } // swagger:route GET /api/hosts hosts getHosts @@ -342,7 +342,7 @@ func authenticateHost(response http.ResponseWriter, request *http.Request) { return } - tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, mux.Vars(request)["network"]) + tokenString, err := logic.CreateJWT(authRequest.ID, authRequest.MacAddress, "") if tokenString == "" { errorResponse.Code = http.StatusUnauthorized errorResponse.Message = "unauthorized" From fe13d2c20c4a370a3476984418a5d1bc453db2ca Mon Sep 17 00:00:00 2001 From: Anish Mukherjee Date: Tue, 24 Jan 2023 17:26:39 +0530 Subject: [PATCH 5/5] update swagger specs --- controllers/hosts.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/controllers/hosts.go b/controllers/hosts.go index 6063a868..08d21e63 100644 --- a/controllers/hosts.go +++ b/controllers/hosts.go @@ -282,9 +282,9 @@ func deleteHostFromNetwork(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) } -// swagger:route POST /api/hosts/adm/{network}/authenticate hosts authenticateHost +// swagger:route POST /api/hosts/adm/authenticate hosts authenticateHost // -// Authenticate to make further API calls related to a network. +// Host based authentication for making further API calls. // // Schemes: https //