user.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567
  1. package controller
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "github.com/gorilla/mux"
  8. "github.com/gorilla/websocket"
  9. "github.com/gravitl/netmaker/auth"
  10. "github.com/gravitl/netmaker/logger"
  11. "github.com/gravitl/netmaker/logic"
  12. "github.com/gravitl/netmaker/models"
  13. "github.com/gravitl/netmaker/mq"
  14. "github.com/gravitl/netmaker/servercfg"
  15. "golang.org/x/exp/slog"
  16. )
  17. var (
  18. upgrader = websocket.Upgrader{}
  19. )
  20. func userHandlers(r *mux.Router) {
  21. r.HandleFunc("/api/users/adm/hassuperadmin", hasSuperAdmin).Methods(http.MethodGet)
  22. r.HandleFunc("/api/users/adm/createsuperadmin", createSuperAdmin).Methods(http.MethodPost)
  23. r.HandleFunc("/api/users/adm/transfersuperadmin/{username}", logic.SecurityCheck(true, http.HandlerFunc(transferSuperAdmin))).Methods(http.MethodPost)
  24. r.HandleFunc("/api/users/adm/authenticate", authenticateUser).Methods(http.MethodPost)
  25. r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(updateUser))).Methods(http.MethodPut)
  26. r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, checkFreeTierLimits(limitChoiceUsers, http.HandlerFunc(createUser)))).Methods(http.MethodPost)
  27. r.HandleFunc("/api/users/{username}", logic.SecurityCheck(true, http.HandlerFunc(deleteUser))).Methods(http.MethodDelete)
  28. r.HandleFunc("/api/users/{username}", logic.SecurityCheck(false, logic.ContinueIfUserMatch(http.HandlerFunc(getUser)))).Methods(http.MethodGet)
  29. r.HandleFunc("/api/users", logic.SecurityCheck(true, http.HandlerFunc(getUsers))).Methods(http.MethodGet)
  30. r.HandleFunc("/api/oauth/login", auth.HandleAuthLogin).Methods(http.MethodGet)
  31. r.HandleFunc("/api/oauth/callback", auth.HandleAuthCallback).Methods(http.MethodGet)
  32. r.HandleFunc("/api/oauth/headless", auth.HandleHeadlessSSO)
  33. r.HandleFunc("/api/oauth/register/{regKey}", auth.RegisterHostSSO).Methods(http.MethodGet)
  34. }
  35. // swagger:route POST /api/users/adm/authenticate authenticate authenticateUser
  36. //
  37. // User authenticates using its password and retrieves a JWT for authorization.
  38. //
  39. // Schemes: https
  40. //
  41. // Security:
  42. // oauth
  43. //
  44. // Responses:
  45. // 200: successResponse
  46. func authenticateUser(response http.ResponseWriter, request *http.Request) {
  47. // Auth request consists of Mac Address and Password (from node that is authorizing
  48. // in case of Master, auth is ignored and mac is set to "mastermac"
  49. var authRequest models.UserAuthParams
  50. var errorResponse = models.ErrorResponse{
  51. Code: http.StatusInternalServerError, Message: "W1R3: It's not you it's me.",
  52. }
  53. if !servercfg.IsBasicAuthEnabled() {
  54. logic.ReturnErrorResponse(response, request, logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"))
  55. return
  56. }
  57. decoder := json.NewDecoder(request.Body)
  58. decoderErr := decoder.Decode(&authRequest)
  59. defer request.Body.Close()
  60. if decoderErr != nil {
  61. logger.Log(0, "error decoding request body: ",
  62. decoderErr.Error())
  63. logic.ReturnErrorResponse(response, request, errorResponse)
  64. return
  65. }
  66. username := authRequest.UserName
  67. jwt, err := logic.VerifyAuthRequest(authRequest)
  68. if err != nil {
  69. logger.Log(0, username, "user validation failed: ",
  70. err.Error())
  71. logic.ReturnErrorResponse(response, request, logic.FormatError(err, "badrequest"))
  72. return
  73. }
  74. if jwt == "" {
  75. // very unlikely that err is !nil and no jwt returned, but handle it anyways.
  76. logger.Log(0, username, "jwt token is empty")
  77. logic.ReturnErrorResponse(response, request, logic.FormatError(errors.New("no token returned"), "internal"))
  78. return
  79. }
  80. var successResponse = models.SuccessResponse{
  81. Code: http.StatusOK,
  82. Message: "W1R3: Device " + username + " Authorized",
  83. Response: models.SuccessfulUserLoginResponse{
  84. AuthToken: jwt,
  85. UserName: username,
  86. },
  87. }
  88. // Send back the JWT
  89. successJSONResponse, jsonError := json.Marshal(successResponse)
  90. if jsonError != nil {
  91. logger.Log(0, username,
  92. "error marshalling resp: ", err.Error())
  93. logic.ReturnErrorResponse(response, request, errorResponse)
  94. return
  95. }
  96. logger.Log(2, username, "was authenticated")
  97. response.Header().Set("Content-Type", "application/json")
  98. response.Write(successJSONResponse)
  99. go func() {
  100. if servercfg.IsPro && servercfg.GetRacAutoDisable() {
  101. // enable all associeated clients for the user
  102. clients, err := logic.GetAllExtClients()
  103. if err != nil {
  104. slog.Error("error getting clients: ", "error", err)
  105. return
  106. }
  107. for _, client := range clients {
  108. if client.OwnerID == username && !client.Enabled {
  109. slog.Info(fmt.Sprintf("enabling ext client %s for user %s due to RAC autodisabling feature", client.ClientID, client.OwnerID))
  110. if newClient, err := logic.ToggleExtClientConnectivity(&client, true); err != nil {
  111. slog.Error("error disabling ext client in RAC autodisable hook", "error", err)
  112. continue // dont return but try for other clients
  113. } else {
  114. // publish peer update to ingress gateway
  115. if ingressNode, err := logic.GetNodeByID(newClient.IngressGatewayID); err == nil {
  116. if err = mq.PublishPeerUpdate(); err != nil {
  117. slog.Error("error updating ext clients on", "ingress", ingressNode.ID.String(), "err", err.Error())
  118. }
  119. }
  120. }
  121. }
  122. }
  123. }
  124. }()
  125. }
  126. // swagger:route GET /api/users/adm/hassuperadmin user hasSuperAdmin
  127. //
  128. // Checks whether the server has an admin.
  129. //
  130. // Schemes: https
  131. //
  132. // Security:
  133. // oauth
  134. //
  135. // Responses:
  136. // 200: hasAdmin
  137. func hasSuperAdmin(w http.ResponseWriter, r *http.Request) {
  138. w.Header().Set("Content-Type", "application/json")
  139. hasSuperAdmin, err := logic.HasSuperAdmin()
  140. if err != nil {
  141. logger.Log(0, "failed to check for admin: ", err.Error())
  142. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  143. return
  144. }
  145. json.NewEncoder(w).Encode(hasSuperAdmin)
  146. }
  147. // swagger:route GET /api/users/{username} user getUser
  148. //
  149. // Get an individual user.
  150. //
  151. // Schemes: https
  152. //
  153. // Security:
  154. // oauth
  155. //
  156. // Responses:
  157. // 200: userBodyResponse
  158. func getUser(w http.ResponseWriter, r *http.Request) {
  159. // set header.
  160. w.Header().Set("Content-Type", "application/json")
  161. var params = mux.Vars(r)
  162. usernameFetched := params["username"]
  163. user, err := logic.GetReturnUser(usernameFetched)
  164. if err != nil {
  165. logger.Log(0, usernameFetched, "failed to fetch user: ", err.Error())
  166. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  167. return
  168. }
  169. logger.Log(2, r.Header.Get("user"), "fetched user", usernameFetched)
  170. json.NewEncoder(w).Encode(user)
  171. }
  172. // swagger:route GET /api/users user getUsers
  173. //
  174. // Get all users.
  175. //
  176. // Schemes: https
  177. //
  178. // Security:
  179. // oauth
  180. //
  181. // Responses:
  182. // 200: userBodyResponse
  183. func getUsers(w http.ResponseWriter, r *http.Request) {
  184. // set header.
  185. w.Header().Set("Content-Type", "application/json")
  186. users, err := logic.GetUsers()
  187. if err != nil {
  188. logger.Log(0, "failed to fetch users: ", err.Error())
  189. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  190. return
  191. }
  192. logic.SortUsers(users[:])
  193. logger.Log(2, r.Header.Get("user"), "fetched users")
  194. json.NewEncoder(w).Encode(users)
  195. }
  196. // swagger:route POST /api/users/adm/createsuperadmin user createAdmin
  197. //
  198. // Make a user an admin.
  199. //
  200. // Schemes: https
  201. //
  202. // Security:
  203. // oauth
  204. //
  205. // Responses:
  206. // 200: userBodyResponse
  207. func createSuperAdmin(w http.ResponseWriter, r *http.Request) {
  208. w.Header().Set("Content-Type", "application/json")
  209. var u models.User
  210. err := json.NewDecoder(r.Body).Decode(&u)
  211. if err != nil {
  212. slog.Error("error decoding request body", "error", err.Error())
  213. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  214. return
  215. }
  216. if !servercfg.IsBasicAuthEnabled() {
  217. logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"))
  218. return
  219. }
  220. err = logic.CreateSuperAdmin(&u)
  221. if err != nil {
  222. slog.Error("failed to create admin", "error", err.Error())
  223. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  224. return
  225. }
  226. logger.Log(1, u.UserName, "was made a super admin")
  227. json.NewEncoder(w).Encode(logic.ToReturnUser(u))
  228. }
  229. // swagger:route POST /api/users/adm/transfersuperadmin user transferSuperAdmin
  230. //
  231. // Transfers superadmin role to an admin user.
  232. //
  233. // Schemes: https
  234. //
  235. // Security:
  236. // oauth
  237. //
  238. // Responses:
  239. // 200: userBodyResponse
  240. func transferSuperAdmin(w http.ResponseWriter, r *http.Request) {
  241. w.Header().Set("Content-Type", "application/json")
  242. caller, err := logic.GetUser(r.Header.Get("user"))
  243. if err != nil {
  244. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  245. }
  246. if !caller.IsSuperAdmin {
  247. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only superadmin can assign the superadmin role to another user"), "forbidden"))
  248. return
  249. }
  250. var params = mux.Vars(r)
  251. username := params["username"]
  252. u, err := logic.GetUser(username)
  253. if err != nil {
  254. slog.Error("error getting user", "user", u.UserName, "error", err.Error())
  255. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  256. return
  257. }
  258. if !u.IsAdmin {
  259. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("only admins can be promoted to superadmin role"), "forbidden"))
  260. return
  261. }
  262. if !servercfg.IsBasicAuthEnabled() {
  263. logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("basic auth is disabled"), "badrequest"))
  264. return
  265. }
  266. u.IsSuperAdmin = true
  267. u.IsAdmin = false
  268. err = logic.UpsertUser(*u)
  269. if err != nil {
  270. slog.Error("error updating user to superadmin: ", "user", u.UserName, "error", err.Error())
  271. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  272. return
  273. }
  274. caller.IsSuperAdmin = false
  275. caller.IsAdmin = true
  276. err = logic.UpsertUser(*caller)
  277. if err != nil {
  278. slog.Error("error demoting user to admin: ", "user", caller.UserName, "error", err.Error())
  279. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  280. return
  281. }
  282. slog.Info("user was made a super admin", "user", u.UserName)
  283. json.NewEncoder(w).Encode(logic.ToReturnUser(*u))
  284. }
  285. // swagger:route POST /api/users/{username} user createUser
  286. //
  287. // Create a user.
  288. //
  289. // Schemes: https
  290. //
  291. // Security:
  292. // oauth
  293. //
  294. // Responses:
  295. // 200: userBodyResponse
  296. func createUser(w http.ResponseWriter, r *http.Request) {
  297. w.Header().Set("Content-Type", "application/json")
  298. caller, err := logic.GetUser(r.Header.Get("user"))
  299. if err != nil {
  300. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  301. }
  302. var user models.User
  303. err = json.NewDecoder(r.Body).Decode(&user)
  304. if err != nil {
  305. logger.Log(0, user.UserName, "error decoding request body: ",
  306. err.Error())
  307. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  308. return
  309. }
  310. if !caller.IsSuperAdmin && user.IsAdmin {
  311. err = errors.New("only superadmin can create admin users")
  312. slog.Error("error creating new user: ", "user", user.UserName, "error", err)
  313. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  314. return
  315. }
  316. if user.IsSuperAdmin {
  317. err = errors.New("additional superadmins cannot be created")
  318. slog.Error("error creating new user: ", "user", user.UserName, "error", err)
  319. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  320. return
  321. }
  322. if !servercfg.IsPro && !user.IsAdmin {
  323. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  324. return
  325. }
  326. err = logic.CreateUser(&user)
  327. if err != nil {
  328. slog.Error("error creating new user: ", "user", user.UserName, "error", err.Error())
  329. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  330. return
  331. }
  332. slog.Info("user was created", "username", user.UserName)
  333. json.NewEncoder(w).Encode(logic.ToReturnUser(user))
  334. }
  335. // swagger:route PUT /api/users/{username} user updateUser
  336. //
  337. // Update a user.
  338. //
  339. // Schemes: https
  340. //
  341. // Security:
  342. // oauth
  343. //
  344. // Responses:
  345. // 200: userBodyResponse
  346. func updateUser(w http.ResponseWriter, r *http.Request) {
  347. w.Header().Set("Content-Type", "application/json")
  348. var params = mux.Vars(r)
  349. // start here
  350. var caller *models.User
  351. var err error
  352. var ismaster bool
  353. if r.Header.Get("user") == logic.MasterUser {
  354. ismaster = true
  355. } else {
  356. caller, err = logic.GetUser(r.Header.Get("user"))
  357. if err != nil {
  358. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  359. }
  360. }
  361. username := params["username"]
  362. user, err := logic.GetUser(username)
  363. if err != nil {
  364. logger.Log(0, username,
  365. "failed to update user info: ", err.Error())
  366. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  367. return
  368. }
  369. var userchange models.User
  370. // we decode our body request params
  371. err = json.NewDecoder(r.Body).Decode(&userchange)
  372. if err != nil {
  373. slog.Error("failed to decode body", "error ", err.Error())
  374. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  375. return
  376. }
  377. if user.UserName != userchange.UserName {
  378. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user in param and request body not matching"), "badrequest"))
  379. return
  380. }
  381. selfUpdate := false
  382. if !ismaster && caller.UserName == user.UserName {
  383. selfUpdate = true
  384. }
  385. if !ismaster && !selfUpdate {
  386. if caller.IsAdmin && user.IsSuperAdmin {
  387. slog.Error("non-superadmin user", "caller", caller.UserName, "attempted to update superadmin user", username)
  388. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"))
  389. return
  390. }
  391. if !caller.IsAdmin && !caller.IsSuperAdmin {
  392. slog.Error("operation not allowed", "caller", caller.UserName, "attempted to update user", username)
  393. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("cannot update superadmin user"), "forbidden"))
  394. return
  395. }
  396. if caller.IsAdmin && user.IsAdmin {
  397. slog.Error("admin user cannot update another admin", "caller", caller.UserName, "attempted to update admin user", username)
  398. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("admin user cannot update another admin"), "forbidden"))
  399. return
  400. }
  401. if caller.IsAdmin && userchange.IsAdmin {
  402. err = errors.New("admin user cannot update role of an another user to admin")
  403. slog.Error("failed to update user", "caller", caller.UserName, "attempted to update user", username, "error", err)
  404. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  405. return
  406. }
  407. }
  408. if !ismaster && selfUpdate {
  409. if user.IsAdmin != userchange.IsAdmin || user.IsSuperAdmin != userchange.IsSuperAdmin {
  410. slog.Error("user cannot change his own role", "caller", caller.UserName, "attempted to update user role", username)
  411. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("user not allowed to self assign role"), "forbidden"))
  412. return
  413. }
  414. }
  415. if ismaster {
  416. if !user.IsSuperAdmin && userchange.IsSuperAdmin {
  417. slog.Error("operation not allowed", "caller", logic.MasterUser, "attempted to update user role to superadmin", username)
  418. logic.ReturnErrorResponse(w, r, logic.FormatError(errors.New("attempted to update user role to superadmin"), "forbidden"))
  419. return
  420. }
  421. }
  422. if auth.IsOauthUser(user) == nil && userchange.Password != "" {
  423. err := fmt.Errorf("cannot update user's password for an oauth user %s", username)
  424. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "forbidden"))
  425. return
  426. }
  427. user, err = logic.UpdateUser(&userchange, user)
  428. if err != nil {
  429. logger.Log(0, username,
  430. "failed to update user info: ", err.Error())
  431. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  432. return
  433. }
  434. logger.Log(1, username, "was updated")
  435. json.NewEncoder(w).Encode(logic.ToReturnUser(*user))
  436. }
  437. // swagger:route DELETE /api/users/{username} user deleteUser
  438. //
  439. // Delete a user.
  440. //
  441. // Schemes: https
  442. //
  443. // Security:
  444. // oauth
  445. //
  446. // Responses:
  447. // 200: userBodyResponse
  448. func deleteUser(w http.ResponseWriter, r *http.Request) {
  449. // Set header
  450. w.Header().Set("Content-Type", "application/json")
  451. // get params
  452. var params = mux.Vars(r)
  453. caller, err := logic.GetUser(r.Header.Get("user"))
  454. if err != nil {
  455. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  456. }
  457. username := params["username"]
  458. user, err := logic.GetUser(username)
  459. if err != nil {
  460. logger.Log(0, username,
  461. "failed to update user info: ", err.Error())
  462. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  463. return
  464. }
  465. if user.IsSuperAdmin {
  466. slog.Error(
  467. "failed to delete user: ", "user", username, "error", "superadmin cannot be deleted")
  468. logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("superadmin cannot be deleted"), "internal"))
  469. return
  470. }
  471. if !caller.IsSuperAdmin {
  472. if caller.IsAdmin && user.IsAdmin {
  473. slog.Error(
  474. "failed to delete user: ", "user", username, "error", "admin cannot delete another admin user, including oneself")
  475. logic.ReturnErrorResponse(w, r, logic.FormatError(fmt.Errorf("admin cannot delete another admin user, including oneself"), "internal"))
  476. return
  477. }
  478. }
  479. success, err := logic.DeleteUser(username)
  480. if err != nil {
  481. logger.Log(0, username,
  482. "failed to delete user: ", err.Error())
  483. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "internal"))
  484. return
  485. } else if !success {
  486. err := errors.New("delete unsuccessful")
  487. logger.Log(0, username, err.Error())
  488. logic.ReturnErrorResponse(w, r, logic.FormatError(err, "badrequest"))
  489. return
  490. }
  491. // check and delete extclient with this ownerID
  492. go func() {
  493. extclients, err := logic.GetAllExtClients()
  494. if err != nil {
  495. slog.Error("failed to get extclients", "error", err)
  496. return
  497. }
  498. for _, extclient := range extclients {
  499. if extclient.OwnerID == user.UserName {
  500. err = logic.DeleteExtClient(extclient.Network, extclient.ClientID)
  501. if err != nil {
  502. slog.Error("failed to delete extclient",
  503. "id", extclient.ClientID, "owner", user.UserName, "error", err)
  504. }
  505. }
  506. }
  507. }()
  508. logger.Log(1, username, "was deleted")
  509. json.NewEncoder(w).Encode(params["username"] + " deleted.")
  510. }
  511. // Called when vpn client dials in to start the auth flow and first stage is to get register URL itself
  512. func socketHandler(w http.ResponseWriter, r *http.Request) {
  513. // Upgrade our raw HTTP connection to a websocket based one
  514. conn, err := upgrader.Upgrade(w, r, nil)
  515. if err != nil {
  516. logger.Log(0, "error during connection upgrade for node sign-in:", err.Error())
  517. return
  518. }
  519. if conn == nil {
  520. logger.Log(0, "failed to establish web-socket connection during node sign-in")
  521. return
  522. }
  523. // Start handling the session
  524. go auth.SessionHandler(conn)
  525. }