Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GRA-1339: host pull #2142

Merged
merged 1 commit into from
Mar 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions controllers/hosts.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package controller

import (
"context"
"encoding/json"
"errors"
"fmt"
Expand All @@ -26,6 +27,7 @@ func hostHandlers(r *mux.Router) {
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/authenticate", authenticateHost).Methods(http.MethodPost)
r.HandleFunc("/api/v1/host", authorize(true, false, "host", http.HandlerFunc(pull))).Methods(http.MethodGet)
}

// swagger:route GET /api/hosts hosts getHosts
Expand Down Expand Up @@ -53,6 +55,53 @@ func getHosts(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(apiHosts)
}

// swagger:route GET /api/v1/host pull pullHost
//
// Used by clients for "pull" command
//
// Schemes: https
//
// Security:
// oauth
//
// Responses:
// 200: pull
func pull(w http.ResponseWriter, r *http.Request) {

hostID := r.Header.Get(hostIDHeader) // return JSON/API formatted keys
if len(hostID) == 0 {
logger.Log(0, "no host authorized to pull")
logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("no host authorized to pull"), "internal"))
return
}
host, err := logic.GetHost(hostID)
if err != nil {
logger.Log(0, "no host found during pull", hostID)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
hPU, err := logic.GetPeerUpdateForHost(context.Background(), "", host, nil, nil)
if err != nil {
logger.Log(0, "could not pull peers for host", hostID)
logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
return
}
serverConf := servercfg.GetServerInfo()
if servercfg.GetBrokerType() == servercfg.EmqxBrokerType {
serverConf.MQUserName = hostID
}
response := models.HostPull{
Host: *host,
ServerConfig: serverConf,
Peers: hPU.Peers,
PeerIDs: hPU.PeerIDs,
}

logger.Log(1, hostID, "completed a pull")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(&response)
}

// swagger:route PUT /api/hosts/{hostid} hosts updateHost
//
// Updates a Netclient host on Netmaker server.
Expand Down
13 changes: 8 additions & 5 deletions controllers/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"golang.org/x/crypto/bcrypt"
)

var hostIDHeader = "host-id"

func nodeHandlers(r *mux.Router) {

r.HandleFunc("/api/nodes", authorize(false, false, "user", http.HandlerFunc(getAllNodes))).Methods(http.MethodGet)
Expand Down Expand Up @@ -152,7 +154,7 @@ func authenticate(response http.ResponseWriter, request *http.Request) {
// even if it's technically ok
// This is kind of a poor man's RBAC. There's probably a better/smarter way.
// TODO: Consider better RBAC implementations
func authorize(nodesAllowed, networkCheck bool, authNetwork string, next http.Handler) http.HandlerFunc {
func authorize(hostAllowed, networkCheck bool, authNetwork string, next http.Handler) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var errorResponse = models.ErrorResponse{
Code: http.StatusUnauthorized, Message: logic.Unauthorized_Msg,
Expand Down Expand Up @@ -184,11 +186,11 @@ func authorize(nodesAllowed, networkCheck bool, authNetwork string, next http.Ha
logic.ReturnErrorResponse(w, r, errorResponse)
return
}
//check if node instead of user
if nodesAllowed {
// check if host instead of user
if hostAllowed {
// TODO --- should ensure that node is only operating on itself
if _, _, _, err := logic.VerifyToken(authToken); err == nil {

if hostID, _, _, err := logic.VerifyHostToken(authToken); err == nil {
r.Header.Set(hostIDHeader, hostID)
// this indicates request is from a node
// used for failover - if a getNode comes from node, this will trigger a metrics wipe
next.ServeHTTP(w, r)
Expand Down Expand Up @@ -244,6 +246,7 @@ func authorize(nodesAllowed, networkCheck bool, authNetwork string, next http.Ha
} else {
isAuthorized = (nodeID == params["netid"])
}
case "host":
case "user":
isAuthorized = true
default:
Expand Down
4 changes: 2 additions & 2 deletions logic/jwts.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ func VerifyUserToken(tokenString string) (username string, networks []string, is
return "", nil, false, err
}

// VerifyToken - [nodes] Only
func VerifyToken(tokenString string) (hostID string, mac string, network string, err error) {
// VerifyHostToken - [hosts] Only
func VerifyHostToken(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
Expand Down
8 changes: 8 additions & 0 deletions models/structs.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,14 @@ type TrafficKeys struct {
Server []byte `json:"server" bson:"server" yaml:"server"`
}

// HostPull - response of a host's pull
type HostPull struct {
Host Host `json:"host" yaml:"host"`
Peers []wgtypes.PeerConfig `json:"peers" yaml:"peers"`
ServerConfig ServerConfig `json:"server_config" yaml:"server_config"`
PeerIDs PeerMap `json:"peer_ids,omitempty" yaml:"peer_ids,omitempty"`
}

// NodeGet - struct for a single node get response
type NodeGet struct {
Node Node `json:"node" bson:"node" yaml:"node"`
Expand Down