users.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. package controllers
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "github.com/gorilla/mux"
  8. "github.com/gravitl/netmaker/logger"
  9. "github.com/gravitl/netmaker/logic"
  10. "github.com/gravitl/netmaker/models"
  11. "github.com/gravitl/netmaker/mq"
  12. "github.com/gravitl/netmaker/pro/auth"
  13. "github.com/gravitl/netmaker/servercfg"
  14. "golang.org/x/exp/slog"
  15. )
  16. func UserHandlers(r *mux.Router) {
  17. r.HandleFunc("/api/users/{username}/remote_access_gw/{remote_access_gateway_id}", logic.SecurityCheck(true, http.HandlerFunc(attachUserToRemoteAccessGw))).
  18. Methods(http.MethodPost)
  19. r.HandleFunc("/api/users/{username}/remote_access_gw/{remote_access_gateway_id}", logic.SecurityCheck(true, http.HandlerFunc(removeUserFromRemoteAccessGW))).
  20. Methods(http.MethodDelete)
  21. r.HandleFunc("/api/users/{username}/remote_access_gw", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUserRemoteAccessGws)))).
  22. Methods(http.MethodGet)
  23. r.HandleFunc("/api/users/ingress/{ingress_id}", logic.SecurityCheck(true, http.HandlerFunc(ingressGatewayUsers))).
  24. Methods(http.MethodGet)
  25. r.HandleFunc("/api/oauth/login", auth.HandleAuthLogin).Methods(http.MethodGet)
  26. r.HandleFunc("/api/oauth/callback", auth.HandleAuthCallback).Methods(http.MethodGet)
  27. r.HandleFunc("/api/oauth/headless", auth.HandleHeadlessSSO)
  28. r.HandleFunc("/api/oauth/register/{regKey}", auth.RegisterHostSSO).Methods(http.MethodGet)
  29. }
  30. // @Summary Attach user to a remote access gateway
  31. // @Router /api/users/{username}/remote_access_gw/{remote_access_gateway_id} [post]
  32. // @Tags PRO
  33. // @Accept json
  34. // @Produce json
  35. // @Param username path string true "Username"
  36. // @Param remote_access_gateway_id path string true "Remote Access Gateway ID"
  37. // @Success 200 {object} models.ReturnUser
  38. // @Failure 400 {object} models.ErrorResponse
  39. // @Failure 500 {object} models.ErrorResponse
  40. func attachUserToRemoteAccessGw(w http.ResponseWriter, r *http.Request) {
  41. // set header.
  42. w.Header().Set("Content-Type", "application/json")
  43. var params = mux.Vars(r)
  44. username := params["username"]
  45. remoteGwID := params["remote_access_gateway_id"]
  46. if username == "" || remoteGwID == "" {
  47. logic.ReturnErrorResponse(
  48. w,
  49. r,
  50. logic.FormatError(
  51. errors.New("required params `username` and `remote_access_gateway_id`"),
  52. "badrequest",
  53. ),
  54. )
  55. return
  56. }
  57. user, err := logic.GetUser(username)
  58. if err != nil {
  59. slog.Error("failed to fetch user: ", "username", username, "error", err.Error())
  60. logic.ReturnErrorResponse(
  61. w,
  62. r,
  63. logic.FormatError(
  64. fmt.Errorf("failed to fetch user %s, error: %v", username, err),
  65. "badrequest",
  66. ),
  67. )
  68. return
  69. }
  70. if user.IsAdmin || user.IsSuperAdmin {
  71. logic.ReturnErrorResponse(
  72. w,
  73. r,
  74. logic.FormatError(
  75. errors.New("superadmins/admins have access to all gateways"),
  76. "badrequest",
  77. ),
  78. )
  79. return
  80. }
  81. node, err := logic.GetNodeByID(remoteGwID)
  82. if err != nil {
  83. slog.Error("failed to fetch gateway node", "nodeID", remoteGwID, "error", err)
  84. logic.ReturnErrorResponse(
  85. w,
  86. r,
  87. logic.FormatError(
  88. fmt.Errorf("failed to fetch remote access gateway node, error: %v", err),
  89. "badrequest",
  90. ),
  91. )
  92. return
  93. }
  94. if !node.IsIngressGateway {
  95. logic.ReturnErrorResponse(
  96. w,
  97. r,
  98. logic.FormatError(fmt.Errorf("node is not a remote access gateway"), "badrequest"),
  99. )
  100. return
  101. }
  102. if user.RemoteGwIDs == nil {
  103. user.RemoteGwIDs = make(map[string]struct{})
  104. }
  105. user.RemoteGwIDs[node.ID.String()] = struct{}{}
  106. err = logic.UpsertUser(*user)
  107. if err != nil {
  108. slog.Error("failed to update user's gateways", "user", username, "error", err)
  109. logic.ReturnErrorResponse(
  110. w,
  111. r,
  112. logic.FormatError(
  113. fmt.Errorf("failed to fetch remote access gateway node,error: %v", err),
  114. "badrequest",
  115. ),
  116. )
  117. return
  118. }
  119. json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
  120. }
  121. // @Summary Remove user from a remote access gateway
  122. // @Router /api/users/{username}/remote_access_gw/{remote_access_gateway_id} [delete]
  123. // @Tags PRO
  124. // @Accept json
  125. // @Produce json
  126. // @Param username path string true "Username"
  127. // @Param remote_access_gateway_id path string true "Remote Access Gateway ID"
  128. // @Success 200 {object} models.ReturnUser
  129. // @Failure 400 {object} models.ErrorResponse
  130. // @Failure 500 {object} models.ErrorResponse
  131. func removeUserFromRemoteAccessGW(w http.ResponseWriter, r *http.Request) {
  132. // set header.
  133. w.Header().Set("Content-Type", "application/json")
  134. var params = mux.Vars(r)
  135. username := params["username"]
  136. remoteGwID := params["remote_access_gateway_id"]
  137. if username == "" || remoteGwID == "" {
  138. logic.ReturnErrorResponse(
  139. w,
  140. r,
  141. logic.FormatError(
  142. errors.New("required params `username` and `remote_access_gateway_id`"),
  143. "badrequest",
  144. ),
  145. )
  146. return
  147. }
  148. user, err := logic.GetUser(username)
  149. if err != nil {
  150. logger.Log(0, username, "failed to fetch user: ", err.Error())
  151. logic.ReturnErrorResponse(
  152. w,
  153. r,
  154. logic.FormatError(
  155. fmt.Errorf("failed to fetch user %s, error: %v", username, err),
  156. "badrequest",
  157. ),
  158. )
  159. return
  160. }
  161. delete(user.RemoteGwIDs, remoteGwID)
  162. go func(user models.User, remoteGwID string) {
  163. extclients, err := logic.GetAllExtClients()
  164. if err != nil {
  165. slog.Error("failed to fetch extclients", "error", err)
  166. return
  167. }
  168. for _, extclient := range extclients {
  169. if extclient.OwnerID == user.UserName && remoteGwID == extclient.IngressGatewayID {
  170. err = logic.DeleteExtClientAndCleanup(extclient)
  171. if err != nil {
  172. slog.Error("failed to delete extclient",
  173. "id", extclient.ClientID, "owner", user.UserName, "error", err)
  174. } else {
  175. if err := mq.PublishDeletedClientPeerUpdate(&extclient); err != nil {
  176. slog.Error("error setting ext peers: " + err.Error())
  177. }
  178. }
  179. }
  180. }
  181. if servercfg.IsDNSMode() {
  182. logic.SetDNS()
  183. }
  184. }(*user, remoteGwID)
  185. err = logic.UpsertUser(*user)
  186. if err != nil {
  187. slog.Error("failed to update user gateways", "user", username, "error", err)
  188. logic.ReturnErrorResponse(
  189. w,
  190. r,
  191. logic.FormatError(
  192. errors.New("failed to fetch remote access gaetway node "+err.Error()),
  193. "badrequest",
  194. ),
  195. )
  196. return
  197. }
  198. json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
  199. }
  200. // @Summary Get user's remote access gateways
  201. // @Router /api/users/{username}/remote_access_gw [get]
  202. // @Tags PRO
  203. // @Accept json
  204. // @Produce json
  205. // @Param username path string true "Username"
  206. // @Param remote_access_clientid query string false "Remote Access Client ID"
  207. // @Param from_mobile query boolean false "Request from mobile"
  208. // @Success 200 {array} models.UserRemoteGws
  209. // @Failure 400 {object} models.ErrorResponse
  210. // @Failure 500 {object} models.ErrorResponse
  211. func getUserRemoteAccessGws(w http.ResponseWriter, r *http.Request) {
  212. // set header.
  213. w.Header().Set("Content-Type", "application/json")
  214. var params = mux.Vars(r)
  215. username := params["username"]
  216. if username == "" {
  217. logic.ReturnErrorResponse(
  218. w,
  219. r,
  220. logic.FormatError(errors.New("required params username"), "badrequest"),
  221. )
  222. return
  223. }
  224. remoteAccessClientID := r.URL.Query().Get("remote_access_clientid")
  225. var req models.UserRemoteGwsReq
  226. if remoteAccessClientID == "" {
  227. err := json.NewDecoder(r.Body).Decode(&req)
  228. if err != nil {
  229. slog.Error("error decoding request body: ", "error", err)
  230. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  231. return
  232. }
  233. }
  234. reqFromMobile := r.URL.Query().Get("from_mobile") == "true"
  235. if req.RemoteAccessClientID == "" && remoteAccessClientID == "" {
  236. logic.ReturnErrorResponse(
  237. w,
  238. r,
  239. logic.FormatError(errors.New("remote access client id cannot be empty"), "badrequest"),
  240. )
  241. return
  242. }
  243. if req.RemoteAccessClientID == "" {
  244. req.RemoteAccessClientID = remoteAccessClientID
  245. }
  246. userGws := make(map[string][]models.UserRemoteGws)
  247. user, err := logic.GetUser(username)
  248. if err != nil {
  249. logger.Log(0, username, "failed to fetch user: ", err.Error())
  250. logic.ReturnErrorResponse(
  251. w,
  252. r,
  253. logic.FormatError(
  254. fmt.Errorf("failed to fetch user %s, error: %v", username, err),
  255. "badrequest",
  256. ),
  257. )
  258. return
  259. }
  260. allextClients, err := logic.GetAllExtClients()
  261. if err != nil {
  262. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  263. return
  264. }
  265. processedAdminNodeIds := make(map[string]struct{})
  266. for _, extClient := range allextClients {
  267. if extClient.RemoteAccessClientID == req.RemoteAccessClientID &&
  268. extClient.OwnerID == username {
  269. node, err := logic.GetNodeByID(extClient.IngressGatewayID)
  270. if err != nil {
  271. continue
  272. }
  273. if node.PendingDelete {
  274. continue
  275. }
  276. if !node.IsIngressGateway {
  277. continue
  278. }
  279. host, err := logic.GetHost(node.HostID.String())
  280. if err != nil {
  281. continue
  282. }
  283. network, err := logic.GetNetwork(node.Network)
  284. if err != nil {
  285. slog.Error("failed to get node network", "error", err)
  286. }
  287. if _, ok := user.RemoteGwIDs[node.ID.String()]; (!user.IsAdmin && !user.IsSuperAdmin) &&
  288. ok {
  289. gws := userGws[node.Network]
  290. extClient.AllowedIPs = logic.GetExtclientAllowedIPs(extClient)
  291. gws = append(gws, models.UserRemoteGws{
  292. GwID: node.ID.String(),
  293. GWName: host.Name,
  294. Network: node.Network,
  295. GwClient: extClient,
  296. Connected: true,
  297. IsInternetGateway: node.IsInternetGateway,
  298. GwPeerPublicKey: host.PublicKey.String(),
  299. GwListenPort: logic.GetPeerListenPort(host),
  300. Metadata: node.Metadata,
  301. AllowedEndpoints: getAllowedRagEndpoints(&node, host),
  302. NetworkAddresses: []string{network.AddressRange, network.AddressRange6},
  303. })
  304. userGws[node.Network] = gws
  305. delete(user.RemoteGwIDs, node.ID.String())
  306. } else {
  307. gws := userGws[node.Network]
  308. extClient.AllowedIPs = logic.GetExtclientAllowedIPs(extClient)
  309. gws = append(gws, models.UserRemoteGws{
  310. GwID: node.ID.String(),
  311. GWName: host.Name,
  312. Network: node.Network,
  313. GwClient: extClient,
  314. Connected: true,
  315. IsInternetGateway: node.IsInternetGateway,
  316. GwPeerPublicKey: host.PublicKey.String(),
  317. GwListenPort: logic.GetPeerListenPort(host),
  318. Metadata: node.Metadata,
  319. AllowedEndpoints: getAllowedRagEndpoints(&node, host),
  320. NetworkAddresses: []string{network.AddressRange, network.AddressRange6},
  321. })
  322. userGws[node.Network] = gws
  323. processedAdminNodeIds[node.ID.String()] = struct{}{}
  324. }
  325. }
  326. }
  327. // add remaining gw nodes to resp
  328. if !user.IsAdmin && !user.IsSuperAdmin {
  329. for gwID := range user.RemoteGwIDs {
  330. node, err := logic.GetNodeByID(gwID)
  331. if err != nil {
  332. continue
  333. }
  334. if !node.IsIngressGateway {
  335. continue
  336. }
  337. if node.PendingDelete {
  338. continue
  339. }
  340. host, err := logic.GetHost(node.HostID.String())
  341. if err != nil {
  342. continue
  343. }
  344. network, err := logic.GetNetwork(node.Network)
  345. if err != nil {
  346. slog.Error("failed to get node network", "error", err)
  347. }
  348. gws := userGws[node.Network]
  349. gws = append(gws, models.UserRemoteGws{
  350. GwID: node.ID.String(),
  351. GWName: host.Name,
  352. Network: node.Network,
  353. IsInternetGateway: node.IsInternetGateway,
  354. GwPeerPublicKey: host.PublicKey.String(),
  355. GwListenPort: logic.GetPeerListenPort(host),
  356. Metadata: node.Metadata,
  357. AllowedEndpoints: getAllowedRagEndpoints(&node, host),
  358. NetworkAddresses: []string{network.AddressRange, network.AddressRange6},
  359. })
  360. userGws[node.Network] = gws
  361. }
  362. } else {
  363. allNodes, err := logic.GetAllNodes()
  364. if err != nil {
  365. slog.Error("failed to fetch all nodes", "error", err)
  366. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  367. return
  368. }
  369. for _, node := range allNodes {
  370. _, ok := processedAdminNodeIds[node.ID.String()]
  371. if node.IsIngressGateway && !node.PendingDelete && !ok {
  372. host, err := logic.GetHost(node.HostID.String())
  373. if err != nil {
  374. slog.Error("failed to fetch host", "error", err)
  375. continue
  376. }
  377. network, err := logic.GetNetwork(node.Network)
  378. if err != nil {
  379. slog.Error("failed to get node network", "error", err)
  380. }
  381. gws := userGws[node.Network]
  382. gws = append(gws, models.UserRemoteGws{
  383. GwID: node.ID.String(),
  384. GWName: host.Name,
  385. Network: node.Network,
  386. IsInternetGateway: node.IsInternetGateway,
  387. GwPeerPublicKey: host.PublicKey.String(),
  388. GwListenPort: logic.GetPeerListenPort(host),
  389. Metadata: node.Metadata,
  390. AllowedEndpoints: getAllowedRagEndpoints(&node, host),
  391. NetworkAddresses: []string{network.AddressRange, network.AddressRange6},
  392. })
  393. userGws[node.Network] = gws
  394. }
  395. }
  396. }
  397. if reqFromMobile {
  398. // send resp in array format
  399. userGwsArr := []models.UserRemoteGws{}
  400. for _, userGwI := range userGws {
  401. userGwsArr = append(userGwsArr, userGwI...)
  402. }
  403. logic.ReturnSuccessResponseWithJson(w, r, userGwsArr, "fetched gateways for user"+username)
  404. return
  405. }
  406. slog.Debug("returned user gws", "user", username, "gws", userGws)
  407. w.WriteHeader(http.StatusOK)
  408. json.NewEncoder(w).Encode(userGws)
  409. }
  410. // @Summary List users attached to an remote access gateway
  411. // @Router /api/nodes/{network}/{nodeid}/ingress/users [get]
  412. // @Tags PRO
  413. // @Accept json
  414. // @Produce json
  415. // @Param ingress_id path string true "Ingress Gateway ID"
  416. // @Success 200 {array} models.IngressGwUsers
  417. // @Failure 400 {object} models.ErrorResponse
  418. // @Failure 500 {object} models.ErrorResponse
  419. func ingressGatewayUsers(w http.ResponseWriter, r *http.Request) {
  420. w.Header().Set("Content-Type", "application/json")
  421. var params = mux.Vars(r)
  422. ingressID := params["ingress_id"]
  423. node, err := logic.GetNodeByID(ingressID)
  424. if err != nil {
  425. slog.Error("failed to get ingress node", "error", err)
  426. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  427. return
  428. }
  429. gwUsers, err := logic.GetIngressGwUsers(node)
  430. if err != nil {
  431. slog.Error(
  432. "failed to get users on ingress gateway",
  433. "nodeid",
  434. ingressID,
  435. "network",
  436. node.Network,
  437. "user",
  438. r.Header.Get("user"),
  439. "error",
  440. err,
  441. )
  442. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  443. return
  444. }
  445. w.WriteHeader(http.StatusOK)
  446. json.NewEncoder(w).Encode(gwUsers)
  447. }
  448. func getAllowedRagEndpoints(ragNode *models.Node, ragHost *models.Host) []string {
  449. endpoints := []string{}
  450. if len(ragHost.EndpointIP) > 0 {
  451. endpoints = append(endpoints, ragHost.EndpointIP.String())
  452. }
  453. if len(ragHost.EndpointIPv6) > 0 {
  454. endpoints = append(endpoints, ragHost.EndpointIPv6.String())
  455. }
  456. if servercfg.IsPro {
  457. for _, ip := range ragNode.AdditionalRagIps {
  458. endpoints = append(endpoints, ip.String())
  459. }
  460. }
  461. return endpoints
  462. }